From 75722e4f198bacae019fcf852c3f358b18a45e5c Mon Sep 17 00:00:00 2001 From: Dries Buytaert <dries@buytaert.net> Date: Tue, 25 Aug 2009 10:58:32 +0000 Subject: [PATCH] - Patch #537434 by chx, bangpound, moshe weitzman, David Strauss: move the blog API module to contrib. --- CHANGELOG.txt | 2 + MAINTAINERS.txt | 3 - modules/blogapi/blogapi.info | 10 - modules/blogapi/blogapi.install | 69 --- modules/blogapi/blogapi.module | 979 -------------------------------- modules/blogapi/blogapi.test | 187 ------ 6 files changed, 2 insertions(+), 1248 deletions(-) delete mode 100644 modules/blogapi/blogapi.info delete mode 100644 modules/blogapi/blogapi.install delete mode 100644 modules/blogapi/blogapi.module delete mode 100644 modules/blogapi/blogapi.test diff --git a/CHANGELOG.txt b/CHANGELOG.txt index cfcd3a39be0e..fb83e6addf07 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -164,6 +164,8 @@ Drupal 7.0, xxxx-xx-xx (development version) experience. - Better module version support. * Modules now can specify which version of another module they depend on. +- Blog API + * This module has been removed from core. - Improved node access control system. * All modules may now influence the access to a node at runtime, not just the module that defined a node. diff --git a/MAINTAINERS.txt b/MAINTAINERS.txt index 5cde446fe520..8f84f339b8ca 100644 --- a/MAINTAINERS.txt +++ b/MAINTAINERS.txt @@ -3,9 +3,6 @@ List of maintainers -------------------------------------------------------------------------------- -BLOG API -James Walker 'walkah' <http://drupal.org/user/1531> - DATABASE SYSTEM Larry Garfield 'Crell' <http://drupal.org/user/26398> diff --git a/modules/blogapi/blogapi.info b/modules/blogapi/blogapi.info deleted file mode 100644 index 87e365e5bc74..000000000000 --- a/modules/blogapi/blogapi.info +++ /dev/null @@ -1,10 +0,0 @@ -; $Id$ - -name = Blog API -description = Allows users to post content using applications that support XML-RPC blog APIs. -package = Core -version = VERSION -core = 7.x -files[] = blogapi.module -files[] = blogapi.install -files[] = blogapi.test diff --git a/modules/blogapi/blogapi.install b/modules/blogapi/blogapi.install deleted file mode 100644 index 2bbcd57a3463..000000000000 --- a/modules/blogapi/blogapi.install +++ /dev/null @@ -1,69 +0,0 @@ -<?php -// $Id$ - -/** - * @file - * Install, update and uninstall functions for the blogapi module. - */ - -/** - * Implement hook_install(). - */ -function blogapi_install() { - // Create tables. - drupal_install_schema('blogapi'); -} - -/** - * Implement hook_uninstall(). - */ -function blogapi_uninstall() { - // Remove tables. - drupal_uninstall_schema('blogapi'); -} - - -/** - * Implement hook_schema(). - */ -function blogapi_schema() { - $schema['blogapi_files'] = array( - 'description' => 'Stores information for files uploaded via the blogapi.', - 'fields' => array( - 'fid' => array( - 'description' => 'Primary Key: Unique file ID.', - 'type' => 'serial', - ), - 'uid' => array( - 'description' => 'The {users}.uid of the user who is associated with the file.', - 'type' => 'int', - 'unsigned' => TRUE, - 'not null' => TRUE, - 'default' => 0, - ), - 'filepath' => array( - 'description' => 'Path of the file relative to Drupal root.', - 'type' => 'varchar', - 'length' => 255, - 'not null' => TRUE, - 'default' => '', - ), - 'filesize' => array( - 'description' => 'The size of the file in bytes.', - 'type' => 'int', - 'unsigned' => TRUE, - 'not null' => TRUE, - 'default' => 0, - ), - ), - 'primary key' => array('fid'), - 'indexes' => array( - 'uid' => array('uid'), - ), - 'foreign keys' => array( - 'uid' => array('users' => 'uid'), - ), - ); - - return $schema; -} diff --git a/modules/blogapi/blogapi.module b/modules/blogapi/blogapi.module deleted file mode 100644 index 857ddae627d9..000000000000 --- a/modules/blogapi/blogapi.module +++ /dev/null @@ -1,979 +0,0 @@ -<?php -// $Id$ - -/** - * @file - * Enable users to post using applications that support XML-RPC blog APIs. - */ - -/** - * Implement hook_help(). - */ -function blogapi_help($path, $arg) { - switch ($path) { - case 'admin/help#blogapi': - $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>'; - $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>'; - $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/config/services/blogapi'))) . '</p>'; - $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>'; - return $output; - } -} - -/** - * Implement hook_permission(). - */ -function blogapi_permission() { - return array( - 'administer content with blog api' => array( - 'title' => t('Administer content with blog API'), - 'description' => t('Manage website content from external tools.'), - ), - ); -} - -/** - * Implement hook_xmlrpc(). - */ -function blogapi_xmlrpc() { - return array( - array( - 'blogger.getUsersBlogs', - 'blogapi_blogger_get_users_blogs', - array('array', 'string', 'string', 'string'), - t('Returns a list of blogs to which an author has posting privileges.')), - array( - 'blogger.getUserInfo', - 'blogapi_blogger_get_user_info', - array('struct', 'string', 'string', 'string'), - t('Returns information about an author in the system.')), - array( - 'blogger.newPost', - 'blogapi_blogger_new_post', - array('string', 'string', 'string', 'string', 'string', 'string', 'boolean'), - t('Creates a new post, and optionally publishes it.')), - array( - 'blogger.editPost', - 'blogapi_blogger_edit_post', - array('boolean', 'string', 'string', 'string', 'string', 'string', 'boolean'), - t('Updates the information about an existing post.')), - array( - 'blogger.getPost', - 'blogapi_blogger_get_post', - array('struct', 'string', 'string', 'string', 'string'), - t('Returns information about a specific post.')), - array( - 'blogger.deletePost', - 'blogapi_blogger_delete_post', - array('boolean', 'string', 'string', 'string', 'string', 'boolean'), - t('Deletes a post.')), - array( - 'blogger.getRecentPosts', - 'blogapi_blogger_get_recent_posts', - array('array', 'string', 'string', 'string', 'string', 'int'), - t('Returns a list of the most recent posts in the system.')), - array( - 'metaWeblog.newPost', - 'blogapi_metaweblog_new_post', - array('string', 'string', 'string', 'string', 'struct', 'boolean'), - t('Creates a new post, and optionally publishes it.')), - array( - 'metaWeblog.editPost', - 'blogapi_metaweblog_edit_post', - array('boolean', 'string', 'string', 'string', 'struct', 'boolean'), - t('Updates information about an existing post.')), - array( - 'metaWeblog.getPost', - 'blogapi_metaweblog_get_post', - array('struct', 'string', 'string', 'string'), - t('Returns information about a specific post.')), - array( - 'metaWeblog.newMediaObject', - 'blogapi_metaweblog_new_media_object', - array('string', 'string', 'string', 'string', 'struct'), - t('Uploads a file to your webserver.')), - array( - 'metaWeblog.getCategories', - 'blogapi_metaweblog_get_category_list', - array('struct', 'string', 'string', 'string'), - t('Returns a list of all categories to which the post is assigned.')), - array( - 'metaWeblog.getRecentPosts', - 'blogapi_metaweblog_get_recent_posts', - array('array', 'string', 'string', 'string', 'int'), - t('Returns a list of the most recent posts in the system.')), - array( - 'mt.getRecentPostTitles', - 'blogapi_mt_get_recent_post_titles', - array('array', 'string', 'string', 'string', 'int'), - t('Returns a bandwidth-friendly list of the most recent posts in the system.')), - array( - 'mt.getCategoryList', - 'blogapi_mt_get_category_list', - array('array', 'string', 'string', 'string'), - t('Returns a list of all categories defined in the blog.')), - array( - 'mt.getPostCategories', - 'blogapi_mt_get_post_categories', - array('array', 'string', 'string', 'string'), - t('Returns a list of all categories to which the post is assigned.')), - array( - 'mt.setPostCategories', - 'blogapi_mt_set_post_categories', - array('boolean', 'string', 'string', 'string', 'array'), - t('Sets the categories for a post.')), - array( - 'mt.supportedMethods', - 'xmlrpc_server_list_methods', - array('array'), - t('Retrieve information about the XML-RPC methods supported by the server.')), - array( - 'mt.supportedTextFilters', - 'blogapi_mt_supported_text_filters', - array('array'), - t('Retrieve information about the text formatting plugins supported by the server.')), - array( - 'mt.publishPost', - 'blogapi_mt_publish_post', - array('boolean', 'string', 'string', 'string'), - 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).'))); -} - -/** - * Blogging API callback. Finds the URL of a user's blog. - */ -function blogapi_blogger_get_users_blogs($appid, $username, $password) { - $user = blogapi_validate_user($username, $password); - if ($user->uid) { - $types = _blogapi_get_node_types(); - $structs = array(); - foreach ($types as $type) { - $structs[] = array('url' => url('user/' . $user->uid, array('absolute' => TRUE)), 'blogid' => $type, 'blogName' => $user->name . ": " . $type); - } - - return $structs; - } - else { - return blogapi_error($user); - } -} - -/** - * Blogging API callback. Returns profile information about a user. - */ -function blogapi_blogger_get_user_info($appkey, $username, $password) { - $user = blogapi_validate_user($username, $password); - - if ($user->uid) { - $name = explode(' ', $user->realname ? $user->realname : $user->name, 2); - return array( - 'userid' => $user->uid, - 'lastname' => $name[1], - 'firstname' => $name[0], - 'nickname' => $user->name, - 'email' => $user->mail, - 'url' => url('user/' . $user->uid, array('absolute' => TRUE))); - } - else { - return blogapi_error($user); - } -} - -/** - * Blogging API callback. Inserts a new blog post as a node. - */ -function blogapi_blogger_new_post($appkey, $blogid, $username, $password, $content, $publish) { - $user = blogapi_validate_user($username, $password); - if (!$user->uid) { - return blogapi_error($user); - } - - if (($error = _blogapi_validate_blogid($blogid)) !== TRUE) { - // Return an error if not configured type. - return $error; - } - - $edit = array(); - $edit['type'] = $blogid; - // Get the node type defaults. - $node_type_default = variable_get('node_options_' . $edit['type'], array('status', 'promote')); - $edit['uid'] = $user->uid; - $edit['name'] = $user->name; - $edit['promote'] = in_array('promote', $node_type_default); - $edit['comment'] = variable_get('comment_' . $edit['type'], 2); - $edit['revision'] = in_array('revision', $node_type_default); - $edit['format'] = FILTER_FORMAT_DEFAULT; - $edit['status'] = $publish; - - // Check for bloggerAPI vs. metaWeblogAPI. - if (is_array($content)) { - $edit['title'] = $content['title']; - $edit['body'] = $content['description']; - _blogapi_mt_extra($edit, $content); - } - else { - $edit['title'] = blogapi_blogger_title($content); - $edit['body'][FIELD_LANGUAGE_NONE][0]['value'] = $content; - } - - if (!node_access('create', $edit['type'])) { - return blogapi_error(t('You do not have permission to create this type of post.')); - } - - if (user_access('administer nodes') && !isset($edit['date'])) { - $edit['date'] = format_date(REQUEST_TIME, 'custom', 'Y-m-d H:i:s O'); - } - - module_invoke_all('node_blogapi_new', $edit); - - $valid = blogapi_status_error_check($edit, $publish); - if ($valid !== TRUE) { - return $valid; - } - - node_validate($edit); - if ($errors = form_get_errors()) { - return blogapi_error(implode("\n", $errors)); - } - - $node = node_submit($edit); - node_save($node); - if ($node->nid) { - watchdog('content', '@type: added %title using blog API.', array('@type' => $node->type, '%title' => $node->title), WATCHDOG_NOTICE, l(t('view'), "node/$node->nid")); - // blogger.newPost returns a string so we cast the nid to a string by putting it in double quotes. - return "$node->nid"; - } - - return blogapi_error(t('Error storing post.')); -} - -/** - * Blogging API callback. Modifies the specified blog node. - */ -function blogapi_blogger_edit_post($appkey, $postid, $username, $password, $content, $publish) { - $user = blogapi_validate_user($username, $password); - - if (!$user->uid) { - return blogapi_error($user); - } - - $node = node_load($postid); - if (!$node) { - return blogapi_error(t('n/a')); - } - // Let the teaser be re-generated. - unset($node->teaser); - - if (!node_access('update', $node)) { - return blogapi_error(t('You do not have permission to update this post.')); - } - // Save the original status for validation of permissions. - $original_status = $node->status; - $node->status = $publish; - - // Check for bloggerAPI vs. metaWeblogAPI. - if (is_array($content)) { - $node->title = $content['title']; - $node->body[FIELD_LANGUAGE_NONE][0]['value'] = $content['description']; - _blogapi_mt_extra($node, $content); - } - else { - $node->title = blogapi_blogger_title($content); - $node->body[FIELD_LANGUAGE_NONE][0]['value'] = $content; - } - - module_invoke_all('node_blogapi_edit', $node); - - $valid = blogapi_status_error_check($node, $original_status); - if ($valid !== TRUE) { - return $valid; - } - - node_validate($node); - if ($errors = form_get_errors()) { - return blogapi_error(implode("\n", $errors)); - } - - if (user_access('administer nodes') && !isset($edit['date'])) { - $node->date = format_date($node->created, 'custom', 'Y-m-d H:i:s O'); - } - $node = node_submit($node); - node_save($node); - if ($node->nid) { - watchdog('content', '@type: updated %title using Blog API.', array('@type' => $node->type, '%title' => $node->title), WATCHDOG_NOTICE, l(t('view'), "node/$node->nid")); - return TRUE; - } - - return blogapi_error(t('Error storing post.')); -} - -/** - * Blogging API callback. Returns a specified blog node. - */ -function blogapi_blogger_get_post($appkey, $postid, $username, $password) { - $user = blogapi_validate_user($username, $password); - if (!$user->uid) { - return blogapi_error($user); - } - - $node = node_load($postid); - - return _blogapi_get_post($node, TRUE); -} - -/** - * Check that the user has permission to save the node with the chosen status. - * - * @return - * TRUE if no error, or the blogapi_error(). - */ -function blogapi_status_error_check($node, $original_status) { - - $node = (object) $node; - - $node_type_default = variable_get('node_options_' . $node->type, array('status', 'promote')); - - // If we don't have the 'administer nodes' permission and the status is - // changing or for a new node the status is not the content type's default, - // then return an error. - if (!user_access('administer nodes') && (($node->status != $original_status) || (empty($node->nid) && $node->status != in_array('status', $node_type_default)))) { - if ($node->status) { - return blogapi_error(t('You do not have permission to publish this type of post. Please save it as a draft instead.')); - } - else { - return blogapi_error(t('You do not have permission to save this post as a draft. Please publish it instead.')); - } - } - return TRUE; -} - - -/** - * Blogging API callback. Removes the specified blog node. - */ -function blogapi_blogger_delete_post($appkey, $postid, $username, $password, $publish) { - $user = blogapi_validate_user($username, $password); - if (!$user->uid) { - return blogapi_error($user); - } - - node_delete($postid); - return TRUE; -} - -/** - * Blogging API callback. Returns the latest few postings in a user's blog. $bodies TRUE - * <a href="http://movabletype.org/docs/mtmanual_programmatic.html#item_mt%2EgetRecentPostTitles"> - * returns a bandwidth-friendly list</a>. - */ -function blogapi_blogger_get_recent_posts($appkey, $blogid, $username, $password, $number_of_posts, $bodies = TRUE) { - // Remove unused appkey (from bloggerAPI). - $user = blogapi_validate_user($username, $password); - if (!$user->uid) { - return blogapi_error($user); - } - - if (($error = _blogapi_validate_blogid($blogid)) !== TRUE) { - // Return an error if not configured type. - return $error; - } - - if ($bodies) { - $result = db_query_range("SELECT n.nid, n.title, n.comment, n.created, u.name FROM {node} n, {node_revision} r, {users} u WHERE n.uid = u.uid AND n.vid = r.vid AND n.type = :type AND n.uid = :uid ORDER BY n.created DESC", array( - ':type' => $blogid, - ':uid' => $user->uid - ), 0, $number_of_posts); - } - else { - $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 = :type AND n.uid = :uid ORDER BY n.created DESC", array( - ':type' => $blogid, - ':uid' => $user->uid - ), 0, $number_of_posts); - } - $blogs = array(); - foreach ($result as $blog) { - $blogs[] = _blogapi_get_post($blog, $bodies); - } - - return $blogs; -} - -function blogapi_metaweblog_new_post($blogid, $username, $password, $content, $publish) { - return blogapi_blogger_new_post('0123456789ABCDEF', $blogid, $username, $password, $content, $publish); -} - -function blogapi_metaweblog_edit_post($postid, $username, $password, $content, $publish) { - return blogapi_blogger_edit_post('0123456789ABCDEF', $postid, $username, $password, $content, $publish); -} - -function blogapi_metaweblog_get_post($postid, $username, $password) { - return blogapi_blogger_get_post('01234567890ABCDEF', $postid, $username, $password); -} - -/** - * Blogging API callback. Inserts a file into Drupal. - */ -function blogapi_metaweblog_new_media_object($blogid, $username, $password, $file) { - $user = blogapi_validate_user($username, $password); - if (!$user->uid) { - return blogapi_error($user); - } - - $usersize = 0; - $uploadsize = 0; - - $roles = array_intersect(user_roles(FALSE, 'administer content with blog api'), $user->roles); - - foreach ($roles as $rid => $name) { - $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'))); - $usersize = max($usersize, variable_get("blogapi_usersize_$rid", variable_get('blogapi_usersize_default', 1)) * 1024 * 1024); - $uploadsize = max($uploadsize, variable_get("blogapi_uploadsize_$rid", variable_get('blogapi_uploadsize_default', 1)) * 1024 * 1024); - } - - $filesize = strlen($file['bits']); - - if ($filesize > $uploadsize) { - return blogapi_error(t('It is not possible to upload the file, because it exceeded the maximum filesize of @maxsize.', array('@maxsize' => format_size($uploadsize)))); - } - - if (_blogapi_space_used($user->uid) + $filesize > $usersize) { - return 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)))); - } - - // Only allow files with whitelisted extensions and convert remaining dots to - // underscores to prevent attacks via non-terminal executable extensions with - // files such as exploit.php.jpg. - - $whitelist = array_unique(explode(' ', trim($extensions))); - - $name = basename($file['name']); - - if ($extension_position = strrpos($name, '.')) { - $filename = drupal_substr($name, 0, $extension_position); - $final_extension = drupal_substr($name, $extension_position + 1); - - if (!in_array(strtolower($final_extension), $whitelist)) { - return 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)))); - } - - $filename = str_replace('.', '_', $filename); - $filename .= '.' . $final_extension; - } - - else { - $filename = $name; - } - $uri = file_build_uri($filename); - $data = $file['bits']; - - if (!$data) { - return blogapi_error(t('No file sent.')); - } - - if (!$file = file_unmanaged_save_data($data, $uri)) { - return blogapi_error(t('Error storing file.')); - } - - $row = new stdClass(); - $row->uid = $user->uid; - $row->uri = $file; - $row->filesize = $filesize; - - drupal_write_record('blogapi_files', $row); - - // Return the successful result. - return array('url' => file_create_url($file), 'struct'); -} -/** - * Blogging API callback. Returns a list of the taxonomy terms that can be - * associated with a blog node. - */ -function blogapi_metaweblog_get_category_list($blogid, $username, $password) { - $user = blogapi_validate_user($username, $password); - if (!$user->uid) { - return blogapi_error($user); - } - - if (($error = _blogapi_validate_blogid($blogid)) !== TRUE) { - // Return an error if not configured type. - return $error; - } - - $vocabularies = module_invoke('taxonomy', 'get_vocabularies', $blogid, 'vid'); - $categories = array(); - if ($vocabularies) { - foreach ($vocabularies as $vocabulary) { - $terms = module_invoke('taxonomy', 'get_tree', $vocabulary->vid); - foreach ($terms as $term) { - $term_name = $term->name; - foreach (module_invoke('taxonomy', 'get_parents', $term->tid, 'tid') as $parent) { - $term_name = $parent->name . '/' . $term_name; - } - $categories[] = array('categoryName' => $term_name, 'categoryId' => $term->tid); - } - } - } - - return $categories; -} - -function blogapi_metaweblog_get_recent_posts($blogid, $username, $password, $number_of_posts) { - return blogapi_blogger_get_recent_posts('0123456789ABCDEF', $blogid, $username, $password, $number_of_posts, TRUE); -} - -function blogapi_mt_get_recent_post_titles($blogid, $username, $password, $number_of_posts) { - return blogapi_blogger_get_recent_posts('0123456789ABCDEF', $blogid, $username, $password, $number_of_posts, FALSE); -} - -function blogapi_mt_get_category_list($blogid, $username, $password) { - return blogapi_metaweblog_get_category_list($blogid, $username, $password); -} - -/** - * Blogging API callback. Returns a list of the taxonomy terms that are - * assigned to a particular node. - */ -function blogapi_mt_get_post_categories($postid, $username, $password) { - $user = blogapi_validate_user($username, $password); - if (!$user->uid) { - return blogapi_error($user); - } - - $node = node_load($postid); - $terms = module_invoke('taxonomy', 'node_get_terms', $node, 'tid'); - $categories = array(); - foreach ($terms as $term) { - $term_name = $term->name; - foreach (module_invoke('taxonomy', 'get_parents', $term->tid, 'tid') as $parent) { - $term_name = $parent->name . '/' . $term_name; - } - $categories[] = array('categoryName' => $term_name, 'categoryId' => $term->tid, 'isPrimary' => TRUE); - } - - return $categories; -} - -/** - * Blogging API callback. Assigns taxonomy terms to a particular node. - */ -function blogapi_mt_set_post_categories($postid, $username, $password, $categories) { - $user = blogapi_validate_user($username, $password); - if (!$user->uid) { - return blogapi_error($user); - } - - $node = node_load($postid); - $node->taxonomy = array(); - foreach ($categories as $category) { - $node->taxonomy[] = $category['categoryId']; - } - $validated = blogapi_mt_validate_terms($node); - if ($validated !== TRUE) { - return $validated; - } - node_save($node); - - return TRUE; -} - -/** - * Blogging API helper - find allowed taxonomy terms for a node type. - */ -function blogapi_mt_validate_terms($node) { - // We do a lot of heavy lifting here since taxonomy module doesn't have a - // stand-alone validation function. - if (module_exists('taxonomy')) { - $found_terms = array(); - if (!empty($node->taxonomy)) { - $term_list = array_unique($node->taxonomy); - $terms = taxonomy_term_load_multiple($term_list, array('type' => $node->type)); - $found_terms = array(); - $found_count = 0; - foreach ($terms as $term) { - $found_terms[$term->vid][$term->tid] = $term->tid; - $found_count++; - } - // If the counts don't match, some terms are invalid or not accessible to this user. - if (count($term_list) != $found_count) { - return blogapi_error(t('Invalid categories submitted.')); - } - } - // Look up all the vocabularies for this node type. - $vocabularies = taxonomy_vocabulary_load_multiple(array(), array('type' => $node->type)); - // Check each vocabulary associated with this node type. - foreach ($vocabularies as $vocabulary) { - // Required vocabularies must have at least one term. - if ($vocabulary->required && empty($found_terms[$vocabulary->vid])) { - return blogapi_error(t('A category from the @vocabulary_name vocabulary is required.', array('@vocabulary_name' => $vocabulary->name))); - } - // Vocabularies that don't allow multiple terms may have at most one. - if (!($vocabulary->multiple) && (isset($found_terms[$vocabulary->vid]) && count($found_terms[$vocabulary->vid]) > 1)) { - return blogapi_error(t('You may only choose one category from the @vocabulary_name vocabulary.'), array('@vocabulary_name' => $vocabulary->name)); - } - } - } - elseif (!empty($node->taxonomy)) { - return blogapi_error(t('Error saving categories. This feature is not available.')); - } - return TRUE; -} - -/** - * Blogging API callback. Sends a list of available text formats. - */ -function blogapi_mt_supported_text_filters() { - // NOTE: we're only using anonymous' formats because the MT spec - // does not allow for per-user formats. - $formats = filter_formats(); - - $filters = array(); - foreach ($formats as $format) { - $filter['key'] = $format->format; - $filter['label'] = $format->name; - $filters[] = $filter; - } - - return $filters; -} - -/** - * Blogging API callback. Publishes the given node. - */ -function blogapi_mt_publish_post($postid, $username, $password) { - $user = blogapi_validate_user($username, $password); - - if (!$user->uid) { - return blogapi_error($user); - } - $node = node_load($postid); - - if (!$node) { - return blogapi_error(t('Invalid post.')); - } - - // Nothing needs to be done if already published. - if ($node->status) { - return; - } - - if (!node_access('update', $node) || !user_access('administer nodes')) { - return blogapi_error(t('You do not have permission to update this post.')); - } - - $node->status = 1; - node_save($node); - - return TRUE; -} - -/** - * Prepare an error message for returning to the XMLRPC caller. - */ -function blogapi_error($message) { - static $xmlrpcusererr; - - if (!is_array($message)) { - $message = array($message); - } - - $message = implode(' ', $message); - - return xmlrpc_error($xmlrpcusererr + 1, strip_tags($message)); -} - -/** - * Ensure that the given user has permission to edit a blog. - */ -function blogapi_validate_user($username, $password) { - $form_state['values']['name'] = $username; - $form_state['values']['pass'] = $password; - $form_state['values']['op'] = t('Login'); - drupal_form_submit('user_login', $form_state); - - if (!form_get_error()) { - if (user_access('administer content with blog api', $user)) { - return $GLOBALS['user']; - } - else { - return t('You do not have permission to edit this blog.'); - } - } - else { - return t('Wrong username or password.'); - } -} - -/** - * For the blogger API, extract the node title from the contents field. - */ -function blogapi_blogger_title(&$contents) { - if (preg_match('/<title>(.*?)<\/title>/i', $contents, $title)) { - $title = strip_tags($title[0]); - $contents = preg_replace('/<title>.*?<\/title>/i', '', $contents); - } - else { - list($title, $contents) = explode("\n", $contents, 2); - } - - return $title; -} - -/** - * Add some settings to the admin_settings form. - */ -function blogapi_admin_settings() { - $node_types = array_map('check_plain', node_type_get_names()); - $defaults = isset($node_types['blog']) ? array('blog' => 1) : array(); - $form['blogapi_node_types'] = array( - '#type' => 'checkboxes', - '#title' => t('Enable for external blogging clients'), - '#required' => TRUE, - '#default_value' => variable_get('blogapi_node_types', $defaults), - '#options' => $node_types, - '#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.') - ); - - $blogapi_extensions_default = variable_get('blogapi_extensions_default', 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp'); - $blogapi_uploadsize_default = variable_get('blogapi_uploadsize_default', 1); - $blogapi_usersize_default = variable_get('blogapi_usersize_default', 1); - - $form['settings_general'] = array( - '#type' => 'fieldset', - '#title' => t('File settings'), - '#collapsible' => TRUE, - ); - - $form['settings_general']['blogapi_extensions_default'] = array( - '#type' => 'textfield', - '#title' => t('Default permitted file extensions'), - '#default_value' => $blogapi_extensions_default, - '#maxlength' => 255, - '#description' => t('Default extensions that users can upload. Separate extensions with a space and do not include the leading dot.'), - ); - - $form['settings_general']['blogapi_uploadsize_default'] = array( - '#type' => 'textfield', - '#title' => t('Default maximum file size per upload'), - '#default_value' => $blogapi_uploadsize_default, - '#size' => 5, - '#maxlength' => 5, - '#description' => t('The default maximum file size a user can upload.'), - '#field_suffix' => t('MB') - ); - - $form['settings_general']['blogapi_usersize_default'] = array( - '#type' => 'textfield', - '#title' => t('Default total file size per user'), - '#default_value' => $blogapi_usersize_default, - '#size' => 5, - '#maxlength' => 5, - '#description' => t('The default maximum size of all files a user can have on the site.'), - '#field_suffix' => t('MB') - ); - - $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>'); - - $roles = user_roles(FALSE, 'administer content with blog api'); - $form['roles'] = array('#type' => 'value', '#value' => $roles); - - foreach ($roles as $rid => $role) { - $form['settings_role_' . $rid] = array( - '#type' => 'fieldset', - '#title' => t('Settings for @role', array('@role' => $role)), - '#collapsible' => TRUE, - '#collapsed' => TRUE, - ); - $form['settings_role_' . $rid]['blogapi_extensions_' . $rid] = array( - '#type' => 'textfield', - '#title' => t('Permitted file extensions'), - '#default_value' => variable_get('blogapi_extensions_' . $rid, $blogapi_extensions_default), - '#maxlength' => 255, - '#description' => t('Extensions that users in this role can upload. Separate extensions with a space and do not include the leading dot.'), - ); - $form['settings_role_' . $rid]['blogapi_uploadsize_' . $rid] = array( - '#type' => 'textfield', - '#title' => t('Maximum file size per upload'), - '#default_value' => variable_get('blogapi_uploadsize_' . $rid, $blogapi_uploadsize_default), - '#size' => 5, - '#maxlength' => 5, - '#description' => t('The maximum size of a file a user can upload (in megabytes).'), - ); - $form['settings_role_' . $rid]['blogapi_usersize_' . $rid] = array( - '#type' => 'textfield', - '#title' => t('Total file size per user'), - '#default_value' => variable_get('blogapi_usersize_' . $rid, $blogapi_usersize_default), - '#size' => 5, - '#maxlength' => 5, - '#description' => t('The maximum size of all files a user can have on the site (in megabytes).'), - ); - } - - return system_settings_form($form, FALSE); -} - -/** - * Implement hook_menu(). - */ -function blogapi_menu() { - $items['blogapi/rsd'] = array( - 'title' => 'RSD', - 'page callback' => 'blogapi_rsd', - 'access arguments' => array('access content'), - 'type' => MENU_CALLBACK, - ); - $items['admin/config/services/blogapi'] = array( - 'title' => 'Blog API', - 'description' => 'Configure the content types available to external blogging clients.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('blogapi_admin_settings'), - 'access arguments' => array('administer site configuration'), - 'type' => MENU_NORMAL_ITEM, - ); - - return $items; -} - -/** - * Implement hook_init(). - */ -function blogapi_init() { - if (drupal_is_front_page()) { - drupal_add_link(array('rel' => 'EditURI', - 'type' => 'application/rsd+xml', - 'title' => t('RSD'), - 'href' => url('blogapi/rsd', array('absolute' => TRUE)))); - } -} - -function blogapi_rsd() { - global $base_url; - - $xmlrpc = $base_url . '/xmlrpc.php'; - $base = url('', array('absolute' => TRUE)); - $blogid = 1; # until we figure out how to handle multiple bloggers - - drupal_set_header('Content-Type', 'application/rsd+xml; charset=utf-8'); - print <<<__RSD__ -<?xml version="1.0"?> -<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd"> - <service> - <engineName>Drupal</engineName> - <engineLink>http://drupal.org/</engineLink> - <homePageLink>$base</homePageLink> - <apis> - <api name="MetaWeblog" preferred="false" apiLink="$xmlrpc" blogID="$blogid" /> - <api name="Blogger" preferred="false" apiLink="$xmlrpc" blogID="$blogid" /> - <api name="MovableType" preferred="true" apiLink="$xmlrpc" blogID="$blogid" /> - </apis> - </service> -</rsd> -__RSD__; -} - -/** - * Handles extra information sent by clients according to MovableType's spec. - */ -function _blogapi_mt_extra($node, $struct) { - if (is_array($node)) { - $was_array = TRUE; - $node = (object)$node; - } - - if (array_key_exists('mt_allow_comments', $struct)) { - switch ($struct['mt_allow_comments']) { - case 0: - $node->comment = COMMENT_NODE_HIDDEN; - break; - case 1: - $node->comment = COMMENT_NODE_OPEN; - break; - case 2: - $node->comment = COMMENT_NODE_CLOSED; - break; - } - } - - // Merge the 3 body sections (description, mt_excerpt, mt_text_more) into one body. - if ($struct['mt_excerpt']) { - $node->body[FIELD_LANGUAGE_NONE][0]['value'] = $struct['mt_excerpt'] . '<!--break-->' . $node->body[FIELD_LANGUAGE_NONE][0]['value']; - } - if ($struct['mt_text_more']) { - $node->body[FIELD_LANGUAGE_NONE][0]['value'] = $node->body[FIELD_LANGUAGE_NONE][0]['value'] . '<!--extended-->' . $struct['mt_text_more']; - } - - if ($struct['mt_convert_breaks']) { - $node->body[FIELD_LANGUAGE_NONE][0]['format'] = $struct['mt_convert_breaks']; - } - - if ($struct['dateCreated']) { - $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'); - } - - if ($was_array) { - $node = (array)$node; - } -} - -function _blogapi_get_post($node, $bodies = TRUE) { - $xmlrpcval = array( - 'userid' => $node->name, - 'dateCreated' => xmlrpc_date($node->created), - 'title' => $node->title, - 'postid' => $node->nid, - 'link' => url('node/' . $node->nid, array('absolute' => TRUE)), - 'permaLink' => url('node/' . $node->nid, array('absolute' => TRUE)), - ); - - if ($bodies) { - $body = $node->body[FIELD_LANGUAGE_NONE][0]['value']; - $format = $node->body[FIELD_LANGUAGE_NONE][0]['format']; - if ($node->comment == 1) { - $comment = 2; - } - elseif ($node->comment == 2) { - $comment = 1; - } - $xmlrpcval['content'] = "<title>$node->title</title>$body"; - $xmlrpcval['description'] = $body; - // Add MT specific fields - $xmlrpcval['mt_allow_comments'] = (int) $comment; - $xmlrpcval['mt_convert_breaks'] = $format; - } - - return $xmlrpcval; -} - -/** - * Validate blog ID, which maps to a content type in Drupal. - * - * Only content types configured to work with Blog API are supported. - * - * @return - * TRUE if the content type is supported and the user has permission - * to post, or a blogapi_error() XML construct otherwise. - */ -function _blogapi_validate_blogid($blogid) { - $types = _blogapi_get_node_types(); - if (in_array($blogid, $types, TRUE)) { - return TRUE; - } - - 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))); -} - -function _blogapi_get_node_types() { - $available_types = array_keys(array_filter(variable_get('blogapi_node_types', array('blog' => 1)))); - $types = array(); - foreach (node_type_get_types() as $type => $name) { - if (node_access('create', $type) && in_array($type, $available_types)) { - $types[] = $type; - } - } - - return $types; -} - -function _blogapi_space_used($uid) { - return db_query('SELECT SUM(filesize) FROM {blogapi_files} f WHERE f.uid = :uid', array(':uid' => $uid))->fetchField(); -} - diff --git a/modules/blogapi/blogapi.test b/modules/blogapi/blogapi.test deleted file mode 100644 index 18a72f218312..000000000000 --- a/modules/blogapi/blogapi.test +++ /dev/null @@ -1,187 +0,0 @@ -<?php -// $Id$ - -class BlogAPITestCase extends DrupalWebTestCase { - public static function getInfo() { - return array( - 'name' => 'Blog API functionality', - 'description' => 'Create, edit, and delete post; upload file; and set/get categories.', - 'group' => 'Blog API', - ); - } - - function setUp() { - parent::setUp('blog', 'blogapi', 'taxonomy'); - } - - /** - * Create, edit, and delete post; upload file; set/get categories. - */ - function testBlogAPI() { - global $base_url; - // Create user. - $web_user = $this->drupalCreateUser(array('create blog content', 'delete own blog content', 'edit own blog content', 'administer content with blog api')); - // Create admin user and taxonomy for later use. - $admin_user = $this->drupalCreateUser(array('administer taxonomy')); - $this->drupalLogin($admin_user); - $vid = $this->addVocabulary('simpletest_vocab'); - $term_1 = $this->addTerm($vid, 'simpletest_term1'); - $term_2 = $this->addTerm($vid, 'simpletest_term2'); - - // Init common variables. - $local = url($base_url . '/xmlrpc.php', array('external' => TRUE)); - $appid = 'simpletest'; - - // Get user's blog. - $result = xmlrpc($local, 'blogger.getUsersBlogs', $appid, $web_user->name, $web_user->pass_raw); - $this->assertTrue($result, t('Request for user\'s blogs returned correctly.')); - - if ($result !== FALSE) { - if ($this->assertTrue(array_key_exists('blogid', $result[0]), t('Blog found.'))) { - $blog_id = $result[0]['blogid']; - } - } - - // Create post. - $content = $this->randomName(32); - $result = xmlrpc($local, 'blogger.newPost', $appid, $blog_id, $web_user->name, $web_user->pass_raw, $content, TRUE); - $this->assertTrue($result, t('Post created.')); - - $nid = $result; - - // Check recent posts. - $result = xmlrpc($local, 'blogger.getRecentPosts', $appid, $blog_id, $web_user->name, $web_user->pass_raw, 5); - $this->assertTrue($result, t('Recent post list retrieved.')); - - if ($result !== FALSE && array_key_exists('title', $result[0])) { - $this->assertEqual($content, $result[0]['title'], t('Post found.')); - } - else { - $this->fail(t('Post found.')); - } - - // Edit post. - $content_new = $this->randomName(10); - $result = xmlrpc($local, 'blogger.editPost', $appid, $nid, $web_user->name, $web_user->pass_raw, $content_new, TRUE); - $this->assertTrue($result, t('Post successfully modified.')); - - // Upload file. - $file = current($this->drupalGetTestFiles('text')); - $file_contents = file_get_contents($file->uri); - $file = array(); - $file['name'] = $this->randomName() . '.txt'; - $file['type'] = 'text'; - $file['bits'] = xmlrpc_base64($file_contents); - $result = xmlrpc($local, 'metaWeblog.newMediaObject', $blog_id, $web_user->name, $web_user->pass_raw, $file); - $this->assertTrue($result, t('File successfully uploaded.')); - - $url = (array_key_exists('url', $result) ? $result['url'] : ''); - - // Check uploaded file. - $this->drupalGet($url); - $this->assertEqual($this->drupalGetContent(), $file_contents, t('Uploaded contents verified.')); - - // Set post categories. - $categories = array(array('categoryId' => $term_1)); - $result = xmlrpc($local, 'mt.setPostCategories', $nid, $web_user->name, $web_user->pass_raw, $categories); - $this->assertTrue($result, t('Post categories set.')); - - // Get post categories. - $result = xmlrpc($local, 'mt.getPostCategories', $nid, $web_user->name, $web_user->pass_raw); - $this->assertTrue($result, t('Category list successfully retrieved.')); - - if ($result !== FALSE && isset($result[0]['categoryId'])) { - $this->assertEqual($term_1, $result[0]['categoryId'], t('Category list verified.')); - } - - // Test validation of category assignment. - // Set post categories. - $categories[] = array('categoryId' => $term_2); - $result = xmlrpc($local, 'mt.setPostCategories', $nid, $web_user->name, $web_user->pass_raw, $categories); - $this->assertFalse($result, t('Post categories fail validation (attempt to post two when one is allowed).')); - - // Change to required. - $this->updateVocabulary($vid, 'simpletest_vocab1', FALSE, TRUE); - $result = xmlrpc($local, 'mt.setPostCategories', $nid, $web_user->name, $web_user->pass_raw, array()); - $this->assertFalse($result, t("Post categories fail validation (none posted when it's required).")); - - // Change to allowing multiple, not required. - $this->updateVocabulary($vid, 'simpletest_vocab1', TRUE, FALSE); - $result = xmlrpc($local, 'mt.setPostCategories', $nid, $web_user->name, $web_user->pass_raw, $categories); - $this->assertTrue($result, t('Post categories pass validation (multiple allowed).')); - $result = xmlrpc($local, 'mt.setPostCategories', $nid, $web_user->name, $web_user->pass_raw, array()); - $this->assertTrue($result, t('Post categories pass validation (multiple allowed, none posted).')); - - // Change to multiple, but required. - $this->updateVocabulary($vid, 'simpletest_vocab1', TRUE, TRUE); - $result = xmlrpc($local, 'mt.setPostCategories', $nid, $web_user->name, $web_user->pass_raw, $categories); - $this->assertTrue($result, t('Post categories pass validation (multiple allowed).')); - $result = xmlrpc($local, 'mt.setPostCategories', $nid, $web_user->name, $web_user->pass_raw, array()); - $this->assertFalse($result, t("Post categories fail validation (none posted when it's required).")); - - // Try to add a non-existent term. - $categories[] = array('categoryId' => $term_2 + 1); - $result = xmlrpc($local, 'mt.setPostCategories', $nid, $web_user->name, $web_user->pass_raw, $categories); - $this->assertFalse($result, t('Post categories fail validation (unknown term).')); - - // Delete post. - $result = xmlrpc($local, 'blogger.deletePost', $appid, $nid, $web_user->name, $web_user->pass_raw, TRUE); - $this->assertTrue($result, t('Post successfully deleted.')); - } - - /** - * Add taxonomy vocabulary. - * - * @param string $vocab - * Vocabulary name. - * @return integer - * The vocab ID. - */ - function addVocabulary($vocab) { - // Create a vocabulary. - $vocabulary = new stdClass(); - $vocabulary->name = $vocab; - $vocabulary->description = $this->randomName(); - $vocabulary->machine_name = $this->randomName(); - $vocabulary->help = ''; - $vocabulary->nodes = array('blog' => 'blog'); - $vocabulary->weight = mt_rand(0, 10); - taxonomy_vocabulary_save($vocabulary); - - return $vocabulary->vid; - } - /** - * Update a taxonomy vocabulary. - * - * @param $vocab - * Vocabulary name. - * @return integer - * The vocab ID. - */ - function updateVocabulary($vid, $vocab, $multiple = FALSE, $required = FALSE) { - $vocabulary = taxonomy_vocabulary_load($vid); - $vocabulary->name = $vocab; - $vocabulary->nodes = array('blog' => 'blog'); - $vocabulary->multiple = $multiple; - $vocabulary->required = $required; - taxonomy_vocabulary_save($vocabulary); - } - - /** - * Add a taxonomy term to vocabulary. - * - * @param integer $vid - * Vocabulary ID. - * @param string $term - * Term name. - * @return integer - * The Term ID. - */ - function addTerm($vid, $term_name) { - $term = new stdClass(); - $term->name = $term_name; - $term->vid = $vid; - taxonomy_term_save($term); - return $term->tid; - } -} -- GitLab