function getDefs()
 {
     return IACLDefinition::select(array('pe' => $this->pe_ids));
 }
 static function getContentAction()
 {
     global $wgTitle, $haclgContLang, $haclgDisableACLTab, $wgUser;
     if ($wgUser->isAnon()) {
         return NULL;
     }
     if ($wgTitle->getNamespace() == HACL_NS_ACL) {
         // Display the link to article or category
         list($peType, $peName) = IACLDefinition::nameOfPE($wgTitle->getText());
         if ($peType == IACL::PE_PAGE || $peType == IACL::PE_CATEGORY) {
             $title = $peType == IACL::PE_PAGE ? Title::newFromText($peName) : Title::makeTitleSafe(NS_CATEGORY, $peName);
             return array('class' => false, 'text' => wfMsg("hacl_tab_" . IACL::$typeToName[$peType]), 'href' => $title->getLocalUrl());
         }
     } elseif ($wgTitle->exists()) {
         // Display the link to category or page SD
         if ($wgTitle->getNamespace() == NS_CATEGORY) {
             $sd = IACLDefinition::nameOfSD(IACL::PE_CATEGORY, $wgTitle);
         } else {
             $sd = IACLDefinition::nameOfSD(IACL::PE_PAGE, $wgTitle);
         }
         $etc = haclfDisableTitlePatch();
         $sd = Title::newFromText($sd, HACL_NS_ACL);
         haclfRestoreTitlePatch($etc);
         // Hide ACL tab if SD does not exist and $haclgDisableACLTab is true
         if (!$sd || !empty($haclgDisableACLTab) && !$sd->exists() && !$wgUser->getOption('showacltab')) {
             return NULL;
         }
         return array('class' => $sd->exists() ? false : 'new', 'text' => wfMsg('hacl_tab_acl'), 'href' => $sd->getLocalUrl());
     }
     return NULL;
 }
 /**
  * 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);
         }
     }
 }
 /**
  * Retrieve the list of content used in article with page_id=$peID
  * from $linkstable = one of 'imagelinks', 'templatelinks', with following info:
  * - count of pages on which it is used
  * - its SD title
  * - modification timestamp its SD, if one does exist, for conflict detection
  * - is its SD a single inclusion of other SD with ID $sdID?
  *   $sdID usually is SD ID for the page $peID as the protection of embedded
  *   content is usually including page SD.
  * with their security descriptors' modification timestamps (if they exist),
  * and the status of these SDs - are they a single inclusion of $sdID ?
  *
  * This is a very high-level subroutine, for optimisation purposes.
  * This method does not return used content with recursion as it used to
  * determine embedded content of only ONE article.
  *
  * @param int $peID      Page ID to retrieve the list of content used in.
  * @param int $incSDType (optional) SD type to to check if used content SDs are a single inclusion of this SD.
  * @param int $incSDId   (optional) SD ID to check if used content SDs are a single inclusion of this SD.
  * @param $linkstable    'imagelinks' (retrieve used images) or 'templatelinks' (retrieve used templates).
  * @return array(array('title' => , 'sd_revid' => , 'single' => ))
  */
 public function getEmbedded($peID, $incSDType, $incSDId, $linkstable)
 {
     global $haclgContLang;
     $dbr = wfGetDB(DB_SLAVE);
     if ($linkstable == 'imagelinks') {
         $linksjoin = "p1.page_title=il1.il_to AND p1.page_namespace=" . NS_FILE;
         $linksfield = "il_from";
     } elseif ($linkstable == 'templatelinks') {
         $linksjoin = "p1.page_title=il1.tl_title AND p1.page_namespace=il1.tl_namespace";
         $linksfield = "tl_from";
     } else {
         die("Unknown \$linkstable='{$linkstable}' passed to " . __METHOD__);
     }
     $linksjoin2 = str_replace('il1.', 'il2.', $linksjoin);
     $il = $dbr->tableName($linkstable);
     $p = $dbr->tableName('page');
     $rules = $dbr->tableName('intraacl_rules');
     $rev = $dbr->tableName('revision');
     // SQL subquery for single inclusion detection
     $sql_is_single = $incSDType && $incSDId ? "(SELECT 1=SUM(CASE WHEN child_type=" . $incSDType . " AND child_id=" . $incSDId . " AND (actions & " . ((1 << IACL::INDIRECT_OFFSET) - 1) . ") = " . IACL::ACTION_INCLUDE_SD . " THEN 1 WHEN !(actions & " . ((1 << IACL::INDIRECT_OFFSET) - 1) . ") THEN 0 ELSE 2 END) FROM {$rules} r" . " WHERE r.pe_type=" . IACL::PE_PAGE . " AND r.pe_id=p1.page_id)" : "0";
     // Full SQL query
     $sql = "SELECT p1.*," . " {$sql_is_single} sd_inc_single," . " COUNT(il2.{$linksfield}) used_on_pages" . " FROM {$il} il1 INNER JOIN {$p} p1 ON {$linksjoin}" . " LEFT JOIN {$il} il2 ON {$linksjoin2}" . " WHERE il1.{$linksfield}={$peID}" . " GROUP BY p1.page_id" . " ORDER BY p1.page_namespace, p1.page_title";
     $res = $dbr->query($sql, __METHOD__);
     $embedded = array();
     $batch = new LinkBatch();
     foreach ($res as $obj) {
         $title = Title::newFromRow($obj);
         $sd_title = Title::newFromText(IACLDefinition::nameOfSD(IACL::PE_PAGE, $title));
         $batch->addObj($sd_title);
         $embedded[] = array('title' => $title, 'sd_title' => $sd_title, 'sd_revid' => NULL, 'sd_single' => $obj->sd_inc_single, 'used_on_pages' => $obj->used_on_pages);
     }
     $batch->execute();
     foreach ($embedded as &$e) {
         if (!$e['sd_title']->exists()) {
             $e['sd_title'] = NULL;
         } else {
             // Add SD modification timestamp
             $e['sd_revid'] = $e['sd_title']->getLatestRevID();
         }
     }
     return $embedded;
 }
