/** * Check whether the main category and the extra categories are valid * in a Blog's context and try to fix errors. * * @author Tilman BLUMENBACH / Tblue * * @param integer The main category to check (by reference). * @param object The Blog to which the category is supposed to belong to (by reference). * @param array Extra categories for the post (by reference). * * @return boolean False on error (use xmlrpcs_resperror() to return it), true on success. */ function xmlrpcs_check_cats(&$maincat, &$Blog, &$extracats) { global $xmlrpcs_errcode, $xmlrpcs_errmsg, $xmlrpcerruser; // Trim $maincat and $extracats (qtm sends whitespace before the cat IDs): $maincat = trim($maincat); $extracats = array_map('trim', $extracats); $ChapterCache =& get_ChapterCache(); // ---- CHECK MAIN CATEGORY ---- if ($ChapterCache->get_by_ID($maincat, false) === false) { // Category does not exist! // Remove old category from extra cats: if (($key = array_search($maincat, $extracats)) !== false) { unset($extracats[$key]); } // Set new category (blog default): $maincat = $Blog->get_default_cat_ID(); logIO('Invalid main cat ID - new ID: ' . $maincat); } else { if (get_allow_cross_posting() < 2 && get_catblog($maincat) != $Blog->ID) { // We cannot use a maincat of another blog than the current one: $xmlrpcs_errcode = $xmlrpcerruser + 11; $xmlrpcs_errmsg = 'Current crossposting setting does not allow moving posts to a different blog.'; return false; } } // ---- CHECK EXTRA CATEGORIES ---- foreach ($extracats as $ecat) { if ($ecat == $maincat) { // We already checked the maincat above (or reset it): continue; } logIO('Checking extra cat: ' . $ecat); if ($ChapterCache->get_by_ID($ecat, false) === false) { // Extra cat does not exist: $xmlrpcs_errcode = $xmlrpcerruser + 11; $xmlrpcs_errmsg = 'Extra category ' . (int) $ecat . ' not found in requested blog.'; return false; } } if (!in_array($maincat, $extracats)) { logIO('$maincat was not found in $extracats array - adding.'); $extracats[] = $maincat; } return true; }
} } $content = trim($content); $UserCache =& get_Cache('UserCache'); $loop_User =& $UserCache->get_by_login($user_login); // --- get infos from content ----------- $post_title = xmlrpc_getposttitle($content); if ($post_title == '') { $post_title = $subject; } if (!($post_category = xmlrpc_getpostcategory($content))) { $post_category = $Settings->get('eblog_default_category'); } echo_message('•<b>' . T_('Category ID') . ':</b> ' . $post_category . '<br />', '', 3); $content = xmlrpc_removepostdata($content); $blog_ID = get_catblog($post_category); // TODO: should not die, if cat does not exist! echo_message('•<b>' . T_('Blog ID') . ':</b> ' . $blog_ID . '<br />', '', 3); // Check permission: echo_message('•' . sprintf(T_('Checking permissions for user «%s» to post to Blog #%d'), $user_login, $blog_ID) . ' '); if (!$loop_User->check_perm('blog_post!published', 'edit', false, $blog_ID)) { echo_message('[ ' . T_('Permission denied') . ' ]', 'red'); continue; } else { echo_message('[ ' . T_('Pass') . ' ]<br />', 'green'); } // todo: finish this last section if (!$test_type > 0) { // CHECK and FORMAT content $post_title = format_to_post(trim($post_title), 0, 0); $content = format_to_post(trim($content), $Settings->get('AutoBR'), 0);
/** * We want to preview a single post, we are going to fake a lot of things... */ function preview_from_request() { global $current_User; if (empty($current_User)) { // dh> only logged in user's can preview. Alternatively we need those checks where $current_User gets used below. return; } global $DB, $localtimenow, $Messages, $BlogCache; global $Plugins; if ($this->Blog->get_setting('allow_html_post')) { // HTML is allowed for this post $text_format = 'html'; } else { // HTML is disallowed for this post $text_format = 'htmlspecialchars'; } $preview_userid = param('preview_userid', 'integer', true); $post_status = param('post_status', 'string', true); $post_locale = param('post_locale', 'string', $current_User->locale); $content = param('content', $text_format, true); $post_title = param('post_title', $text_format, true); $post_titletag = param('titletag', 'string', true); $post_excerpt = param('post_excerpt', 'string', true); $post_url = param('post_url', 'string', ''); check_categories_nosave($post_category, $post_extracats); $post_views = param('post_views', 'integer', 0); $renderers = param('renderers', 'array/string', array('default')); if (!is_array($renderers)) { // dh> workaround for param() bug. See rev 1.93 of /inc/_misc/_misc.funcs.php $renderers = array('default'); } if ($post_category == 0) { $post_category = $this->Blog->get_default_cat_ID(); } $comment_Blog =& $BlogCache->get_by_ID(get_catblog($post_category)); if ($comment_Blog->get_setting('allow_comments') != 'never' && $comment_Blog->get_setting('disable_comments_bypost')) { // param is required $post_comment_status = param('post_comment_status', 'string', true); } else { $post_comment_status = $comment_Blog->get_setting('allow_comments'); } // Get issue date, using the user's locale (because it's entered like this in the form): locale_temp_switch($current_User->locale); param_date('item_issue_date', T_('Please enter a valid issue date.'), false); // TODO: dh> get_param() is always true here, also on invalid dates: if (strlen(get_param('item_issue_date'))) { // only set it, if a date was given: param_time('item_issue_time'); $item_issue_date = form_date(get_param('item_issue_date'), get_param('item_issue_time')); // TODO: cleanup... } else { $item_issue_date = date('Y-m-d H:i:s', $localtimenow); } locale_restore_previous(); $item_typ_ID = param('item_typ_ID', 'integer', NULL); $item_st_ID = param('item_st_ID', 'integer', NULL); $item_assigned_user_ID = param('item_assigned_user_ID', 'integer', NULL); $item_deadline = param('item_deadline', 'string', NULL); $item_priority = param('item_priority', 'integer', NULL); // QUESTION: can this be also empty/NULL? // Do some optional filtering on the content // Typically stuff that will help the content to validate // Useful for code display. // Will probably be used for validation also. $Plugins_admin =& get_Plugins_admin(); $params = array('object_type' => 'Item', 'object_Blog' => &$comment_Blog); $Plugins_admin->filter_contents($post_title, $content, $renderers, $params); $post_title = format_to_post($post_title); $content = format_to_post($content); $post_ID = param('post_ID', 'integer', 0); $this->sql = "SELECT\n\t\t\t{$post_ID} AS post_ID,\n\t\t\t{$preview_userid} AS post_creator_user_ID,\n\t\t\t{$preview_userid} AS post_lastedit_user_ID,\n\t\t\t'{$item_issue_date}' AS post_datestart,\n\t\t\t'{$item_issue_date}' AS post_datecreated,\n\t\t\t'{$item_issue_date}' AS post_datemodified,\n\t\t\t'{$item_issue_date}' AS post_last_touched_ts,\n\t\t\t0 AS post_dateset,\n\t\t\t'" . $DB->escape($post_status) . "' AS post_status,\n\t\t\t'" . $DB->escape($post_locale) . "' AS post_locale,\n\t\t\t'" . $DB->escape($content) . "' AS post_content,\n\t\t\t'" . $DB->escape($post_title) . "' AS post_title,\n\t\t\t'" . $DB->escape($post_titletag) . "' AS post_titletag,\n\t\t\t'" . $DB->escape($post_excerpt) . "' AS post_excerpt,\n\t\t\tNULL AS post_excerpt_autogenerated,\n\t\t\tNULL AS post_urltitle,\n\t\t\tNULL AS post_canonical_slug_ID,\n\t\t\tNULL AS post_tiny_slug_ID,\n\t\t\t'" . $DB->escape($post_url) . "' AS post_url,\n\t\t\t{$post_category} AS post_main_cat_ID,\n\t\t\t{$post_views} AS post_views,\n\t\t\t'' AS post_flags,\n\t\t\t'noreq' AS post_notifications_status,\n\t\t\tNULL AS post_notifications_ctsk_ID,\n\t\t\t" . bpost_count_words($content) . " AS post_wordcount,\n\t\t\t" . $DB->quote($post_comment_status) . " AS post_comment_status,\n\t\t\t'" . $DB->escape(implode('.', $renderers)) . "' AS post_renderers,\n\t\t\t" . $DB->quote($item_assigned_user_ID) . " AS post_assigned_user_ID,\n\t\t\t" . $DB->quote($item_typ_ID) . " AS post_ptyp_ID,\n\t\t\t" . $DB->quote($item_st_ID) . " AS post_pst_ID,\n\t\t\t" . $DB->quote($item_deadline) . " AS post_datedeadline,\n\t\t\t" . $DB->quote($item_priority) . " AS post_priority,"; $this->sql .= $DB->quote(param('item_order', 'double', NULL)) . ' AS post_order' . ",\n" . $DB->quote(param('item_featured', 'integer', NULL)) . ' AS post_featured' . "\n"; $this->total_rows = 1; $this->total_pages = 1; $this->page = 1; // ATTENTION: we skip the parent on purpose here!! fp> refactor DataObjectList2::query(false, false, false, 'PREVIEW QUERY'); $Item =& $this->Cache->instantiate($this->rows[0]); // set Item settings $Item->set_setting('hide_teaser', param('item_hideteaser', 'integer', 0)); $Item->set_setting('post_metadesc', param('metadesc', 'string', true)); $Item->set_setting('post_custom_headers', param('custom_headers', 'string', true)); // set custom Item settings foreach (array('double', 'varchar') as $type) { $count_custom_field = $comment_Blog->get_setting('count_custom_' . $type); $param_type = $type == 'varchar' ? 'string' : $type; for ($i = 1; $i <= $count_custom_field; $i++) { // For each custom double field: $field_guid = $comment_Blog->get_setting('custom_' . $type . $i); $Item->set_setting('custom_' . $type . '_' . $field_guid, param('item_' . $type . '_' . $field_guid, $param_type, NULL)); } } // Trigger plugin event, allowing to manipulate or validate the item before it gets previewed $Plugins->trigger_event('AppendItemPreviewTransact', array('Item' => &$Item)); if ($Messages->has_errors()) { $errcontent = $Messages->display(T_('Invalid post, please correct these errors:'), '', false); $Item->content = $errcontent . "\n<hr />\n" . $content; } // little funky fix for IEwin, rawk on that code global $Hit; if ($Hit->is_winIE() && !isset($IEWin_bookmarklet_fix)) { // QUESTION: Is this still needed? What about $IEWin_bookmarklet_fix? (blueyed) $Item->content = preg_replace('/\\%u([0-9A-F]{4,4})/e', "'&#'.base_convert('\\1',16,10). ';'", $Item->content); } }
/** * Check permission for this user * * @param string Permission name, can be one of: * - 'edit_timestamp' * - 'cats_post_statuses', see {@link User::check_perm_catsusers()} * - either group permission names, see {@link Group::check_perm()} * - either blogusers permission names, see {@link User::check_perm_blogusers()} * @param string Permission level * @param boolean Execution will halt if this is !0 and permission is denied * @param mixed Permission target (blog ID, array of cat IDs, Item, Comment...) * @return boolean 0 if permission denied */ function check_perm($permname, $permlevel = 'any', $assert = false, $perm_target = NULL) { global $Debuglog, $Settings; if (is_object($perm_target) && isset($perm_target->ID)) { $perm_target_ID = $perm_target->ID; } elseif (!is_array($perm_target)) { $perm_target_ID = $perm_target; } if (isset($perm_target_ID) && isset($this->cache_perms[$permname][$permlevel][$perm_target_ID])) { // Permission in available in Cache: $Debuglog->add("Got perm [{$permname}][{$permlevel}][{$perm_target_ID}] from cache", 'perms'); return $this->cache_perms[$permname][$permlevel][$perm_target_ID]; } $pluggable_perms = array('admin', 'spamblacklist', 'slugs', 'templates', 'options', 'files', 'users'); if (in_array($permname, $pluggable_perms)) { $permname = 'perm_' . $permname; } //$Debuglog->add( "Querying perm [$permname][$permlevel]".( isset( $perm_target_ID ) ? '['.$perm_target_ID.']' : '' ).']', 'perms' ); //pre_dump( 'Perm target: '.var_export( $perm_target, true ) ); $perm = false; switch ($permname) { // What permission do we want to check? case 'cats_post_statuses': case 'cats_post!published': case 'cats_post!community': case 'cats_post!protected': case 'cats_post!private': case 'cats_post!review': case 'cats_post!draft': case 'cats_post!deprecated': case 'cats_post!redirected': case 'cats_item_type_standard': case 'cats_item_type_restricted': case 'cats_item_type_admin': // Category permissions... if (!is_array($perm_target)) { // We need an array here: $perm_target = array($perm_target); } // First we need to create an array of blogs, not cats $perm_target_blogs = array(); foreach ($perm_target as $loop_cat_ID) { $loop_cat_blog_ID = get_catblog($loop_cat_ID); // echo "cat $loop_cat_ID -> blog $loop_cat_blog_ID <br />"; if (!in_array($loop_cat_blog_ID, $perm_target_blogs)) { // not already in list: add it: $perm_target_blogs[] = $loop_cat_blog_ID; } } $perm = true; // Permission granted if no blog denies it below $blogperm = 'blog_' . substr($permname, 5); // Now we'll check permissions for each blog: foreach ($perm_target_blogs as $loop_blog_ID) { if (!$this->check_perm($blogperm, $permlevel, false, $loop_blog_ID)) { // If at least one blog denies the permission: $perm = false; break; } } break; case 'recycle_owncmts': // Check permission to edit comments for own items $Comment =& $perm_target; $Item =& $Comment->get_Item(); $blog_ID = $Item->get_blog_ID(); if ($Item->creator_user_ID == $this->ID) { // Current user is owner of this item if ($Item->is_locked() && !$this->check_perm('blog_cats', 'edit', false, $blog_ID)) { // Comment item is locked and current user is not allowed to edit locked items comment break; } $comment_author_User =& $Comment->get_author_User(); if ((empty($comment_author_User) || $comment_author_User->level <= $this->level) && in_array($Comment->status, array('published', 'community', 'protected'))) { // Comment author is anonymous or his level is lower than current User level, and the Comment was published with some of the above statuses // Check blog user perms to see if user may recycle his own posts comments $perm = $this->check_perm_blogusers('blog_recycle_owncmts', $permlevel, $blog_ID); if (!$perm) { // Check groups for permissions to this specific blog: $perm = $this->Group->check_perm_bloggroups('blog_recycle_owncmts', $permlevel, $blog_ID); } } } break; case 'blog_ismember': case 'blog_can_be_assignee': case 'blog_post_statuses': case 'blog_post!published': case 'blog_post!community': case 'blog_post!protected': case 'blog_post!private': case 'blog_post!review': case 'blog_post!draft': case 'blog_post!deprecated': case 'blog_post!redirected': case 'blog_del_post': case 'blog_edit': case 'blog_edit_cmt': case 'blog_comments': case 'blog_comment_statuses': case 'blog_del_cmts': case 'blog_vote_spam_comments': case 'blog_comment!published': case 'blog_comment!community': case 'blog_comment!protected': case 'blog_comment!private': case 'blog_comment!deprecated': case 'blog_comment!review': case 'blog_comment!draft': case 'blog_properties': case 'blog_cats': case 'blog_item_type_standard': case 'blog_item_type_restricted': case 'blog_item_type_admin': case 'blog_edit_ts': // Blog permission to edit its properties... if ($this->check_perm_blogowner($perm_target_ID)) { // Owner can do *almost* anything: $perm = true; break; } /* continue */ /* continue */ case 'blog_admin': // This is what the owner does not have access to! // Group may grant VIEW access, FULL access: $this->get_Group(); $group_permlevel = $permlevel == 'view' || $permlevel == 'any' ? $permlevel : 'editall'; if ($this->Group->check_perm('blogs', $group_permlevel)) { // If group grants a global permission: $perm = true; break; } if ($perm_target_ID > 0) { // Check user perm for this blog: $perm = $this->check_perm_blogusers($permname, $permlevel, $perm_target_ID); if (!$perm) { // Check groups for permissions to this specific blog: $perm = $this->Group->check_perm_bloggroups($permname, $permlevel, $perm_target_ID); } } break; case 'comment!CURSTATUS': /** * @var Comment */ $Comment =& $perm_target; // Change the permname to one of the following: $permname = 'comment!' . $Comment->status; case 'comment!published': case 'comment!community': case 'comment!protected': case 'comment!private': case 'comment!review': case 'comment!draft': case 'comment!deprecated': case 'comment!trash': /** * @var Comment */ $Comment =& $perm_target; $Item =& $Comment->get_Item(); $blog_ID = $Item->get_blog_ID(); $check_status = substr($permname, 8); if ($Comment->is_meta() && in_array($permlevel, array('edit', 'moderate', 'delete'))) { // Check the permissions for meta comment with special function $perm = $this->check_perm('meta_comment', $permlevel, false, $Comment); break; } if ($permlevel != 'view' && $Item->is_locked() && !$this->check_perm('blog_cats', 'edit', false, $blog_ID)) { // Comment item is locked and current user is not allowed to edit/moderate locked items comment break; } if ($this->check_perm_blog_global($blog_ID, $permlevel)) { // User has global permission on this blog: $perm = true; break; } if ($Comment->status == 'trash') { // only global group 'editall' perm can give rights to 'trash' status, but this is not the case break; } if ($permlevel == 'delete') { // permlevel is delete so we have to check the 'blog_del_cmts' permission $perm = $this->check_perm('blog_del_cmts', 'edit', false, $blog_ID) || $this->check_perm('recycle_owncmts', $permlevel, false, $Comment); break; } // Check comment current status permissions at the blog level: $blog_permname = 'blog_comment!' . $Comment->status; $perm = $perm || $this->check_perm_blogusers($blog_permname, $permlevel, $blog_ID, $Comment); if (!$perm) { // Check groups for permissions to this specific blog: $perm = $this->Group->check_perm_bloggroups($blog_permname, $permlevel, $blog_ID, $Comment, $this); } if ($perm && $Comment->status != $check_status) { // also check the requested status permissions at the blog level $blog_permname = 'blog_comment!' . $check_status; $perm = $this->check_perm_blogusers($blog_permname, 'create', $blog_ID); if (!$perm) { // Check groups for permissions to this specific blog: $perm = $this->Group->check_perm_bloggroups($blog_permname, 'create', $blog_ID); } } break; case 'meta_comment': // Check permission for meta comment: if ($permlevel == 'view' || $permlevel == 'add') { // Set Item from target object $Item =& $perm_target; } elseif ($permlevel == 'edit' || $permlevel == 'moderate' || $permlevel == 'delete') { // Set Comment from target object $Comment =& $perm_target; if (empty($Comment) || !$Comment->is_meta()) { // Comment must be defined and meta to check these permissions $perm = false; break; } $Item =& $Comment->get_Item(); } else { // Invalid permission level $perm = false; break; } if (empty($Item)) { // Item must be defined to check these permissions $perm = false; break; } switch ($permlevel) { case 'view': case 'add': // Check perms to View/Add meta comments: $perm = $this->check_perm('item_post!CURSTATUS', 'edit', false, $Item) || $this->check_perm('blog_del_post', '', false, $Item->get_blog_ID()); break; case 'edit': // Check perms to Edit meta comment $perm = $Comment->author_user_ID == $this->ID && $this->check_perm('meta_comment', 'view', false, $Item); break; case 'moderate': // Moderation is not available for meta comment $perm = false; break; case 'delete': // Check perms to Delete meta comment: if ($this->check_perm('blog_del_post', '', false, $Item->get_blog_ID())) { // If User can delete this Item $perm = true; break; } if ($this->check_perm('item_post!CURSTATUS', 'edit', false, $Item) && $Comment->author_user_ID == $this->ID) { // If it is own meta comment of the User $perm = true; break; } break; } break; case 'item_post!CURSTATUS': /** * @var Item */ $Item =& $perm_target; // Change the permname to one of the following: $permname = 'item_post!' . $Item->status; case 'item_post!published': case 'item_post!community': case 'item_post!protected': case 'item_post!private': case 'item_post!review': case 'item_post!draft': case 'item_post!deprecated': case 'item_post!redirected': // Get the Blog ID /** * @var Item */ $Item =& $perm_target; $blog_ID = $Item->get_blog_ID(); $check_status = substr($permname, 10); if ($permlevel != 'view' && $Item->is_locked() && !$this->check_perm('blog_cats', 'edit', false, $blog_ID)) { // Item is locked and current user is not allowed to edit locked items ( only view permission is allowed by default for locked items ) break; } if ($this->check_perm_blog_global($blog_ID, $permlevel)) { // User has global permission on this blog: $perm = true; break; } if ($permlevel == 'delete') { // permlevel is delete so we have to check the 'blog_del_post' permission $perm = $this->check_perm('blog_del_post', 'edit', false, $blog_ID); break; } // Check permissions at the blog level: $blog_permname = 'blog_post!' . $Item->status; $perm = $this->check_perm_blogusers($blog_permname, $permlevel, $blog_ID, $Item); if (!$perm) { // Check groups for permissions to this specific blog: $perm = $this->Group->check_perm_bloggroups($blog_permname, $permlevel, $blog_ID, $Item, $this); } if ($perm && $Item->status != $check_status) { // also check the requested status permissions at the blog level $blog_permname = 'blog_post!' . $check_status; $perm = $this->check_perm_blogusers($blog_permname, 'create', $blog_ID); if (!$perm) { // Check groups for permissions to this specific blog: $perm = $this->Group->check_perm_bloggroups($blog_permname, 'create', $blog_ID); } } break; case 'stats': // Blog permission to edit its properties... $this->get_Group(); // Group may grant VIEW acces, FULL access: if ($this->Group->check_perm($permname, $permlevel)) { // If group grants a global permission: $perm = true; break; } if ($perm_target > 0) { // Check user perm for this blog: $perm = $this->check_perm_blogusers($permname, $permlevel, $perm_target); if (!$perm) { // Check groups for permissions to this specific blog: $perm = $this->Group->check_perm_bloggroups($permname, $permlevel, $perm_target); } } break; case 'user': // Check if user can 'view'/'moderate'/'edit'/'delete' another user $User =& $perm_target; if (!$this->check_status('can_view_user', $User->ID)) { // User can't even view the edited User break; } // If user has global permission on all users then everything is allowed if ($this->check_perm('users', 'edit')) { // Check if user can edit/delete other users $perm = true; break; } if ($permlevel == 'delete' || $permlevel == 'edit') { // These permission levels are not allowed for this user break; } if (!$Settings->get('allow_anonymous_user_profiles') && !$this->check_perm('cross_country_allow_profiles') && (empty($this->ctry_ID) || $this->ctry_ID !== $User->ctry_ID)) { // Users can view/browse other users only from the same country, but this user country is empty or not the same as the target user country // this User has no permission to even view the target user $User->get_Group(); if ($User->Group->level < $Settings->get('allow_anonymous_user_level_min') || $User->Group->level > $Settings->get('allow_anonymous_user_level_max')) { // The anonymous users have no access to view this user break; } } // Note: With this implementation only admin users are allowed to view users from different countries when cross country browsing is restricted // check if user has permission to moderate another user if ($permlevel == 'moderate' && $this->check_perm('users', 'moderate')) { // this user has moderator permission, check if the group level is higher then the target user group level $this->get_Group(); $User->get_Group; $perm = $this->Group->level > $User->Group->level; break; } // Only 'view' permlevel remained, and this user is allowed to view the target user $perm = true; break; // asimo> edit_timestamp permission was converted to blog_edit_ts permission // asimo> files permission was converted to pluggable permission /*case 'files': $this->get_Group(); $perm = $this->Group->check_perm( $permname, $permlevel );*/ /* Notes: * - $perm_target can be: * - NULL or 0: check global group permission only * - positive: check global group permission and * (if granted) if a specific blog denies it. * fp> This is BAD BAD BAD because it's inconsistent with the other permissions * in b2evolution. There should NEVER be a denying. ony additional allowing. * It's also inconsistent with most other permission systems. * The lower file permission level for groups is now called "No Access" * This should be renamed to "Depending on each blog's permissions" * Whatever general permissions you have on files, blog can give you additional permissions * but they can never take a global perm away. * Tblue> On the permissions page it says that the blog perms will be restricted * by any global perms, which means to me that a blog cannot grant e. g. * the files upload perm if this perm isn't granted globally... But apparently * it shouldn't be like that?! I understand it should be like that then: * if( ! $perm && $perm_target && in_array( $permlevel, array( 'add', 'view', 'edit' ) ) * { * // check if blog grants permission. * } * If this is correct, we should remove the note on the blog permissions * pages and the group properties form. * fp> ok, I had forgotten we had that old message, but still it doesn't say it will, it says it *may* ! * To be exact the message should be " * Note: General group permissions may further restrict or extend any permissions defined here." * Restriction should only happen when "NO ACCESS" is selected * But when "Depending on each blog's permissions" is selected, THEN (and I guess ONLY then) the blog permissions should be used * Note: This is quite messy actually. maybe it would make more sense to separate group permissions by "root type": * i-e nto use the same permission for blog roots vs user root vs shared root vs skins root * what do you think? * Tblue> That sounds OK. So we would add another option to the global * 'files' group perm setting ("Depending on each blog's permissions"), right? * fp> yes. * tb> Regarding separation: It could make sense. The blog-specific permissions would only * affect blog roots (and if "Depending on each blog's permissions" is selected; * for the other roots we would add separate (global) settings... * fp> yes. * - Only a $permlevel of 'add', 'view' or 'edit' can be * denied by blog permissions. * - If the group grants the 'all' permission, blogs cannot * deny it. */ /* if( $perm && $perm_target && in_array( $permlevel, array( 'add', 'view', 'edit' ) ) && $this->Group->get( 'perm_files' ) != 'all' ) { // Check specific blog perms: $perm = $this->check_perm_blogusers( $permname, $permlevel, $perm_target ); if ( ! $perm ) { // Check groups for permissions for this specific blog: $perm = $this->Group->check_perm_bloggroups( $permname, $permlevel, $perm_target ); } } */ //break; // asimo> edit_timestamp permission was converted to blog_edit_ts permission // asimo> files permission was converted to pluggable permission /*case 'files': $this->get_Group(); $perm = $this->Group->check_perm( $permname, $permlevel );*/ /* Notes: * - $perm_target can be: * - NULL or 0: check global group permission only * - positive: check global group permission and * (if granted) if a specific blog denies it. * fp> This is BAD BAD BAD because it's inconsistent with the other permissions * in b2evolution. There should NEVER be a denying. ony additional allowing. * It's also inconsistent with most other permission systems. * The lower file permission level for groups is now called "No Access" * This should be renamed to "Depending on each blog's permissions" * Whatever general permissions you have on files, blog can give you additional permissions * but they can never take a global perm away. * Tblue> On the permissions page it says that the blog perms will be restricted * by any global perms, which means to me that a blog cannot grant e. g. * the files upload perm if this perm isn't granted globally... But apparently * it shouldn't be like that?! I understand it should be like that then: * if( ! $perm && $perm_target && in_array( $permlevel, array( 'add', 'view', 'edit' ) ) * { * // check if blog grants permission. * } * If this is correct, we should remove the note on the blog permissions * pages and the group properties form. * fp> ok, I had forgotten we had that old message, but still it doesn't say it will, it says it *may* ! * To be exact the message should be " * Note: General group permissions may further restrict or extend any permissions defined here." * Restriction should only happen when "NO ACCESS" is selected * But when "Depending on each blog's permissions" is selected, THEN (and I guess ONLY then) the blog permissions should be used * Note: This is quite messy actually. maybe it would make more sense to separate group permissions by "root type": * i-e nto use the same permission for blog roots vs user root vs shared root vs skins root * what do you think? * Tblue> That sounds OK. So we would add another option to the global * 'files' group perm setting ("Depending on each blog's permissions"), right? * fp> yes. * tb> Regarding separation: It could make sense. The blog-specific permissions would only * affect blog roots (and if "Depending on each blog's permissions" is selected; * for the other roots we would add separate (global) settings... * fp> yes. * - Only a $permlevel of 'add', 'view' or 'edit' can be * denied by blog permissions. * - If the group grants the 'all' permission, blogs cannot * deny it. */ /* if( $perm && $perm_target && in_array( $permlevel, array( 'add', 'view', 'edit' ) ) && $this->Group->get( 'perm_files' ) != 'all' ) { // Check specific blog perms: $perm = $this->check_perm_blogusers( $permname, $permlevel, $perm_target ); if ( ! $perm ) { // Check groups for permissions for this specific blog: $perm = $this->Group->check_perm_bloggroups( $permname, $permlevel, $perm_target ); } } */ //break; default: // Check pluggable permissions using user permission check function $this->get_Group(); $perm = Module::check_perm($permname, $permlevel, $perm_target, 'user_func', $this->Group); if ($perm === true || $perm === NULL) { // If user_func or user perm not exists in the corresponding module then $perm value will be NULL and we have to check the group permission. // If user_func exists and returns true, then we have to check group permission to make sure it does not restrict the user perm. // Other global permissions (see if the group can handle them). // Forward request to group: $perm = $this->Group->check_perm($permname, $permlevel, $perm_target); } } if (is_object($perm_target)) { // Prevent catchable E_FATAL with PHP 5.2 (because there's no __tostring for e.g. Item) $taget_name = get_class($perm_target) . '(' . $perm_target_ID . ')'; } elseif (is_array($perm_target)) { // Convert to ID list $taget_name = '(' . implode(',', $perm_target) . ')'; } else { $taget_name = $perm_target; } $Debuglog->add('User perm ' . $permname . ':' . $permlevel . ':' . $taget_name . ' => ' . ($perm ? 'granted' : 'DENIED'), 'perms'); if (!$perm && $assert) { // We can't let this go on! global $app_name; debug_die(sprintf(T_('Group/user permission denied by %s!'), $app_name) . " ({$permname}:{$permlevel}:" . (is_object($perm_target) ? get_class($perm_target) . '(' . $perm_target_ID . ')' : (is_array($perm_target) ? implode(', ', $perm_target) : $perm_target)) . ")"); } if (isset($perm_target_ID)) { // echo "cache_perms[$permname][$permlevel][$perm_target] = $perm;"; $this->cache_perms[$permname][$permlevel][$perm_target_ID] = $perm; } return $perm; }
/** * * Check if new category needs to be created or not (after post editing). * If the new category radio is checked creates the new category and set it to post category * If the new category checkbox is checked creates the new category and set it to post extracat * * Function is called during post creation or post update * * @param Object Post category (by reference). * @param Array Post extra categories (by reference). * @return boolean true - if there is no new category, or new category created succesfull; false if new category creation failed. */ function check_categories(&$post_category, &$post_extracats) { $post_category = param('post_category', 'integer', -1); $post_extracats = param('post_extracats', 'array/integer', array()); global $Messages, $Blog, $blog; load_class('chapters/model/_chaptercache.class.php', 'ChapterCache'); $GenericCategoryCache =& get_ChapterCache(); if ($post_category == -1) { // no main cat select if (count($post_extracats) == 0) { // no extra cat select $post_category = $Blog->get_default_cat_ID(); } else { // first extracat become main_cat if (get_allow_cross_posting() >= 2) { // allow moving posts between different blogs is enabled, set first selected cat as main cat $post_category = $post_extracats[0]; } else { // allow moving posts between different blogs is disabled - we need a main cat from $blog foreach ($post_extracats as $cat) { if (get_catblog($cat) != $blog) { // this cat is not from $blog continue; } // set first cat from $blog as main cat $post_category = $cat; break; } if ($post_category == -1) { // wasn't cat selected from $blog select a default as main cat $post_category = $Blog->get_default_cat_ID(); } } } if ($post_category) { // If main cat is not a new category, and has been autoselected $GenericCategory =& $GenericCategoryCache->get_by_ID($post_category); $post_category_Blog = $GenericCategory->get_Blog(); $Messages->add(sprintf(T_('The main category for this post has been automatically set to "%s" (Blog "%s")'), $GenericCategory->get_name(), $post_category_Blog->get('name')), 'warning'); } } if (!$post_category || in_array(0, $post_extracats)) { global $current_User; if (!$current_User->check_perm('blog_cats', '', false, $Blog->ID)) { // Current user cannot add a categories for this blog check_categories_nosave($post_category, $post_extracats); // set up the category parameters $Messages->add(T_('You are not allowed to create a new category.'), 'error'); return false; } $category_name = param('category_name', 'string', true); if ($category_name == '') { $show_error = !$post_category; // new main category without name => error message check_categories_nosave($post_category, $post_extracats); // set up the category parameters if ($show_error) { // new main category without name $Messages->add(T_('Please provide a name for new category.'), 'error'); return false; } return true; } $new_GenericCategory =& $GenericCategoryCache->new_obj(NULL, $blog); // create new category object $new_GenericCategory->set('name', $category_name); if ($new_GenericCategory->dbinsert() !== false) { $Messages->add(T_('New category created.'), 'success'); if (!$post_category) { $post_category = $new_GenericCategory->ID; // set the new ID } if (($extracat_key = array_search('0', $post_extracats)) || $post_extracats[0] == '0') { if ($extracat_key) { unset($post_extracats[$extracat_key]); } else { unset($post_extracats[0]); } $post_extracats[] = $new_GenericCategory->ID; } $GenericCategoryCache->add($new_GenericCategory); } else { $Messages->add(T_('New category creation failed.'), 'error'); return false; } } if (get_allow_cross_posting() == 2) { // Extra cats in different blogs is disabled, check selected extra cats $post_category_blog = get_catblog($post_category); $ignored_cats = ''; foreach ($post_extracats as $key => $cat) { if (get_catblog($cat) != $post_category_blog) { // this cat is not from main category blog, it has to be ingnored $GenericCategory =& $GenericCategoryCache->get_by_ID($cat); $ignored_cats = $ignored_cats . $GenericCategory->get_name() . ', '; unset($post_extracats[$key]); } } $ingnored_length = strlen($ignored_cats); if ($ingnored_length > 2) { // ingnore list is not empty global $current_User, $admin_url; if ($current_User->check_perm('options', 'view', false)) { $cross_posting_text = '<a href="' . $admin_url . '?ctrl=features">' . T_('cross-posting is disabled') . '</a>'; } else { $cross_posting_text = T_('cross-posting is disabled'); } $ignored_cats = substr($ignored_cats, 0, $ingnored_length - 2); $Messages->add(sprintf(T_('The category selection "%s" was ignored since %s'), $ignored_cats, $cross_posting_text), 'warning'); } } // make sure main cat is in extracat list and there are no duplicates $post_extracats[] = $post_category; $post_extracats = array_unique($post_extracats); return true; }
/** * Set param value * * By default, all values will be considered strings * * @todo extra_cat_IDs recording * * @param string parameter name * @param mixed parameter value * @param boolean true to set to NULL if empty value * @return boolean true, if a value has been set; false if it has not changed */ function set($parname, $parvalue, $make_null = false) { switch ($parname) { case 'main_cat_ID': $r = $this->set_param('main_cat_ID', 'number', $parvalue, false); // make sure main cat is in extracat list and there are no duplicates $this->extra_cat_IDs[] = $this->main_cat_ID; $this->extra_cat_IDs = array_unique($this->extra_cat_IDs); // Update derived property: $this->blog_ID = get_catblog($this->main_cat_ID); // This is a derived var return $r; case 'extra_cat_IDs': // ARRAY! We do not record this change (yet) $this->extra_cat_IDs = $parvalue; // make sure main cat is in extracat list and there are no duplicates $this->extra_cat_IDs[] = $this->main_cat_ID; $this->extra_cat_IDs = array_unique($this->extra_cat_IDs); break; case 'issue_date': case 'datestart': $this->issue_date = $parvalue; return $this->set_param('datestart', 'date', $parvalue, false); case 'ptyp_ID': return $this->set_param($parname, 'number', $parvalue, true); default: return $this->set_param($parname, 'string', $parvalue, $make_null); } }
/** * Check permission for this group on a set of specified categories * * This is not for direct use, please call {@link User::check_perm()} instead * * @see User::check_perm() * @param string Permission name, can be one of the following: * - cat_post_statuses * - more to come later... * @param string Permission level * @param array Array of target cat IDs * @return boolean 0 if permission denied */ function check_perm_catsgroups($permname, $permlevel, &$perm_target_cats) { // Check if permission is granted: switch ($permname) { case 'cats_post_statuses': case 'cats_post!published': case 'cats_post!protected': case 'cats_post!private': case 'cats_post!draft': case 'cats_post!deprecated': case 'cats_post!redirected': // We'll actually pass this on to blog permissions // First we need to create an array of blogs, not cats $perm_target_blogs = array(); foreach ($perm_target_cats as $loop_cat_ID) { $loop_cat_blog_ID = get_catblog($loop_cat_ID); // echo "cat $loop_cat_ID -> blog $loop_cat_blog_ID <br />"; if (!in_array($loop_cat_blog_ID, $perm_target_blogs)) { // not already in list: add it: $perm_target_blogs[] = $loop_cat_blog_ID; } } // Now we'll check permissions for each blog: foreach ($perm_target_blogs as $loop_blog_ID) { if (!$this->check_perm('blog_' . substr($permname, 5), $permlevel, $loop_blog_ID)) { // If at least one blog is denied: return false; // permission denied } } return true; // Permission granted } return false; // permission denied }
/** * We want to preview a single post, we are going to fake a lot of things... */ function preview_from_request() { global $current_User; if (empty($current_User)) { // dh> only logged in user's can preview. Alternatively we need those checks where $current_User gets used below. return; } global $DB, $localtimenow, $Messages, $BlogCache; global $Plugins; $preview_userid = param('preview_userid', 'integer', true); $post_status = param('post_status', 'string', true); $post_locale = param('post_locale', 'string', $current_User->locale); $content = param('content', 'html', true); $post_title = param('post_title', 'html', true); $post_excerpt = param('post_excerpt', 'string', true); $post_url = param('post_url', 'string', ''); $post_category = param('post_category', 'integer', true); $post_views = param('post_views', 'integer', 0); $renderers = param('renderers', 'array', array('default')); if (!is_array($renderers)) { // dh> workaround for param() bug. See rev 1.93 of /inc/_misc/_misc.funcs.php $renderers = array('default'); } $comment_Blog =& $BlogCache->get_by_ID(get_catblog($post_category)); if ($comment_Blog->allowcomments == 'post_by_post') { // param is required $post_comment_status = param('post_comment_status', 'string', true); } else { $post_comment_status = $comment_Blog->allowcomments; } // Get issue date, using the user's locale (because it's entered like this in the form): locale_temp_switch($current_User->locale); param_date('item_issue_date', T_('Please enter a valid issue date.'), false); // TODO: dh> get_param() is always true here, also on invalid dates: if (strlen(get_param('item_issue_date'))) { // only set it, if a date was given: param_time('item_issue_time'); $item_issue_date = form_date(get_param('item_issue_date'), get_param('item_issue_time')); // TODO: cleanup... } else { $item_issue_date = date('Y-m-d H:i:s', $localtimenow); } locale_restore_previous(); if (!($item_typ_ID = param('item_typ_ID', 'integer', NULL))) { $item_typ_ID = NULL; } if (!($item_st_ID = param('item_st_ID', 'integer', NULL))) { $item_st_ID = NULL; } if (!($item_assigned_user_ID = param('item_assigned_user_ID', 'integer', NULL))) { $item_assigned_user_ID = NULL; } if (!($item_deadline = param('item_deadline', 'string', NULL))) { $item_deadline = NULL; } $item_priority = param('item_priority', 'integer', NULL); // QUESTION: can this be also empty/NULL? // Do some optional filtering on the content // Typically stuff that will help the content to validate // Useful for code display. // Will probably be used for validation also. $Plugins_admin =& get_Cache('Plugins_admin'); $Plugins_admin->filter_contents($post_title, $content, $renderers); $post_title = format_to_post($post_title); $content = format_to_post($content); $this->sql = "SELECT\r\n\t\t\t0 AS post_ID,\r\n\t\t\t{$preview_userid} AS post_creator_user_ID,\r\n\t\t\t{$preview_userid} AS post_lastedit_user_ID,\r\n\t\t\t'{$item_issue_date}' AS post_datestart,\r\n\t\t\t'{$item_issue_date}' AS post_datecreated,\r\n\t\t\t'{$item_issue_date}' AS post_datemodified,\r\n\t\t\t'" . $DB->escape($post_status) . "' AS post_status,\r\n\t\t\t'" . $DB->escape($post_locale) . "' AS post_locale,\r\n\t\t\t'" . $DB->escape($content) . "' AS post_content,\r\n\t\t\t'" . $DB->escape($post_title) . "' AS post_title,\r\n\t\t\t'" . $DB->escape($post_excerpt) . "' AS post_excerpt,\r\n\t\t\tNULL AS post_urltitle,\r\n\t\t\t'" . $DB->escape($post_url) . "' AS post_url,\r\n\t\t\t{$post_category} AS post_main_cat_ID,\r\n\t\t\t{$post_views} AS post_views,\r\n\t\t\t'' AS post_flags,\r\n\t\t\t'noreq' AS post_notifications_status,\r\n\t\t\tNULL AS post_notifications_ctsk_ID,\r\n\t\t\t" . bpost_count_words($content) . " AS post_wordcount,\r\n\t\t\t" . $DB->quote($post_comment_status) . " AS post_comment_status,\r\n\t\t\t'" . $DB->escape(implode('.', $renderers)) . "' AS post_renderers,\r\n\t\t\t" . $DB->quote($item_assigned_user_ID) . " AS post_assigned_user_ID,\r\n\t\t\t" . $DB->quote($item_typ_ID) . " AS post_ptyp_ID,\r\n\t\t\t" . $DB->quote($item_st_ID) . " AS post_pst_ID,\r\n\t\t\t" . $DB->quote($item_deadline) . " AS post_datedeadline,\r\n\t\t\t" . $DB->quote($item_priority) . " AS post_priority"; $this->total_rows = 1; $this->total_pages = 1; $this->page = 1; // ATTENTION: we skip the parent on purpose here!! fp> refactor DataObjectList2::query(false, false, false, 'PREVIEW QUERY'); $Item =& $this->Cache->instantiate($this->rows[0]); // Trigger plugin event, allowing to manipulate or validate the item before it gets previewed $Plugins->trigger_event('AppendItemPreviewTransact', array('Item' => &$Item)); if ($errcontent = $Messages->display(T_('Invalid post, please correct these errors:'), '', false, 'error')) { $Item->content = $errcontent . "\n<hr />\n" . $content; } // little funky fix for IEwin, rawk on that code global $Hit; if ($Hit->is_winIE && !isset($IEWin_bookmarklet_fix)) { // QUESTION: Is this still needed? What about $IEWin_bookmarklet_fix? (blueyed) $Item->content = preg_replace('/\\%u([0-9A-F]{4,4})/e', "'&#'.base_convert('\\1',16,10). ';'", $Item->content); } }
/** * blogger.newPost makes a new post to a designated blog. * * Optionally, will publish the blog after making the post. (In b2evo, this means the * new post will be in 'published' state). * On success, it returns the unique ID of the new post (usually a seven-digit number * at this time). * On error, it will return some error message. * * @see http://www.blogger.com/developers/api/1_docs/xmlrpc_newPost.html * @see http://www.sixapart.com/developers/xmlrpc/blogger_api/bloggernewpost.html * * @param xmlrpcmsg XML-RPC Message * 0 appkey (string): Unique identifier/passcode of the application sending the post. * (See access info {@link http://www.blogger.com/developers/api/1_docs/#access} .) * 1 blogid (string): Unique identifier of the blog the post will be added to. * Currently ignored in b2evo, in favor of the category. * 2 username (string): Login for a Blogger user who has permission to post to the blog. * 3 password (string): Password for said username. * 4 content (string): Contents of the post. * 5 publish (boolean): If true, the blog will be published immediately after the * post is made. (In b2evo,this means, the new post will be in 'published' state, * otherwise it would be in draft state). * @return xmlrpcresp XML-RPC Response */ function blogger_newpost($m) { global $xmlrpcerruser; // import user errcode value global $DB; global $Settings, $Messages; // CHECK LOGIN: /** * @var User */ if (!($current_User =& xmlrpcs_login($m, 2, 3))) { // Login failed, return (last) error: return xmlrpcs_resperror(); } // GET BLOG: /** * @var Blog */ if (!($Blog =& xmlrpcs_get_Blog($m, 1))) { // Login failed, return (last) error: return xmlrpcs_resperror(); } $content = $m->getParam(4); $content = $content->scalarval(); $publish = $m->getParam(5); $publish = $publish->scalarval(); $status = $publish ? 'published' : 'draft'; logIO("Publish: {$publish} -> Status: {$status}"); $cat_IDs = xmlrpc_getpostcategories($content); if (empty($cat_IDs)) { // There were no categories passed in the content: if (!($main_cat = $Blog->get_default_cat_ID())) { // No default category found for requested blog. return xmlrpcs_resperror(12); // User error 12 } $cat_IDs = array($main_cat); } else { $main_cat = $cat_IDs[0]; } // CHECK PERMISSION: (we need perm on all categories, especially if they are in different blogs) if (!$current_User->check_perm('cats_post!' . $status, 'edit', false, $cat_IDs)) { // Permission denied return xmlrpcs_resperror(3); // User error 3 } logIO('Permission granted.'); logIO('Main cat: ' . $main_cat); // Check if category exists if (get_the_category_by_ID($main_cat, false) === false) { // Cat does not exist: // fp> TODO use $Blog->get_default_cat_ID(); return xmlrpcs_resperror(11); // User error 11 } if (get_catblog($main_cat) != $Blog->ID) { // The category does not match the blog! return xmlrpcs_resperror(11); // User error 11 } $post_date = date('Y-m-d H:i:s', time() + $Settings->get('time_difference')); // Extract <title> from content $post_title = xmlrpc_getposttitle($content); // cleanup content from extra tags like <category> and <title>: $content = xmlrpc_removepostdata($content); // COMPLETE VALIDATION & INSERT: return xmlrpcs_new_item($post_title, $content, $post_date, $main_cat, $cat_IDs, $status); }
// Check permission based on DB status: $current_User->check_perm('item_post!' . $edited_Item->get('status'), 'edit', true, $edited_Item); $edited_Item->status = param('post_status', 'string', NULL); // 'published' or 'draft' or ... // We know we can use at least one status, // but we need to make sure the requested/default one is ok: $edited_Item->status = $Blog->get_allowed_item_status($edited_Item->status); // We use the request variables to fill the edit form, because we need to be able to pass those values // from tab to tab via javascript when the editor wants to switch views... $edited_Item->load_from_Request(); // needs Blog set param('post_extracats', 'array', array()); param('edit_date', 'integer', 0); // checkbox $edited_Item->main_cat_ID = param('post_category', 'integer', $edited_Item->main_cat_ID); if ($edited_Item->main_cat_ID && $allow_cross_posting < 3 && get_catblog($edited_Item->main_cat_ID) != $blog) { // the main cat is not in the list of categories; this happens, if the user switches blogs during editing: $edited_Item->main_cat_ID = $Blog->get_default_cat_ID(); } $post_extracats = param('post_extracats', 'array', $post_extracats); param('item_tags', 'string', ''); // Trackback addresses (never saved into item) param('trackback_url', 'string', ''); // Page title: $js_doc_title_prefix = T_('Editing post') . ': '; $AdminUI->title = $js_doc_title_prefix . $edited_Item->dget('title', 'htmlhead'); $AdminUI->title_titlearea = sprintf(T_('Editing post #%d in blog: %s'), $edited_Item->ID, $Blog->get('name')); // Params we need for tab switching: $tab_switch_params = 'p=' . $edited_Item->ID; break; case 'edit':