/[drupal]/contributions/modules/wlw_blogapi/wlw_blogapi.module
ViewVC logotype

Contents of /contributions/modules/wlw_blogapi/wlw_blogapi.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.16 - (show annotations) (download) (as text)
Tue Jan 6 06:31:46 2009 UTC (10 months, 3 weeks ago) by jrglasgow
Branch: MAIN
CVS Tags: DRUPAL-6--1-4, HEAD
Branch point for: DRUPAL-5, DRUPAL-6--1
Changes since 1.15: +6 -2 lines
File MIME type: text/x-php
When tags are heirarchical(sp) WLW submits the tag for the post as 'term/subterm' where term is the root for subterm. This fix will parse the terms and only submit the last subterm
1 <?php
2 // $Id: wlw_blogapi.module,v 1.15 2008/12/10 02:22:40 jrglasgow 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 wlw_blogapi_help($path, $arg) {
13 switch ($path) {
14 case 'admin/help#blogapi':
15 $output = '<p>'. t('The blog API module enables a post to be posted to a site via external GUI applications. Many users prefer to use external tools to improve their ability to read and post responses in a customized way. The blog api provides users the freedom to use the blogging tools they want but still have the blogging server of choice.') .'</p>';
16 $output .= '<p>'. t('When this module is enabled and configured you can use programs like <a href="@external-http-ecto-kung-foo-tv">Ecto</a> to create and publish posts from your desktop. Blog API module supports several XML-RPC based blogging APIs such as the <a href="@-">Blogger API</a>, <a href="@external-http-www-xmlrpc-com-metaWeblogApi">MetaWeblog API</a>, and most of the <a href="@external-http-www-movabletype-org-docs-mtmanual_programmatic-html">Movable Type API</a>. Any desktop blogging tools or other services (e.g. <a href="@external-http-www-flickr-com">Flickr\'s</a> "post to blog") that support these APIs should work with this site.', array('@external-http-ecto-kung-foo-tv' => 'http://ecto.kung-foo.tv/', '@-' => url('http://www.blogger.com/developers/api/1_docs/'), '@external-http-www-xmlrpc-com-metaWeblogApi' => 'http://www.xmlrpc.com/metaWeblogApi', '@external-http-www-movabletype-org-docs-mtmanual_programmatic-html' => 'http://www.movabletype.org/docs/mtmanual_programmatic.html', '@external-http-www-flickr-com' => 'http://www.flickr.com')) .'</p>';
17 $output .= '<p>'. t('This module also allows site administrators to configure which content types can be posted via the external applications. So, for instance, users can post forum topics as well as blog posts. Where supported, the external applications will display each content type as a separate "blog".') .'</p>';
18 $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="@blogapi">BlogApi page</a>.', array('@blogapi' => 'http://drupal.org/handbook/modules/blogapi/')) .'</p>';
19 return $output;
20 }
21 }
22
23 /**
24 * Implementation of hook_perm().
25 */
26 function wlw_blogapi_perm() {
27 return array('administer content with blog api');
28 }
29
30 /**
31 * Implementation of hook_xmlrpc().
32 */
33 function wlw_blogapi_xmlrpc() {
34 return array(
35 array(
36 'blogger.getUsersBlogs',
37 'wlw_blogapi_blogger_get_users_blogs',
38 array('array', 'string', 'string', 'string'),
39 t('Returns a list of weblogs to which an author has posting privileges.')),
40 array(
41 'blogger.getUserInfo',
42 'wlw_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 'wlw_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 'wlw_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 'wlw_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 'wlw_blogapi_blogger_delete_post',
63 array('boolean', 'string', 'string', 'string', 'string', 'boolean'),
64 t('Deletes a post.')),
65 array(
66 'blogger.getRecentPosts',
67 'wlw_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 'wlw_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 'wlw_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 'wlw_blogapi_metaweblog_get_post',
83 array('struct', 'string', 'string', 'string'),
84 t('Returns information about a specific post.')),
85 array(
86 'metaWeblog.newMediaObject',
87 'wlw_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 'wlw_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 'wlw_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 'wlw_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 'wlw_blogapi_mt_get_category_list',
108 array('array', 'string', 'string', 'string'),
109 t('Returns a list of all categories defined in the weblog.')),
110 array(
111 'mt.getPostCategories',
112 'wlw_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 'wlw_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 'wlw_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 'wlw_blogapi_mt_publish_post',
133 array('boolean', 'string', 'string', 'string'),
134 t('Publish (rebuild) all of the static files related to an entry from your weblog. 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 wlw_blogapi_blogger_get_users_blogs($appid, $username, $password) {
142
143 $user = wlw_blogapi_validate_user($username, $password);
144 if ($user->uid) {
145 $types = _wlw_blogapi_get_node_types();
146 $structs = array();
147 foreach ($types as $type) {
148 if (strcmp($type, 'blog') == 0) {
149 $url = 'blog/'. $user->uid;
150 $blogName = $user->name .': '. $type;
151 }
152 else {
153 $url = 'node';
154 $blogName = $user->name .': '. $type;
155 }
156 $structs[] = array('url' => url($url, array('absolute' => TRUE)), 'blogid' => $type, 'blogName' => $blogName);
157 }
158 return $structs;
159 }
160 else {
161 return wlw_blogapi_error($user);
162 }
163 }
164
165 /**
166 * Blogging API callback. Returns profile information about a user.
167 */
168 function wlw_blogapi_blogger_get_user_info($appkey, $username, $password) {
169 $user = wlw_blogapi_validate_user($username, $password);
170
171 if ($user->uid) {
172 $name = explode(' ', $user->realname ? $user->realname : $user->name, 2);
173 return array(
174 'userid' => $user->uid,
175 'lastname' => $name[1],
176 'firstname' => $name[0],
177 'nickname' => $user->name,
178 'email' => $user->mail,
179 'url' => url('blog/'. $user->uid, array('absolute', TRUE)));
180 }
181 else {
182 return wlw_blogapi_error($user);
183 }
184 }
185
186 /**
187 * Blogging API callback. Inserts a new blog post as a node.
188 */
189 function wlw_blogapi_blogger_new_post($appkey, $blogid, $username, $password, $content, $publish) {
190 $args = func_get_args();
191 // since some modules assume that the user is logged in in their hook_nodeapi()
192 // wlw_blogapi has to set the global variable
193 global $user;
194 if (!$user->uid) {
195 $user = wlw_blogapi_validate_user($username, $password);
196 }
197 if (!$user->uid) {
198 return wlw_blogapi_error($user);
199 }
200
201 $edit = array();
202 $edit['type'] = _wlw_blogapi_blogid($blogid);
203 // get the node type defaults
204 $node_type_default = variable_get('node_options_'. $edit['type'], array('status', 'promote'));
205 $edit['uid'] = $user->uid;
206 $edit['name'] = $user->name;
207 $edit['promote'] = in_array('promote', $node_type_default);
208 $edit['comment'] = variable_get('comment_'. $edit['type'], 2);
209 $edit['revision'] = in_array('revision', $node_type_default);
210 $edit['format'] = FILTER_FORMAT_DEFAULT;
211 $edit['status'] = $publish;
212 //watchdog('wlw_blogapi', 'content = <pre>$content</pre>', array('$content' => print_r($content, true)), WATCHDOG_DEBUG);
213 // check for bloggerAPI vs. metaWeblogAPI
214 if (is_array($content)) {
215 $edit['title'] = $content['title'];
216 $edit['body'] = $content['description'];
217 _wlw_blogapi_mt_extra($edit, $content);
218 }
219 else {
220 $edit['title'] = wlw_blogapi_blogger_title($content);
221 $edit['body'] = $content;
222 }
223
224 if (!node_access('create', $edit['type'])) {
225 return wlw_blogapi_error(t('You do not have permission to create the type of post you wanted to create.'));
226 }
227
228 if (user_access('administer nodes') && !isset($edit['date'])) {
229 $edit['date'] = format_date(time(), 'custom', 'Y-m-d H:i:s O');
230 }
231 $edit['body'] = _wlw_blogapi_filter_extra_code($edit['body']);
232 $edit['title'] = _wlw_blogapi_filter_extra_code($edit['title']);
233 node_invoke_nodeapi($edit, 'blogapi new');
234
235 node_validate($edit);
236 if ($errors = form_get_errors()) {
237 return wlw_blogapi_error(implode("\n", $errors));
238 }
239
240 $node = node_submit($edit);
241 node_save($node);
242 if ($node->nid) {
243 watchdog('content', '@type: added %title using WLW Blog API.', array('@type' => t($node->type), '%title' => $node->title), WATCHDOG_NOTICE, l(t('view'), "node/$node->nid"));
244 // blogger.newPost returns a string so we cast the nid to a string by putting it in double quotes:
245 return "$node->nid";
246 }
247
248 return wlw_blogapi_error(t('Error storing post.'));
249 }
250
251 /**
252 * Blogging API callback. Modifies the specified blog node.
253 */
254 function wlw_blogapi_blogger_edit_post($appkey, $postid, $username, $password, $content, $publish) {
255 // since some modules assume that the user is logged in in their hook_nodeapi()
256 // wlw_blogapi has to set the global variable
257 global $user;
258 if (!$user->uid) {
259 $user = wlw_blogapi_validate_user($username, $password);
260 }
261 if (!$user->uid) {
262 return wlw_blogapi_error($user);
263 }
264
265 $node = node_load($postid);
266 if (!$node) {
267 return wlw_blogapi_error(t('n/a'));
268 }
269 // Let the teaser be re-generated.
270 unset($node->teaser);
271
272 if (!node_access('update', $node)) {
273 return wlw_blogapi_error(t('You do not have permission to update this post.'));
274 }
275
276 $node->status = $publish;
277
278 // check for bloggerAPI vs. metaWeblogAPI
279 if (is_array($content)) {
280 $node->title = $content['title'];
281 $node->body = $content['description'];
282 _wlw_blogapi_mt_extra($node, $content);
283 }
284 else {
285 $node->title = blogapi_blogger_title($content);
286 $node->body = $content;
287 }
288
289 node_invoke_nodeapi($node, 'blogapi edit');
290
291 node_validate($node);
292 if ($errors = form_get_errors()) {
293 return wlw_blogapi_error(implode("\n", $errors));
294 }
295
296 if (user_access('administer nodes') && !isset($edit['date'])) {
297 $node->date = format_date($node->created, 'custom', 'Y-m-d H:i:s O');
298 }
299 $node->body = _wlw_blogapi_filter_extra_code($node->body);
300 $node->title = _wlw_blogapi_filter_extra_code($node->title);
301 $node = node_submit($node);
302 node_save($node);
303 if ($node->nid) {
304 watchdog('content', '@type: updated %title using WLW Blog API.', array('@type' => t($node->type), '%title' => $node->title), WATCHDOG_NOTICE, l(t('view'), "node/$node->nid"));
305 return TRUE;
306 }
307
308 return wlw_blogapi_error(t('Error storing post.'));
309 }
310
311 /**
312 * Blogging API callback. Returns a specified blog node.
313 */
314 function wlw_blogapi_blogger_get_post($appkey, $postid, $username, $password) {
315 $user = wlw_blogapi_validate_user($username, $password);
316 if (!$user->uid) {
317 return wlw_blogapi_error($user);
318 }
319
320 $node = node_load($postid);
321
322 return _wlw_blogapi_get_post($node, TRUE);
323 }
324
325 /**
326 * Blogging API callback. Removes the specified blog node.
327 */
328 function wlw_blogapi_blogger_delete_post($appkey, $postid, $username, $password, $publish) {
329 $user = wlw_blogapi_validate_user($username, $password);
330 if (!$user->uid) {
331 return wlw_blogapi_error($user);
332 }
333
334 node_delete($postid);
335 return TRUE;
336 }
337
338 /**
339 * Blogging API callback. Returns the latest few postings in a user's blog. $bodies TRUE
340 * <a href="http://movabletype.org/docs/mtmanual_programmatic.html#item_mt%2EgetRecentPostTitles">
341 * returns a bandwidth-friendly list</a>.
342 */
343 function wlw_blogapi_blogger_get_recent_posts($appkey, $blogid, $username, $password, $number_of_posts, $bodies = TRUE) {
344 // Remove unused appkey (from bloggerAPI).
345 $user = wlw_blogapi_validate_user($username, $password);
346 if (!$user->uid) {
347 return wlw_blogapi_error($user);
348 }
349
350 $type = _wlw_blogapi_blogid($blogid);
351 if ($bodies) {
352 $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", $type, $user->uid, 0, $number_of_posts);
353 }
354 else {
355 $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", $type, $user->uid, 0, $number_of_posts);
356 }
357 $blogs = array();
358 while ($blog = db_fetch_object($result)) {
359 $blogs[] = _wlw_blogapi_get_post($blog, $bodies);
360 }
361 return $blogs;
362 }
363
364 function wlw_blogapi_metaweblog_new_post($blogid, $username, $password, $content, $publish) {
365 $args = func_get_args();
366 return wlw_blogapi_blogger_new_post('0123456789ABCDEF', $blogid, $username, $password, $content, $publish);
367 }
368
369 function wlw_blogapi_metaweblog_edit_post($postid, $username, $password, $content, $publish) {
370 return wlw_blogapi_blogger_edit_post('0123456789ABCDEF', $postid, $username, $password, $content, $publish);
371 }
372
373 function wlw_blogapi_metaweblog_get_post($postid, $username, $password) {
374 return wlw_blogapi_blogger_get_post('01234567890ABCDEF', $postid, $username, $password);
375 }
376
377 /**
378 * Blogging API callback. Inserts a file into Drupal.
379 */
380 function wlw_blogapi_metaweblog_new_media_object($blogid, $username, $password, $file) {
381 $user = wlw_blogapi_validate_user($username, $password);
382 if (!$user->uid) {
383 return wlw_blogapi_error($user);
384 }
385
386 $usersize = 0;
387 $uploadsize = 0;
388
389 $roles = array_intersect(user_roles(0, 'administer content with blog api'), $user->roles);
390
391 foreach ($roles as $rid => $name) {
392 $extensions .= ' '. strtolower(variable_get("blogapi_extensions_$rid", variable_get('blogapi_extensions_default', 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp')));
393 $usersize= max($usersize, variable_get("blogapi_usersize_$rid", variable_get('blogapi_usersize_default', 1)) * 1024 * 1024);
394 $uploadsize = max($uploadsize, variable_get("blogapi_uploadsize_$rid", variable_get('blogapi_uploadsize_default', 1)) * 1024 * 1024);
395 }
396
397 $filesize = strlen($file['bits']);
398
399 if ($filesize > $uploadsize) {
400 return wlw_blogapi_error(t('It is not possible to upload the file, because it exceeded the maximum filesize of @maxsize.', array('@maxsize' => format_size($uploadsize))));
401 }
402
403 if (_wlw_blogapi_space_used($user->uid) + $filesize > $usersize) {
404 return wlw_blogapi_error(t('The file can not be attached to this post, because the disk quota of @quota has been reached.', array('@quota' => format_size($usersize))));
405 }
406
407 // Only allow files with whitelisted extensions and convert remaining dots to
408 // underscores to prevent attacks via non-terminal executable extensions with
409 // files such as exploit.php.jpg.
410
411 $whitelist = array_unique(explode(' ', trim($extensions)));
412
413 $name = basename($file['name']);
414
415 if ($extension_position = strrpos($name, '.')) {
416 $filename = drupal_substr($name, 0, $extension_position);
417 $final_extension = drupal_substr($name, $extension_position + 1);
418
419 if (!in_array(strtolower($final_extension), $whitelist)) {
420 return wlw_blogapi_error(t('It is not possible to upload the file, because it is only possible to upload files with the following extensions: @extensions', array('@extensions' => implode(' ', $whitelist))));
421 }
422
423 $filename = str_replace('.', '_', $filename);
424 $filename .= '.'. $final_extension;
425 }
426
427 $data = $file['bits'];
428
429 if (!$data) {
430 return wlw_blogapi_error(t('No file sent.'));
431 }
432
433 if (!$file = file_save_data($data, $filename)) {
434 return wlw_blogapi_error(t('Error storing file.'));
435 }
436
437 db_query("INSERT INTO {blogapi_files} (uid, filepath, filesize) VALUES (%d, '%s', %d)", $user->uid, $file, $filesize);
438
439 // Return the successful result.
440 return array('url' => file_create_url($file), 'struct');
441 }
442
443 /**
444 * Blogging API callback. Returns a list of the taxonomy terms that can be
445 * associated with a blog node.
446 */
447 function wlw_blogapi_metaweblog_get_category_list($blogid, $username, $password) {
448 $type = _wlw_blogapi_blogid($blogid);
449 $vocabularies = module_invoke('taxonomy', 'get_vocabularies', $type, 'vid');
450 $categories = array();
451 if ($vocabularies) {
452 foreach ($vocabularies as $vocabulary) {
453 $terms = module_invoke('taxonomy', 'get_tree', $vocabulary->vid, 0, -1);
454 foreach ($terms as $term) {
455 $term_name = $term->name;
456 foreach (module_invoke('taxonomy', 'get_parents', $term->tid, 'tid') as $parent) {
457 $term_name = $parent->name .'/'. $term_name;
458 }
459 $categories[] = array('categoryName' => $term_name, 'categoryId' => $term->tid);
460 }
461 }
462 }
463 return $categories;
464 }
465
466 function wlw_blogapi_metaweblog_get_recent_posts($blogid, $username, $password, $number_of_posts) {
467 return wlw_blogapi_blogger_get_recent_posts('0123456789ABCDEF', $blogid, $username, $password, $number_of_posts, TRUE);
468 }
469
470 // see above
471 function wlw_blogapi_mt_get_recent_post_titles($blogid, $username, $password, $number_of_posts) {
472 return wlw_blogapi_blogger_get_recent_posts('0123456789ABCDEF', $blogid, $username, $password, $number_of_posts, FALSE);
473 }
474
475 /* **** */
476 function wlw_blogapi_mt_get_category_list($blogid, $username, $password) {
477 return wlw_blogapi_metaweblog_get_category_list($blogid, $username, $password);
478 }
479
480 /**
481 * Blogging API callback. Returns a list of the taxonomy terms that are
482 * assigned to a particular node.
483 */
484 function wlw_blogapi_mt_get_post_categories($postid, $username, $password) {
485 $user = wlw_blogapi_validate_user($username, $password);
486 if (!$user->uid) {
487 return wlw_blogapi_error($user);
488 }
489
490 $terms = module_invoke('taxonomy', 'node_get_terms', $postid, 'tid');
491 $categories = array();
492 foreach ($terms as $term) {
493 $term_name = $term->name;
494 foreach (module_invoke('taxonomy', 'get_parents', $term->tid, 'tid') as $parent) {
495 $term_name = $parent->name .'/'. $term_name;
496 }
497 $categories[] = array('categoryName' => $term_name, 'categoryId' => $term->tid, 'isPrimary' => TRUE);
498 }
499 return $categories;
500 }
501
502 /**
503 * Blogging API callback. Assigns taxonomy terms to a particular node.
504 */
505 function wlw_blogapi_mt_set_post_categories($postid, $username, $password, $categories) {
506 global $user;
507 if (!$user->uid) {
508 $user = wlw_blogapi_validate_user($username, $password);
509 }
510 if (!$user->uid) {
511 return wlw_blogapi_error($user);
512 }
513
514 $node = node_load($postid);
515 $node->taxonomy = array();
516 foreach ($categories as $category) {
517 $node->taxonomy[] = $category['categoryId'];
518 }
519 node_save($node);
520 return TRUE;
521 }
522
523 /**
524 * Blogging API callback. Sends a list of available input formats.
525 */
526 function wlw_blogapi_mt_supported_text_filters() {
527 // NOTE: we're only using anonymous' formats because the MT spec
528 // does not allow for per-user formats.
529 $formats = filter_formats();
530
531 $filters = array();
532 foreach ($formats as $format) {
533 $filter['key'] = $format->format;
534 $filter['label'] = $format->name;
535 $filters[] = $filter;
536 }
537
538 return $filters;
539 }
540
541 /**
542 * Blogging API callback. Publishes the given node
543 */
544 function wlw_blogapi_mt_publish_post($postid, $username, $password) {
545 $user = wlw_blogapi_validate_user($username, $password);
546 if (!$user->uid) {
547 return wlw_blogapi_error($user);
548 }
549 $node = node_load($postid);
550 if (!$node) {
551 return wlw_blogapi_error(t('Invalid post.'));
552 }
553
554 $node->status = 1;
555 if (!node_access('update', $node)) {
556 return wlw_blogapi_error(t('You do not have permission to update this post.'));
557 }
558
559 node_save($node);
560
561 return TRUE;
562 }
563
564 /**
565 * Prepare an error message for returning to the XMLRPC caller.
566 */
567 function wlw_blogapi_error($message) {
568 static $xmlrpcusererr;
569 if (!is_array($message)) {
570 $message = array($message);
571 }
572
573 $message = implode(' ', $message);
574
575 return xmlrpc_error($xmlrpcusererr + 1, strip_tags($message));
576 }
577
578 /**
579 * Ensure that the given user has permission to edit a blog.
580 */
581 function wlw_blogapi_validate_user($username, $password) {
582 global $user;
583
584 $user = user_authenticate(array('name' => $username, 'pass' => $password));
585 if ($user->uid) {
586 if (user_access('administer content with blog api', $user)) {
587 return $user;
588 }
589 else {
590 return t("You either tried to edit somebody else's blog or you don't have permission to edit your own blog.");
591 }
592 }
593 else {
594 return t('Wrong username or password.');
595 }
596 }
597
598 /**
599 * For the blogger API, extract the node title from the contents field.
600 */
601 function wlw_blogapi_blogger_title(&$contents) {
602 if (eregi('<title>([^<]*)</title>', $contents, $title)) {
603 $title = strip_tags($title[0]);
604 $contents = ereg_replace('<title>[^<]*</title>', '', $contents);
605 }
606 else {
607 list($title, $contents) = explode("\n", $contents, 2);
608 }
609 return $title;
610 }
611
612 function wlw_blogapi_admin_settings_form() {
613 $node_types = array_map('check_plain', node_get_types('names'));
614 $defaults = isset($node_types['blog']) ? array('blog' => 1) : array();
615 $form['blogapi_node_types'] = array(
616 '#type' => 'checkboxes',
617 '#title' => t('Blog types'),
618 '#required' => TRUE,
619 '#default_value' => variable_get('blogapi_node_types', $defaults),
620 '#options' => $node_types,
621 '#description' => t('Select the content types for which you wish to enable posting via blogapi. Each type will appear as a different "blog" in the client application (if supported).')
622 );
623 $menus = array('none' => 'None');
624 $menus += menu_get_menus(TRUE);
625 $form['menu_settings'] = array(
626 '#type' => 'fieldset',
627 '#title' => 'Menu Settings',
628 '#description' => 'When a node is added it can be automatically added to a menu. Choose which menu nodes of each type wil be added to.',
629 '#collapsible' => TRUE,
630 '#collapsed' => FALSE,
631 );
632 foreach ($node_types as $key => $value) {
633 $form['menu_settings']['wlw_blogapi_menu_'. $key] = array(
634 '#type' => 'select',
635 '#options' => $menus,
636 '#default_value' => variable_get('wlw_blogapi_menu_'. $key, 'none'),
637 '#title' => $value,
638 );
639 }
640 $form['blogapi_excerpt'] = array(
641 '#type' => 'checkbox',
642 '#title' => t('Use Excerpt'),
643 '#description' => t('Will you use the excerpt field to input your teaser?'),
644 '#default_value' => variable_get('blogapi_excerpt', 0),
645 );
646
647 $blogapi_extensions_default = variable_get('blogapi_extensions_default', 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp');
648 $blogapi_uploadsize_default = variable_get('blogapi_uploadsize_default', 1);
649 $blogapi_usersize_default = variable_get('blogapi_usersize_default', 1);
650
651 $form['settings_general'] = array(
652 '#type' => 'fieldset',
653 '#title' => t('File settings'),
654 '#collapsible' => TRUE,
655 );
656
657 $form['settings_general']['blogapi_extensions_default'] = array(
658 '#type' => 'textfield',
659 '#title' => t('Default permitted file extensions'),
660 '#default_value' => $blogapi_extensions_default,
661 '#maxlength' => 255,
662 '#description' => t('Default extensions that users can upload. Separate extensions with a space and do not include the leading dot.'),
663 );
664
665 $form['settings_general']['blogapi_uploadsize_default'] = array(
666 '#type' => 'textfield',
667 '#title' => t('Default maximum file size per upload'),
668 '#default_value' => $blogapi_uploadsize_default,
669 '#size' => 5,
670 '#maxlength' => 5,
671 '#description' => t('The default maximum file size a user can upload.'),
672 '#field_suffix' => t('MB')
673 );
674
675 $form['settings_general']['blogapi_usersize_default'] = array(
676 '#type' => 'textfield',
677 '#title' => t('Default total file size per user'),
678 '#default_value' => $blogapi_usersize_default,
679 '#size' => 5,
680 '#maxlength' => 5,
681 '#description' => t('The default maximum size of all files a user can have on the site.'),
682 '#field_suffix' => t('MB')
683 );
684
685 $form['settings_general']['upload_max_size'] = array('#value' => '<p>'. t('Your PHP settings limit the maximum file size per upload to %size.', array('%size' => format_size(file_upload_max_size()))) .'</p>');
686
687 $roles = user_roles(0, 'administer content with blog api');
688 $form['roles'] = array('#type' => 'value', '#value' => $roles);
689
690
691
692 foreach ($roles as $rid => $role) {
693 $form['settings_role_'. $rid] = array(
694 '#type' => 'fieldset',
695 '#title' => t('Settings for @role', array('@role' => $role)),
696 '#collapsible' => TRUE,
697 '#collapsed' => TRUE,
698 );
699 $form['settings_role_'. $rid]['blogapi_extensions_'. $rid] = array(
700 '#type' => 'textfield',
701 '#title' => t('Permitted file extensions'),
702 '#default_value' => variable_get('blogapi_extensions_'. $rid, $blogapi_extensions_default),
703 '#maxlength' => 255,
704 '#description' => t('Extensions that users in this role can upload. Separate extensions with a space and do not include the leading dot.'),
705 );
706 $form['settings_role_'. $rid]['blogapi_uploadsize_'. $rid] = array(
707 '#type' => 'textfield',
708 '#title' => t('Maximum file size per upload'),
709 '#default_value' => variable_get('blogapi_uploadsize_'. $rid, $blogapi_uploadsize_default),
710 '#size' => 5,
711 '#maxlength' => 5,
712 '#description' => t('The maximum size of a file a user can upload (in megabytes).'),
713 );
714 $form['settings_role_'. $rid]['blogapi_usersize_'. $rid] = array(
715 '#type' => 'textfield',
716 '#title' => t('Total file size per user'),
717 '#default_value' => variable_get('blogapi_usersize_'. $rid, $blogapi_usersize_default),
718 '#size' => 5,
719 '#maxlength' => 5,
720 '#description' => t('The maximum size of all files a user can have on the site (in megabytes).'),
721 );
722 }/**
723 $form['submit'] = array(
724 '#type' => 'submit',
725 '#value' => 'Submit',
726 );
727 $form['submit'] = array(
728 '#type' => 'submit',
729 '#value' => 'Reset',
730 );/**/
731 $form = system_settings_form($form);
732 //$form['#theme'] = 'wlw_blogapi_admin_settings_form';
733 //drupal_set_message('$form = <pre>'. print_r($form, TRUE) .'</pre>');
734 //drupal_rebuild_theme_registry();
735 //$hooks = theme_get_registry();
736 //drupal_set_message('$hooks = <pre>'. print_r($hooks, TRUE) .'</pre>');
737
738 return $form;
739 }
740 function theme_wlw_blogapi_admin_settings_form(&$form, &$form_state) {
741 $args = func_get_args();
742 drupal_set_message('$args = <pre>'. print_r($args, TRUE) .'</pre>');
743 }
744 /**
745 * implementation os hook_init()
746 */
747 function wlw_blogapi_init() {
748 drupal_add_link(array(
749 'rel' => 'wlwmanifest',
750 'type' => 'application/wlwmanifest+xml',
751 'href' => url('blogapi/wlwmanifest.xml', array('absolute' => TRUE))
752 ));
753 drupal_add_link(array(
754 'rel' => 'EditURI',
755 'type' => 'application/rsd+xml',
756 'title' => t('RSD'),
757 'href' => url('blogapi/rsd', array('absolute' => TRUE))
758 ));
759 }
760
761
762 function wlw_blogapi_menu() {
763 $items = array();
764
765 $items['blogapi'] = array(
766 'title' => 'RSD',
767 'page callback' => 'wlw_blogapi_blogapi',
768 'access arguments' => array('access content'),
769 'type' => MENU_CALLBACK
770 );
771 $items['admin/settings/wlw_blogapi'] = array(
772 'title' => 'WLW Blog API',
773 'description' => 'Configure which content types blog clients can use, as well as WLW settings.',
774 'page callback' => 'drupal_get_form',
775 'page arguments' => array('wlw_blogapi_admin_settings_form'),
776 'access arguments' => array('administer site configuration'),
777 'type' => MENU_NORMAL_ITEM
778 );
779 $items['blogapi/wlwmanifest.xml'] = array(
780 'title' => 'WLW Manifest',
781 'description' => 'This provides the wlwmanifest.xml file for WLW configuration',
782 'page callback' => '_wlw_blogapi_wlwmanifest',
783 'type' => MENU_CALLBACK,
784 'access callback' => TRUE,
785 );
786 return $items;
787 }
788
789 function wlw_blogapi_blogapi() {
790 switch (arg(1)) {
791 case 'rsd':
792 wlw_blogapi_rsd();
793 break;
794 default:
795 drupal_not_found();
796 break;
797 }
798 }
799
800 function wlw_blogapi_rsd() {
801 global $base_url;
802
803 $xmlrpc = $base_url .'/'.'xmlrpc.php';
804 $base = url('', array('absolute' => TRUE));
805 $blogid = 1; # until we figure out how to handle multiple bloggers
806
807 drupal_set_header('Content-Type: application/rsd+xml; charset=utf-8');
808 print <<<__RSD__
809 <?xml version="1.0"?>
810 <rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
811 <service>
812 <engineName>Drupal</engineName>
813 <engineLink>http://drupal.org/</engineLink>
814 <homePageLink>$base</homePageLink>
815 <apis>
816 <api name="MetaWeblog" preferred="false" apiLink="$xmlrpc" blogID="$blogid" />
817 <api name="Blogger" preferred="false" apiLink="$xmlrpc" blogID="$blogid" />
818 <api name="MovableType" preferred="true" apiLink="$xmlrpc" blogID="$blogid" />
819 </apis>
820 </service>
821 </rsd>
822 __RSD__;
823 }
824
825 /**
826 * Handles extra information sent by clients according to MovableType's spec.
827 */
828 function _wlw_blogapi_mt_extra(&$node, $struct) {
829 //watchdog('wlw_blogapi', 'struct = <pre>@struct</pre>', array('@struct' => print_r($struct, true)), WATCHDOG_DEBUG);
830
831 if (is_array($node)) {
832 $was_array = TRUE;
833 $node = (object)$node;
834 }
835
836 // take the categories from the struct and add them to the first vocabulary
837 // that allows free tagging that is assigned to the node type
838 $vocabs = taxonomy_get_vocabularies($node->type);
839 $vocab_to_use_for_tags = 0;
840 foreach ($vocabs as $vocab) {
841 if ($vocab_to_use_for_tags) {
842 continue;
843 }
844 else if ($vocab->tags) {
845 $vocab_to_use_for_tags = $vocab->vid;
846 }
847 }
848 if ($vocab_to_use_for_tags) {
849 $tags = array();
850 foreach ($struct['categories'] as $tag) {
851 // if there is a heirarchy we will only submit the last branch
852 $tag = explode('/', $tag);
853 $tag = array_reverse($tag);
854 $tag = $tag[0];
855 $tags[$vocab_to_use_for_tags] .= $tag .', ';
856 }
857 }
858 $node->taxonomy = array('tags' => $tags);
859
860
861 // set the nodewords variable, if the nodewords (Meta Tags) module
862 // is installed this will take the keywords submitted and set those
863 // as the meta tags
864 if (isset($struct['mt_keywords'])) {
865 $node->nodewords = array(
866 'description' => '',
867 'keywords' => $struct['mt_keywords'],
868 );
869 }
870 // mt_allow_comments
871 if (array_key_exists('mt_allow_comments', $struct)) {
872 switch ($struct['mt_allow_comments']) {
873 case 0:
874 $node->comment = COMMENT_NODE_DISABLED;
875 break;
876 case 1:
877 $node->comment = COMMENT_NODE_READ_WRITE;
878 break;
879 case 2:
880 $node->comment = COMMENT_NODE_READ_ONLY;
881 break;
882 }
883 }
884 // add the new node to the menu
885 $menu = variable_get('wlw_blogapi_menu_'. $node->type, 'none');
886 if (($menu !== 'none') && (!isset($node->nid))) {
887 //watchdog('wlw_blogapi', 'wlw_blogapi_mt_extra node = <pre>@node</pre>', array('@node' => print_r($node, true)), WATCHDOG_DEBUG);
888 $node->menu = array(
889 'module' => 'menu',
890 'menu_name' => $menu,
891 'link_title' => $struct['title'],
892 );
893 }
894 // do the slug or url_alias
895 if ($struct['wp_slug']) {
896 $node->path = $struct['wp_slug'];
897 }
898
899 // merge the 3 body sections (description, mt_excerpt, mt_text_more) into one body
900 if ($struct['mt_excerpt']) {
901 $node->body = $struct['mt_excerpt'] .'<!--break-->'. $node->body;
902 }
903 if ($struct['mt_text_more']) {
904 $node->body = $node->body .'<!--break-->'. $struct['mt_text_more'];
905 }
906
907 // mt_convert_breaks
908 if ($struct['mt_convert_breaks']) {
909 $node->format = $struct['mt_convert_breaks'];
910 }
911
912 // dateCreated
913 if ($struct['dateCreated']) {
914 //$formatted_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');
915 //So WLW claims to give the date in ISO8601 format, they don't quite,
916 // they give the time in UTC but don't declare it, also this function
917 // didn't even worry about the time zone except to format for it.
918 $formatted_date = format_date(strtotime($struct['dateCreated']->iso8601 .'+00:00'), 'custom', 'Y-m-d H:i:s O');
919 //watchdog('wlw_blogapi', 'dateCreated = <pre>$dateCreated</pre><br/>date = $date<br/>formatted_date = $formatted_date', array('$dateCreated' => print_r($struct['dateCreated'], true), '$date' => date('r', strtotime($struct['dateCreated']->iso8601 .'+00:00')),'$formatted_date' => $formatted_date ), WATCHDOG_DEBUG);
920 $node->date = $formatted_date;
921 }
922 // take care of special chars in title
923 //watchdog('wlw_blogapi', 'func: _wlw_blogapi_mt_extra, node = <pre>$node</pre>', array('$node' => print_r($node, true)));
924 $node->title = str_replace('&amp;', '&', $node->title);
925 //watchdog('wlw_blogapi', 'func: _wlw_blogapi_mt_extra 2, node = <pre>$node</pre>', array('$node' => print_r($node, true)));
926 $title = $node->title;
927 //watchdog('wlw_blogapi', 'func: _wlw_blogapi_mt_extra 1, title = $title', array('$title' => print_r($title, true)));
928 $temp = array();
929 $title2 = 'Ž';
930 for ($i = 0; $i <= 20; $i++) {
931 $temp[] = $title2[$i];
932 }
933 if ($was_array) {
934 $node = (array)$node;
935 }
936 }
937
938 /**
939 * Some times with WYSIWYG editors you have the problem
940 * where they like to add extra code, usually without your
941 * knowledge, until you go to look at the final result and
942 * you see the result.
943 *
944 * _wlw_blogapi_filter_extra_code() Filter out some extra code that is
945 * usually unwanted. Code that usually adds undesired
946 * whitespace
947 */
948 function _wlw_blogapi_filter_extra_code($text) {
949 $text = str_replace('<p>&#160;</p>', '', $text);
950 $text = str_replace('<p>&nbsp</p>', '', $text);
951 $text = str_replace('<p></p>', '', $text);
952 //$text = str_Replace('&eacute;', 'Ž', $text);
953 //$text = str_Replace('&#233;', 'Ž', $text);
954 //watchdog('wlw_blogapi', 'func: _wlw_blogapi_filter_extra_code, text = <pre>$text</pre>', array('$text' => print_r($text, true)));
955 return $text;
956 }
957 function wlw_blogapi_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
958 switch ($op) {
959 case 'insert':
960 case 'update':
961 case 'presave':
962 //$text = str_Replace('Ž', '&#233;', $text);
963 //watchdog('wlw_blogapi', 'func: wlw_blogapi_nodeapi, node = <pre>'. print_r($node, true) .'</pre>');
964 break;
965 }
966 }
967 function _wlw_blogapi_get_post($node, $bodies = TRUE) {
968 $xmlrpcval = array(
969 'userid' => $node->name,
970 'dateCreated' => xmlrpc_date($node->created),
971 'title' => $node->title,
972 'postid' => $node->nid,
973 'link' => url('node/'. $node->nid, array('absolute', TRUE)),
974 'permaLink' => url('node/'. $node->nid, array('absolute', TRUE)),
975 );
976 if ($bodies) {
977 if ($node->comment == 1) {
978 $comment = 2;
979 }
980 else if ($node->comment == 2) {
981 $comment = 1;
982 }
983 $xmlrpcval['content'] = "<title>$node->title</title>$node->body";
984 $xmlrpcval['description'] = $node->body;
985 // Add MT specific fields
986 $xmlrpcval['mt_allow_comments'] = (int) $comment;
987 $xmlrpcval['mt_convert_breaks'] = $node->format;
988 }
989
990 return $xmlrpcval;
991 }
992
993 function _wlw_blogapi_blogid($id) {
994 if (is_numeric($id)) {
995 return 'blog';
996 }
997 else {
998 return $id;
999 }
1000 }
1001
1002 function _wlw_blogapi_get_node_types() {
1003 $available_types = array_keys(array_filter(variable_get('blogapi_node_types', array('blog' => 1))));
1004 $types = array();
1005 foreach (node_get_types() as $type => $name) {
1006 if (node_access('create', $type) && in_array($type, $available_types)) {
1007 $types[] = $type;
1008 }
1009 }
1010
1011 return $types;
1012 }
1013
1014
1015 function _wlw_blogapi_space_used($uid) {
1016 return db_result(db_query('SELECT SUM(filesize) FROM {blogapi_files} f WHERE f.uid = %d', $uid));
1017 }
1018
1019 function _wlw_blogapi_wlwmanifest() {
1020
1021 $slug = (module_exists('path') ? 'Yes' : 'No');
1022 $keywords = (module_exists('nodewords') ? 'Yes' : 'No');
1023 $excerpt = (variable_get('blogapi_excerpt', 0) ? 'Yes' : 'No');
1024
1025 $output = <<<__manifest__
1026 <?xml version="1.0" encoding="utf-8" ?>
1027 <manifest xmlns="http://schemas.microsoft.com/wlw/manifest/weblog">
1028 <options>
1029 <clientType>MovableType</clientType>
1030 <supportsKeywords>$keywords</supportsKeywords>
1031 <supportsTrackbacks>Yes</supportsTrackbacks>
1032 <supportsCategoriesInline>Yes</supportsCategoriesInline>
1033 <supportsMultipleCategories>Yes</supportsMultipleCategories>
1034 <supportsNewCategories>Yes</supportsNewCategories>
1035 <supportsNewCategoriesInline>Yes</supportsNewCategoriesInline>
1036 <supportsSlug>$slug</supportsSlug>
1037 <supportsAutoUpdate>Yes</supportsAutoUpdate>
1038 <requiresHtmlTitles>No</requiresHtmlTitles>
1039 <supportsExcerpt>$excerpt</supportsExcerpt>
1040 </options>
1041 </manifest>
1042 __manifest__;
1043 print $output;
1044 }

  ViewVC Help
Powered by ViewVC 1.1.2