Changeset 809

Show
Ignore:
Timestamp:
11/30/06 12:21:06 (2 years ago)
Author:
fumiakiy
Message:

Implemented assets backup and restore. BugId: 45484

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/wheeljack/lib/MT/App/CMS.pm

    r806 r809  
    152152        'backup' => \&backup, 
    153153        'restore' => \&restore, 
    154         'backup_download' => \&backup_download, 
    155154        'restore_upload_manifest' => \&restore_upload_manifest, 
    156155        'dialog_restore_upload' => \&dialog_restore_upload, 
     
    1082510824sub _loop_through_objects { 
    1082610825    my $app = shift; 
    10827     my ($printer, $splitter, $number, $obj_to_backup) = @_; 
     10826    my ($printer, $splitter, $number, $obj_to_backup, $files) = @_; 
    1082810827 
    1082910828    my $counter = 0; 
     
    1084510844                    $splitter->(int($counter / $number + 1)); 
    1084610845                } 
    10847                 $printer->($object->to_xml . "\n") if $object->to_backup; 
     10846                if ($class eq 'MT::Asset') { 
     10847                    $printer->($object->to_xml . "\n") if $object->to_backup; 
     10848                    $files->{$object->id} = [$object->url, $object->file_path, $object->file_name]; 
     10849                } else { 
     10850                    $printer->($object->to_xml . "\n") if $object->to_backup; 
     10851                } 
    1084810852                my $xml = MT->run_callbacks('CMSBackup.' . $object->datasource, $app, $object) 
    1084910853                    or $printer->($app->error(MT->errstr())); 
     
    1088210886    } 
    1088310887 
     10888    require MT::Asset; 
     10889    my $num_assets = MT::Asset->count(); 
    1088410890    my $printer; 
    1088510891    my $splitter; 
     
    1088710893    my $fh; 
    1088810894    my $arc_buf; 
    10889     if (!$number) { 
     10895    if (!($number || $num_assets)) { 
    1089010896        $app->{no_print_body} = 1; 
    1089110897        $splitter = sub {}; 
     
    1089510901                                        : 'text/xml'); 
    1089610902            $printer = sub { $app->print(@_); }; 
    10897             $finisher = sub {}; 
     10903            $finisher = sub { my ($asset_files) = @_; 1; }; 
    1089810904        } elsif ('1' eq $archive) { # tar.gz 
    1089910905            require Archive::Tar; 
     
    1090310909            $printer = sub { $arc_buf .= $_[0]; }; 
    1090410910            $finisher = sub { 
     10911                my ($asset_files) = @_; 
    1090510912                my $arc = Archive::Tar->new; 
    1090610913                $arc->add_data("$file.xml", $arc_buf); 
     10914                $arc->add_data( 
     10915                    "$file.manifest", 
     10916                    "<manifest xmlns='" . NS_MOVABLETYPE . "'><file type='backup' name='$file.xml' /></manifest>");  
    1090710917                require Compress::Zlib; 
    1090810918                my $dest = Compress::Zlib::memGzip($arc->write); 
     
    1091510925            $printer = sub { $arc_buf .= $_[0]; }; 
    1091610926            $finisher = sub { 
     10927                my ($asset_files) = @_; 
    1091710928                my $arc = Archive::Zip->new; 
    1091810929                $arc->addString($arc_buf, "$file.xml"); 
     10930                $arc->addString( 
     10931                    "<manifest xmlns='" . NS_MOVABLETYPE . "'><file type='backup' name='$file.xml' /></manifest>",  
     10932                    "$file.manifest"); 
    1091910933                my $buf; 
    1092010934                require IO::String; 
     
    1094510959        }; 
    1094610960        $finisher = sub { 
     10961            my ($asset_files) = @_; 
    1094710962            close $fh; 
    1094810963            my $filename = File::Spec->catfile($temp_dir, "$file.manifest"); 
     
    1095310968                my $name = $file->{filename}; 
    1095410969                print $fh "<file type='backup' name='$name' />\n"; 
     10970            } 
     10971            for my $id (keys %$asset_files) { 
     10972                print $fh "<file type='asset' name='$asset_files->{$id}->[2]' asset_id='" . $id . "' />\n"; 
     10973                push @files, { 
     10974                    filename => $asset_files->{$id}->[2],  
     10975                    url=> $asset_files->{$id}->[0],  
     10976                    path => $asset_files->{$id}->[1], 
     10977                    asset_id => $id, 
     10978                }; 
    1095510979            } 
    1095610980            print $fh "</manifest>\n"; 
     
    1097010994                my $arc = Archive::Tar->new; 
    1097110995                for my $f (@files) { 
    10972                     $arc->add_files(File::Spec->catfile($temp_dir, $f->{filename})); 
     10996                    if (defined $f->{path}) { 
     10997                        my @arc_files = $arc->add_files($f->{path}); 
     10998                        $arc_files[0]->rename($f->{asset_id} . '-' . $f->{filename}) if scalar(@arc_files); 
     10999                    } else { 
     11000                        my $tmp_filename = File::Spec->catfile($temp_dir, $f->{filename}); 
     11001                        my @arc_files = $arc->add_files($tmp_filename); 
     11002                        $arc_files[0]->rename($f->{filename}); 
     11003                        unlink $tmp_filename; 
     11004                    } 
    1097311005                } 
    1097411006                require Compress::Zlib; 
     
    1098511017                $app->send_http_header('application/zip'); 
    1098611018                for my $f (@files) { 
    10987                     $arc->addFile(File::Spec->catfile($temp_dir, $f->{filename}), $f->{filename}); 
     11019                    if (defined $f->{path}) { 
     11020                        $arc->addFile($f->{path}, $f->{asset_id} . '-' . $f->{filename}); 
     11021                    } else { 
     11022                        my $tmp_filename = File::Spec->catfile($temp_dir, $f->{filename}); 
     11023                        $arc->addFile($tmp_filename, $f->{filename}); 
     11024                    } 
    1098811025                } 
    1098911026                my $buf; 
     
    1099111028                my $ios = IO::String->new(\$buf); 
    1099211029                $arc->writeToFileHandle($ios); 
     11030                for my $f (@files) { 
     11031                    unlink File::Spec->catfile($temp_dir, $f->{filename}) if !defined($f->{path}); 
     11032                } 
    1099311033                $app->print($buf); 
    1099411034            } 
     
    1101011050    $printer->($header); 
    1101111051 
    11012     $app->_loop_through_objects($printer, $splitter, $number, \@obj_to_backup); 
     11052    my $files = {}; 
     11053    $app->_loop_through_objects($printer, $splitter, $number, \@obj_to_backup, $files); 
    1101311054 
    1101411055    $printer->('</movabletype>'); 
    11015     $finisher->(); 
     11056    $finisher->($files); 
    1101611057} 
    1101711058 
     
    1103211073 
    1103311074    $app->errtrans("Not implemented yet"); 
    11034 } 
    11035  
    11036 sub backup_download { 
    11037     my $app = shift; 
    11038     my $user = $app->user; 
    11039  
    11040     return $app->errtrans("Permission denied.") if !$user->is_superuser; 
    11041     $app->validate_magic() or return; 
    11042  
    11043     my $file = $app->param('file'); 
    11044     return $app->errtrans("Filename is needed to download.") if !defined($file) || !$file; 
    11045     my $temp_dir = $app->config('TempDir'); 
    11046     my $filename = File::Spec->catfile($temp_dir, $file); 
    11047  
    11048     return $app->errtrans("[_1] is not found.", $file) if (!(-f $filename)); 
    11049          
    11050     my $enc = $app->config('PublishCharset') || 'utf-8'; 
    11051     $app->{no_print_body} = 1; 
    11052     $app->set_header("Content-Disposition" => "attachment; filename=$file"); 
    11053     $app->send_http_header($enc ? "text/xml; charset=$enc" 
    11054                                     : 'text/xml'); 
    11055     my $fh = gensym(); 
    11056     open $fh, "<$filename"; 
    11057     my $data; 
    11058     binmode $fh; 
    11059     while (read $fh, my($chunk), 8192) { 
    11060         $data .= $chunk; 
    11061     } 
    11062     close $fh; 
    11063     $app->print($data); 
    11064     1; 
    1106511075} 
    1106611076 
     
    1113411144                my $tar = Archive::Tar->new($ios); 
    1113511145                for my $file ($tar->list_files) { 
    11136                     my ($vol, $dir, $fn) = File::Spec->splitpath($file); 
    11137                     my $f = File::Spec->catfile($tmp, $fn); 
     11146                    my $f = File::Spec->catfile($tmp, $file); 
    1113811147                    $tar->extract_file($file, $f); 
    1113911148                } 
     
    1128611295} 
    1128711296 
     11297sub _restore_asset { 
     11298    my $app = shift; 
     11299    my ($tmp, $asset_element, $objects, $errors) = @_; 
     11300 
     11301    my $id = $asset_element->{asset_id}; 
     11302    next if !defined($id); 
     11303    next if !(exists $objects->{"MT::Asset#$id"}); 
     11304    my $asset = $objects->{"MT::Asset#$id"}; 
     11305    my $path = $asset->file_path; 
     11306    next if !defined($path); 
     11307    my ($vol, $dir, $fn) = File::Spec->splitpath($path); 
     11308    if (!-w "$vol$dir") { 
     11309        $errors->{$id} = $app->translate('[_1] is not writable.', "$vol$dir"); 
     11310        next; 
     11311    } 
     11312    my $filename = "$id-" . $asset_element->{name}; 
     11313    $app->print($app->translate("Copying [_1] to [_2]...", $filename, $path)); 
     11314    my $file; 
     11315    if (defined($tmp)) { 
     11316        $file = File::Spec->catfile($tmp, $filename) if defined($tmp); 
     11317    } else { 
     11318        $file = $asset_element->{fh}; 
     11319    } 
     11320    copy($file, $path) 
     11321        or $errors->{$id} = $!; 
     11322    $app->print(exists($errors->{$id}) ? 
     11323        $app->translate("Failed: [_1]\n", $errors->{$id}) : 
     11324        $app->translate("Done.\n") 
     11325    ); 
     11326} 
     11327 
     11328sub _restore_assets { 
     11329    my $app = shift; 
     11330    my ($tmp, $backups, $objects) = @_; 
     11331    my $assets = $backups->{assets}; 
     11332    my $errors = {}; 
     11333    return $errors if !defined($assets); 
     11334    use File::Copy; 
     11335    require File::Spec; 
     11336    for my $asset_element (@$assets) { 
     11337        $app->_restore_asset($tmp, $asset_element, $objects, $errors); 
     11338    } 
     11339    $errors; 
     11340} 
     11341 
    1128811342sub restore_directory { 
    1128911343    my $app = shift; 
     
    1134811402        close $fh; 
    1134911403    } 
     11404     
     11405    my $error_assets = $app->_restore_assets($dir, $backups, \%objects) if defined($backups->{assets}); 
     11406 
     11407    if (defined($error_assets) && scalar(keys %$error_assets)) { 
     11408        my $data; 
     11409        while (my ($key, $value) = each %$error_assets) { 
     11410            $data .= $app->translate("Actual file for an asset (ID: [_1]) could not be restored: [_2]\n", $key, $value); 
     11411        } 
     11412        my $message = 'Some of the actual files for assets could not be restored.'; 
     11413        $app->log({ 
     11414            message => $message, 
     11415            level => MT::Log::WARNING(), 
     11416            class => 'system', 
     11417            category => 'restore', 
     11418            metadata => $data, 
     11419        }); 
     11420        $$error .= $message; 
     11421    }     
    1135011422 
    1135111423    if (scalar(keys %deferred)) { 
     
    1136311435        }); 
    1136411436        my $log_url = $app->uri(mode => 'view_log', args => {}); 
    11365         $$error = $message . '  ' 
     11437        $$error .= $message . '  ' 
    1136611438            . $app->translate('Detailed information is in the <a href="[_1]">activity log</a>.', $log_url); 
    11367         return 0; 
    11368     } 
     11439    } 
     11440 
     11441    return 0 if $$error; 
    1136911442 
    1137011443    $app->log({ 
     
    1140211475                    push @{$backups->{files}}, $node->getAttribute('name'); 
    1140311476                } elsif ('asset' eq $node->getAttribute('type')) { 
    11404                     push @{$backups->{assets}}, $node->getAttribute('name'); 
     11477                    push @{$backups->{assets}}, {  
     11478                        name => $node->getAttribute('name'), 
     11479                        asset_id => $node->getAttribute('asset_id'), 
     11480                    }; 
    1140511481                } 
    1140611482            } 
     
    1144111517    my $assets = $backups->{assets}; 
    1144211518    my $file_next = shift @$files if defined($files) && scalar(@$files); 
     11519    my $assets_json; 
     11520    my $param = {}; 
    1144311521    if (!defined($file_next)) { 
    11444         $file_next = shift @$assets if defined($assets) && scalar(@$assets); 
    11445     } 
    11446     my $param = { 
    11447         'files' => join(',', @$files), 
    11448         'assets' => join(',', @$assets), 
    11449         'filename' => $file_next, 
    11450         'open_dialog' => 1, 
    11451     }; 
     11522        if (scalar(@$assets)) { 
     11523            my $asset = shift @$assets; 
     11524            $file_next = $asset->{name}; 
     11525            $param->{is_asset} = 1; 
     11526        } 
     11527    } 
     11528    require JSON; 
     11529    $assets_json = MT::Util::encode_html(JSON::objToJson($assets)) if scalar(@$assets); 
     11530    $param->{files} = join(',', @$files); 
     11531    $param->{assets} = $assets_json; 
     11532    $param->{filename} = $file_next; 
     11533    $param->{open_dialog} = 1; 
     11534 
    1145211535    $app->build_page('backup_restore.tmpl', $param); 
    1145311536    #close $fh if !$no_upload; 
     
    1146511548    my $last = $q->param('last'); 
    1146611549    my $files = $q->param('files'); 
    11467     my $assets = $q->param('assets'); 
     11550    my $assets_json = $q->param('assets'); 
     11551    my $is_asset = $q->param('is_asset') || 0; 
    1146811552 
    1146911553    my $objects = {}; 
     
    1148811572 
    1148911573    my $param = {}; 
     11574    $param->{is_asset} = $is_asset; 
    1149011575    $param->{name} = $current; 
    1149111576    $param->{files} = $files; 
    11492     $param->{assets} = $assets; 
    11493     $param->{name} = $current; 
     11577    $param->{assets} = $assets_json; 
    1149411578    $param->{last} = $last; 
    1149511579    $param->{redirect} = 1; 
     
    1156011644    } 
    1156111645 
    11562     my $result = $app->_restore_process_single_file( 
    11563         $fh, \@obj_to_restore, $objects, $deferred, \$error); 
     11646    my $assets = JSON::jsonToObj(MT::Util::decode_html($assets_json)) if defined($assets_json); 
     11647    my $asset; 
     11648    if ($is_asset) { 
     11649        $asset = shift @$assets; 
     11650        my $error_assets = {}; 
     11651        $asset->{fh} = $fh; 
     11652        $app->_restore_asset(undef, $asset, $objects, $error_assets); 
     11653        if (defined($error_assets->{$asset->{asset_id}})) { 
     11654            $app->log({ 
     11655                message => $app->translate('Restoring an actual file for an asset failed: [_1]', $error_assets->{$asset->{asset_id}}), 
     11656                level => MT::Log::WARNING(), 
     11657                class => 'system', 
     11658                category => 'restore', 
     11659            }); 
     11660        } 
     11661    } else { 
     11662        $app->_restore_process_single_file( 
     11663            $fh, \@obj_to_restore, $objects, $deferred, \$error); 
     11664    } 
    1156411665 
    1156511666    my @files = split(',', $files); 
    11566     my @assets; 
    1156711667    my $file_next = shift @files if scalar(@files); 
    1156811668    if (!defined($file_next)) { 
    11569         @assets = split(',', $assets); 
    11570         $file_next = shift @assets if scalar(@assets); 
     11669        if (scalar(@$assets)) { 
     11670            $asset = $assets->[0]; 
     11671            $file_next = $asset->{asset_id} . '-' . $asset->{name}; 
     11672            $param->{is_asset} = 1; 
     11673        } 
    1157111674    } 
    1157211675 
    1157311676    $param->{files} = join(',', @files); 
    11574     $param->{assets} = join(',', @assets); 
     11677    $param->{assets} = MT::Util::encode_html(JSON::objToJson($assets)); 
    1157511678    $param->{name} = $file_next; 
    11576     $param->{last} = (scalar(@files) || scalar(@assets)) ? 0 : 1; 
     11679    $param->{last} = (scalar(@files) || (scalar(@$assets) - 1)) ? 0 : 1; 
    1157711680    $param->{is_dirty} = scalar(keys %$deferred); 
    1157811681    if ($last) { 
  • branches/wheeljack/tmpl/cms/backup_files.tmpl

    r795 r809  
    2828<tr class="<TMPL_IF __ODD__>odd<TMPL_ELSE>even</TMPL_IF>"> 
    2929<td><TMPL_VAR NAME=FILENAME></td> 
    30 <td class="status-view"><a href="<TMPL_VAR NAME=SCRIPT_URL>?__mode=backup_download&amp;magic_token=<TMPL_VAR NAME=MAGIC_TOKEN>&amp;file=<TMPL_VAR NAME=FILENAME ESCAPE=URL>" target="<MT_TRANS phrase="_external_link_target">" title="<MT_TRANS phrase="Download This File">"><img src="<TMPL_VAR NAME=STATIC_URI>images/spacer.gif" alt="<MT_TRANS phrase="Download This File">" width="13" height="9" /></a></td> 
     30<td class="status-view"><TMPL_IF NAME=URL><a href="<TMPL_VAR NAME=URL>" target="<MT_TRANS phrase="_external_link_target">" title="<MT_TRANS phrase="Download This File">"><img src="<TMPL_VAR NAME=STATIC_URI>images/spacer.gif" alt="<MT_TRANS phrase="Download This File">" width="13" height="9" /></a><TMPL_ELSE>&nbsp;</TMPL_IF></td> 
    3131</tr> 
    3232</TMPL_LOOP> 
  • branches/wheeljack/tmpl/cms/dialog_restore_end.tmpl

    r800 r809  
    3838<input type="hidden" name="redirect" value="1" /> 
    3939<input type="hidden" name="is_dirty" value="<TMPL_VAR NAME=IS_DIRTY>" /> 
     40<input type="hidden" name="is_asset" value="<TMPL_VAR NAME=IS_ASSET>" /> 
    4041<input type="hidden" name="objects_json" value="<TMPL_VAR NAME=OBJECTS_JSON ESCAPE=HTML>" /> 
    4142<input type="hidden" name="deferred_json" value="<TMPL_VAR NAME=DEFERRED_JSON ESCAPE=HTML>" /> 
  • branches/wheeljack/tmpl/cms/dialog_restore_upload.tmpl

    r800 r809  
    5757<input type="hidden" name="magic_token" value="<TMPL_VAR NAME=MAGIC_TOKEN>" /> 
    5858<input type="hidden" name="files" value="<TMPL_VAR NAME=FILES>" /> 
    59 <input type="hidden" name="assets" value="<TMPL_VAR NAME=ASSETS>" /> 
     59<input type="hidden" name="assets" value="<TMPL_VAR NAME=ASSETS ESCAPE=HTML>" /> 
    6060<input type="hidden" name="current_file" value="<TMPL_VAR NAME=NAME>" /> 
    6161<input type="hidden" name="last" value="<TMPL_VAR NAME=LAST>" /> 
    6262<input type="hidden" name="is_dirty" value="<TMPL_VAR NAME=IS_DIRTY>" /> 
     63<input type="hidden" name="is_asset" value="<TMPL_VAR NAME=IS_ASSET>" /> 
    6364<input type="hidden" name="objects_json" value="<TMPL_VAR NAME=OBJECTS_JSON ESCAPE=HTML>" /> 
    6465<input type="hidden" name="deferred_json" value="<TMPL_VAR NAME=DEFERRED_JSON ESCAPE=HTML>" />