Mercurial > defr > drupal > core
comparison modules/blogapi/blogapi.module @ 1:c1f4ac30525a 6.0
Drupal 6.0
author | Franck Deroche <webmaster@defr.org> |
---|---|
date | Tue, 23 Dec 2008 14:28:28 +0100 |
parents | |
children | acef7ccb09b5 |
comparison
equal
deleted
inserted
replaced
0:5a113a1c4740 | 1:c1f4ac30525a |
---|---|
1 <?php | |
2 // $Id: blogapi.module,v 1.115.2.1 2008/02/07 20:11:02 goba Exp $ | |
3 | |
4 /** | |
5 * @file | |
6 * Enable users to post using applications that support XML-RPC blog APIs. | |
7 */ | |
8 | |
9 /** | |
10 * Implementation of hook_help(). | |
11 */ | |
12 function blogapi_help($path, $arg) { | |
13 switch ($path) { | |
14 case 'admin/help#blogapi': | |
15 $output = '<p>'. t("The Blog API module allows your site's users to access and post to their blogs from external blogging clients. External blogging clients are available for a wide range of desktop operating systems, and generally provide a feature-rich graphical environment for creating and editing posts.") .'</p>'; | |
16 $output .= '<p>'. t('<a href="@ecto-link">Ecto</a>, a blogging client available for both Mac OS X and Microsoft Windows, can be used with Blog API. Blog API also supports <a href="@blogger-api">Blogger API</a>, <a href="@metaweblog-api">MetaWeblog API</a>, and most of the <a href="@movabletype-api">Movable Type API</a>. Blogging clients and other services (e.g. <a href="@flickr">Flickr\'s</a> "post to blog") that support these APIs may also be compatible.', array('@ecto-link' => url('http://infinite-sushi.com/software/ecto/'), '@blogger-api' => url('http://www.blogger.com/developers/api/1_docs/'), '@metaweblog-api' => url('http://www.xmlrpc.com/metaWeblogApi'), '@movabletype-api' => url('http://www.movabletype.org/docs/mtmanual_programmatic.html'), '@flickr' => url('http://www.flickr.com'))) .'</p>'; | |
17 $output .= '<p>'. t('Select the content types available to external clients on the <a href="@blogapi-settings">Blog API settings page</a>. If supported and available, each content type will be displayed as a separate "blog" by the external client.', array('@blogapi-settings' => url('admin/settings/blogapi'))) .'</p>'; | |
18 $output .= '<p>'. t('For more information, see the online handbook entry for <a href="@blogapi">Blog API module</a>.', array('@blogapi' => url('http://drupal.org/handbook/modules/blogapi/'))) .'</p>'; | |
19 return $output; | |
20 } | |
21 } | |
22 | |
23 /** | |
24 * Implementation of hook_perm(). | |
25 */ | |
26 function blogapi_perm() { | |
27 return array('administer content with blog api'); | |
28 } | |
29 | |
30 /** | |
31 * Implementation of hook_xmlrpc(). | |
32 */ | |
33 function blogapi_xmlrpc() { | |
34 return array( | |
35 array( | |
36 'blogger.getUsersBlogs', | |
37 'blogapi_blogger_get_users_blogs', | |
38 array('array', 'string', 'string', 'string'), | |
39 t('Returns a list of blogs to which an author has posting privileges.')), | |
40 array( | |
41 'blogger.getUserInfo', | |
42 'blogapi_blogger_get_user_info', | |
43 array('struct', 'string', 'string', 'string'), | |
44 t('Returns information about an author in the system.')), | |
45 array( | |
46 'blogger.newPost', | |
47 'blogapi_blogger_new_post', | |
48 array('string', 'string', 'string', 'string', 'string', 'string', 'boolean'), | |
49 t('Creates a new post, and optionally publishes it.')), | |
50 array( | |
51 'blogger.editPost', | |
52 'blogapi_blogger_edit_post', | |
53 array('boolean', 'string', 'string', 'string', 'string', 'string', 'boolean'), | |
54 t('Updates the information about an existing post.')), | |
55 array( | |
56 'blogger.getPost', | |
57 'blogapi_blogger_get_post', | |
58 array('struct', 'string', 'string', 'string', 'string'), | |
59 t('Returns information about a specific post.')), | |
60 array( | |
61 'blogger.deletePost', | |
62 'blogapi_blogger_delete_post', | |
63 array('boolean', 'string', 'string', 'string', 'string', 'boolean'), | |
64 t('Deletes a post.')), | |
65 array( | |
66 'blogger.getRecentPosts', | |
67 'blogapi_blogger_get_recent_posts', | |
68 array('array', 'string', 'string', 'string', 'string', 'int'), | |
69 t('Returns a list of the most recent posts in the system.')), | |
70 array( | |
71 'metaWeblog.newPost', | |
72 'blogapi_metaweblog_new_post', | |
73 array('string', 'string', 'string', 'string', 'struct', 'boolean'), | |
74 t('Creates a new post, and optionally publishes it.')), | |
75 array( | |
76 'metaWeblog.editPost', | |
77 'blogapi_metaweblog_edit_post', | |
78 array('boolean', 'string', 'string', 'string', 'struct', 'boolean'), | |
79 t('Updates information about an existing post.')), | |
80 array( | |
81 'metaWeblog.getPost', | |
82 'blogapi_metaweblog_get_post', | |
83 array('struct', 'string', 'string', 'string'), | |
84 t('Returns information about a specific post.')), | |
85 array( | |
86 'metaWeblog.newMediaObject', | |
87 'blogapi_metaweblog_new_media_object', | |
88 array('string', 'string', 'string', 'string', 'struct'), | |
89 t('Uploads a file to your webserver.')), | |
90 array( | |
91 'metaWeblog.getCategories', | |
92 'blogapi_metaweblog_get_category_list', | |
93 array('struct', 'string', 'string', 'string'), | |
94 t('Returns a list of all categories to which the post is assigned.')), | |
95 array( | |
96 'metaWeblog.getRecentPosts', | |
97 'blogapi_metaweblog_get_recent_posts', | |
98 array('array', 'string', 'string', 'string', 'int'), | |
99 t('Returns a list of the most recent posts in the system.')), | |
100 array( | |
101 'mt.getRecentPostTitles', | |
102 'blogapi_mt_get_recent_post_titles', | |
103 array('array', 'string', 'string', 'string', 'int'), | |
104 t('Returns a bandwidth-friendly list of the most recent posts in the system.')), | |
105 array( | |
106 'mt.getCategoryList', | |
107 'blogapi_mt_get_category_list', | |
108 array('array', 'string', 'string', 'string'), | |
109 t('Returns a list of all categories defined in the blog.')), | |
110 array( | |
111 'mt.getPostCategories', | |
112 'blogapi_mt_get_post_categories', | |
113 array('array', 'string', 'string', 'string'), | |
114 t('Returns a list of all categories to which the post is assigned.')), | |
115 array( | |
116 'mt.setPostCategories', | |
117 'blogapi_mt_set_post_categories', | |
118 array('boolean', 'string', 'string', 'string', 'array'), | |
119 t('Sets the categories for a post.')), | |
120 array( | |
121 'mt.supportedMethods', | |
122 'xmlrpc_server_list_methods', | |
123 array('array'), | |
124 t('Retrieve information about the XML-RPC methods supported by the server.')), | |
125 array( | |
126 'mt.supportedTextFilters', | |
127 'blogapi_mt_supported_text_filters', | |
128 array('array'), | |
129 t('Retrieve information about the text formatting plugins supported by the server.')), | |
130 array( | |
131 'mt.publishPost', | |
132 'blogap_mti_publish_post', | |
133 array('boolean', 'string', 'string', 'string'), | |
134 t('Publish (rebuild) all of the static files related to an entry from your blog. Equivalent to saving an entry in the system (but without the ping).'))); | |
135 } | |
136 | |
137 /** | |
138 * Blogging API callback. Finds the URL of a user's blog. | |
139 */ | |
140 | |
141 function blogapi_blogger_get_users_blogs($appid, $username, $password) { | |
142 | |
143 $user = blogapi_validate_user($username, $password); | |
144 if ($user->uid) { | |
145 $types = _blogapi_get_node_types(); | |
146 $structs = array(); | |
147 foreach ($types as $type) { | |
148 $structs[] = array('url' => url('blog/'. $user->uid, array('absolute' => TRUE)), 'blogid' => $type, 'blogName' => $user->name .": ". $type); | |
149 } | |
150 return $structs; | |
151 } | |
152 else { | |
153 return blogapi_error($user); | |
154 } | |
155 } | |
156 | |
157 /** | |
158 * Blogging API callback. Returns profile information about a user. | |
159 */ | |
160 function blogapi_blogger_get_user_info($appkey, $username, $password) { | |
161 $user = blogapi_validate_user($username, $password); | |
162 | |
163 if ($user->uid) { | |
164 $name = explode(' ', $user->realname ? $user->realname : $user->name, 2); | |
165 return array( | |
166 'userid' => $user->uid, | |
167 'lastname' => $name[1], | |
168 'firstname' => $name[0], | |
169 'nickname' => $user->name, | |
170 'email' => $user->mail, | |
171 'url' => url('blog/'. $user->uid, array('absolute' => TRUE))); | |
172 } | |
173 else { | |
174 return blogapi_error($user); | |
175 } | |
176 } | |
177 | |
178 /** | |
179 * Blogging API callback. Inserts a new blog post as a node. | |
180 */ | |
181 function blogapi_blogger_new_post($appkey, $blogid, $username, $password, $content, $publish) { | |
182 $user = blogapi_validate_user($username, $password); | |
183 if (!$user->uid) { | |
184 return blogapi_error($user); | |
185 } | |
186 | |
187 if (($error = _blogapi_validate_blogid($blogid)) !== TRUE) { | |
188 // Return an error if not configured type. | |
189 return $error; | |
190 } | |
191 | |
192 $edit = array(); | |
193 $edit['type'] = $blogid; | |
194 // get the node type defaults | |
195 $node_type_default = variable_get('node_options_'. $edit['type'], array('status', 'promote')); | |
196 $edit['uid'] = $user->uid; | |
197 $edit['name'] = $user->name; | |
198 $edit['promote'] = in_array('promote', $node_type_default); | |
199 $edit['comment'] = variable_get('comment_'. $edit['type'], 2); | |
200 $edit['revision'] = in_array('revision', $node_type_default); | |
201 $edit['format'] = FILTER_FORMAT_DEFAULT; | |
202 $edit['status'] = $publish; | |
203 | |
204 // check for bloggerAPI vs. metaWeblogAPI | |
205 if (is_array($content)) { | |
206 $edit['title'] = $content['title']; | |
207 $edit['body'] = $content['description']; | |
208 _blogapi_mt_extra($edit, $content); | |
209 } | |
210 else { | |
211 $edit['title'] = blogapi_blogger_title($content); | |
212 $edit['body'] = $content; | |
213 } | |
214 | |
215 if (!node_access('create', $edit['type'])) { | |
216 return blogapi_error(t('You do not have permission to create this type of post.')); | |
217 } | |
218 | |
219 if (user_access('administer nodes') && !isset($edit['date'])) { | |
220 $edit['date'] = format_date(time(), 'custom', 'Y-m-d H:i:s O'); | |
221 } | |
222 | |
223 node_invoke_nodeapi($edit, 'blogapi new'); | |
224 | |
225 node_validate($edit); | |
226 if ($errors = form_get_errors()) { | |
227 return blogapi_error(implode("\n", $errors)); | |
228 } | |
229 | |
230 $node = node_submit($edit); | |
231 node_save($node); | |
232 if ($node->nid) { | |
233 watchdog('content', '@type: added %title using blog API.', array('@type' => $node->type, '%title' => $node->title), WATCHDOG_NOTICE, l(t('view'), "node/$node->nid")); | |
234 // blogger.newPost returns a string so we cast the nid to a string by putting it in double quotes: | |
235 return "$node->nid"; | |
236 } | |
237 | |
238 return blogapi_error(t('Error storing post.')); | |
239 } | |
240 | |
241 /** | |
242 * Blogging API callback. Modifies the specified blog node. | |
243 */ | |
244 function blogapi_blogger_edit_post($appkey, $postid, $username, $password, $content, $publish) { | |
245 | |
246 $user = blogapi_validate_user($username, $password); | |
247 | |
248 if (!$user->uid) { | |
249 return blogapi_error($user); | |
250 } | |
251 | |
252 $node = node_load($postid); | |
253 if (!$node) { | |
254 return blogapi_error(t('n/a')); | |
255 } | |
256 // Let the teaser be re-generated. | |
257 unset($node->teaser); | |
258 | |
259 if (!node_access('update', $node)) { | |
260 return blogapi_error(t('You do not have permission to update this post.')); | |
261 } | |
262 | |
263 $node->status = $publish; | |
264 | |
265 // check for bloggerAPI vs. metaWeblogAPI | |
266 if (is_array($content)) { | |
267 $node->title = $content['title']; | |
268 $node->body = $content['description']; | |
269 _blogapi_mt_extra($node, $content); | |
270 } | |
271 else { | |
272 $node->title = blogapi_blogger_title($content); | |
273 $node->body = $content; | |
274 } | |
275 | |
276 node_invoke_nodeapi($node, 'blogapi edit'); | |
277 | |
278 node_validate($node); | |
279 if ($errors = form_get_errors()) { | |
280 return blogapi_error(implode("\n", $errors)); | |
281 } | |
282 | |
283 if (user_access('administer nodes') && !isset($edit['date'])) { | |
284 $node->date = format_date($node->created, 'custom', 'Y-m-d H:i:s O'); | |
285 } | |
286 $node = node_submit($node); | |
287 node_save($node); | |
288 if ($node->nid) { | |
289 watchdog('content', '@type: updated %title using Blog API.', array('@type' => $node->type, '%title' => $node->title), WATCHDOG_NOTICE, l(t('view'), "node/$node->nid")); | |
290 return TRUE; | |
291 } | |
292 | |
293 return blogapi_error(t('Error storing post.')); | |
294 } | |
295 | |
296 /** | |
297 * Blogging API callback. Returns a specified blog node. | |
298 */ | |
299 function blogapi_blogger_get_post($appkey, $postid, $username, $password) { | |
300 $user = blogapi_validate_user($username, $password); | |
301 if (!$user->uid) { | |
302 return blogapi_error($user); | |
303 } | |
304 | |
305 $node = node_load($postid); | |
306 | |
307 return _blogapi_get_post($node, TRUE); | |
308 } | |
309 | |
310 /** | |
311 * Blogging API callback. Removes the specified blog node. | |
312 */ | |
313 function blogapi_blogger_delete_post($appkey, $postid, $username, $password, $publish) { | |
314 $user = blogapi_validate_user($username, $password); | |
315 if (!$user->uid) { | |
316 return blogapi_error($user); | |
317 } | |
318 | |
319 node_delete($postid); | |
320 return TRUE; | |
321 } | |
322 | |
323 /** | |
324 * Blogging API callback. Returns the latest few postings in a user's blog. $bodies TRUE | |
325 * <a href="http://movabletype.org/docs/mtmanual_programmatic.html#item_mt%2EgetRecentPostTitles"> | |
326 * returns a bandwidth-friendly list</a>. | |
327 */ | |
328 function blogapi_blogger_get_recent_posts($appkey, $blogid, $username, $password, $number_of_posts, $bodies = TRUE) { | |
329 // Remove unused appkey (from bloggerAPI). | |
330 $user = blogapi_validate_user($username, $password); | |
331 if (!$user->uid) { | |
332 return blogapi_error($user); | |
333 } | |
334 | |
335 if (($error = _blogapi_validate_blogid($blogid)) !== TRUE) { | |
336 // Return an error if not configured type. | |
337 return $error; | |
338 } | |
339 | |
340 if ($bodies) { | |
341 $result = db_query_range("SELECT n.nid, n.title, r.body, r.format, n.comment, n.created, u.name FROM {node} n, {node_revisions} r, {users} u WHERE n.uid = u.uid AND n.vid = r.vid AND n.type = '%s' AND n.uid = %d ORDER BY n.created DESC", $blogid, $user->uid, 0, $number_of_posts); | |
342 } | |
343 else { | |
344 $result = db_query_range("SELECT n.nid, n.title, n.created, u.name FROM {node} n, {users} u WHERE n.uid = u.uid AND n.type = '%s' AND n.uid = %d ORDER BY n.created DESC", $blogid, $user->uid, 0, $number_of_posts); | |
345 } | |
346 $blogs = array(); | |
347 while ($blog = db_fetch_object($result)) { | |
348 $blogs[] = _blogapi_get_post($blog, $bodies); | |
349 } | |
350 return $blogs; | |
351 } | |
352 | |
353 function blogapi_metaweblog_new_post($blogid, $username, $password, $content, $publish) { | |
354 return blogapi_blogger_new_post('0123456789ABCDEF', $blogid, $username, $password, $content, $publish); | |
355 } | |
356 | |
357 function blogapi_metaweblog_edit_post($postid, $username, $password, $content, $publish) { | |
358 return blogapi_blogger_edit_post('0123456789ABCDEF', $postid, $username, $password, $content, $publish); | |
359 } | |
360 | |
361 function blogapi_metaweblog_get_post($postid, $username, $password) { | |
362 return blogapi_blogger_get_post('01234567890ABCDEF', $postid, $username, $password); | |
363 } | |
364 | |
365 /** | |
366 * Blogging API callback. Inserts a file into Drupal. | |
367 */ | |
368 function blogapi_metaweblog_new_media_object($blogid, $username, $password, $file) { | |
369 $user = blogapi_validate_user($username, $password); | |
370 if (!$user->uid) { | |
371 return blogapi_error($user); | |
372 } | |
373 | |
374 $name = basename($file['name']); | |
375 $data = $file['bits']; | |
376 | |
377 if (!$data) { | |
378 return blogapi_error(t('No file sent.')); | |
379 } | |
380 | |
381 if (!$file = file_save_data($data, $name)) { | |
382 return blogapi_error(t('Error storing file.')); | |
383 } | |
384 | |
385 // Return the successful result. | |
386 return array('url' => file_create_url($file), 'struct'); | |
387 } | |
388 /** | |
389 * Blogging API callback. Returns a list of the taxonomy terms that can be | |
390 * associated with a blog node. | |
391 */ | |
392 function blogapi_metaweblog_get_category_list($blogid, $username, $password) { | |
393 if (($error = _blogapi_validate_blogid($blogid)) !== TRUE) { | |
394 // Return an error if not configured type. | |
395 return $error; | |
396 } | |
397 | |
398 $vocabularies = module_invoke('taxonomy', 'get_vocabularies', $blogid, 'vid'); | |
399 $categories = array(); | |
400 if ($vocabularies) { | |
401 foreach ($vocabularies as $vocabulary) { | |
402 $terms = module_invoke('taxonomy', 'get_tree', $vocabulary->vid, 0, -1); | |
403 foreach ($terms as $term) { | |
404 $term_name = $term->name; | |
405 foreach (module_invoke('taxonomy', 'get_parents', $term->tid, 'tid') as $parent) { | |
406 $term_name = $parent->name .'/'. $term_name; | |
407 } | |
408 $categories[] = array('categoryName' => $term_name, 'categoryId' => $term->tid); | |
409 } | |
410 } | |
411 } | |
412 return $categories; | |
413 } | |
414 | |
415 function blogapi_metaweblog_get_recent_posts($blogid, $username, $password, $number_of_posts) { | |
416 return blogapi_blogger_get_recent_posts('0123456789ABCDEF', $blogid, $username, $password, $number_of_posts, TRUE); | |
417 } | |
418 | |
419 function blogapi_mt_get_recent_post_titles($blogid, $username, $password, $number_of_posts) { | |
420 return blogapi_blogger_get_recent_posts('0123456789ABCDEF', $blogid, $username, $password, $number_of_posts, FALSE); | |
421 } | |
422 | |
423 function blogapi_mt_get_category_list($blogid, $username, $password) { | |
424 return blogapi_metaweblog_get_category_list($blogid, $username, $password); | |
425 } | |
426 | |
427 /** | |
428 * Blogging API callback. Returns a list of the taxonomy terms that are | |
429 * assigned to a particular node. | |
430 */ | |
431 function blogapi_mt_get_post_categories($postid, $username, $password) { | |
432 $user = blogapi_validate_user($username, $password); | |
433 if (!$user->uid) { | |
434 return blogapi_error($user); | |
435 } | |
436 | |
437 $node = node_load($postid); | |
438 $terms = module_invoke('taxonomy', 'node_get_terms', $node, 'tid'); | |
439 $categories = array(); | |
440 foreach ($terms as $term) { | |
441 $term_name = $term->name; | |
442 foreach (module_invoke('taxonomy', 'get_parents', $term->tid, 'tid') as $parent) { | |
443 $term_name = $parent->name .'/'. $term_name; | |
444 } | |
445 $categories[] = array('categoryName' => $term_name, 'categoryId' => $term->tid, 'isPrimary' => TRUE); | |
446 } | |
447 | |
448 return $categories; | |
449 } | |
450 | |
451 /** | |
452 * Blogging API callback. Assigns taxonomy terms to a particular node. | |
453 */ | |
454 function blogapi_mt_set_post_categories($postid, $username, $password, $categories) { | |
455 $user = blogapi_validate_user($username, $password); | |
456 if (!$user->uid) { | |
457 return blogapi_error($user); | |
458 } | |
459 | |
460 $node = node_load($postid); | |
461 $node->taxonomy = array(); | |
462 foreach ($categories as $category) { | |
463 $node->taxonomy[] = $category['categoryId']; | |
464 } | |
465 node_save($node); | |
466 return TRUE; | |
467 } | |
468 | |
469 /** | |
470 * Blogging API callback. Sends a list of available input formats. | |
471 */ | |
472 function blogapi_mt_supported_text_filters() { | |
473 // NOTE: we're only using anonymous' formats because the MT spec | |
474 // does not allow for per-user formats. | |
475 $formats = filter_formats(); | |
476 | |
477 $filters = array(); | |
478 foreach ($formats as $format) { | |
479 $filter['key'] = $format->format; | |
480 $filter['label'] = $format->name; | |
481 $filters[] = $filter; | |
482 } | |
483 | |
484 return $filters; | |
485 } | |
486 | |
487 /** | |
488 * Blogging API callback. Publishes the given node | |
489 */ | |
490 function blogap_mti_publish_post($postid, $username, $password) { | |
491 $user = blogapi_validate_user($username, $password); | |
492 if (!$user->uid) { | |
493 return blogapi_error($user); | |
494 } | |
495 $node = node_load($postid); | |
496 if (!$node) { | |
497 return blogapi_error(t('Invalid post.')); | |
498 } | |
499 | |
500 $node->status = 1; | |
501 if (!node_access('update', $node)) { | |
502 return blogapi_error(t('You do not have permission to update this post.')); | |
503 } | |
504 | |
505 node_save($node); | |
506 | |
507 return TRUE; | |
508 } | |
509 | |
510 /** | |
511 * Prepare an error message for returning to the XMLRPC caller. | |
512 */ | |
513 function blogapi_error($message) { | |
514 static $xmlrpcusererr; | |
515 if (!is_array($message)) { | |
516 $message = array($message); | |
517 } | |
518 | |
519 $message = implode(' ', $message); | |
520 | |
521 return xmlrpc_error($xmlrpcusererr + 1, strip_tags($message)); | |
522 } | |
523 | |
524 /** | |
525 * Ensure that the given user has permission to edit a blog. | |
526 */ | |
527 function blogapi_validate_user($username, $password) { | |
528 global $user; | |
529 | |
530 $user = user_authenticate(array('name' => $username, 'pass' => $password)); | |
531 | |
532 if ($user->uid) { | |
533 if (user_access('administer content with blog api', $user)) { | |
534 return $user; | |
535 } | |
536 else { | |
537 return t('You do not have permission to edit this blog.'); | |
538 } | |
539 } | |
540 else { | |
541 return t('Wrong username or password.'); | |
542 } | |
543 } | |
544 | |
545 /** | |
546 * For the blogger API, extract the node title from the contents field. | |
547 */ | |
548 function blogapi_blogger_title(&$contents) { | |
549 if (eregi('<title>([^<]*)</title>', $contents, $title)) { | |
550 $title = strip_tags($title[0]); | |
551 $contents = ereg_replace('<title>[^<]*</title>', '', $contents); | |
552 } | |
553 else { | |
554 list($title, $contents) = explode("\n", $contents, 2); | |
555 } | |
556 return $title; | |
557 } | |
558 | |
559 function blogapi_admin_settings() { | |
560 $node_types = array_map('check_plain', node_get_types('names')); | |
561 $defaults = isset($node_types['blog']) ? array('blog' => 1) : array(); | |
562 $form['blogapi_node_types'] = array( | |
563 '#type' => 'checkboxes', | |
564 '#title' => t('Enable for external blogging clients'), | |
565 '#required' => TRUE, | |
566 '#default_value' => variable_get('blogapi_node_types', $defaults), | |
567 '#options' => $node_types, | |
568 '#description' => t('Select the content types available to external blogging clients via Blog API. If supported, each enabled content type will be displayed as a separate "blog" by the external client.') | |
569 ); | |
570 | |
571 return system_settings_form($form); | |
572 } | |
573 | |
574 function blogapi_menu() { | |
575 $items['blogapi/rsd'] = array( | |
576 'title' => 'RSD', | |
577 'page callback' => 'blogapi_rsd', | |
578 'access arguments' => array('access content'), | |
579 'type' => MENU_CALLBACK, | |
580 ); | |
581 $items['admin/settings/blogapi'] = array( | |
582 'title' => 'Blog API', | |
583 'description' => 'Configure the content types available to external blogging clients.', | |
584 'page callback' => 'drupal_get_form', | |
585 'page arguments' => array('blogapi_admin_settings'), | |
586 'access arguments' => array('administer site configuration'), | |
587 'type' => MENU_NORMAL_ITEM, | |
588 ); | |
589 | |
590 return $items; | |
591 } | |
592 | |
593 function blogapi_init() { | |
594 if (drupal_is_front_page()) { | |
595 drupal_add_link(array('rel' => 'EditURI', | |
596 'type' => 'application/rsd+xml', | |
597 'title' => t('RSD'), | |
598 'href' => url('blogapi/rsd', array('absolute' => TRUE)))); | |
599 } | |
600 } | |
601 | |
602 function blogapi_rsd() { | |
603 global $base_url; | |
604 | |
605 $xmlrpc = $base_url .'/xmlrpc.php'; | |
606 $base = url('', array('absolute' => TRUE)); | |
607 $blogid = 1; # until we figure out how to handle multiple bloggers | |
608 | |
609 drupal_set_header('Content-Type: application/rsd+xml; charset=utf-8'); | |
610 print <<<__RSD__ | |
611 <?xml version="1.0"?> | |
612 <rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd"> | |
613 <service> | |
614 <engineName>Drupal</engineName> | |
615 <engineLink>http://drupal.org/</engineLink> | |
616 <homePageLink>$base</homePageLink> | |
617 <apis> | |
618 <api name="MetaWeblog" preferred="false" apiLink="$xmlrpc" blogID="$blogid" /> | |
619 <api name="Blogger" preferred="false" apiLink="$xmlrpc" blogID="$blogid" /> | |
620 <api name="MovableType" preferred="true" apiLink="$xmlrpc" blogID="$blogid" /> | |
621 </apis> | |
622 </service> | |
623 </rsd> | |
624 __RSD__; | |
625 } | |
626 | |
627 /** | |
628 * Handles extra information sent by clients according to MovableType's spec. | |
629 */ | |
630 function _blogapi_mt_extra(&$node, $struct) { | |
631 if (is_array($node)) { | |
632 $was_array = TRUE; | |
633 $node = (object)$node; | |
634 } | |
635 | |
636 // mt_allow_comments | |
637 if (array_key_exists('mt_allow_comments', $struct)) { | |
638 switch ($struct['mt_allow_comments']) { | |
639 case 0: | |
640 $node->comment = COMMENT_NODE_DISABLED; | |
641 break; | |
642 case 1: | |
643 $node->comment = COMMENT_NODE_READ_WRITE; | |
644 break; | |
645 case 2: | |
646 $node->comment = COMMENT_NODE_READ_ONLY; | |
647 break; | |
648 } | |
649 } | |
650 | |
651 // merge the 3 body sections (description, mt_excerpt, mt_text_more) into | |
652 // one body | |
653 if ($struct['mt_excerpt']) { | |
654 $node->body = $struct['mt_excerpt'] .'<!--break-->'. $node->body; | |
655 } | |
656 if ($struct['mt_text_more']) { | |
657 $node->body = $node->body .'<!--extended-->'. $struct['mt_text_more']; | |
658 } | |
659 | |
660 // mt_convert_breaks | |
661 if ($struct['mt_convert_breaks']) { | |
662 $node->format = $struct['mt_convert_breaks']; | |
663 } | |
664 | |
665 // dateCreated | |
666 if ($struct['dateCreated']) { | |
667 $node->date = format_date(mktime($struct['dateCreated']->hour, $struct['dateCreated']->minute, $struct['dateCreated']->second, $struct['dateCreated']->month, $struct['dateCreated']->day, $struct['dateCreated']->year), 'custom', 'Y-m-d H:i:s O'); | |
668 } | |
669 | |
670 if ($was_array) { | |
671 $node = (array)$node; | |
672 } | |
673 } | |
674 | |
675 function _blogapi_get_post($node, $bodies = TRUE) { | |
676 $xmlrpcval = array( | |
677 'userid' => $node->name, | |
678 'dateCreated' => xmlrpc_date($node->created), | |
679 'title' => $node->title, | |
680 'postid' => $node->nid, | |
681 'link' => url('node/'. $node->nid, array('absolute' => TRUE)), | |
682 'permaLink' => url('node/'. $node->nid, array('absolute' => TRUE)), | |
683 ); | |
684 if ($bodies) { | |
685 if ($node->comment == 1) { | |
686 $comment = 2; | |
687 } | |
688 else if ($node->comment == 2) { | |
689 $comment = 1; | |
690 } | |
691 $xmlrpcval['content'] = "<title>$node->title</title>$node->body"; | |
692 $xmlrpcval['description'] = $node->body; | |
693 // Add MT specific fields | |
694 $xmlrpcval['mt_allow_comments'] = (int) $comment; | |
695 $xmlrpcval['mt_convert_breaks'] = $node->format; | |
696 } | |
697 | |
698 return $xmlrpcval; | |
699 } | |
700 | |
701 /** | |
702 * Validate blog ID, which maps to a content type in Drupal. | |
703 * | |
704 * Only content types configured to work with Blog API are supported. | |
705 * | |
706 * @return | |
707 * TRUE if the content type is supported and the user has permission | |
708 * to post, or a blogapi_error() XML construct otherwise. | |
709 */ | |
710 function _blogapi_validate_blogid($blogid) { | |
711 $types = _blogapi_get_node_types(); | |
712 if (in_array($blogid, $types, TRUE)) { | |
713 return TRUE; | |
714 } | |
715 return blogapi_error(t("Blog API module is not configured to support the %type content type, or you don't have sufficient permissions to post this type of content.", array('%type' => $blogid))); | |
716 } | |
717 | |
718 function _blogapi_get_node_types() { | |
719 $available_types = array_keys(array_filter(variable_get('blogapi_node_types', array('blog' => 1)))); | |
720 $types = array(); | |
721 foreach (node_get_types() as $type => $name) { | |
722 if (node_access('create', $type) && in_array($type, $available_types)) { | |
723 $types[] = $type; | |
724 } | |
725 } | |
726 | |
727 return $types; | |
728 } |