| 1 | package PluginManager::CMS; |
|---|
| 2 | |
|---|
| 3 | use strict; |
|---|
| 4 | @PluginManager::CMS::ISA = qw( MT::App ); |
|---|
| 5 | |
|---|
| 6 | use MT::App; |
|---|
| 7 | use MT::App::CMS; |
|---|
| 8 | use MT::ConfigMgr; |
|---|
| 9 | use MT::PluginData; |
|---|
| 10 | |
|---|
| 11 | use PluginManager::Plugin; |
|---|
| 12 | use PluginManager::Util qw(debug scrub_path); |
|---|
| 13 | |
|---|
| 14 | use XML::Simple; |
|---|
| 15 | use LWP::Simple; |
|---|
| 16 | use File::Copy::Recursive qw(pathrm dircopy); |
|---|
| 17 | use Archive::Extract; |
|---|
| 18 | use File::Copy; |
|---|
| 19 | use File::Basename; |
|---|
| 20 | use File::Spec qw(catfile); |
|---|
| 21 | use File::Temp; |
|---|
| 22 | use File::Path; |
|---|
| 23 | use File::Find; |
|---|
| 24 | |
|---|
| 25 | sub init { |
|---|
| 26 | my $app = shift; |
|---|
| 27 | my %param = @_; |
|---|
| 28 | $app->SUPER::init(%param) or return; |
|---|
| 29 | |
|---|
| 30 | $app->add_methods( |
|---|
| 31 | 'init' => \&initialize, |
|---|
| 32 | 'install' => \&install_plugin, |
|---|
| 33 | 'uninstall' => \&uninstall_plugin, |
|---|
| 34 | 'upgrade' => \&upgrade_plugin, |
|---|
| 35 | 'list' => \&list_plugins, |
|---|
| 36 | 'check_ajax' => \&check_ajax, |
|---|
| 37 | ); |
|---|
| 38 | |
|---|
| 39 | $app->{default_mode} = 'list'; |
|---|
| 40 | $app->{requires_login} = 1; |
|---|
| 41 | $app; |
|---|
| 42 | } |
|---|
| 43 | |
|---|
| 44 | sub check_ajax { |
|---|
| 45 | my $app = shift; |
|---|
| 46 | my $q = $app->{query}; |
|---|
| 47 | |
|---|
| 48 | my $id = $q->param('id'); |
|---|
| 49 | |
|---|
| 50 | my $m; |
|---|
| 51 | $m = PluginManager::Plugin->load( { id => $id } ); |
|---|
| 52 | if (!$m) { |
|---|
| 53 | return 'error'; |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | my $record; |
|---|
| 57 | for my $sig (keys %MT::Plugins) { |
|---|
| 58 | if ($sig eq $m->sig) { |
|---|
| 59 | $record = $MT::Plugins{$sig}{object}; |
|---|
| 60 | last; |
|---|
| 61 | } |
|---|
| 62 | } |
|---|
| 63 | my $plugin = { |
|---|
| 64 | key => $m->id, |
|---|
| 65 | version => $record->{version}, |
|---|
| 66 | name => $m->name, |
|---|
| 67 | icon => $m->icon, |
|---|
| 68 | description => $record->{description}, |
|---|
| 69 | url => $m->url, |
|---|
| 70 | created => $m->created_on, |
|---|
| 71 | updated => $m->updated_on, |
|---|
| 72 | }; |
|---|
| 73 | |
|---|
| 74 | |
|---|
| 75 | my $local_cfg = XMLin($m->config); |
|---|
| 76 | my $local_version = $plugin->{version}; |
|---|
| 77 | |
|---|
| 78 | my $version_url = $local_cfg->{version_url}; |
|---|
| 79 | my $remote_data = get($version_url) or return; |
|---|
| 80 | my $remote_cfg = XMLin($remote_data); |
|---|
| 81 | my $remote_version = $remote_cfg->{version}; |
|---|
| 82 | |
|---|
| 83 | debug($m->name.": ".$remote_version." > ".$local_version."?"); |
|---|
| 84 | my $param = { |
|---|
| 85 | key => $m->id, |
|---|
| 86 | upgrade_available => $remote_version > $local_version, |
|---|
| 87 | }; |
|---|
| 88 | my $tmpl = $app->init_tmpl('check_ajax.tmpl'); |
|---|
| 89 | for my $key (keys %$param) { |
|---|
| 90 | $tmpl->param($key, $param->{$key}); |
|---|
| 91 | } |
|---|
| 92 | $app->l10n_filter($tmpl->output); |
|---|
| 93 | } |
|---|
| 94 | |
|---|
| 95 | sub list_plugins { |
|---|
| 96 | my $app = shift; |
|---|
| 97 | my $q = $app->{query}; |
|---|
| 98 | |
|---|
| 99 | # my $data = MT::PluginData->load({ plugin => 'PluginManager', |
|---|
| 100 | # key => 'static-path' }); |
|---|
| 101 | # my $static_path = $data->data; |
|---|
| 102 | |
|---|
| 103 | my (%constraints, %options); |
|---|
| 104 | $options{sort} = 'name'; |
|---|
| 105 | $options{direction} = 'ascend'; |
|---|
| 106 | my $iter = PluginManager::Plugin->load_iter( \%constraints, \%options ); |
|---|
| 107 | my @plugins; |
|---|
| 108 | my $count = 0; |
|---|
| 109 | my $plugin_keys = ''; |
|---|
| 110 | while (my $m = $iter->()) { |
|---|
| 111 | my $record; |
|---|
| 112 | for my $sig (keys %MT::Plugins) { |
|---|
| 113 | if ($sig eq $m->sig) { |
|---|
| 114 | $record = $MT::Plugins{$sig}{object}; |
|---|
| 115 | last; |
|---|
| 116 | } |
|---|
| 117 | } |
|---|
| 118 | my $plugin = { |
|---|
| 119 | key => $m->id, |
|---|
| 120 | version => $record->{version}, |
|---|
| 121 | name => $m->name, |
|---|
| 122 | description => $record->{description}, |
|---|
| 123 | url => $m->url, |
|---|
| 124 | created => $m->created_on, |
|---|
| 125 | updated => $m->updated_on, |
|---|
| 126 | count => $count++, |
|---|
| 127 | entry_odd => $count % 2 == 0, |
|---|
| 128 | }; |
|---|
| 129 | $plugin->{icon} = MT->instance->{cfg}->CGIPath . $m->icon |
|---|
| 130 | if $m->icon; |
|---|
| 131 | |
|---|
| 132 | $plugin_keys .= ',' if ($plugin_keys ne ''); |
|---|
| 133 | $plugin_keys .= $plugin->{key}; |
|---|
| 134 | |
|---|
| 135 | push @plugins,$plugin; |
|---|
| 136 | } |
|---|
| 137 | |
|---|
| 138 | my $param = { |
|---|
| 139 | url => $q->param('url'), |
|---|
| 140 | tmpfile => $q->param('tmpdir'), |
|---|
| 141 | tmpdir => $q->param('tmpfile'), |
|---|
| 142 | plugin => $q->param('plugin'), |
|---|
| 143 | plugin_keys => $plugin_keys, |
|---|
| 144 | plugin_loop => \@plugins, |
|---|
| 145 | }; |
|---|
| 146 | |
|---|
| 147 | my $tmpl = $app->init_tmpl('list.tmpl'); |
|---|
| 148 | $app->add_breadcrumb("Main Menu",$app->{mtscript_url}); |
|---|
| 149 | $app->add_breadcrumb("Plugin Manager"); |
|---|
| 150 | $app->{breadcrumbs}[-1]{is_last} = 1; |
|---|
| 151 | |
|---|
| 152 | $tmpl->param(breadcrumbs => $app->{breadcrumbs}); |
|---|
| 153 | $tmpl->param(blog_id => $app->{query}->param('blog_id')); |
|---|
| 154 | $tmpl->param(plugin_version => $MT::Plugin::PluginManager::VERSION); |
|---|
| 155 | for my $key (keys %$param) { |
|---|
| 156 | $tmpl->param($key, $param->{$key}); |
|---|
| 157 | } |
|---|
| 158 | $app->l10n_filter($tmpl->output); |
|---|
| 159 | } |
|---|
| 160 | |
|---|
| 161 | sub extract_linkrel { |
|---|
| 162 | my ($url,$match) = @_; |
|---|
| 163 | my $content = get($url) |
|---|
| 164 | or die "Download failed ($url): $@"; |
|---|
| 165 | my @links = ($content =~ /(<link [^\>]*>)/gmi); |
|---|
| 166 | foreach my $link (@links) { |
|---|
| 167 | my ($rel) = ($link =~ /rel=\"([^\"]*)\"/i); |
|---|
| 168 | my ($href) = ($link =~ /href=\"([^\"]*)\"/i); |
|---|
| 169 | if ($rel eq $match) { |
|---|
| 170 | return $href; |
|---|
| 171 | } |
|---|
| 172 | } |
|---|
| 173 | } |
|---|
| 174 | |
|---|
| 175 | sub repair_class { |
|---|
| 176 | my $app = shift; |
|---|
| 177 | my ($class) = @_; |
|---|
| 178 | require MT::Upgrade; |
|---|
| 179 | my $driver = MT::Object->driver; |
|---|
| 180 | my $diff = MT::Upgrade->class_diff($class); |
|---|
| 181 | debug("diff=$diff"); |
|---|
| 182 | if ($diff) { |
|---|
| 183 | my @stmt; |
|---|
| 184 | if ($diff->{fix}) { |
|---|
| 185 | @stmt = $driver->fix_class($class); |
|---|
| 186 | } else { |
|---|
| 187 | if ($diff->{add}) { |
|---|
| 188 | push @stmt, $driver->add_column($class, $_->{name}) |
|---|
| 189 | foreach @{$diff->{add}}; |
|---|
| 190 | } |
|---|
| 191 | if ($diff->{alter}) { |
|---|
| 192 | push @stmt, $driver->alter_column($class, $_->{name}) |
|---|
| 193 | foreach @{$diff->{alter}}; |
|---|
| 194 | } |
|---|
| 195 | if ($diff->{drop}) { |
|---|
| 196 | push @stmt, $driver->drop_column($class, $_->{name}) |
|---|
| 197 | foreach @{$diff->{drop}}; |
|---|
| 198 | } |
|---|
| 199 | } |
|---|
| 200 | if (@stmt) { |
|---|
| 201 | $driver->sql(\@stmt) or return $app->error($driver->errstr); |
|---|
| 202 | } |
|---|
| 203 | } |
|---|
| 204 | return $diff; |
|---|
| 205 | } |
|---|
| 206 | |
|---|
| 207 | sub initialize { |
|---|
| 208 | my $app = shift; |
|---|
| 209 | my $q = $app->{query}; |
|---|
| 210 | |
|---|
| 211 | require PluginManager::Plugin; |
|---|
| 212 | |
|---|
| 213 | my $diff = $app->repair_class("PluginManager::Plugin"); |
|---|
| 214 | |
|---|
| 215 | my $data = MT::PluginData->new; |
|---|
| 216 | $data->plugin('PluginManager'); |
|---|
| 217 | $data->key('static-path'); |
|---|
| 218 | $data->data($q->param('static_path')); |
|---|
| 219 | $data->save or die $data->errstr; |
|---|
| 220 | |
|---|
| 221 | my $filename = File::Spec->catfile(MT->instance->mt_dir, |
|---|
| 222 | 'plugins','PluginManager','mtplugin.pkg'); |
|---|
| 223 | open FILE,$filename or die "Could not open file: $!"; |
|---|
| 224 | my $data = join('',<FILE>); |
|---|
| 225 | close FILE; |
|---|
| 226 | my $package = XMLin($data); |
|---|
| 227 | |
|---|
| 228 | my $plugin = PluginManager::Plugin->load( { |
|---|
| 229 | sig => 'PluginManager/PluginManager.pl' |
|---|
| 230 | } ); |
|---|
| 231 | if (!$plugin) { |
|---|
| 232 | $plugin = PluginManager::Plugin->new; |
|---|
| 233 | } |
|---|
| 234 | $plugin->name($package->{name}); |
|---|
| 235 | $plugin->sig($package->{sig}); |
|---|
| 236 | $plugin->icon($package->{icon}->{content}); |
|---|
| 237 | $plugin->config($data); |
|---|
| 238 | $plugin->url($package->{version_url}); |
|---|
| 239 | |
|---|
| 240 | $plugin->save or |
|---|
| 241 | return $app->error("Error initializing Plugin Manager: " . $plugin->errstr); |
|---|
| 242 | |
|---|
| 243 | $app->list_plugins(); |
|---|
| 244 | } |
|---|
| 245 | |
|---|
| 246 | sub uninstall_plugin { |
|---|
| 247 | my $app = shift; |
|---|
| 248 | my $q = $app->{query}; |
|---|
| 249 | |
|---|
| 250 | my $id = $q->param('id'); |
|---|
| 251 | my $commit = $q->param('commit'); |
|---|
| 252 | |
|---|
| 253 | my $plugin; |
|---|
| 254 | $plugin = PluginManager::Plugin->load( { id => $id } ); |
|---|
| 255 | if (!$plugin) { |
|---|
| 256 | return $app->list_plugins(); |
|---|
| 257 | } |
|---|
| 258 | |
|---|
| 259 | my $cfg; |
|---|
| 260 | eval { |
|---|
| 261 | $cfg = XMLin($plugin->config, |
|---|
| 262 | ForceArray => 1, |
|---|
| 263 | ForceContent => 1); |
|---|
| 264 | }; |
|---|
| 265 | if ($@) { |
|---|
| 266 | return $app->errtrans("Could not load plugin descriptor: $@"); |
|---|
| 267 | } |
|---|
| 268 | |
|---|
| 269 | my @preview; |
|---|
| 270 | eval { |
|---|
| 271 | my $files = $cfg->{files}->{file}; |
|---|
| 272 | foreach my $file (@$files) { |
|---|
| 273 | my $destination = File::Spec->catfile(MT->instance->mt_dir, |
|---|
| 274 | $file->{destination}); |
|---|
| 275 | $destination = scrub_path($destination); |
|---|
| 276 | if (-f $destination) { |
|---|
| 277 | if ($commit) { |
|---|
| 278 | unlink($destination); |
|---|
| 279 | debug("Executing 'unlink $destination'"); |
|---|
| 280 | } else { |
|---|
| 281 | push @preview, { text => "Deleting file: $destination" }; |
|---|
| 282 | } |
|---|
| 283 | } elsif (-d $destination) { |
|---|
| 284 | } |
|---|
| 285 | } |
|---|
| 286 | |
|---|
| 287 | my @protected; |
|---|
| 288 | push @protected,MT->instance->mt_dir; |
|---|
| 289 | foreach (qw(plugins mt-static alt-tmpl docs extlib examples extras |
|---|
| 290 | import lib php tools schemas search_templates)) { |
|---|
| 291 | push @protected,File::Spec->catfile(MT->instance->mt_dir,$_); |
|---|
| 292 | } |
|---|
| 293 | |
|---|
| 294 | my $data = MT::PluginData->load({ plugin => 'PluginManager', |
|---|
| 295 | key => 'static-path' }); |
|---|
| 296 | my $static_path = $data->data; |
|---|
| 297 | |
|---|
| 298 | my $cmds = $cfg->{uninstall}->[0]; |
|---|
| 299 | use Data::Dumper; |
|---|
| 300 | foreach my $cmd_name (keys %$cmds) { |
|---|
| 301 | my $tmp = $cmds->{$cmd_name}; |
|---|
| 302 | foreach my $cmd (@$tmp) { |
|---|
| 303 | debug("$cmd_name = ".Dumper($cmd));; |
|---|
| 304 | if ($cmd_name eq 'rmdir' && |
|---|
| 305 | !in_array($cmd->{content},@protected)) { |
|---|
| 306 | my $dir; |
|---|
| 307 | if ($cmd->{static}) { |
|---|
| 308 | $dir = File::Spec->catfile($static_path, |
|---|
| 309 | $cmd->{content}); |
|---|
| 310 | } else { |
|---|
| 311 | $dir = File::Spec->catfile(MT->instance->mt_dir, |
|---|
| 312 | $cmd->{content}); |
|---|
| 313 | } |
|---|
| 314 | if ($commit) { |
|---|
| 315 | debug("Executing 'pathrm($dir)'"); |
|---|
| 316 | File::Copy::Recursive::pathrm($dir,1); |
|---|
| 317 | } else { |
|---|
| 318 | push @preview, { text => "Removing the directory $dir" }; |
|---|
| 319 | } |
|---|
| 320 | } |
|---|
| 321 | } |
|---|
| 322 | } |
|---|
| 323 | }; |
|---|
| 324 | if ($@) { |
|---|
| 325 | return $app->errtrans("Could not clean up after plugin installation: $@"); |
|---|
| 326 | } |
|---|
| 327 | |
|---|
| 328 | if ($commit) { |
|---|
| 329 | $plugin->remove or |
|---|
| 330 | return $app->error("Error removing plugin: " . $plugin->errstr); |
|---|
| 331 | $app->redirect($app->{cfg}->CGIPath . "plugins/PluginManager/plugins.cgi?__mode=list"); |
|---|
| 332 | } else { |
|---|
| 333 | my $param = { |
|---|
| 334 | plugin_id => $plugin->id, |
|---|
| 335 | plugin_name => $plugin->name, |
|---|
| 336 | preview_loop => \@preview, |
|---|
| 337 | }; |
|---|
| 338 | |
|---|
| 339 | my $tmpl = $app->init_tmpl('preview.tmpl'); |
|---|
| 340 | $app->add_breadcrumb("Main Menu",$app->{mtscript_url}); |
|---|
| 341 | $app->add_breadcrumb("Plugin Manager"); |
|---|
| 342 | $app->{breadcrumbs}[-1]{is_last} = 1; |
|---|
| 343 | |
|---|
| 344 | $tmpl->param(breadcrumbs => $app->{breadcrumbs}); |
|---|
| 345 | $tmpl->param(blog_id => $app->{query}->param('blog_id')); |
|---|
| 346 | $tmpl->param(plugin_version => $MT::Plugin::PluginManager::VERSION); |
|---|
| 347 | for my $key (keys %$param) { |
|---|
| 348 | $tmpl->param($key, $param->{$key}); |
|---|
| 349 | } |
|---|
| 350 | $app->l10n_filter($tmpl->output); |
|---|
| 351 | } |
|---|
| 352 | } |
|---|
| 353 | |
|---|
| 354 | sub upgrade_plugin { |
|---|
| 355 | my $app = shift; |
|---|
| 356 | my $q = $app->{query}; |
|---|
| 357 | |
|---|
| 358 | my $id = $q->param('id'); |
|---|
| 359 | my $plugin; |
|---|
| 360 | $plugin = PluginManager::Plugin->load( { id => $id } ); |
|---|
| 361 | if (!$plugin) { |
|---|
| 362 | return $app->list_plugins(); |
|---|
| 363 | } |
|---|
| 364 | |
|---|
| 365 | my $cfg; |
|---|
| 366 | eval { |
|---|
| 367 | $cfg = XMLin($plugin->config); |
|---|
| 368 | }; |
|---|
| 369 | if ($@) { |
|---|
| 370 | return $app->errtrans("Could not load plugin descriptor: $@"); |
|---|
| 371 | } |
|---|
| 372 | |
|---|
| 373 | my ($tmp_dir,$tmp_file) = $app->create_tmp_file(); |
|---|
| 374 | |
|---|
| 375 | my $url = $cfg->{version_url}; |
|---|
| 376 | my $content = get($url); |
|---|
| 377 | my ($mti) = XMLin($content); |
|---|
| 378 | $url = $mti->{download_url}; |
|---|
| 379 | |
|---|
| 380 | # get the data |
|---|
| 381 | debug("Fetching data."); |
|---|
| 382 | is_success(getstore($url, $tmp_file)) |
|---|
| 383 | or return $app->errtrans("Download failed ($url): $@"); |
|---|
| 384 | |
|---|
| 385 | my $package = $app->handle_install($tmp_dir,$tmp_file, 1); |
|---|
| 386 | |
|---|
| 387 | $plugin->name($package->{name}); |
|---|
| 388 | $plugin->sig($package->{sig}); |
|---|
| 389 | $plugin->icon($package->{icon}->{content}); |
|---|
| 390 | $plugin->config($package->{raw_data}); |
|---|
| 391 | $plugin->url($package->{version_url}); |
|---|
| 392 | $plugin->save or |
|---|
| 393 | return $app->error("Error updating plugin: " . $plugin->errstr); |
|---|
| 394 | |
|---|
| 395 | $q->param('blog_id' => $app->{query}->param('blog_id')); |
|---|
| 396 | $q->param('url' => $url); |
|---|
| 397 | $q->param('plugin' => $package->{name}); |
|---|
| 398 | $app->redirect($app->{cfg}->CGIPath . "plugins/PluginManager/plugins.cgi?__mode=list"); |
|---|
| 399 | |
|---|
| 400 | $app->list_plugins(); |
|---|
| 401 | } |
|---|
| 402 | |
|---|
| 403 | sub create_tmp_file { |
|---|
| 404 | my $app = shift; |
|---|
| 405 | my $tmp_dir = $app->config('TempDir'); |
|---|
| 406 | my ($tmp_fh, $tmp_file); |
|---|
| 407 | $tmp_dir = File::Temp::tempdir( 'PluginManager/XXXX', |
|---|
| 408 | DIR => $tmp_dir); |
|---|
| 409 | debug("Making path: $tmp_dir"); |
|---|
| 410 | eval { |
|---|
| 411 | File::Path::mkpath($tmp_dir); |
|---|
| 412 | chmod(0775,$tmp_dir); |
|---|
| 413 | }; |
|---|
| 414 | if ($@) { |
|---|
| 415 | return $app->errtrans("Error creating temporary directory: $@."); |
|---|
| 416 | } |
|---|
| 417 | debug("Creating temp file."); |
|---|
| 418 | eval { |
|---|
| 419 | ($tmp_fh, $tmp_file) = File::Temp::tempfile("PluginXXXX", |
|---|
| 420 | DIR => $tmp_dir, |
|---|
| 421 | SUFFIX => '.tar.gz', |
|---|
| 422 | ); |
|---|
| 423 | }; |
|---|
| 424 | if ($@) { |
|---|
| 425 | return $app->errtrans( |
|---|
| 426 | "Error creating temporary file; please check your TempDir ". |
|---|
| 427 | "setting in mt.cfg (currently '[_1]') " . |
|---|
| 428 | "this location should be writable. ($@)", |
|---|
| 429 | ($tmp_dir ? $tmp_dir : '['.$app->translate('unassigned').']')); |
|---|
| 430 | } |
|---|
| 431 | return ($tmp_dir, $tmp_file); |
|---|
| 432 | } |
|---|
| 433 | |
|---|
| 434 | sub handle_install { |
|---|
| 435 | my $app = shift; |
|---|
| 436 | my ($tmp_dir,$tmp_file,$force) = @_; |
|---|
| 437 | my $q = $app->{query}; |
|---|
| 438 | |
|---|
| 439 | my @files; |
|---|
| 440 | eval { |
|---|
| 441 | debug("Extracting archive found at: $tmp_file"); |
|---|
| 442 | my $ae = Archive::Extract->new( archive => $tmp_file ); |
|---|
| 443 | my $ok = $ae->extract( to => $tmp_dir ); |
|---|
| 444 | debug("Extracted file to $tmp_dir."); |
|---|
| 445 | }; |
|---|
| 446 | if ($@) { |
|---|
| 447 | return $app->errtrans("Could not unpack plugin. $@"); |
|---|
| 448 | } |
|---|
| 449 | |
|---|
| 450 | my $package; |
|---|
| 451 | my $data; |
|---|
| 452 | File::Find::find( |
|---|
| 453 | sub { |
|---|
| 454 | if (/^mtplugin.pkg$/) { |
|---|
| 455 | my $file = File::Spec->catfile($tmp_dir,$_); |
|---|
| 456 | debug("Found ".$File::Find::name); |
|---|
| 457 | open FILE,$File::Find::name or die "Could not open file: $!"; |
|---|
| 458 | $data = join('',<FILE>); |
|---|
| 459 | close FILE; |
|---|
| 460 | my ($cfg) = XMLin($data); |
|---|
| 461 | $package = $app->process_package($cfg,$tmp_dir,$force); |
|---|
| 462 | $package->{raw_data} = $data; |
|---|
| 463 | debug("Successfully installed plugin."); |
|---|
| 464 | } |
|---|
| 465 | }, |
|---|
| 466 | $tmp_dir); |
|---|
| 467 | if (!$package) { |
|---|
| 468 | return $app->errtrans("Error processing plugin descriptor."); |
|---|
| 469 | } |
|---|
| 470 | eval { |
|---|
| 471 | File::Copy::Recursive::pathrm($tmp_dir,1); |
|---|
| 472 | }; |
|---|
| 473 | if ($@) { |
|---|
| 474 | return $app->errtrans("Could not clean up after plugin installation: $@"); |
|---|
| 475 | } |
|---|
| 476 | return $package; |
|---|
| 477 | } |
|---|
| 478 | |
|---|
| 479 | sub install_plugin { |
|---|
| 480 | my $app = shift; |
|---|
| 481 | my $q = $app->{query}; |
|---|
| 482 | |
|---|
| 483 | my $file = $q->param('uploaded_plugin'); |
|---|
| 484 | my $url = $q->param('url'); |
|---|
| 485 | |
|---|
| 486 | my ($tmp_dir,$tmp_file) = $app->create_tmp_file(); |
|---|
| 487 | |
|---|
| 488 | if ($url) { |
|---|
| 489 | debug("User specified a URL for installation: $url"); |
|---|
| 490 | my $link = extract_linkrel($url,'mt-installer'); |
|---|
| 491 | my $content = get($link); |
|---|
| 492 | my ($mti) = XMLin($content); |
|---|
| 493 | $url = $mti->{download_url}; |
|---|
| 494 | |
|---|
| 495 | # get the data |
|---|
| 496 | debug("Fetching data."); |
|---|
| 497 | is_success(getstore($url, $tmp_file)) |
|---|
| 498 | or return $app->errtrans("Download failed ($url): $@"); |
|---|
| 499 | |
|---|
| 500 | } elsif ($file) { |
|---|
| 501 | debug("User uploaded a file: ".$q->param('uploaded_plugin')); |
|---|
| 502 | my $fh = $q->upload('uploaded_plugin'); |
|---|
| 503 | open UPLOADFILE, ">$tmp_file"; |
|---|
| 504 | binmode UPLOADFILE; |
|---|
| 505 | while ( <$fh> ){ |
|---|
| 506 | print UPLOADFILE; |
|---|
| 507 | } |
|---|
| 508 | close UPLOADFILE; |
|---|
| 509 | |
|---|
| 510 | } else { |
|---|
| 511 | debug("Fetching data."); |
|---|
| 512 | # no file specified |
|---|
| 513 | } |
|---|
| 514 | |
|---|
| 515 | debug("Calling handle_install($tmp_dir,$tmp_file)"); |
|---|
| 516 | my $package = $app->handle_install($tmp_dir,$tmp_file); |
|---|
| 517 | |
|---|
| 518 | # use Data::Dumper; |
|---|
| 519 | # debug("package=".Dumper($package)); |
|---|
| 520 | |
|---|
| 521 | my $plugin; |
|---|
| 522 | $plugin = PluginManager::Plugin->new; |
|---|
| 523 | $plugin->name($package->{name}); |
|---|
| 524 | $plugin->sig($package->{sig}); |
|---|
| 525 | $plugin->icon($package->{icon}->{content}); |
|---|
| 526 | $plugin->config($package->{raw_data}); |
|---|
| 527 | $plugin->url($package->{version_url}); |
|---|
| 528 | $plugin->save or |
|---|
| 529 | return $app->error("Error adding plugin: " . $plugin->errstr); |
|---|
| 530 | |
|---|
| 531 | $q->param('blog_id' => $app->{query}->param('blog_id')); |
|---|
| 532 | $q->param('url' => $url); |
|---|
| 533 | $q->param('plugin' => $package->{name}); |
|---|
| 534 | $app->redirect($app->{cfg}->CGIPath . "plugins/PluginManager/plugins.cgi?__mode=list"); |
|---|
| 535 | } |
|---|
| 536 | |
|---|
| 537 | sub process_package { |
|---|
| 538 | my ($app,$cfg,$tmp_dir,$force) = @_; |
|---|
| 539 | my $plugin = PluginManager::Plugin->load( { |
|---|
| 540 | sig => $cfg->{sig} |
|---|
| 541 | } ); |
|---|
| 542 | |
|---|
| 543 | # use Data::Dumper; |
|---|
| 544 | # debug(Dumper($cfg)); |
|---|
| 545 | |
|---|
| 546 | if ($plugin && !$force) { |
|---|
| 547 | die "It appears this plugin has already been installed."; |
|---|
| 548 | } |
|---|
| 549 | |
|---|
| 550 | my $data = MT::PluginData->load({ plugin => 'PluginManager', |
|---|
| 551 | key => 'static-path' }); |
|---|
| 552 | my $static_path = $data->data; |
|---|
| 553 | |
|---|
| 554 | my $files = $cfg->{files}->{file}; |
|---|
| 555 | foreach my $file (@$files) { |
|---|
| 556 | my $filename = File::Spec->catfile($tmp_dir,$file->{src}); |
|---|
| 557 | debug("Processing $filename"); |
|---|
| 558 | my $destination; |
|---|
| 559 | if ($file->{static}) { |
|---|
| 560 | $destination = File::Spec->catfile($static_path, |
|---|
| 561 | $file->{destination}); |
|---|
| 562 | } else { |
|---|
| 563 | $destination = File::Spec->catfile(MT->instance->mt_dir, |
|---|
| 564 | $file->{destination}); |
|---|
| 565 | } |
|---|
| 566 | $destination = scrub_path($destination); |
|---|
| 567 | if (-d $filename) { |
|---|
| 568 | debug("Processing directory: ".$file->{src}); |
|---|
| 569 | File::Copy::Recursive::pathmk($destination) |
|---|
| 570 | or die "Plugin Manager failed to create the directory tree for $destination: $!\n"; |
|---|
| 571 | if (!(-w $destination)) { |
|---|
| 572 | debug("File is not writable: $destination"); |
|---|
| 573 | die "The directory that Plugin Manager is trying to write to is not writable by the web server: $destination\n"; |
|---|
| 574 | } |
|---|
| 575 | dircopy($filename,$destination) or die "Could not copy $filename into directory $destination: $!"; |
|---|
| 576 | if ($file->{permissions}) { |
|---|
| 577 | chmod(oct($file->{permissions}),$destination); |
|---|
| 578 | } |
|---|
| 579 | } elsif (-f $filename) { |
|---|
| 580 | debug("Processing file: ".$file->{src}); |
|---|
| 581 | my $destdir = dirname($destination); |
|---|
| 582 | File::Copy::Recursive::pathmk($destdir); |
|---|
| 583 | if (!(-w $destdir)) { |
|---|
| 584 | debug("Directory is not writable: $destdir"); |
|---|
| 585 | die "The directory that Plugin Manager is trying to write to is not writable by the web server: $destdir"; |
|---|
| 586 | } |
|---|
| 587 | debug("Copying $filename to $destination"); |
|---|
| 588 | copy($filename,$destination) or die $!; |
|---|
| 589 | if ($file->{permissions}) { |
|---|
| 590 | chmod(oct($file->{permissions}),$destination); |
|---|
| 591 | } |
|---|
| 592 | } |
|---|
| 593 | } |
|---|
| 594 | return $cfg; |
|---|
| 595 | } |
|---|
| 596 | |
|---|
| 597 | sub in_array { |
|---|
| 598 | my ($needle,@haystack) = @_; |
|---|
| 599 | foreach my $e (@haystack) { |
|---|
| 600 | if ($e eq $needle) { |
|---|
| 601 | return 1; |
|---|
| 602 | } |
|---|
| 603 | } |
|---|
| 604 | return 0; |
|---|
| 605 | } |
|---|
| 606 | |
|---|
| 607 | sub init_tmpl { |
|---|
| 608 | my $app = shift; |
|---|
| 609 | # PluginManager::Util::debug("Initializing template file."," >"); |
|---|
| 610 | # PluginManager::Util::debug("Calling MT::App::load_tmpl(".join(", ",@_).")"," >"); |
|---|
| 611 | my $tmpl = $app->load_tmpl(@_); |
|---|
| 612 | if (!$tmpl) { |
|---|
| 613 | my $err = $app->translate("Loading template '[_1]' ". |
|---|
| 614 | "failed: [_2]", |
|---|
| 615 | $_[0], $@); |
|---|
| 616 | # PluginManager::Util::debug($err," >"); |
|---|
| 617 | return $app->error($err); |
|---|
| 618 | } else { |
|---|
| 619 | # PluginManager::Util::debug("Template file successfully loaded."," >"); |
|---|
| 620 | } |
|---|
| 621 | |
|---|
| 622 | $tmpl->param(plugin_name => "Plugin Manager"); |
|---|
| 623 | $tmpl->param(plugin_version => $MT::Plugin::PluginManager::VERSION); |
|---|
| 624 | $tmpl->param(plugin_author => "Byrne Reese"); |
|---|
| 625 | $tmpl->param(page_titles => [ reverse @{ $app->{breadcrumbs} } ]); |
|---|
| 626 | |
|---|
| 627 | return $tmpl; |
|---|
| 628 | } |
|---|
| 629 | |
|---|
| 630 | 1; |
|---|