| 1 | # Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd. |
|---|
| 2 | # This program is distributed under the terms of the |
|---|
| 3 | # GNU General Public License, version 2. |
|---|
| 4 | # |
|---|
| 5 | # $Id$ |
|---|
| 6 | |
|---|
| 7 | package MT::Atom; |
|---|
| 8 | use strict; |
|---|
| 9 | |
|---|
| 10 | package MT::Atom::Entry; |
|---|
| 11 | use MT::I18N qw( encode_text ); |
|---|
| 12 | use base qw( XML::Atom::Entry ); |
|---|
| 13 | |
|---|
| 14 | sub _create_issued { |
|---|
| 15 | my ($ts, $blog) = @_; |
|---|
| 16 | my @co_list = unpack 'A4A2A2A2A2A2', $ts; |
|---|
| 17 | my $co = sprintf "%04d-%02d-%02dT%02d:%02d:%02d", @co_list; |
|---|
| 18 | my $epoch = Time::Local::timegm($co_list[5], $co_list[4], $co_list[3], |
|---|
| 19 | $co_list[2], $co_list[1]-1, $co_list[0]); |
|---|
| 20 | my $so = $blog->server_offset; |
|---|
| 21 | $so += 1 if (localtime $epoch)[8]; |
|---|
| 22 | $so = sprintf("%s%02d:%02d", $so < 0 ? '-' : '+', |
|---|
| 23 | abs(int $so), abs($so - int $so)*60); |
|---|
| 24 | $co .= $so; |
|---|
| 25 | } |
|---|
| 26 | |
|---|
| 27 | sub new_with_entry { |
|---|
| 28 | my $class = shift; |
|---|
| 29 | my($entry, %param) = @_; |
|---|
| 30 | my $rfc_compat = $param{Version} && $param{Version} eq '1'; |
|---|
| 31 | |
|---|
| 32 | my $atom = $class->new(%param); |
|---|
| 33 | $atom->title(encode_text($entry->title, undef, 'utf-8')); |
|---|
| 34 | $atom->summary(encode_text($entry->excerpt, undef, 'utf-8')); |
|---|
| 35 | $atom->content(encode_text($entry->text, undef, 'utf-8')); |
|---|
| 36 | # Old Atom API gets application/xhtml+xml for compatibility -- but why |
|---|
| 37 | # do we say it's that when all we're guaranteed is it's an opaque blob |
|---|
| 38 | # of text? So use 'html' for new RFC compatible output. |
|---|
| 39 | # XML::Atom::Content intelligently determines content-type for rfc compat. |
|---|
| 40 | unless ( $rfc_compat ) { |
|---|
| 41 | $atom->content->type('application/xhtml+xml'); |
|---|
| 42 | } |
|---|
| 43 | |
|---|
| 44 | my $mt_author = MT::Author->load($entry->author_id) |
|---|
| 45 | or return undef; |
|---|
| 46 | my $atom_author = new XML::Atom::Person(%param); |
|---|
| 47 | $atom_author->name(encode_text($mt_author->nickname, undef, 'utf-8')); |
|---|
| 48 | $atom_author->email($mt_author->email) if $mt_author->email; |
|---|
| 49 | my $author_url_field = $rfc_compat ? 'uri' : 'url'; |
|---|
| 50 | $atom_author->$author_url_field($mt_author->url) if $mt_author->url; |
|---|
| 51 | $atom->author($atom_author); |
|---|
| 52 | |
|---|
| 53 | for my $cat (@{ $entry->categories }) { |
|---|
| 54 | my $atom_cat = XML::Atom::Category->new(%param); |
|---|
| 55 | $atom_cat->term($cat->label); |
|---|
| 56 | $atom->add_category($atom_cat); |
|---|
| 57 | } |
|---|
| 58 | |
|---|
| 59 | my $blog = MT::Blog->load($entry->blog_id) |
|---|
| 60 | or return undef; |
|---|
| 61 | my $co = _create_issued($entry->authored_on, $blog); |
|---|
| 62 | $atom->issued($co); |
|---|
| 63 | my $upd = $entry->modified_on; |
|---|
| 64 | if ( $upd ) { |
|---|
| 65 | $atom->updated( _create_issued( $upd, $blog ) ); |
|---|
| 66 | } |
|---|
| 67 | else { |
|---|
| 68 | $atom->updated( $co ); |
|---|
| 69 | } |
|---|
| 70 | $atom->add_link({ rel => 'alternate', type => 'text/html', |
|---|
| 71 | href => $entry->permalink }); |
|---|
| 72 | my ($host) = $blog->site_url =~ m!^https?://([^/:]+)(:\d+)?/!; |
|---|
| 73 | |
|---|
| 74 | unless ( $entry->atom_id ) { |
|---|
| 75 | # atom_id is not there - probably because |
|---|
| 76 | # the entry is in HOLD state |
|---|
| 77 | $entry->atom_id($entry->make_atom_id()); |
|---|
| 78 | # call update directly because MT::Entry::save |
|---|
| 79 | # is overkill for the purpose. |
|---|
| 80 | $entry->update if $entry->atom_id(); |
|---|
| 81 | } |
|---|
| 82 | |
|---|
| 83 | $atom->id($entry->atom_id); |
|---|
| 84 | #$atom->draft('true') if $entry->status != MT::Entry::RELEASE(); |
|---|
| 85 | |
|---|
| 86 | $atom; |
|---|
| 87 | } |
|---|
| 88 | |
|---|
| 89 | sub new_with_asset { |
|---|
| 90 | my $class = shift; |
|---|
| 91 | my($asset, %param) = @_; |
|---|
| 92 | my $atom = $class->new(%param); |
|---|
| 93 | $atom->title($asset->label); |
|---|
| 94 | $atom->summary($asset->description); |
|---|
| 95 | my $blog = MT::Blog->load($asset->blog_id) |
|---|
| 96 | or return undef; |
|---|
| 97 | $atom->issued(_create_issued($asset->created_on, $blog)); |
|---|
| 98 | $atom->add_link({ rel => 'alternate', type => $asset->mime_type, |
|---|
| 99 | href => $asset->url, title => $asset->label }); |
|---|
| 100 | my ($host) = $blog->site_url =~ m!^https?://([^/:]+)(:\d+)?/!; |
|---|
| 101 | $atom->id('tag:' . $host . ':asset-' . $asset->id); |
|---|
| 102 | return $atom; |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | sub new_with_comment { |
|---|
| 106 | my $class = shift; |
|---|
| 107 | my ( $comment, %param ) = @_; |
|---|
| 108 | my $rfc_compat = $param{Version} && $param{Version} eq '1'; |
|---|
| 109 | |
|---|
| 110 | my $entry = $comment->entry; |
|---|
| 111 | return unless $entry; |
|---|
| 112 | my $blog = $comment->blog; |
|---|
| 113 | return unless $blog; |
|---|
| 114 | |
|---|
| 115 | my $atom = $class->new(%param); |
|---|
| 116 | $atom->title(encode_text($entry->title, undef, 'utf-8')); |
|---|
| 117 | $atom->content(encode_text($comment->text, undef, 'utf-8')); |
|---|
| 118 | # Old Atom API gets application/xhtml+xml for compatibility -- but why |
|---|
| 119 | # do we say it's that when all we're guaranteed is it's an opaque blob |
|---|
| 120 | # of text? So use 'html' for new RFC compatible output. |
|---|
| 121 | # XML::Atom::Content intelligently determines content-type for rfc compat. |
|---|
| 122 | unless ( $rfc_compat ) { |
|---|
| 123 | $atom->content->type('application/xhtml+xml'); |
|---|
| 124 | } |
|---|
| 125 | |
|---|
| 126 | my $atom_author = new XML::Atom::Person(%param); |
|---|
| 127 | $atom_author->name(encode_text($comment->author, undef, 'utf-8')); |
|---|
| 128 | $atom_author->email($comment->email) if $comment->email; |
|---|
| 129 | my $author_url_field = $rfc_compat ? 'uri' : 'url'; |
|---|
| 130 | $atom_author->$author_url_field($comment->url) if $comment->url; |
|---|
| 131 | $atom->author($atom_author); |
|---|
| 132 | |
|---|
| 133 | my $co = _create_issued($comment->created_on, $blog); |
|---|
| 134 | $atom->issued($co); |
|---|
| 135 | my $upd = $comment->modified_on; |
|---|
| 136 | if ( $upd ) { |
|---|
| 137 | $atom->updated( _create_issued( $upd, $blog ) ); |
|---|
| 138 | } |
|---|
| 139 | else { |
|---|
| 140 | $atom->updated( $co ); |
|---|
| 141 | } |
|---|
| 142 | $atom->add_link({ rel => 'alternate', type => 'text/html', |
|---|
| 143 | href => $entry->archive_url . '#comment-' . $comment->id }); |
|---|
| 144 | my ($host) = $blog->site_url =~ m!^https?://([^/:]+)(:\d+)?/!; |
|---|
| 145 | |
|---|
| 146 | $atom->id($entry->atom_id . '/' . $comment->id); |
|---|
| 147 | $atom; |
|---|
| 148 | } |
|---|
| 149 | |
|---|
| 150 | 1; |
|---|
| 151 | __END__ |
|---|
| 152 | |
|---|
| 153 | =head1 NAME |
|---|
| 154 | |
|---|
| 155 | MT::Atom |
|---|
| 156 | |
|---|
| 157 | =head1 AUTHOR & COPYRIGHT |
|---|
| 158 | |
|---|
| 159 | Please see L<MT/AUTHOR & COPYRIGHT>. |
|---|
| 160 | |
|---|
| 161 | =cut |
|---|