Changeset 1947
- Timestamp:
- 04/17/08 07:14:54 (22 months ago)
- Location:
- branches/release-35
- Files:
-
- 4 modified
-
lib/MT/Atom.pm (modified) (2 diffs)
-
lib/MT/AtomServer.pm (modified) (9 diffs)
-
lib/MT/Core.pm (modified) (1 diff)
-
t/41-atom.t (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/release-35/lib/MT/Atom.pm
r1823 r1947 72 72 my ($host) = $blog->site_url =~ m!^https?://([^/:]+)(:\d+)?/!; 73 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 74 83 $atom->id($entry->atom_id); 75 84 #$atom->draft('true') if $entry->status != MT::Entry::RELEASE(); … … 94 103 } 95 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 96 150 1; 97 151 __END__ -
branches/release-35/lib/MT/AtomServer.pm
r1915 r1947 466 466 467 467 my $e_title = XML::XPath::Node::Element->new('atom:title', 'atom'); 468 $e_title->appendChild(XML::XPath::Node::Text->new(MT->translate(' Entries')));468 $e_title->appendChild(XML::XPath::Node::Text->new(MT->translate('[_1]: Entries', $blog->name))); 469 469 $entries->appendChild($e_title); 470 470 … … 563 563 my $pub_ts = MT::Util::iso2ts($blog, $iso); 564 564 $entry->authored_on($pub_ts); 565 require MT::DateTime; 565 566 if ( 0 < MT::DateTime->compare( blog => $blog, 566 567 a => $pub_ts, … … 654 655 my $pub_ts = MT::Util::iso2ts($blog, $iso); 655 656 $entry->authored_on($pub_ts); 657 require MT::DateTime; 656 658 if ( 0 < MT::DateTime->compare( blog => $blog, 657 659 a => $pub_ts, … … 727 729 $e->add_link({ rel => $app->edit_link_rel, type => $app->atom_x_content_type, 728 730 href => ($uri . $entry->id), title => encode_text($entry->title, undef,'utf-8') }); 731 $e->add_link({ rel => 'replies', type => $app->atom_x_content_type, 732 href => $app->base . $app->app_path . $app->config->AtomScript . '/comments/blog_id=' . $blog->id . '/entry_id=' . $entry->id }); 733 729 734 # feed/updated should be added before entries 730 735 # so we postpone adding them until later … … 738 743 $feed->add_entry($_) foreach @entries; 739 744 ## xxx add next/prev links 745 $app->run_callbacks( 'get_posts', $feed, $blog ); 740 746 $app->response_content_type($app->atom_content_type); 741 747 $feed->as_xml; … … 756 762 $uri .= '/entry_id='; 757 763 $atom->add_link({ rel => $app->edit_link_rel, type => $app->atom_x_content_type, 758 href => ($uri . $entry->id), title => encode_text($entry->title, undef,'utf-8') }); 764 href => ($uri . $entry->id), title => encode_text($entry->title, undef,'utf-8') }); 765 $atom->add_link({ rel => 'replies', type => $app->atom_x_content_type, 766 href => $app->base 767 . $app->app_path 768 . $app->config->AtomScript 769 . '/comments/blog_id=' . $blog->id 770 . '/entry_id=' . $entry->id 771 }); 772 $app->run_callbacks( 'get_post', $atom, $entry ); 773 $app->response_content_type($app->atom_content_type); 759 774 $atom->as_xml; 760 775 } … … 903 918 use XML::Atom; # for LIBXML 904 919 use XML::Atom::Feed; 905 use base qw( MT::AtomServer );906 920 use MT::Blog; 907 921 use MT::Permission; … … 1011 1025 } 1012 1026 1027 package MT::AtomServer::Comments; 1028 use strict; 1029 1030 use base qw( MT::AtomServer::Weblog ); 1031 use MT::I18N qw( encode_text ); 1032 1033 sub script { $_[0]->{cfg}->AtomScript . '/comments' } 1034 1035 sub handle_request { 1036 my $app = shift; 1037 $app->authenticate || return; 1038 if (my $svc = $app->{param}{svc}) { 1039 if ($svc eq 'upload') { 1040 return $app->handle_upload; 1041 } elsif ($svc eq 'categories') { 1042 return $app->get_categories; 1043 } 1044 } 1045 my $method = $app->request_method; 1046 if ($method eq 'POST') { 1047 # return $app->new_comment; 1048 } elsif ($method eq 'PUT') { 1049 # return $app->edit_comment; 1050 } elsif ($method eq 'DELETE') { 1051 # return $app->delete_comment; 1052 } elsif ($method eq 'GET') { 1053 if ($app->{param}{comment_id}) { 1054 return $app->get_comment; 1055 } elsif ($app->{param}{entry_id}) { 1056 return $app->get_comments; 1057 } else { 1058 return $app->get_blog_comments; 1059 } 1060 } 1061 } 1062 1063 sub new_with_comment { 1064 my $app = shift; 1065 my ($comment) = @_; 1066 my $atom = MT::Atom::Entry->new_with_comment( $comment, Version => 1.0 ); 1067 1068 my $mo = MT::Atom::Entry::_create_issued( 1069 $comment->modified_on || $comment->created_on, $comment->blog); 1070 $atom->set(MT::AtomServer::Weblog::NS_APP(), 'edited', $mo); 1071 1072 $atom; 1073 } 1074 1075 sub get_comment { 1076 my $app = shift; 1077 my $blog = $app->{blog}; 1078 my $comment_id = $app->{param}{comment_id} 1079 or return $app->error(400, "No comment_id"); 1080 my $comment = MT::Comment->load($comment_id) 1081 or return $app->error(400, "Invalid comment_id"); 1082 my $entry = $comment->entry; 1083 my $uri = $app->base . $app->uri . '/blog_id=' . $blog->id; 1084 my $c = $app->new_with_comment($comment); 1085 $c->add_link({ rel => 'self', type => $app->atom_x_content_type, 1086 href => $uri . '/comment_id=' . $comment->id }); 1087 # feed/updated should be added before entries 1088 # so we postpone adding them until later 1089 $c->set('http://purl.org/syndication/thread/1.0', 'in-reply-to', 1090 undef, 1091 { ref => $entry->atom_id, 1092 type => 'text/html', 1093 href => $entry->permalink } ); 1094 $app->run_callbacks( 'get_comment', $c, $comment ); 1095 $app->response_content_type($app->atom_content_type); 1096 $c->as_xml; 1097 } 1098 1099 sub get_blog_comments { 1100 my $app = shift; 1101 my $blog = $app->{blog}; 1102 my %terms = (blog_id => $blog->id, visible => 1); 1103 my %arg = (sort => $app->get_posts_order_field, direction => 'descend'); 1104 my $Limit = 20; 1105 $arg{limit} = $Limit + 1; 1106 $arg{offset} = $app->{param}{offset} || 0; 1107 1108 my $feed = $app->new_feed(); 1109 my $uri = $app->base . $app->uri . '/blog_id=' . $blog->id; 1110 my $blogname = encode_text($blog->name, undef, 'utf-8'); 1111 $feed->add_link({ rel => 'alternate', type => 'text/html', 1112 href => $blog->site_url }); 1113 $feed->add_link({ rel => 'self', type => $app->atom_x_content_type, 1114 href => $uri }); 1115 $feed->title($blogname); 1116 1117 require URI; 1118 my $site_uri = URI->new($blog->site_url); 1119 if ( $site_uri ) { 1120 my $blog_created = MT::Util::format_ts('%Y-%m-%d', $blog->created_on, $blog, 'en', 0); 1121 my $id = 'tag:'.$site_uri->host.','.$blog_created.':'.$site_uri->path.'/'.$blog->id; 1122 $feed->id($id); 1123 } 1124 $app->_comments_in_atom($feed, \%terms, \%arg); 1125 $app->run_callbacks( 'get_blog_comments', $feed, $blog ); 1126 ## xxx add next/prev links 1127 $app->response_content_type($app->atom_content_type); 1128 $feed->as_xml; 1129 } 1130 1131 sub get_comments { 1132 my $app = shift; 1133 my $blog = $app->{blog}; 1134 my $entry_id = $app->{param}{entry_id} 1135 or return $app->error(400, "No entry_id"); 1136 my $entry = MT::Entry->load($entry_id) 1137 or return $app->error(400, "Invalid entry_id"); 1138 my %terms = (blog_id => $blog->id, entry_id => $entry->id, visible => 1); 1139 my %arg = (sort => $app->get_posts_order_field, direction => 'descend'); 1140 my $Limit = 20; 1141 $arg{limit} = $Limit + 1; 1142 $arg{offset} = $app->{param}{offset} || 0; 1143 1144 my $feed = $app->new_feed(); 1145 my $uri = $app->base . $app->uri . '/blog_id=' . $blog->id; 1146 my $blogname = encode_text($blog->name, undef, 'utf-8'); 1147 $feed->add_link({ rel => 'alternate', type => 'text/html', 1148 href => $entry->permalink }); 1149 $feed->add_link({ rel => 'self', type => $app->atom_x_content_type, 1150 href => $uri . '/entry_id=' . $entry->id }); 1151 $feed->title($entry->title); 1152 $feed->id($entry->atom_id . '/comments'); 1153 $app->_comments_in_atom($feed, \%terms, \%arg); 1154 $app->run_callbacks( 'get_comments', $feed, $entry ); 1155 ## xxx add next/prev links 1156 $app->response_content_type($app->atom_content_type); 1157 $feed->as_xml; 1158 } 1159 1160 sub _comments_in_atom { 1161 my $app = shift; 1162 my ( $feed, $terms, $args ) = @_; 1163 require MT::Comment; 1164 my $iter = MT::Comment->load_iter($terms, $args); 1165 my $latest_date = 0; 1166 my @comments; 1167 while (my $comment = $iter->()) { 1168 my $c = $app->new_with_comment($comment); 1169 # feed/updated should be added before entries 1170 # so we postpone adding them until later 1171 my $entry = $comment->entry; 1172 $c->set('http://purl.org/syndication/thread/1.0', 'in-reply-to', 1173 undef, 1174 { ref => $entry->atom_id, 1175 type => 'text/html', 1176 href => $entry->permalink } ); 1177 push @comments, $c; 1178 my $date = $comment->modified_on || $comment->created_on; 1179 if ( $latest_date < $date ) { 1180 $latest_date = $date; 1181 $feed->updated( $c->updated ); 1182 } 1183 } 1184 $feed->add_entry($_) foreach @comments; 1185 $feed; 1186 } 1187 1188 1013 1189 1; 1014 1190 __END__ … … 1110 1286 $original_entry will have an unassigned 'id'. 1111 1287 1288 =item get_posts 1289 1290 callback($eh, $app, $feed, $blog) 1291 1292 Called right before get_posts method returns atom feed response. 1293 I<$feed> is a reference to XML::Atom::Feed object. 1294 I<$blog> is a reference to the requested MT::Blog object. 1295 1296 =item get_post 1297 1298 callback($eh, $app, $atom_entry, $entry) 1299 1300 Called right before get_post method returns atom entry response. 1301 I<$atom_entry> is a reference to XML::Atom::Entry object. 1302 I<$entry> is a reference to the requested MT::Entry object. 1303 1304 =item get_blog_comments 1305 1306 callback($eh, $app, $feed, $blog) 1307 1308 Called right before get_blog_comments method returns atom feed response. 1309 I<$feed> is a reference to XML::Atom::Feed object. 1310 I<$blog> is a reference to the requested MT::Blog object. 1311 1312 =item get_comments 1313 1314 callback($eh, $app, $feed, $entry) 1315 1316 Called right before get_comments method returns atom feed response. 1317 I<$feed> is a reference to XML::Atom::Feed object. 1318 I<$entry> is a reference to the requested MT::Entry object. 1319 1320 =item get_comment 1321 1322 callback($eh, $app, $atom_entry, $comment) 1323 1324 Called right before get_comment method returns atom entry response. 1325 I<$atom_entry> is a reference to XML::Atom::Entry object. 1326 I<$comment> is a reference to the requested MT::Comment object. 1327 1112 1328 =back 1113 1329 -
branches/release-35/lib/MT/Core.pm
r1883 r1947 235 235 weblog => 'MT::AtomServer::Weblog::Legacy', 236 236 '1.0' => 'MT::AtomServer::Weblog', 237 comments => 'MT::AtomServer::Comments', 237 238 }, 238 239 }, -
branches/release-35/t/41-atom.t
r1946 r1947 11 11 use XML::Atom::Entry; 12 12 13 use Test::More tests => 37;13 use Test::More tests => 97; 14 14 15 15 # To keep away from being under FastCGI … … 118 118 if (ok($resp->is_success)) { 119 119 my $blog_feed_url = $feed_link{$base_uri}->($resp); 120 my $ uri = new URI($blog_feed_url);121 is($ uri->path, $base_uri . '/blog_id=1', 'blog feed url is correct');120 my $blog_feed_uri = new URI($blog_feed_url); 121 is($blog_feed_uri->path, $base_uri . '/blog_id=1', 'blog feed url is correct'); 122 122 } 123 123 else { … … 152 152 my @entries = $feed->entries; 153 153 is($entry_count, scalar(@entries), 'number of entries is correct'); 154 155 # check if entries have replies link relation 156 my $failed = 0; 157 foreach my $entry (@entries) { 158 next if !$entry->id && $entry->title =~ /^I just finished installing Movable Type/; 159 my $mt_entry = MT::Entry->load({ 160 atom_id => $entry->id, 161 blog_id => 1, 162 }); 163 $failed = 1, last unless $mt_entry; 164 my ($replies) = grep { 165 $_->rel eq 'replies' 166 } $entry->links; 167 $failed = 1, last unless $replies; 168 my $replies_uri = new URI($replies->href); 169 $failed = 1, last unless $replies_uri->path eq '/mt-atom.cgi/comments/blog_id=1/entry_id='.$mt_entry->id; 170 } 171 is($failed, 0, 'all the entries have replies link rel'); 154 172 } 155 173 else { … … 342 360 } #end foreach 343 361 362 COMMENT: 363 # comments retrieval 364 { 365 my $wsse_header = make_wsse($chuck_token); 366 my $uri = new URI; 367 $uri->path('/mt-atom.cgi/comments/blog_id=1'); 368 my $req = new HTTP::Request(GET => $uri); 369 $req->header('Authorization' => 'Atom'); 370 $req->header('X-WSSE' => $wsse_header); 371 372 my $resp = $ua->request($req); 373 if (ok($resp->is_success)) { 374 my $thr_ns = XML::Atom::Namespace->new(prefix => undef, uri => 'http://purl.org/syndication/thread/1.0'); 375 my $comments = XML::Atom::Feed->new(\$resp->content()); 376 my $count = MT::Comment->count({ 377 blog_id => 1, visible => 1 378 }); 379 is( $count, scalar($comments->entries), 'comment count' ); 380 foreach my $c ( $comments->entries ) { 381 my $id = $c->id; 382 my ( $cmt_id ) = $id =~ m{/([0-9]+)$}; 383 die unless $cmt_id; 384 my $mt_comment = MT::Comment->load($cmt_id); 385 die unless $mt_comment; 386 my $mt_entry = $mt_comment->entry; 387 is($c->title, $mt_entry->title, 'comment title == entry title'); 388 is( $c->author->name, $mt_comment->author, 'comment author' ); 389 is( $c->author->email || '', $mt_comment->email || '', 'commenter email' ); 390 is( $c->author->uri || '', $mt_comment->url || '', 'commenter url' ); 391 if ( $XML::Atom::LIBXML ) { 392 my $nodelist = $c->elem->getElementsByTagNameNS('http://purl.org/syndication/thread/1.0', 'in-reply-to'); 393 my $irt = $nodelist->shift; 394 ok($irt, 'in-reply-to'); 395 is( $irt->ref, $mt_entry->atom_id, 'in-reply-to/ref' ); 396 is( $irt->href, $mt_entry->permalink, 'in-reply-to/href' ); 397 } 398 } 399 } 400 else { 401 die $resp->content(); 402 } 403 } 404 405 { 406 my $iter = MT::Comment->count_group_by( 407 { blog_id => 1, visible => 1 }, 408 { group => ['entry_id'], sort => [ { desc => 'DESC', column => '1' } ] 409 } 410 ); 411 #$Data::ObjectDriver::PROFILE = 1; 412 #my $p = Data::ObjectDriver->profiler; 413 #$p->reset; 414 #print "$_\n" foreach @{$p->query_log}; 415 my ( $count, $eid ) = $iter->(); 416 $iter->('finish'); 417 my $entry = MT::Entry->load($eid); 418 419 my $wsse_header = make_wsse($chuck_token); 420 my $uri = new URI; 421 $uri->path('/mt-atom.cgi/1.0/blog_id=1/entry_id=' . $entry->id); 422 my $req = new HTTP::Request(GET => $uri); 423 $req->header('Authorization' => 'Atom'); 424 $req->header('X-WSSE' => $wsse_header); 425 426 my $resp = $ua->request($req); 427 if (ok($resp->is_success)) { 428 my $feed = XML::Atom::Entry->new(\$resp->content()); 429 my ($replies) = grep { 430 $_->rel eq 'replies' 431 } $feed->links; 432 433 # retrieve comments from replies url 434 my $replies_uri = new URI($replies->href); 435 my $wsse_header = make_wsse($chuck_token); 436 my $uri = new URI; 437 $uri->path($replies_uri->path); 438 my $req = new HTTP::Request(GET => $uri); 439 $req->header('Authorization' => 'Atom'); 440 $req->header('X-WSSE' => $wsse_header); 441 442 my $resp = $ua->request($req); 443 my $thr_ns = XML::Atom::Namespace->new(prefix => undef, uri => 'http://purl.org/syndication/thread/1.0'); 444 if (ok($resp->is_success)) { 445 my $comments = XML::Atom::Feed->new(\$resp->content()); 446 is( $count, scalar($comments->entries), 'comment count' ); 447 foreach my $e ( $comments->entries ) { 448 is($e->title, $entry->title, 'comment title == entry title'); 449 my $id = $e->id; 450 my ( $cmt_id ) = $id =~ m{/([0-9]+)$}; 451 die unless $cmt_id; 452 my $mt_comment = MT::Comment->load($cmt_id); 453 die unless $mt_comment; 454 is( $e->author->name, $mt_comment->author, 'comment author' ); 455 is( $e->author->email || '', $mt_comment->email || '', 'commenter email' ); 456 is( $e->author->uri || '', $mt_comment->url || '', 'commenter url' ); 457 if ( $XML::Atom::LIBXML ) { 458 my $nodelist = $e->elem->getElementsByTagNameNS('http://purl.org/syndication/thread/1.0', 'in-reply-to'); 459 my $irt = $nodelist->shift; 460 ok($irt, 'in-reply-to'); 461 is( $irt->ref, $entry->atom_id, 'in-reply-to/ref' ); 462 is( $irt->href, $entry->permalink, 'in-reply-to/href' ); 463 } 464 } 465 } 466 else { 467 die $resp->content(); 468 } 469 } 470 } 471 472 { 473 my $thr_ns = XML::Atom::Namespace->new(prefix => undef, uri => 'http://purl.org/syndication/thread/1.0'); 474 my $wsse_header = make_wsse($chuck_token); 475 my $uri = new URI; 476 $uri->path('/mt-atom.cgi/comments/blog_id=1/comment_id=1'); 477 my $req = new HTTP::Request(GET => $uri); 478 $req->header('Authorization' => 'Atom'); 479 $req->header('X-WSSE' => $wsse_header); 480 481 my $resp = $ua->request($req); 482 if (ok($resp->is_success)) { 483 my $c = XML::Atom::Entry->new(\$resp->content()); 484 my $mt_comment = MT::Comment->load(1); 485 die unless $mt_comment; 486 my $entry = $mt_comment->entry; 487 is( $c->title, $entry->title, 'comment title == entry title' ); 488 is( $c->author->name, $mt_comment->author, 'comment author' ); 489 is( $c->author->email || '', $mt_comment->email || '', 'commenter email' ); 490 is( $c->author->uri || '', $mt_comment->url || '', 'commenter url' ); 491 if ( $XML::Atom::LIBXML ) { 492 my $nodelist = $c->elem->getElementsByTagNameNS('http://purl.org/syndication/thread/1.0', 'in-reply-to'); 493 my $irt = $nodelist->shift; 494 ok($irt, 'in-reply-to'); 495 is( $irt->ref, $entry->atom_id, 'in-reply-to/ref' ); 496 is( $irt->href, $entry->permalink, 'in-reply-to/href' ); 497 } 498 } 499 else { 500 die $resp->content(); 501 } 502 } 344 503 345 504 END {
