includes/namespaces/default.php
changeset 953 323c4cd1aa37
parent 935 9e124177c9a4
child 963 b572ce1114f1
--- a/includes/namespaces/default.php	Mon May 04 23:07:00 2009 -0400
+++ b/includes/namespaces/default.php	Tue May 05 00:10:26 2009 -0400
@@ -64,6 +64,42 @@
   public $title = '';
   
   /**
+   * PathManager info array ("cdata") for this page. (The one with urlname, name, namespace, delvotes, delvote_ips, protected, visible, etc.)
+   * @var array
+   */
+  
+  public $cdata = array();
+  
+  /**
+   * ACL calculation instance for this page.
+   * @var object(Session_ACLPageInfo)
+   */
+  
+  public $perms = false;
+  
+  /**
+   * Protection calculation
+   * @var bool
+   */
+  
+  public $page_protected = false;
+  
+  /**
+   * Wiki mode calculation
+   * @var bool
+   */
+  
+  public $wiki_mode = false;
+  
+  /**
+   * Page conditions. These represent the final decision as to whether an action is allowed or not. They are set to true if ACLs permit AND if
+   * the action "makes sense." (e.g., you can't vote to delete a non-wikimode page.)
+   * @var array
+   */
+  
+  public $conds = array();
+  
+  /**
    * Constructor.
    */
   
@@ -75,50 +111,65 @@
     $this->namespace = $namespace;
     $this->revision_id = intval($revision_id);
     
-    // only do this if calling from the (very heavily feature filled) abstract
-    // this will still be called if you're using your own handler but not replacing the constructor
-    if ( __CLASS__ == 'Namespace_Default' )
+    // grab the cdata
+    $this->build_cdata();
+    
+    $this->page_protected = $this->cdata['really_protected'] ? true : false;
+    switch($this->cdata['wiki_mode'])
     {
-      $this->exists = false;
-      // NOTE! These should already be WELL sanitized before we reach this stage.
-      $q = $db->sql_query('SELECT name FROM ' . table_prefix . "pages WHERE urlname = '$this->page_id' AND namespace = '$this->namespace';");
-      if ( !$q )
-        $db->_die();
+      case 0: $this->wiki_mode = false; break;
+      case 1: $this->wiki_mode = true; break;
+      default: case 2: $this->wiki_mode = getConfig('wiki_mode') == 1; break;
+    }
+  }
+  
+  /**
+   * Build the page's cdata.
+   */
+  
+  public function build_cdata()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    static $cdata_cache = array();
+    $pathskey = $paths->get_pathskey($this->page_id, $this->namespace);
+    if ( isset($cdata_cache[$pathskey]) )
+    {
+      $this->cdata = $cdata_cache[$pathskey];
+      $this->exists = $cdata_cache[$pathskey]['page_exists'];
+      $this->title = $cdata_cache[$pathskey]['name'];
+      return null;
+    }
+    
+    $this->exists = false;
+    $ns_char = substr($paths->nslist['Special'], -1);
       
-      if ( $db->numrows() < 1 )
-      {
-        // we still have a chance... some older databases don't do dots in the page title right
-        if ( strstr(dirtify_page_id($this->page_id), '.') )
-        {
-          $page_id = str_replace('.', '.2e', $page_id);
-          
-          $q = $db->sql_query('SELECT name FROM ' . table_prefix . "pages WHERE urlname = '$page_id' AND namespace = '$this->namespace';");
-          if ( !$q )
-            $db->_die();
-          
-          if ( $db->numrows() < 1 )
-          {
-            $this->title = $paths->nslist[$namespace] . dirtify_page_id($page_id);
-          }
-          else
-          {
-            list($this->title) = $db->fetchrow_num();
-            $this->exists = true;
-            $this->page_id = $page_id;
-          }
-        }
-        else
-        {
-          $this->title = $paths->nslist[$namespace] . dirtify_page_id($page_id);
-        }
-      }
-      else
-      {
-        list($this->title) = $db->fetchrow_num();
-        $this->exists = true;
-      }
-      $db->free_result();
+    $page_name = $this->namespace == 'Article' ? dirtify_page_id($this->page_id) : "{$this->namespace}{$ns_char}" . dirtify_page_id($this->page_id);
+    $this->cdata = array(
+      'name' => $page_name,
+      'urlname' => $this->page_id,
+      'namespace' => $this->namespace,
+      'special' => 0,
+      'visible' => 0,
+      'comments_on' => 1,
+      'protected' => 0,
+      'delvotes' => 0,
+      'delvote_ips' => '',
+      'wiki_mode' => 2,
+      'page_exists' => false,
+      'page_format' => getConfig('default_page_format', 'wikitext')
+    );
+    
+    if ( $data_from_db = Namespace_Default::get_cdata_from_db($this->page_id, $this->namespace) )
+    {
+      $this->exists = true;
+      $this->cdata = $data_from_db;
+      $this->cdata['page_exists'] = true;
+      $this->title = $this->cdata['name'];
     }
