root/branches/release-41/plugins/WXRImporter/lib/WXRImporter/WXRHandler.pm @ 2716

Revision 2716, 26.5 kB (checked in by auno, 17 months ago)

Added tag support for importing WXR file. BugzID:80487

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