root/branches/athena/lib/MT/BackupRestore/BackupFileHandler.pm @ 1092

Revision 1092, 9.9 kB (checked in by hachi, 2 years ago)

Merging release-15 to athena branch. svn merge -r59987:60375 http://svn.sixapart.com/repos/eng/movabletype/branches/release-15 .

  • Property svn:keywords set to Id Author Date Revision
Line 
1# Copyright 2001-2006 Six Apart. This code cannot be redistributed without
2# permission from www.sixapart.com.  For more information, consult your
3# Movable Type license.
4#
5# $Id$
6
7package MT::BackupRestore::BackupFileHandler;
8
9use strict;
10use XML::SAX::Base;
11
12@MT::BackupRestore::BackupFileHandler::ISA = qw(XML::SAX::Base);
13
14sub new {
15    my $class = shift;
16    my (%param) = @_;
17    my $self = bless \%param, $class;
18    return $self;
19}
20
21sub start_document {
22    my $self = shift;
23    my $data = shift;
24
25    $self->{start} = 1;
26
27    1;
28}
29
30sub start_element {
31    my $self = shift;
32    my $data = shift;
33
34    return if $self->{skip};
35
36    my $name = $data->{LocalName};
37    my $attrs = $data->{Attributes};
38    my $ns = $data->{NamespaceURI};
39
40    if ($self->{start}) {
41        die MT->translate('Uploaded file was not a valid Movable Type backup manifest file.')
42            if !(('movabletype' eq $name) && (MT::BackupRestore::NS_MOVABLETYPE() eq $ns));
43        unless ($self->{ignore_schema_conflicts}) {
44            my $schema = $attrs->{'{}schema_version'}->{Value};
45            if (('ignore' ne $self->{schema_version}) && ($schema > $self->{schema_version})) {
46                $self->{critical} = 1;
47                die MT->translate('Uploaded file was backed up from Movable Type with the newer schema version ([_1]) than the one in this system ([_2]).  It is not safe to restore the file to this version of Movable Type.', $schema, $self->{schema_version})
48               
49            }
50        }
51        $self->{start} = 0;
52        return 1;
53    }
54
55    my $objects = $self->{objects};
56    my $deferred = $self->{deferred};
57    my $callback = $self->{callback};
58
59    if (my $current = $self->{current}) {
60        # this is an element for a text column of the object
61        $self->{current_text} = [ $name ];
62    } else {
63        if (MT::BackupRestore::NS_MOVABLETYPE() eq $ns) {
64            my $class = MT->model($name);
65            unless ($class) {
66                push @{$self->{errors}}, MT->translate('[_1] is not a subject to be restored by Movable Type.', $name);
67            } else {
68                if ($self->{current_class} ne $class) {
69                    if (my $c = $self->{current_class}) {
70                        my $state = $self->{state};
71                        my $records = $self->{records};
72                        $callback->($state . " " . MT->translate("[_1] records restored.", $records), $c->class_type || $c->datasource);
73                    }
74                    $self->{records} = 0;
75                    $self->{current_class} = $class;
76                    my $state = MT->translate('Restoring [_1] records:', $class);
77                    $callback->($state, $name);
78                    $self->{state} = $state;
79                }
80                my %column_data = map { $attrs->{$_}->{LocalName} => 
81                        MT::I18N::encode_text(MT::I18N::utf8_off($attrs->{$_}->{Value}), 'utf-8')
82                    } keys(%$attrs);
83                my $obj;
84                if ( 'author' eq $name ) {
85                    $obj = $class->load({ name => $column_data{name} });
86                    if ($obj) {
87                        if ( $obj->id == MT->instance->user->id ) {
88                            MT->log({ message => MT->translate(
89                                "User with the same name as the name of the currently logged in ([_1]) found.  Skipped the record.", $obj->name),
90                                level => MT::Log::INFO(),
91                                metadata => 'Permissions and Associations have been restored.',
92                                class => 'system',
93                                category => 'restore',
94                            });
95                            $objects->{"$class#" . $column_data{id}} = $obj;
96                            $self->{skip} += 1;
97                        }
98                        else {
99                            $self->{callback}->("\n");
100                            MT->log({ message => MT->translate(
101                                "User with the same name '[_1]' found (ID:[_2]).  Restore replaced this user with the data backed up.",
102                                                  $obj->name, $obj->id),
103                                level => MT::Log::INFO(),
104                                metadata => 'Permissions and Associations have been restored as well.',
105                                class => 'system',
106                                category => 'restore',
107                            });
108                            my $old_id = delete $column_data{id};
109                            $objects->{"$class#$old_id"} = $obj;
110                            my $child_classes = $obj->properties->{child_classes} || {};
111                            for my $class (keys %$child_classes) {
112                                eval "use $class;";
113                                $class->remove({ author_id => $obj->id, blog_id => '0' });
114                            }
115                            $self->{loaded} = 1;
116                        }
117                    }
118                }
119                unless ($obj) {
120                    $obj = $class->new;
121                }
122                my $success = $obj->restore_parent_ids(\%column_data, $objects);
123                if ($success) {
124                    $obj->set_values(\%column_data);
125                    $self->{current} = $obj;
126                } else {
127                    $deferred->{$class . '#' . $column_data{id}} = 1;
128                    $self->{deferred} = $deferred;
129                    $self->{skip} += 1;
130                }
131            }
132        } else {
133            my $obj = MT->run_callbacks("Restore.$name:$ns", $data, $objects, $deferred, $callback);
134            $self->{current} = $obj if defined($obj) && ('1' ne $obj);
135        }
136    }
137    1;
138}
139
140sub characters {
141    my $self = shift;
142    my $data = shift;
143
144    return if $self->{skip};
145    return if !exists($self->{current});
146    if (my $text_data = $self->{current_text}) {
147        push @$text_data, MT::I18N::utf8_off($data->{Data});
148        $self->{current_text} = $text_data;
149    }
150    1;
151}
152
153sub end_element {
154    my $self = shift;
155    my $data = shift;
156
157    if ($self->{skip}) {
158        $self->{skip} -= 1;
159        return;
160    }
161
162    my $name = $data->{LocalName};
163    my $class = MT->model($name);
164
165    if (my $obj = $self->{current}) {
166        if (my $text_data = delete $self->{current_text}) {
167            my $column_name = shift @$text_data;
168            my $text;
169            $text .= $_ foreach @$text_data;
170           
171            my $defs = $obj->column_defs;
172            if ('blob' eq $defs->{$column_name}->{type}) {
173                require MIME::Base64;
174                $obj->column($column_name, MIME::Base64::decode_base64($text));
175            } else {
176                $text = MT::I18N::encode_text($text, 'utf-8');
177                $obj->column($column_name, $text);
178            }
179        } else {
180            my $old_id = $obj->id;
181            unless (('author' eq $name) && (exists $self->{loaded})) {
182                delete $obj->{column_values}->{id};
183                delete $obj->{changed_cols}->{id};
184            } else {
185                delete $self->{loaded};
186            }
187            my $exists = 0;
188            if ('tag' eq $name) {
189                if (my $tag = MT::Tag->load({ name => $obj->name }, { binary => { name => 1 } } )) {
190                    $exists = 1;
191                    $self->{objects}->{"$class#$old_id"} = $tag;
192                    $self->{callback}->(
193                        MT->translate("Tag '[_1]' exists in the system.",
194                            $obj->name)
195                    );
196                    $self->{callback}->("\n");
197                }
198            } elsif ('trackback' eq $name) {
199                my $term;
200                my $message;
201                if ($obj->entry_id) {
202                    $term = { entry_id => $obj->entry_id };
203                } elsif ($obj->category_id) {
204                    $term = { category_id => $obj->category_id };
205                }
206                if (my $tb = $class->load($term)) {
207                    $exists = 1;
208                    my $changed = 0;
209                    if ($obj->passphrase) {
210                        $tb->passphrase($obj->passphrase);
211                        $changed = 1;
212                    }
213                    if ($obj->is_disabled) {
214                        $tb->is_disabled($obj->is_disabled);
215                        $changed = 1;
216                    }
217                    $tb->save if $changed;
218                    $self->{objects}->{"$class#$old_id"} = $tb;
219                    my $records = $self->{records};
220                    $self->{callback}->($self->{state} . " " . MT->translate("[_1] records restored...", $records), $data->{LocalName})
221                        if $records && ($records % 10 == 0);
222                    $self->{records} = $records + 1;
223                }
224            }
225            unless ($exists) {
226                if ($obj->save()) {
227                    if ($class =~ /MT::Asset(::.+)*/) {
228                        $class = 'MT::Asset';
229                    }
230                    $self->{objects}->{"$class#$old_id"} = $obj;
231                    my $records = $self->{records};
232                    $self->{callback}->($self->{state} . " " . MT->translate("[_1] records restored...", $records), $data->{LocalName})
233                        if $records && ($records % 10 == 0);
234                    $self->{records} = $records + 1;
235                } else {
236                    push @{$self->{errors}}, $obj->errstr;
237                    $self->{callback}->($obj->errstr);
238                }
239            }
240            delete $self->{current};
241        }
242    }
243}
244
245sub end_document {
246    my $self = shift;
247    my $data = shift;
248
249    if (my $c = $self->{current_class}) {
250        my $state = $self->{state};
251        my $records = $self->{records};
252        $self->{callback}->($state . " " . MT->translate("[_1] records restored.", $records), $c->class_type || $c->datasource);
253    }
254
255    1;
256}
257
2581;
Note: See TracBrowser for help on using the browser.