+        
+    $this->cdata = Namespace_Default::bake_cdata($this->cdata);
+    
+    $cdata_cache[$pathskey] = $this->cdata;
   }
   
   /**
@@ -287,6 +338,8 @@
     
     $text = $this->fetch_text();
     
+    profiler_log("Namespace [$this->namespace, $this->page_id]: pulled text from DB");
+    
     $text = preg_replace('/([\s]*)__NOBREADCRUMBS__([\s]*)/', '', $text);
     $text = preg_replace('/([\s]*)__NOTOC__([\s]*)/', '', $text);
     
@@ -299,8 +352,7 @@
       $oldtarget[0] = sanitize_page_id($oldtarget[0]);
       
       $url = makeUrlNS($oldtarget[1], $oldtarget[0], false, true);
-      $page_id_key = $paths->nslist[ $oldtarget[1] ] . $oldtarget[0];
-      $page_data = $paths->pages[$page_id_key];
+      $page_data = $paths->get_cdata($oldtarget[0], $oldtarget[1]);
       $title = ( isset($page_data['name']) ) ? $page_data['name'] : $paths->nslist[$oldtarget[1]] . htmlspecialchars( str_replace('_', ' ', dirtify_page_id( $oldtarget[0] ) ) );
       if ( !isset($page_data['name']) )
       {
@@ -331,7 +383,6 @@
     
     if ( $send_headers )
     {
-      $template->init_vars($this);
       $output->set_title($this->title);
       $output->header();
     }
@@ -339,7 +390,23 @@
     
     if ( $incl_inner_headers )
     {
-      display_page_headers();
+      if ( !$this->perms )
+        $this->perms = $session->fetch_page_acl($this->page_id, $this->namespace);
+      
+      if ( $this->perms->get_permissions('vote_reset') && $this->cdata['delvotes'] > 0)
+      {
+        $delvote_ips = unserialize($this->cdata['delvote_ips']);
+        $hr = htmlspecialchars(implode(', ', $delvote_ips['u']));
+        
+        $string_id = ( $this->cdata['delvotes'] == 1 ) ? 'delvote_lbl_votes_one' : 'delvote_lbl_votes_plural';
+        $string = $lang->get($string_id, array('num_users' => $this->cdata['delvotes']));
+        
+        echo '<div class="info-box" style="margin-left: 0; margin-top: 5px;" id="mdgDeleteVoteNoticeBox">
+                <b>' . $lang->get('etc_lbl_notice') . '</b> ' . $string . '<br />
+                <b>' . $lang->get('delvote_lbl_users_that_voted') . '</b> ' . $hr . '<br />
+                <a href="'.makeUrl($paths->page, 'do=deletepage').'" onclick="ajaxDeletePage(); return false;">' . $lang->get('delvote_btn_deletepage') . '</a>  |  <a href="'.makeUrl($paths->page, 'do=resetvotes').'" onclick="ajaxResetDelVotes(); return false;">' . $lang->get('delvote_btn_resetvotes') . '</a>
+              </div>';
+      }
     }
     
     if ( $this->revision_id )
@@ -363,8 +430,7 @@
     }
     else
     {
-      $pathskey = $paths->nslist[ $this->namespace ] . $this->page_id;
-      $page_format = $paths->pages[$pathskey]['page_format'];
+      $page_format = $this->cdata['page_format'];
     }
     
     if ( $redir_enabled )
@@ -378,6 +444,8 @@
       eval($cmd);
     }
     
+    $prof_contentevent = profiler_log("Namespace [$this->namespace, $this->page_id]: headers and preprocessing done - about to send content");
+    
     if ( $incl_inner_headers )
     {
       if ( $page_format === 'wikitext' )
@@ -400,6 +468,8 @@
     
     eval ( $text );
     
+    profiler_log("Namespace [$this->namespace, $this->page_id]: content sent", true, $prof_contentevent);
+    
     $code = $plugins->setHook('pageprocess_render_tail');
     foreach ( $code as $cmd )
     {
@@ -411,6 +481,8 @@
       display_page_footers();
     }
     
+    profiler_log("Namespace [$this->namespace, $this->page_id]: sent footers");
+    
     if ( $send_headers )
       $output->footer();
   }
@@ -709,7 +781,7 @@
           $link = makeUrlNS('Category', $cid);
           $list[] = '<a href="' . $link . '">' . htmlspecialchars($title) . '</a>';
         }
-        while ( $row = $db->fetchrow() );
+        while ( $row = $db->fetchrow($q) );
         $html .= implode(', ', $list);
       }
       else
@@ -728,15 +800,189 @@
     }
     return $html;
   }
+  
+  /**
+   * Pull in switches as to whether a specific toolbar button should be used or not. This sets things up according to the current page being displayed.
+   * @return array Associative
+   */
+  
+  function set_conds()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    if ( !$this->perms )
+      $this->perms = $session->fetch_page_acl($this->page_id, $this->namespace);
+    
+    $enforce_protection = ( $this->page_protected && ( ( $session->check_acl_scope('even_when_protected', $this->namespace) && !$this->perms->get_permissions('even_when_protected') ) || !$session->check_acl_scope('even_when_protected', $this->namespace) ) );
+    
+    $conds = array();
+    
+    // Article: always show
+    $conds['article'] = true;
+    
+    // Discussion: Show if comments are enabled on the site, and if comments are on for this page.
+    $conds['comments'] = $this->perms->get_permissions('read') && getConfig('enable_comments', '1')=='1' && $this->cdata['comments_on'] == 1;
+    
+    // Edit: Show if we have permission to edit the page, and if we don't have protection in effect
+    $conds['edit'] = $this->perms->get_permissions('read') && $session->check_acl_scope('edit_page', $this->namespace) && $this->perms->get_permissions('edit_page') && !$enforce_protection;
+    
+    // View source: Show if we have permission to view source and either ACLs prohibit editing or protection is in effect
+    $conds['viewsource'] = $session->check_acl_scope('view_source', $this->namespace) && $this->perms->get_permissions('view_source') && ( !$this->perms->get_permissions('edit_page') || $enforce_protection ) && $this->namespace != 'API';
+    
+    // History: Show if we have permission to see history and if the page exists
+    $conds['history'] = $session->check_acl_scope('history_view', $this->namespace) && $this->exists && $this->perms->get_permissions('history_view');
+    
+    // Rename: Show if the page exists, if we have permission to rename, and if protection isn't in effect
+    $conds['rename'] = $session->check_acl_scope('rename', $this->namespace) && $this->exists && $this->perms->get_permissions('rename') && !$enforce_protection;
+    
+    // Vote-to-delete: Show if we have Wiki Mode on, if we have permission to vote for deletion, and if the page exists (can't vote to delete a nonexistent page)
+    $conds['delvote'] = $this->wiki_mode && $session->check_acl_scope('vote_delete', $this->namespace) && $this->perms->get_permissions('vote_delete') && $this->exists;
+    
+    // Reset votes: Show if we have Wiki Mode on, if we have permission to reset votes, if the page exists, and if there's at least one vote
+    $conds['resetvotes'] = $session->check_acl_scope('vote_reset', $this->namespace) && $this->wiki_mode && $this->exists && $this->perms->get_permissions('vote_reset') && $this->cdata['delvotes'] > 0;
+    
+    // Delete page: Show if the page exists and if we have permission to delete it
+    $conds['delete'] = $session->check_acl_scope('delete_page', $this->namespace) && $this->exists && $this->perms->get_permissions('delete_page');
+    
+    // Printable view: Show if the page exists
+    $conds['printable'] = $this->exists;
+    
+    // Protect: Show if we have Wiki Mode on, if the page exists, and if we have permission to protect the page.
+    $conds['protect'] = $session->check_acl_scope('protect', $this->namespace) && $this->wiki_mode && $this->exists && $this->perms->get_permissions('protect');
+    
+    // Set Wiki Mode: Show if the page exists and if we have permission to set wiki mode
+    $conds['setwikimode'] = $session->check_acl_scope('set_wiki_mode', $this->namespace) && $this->exists && $this->perms->get_permissions('set_wiki_mode');
+    
+    // Clear logs: Show if we have permission to clear logs
+    $conds['clearlogs'] = $session->check_acl_scope('clear_logs', $this->namespace) && $this->perms->get_permissions('clear_logs');
+    
+    // Set password: a little bit complicated. If there's a password, check for password_reset; else, check for password_set.
+    $conds['password'] = empty($this->cdata['password']) ?
+                           $session->check_acl_scope('password_set', $this->namespace) && $this->perms->get_permissions('password_set') :
+                           $session->check_acl_scope('password_reset', $this->namespace) && $this->perms->get_permissions('password_reset');
+    
+    // Edit ACLs: Show if this is a non-Enano page that's calling the Enano API and (a) if we have permissions to edit ACLs or (b) we're an admin AND ACL_ALWAYS_ALLOW_ADMIN_EDIT_ACL is on
+    $conds['acledit'] = $this->namespace != 'API' && $session->check_acl_scope('edit_acl', $this->namespace) && ( $this->perms->get_permissions('edit_acl') || ( defined('ACL_ALWAYS_ALLOW_ADMIN_EDIT_ACL') &&  $session->user_level >= USER_LEVEL_ADMIN ) );
+    
+    // Admin page: Show if the page exists and if we're an admin
+    $conds['adminpage'] = $session->user_level >= USER_LEVEL_ADMIN && $this->exists;
+    
+    // Allow plugins to change stuff
+    $code = $plugins->setHook('page_conds_set');
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    
+    $this->conds = $conds;
+  }
+  
+  /**
+   * Return page conditions
+   * @return array
+   */
+  
+  public function get_conds()
+  {
+    if ( empty($this->conds) )
+      $this->set_conds();
+    
+    return $this->conds;
+  }
+  
   /**
    * Just tell us if the current page exists or not.
    * @return bool
    */
    