function haclSDExists_GetEmbedded($type, $name)
{
    if (!isset(IACL::$nameToType[$type])) {
        return 'null';
    }
    $type = IACL::$nameToType[$type];
    $data = array('exists' => false, 'embedded' => '', 'canon' => false);
    $sd = IACLDefinition::newFromName($type, $name);
    if ($sd) {
        $data['canon'] = $sd['def_title']->getPrefixedText();
        if ($sd['rules']) {
            // FIXME Maybe check page for existence instead of SD rules?
            $data['exists'] = true;
        }
        if ($type == IACL::PE_PAGE) {
            // Build HTML code for embedded protection toolbar
            $data['embedded'] = IACLToolbar::getEmbeddedHtml(Title::newFromText($name)->getArticleId(), $sd['pe_type'], $sd['pe_id']);
        }
    }
    return json_encode($data);
}
 /**
  * "Real" ACL list, loaded using AJAX
  */
 static function haclAcllist($t, $n, $offset = 0, $limit = 10)
 {
     global $wgScript, $wgTitle, $haclgHaloScriptPath, $haclgContLang, $wgUser;
     haclCheckScriptPath();
     // Load data
     $spec = SpecialPage::getTitleFor('IntraACL');
     $titles = IACLStorage::get('SD')->getSDPages($t, $n, NULL, $offset, $limit, $total);
     $defs = IACLDefinition::newFromTitles($titles);
     // Build SD data for template
     $lists = array();
     foreach ($titles as $k => $sd) {
         $d = array('name' => $sd->getText(), 'real' => $sd->getText(), 'editlink' => $spec->getLocalUrl(array('action' => 'acl', 'sd' => $sd->getText())), 'viewlink' => $sd->getLocalUrl(), 'single' => NULL);
         $pe = IACLDefinition::nameOfPE($sd);
         $d['type'] = IACL::$typeToName[$pe[0]];
         $d['real'] = $pe[1];
         // Single SD inclusion
         if (isset($defs[$k]) && !empty($defs[$k]['single_child'])) {
             $s = $defs[$k]['single_child'];
             $name = IACLDefinition::peNameForID($s[0], $s[1]);
             $d['single'] = Title::newFromText(IACLDefinition::nameOfSD($s[0], $name));
             $d['singletype'] = IACL::$typeToName[$s[0]];
             $d['singlename'] = $name;
             $d['singlelink'] = $d['single']->getLocalUrl();
             $d['singletip'] = wfMsg('hacl_acllist_hint_single', $d['real'], $d['single']->getPrefixedText());
         }
         $lists[$d['type']][] = $d;
     }
     // Next and previous page links
     $pageurl = Title::makeTitleSafe(NS_SPECIAL, 'IntraACL')->getLocalUrl(array('types' => $t, 'filter' => $n, 'limit' => $limit));
     $nextpage = $prevpage = false;
     if ($total > $limit + $offset) {
         $nextpage = $pageurl . '&offset=' . intval($offset + $limit);
     }
     if ($offset >= $limit) {
         $prevpage = $pageurl . '&offset=' . intval($offset - $limit);
     }
     // Run template
     ob_start();
     require dirname(__FILE__) . '/../templates/HACL_ACLListContents.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;
 }