root/branches/boomer/plugins/WXRImporter/lib/WXRImporter/WXRHandler.pm @ 1104

Revision 1104, 25.0 kB (checked in by hachi, 2 years ago)

Merging release-24 to boomer branch: svn merge -r67670:69246 http://svn.sixapart.com/repos/eng/movabletype/branches/release-24 .

  • Property svn:keywords set to Author Date Id Revision
Line 
1# WXRImporter plugin for Movable Type
2# Author: Six Apart (http://www.sixapart.com)
3# Released under the Artistic License
4#
5# $Id$
6
7package WXRImporter::WXRHandler;
8
9use strict;
10use XML::SAX::Base;
11use Time::Local qw( timegm );
12use MT;
13use MT::Util qw( offset_time_list );
14
15@WXRImporter::WXRHandler::ISA = qw(XML::SAX::Base);
16
17use constant POST_SEPARATOR => '<!--more-->'; # WordPress's separator string
18
19sub new {
20    my $class = shift;
21    my (%param) = @_;
22    my $self = bless \%param, $class;
23    return $self;
24}
25
26sub start_document {
27    my $self = shift;
28    my $data = shift;
29
30    $self->{start} = 1;
31    $self->{basename_limit} = 255; # max length of the column
32
33    1;
34}
35
36sub start_element {
37    my $self = shift;
38    my $data = shift;
39
40    my $name = $data->{LocalName};
41    my $prefix = $data->{Prefix};
42    my $attrs = $data->{Attributes};
43    my $ns = $data->{NamespaceURI};
44
45    if (exists $self->{in_wp_comment_content}) {
46        # wordpress's comment content consists of mixed contents (tags and texts)...
47        my $element_data = '<' . $data->{Name};
48        for my $attr (keys %$attrs) {
49            $element_data .= ' ' . $attrs->{$attr}->{Name} . '=' . $attrs->{$attr}->{Value};
50        }
51        $element_data .= '>';
52        $data->{Data} = $element_data;
53        $self->characters($data);
54        return;
55    }
56
57    if ($self->{start}) {
58        die MT->translate("File is not in WXR format.")
59            unless (('rss' eq $name) && ('2.0' eq $attrs->{'{}version'}->{Value})); ## FIXME: This is checking RSS2.
60        $self->{start} = 0;
61        $self->{'bucket'} = [];
62        return 1;
63    }
64
65    my %values = map { $attrs->{$_}->{LocalName} => 
66            MT::I18N::encode_text(MT::I18N::utf8_off($attrs->{$_}->{Value}), 'utf-8')
67        } keys(%$attrs);
68
69    $self->{in_wp_comment_content} = 1 if ('wp' eq $prefix) && ('comment_content' eq $name);
70
71    push @{$self->{'bucket'}}, \%values if scalar(%values);
72    push @{$self->{'bucket'}}, $prefix . '_' . $name;
73    1;
74}
75
76sub characters {
77    my $self = shift;
78    my $data = shift;
79
80    return unless ($data->{Data} !~ /^\s+$/)
81        || (exists $self->{in_wp_comment_content}); # see if we need to process whitespaces
82
83    my $element = pop @{$self->{'bucket'}};
84    return unless $element;
85
86    my $chars = MT::I18N::utf8_off($data->{Data});
87    if ('HASH' eq ref($element)) {
88        my @hash_array = %$element;
89        return unless $hash_array[0];
90        my $val = $element->{$hash_array[0]};
91        $val .= $chars;
92        $element->{$hash_array[0]} = $val;
93    } elsif ($element) {
94        $element = { $element => $chars };
95    }
96    push @{$self->{'bucket'}}, $element;
97    1;
98}
99
100sub end_element {
101    my $self = shift;
102    my $data = shift;
103
104    my $name = $data->{LocalName};
105    my $prefix = $data->{Prefix};
106
107    if ((exists $self->{in_wp_comment_content}) && ('wp:comment_content' ne $data->{Name})) {
108        # wordpress's comment content consists of mixed contents (tags and texts)...
109        my $element_data = '</' . $data->{Name} . '>';
110        $data->{Data} = $element_data;
111        $self->characters($data);
112        return;
113    }
114    my $element = pop @{$self->{'bucket'}};
115    if ('HASH' eq ref($element)) {
116        $element->{$prefix . '_' . $name} = 
117            MT::I18N::encode_text($element->{$prefix . '_' . $name}, 'utf-8')
118                if exists $element->{$prefix . '_' . $name};
119    }
120    push @{$self->{'bucket'}}, $element;
121
122    my $name_element = $prefix . '_' . $name;
123    if ('_item' eq $name_element) {
124        $self->_create_item($data);
125    } elsif ('wp_postmeta' eq $name_element) {
126        $self->_setup_metadata($data);
127    } elsif ('wp_category' eq $name_element) {
128        $self->_create_category($data);
129    } elsif ('wp_comment' eq $name_element) {
130        $self->_create_feedback($data);
131    } elsif ('_channel' eq $name_element) {
132        $self->_update_blog($data);
133    } elsif ('wp_comment_content' eq $name_element) {
134        delete $self->{in_wp_comment_content};
135    }
136
137    1;
138}
139
140sub _setup_metadata {
141    my $self = shift;
142    my $data = shift;
143   
144    my $cb = $self->{callback};
145    my $blog = $self->{blog};
146
147    my $meta = {};
148    my $current_key;
149    my $current_value;
150    while (my $hash = pop @{$self->{'bucket'}}) {
151        last if 'wp_postmeta' eq $hash;
152        next if 'HASH' ne ref $hash;
153        my @hash_array = %$hash;
154        my $key = $hash_array[0];
155        my $value = $hash_array[1];
156        if ('wp_meta_key' eq $key) {
157            $current_key = $value;
158        } elsif ('wp_meta_value' eq $key) {
159            $current_value = $value;
160        }
161        if ($current_key && $current_value) {
162            $meta->{$current_key} = $current_value;
163            $current_key = $current_value = undef;
164        }
165    }
166    push @{$self->{'bucket'}}, { 'wp_postmeta' => $meta };
167}
168
169sub _update_blog {
170    my $self = shift;
171    my $data = shift;
172   
173    my $cb = $self->{callback};
174    my $blog = $self->{blog};
175
176    while (my $hash = pop @{$self->{'bucket'}}) {
177        last if '_channel' eq $hash;
178        next if 'HASH' ne ref $hash;
179        my @hash_array = %$hash;
180        my $key = $hash_array[0];
181        my $value = $hash_array[1];
182        if ('_description' eq $key) {
183            $blog->description($value) unless $blog->description;
184# Should we do these?
185#        } elsif ('_link' eq $key) {
186#            $blog->site_url($value) unless $blog->site_url;
187#        } elsif ('_title' eq $key) {
188#            $blog->name($value) if 'First Weblog' eq $blog->name;
189#        } elsif ('_language' eq $key) {
190#            $blog->language($value);
191        }
192    }
193    $blog->save;
194}
195
196sub _create_category {
197    my $self = shift;
198    my $data = shift;
199   
200    my $cb = $self->{callback};
201    my $blog = $self->{blog};
202
203    require MT::Category; ##FIXME: don't directly reference packages
204    my $cat = MT::Category->new;
205
206    while (my $hash = pop @{$self->{'bucket'}}) {
207        last if 'wp_category' eq $hash;
208        next if 'HASH' ne ref $hash;
209        my @hash_array = %$hash;
210        my $key = $hash_array[0];
211        my $value = $hash_array[1];
212        $cat->blog_id($blog->id);
213        if ('wp_category_nicename' eq $key) {
214            my $dash = MT->instance->config('CategoryNameNodash') ? '' : '-';
215            my $base = MT::Util::dirify(MT::Util::decode_url($value)) || ("cat" . $dash . $cat->id);
216            $base = substr($base, 0, $self->{basename_limit});
217            $base =~ s/_+$//;
218            $base = 'cat' if $base eq '';
219            my $i = 1;
220            my $base_copy = $base;
221            while (MT::Category->count({ blog_id => $blog->id,
222                                         basename => $base })) {
223                $base = $base_copy . '_' . $i++;
224            }
225            $cat->basename($base);
226        } elsif ('wp_category_parent' eq $key) {
227            my $parent = MT::Category->load(
228                { label => $value,
229                  blog_id => $self->{blog}->id });
230            $cat->parent($parent->id) if defined $parent;
231        } elsif ('wp_posts_private' eq $key) {
232            # skip
233        } elsif ('wp_posts_private' eq $key) {
234            # skip
235        } elsif ('wp_cat_name' eq $key) {
236            return if (MT::Category->load({ label => $value }));
237            $cat->label($value);
238        } elsif ('wp_category_description' eq $key) {
239            $cat->description($value);
240        }
241    }
242    if (defined $cat) {
243        if (exists $self->{author}) {
244            $cat->author_id($self->{author}->id);
245        } elsif (exists $self->{parent}) {
246            $cat->author_id($self->{parent}->id);
247        }
248        $cb->(MT->translate("Creating new category ('[_1]')...", $cat->label));
249        if ($cat->save) {
250            $cb->(MT->translate("ok") . "\n");
251        } else {
252            $cb->(MT->translate("failed") . "\n");
253            return die MT->translate(
254                 "Saving category failed: [_1]", $cat->errstr);
255        }
256    }
257}
258
259sub _create_feedback {
260    my $self = shift;
261    my $data = shift;
262   
263    my $cb = $self->{callback};
264
265    my $feedback_data = {};
266    my $type = 'comment';
267
268    while (my $hash = pop @{$self->{'bucket'}}) {
269        last if 'wp_comment' eq $hash;
270        next if 'HASH' ne ref $hash;
271        my @hash_array = %$hash;
272        my $key = $hash_array[0];
273        my $value = $hash_array[1];
274        if ('wp_comment_type' eq $key) {
275            $type = $value;
276        } else {
277            $feedback_data->{$key} = $value;
278        }
279    }
280    push @{$self->{'bucket'}}, { $type => $feedback_data };
281}
282
283sub _create_item {
284    my $self = shift;
285    my $data = shift;
286
287    my @hashes;
288    my $post_type = 'post';  ## TODO: default?
289    while (my $hash = pop @{$self->{'bucket'}}) {
290        last if '_item' eq $hash;
291        next if 'HASH' ne ref $hash;
292        $post_type = $hash->{'wp_post_type'}, next if exists $hash->{'wp_post_type'};
293        push @hashes, $hash if 'HASH' eq ref($hash);
294    }
295
296    my $blog = $self->{blog};
297    return unless $blog;
298
299    if ('post' eq $post_type) {
300        $self->_create_post('entry', \@hashes);
301    } elsif ('page' eq $post_type) {
302        $self->_create_post('page', \@hashes);
303    } elsif ('attachment') {
304        $self->_create_asset(\@hashes);
305    }
306    1;
307}
308
309sub _create_asset {
310    my $self = shift;
311    my ($hashes) = @_;
312
313    my $blog = $self->{blog};
314    my $cb = $self->{callback};
315
316    my @tags;
317    my %meta_hash;
318    my $asset_values = { 'blog_id' => $blog->id };
319    for my $hash (@$hashes) {
320        my @hash_array = %$hash;
321        my $key = $hash_array[0];
322        my $value = $hash_array[1];
323        if ('_title' eq $key) {
324            $asset_values->{'label'} = $value;
325        } elsif ('_link' eq $key) {
326            # skip
327        } elsif ('_pubDate' eq $key) {
328            # skip - we use post_date_gmt;
329        } elsif ('dc_creator' eq $key) {
330            $asset_values->{'created_by'} = $self->_get_author_id($cb, $value);
331        } elsif ('_category' eq $key) {
332            # TODO: is it ok to make it tags?
333            push @tags, $value;
334        } elsif ('_guid' eq $key) {
335            $asset_values->{'url'} = $value;
336        } elsif ('_description' eq $key) {
337            # skip
338        } elsif ('content_encoded' eq $key) {
339            $asset_values->{'description'} = $value;
340        } elsif ('wp_post_id' eq $key) {
341            # skip;
342        } elsif ('wp_post_date' eq $key) {
343            # skip;
344        } elsif ('wp_post_date_gmt' eq $key) {
345            $asset_values->{'created_on'} = $self->_gmt2blogtime($value, $blog);
346        } elsif ('wp_comment_status' eq $key) {
347            # skip
348        } elsif ('wp_ping_status' eq $key) {
349            # skip
350        } elsif ('wp_post_name' eq $key) {
351            # skip - we don't have an equivalent.
352        } elsif ('wp_status' eq $key) {
353            # skip possible values: inherit,
354        } elsif ('wp_post_parent' eq $key) {
355            # skip - entry association?
356        } elsif ('wp_postmeta' eq $key) {
357            for my $meta_key (keys %$value) {
358                if ('_wp_attached_file' eq $meta_key) {
359                    $asset_values->{'file_path'} = $value->{$meta_key};
360                } elsif ('_wp_attachment_metadata' eq $meta_key) {
361                    # only parse width and height
362                    my $serialized = $value->{$meta_key};
363                    if ($serialized =~ m!s:5:"width";i:(\d+);s:6:"height";i:(\d+);!i) {
364                        $asset_values->{'image_width'} = $1;
365                        $asset_values->{'image_height'} = $2;
366                    }
367                    $meta_hash{$meta_key} = $value->{$meta_key};
368                } else {
369                    $meta_hash{$meta_key} = $value->{$meta_key};
370                }
371            }
372        }
373    }
374
375    my $wp_path = $self->{'wp_path'};
376    my $mt_path = $self->{'mt_path'};
377    my $path = $asset_values->{'file_path'};
378    if ($wp_path && $mt_path) {
379        $path =~ s/^.*$wp_path(.+)$/$mt_path$1/i;
380        $path = File::Spec->canonpath($path);
381    }
382    $asset_values->{'file_path'} = $path;
383
384    my $mt_url = $self->{'mt_url'};
385    my $url = $asset_values->{'url'};
386    my $old_url = $url;
387    if ($mt_url) {
388        $url =~ s/^.*$wp_path(.+)$/$mt_url$1/i;
389    }
390    $asset_values->{'url'} = $url;
391
392    require MT::Asset;
393
394    # Check dupe
395    if ( MT::Asset->count(
396      {
397        blog_id => $asset_values->{blog_id},
398        label => $asset_values->{label},
399        file_path => $asset_values->{file_path},
400      }
401    ))
402    {
403        $cb->(MT->translate("Duplicate asset ('[_1]') found.  Skipping.", $asset_values->{label}));
404        $cb->("\n");
405        return 1;
406    }
407    require File::Basename;
408    my $local_basename = File::Basename::basename($path);
409    my $ext = (File::Basename::fileparse($path, qr/[A-Za-z]+$/))[2];
410
411    $asset_values->{'file_name'} = $local_basename;
412    $asset_values->{'file_ext'} = $ext;
413
414    # Now save the asset.
415    my $asset_pkg = MT::Asset->handler_for_file($local_basename);
416    my $asset = $asset_pkg->new();
417    my $w = delete $asset_values->{'image_width'};
418    my $h = delete $asset_values->{'image_height'};
419    $asset->set_values($asset_values);
420    if ( $h && $w ) {
421        $asset->image_width($w);
422        $asset->image_height($h);
423    }
424    $cb->(MT->translate("Saving asset ('[_1]')...", $asset->label));
425    $asset->add_tags(@tags) if 0 < scalar(@tags);
426    $cb->(MT->translate(" and asset will be tagged ('[_1]')...", join(',', @tags)));
427    if ($asset->save) {
428        $cb->(MT->translate("ok (ID [_1])", $asset->id) . "\n");
429        if ( exists($self->{'wp_download'}) && $self->{'wp_download'} ) {
430            _get_item_via_http($asset->id, $old_url);
431        }
432    } else {
433        $cb->(MT->translate("failed") . "\n");
434        die MT->translate(
435            "Saving entry failed: [_1]", $asset->errstr);
436    }
437}
438
439sub _create_post {
440    my $self = shift;
441    my ($class_type, $hashes) = @_;
442
443    my $blog = $self->{blog};
444    my $cb = $self->{callback};
445
446    my %cat_ids;
447    my $primary_cat_id;
448    my $feedbacks = {
449        'comments' => [],
450        'trackbacks' => [],
451    };
452    my %meta_hash;
453
454    my $class = MT->model($class_type);
455    require MT::Comment;
456    require MT::TBPing;
457    require MT::Trackback;
458
459    my $post = $class->new;
460    $post->blog_id($blog->id);
461    $post->convert_breaks($self->{convert_breaks});
462    for my $hash (@$hashes) {
463        my @hash_array = %$hash;
464        my $key = $hash_array[0];
465        my $value = $hash_array[1];
466        if ('_title' eq $key) {
467            $post->title($value);
468        } elsif ('_link' eq $key) {
469            # skip;
470        } elsif ('_pubDate' eq $key) {
471            # skip - we use post_date_gmt;
472        } elsif ('dc_creator' eq $key) {
473            $post->author_id($self->_get_author_id($cb, $value));
474        } elsif ('_category' eq $key) {
475            my $cat_class = MT->model(
476                $class_type eq 'entry' ? 'category' : 'folder');
477            my $cat = $cat_class->load(
478                { label => $value,
479                  blog_id => $self->{blog}->id });
480            if (defined $cat) {
481                $cat_ids{$cat->id} = 1;
482                $primary_cat_id = $cat->id unless $primary_cat_id;
483            }
484        } elsif ('_guid' eq $key) {
485            # skip;
486        } elsif ('_description' eq $key) {
487            # skip;
488        } elsif ('content_encoded' eq $key) {
489            my $pos = index $value, POST_SEPARATOR();
490            if (-1 == $pos) {
491                $post->text($value);
492            } else {
493                $post->text(substr $value, 0, $pos);
494                $post->text_more(substr $value, $pos + length(POST_SEPARATOR()));
495            }
496        } elsif ('wp_post_id' eq $key) {
497            # skip;
498        } elsif ('wp_post_date' eq $key) {
499            # skip;
500        } elsif ('wp_post_date_gmt' eq $key) {
501            $post->authored_on($self->_gmt2blogtime($value, $blog));
502        } elsif ('wp_comment_status' eq $key) {
503            $post->allow_comments('open' eq $value ? 1 : 0);
504        } elsif ('wp_ping_status' eq $key) {
505            $post->allow_pings('open' eq $value ? 1 : 0);
506        } elsif ('wp_post_name' eq $key) {
507            my $base = MT::Util::decode_url($value);
508            $base = MT::Util::dirify($base) if $base ne $value;
509            $base = substr($base, 0, $self->{basename_limit});
510            $base =~ s/_+$//;
511            $base = 'post' if $base eq '';
512            my $i = 1;
513            my $base_copy = $base;
514            while ($class->count({ blog_id => $blog->id,
515                                      basename => $base })) {
516                $base = $base_copy . '_' . $i++;
517            }
518            $post->basename($base);
519        } elsif ('wp_status' eq $key) {
520            $post->status(MT::Entry::HOLD()) unless 'publish' eq $value;
521            $post->status(MT::Entry::RELEASE()) if 'publish' eq $value;
522        } elsif ('wp_post_parent' eq $key) {
523            # skip;
524        } elsif ('wp_postmeta' eq $key) {
525            for my $meta_key (keys %$value) {
526                $meta_hash{$meta_key} = $value->{$meta_key};
527            }
528            # TODO: how we should handle metadata is to be decided later
529        } elsif ('comment' eq $key) {
530            my $cmt = MT::Comment->new;
531            $cmt->blog_id($blog->id);
532            $cmt->author($value->{'wp_comment_author'}) if exists $value->{'wp_comment_author'};
533            $cmt->email($value->{'wp_comment_author_email'}) if exists $value->{'wp_comment_author_email'};
534            $cmt->url($value->{'wp_comment_author_url'}) if exists $value->{'wp_comment_author_url'};
535            $cmt->ip($value->{'wp_comment_author_IP'}) if exists $value->{'wp_comment_author_IP'};
536            my $date = $value->{'wp_comment_date_gmt'};
537            $cmt->created_on($self->_gmt2blogtime($date, $blog));
538            $cmt->text($value->{'wp_comment_content'}) if exists $value->{'wp_comment_content'};
539            my $status = $value->{'wp_comment_approved'};
540            if ($status eq '1') {
541                $cmt->approve;
542            } elsif ('spam' eq $status) {
543                $cmt->junk;
544            }
545            # skip wp:comment_id
546            # skip wp:comment_parent
547            push @{$feedbacks->{comments}}, $cmt;
548        } elsif (('trackback' eq $key) || ('pingback' eq $key)) {
549            # TODO: are trackback and pingback the same in its data structure?
550            my $ping = MT::TBPing->new;
551            $ping->blog_id($blog->id);
552            $ping->blog_name($value->{'wp_comment_author'}) if exists $value->{'wp_comment_author'};
553            $ping->source_url($value->{'wp_comment_author_url'}) if exists $value->{'wp_comment_author_url'};
554            $ping->ip($value->{'wp_comment_author_IP'}) if exists $value->{'wp_comment_author_IP'};
555            my $date = $value->{'wp_comment_date_gmt'};
556            $ping->created_on($self->_gmt2blogtime($date, $blog));
557            if (exists $value->{'wp_comment_content'}) {
558                my $content = $value->{'wp_comment_content'} ;
559                if ($content =~ m!^<strong>(.+)</strong>\n*(.+)$!m) {
560                    # this is exactly how wordpress stores trackbacks in its database as of v2.1.
561                    $ping->title($1);
562                    $ping->excerpt($2);
563                }
564            }
565            my $status = $value->{'wp_comment_approved'};
566            if ($status eq '1') {
567                $ping->approve;
568            } elsif ('spam' eq $status) {
569                $ping->junk;
570            }
571            push @{$feedbacks->{trackbacks}}, $ping;
572        }
573    }
574
575    # Check dupe
576    if ( $class->count(
577      {
578        class => $class_type,
579        blog_id => $post->blog_id,
580        title => $post->title,
581        authored_on => $post->authored_on
582      }
583    ))
584    {
585        $cb->(MT->translate("Duplicate entry ('[_1]') found.  Skipping.", $post->title));
586        $cb->("\n");
587        return 1;
588    }
589
590    # Now save the entry/page.
591    if ('entry' eq $class_type) {
592        $cb->(MT->translate("Saving entry ('[_1]')...", $post->title));
593    } elsif ('page' eq $class_type) {
594        $cb->(MT->translate("Saving page ('[_1]')...", $post->title));
595    }
596    if ($post->save) {
597        $cb->(MT->translate("ok (ID [_1])", $post->id) . "\n");
598    } else {
599        $cb->(MT->translate("failed") . "\n");
600        die MT->translate(
601            "Save failed: [_1]", $post->errstr);
602    }
603
604    # Associate the entry to categories.
605    $primary_cat_id = $self->{def_cat_id} unless $primary_cat_id;
606    if ($primary_cat_id) {
607        my $place = MT::Placement->new;
608        $place->is_primary(1);
609        $place->entry_id($post->id);
610        $place->blog_id($self->{blog}->id);
611        $place->category_id($primary_cat_id);
612        $place->save
613            or die MT->translate(
614                "Saving placement failed: [_1]", $place->errstr);
615        delete $cat_ids{$primary_cat_id};
616    }
617
618    for my $cat_id (keys %cat_ids) {
619        my $place = MT::Placement->new;
620        $place->is_primary(0);
621        $place->entry_id($post->id);
622        $place->blog_id($self->{blog}->id);
623        $place->category_id($cat_id);
624        $place->save
625            or die MT->translate(
626                "Saving placement failed: [_1]", $place->errstr);
627    }
628
629    # Associate comments to the entry.
630    for my $comment (@{$feedbacks->{comments}}) {
631        $comment->entry_id($post->id);
632        $cb->(MT->translate("Creating new comment (from '[_1]')...", $comment->author));
633        if ($comment->save) {
634            $cb->(MT->translate("ok (ID [_1])", $comment->id) . "\n");
635        } else {
636            $cb->(MT->translate("failed") . "\n");
637            die MT->translate(
638                "Saving comment failed: [_1]", $comment->errstr);
639        }
640    }
641
642    # Associate trackbacks to the entry.
643    if (scalar @{$feedbacks->{trackbacks}}) {
644        my $tb = $post->trackback;
645        unless ($tb) {
646            $tb = MT::Trackback->new;
647            $tb->blog_id($post->blog_id);
648            $tb->entry_id($post->id);
649            $tb->category_id(0);   ## category_id can't be NULL
650        }
651        $tb->title($post->title);
652        $tb->description($post->get_excerpt);
653        $tb->url($post->permalink);
654        $tb->is_disabled($post->allow_pings);
655        $tb->save;
656        unless ($tb) {
657            die MT->translate("Entry has no MT::Trackback object!");
658        }
659        $post->trackback($tb);
660        for my $ping (@{$feedbacks->{trackbacks}}) {
661            $ping->tb_id($tb->id);
662            $cb->(MT->translate("Creating new ping ('[_1]')...", $ping->title));
663            if ($ping->save) {
664                $cb->(MT->translate("ok (ID [_1])", $ping->id) . "\n");
665            } else {
666                $cb->(MT->translate("failed") . "\n");
667                die MT->translate(
668                    "Saving ping failed: [_1]", $ping->errstr);
669            }
670        }
671    }
672    1;
673}
674
675sub _get_author_id {
676    my $self = shift;
677    my ($cb, $value) = @_;
678
679    my $author = $self->{author};
680    unless ($author) {
681        require MT::BasicAuthor;
682        $author = MT::BasicAuthor->load({ name => $value });
683        unless (defined $author) {
684            my $parent_author = $self->{parent};
685            my $pass = $self->{pass};
686            $author = MT::Author->new;
687            $author->created_by($parent_author->id) if defined $parent_author;
688            $author->name($value);
689            $author->email('');
690            $author->type(MT::Author::AUTHOR());
691            if ($pass) {
692                $author->set_password($pass);
693            } else {
694                $author->password('(none)');
695            }
696            $cb->(MT->translate("Creating new user ('[_1]')...", $value));
697            if ($author->save) {
698                $cb->(MT->translate("ok") . "\n");
699            } else {
700                $cb->(MT->translate("failed") . "\n");
701                die MT->translate(
702                    "Saving user failed: [_1]", $author->errstr);
703            }
704            $cb->(MT->translate("Assigning permissions for new user..."));
705            require MT::Role;
706            require MT::Association;
707            my $role = MT::Role->load_by_permission('post');
708            if ($role) {
709                my $assoc;
710                if ($assoc = MT::Association->link($author => $role => $self->{blog})) {
711                    $cb->(MT->translate("ok") . "\n");
712                } else {
713                    $cb->(MT->translate("failed") . "\n");
714                    die MT->translate(
715                         "Saving permission failed: [_1]", $assoc->errstr);
716                }
717            }
718        }
719    }
720    defined $author ? $author->id : undef;
721}
722
723sub _gmt2blogtime {
724    my $self = shift;
725    my ($datetime, $blog) = @_;
726    if ($datetime =~ /^(\d{4})-?(\d{2})-?(\d{2})\s?(\d{2}):(\d{2}):(\d{2})/) {
727        my($y, $mo, $d, $h, $m, $s) =
728            ($1, $2 || 1, $3 || 1, $4 || 0, $5 || 0, $6 || 0);
729        my $time = eval { timegm($s, $m, $h, $d, $mo-1, $y); } or return undef;
730        ($s, $m, $h, $d, $mo, $y) = offset_time_list($time, $blog);
731        $y += 1900;
732        $mo++;
733        return sprintf "%04d%02d%02d%02d%02d%02d", $y, $mo, $d, $h, $m, $s;
734    }
735    return undef;
736}
737
738sub _get_item_via_http {
739    my ($asset_id, $url) = @_;
740
741    require MT::TheSchwartz;
742    require TheSchwartz::Job;
743    my $job = TheSchwartz::Job->new();
744    $job->funcname('WXRImporter::Worker::Downloader');
745    $job->uniqkey( $asset_id );
746    $job->arg( { old_url => $url } );
747    $job->coalesce( $$ . ':' . ( time - ( time % 100 ) ) );
748    MT::TheSchwartz->insert($job);
749}
750
7511;
Note: See TracBrowser for help on using the browser.