-  function exists()
+  public function exists()
   {
     return $this->exists;
   }
+  
+  /**
+   * Return cdata
+   * @return array
+   */
+  
+  public function get_cdata()
+  {
+    return $this->cdata;
+  }
+  
+  /**
+   * Bake, or finalize the processing of, a cdata array.
+   * @static
+   * @access public
+   */
+  
+  public static function bake_cdata($cdata)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    // urlname_nons is the actual page_id.
+    $cdata['urlname_nons'] = $cdata['urlname'];
+    if ( isset($paths->nslist[ $cdata['namespace'] ]) )
+    {
+      $cdata['urlname'] = $paths->nslist[ $cdata['namespace'] ] . $cdata['urlname'];
+    }
+    else
+    {
+      $ns_char = substr($paths->nslist['Special'], -1);
+      $cdata['urlname'] = $cdata['namespace'] . $ns_char . $cdata['urlname'];
+    }
+    
+    // fix up deletion votes
+    if ( empty($cdata['delvotes']) )
+      $cdata['delvotes'] = 0;
+    
+    // calculate wiki mode
+    $cdata['really_wiki_mode'] = ( $cdata['wiki_mode'] == 1 || ( $cdata['wiki_mode'] == 2 && getConfig('wiki_mode', 0) == 1 ) );
+    
+    // calculate protection
+    $cdata['really_protected'] = ( $cdata['protected'] > 0 );
+    if ( $cdata['protected'] == 2 )
+    {
+      $cdata['really_protected'] = !$session->user_logged_in || ( $session->user_logged_in && $session->reg_time + 86400*4 > time() );
+    }
+    
+    return $cdata;
+  }
+  
+  /**
+   * Grabs raw (unbaked) cdata from the database, caching if possible.
+   * @param string Page ID
+   * @param string Namespace.
+   * @static
+   */
+  
+  public static function get_cdata_from_db($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    static $cache = array();
+    
+    $pathskey = $paths->get_pathskey($page_id, $namespace);
+    if ( isset($cache[$pathskey]) )
+      return $cache[$pathskey];
+    
+    $page_id_db = $db->escape($page_id);
+    $namespace_db = $db->escape($namespace);
+    
+    $q = $db->sql_query('SELECT * FROM ' . table_prefix . "pages WHERE urlname = '$page_id_db' AND namespace = '$namespace_db';");
+    if ( !$q )
+      $db->_die();
+    
+    if ( $db->numrows() < 1 )
+    {
+      $db->free_result();
+      $cache[$pathskey] = false;
+      return false;
+    }
+    
+    $row = $db->fetchrow();
+    $cache[$pathskey] = $row;
+    return $row;
+  }
 }
 
 /**
@@ -755,3 +1001,7 @@
 {
 }
 
+class Namespace_Category extends Namespace_Default
+{
+}
+