/** * Select all SD pages (not only saved SDs as incorrect SDs may be not saved). */ public function getSDPages($types, $name, $not_name, $offset, $limit, &$total) { global $haclgContLang; $dbr = wfGetDB(DB_SLAVE); $t = $types ? array_flip(IACLStorage::explode($types)) : NULL; $n = str_replace(' ', '_', $name); $not_n = $not_name ? str_replace(' ', '_', $not_name) : NULL; $where = array(); foreach ($haclgContLang->getPetAliases() as $k => $v) { if (!$t || array_key_exists($k, $t)) { $where[] = 'CAST(page_title AS CHAR CHARACTER SET utf8) COLLATE utf8_unicode_ci LIKE ' . $dbr->addQuotes($k . '/' . $n . '%'); } } if (!$where) { return array(); } $where = 'page_namespace=' . HACL_NS_ACL . ' AND (' . implode(' OR ', $where) . ')'; if ($not_n) { $where .= ' AND CAST(page_title AS CHAR CHARACTER SET utf8) COLLATE utf8_unicode_ci NOT LIKE ' . $dbr->addQuotes('%' . $not_n . '%'); } // Select SDs $res = $dbr->select('page', '*', $where, __METHOD__, array('SQL_CALC_FOUND_ROWS', 'ORDER BY' => 'page_title', 'OFFSET' => $offset, 'LIMIT' => $limit)); $rows = array(); foreach ($res as $row) { $t = Title::newFromRow($row); $rows["{$t}"] = $t; } return $rows; }
/** * Get HTML code for linked content protection toolbar. * Used by ACL editor and IntraACL toolbar. * Handled by IACLToolbar::articleSaveComplete_SaveEmbedded. * * FIXME: Linked content protection is not exactly usable, because it does not replicate * namespace and category rights applied to the source page. I don't yet know how to deal * with it... * * @param required int $peID - page ID to retrieve linked content from * @param optional int $sdType * @param optional int $sdID - page SD ID to check if SDs of linked content are already * single inclusions of this SD. * @return html code for embedded content protection toolbar * it containts checkboxes with names "sd_emb_$pageID" and values * "$sdType-$sdID-$revid". $sdID here is the passed $sdID and $revid is the ID * of embedded element's SD last revision, if it exists. * Value may be even just "-" when the toolbar was queried for article without SD, * and when the embedded element did not have any SD. */ public static function getEmbeddedHtml($peID, $sdType, $sdID) { global $haclgContLang, $wgRequest; if (!$sdID) { $sdID = ''; } // Retrieve the list of templates used on the page with id=$peID $templatelinks = IACLStorage::get('SD')->getEmbedded($peID, $sdType, $sdID, 'templatelinks'); // Retrieve the list of images used on the page $imagelinks = IACLStorage::get('SD')->getEmbedded($peID, $sdType, $sdID, 'imagelinks'); // Build HTML code for embedded content toolbar $links = array_merge($templatelinks, $imagelinks); $html = array(); $all = array(); foreach ($links as $link) { $id = $link['title']->getArticleId(); $href = $link['title']->getLocalUrl(); $t = $link['title']->getPrefixedText(); // Latest revision ID is checked to detect editing conflicts $revid = $link['sd_revid']; if ($prev = $wgRequest->getVal("sd_emb_{$id}")) { list($unused, $revid) = explode($prev, '/', 2); } if ($link['sd_title']) { if ($link['sd_single']) { // Already protected by page SD $customprot = wfMsgForContent('hacl_toolbar_emb_already_prot'); } else { // Custom SD defined $customprot = wfMsgForContent('hacl_toolbar_emb_custom_prot', $link['sd_title']->getLocalUrl()); } } else { $customprot = ''; } if ($link['used_on_pages'] > 1) { $usedon = Title::newFromText("Special:WhatLinksHere/{$t}")->getLocalUrl(array('hidelinks' => 1)); $usedon = wfMsgForContent('hacl_toolbar_used_on', $link['used_on_pages'], $usedon); } else { $usedon = ''; } $P = $customprot || $usedon ? " — " : ""; $S = $customprot && $usedon ? "; " : ""; // [x] Title — custom SD defined; used on Y pages $h = '<input type="checkbox" id="sd_emb_' . $id . '" name="sd_emb_' . $id . '"' . ($link['sd_single'] ? ' value="" checked="checked" disabled="disabled"' : " value=\"{$sdType}-{$sdID}-{$revid}\" onchange=\"hacle_noall(this)\" onclick=\"hacle_noall(this)\"" . ($prev ? ' checked="checked"' : '')) . ' />' . ' <label for="sd_emb_' . $id . '"><a target="_blank" href="' . htmlspecialchars($href) . '">' . htmlspecialchars($t) . '</a></label>' . $P . $customprot . $S . $usedon; $h = '<div class="hacl_embed' . ($link['sd_single'] ? '_disabled' : '') . '">' . $h . '</div>'; $html[] = $h; if (!$link['sd_single']) { $all[] = $id; } } if ($all) { $html[] = '<div class="hacl_embed"><input type="checkbox" id="hacl_emb_all" onchange="hacle_checkall(this, [' . implode(',', $all) . '])" onclick="hacle_checkall(this, [' . implode(',', $all) . '])" /> ' . wfMsg('hacl_toolbar_emb_all') . '</div>'; } elseif ($html) { $html[] = '<div class="hacl_embed_disabled"><input type="checkbox" disabled="disabled" checked="checked" /> ' . wfMsg('hacl_toolbar_emb_all_already') . '</div>'; } if ($html) { array_unshift($html, '<div class="hacl_emb_text">' . wfMsgForContent('hacl_toolbar_protect_embedded') . '</div>'); } $html = implode("\n", $html); return $html; }
/** * Returns the article ID for a given article name. This function has a special * handling for Special pages, which do not have an article ID. IntraACL stores * special IDs for these pages. Their IDs are always negative while the IDs of * normal pages are positive. * * @param string $articleName Name of the article * @param int $defaultNS The default namespace if no namespace is given in the name * @param boolean $force True to force the namespace to be $defaultNS * * @return int * ID of the article: * >0: ID of an article in a normal namespace * =0: Name of the article is invalid * <0: ID of a Special Page * */ function haclfArticleID($articleName, $defaultNS = NS_MAIN, $force = false) { $t = $articleName; if (!is_object($t)) { $etc = haclfDisableTitlePatch(); $t = $force ? Title::makeTitleSafe($defaultNS, $articleName) : Title::newFromText($articleName, $defaultNS); haclfRestoreTitlePatch($etc); } if (!$t || $t->getInterwiki()) { return 0; } if ($t->getNamespace() == NS_SPECIAL) { // Canonicalize special page titles list($base, $par) = SpecialPageFactory::resolveAlias($t->getText()); if (!$base) { // No such special page exists, just take the base text $base = $t->getBaseText(); } return -IACLStorage::get('SpecialPage')->idForSpecial($base); } $id = $t->getArticleID(); if ($id === 0) { $id = $t->getArticleID(Title::GAID_FOR_UPDATE); } return $id; }
function save() { return IACLStorage::get('QuickACL')->saveQuickacl($this->userid, $this->pe_ids, $this->default_pe_id); }
/** * Saves this definition into database */ public function save(&$preventLoop = array()) { // Load ID and parents before saving, as the definition may be deleted next $parents = $this['parents']; $peType = $this['pe_type']; $peID = $this['pe_id']; $key = $peType . '-' . $peID; $st = IACLStorage::get('SD'); if (!$this->data['rules']) { // Delete definition $clean = $this->clean(); $delRules = $clean['rules'] ? $clean['rules'] : array(); $addRules = array(); $st->deleteRules(array(array('pe_type' => $peType, 'pe_id' => $peID))); } else { // Update definition list($delRules, $addRules) = $this->diffRulesAssoc(); if ($delRules) { $st->deleteRules(self::expandRuleArray($delRules)); } if ($addRules) { $st->addRules(self::expandRuleArray($addRules)); } } // Invalidate userCan() cache (FIXME - in fact our parents don't need to do it...) if (isset($delRules[IACL::PE_ALL_USERS]) || isset($delRules[IACL::PE_REG_USERS]) || isset($addRules[IACL::PE_ALL_USERS]) || isset($addRules[IACL::PE_REG_USERS])) { self::$userCache = array(); self::$userCacheLoaded = array(); } else { if (isset($delRules[IACL::PE_USER])) { foreach ($delRules[IACL::PE_USER] as $userID => $rule) { unset(self::$userCache[$userID]); unset(self::$userCacheLoaded[$userID]); } } if (isset($addRules[IACL::PE_USER])) { foreach ($addRules[IACL::PE_USER] as $userID => $rule) { unset(self::$userCache[$userID]); unset(self::$userCacheLoaded[$userID]); } } } // Invalidate 'parents' field for children foreach ($delRules as $peType => $ids) { foreach ($ids as $peID => $rules) { if (!empty(self::$clean["{$peType}-{$peID}"])) { unset(self::$clean["{$peType}-{$peID}"]->data['parents']); } } } foreach ($addRules as $peType => $ids) { foreach ($ids as $peID => $rules) { if (!empty(self::$clean["{$peType}-{$peID}"])) { unset(self::$clean["{$peType}-{$peID}"]->data['parents']); } } } // Commit new state into the object cache (FIXME - is the object cache needed at all?) unset(self::$dirty[$key]); $this->rw = false; if ($this->data['rules']) { self::$clean[$key] = $this; } else { self::$clean[$key] = false; } // Invalidate parents - they will do the same recursively for their parents and so on $preventLoop[$key] = true; foreach ($parents as $p) { if (!isset($preventLoop[$p['key']])) { $p->save($preventLoop); } } }
/** * Return group members for each group of $groups='group1,group2,...', * + returns rights for each predefined right of $predefined='sd1[sd2,...' * predefined right names are joined by [ as it is forbidden by MediaWiki in titles * * TODO: Rewrite it to just getRights($titles) returning json array(array( * 'pe_type' => $pe_type, * 'pe_id' => $pe_id, * 'child_type' => $child_type, * 'child_id' => $child_id, * 'actions' => $actions, * )) */ function haclGroupClosure($groups, $rights) { global $haclgContLang; $pe = array(); $grp = $haclgContLang->getPetPrefix(IACL::PE_GROUP) . '/'; foreach (explode(',', $groups) as $k) { if (substr($k, 0, strlen($grp)) !== $grp) { $k = $grp . $k; } $pe[] = $k; } foreach (explode('[', $rights) as $k) { $pe[] = $k; } $pe = IACLDefinition::newFromTitles($pe); // Transform all user and group IDs into names $users = $groups = array(); foreach ($pe as $name => $def) { if (isset($def['rules'][IACL::PE_USER])) { $users += $def['rules'][IACL::PE_USER]; } if (isset($def['rules'][IACL::PE_GROUP])) { $groups += $def['rules'][IACL::PE_GROUP]; } } $users = IACLStorage::get('Util')->getUsers(array_keys($users)); if ($groups) { $res = wfGetDB(DB_SLAVE)->select('page', '*', array('page_id' => array_keys($groups))); $groups = array(); foreach ($res as $row) { $groups[$row->page_id] = $row; } } // Then form the result $memberAction = IACL::ACTION_GROUP_MEMBER | IACL::ACTION_GROUP_MEMBER << IACL::INDIRECT_OFFSET; $members = array(); $rules = array(); foreach ($pe as $name => $def) { if ($def['pe_type'] != IACL::PE_GROUP) { // Select all user and group rules for SDs $cur = array(); if (isset($def['rules'][IACL::PE_ALL_USERS])) { foreach ($def['rules'][IACL::PE_ALL_USERS] as $uid => $rule) { $cur[] = array('*', $rule['actions']); } } if (isset($def['rules'][IACL::PE_REG_USERS])) { foreach ($def['rules'][IACL::PE_REG_USERS] as $uid => $rule) { $cur[] = array('#', $rule['actions']); } } if (isset($def['rules'][IACL::PE_USER])) { foreach ($def['rules'][IACL::PE_USER] as $uid => $rule) { if (!isset($users[$uid])) { continue; } $cur[] = array('User:'******'actions']); } } if (isset($def['rules'][IACL::PE_GROUP])) { foreach ($def['rules'][IACL::PE_GROUP] as $gid => $rule) { if (!isset($groups[$gid])) { continue; } $cur[] = array(str_replace('_', ' ', $groups[$gid]->page_title), $rule['actions']); } } foreach ($cur as $child) { foreach (IACL::$actionToName as $i => $a) { if ($child[1] & ($i | $i << IACL::INDIRECT_OFFSET)) { $rules[$name][$child[0]][$a] = true; } } } } else { // Select user and group members for groups if (isset($def['rules'][IACL::PE_ALL_USERS])) { $rule = $def['rules'][IACL::PE_ALL_USERS]; $rule = reset($rule); if ($rule['actions'] & $memberAction) { $members[$name][] = '*'; } } if (isset($def['rules'][IACL::PE_REG_USERS])) { $rule = reset($def['rules'][IACL::PE_REG_USERS]); if ($rule['actions'] & $memberAction) { $members[$name][] = '#'; } } if (isset($def['rules'][IACL::PE_USER])) { foreach ($def['rules'][IACL::PE_USER] as $uid => $rule) { if ($rule['actions'] & $memberAction) { if (!isset($users[$uid])) { continue; } $members[$name][] = 'User:'******'rules'][IACL::PE_GROUP])) { foreach ($g['rules'][IACL::PE_GROUP] as $gid => $right) { if ($right['actions'] & $memberAction) { $members[$name][] = str_replace('_', ' ', $groups[$gid]->page_title); } } sort($members[$name]); } } } return json_encode(array('groups' => $members, 'rights' => $rules)); }
/** * "Real" group list, loaded using AJAX */ static function haclGrouplist($n, $not_n = NULL) { global $wgScript, $haclgHaloScriptPath, $haclgContLang; haclCheckScriptPath(); /* Load data */ $total = 0; $titles = IACLStorage::get('SD')->getSDPages('group', $n, $not_n, NULL, NULL, $total); $groups = array(); $l = strlen($haclgContLang->getPetPrefix(IACL::PE_GROUP)) + 1; foreach ($titles as $t) { $groups[] = array('name' => $t->getText(), 'real' => substr($t->getText(), $l), 'editlink' => $wgScript . '?title=Special:IntraACL&action=group&group=' . urlencode($t->getText()), 'viewlink' => $t->getLocalUrl()); } $max = false; /* Run template */ ob_start(); require dirname(__FILE__) . '/../templates/HACL_GroupListContents.tpl.php'; $html = ob_get_contents(); ob_end_clean(); return $html; }
protected static function checkProtectPageRight($pageID, $userID) { $etc = haclfDisableTitlePatch(); $title = Title::newFromId($pageID); haclfRestoreTitlePatch($etc); return IACLDefinition::userCan($userID, IACL::PE_NAMESPACE, $title->getNamespace(), IACL::ACTION_PROTECT_PAGES) > 0 || IACLDefinition::userCan($userID, IACL::PE_CATEGORY, IACLStorage::get('Util')->getParentCategoryIDs($pageID), IACL::ACTION_PROTECT_PAGES) > 0; }