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 }