root/trunk/build/cwapi.pm

Revision 4196, 12.3 kB (checked in by takayama, 3 months ago)

* Set svn keywords

  • Property svn:keywords set to Author Date Id Revision
Line 
1# $Id$
2
3## xxx issues with weblogs API:
4## error handling
5## is "array of categories" array of labels, or of structs?
6## categories.edit has no category ID
7## templates.* should use template IDs?
8## what about $publish flag? in 'options' struct?
9
10my($HAVE_XML_PARSER);
11BEGIN {
12    eval { require XML::Parser };
13    $HAVE_XML_PARSER = $@ ? 0 : 1;
14}
15
16## Common Weblogs API support
17
18*weblogs::user::login = \&MT::XMLRPC::Methods::login;
19*weblogs::user::getBlogNames = \&MT::XMLRPC::Methods::get_blogs;
20
21*weblogs::posts::new = \&MT::XMLRPC::Methods::new_post;
22*weblogs::posts::edit = \&MT::XMLRPC::Methods::edit_post;
23*weblogs::posts::delete = \&MT::XMLRPC::Methods::delete_post;
24*weblogs::posts::count = \&MT::XMLRPC::Methods::count_posts;
25*weblogs::posts::getAll = \&MT::XMLRPC::Methods::get_posts;
26*weblogs::posts::get = \&MT::XMLRPC::Methods::get_posts;
27
28## Blogger API support
29
30*blogger::newPost = \&MT::XMLRPC::Methods::new_post;
31*blogger::editPost = \&MT::XMLRPC::Methods::edit_post;
32*blogger::deletePost = \&MT::XMLRPC::Methods::delete_post;
33*blogger::getUsersBlogs = \&MT::XMLRPC::Methods::get_blogs;
34*blogger::getUserInfo = \&MT::XMLRPC::Methods::login;
35
36## getTemplate and setTemplate are not applicable in MT's template
37## structure, so they are unimplemented (they return a fault).
38## We assign it twice to get rid of "setTemplate used only once" warnings.
39
40*blogger::getTemplate = sub {
41    die "Template methods are not implemented, due to differences between " .
42        "the Blogger API and the Movable Type API.\n";
43};
44*blogger::setTemplate = \&getTemplate;
45
46
47package MT::XMLRPC::Helpers;
48use strict;
49
50sub _login {
51    my $class = shift;
52    my($user, $pass, $blog_id) = @_;
53    require MT::Author;
54    my $author = MT::Author->load({ name => $user }) or return;
55    $author->is_valid_password($pass) or return;
56    return $author unless $blog_id;
57    require MT::Permission;
58    my $perms = MT::Permission->load({ author_id => $author->id,
59                                       blog_id => $blog_id });
60    ($author, $perms);
61}
62
63sub _publish {
64    my $class = shift;
65    my($mt, $entry) = @_;
66    require MT::Blog;
67    my $blog = MT::Blog->load($entry->blog_id);
68    $mt->rebuild_entry( Entry => $entry, Blog => $blog,
69                        BuildDependencies => 1 )
70        or return $class->error("Publish error: " . $mt->errstr);
71    $mt->ping(Blog => $blog)
72        or return $class->error("Ping error: " . $mt->errstr);
73    1;
74}
75
76sub no_utf8 {
77    for (@_) {
78        next if !defined $_;
79        $_ = pack 'C0A*', $_;
80    }
81}
82
83package MT::XMLRPC::Methods;
84use strict;
85
86use MT::Util qw( decode_html first_n_words );
87use MT;
88
89sub login {
90    my $class = shift;
91    my $is_blogger = $class =~ /^blogger/;
92    my($appkey, $user, $pass) = @_;
93    my $mt = MT->new;
94    my $author = MT::XMLRPC::Helpers->_login($user, $pass)
95        or die "Invalid login\n";
96    if ($is_blogger) {
97        my($fname, $lname) = split /\s+/, $author->name;
98        return { userid    => SOAP::Data->type(string => $author->id),
99                 firstname => SOAP::Data->type(string => $fname),
100                 lastname  => SOAP::Data->type(string => $lname),
101                 nickname  => SOAP::Data->type(string => $author->nickname),
102                 email     => SOAP::Data->type(string => $author->email),
103                 url       => SOAP::Data->type(string => $author->url) };
104    } else {
105        return { username => SOAP::Data->type(string => $author->name),
106                 userID   => SOAP::Data->type('int'  => $author->id),
107                 url      => SOAP::Data->type(string => $author->url),
108                 email    => SOAP::Data->type(string => $author->email) };
109    }
110}
111
112sub get_blogs {
113    my $class = shift;
114    my $is_blogger = $class =~ /^blogger/;
115    my($appkey, $user, $pass) = @_;
116    my $mt = MT->new;
117    my $author = MT::XMLRPC::Helpers->_login($user, $pass)
118        or die "Invalid login\n";
119    require MT::Permission;
120    require MT::Blog;
121    my $iter = MT::Permission->load_iter({ author_id => $author->id });
122    my @res;
123    my $id_key = $is_blogger ? 'blogid' : 'blogID';
124    while (my $perms = $iter->()) {
125        next unless $perms->can_post;
126        my $blog = MT::Blog->load($perms->blog_id);
127        push @res, { $id_key  => SOAP::Data->type(string => $blog->id),
128                     blogName => SOAP::Data->type(string => $blog->name),
129                     url      => SOAP::Data->type(string => $blog->site_url) };
130    }
131    \@res;
132}
133
134sub new_post {
135    my $class = shift;
136    my $is_blogger = $class =~ /^blogger/;
137    my($appkey, $user, $pass, $blog_id, $content,
138       $cats, $title, $publish, $opt);
139    if ($is_blogger) {
140        ($appkey, $blog_id, $user, $pass, $content, $publish) = @_;
141    } else {
142        ($appkey, $user, $pass, $blog_id, $content, $cats, $title, $opt) = @_;
143    }
144    MT::XMLRPC::Helpers::no_utf8($blog_id, $content, $title);
145    unless ($HAVE_XML_PARSER) {
146        $content = decode_html($content);
147        $title = decode_html($title);
148    }
149    my $mt = MT->new;
150    require MT::Blog;
151    my $blog = MT::Blog->load($blog_id)
152        or die "Invalid blog ID '$blog_id'\n";
153    my($author, $perms) = MT::XMLRPC::Helpers->_login($user, $pass, $blog_id);
154    die "Invalid login\n" unless $author;
155    die "No posting privileges\n" unless $perms && $perms->can_post;
156    require MT::Entry;
157    my $entry = MT::Entry->new;
158    $entry->blog_id($blog_id);
159    $entry->author_id($author->id);
160## xxx handle categories
161    $entry->status($blog->status_default);
162    $entry->convert_breaks($blog->convert_paras);
163    $entry->allow_comments($blog->allow_comments_default);
164    $entry->title($title || first_n_words($content, 5));
165    $entry->text($content);
166    $entry->save;
167    if ($publish) {
168        MT::XMLRPC::Helpers->_publish($mt, $entry)
169            or die MT::XMLRPC::Helpers->errstr;
170    }
171    if ($is_blogger) {
172        return SOAP::Data->type(string => $entry->id);
173    } else {
174        return SOAP::Data->type('int' => $entry->id);
175    }
176}
177
178sub edit_post {
179    my $class = shift;
180    my $is_blogger = $class =~ /^blogger/;
181    my($appkey, $user, $pass, $blog_id, $entry_id, $content,
182       $cats, $title, $publish, $opt);
183    if ($is_blogger) {
184        ($appkey, $entry_id, $user, $pass, $content, $publish) = @_;
185    } else {
186        ($appkey, $user, $pass, $blog_id, $entry_id, $content, $cats,
187         $title, $opt) = @_;
188    }
189    MT::XMLRPC::Helpers::no_utf8($blog_id, $content, $title);
190    unless ($HAVE_XML_PARSER) {
191        $content = decode_html($content);
192        $title = decode_html($title);
193    }
194    my $mt = MT->new;
195    require MT::Entry;
196    my $entry = MT::Entry->load($entry_id)
197        or die "Invalid entry ID '$entry_id'\n";
198    my($author, $perms) =
199        MT::XMLRPC::Helpers->_login($user, $pass, $entry->blog_id);
200    die "Invalid login\n" unless $author;
201    die "Not privileged to edit entry\n"
202        unless $perms && $perms->can_post ||
203        ($perms->can_edit_all_posts && $entry->author_id == $author->id);
204    $entry->status(MT::Entry::RELEASE()) if $publish;
205## xxx handle categories
206    $entry->title($title) if $title;
207    $entry->text($content);
208    $entry->save;
209    if ($publish) {
210        MT::XMLRPC::Helpers->_publish($mt, $entry)
211            or die MT::XMLRPC::Helpers->errstr;
212    }
213    SOAP::Data->type(boolean => 1);
214}
215
216sub delete_post {
217    my $class = shift;
218    my $is_blogger = $class =~ /^blogger/;
219    my($appkey, $user, $pass, $blog_id, $entry_id, $publish);
220    if ($is_blogger) {
221        ($appkey, $entry_id, $user, $pass, $publish) = @_;
222    } else {
223        ($appkey, $user, $pass, $blog_id, $entry_id) = @_;
224    }
225    my $mt = MT->new;
226    require MT::Entry;
227    my $entry = MT::Entry->load($entry_id)
228        or die "Invalid entry ID '$entry_id'\n";
229    my($author, $perms) =
230        MT::XMLRPC->_login($user, $pass, $entry->blog_id);
231    die "Invalid login\n" unless $author;
232    die "Not privileged to delete entry\n"
233        unless $perms && $perms->can_post ||
234        ($perms->can_edit_all_posts && $entry->author_id == $author->id);
235    $entry->remove;
236    if ($publish) {
237        MT::XMLRPC::Helpers->_publish($mt, $entry)
238            or die MT::XMLRPC::Helpers->errstr;
239    }
240    SOAP::Data->type(boolean => 1);
241}
242
243sub count_posts {
244    my $class = shift;
245    my($appkey, $user, $pass, $blog_id) = @_;
246    require MT::Blog;
247    my $blog = MT::Blog->load($blog_id)
248        or die "Invalid blog ID '$blog_id'\n";
249    my($author, $perms) = MT::XMLRPC->_login($user, $pass, $blog_id);
250    die "Invalid login\n" unless $author;
251    die "Not privileged to post to blog\n" unless $perms->can_post;
252    require MT::Entry;
253    my $count = MT::Entry->count({ blog_id => $blog_id });
254    SOAP::Data->type('int' => $count);
255}
256
257sub get_posts {
258    my $class = shift;
259    my $is_blogger = $class =~ /^blogger/;
260    my($appkey, $user, $pass, $blog_id, $limit, $offset);
261    if ($is_blogger) {
262        ($appkey, $blog_id, $user, $pass, $limit) = @_;
263    } else {
264        ($appkey, $user, $pass, $blog_id, $limit, $offset) = @_;
265    }
266    my $mt = MT->new;
267    my($author, $perms) = MT::XMLRPC::Helpers->_login($user, $pass, $blog_id);
268    die "Invalid login\n" unless $author;
269    die "No posting privileges\n" unless $perms && $perms->can_post;
270    require MT::Entry;
271    my %arg = ('sort' => 'created_on', direction => 'descend');
272    if ($limit) {
273        $arg{limit} = $limit;
274        $arg{offset} = $offset if $offset;
275    }
276    my $iter = MT::Entry->load_iter({ blog_id => $blog_id }, \%arg);
277    my @res;
278    my $mk_row;
279    if ($is_blogger) {
280        $mk_row = sub { {
281            dateCreated => SOAP::Data->type(dateTime => $_[0]),
282            userid      => SOAP::Data->type(userid => $_[1]),
283            postid      => SOAP::Data->type(string => $_[2]),
284            content     => SOAP::Data->type(string => $_[3]),
285        } };
286    } else {
287        $mk_row = sub { {
288            postID       => SOAP::Data->type('int' => $_[2]),
289            'time'       => SOAP::Data->type(dateTime => $_[0]),
290            subject      => SOAP::Data->type(string => $_[4]),
291            post         => SOAP::Data->type(string => $_[3]),
292            num_comments => SOAP::Data->type('int' => $_[5]),
293        } };
294    }
295    if (!$is_blogger) {
296        require MT::Comment;
297    }
298    while (my $entry = $iter->()) {
299        my $co = sprintf "%04d%02d%02dT%02d:%02d:%02d",
300            unpack 'A4A2A2A2A2A2', $entry->created_on;
301        my @arg = ($co, $entry->author_id, $entry->id, $entry->text);
302        if (!$is_blogger) {
303## xxx need to handle categories
304            push @arg, $entry->title;
305            my $count = MT::Comment->count({ entry_id => $entry->id });
306            push @arg, $count;
307        }
308        my $row = $mk_row->(@arg);
309        push @res, $row;
310    }
311    \@res;
312}
313
314sub get_categories {
315    my $class = shift;
316    my($appkey, $user, $pass, $blog_id) = @_;
317    my $mt = MT->new;
318    my($author, $perms) = MT::XMLRPC::Helpers->_login($user, $pass, $blog_id);
319    die "Invalid login\n" unless $author;
320    die "No posting privileges\n" unless $perms && $perms->can_post;
321    require MT::Category;
322    my $iter = MT::Category->load_iter({ blog_id => $blog_id });
323    my @res;
324    while (my $cat = $iter->()) {
325        push @res, {
326            catID   => SOAP::Data->type('int' => $cat->id),
327            catName => SOAP::Data->type(string => $cat->label)
328        };
329    }
330    \@res;
331}
332
333sub new_category {
334    my $class = shift;
335    my($appkey, $user, $pass, $blog_id, $label, $opt) = @_;
336    MT::XMLRPC::Helpers::no_utf8($blog_id, $label);
337    my $mt = MT->new;
338    my($author, $perms) = MT::XMLRPC::Helpers->_login($user, $pass, $blog_id);
339    die "Invalid login\n" unless $author;
340    die "No category editing privileges\n"
341        unless $perms && $perms->can_edit_categories;
342    require MT::Category;
343    my $cat = MT::Category->new;
344    $cat->blog_id($blog_id);
345    $cat->label($label);
346    $cat->author_id($author->id);
347    $cat->save;
348    SOAP::Data->type('int' => $cat->id);
349}
350
351sub edit_category {
352    my $class = shift;
353    my($appkey, $user, $pass, $blog_id, $label, $opt) = @_;
354    MT::XMLRPC::Helpers::no_utf8($blog_id, $label);
355    my $mt = MT->new;
356    my($author, $perms) = MT::XMLRPC::Helpers->_login($user, $pass, $blog_id);
357    die "Invalid login\n" unless $author;
358    die "No category editing privileges\n"
359        unless $perms && $perms->can_edit_categories;
360    require MT::Category;
361    my $cat = MT::Category->new;
362    $cat->blog_id($blog_id);
363    $cat->label($label);
364    $cat->author_id($author->id);
365    $cat->save;
366    SOAP::Data->type('int' => $cat->id);
367}
368
3691;
Note: See TracBrowser for help on using the browser.