plugins/admin/PageManager.php
author Dan
Sun, 04 May 2008 21:57:48 -0400
changeset 541 acb7e23b6ffa
parent 536 218a627eb53e
child 635 b3a33b661681
permissions -rw-r--r--
Massive commit with various changes. Added user ranks system (no admin interface yet) and ability for users to have custom user titles. Made cron framework accept fractions of hours through floating-point intervals. Modifed ACL editor to use miniPrompt framework for close confirmation box. Made avatar system use a special page as opposed to fetching the files directly for caching reasons.

<?php

/*
 * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
 * Version 1.1.4 (Caoineag alpha 4)
 * Copyright (C) 2006-2008 Dan Fuhry
 *
 * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
 */

// Page management smart form

function page_Admin_PageManager()
{
  global $db, $session, $paths, $template, $plugins; // Common objects
  global $lang;
  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
  {
    $login_link = makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true);
    echo '<h3>' . $lang->get('adm_err_not_auth_title') . '</h3>';
    echo '<p>' . $lang->get('adm_err_not_auth_body', array( 'login_link' => $login_link )) . '</p>';
    return;
  }
  
  echo '<h3>' . $lang->get('acppm_heading_main') . '</h3>';
  $show_select = true;
  
  if ( isset($_REQUEST['action']) || isset($_REQUEST['source']) )
  {
    if ( isset($_REQUEST['action']) )
    {
      $act =& $_REQUEST['action'];
      $act = strtolower($act);
    }
    else if ( isset($_REQUEST['source']) && $_REQUEST['source'] == 'ajax' )
    {
      $act = 'select';
    }
    switch ( $act )
    {
      case 'save':
      case 'select':
        // First step is to determine the page ID and namespace
        
        if ( isset($_REQUEST['pid_search']) )
        {
          list($page_id, $namespace) = RenderMan::strToPageID($_REQUEST['page_id']);
          $name = $db->escape(dirtify_page_id($page_id));
          $page_id = $db->escape(sanitize_page_id($page_id));
          $namespace = $db->escape($namespace);
          $name = strtolower($name);
          $page_id = strtolower($page_id);
          $sql = "SELECT * FROM " . table_prefix . "pages WHERE ( " . ENANO_SQLFUNC_LOWERCASE . "(urlname) LIKE '%$page_id%' OR " . ENANO_SQLFUNC_LOWERCASE . "(name) LIKE '%$name%' ) ORDER BY name ASC;";
        }
        else
        {
          // pid_search was not set, assume absolute page ID
          list($page_id, $namespace) = RenderMan::strToPageID($_REQUEST['page_id']);
          $page_id = $db->escape(sanitize_page_id($page_id));
          $namespace = $db->escape($namespace);
          
          $sql = "SELECT * FROM " . table_prefix . "pages WHERE urlname = '$page_id' AND namespace = '$namespace';";
        }
        
        if ( !($q = $db->sql_query($sql)) )
        {
          $db->_die('PageManager selecting dataset for page');
        }
        
        if ( $db->numrows() < 1 )
        {
          echo '<div class="error-box">
                  ' . $lang->get('acppm_err_page_not_found') . '
                </div>';
          break;
        }
        
        if ( $db->numrows() > 1 )
        {
          // Ambiguous results
          if ( isset($_REQUEST['pid_search']) )
          {
            echo '<h3>' . $lang->get('acppm_msg_results_ambiguous_title') . '</h3>';
            echo '<p>' . $lang->get('acppm_msg_results_ambiguous_body') . '</p>';
            echo '<ul>';
            while ( $row = $db->fetchrow($q) )
            {
              echo '<li>';
              $pathskey = $paths->nslist[$row['namespace']] . $row['urlname'];
              $edit_url = makeUrlNS('Special', 'Administration', "module={$paths->nslist['Admin']}PageManager&action=select&page_id=$pathskey", true);
              $view_url = makeUrlNS($row['namespace'], $row['urlname']);
              $page_name = htmlspecialchars(get_page_title_ns( $row['urlname'], $row['namespace'] ));
              $view_link = $lang->get('acppm_ambig_btn_viewpage');
              echo "<a href=\"$edit_url\">$page_name</a> (<a onclick=\"window.open(this.href); return false;\" href=\"$view_url\">$view_link</a>)";
              echo '</li>';
            }
            echo '</ul>';
            $show_select = false;
            break;
          }
          else
          {
            echo '<p>' . $lang->get('acppm_err_ambig_absolute') . '</p>';
            break;
          }
        }
        
        // From this point on we can assume that exactly one matching page was found.
        $dataset = $db->fetchrow();
        $page_id = $dataset['urlname'];
        $namespace = $dataset['namespace'];
        
        // This is used to re-determine the page ID after submit.
        $pathskey = $paths->nslist[$namespace] . sanitize_page_id($page_id);
        
        // The extra switch allows us to break out of the save routine if needed
        switch ( $act )
        {
          case 'save':
            
            $errors = array();
            $page_id_changed = false;
            $namespace_changed = false;
            
            // Backup the dataset to avoid redundantly updating values
            $dataset_backup = $dataset;
            
            // We've elected to save the page. The angle of attack here is to validate each form field,
            // and if the field validates successfully, change the value in $dataset accordingly.
            
            // Field: page name
            $page_name = $_POST['page_name'];
            $page_name = trim($page_name);
            if ( empty($page_name) )
            {
              $errors[] = $lang->get('acppm_err_invalid_page_name');
            }
            else
            {
              $dataset['name'] = $page_name;
            }
            
            // Field: page URL string
            $page_urlname = $_POST['page_urlname'];
            $page_urlname = trim($_POST['page_urlname']);
            if ( empty($page_urlname) && getConfig('main_page') !== '' )
            {
              $errors[] = $lang->get('acppm_err_invalid_url_string');
            }
            else
            {
              $page_id_changed = ( $_POST['page_urlname'] !== $dataset['urlname'] );
              $dataset['urlname'] = sanitize_page_id($page_urlname);
            }
            
            // Field: namespace
            $namespace = $_POST['page_namespace'];
            if ( !isset($paths->nslist[ $namespace ]) )
            {
              $errors[] = $lang->get('acppm_err_invalid_namespace');
            }
            else
            {
              $namespace_changed = ( $_POST['page_namespace'] !== $dataset['namespace'] );
              $dataset['namespace'] = $namespace;
            }
            
            // Field: comments enabled
            $dataset['comments_on'] = ( isset($_POST['comments_on']) ) ? 1 : 0;
            
            // Field: page visible
            $dataset['visible'] = ( isset($_POST['visible']) ) ? 1 : 0;
            
            // Field: standalone page
            $dataset['special'] = ( isset($_POST['special']) ) ? 1 : 0;
            
            // Field: page protection
            $protect_level = $_POST['protected'];
            if ( !in_array($protect_level, array('0', '1', '2')) )
            {
              $errors[] = $lang->get('acppm_err_invalid_protection');
            }
            else
            {
              $dataset['protected'] = intval($protect_level);
            }
            
            // Field: wiki mode
            $wiki_mode = $_POST['wikimode'];
            if ( !in_array($wiki_mode, array('0', '1', '2')) )
            {
              $errors[] = $lang->get('acppm_err_invalid_wiki_mode');
            }
            else
            {
              $dataset['wiki_mode'] = intval($wiki_mode);
            }
            
            if ( count($errors) < 1 )
            {
              // We're free of errors. Build a SQL query to update the page table.
              $particles = array();
              
              foreach ( $dataset as $key => $value )
              {
                if ( $value === $dataset_backup[$key] || ( is_int($value) && $value === intval($dataset_backup[$key]) ) )
                  continue;
                if ( is_int($value) )
                {
                  $particle = "$key = $value";
                }
                else
                {
                  $value = $db->escape($value);
                  $particle = "$key = '$value'";
                }
                $particles[] = $particle;
                unset($particle);
              }
              
              $page_id_new = $db->escape($dataset['urlname']);
              $namespace_new = $db->escape($dataset['namespace']);
              
              // Only run the update query if at least one field was changed.
              if ( count($particles) > 0 )
              {
                $particles = implode(', ', $particles);
                $page_id_db = $db->escape($page_id);
                $namespace_db = $db->escape($namespace);
                $sql = 'UPDATE ' . table_prefix . "pages SET $particles WHERE urlname = '$page_id_db' AND namespace = '$namespace_db';";
                
                if ( !$db->sql_query($sql) )
                  $db->_die('PageManager running primary update query');
                
                // Did we change the page ID or namespace? If so we need to also change logs, comments, tags, etc.
                if ( $page_id_changed || $namespace_changed )
                {
                  $sql = array(
                      'UPDATE ' . table_prefix . "logs SET page_id = '$page_id_new', namespace = '$namespace_new' WHERE page_id = '$page_id_db' AND namespace = '$namespace_db';",
                      'UPDATE ' . table_prefix . "tags SET page_id = '$page_id_new', namespace = '$namespace_new' WHERE page_id = '$page_id_db' AND namespace = '$namespace_db';",
                      'UPDATE ' . table_prefix . "comments SET page_id = '$page_id_new', namespace = '$namespace_new' WHERE page_id = '$page_id_db' AND namespace = '$namespace_db';",
                      'UPDATE ' . table_prefix . "page_text SET page_id = '$page_id_new', namespace = '$namespace_new' WHERE page_id = '$page_id_db' AND namespace = '$namespace_db';",
                      'UPDATE ' . table_prefix . "categories SET page_id = '$page_id_new', namespace = '$namespace_new' WHERE page_id = '$page_id_db' AND namespace = '$namespace_db';"
                    );
                  foreach ( $sql as $q )
                  {
                    if ( !$db->sql_query($q) )
                      $db->_die('PageManager running slave update query after page ID/namespace change');
                  }
                }
                
                // Did we change the name of the page? If so, make PageUtils log it
                if ( $dataset_backup['name'] != $dataset['name'] )
                {
                  PageUtils::rename($page_id_new, $namespace_new, $dataset['name']);
                }
              }
              
              // Did the user ask to delete the page?
              if ( isset($_POST['delete']) )
              {
                PageUtils::deletepage($page_id_new, $namespace_new, $lang->get('acppm_delete_reason'));
              }
              
              echo '<div class="info-box">' . $lang->get('acppm_msg_save_success', array( 'viewpage_url' => makeUrlNS($dataset['namespace'], $dataset['urlname']) )) . '</div>';
              break 2;
            }
            
            break;
        }
        $tpl_code = <<<TPLCODE
        <div class="tblholder">
          <table border="0" cellspacing="1" cellpadding="4">
            <tr>
              <th colspan="2">
                {lang:acppm_heading_editing} "{PAGE_NAME}"
              </th>
            </tr>
            
            <tr>
              <td class="row2">
                {lang:acppm_lbl_page_name}
              </td>
              <td class="row1">
                <input type="text" name="page_name" value="{PAGE_NAME}" size="40" />
              </td>
            </tr>
            
            <tr>
              <td class="row2">
                {lang:acppm_lbl_page_urlname}<br />
                <small>{lang:acppm_lbl_page_urlname_hint}</small>
              </td>
              <td class="row1">
                <input type="text" name="page_urlname" value="{PAGE_URLNAME}" size="40" />
              </td>
            </tr>
            
            <tr>
              <td class="row2">
                {lang:acppm_lbl_namespace}
              </td>
              <td class="row1">
                <select name="page_namespace">
                {NAMESPACE_LIST}</select>
              </td>
            </tr>
            
            <tr>
              <th colspan="2" class="subhead">
                {lang:acppm_heading_advanced}
              </th>
            </tr>
            
            <tr>
              <td class="row2">
                {lang:acppm_lbl_enable_comments_title}
              </td>
              <td class="row1">
                <label>
                  <input type="checkbox" name="comments_on" <!-- BEGIN comments_enabled -->checked="checked" <!-- END comments_enabled -->/>
                  {lang:acppm_lbl_enable_comments}
                </label>
                <br />
                <small>{lang:acppm_lbl_enable_comments_hint}</small>
              </td>
            </tr>
            
            <tr>
              <td class="row2">
                {lang:acppm_lbl_special_title}
              </td>
              <td class="row1">
                <label>
                  <input type="checkbox" name="special" <!-- BEGIN special -->checked="checked" <!-- END special -->/>
                  {lang:acppm_lbl_special}
                </label>
                <br />
                <small>{lang:acppm_lbl_special_hint}</small>
              </td>
            </tr>
            
            <tr>
              <td class="row2">
                {lang:acppm_lbl_visible_title}
              </td>
              <td class="row1">
                <label>
                  <input type="checkbox" name="visible" <!-- BEGIN visible -->checked="checked" <!-- END visible -->/>
                  {lang:acppm_lbl_visible}
                </label>
                <br />
                <small>{lang:acppm_lbl_visible_hint}</small>
              </td>
            </tr>
            
            <tr>
              <td class="row2">
                {lang:acppm_lbl_protected_title}
              </td>
              <td class="row1">
                <label>
                  <input type="radio" name="protected" value="0" <!-- BEGIN protected_off -->checked="checked" <!-- END protected_off -->/>
                  {lang:acppm_lbl_protected_off}
                </label>
                <br />
                <label>
                  <input type="radio" name="protected" value="1" <!-- BEGIN protected_on -->checked="checked" <!-- END protected_on -->/>
                  {lang:acppm_lbl_protected_on}
                </label>
                <br />
                <label>
                  <input type="radio" name="protected" value="2" <!-- BEGIN protected_semi -->checked="checked" <!-- END protected_semi -->/>
                  {lang:acppm_lbl_protected_semi}
                </label>
                <br />
                <small>{lang:acppm_lbl_protected_hint}</small>
              </td>
            </tr>
            
            <tr>
              <td class="row2">
                {lang:acppm_lbl_wikimode_title}
              </td>
              <td class="row1">
                <label>
                  <input type="radio" name="wikimode" value="0" <!-- BEGIN wikimode_off -->checked="checked" <!-- END wikimode_off -->/>
                  {lang:acppm_lbl_wikimode_off}
                </label>
                <br />
                <label>
                  <input type="radio" name="wikimode" value="1" <!-- BEGIN wikimode_on -->checked="checked" <!-- END wikimode_on -->/>
                  {lang:acppm_lbl_wikimode_on}
                </label>
                <br />
                <label>
                  <input type="radio" name="wikimode" value="2" <!-- BEGIN wikimode_global -->checked="checked" <!-- END wikimode_global -->/>
                  {lang:acppm_lbl_wikimode_global}
                </label>
                <br />
                <small>{lang:acppm_lbl_wikimode_hint}</small>
              </td>
            </tr>
            
            <tr>
              <td class="row2">
                {lang:acppm_lbl_delete_title}
              </td>
              <td class="row1">
                <label>
                  <input type="checkbox" name="delete" />
                  {lang:acppm_lbl_delete}
                </label>
                <br />
                <small>{lang:acppm_lbl_delete_hint}</small>
              </td>
            </tr>
            
            <tr>
              <th colspan="2" class="subhead">
                <button name="action" value="save">
                  <b>{lang:etc_save_changes}</b>
                </button>
                <button name="action" value="nil">
                  <b>{lang:etc_cancel}</b>
                </button>
              </th>
            </tr>
            
          </table>
        </div>
        
        <input type="hidden" name="page_id" value="{PATHS_KEY}" />
TPLCODE;
        $parser = $template->makeParserText($tpl_code);
        
        $ns_list = '';
        foreach ( $paths->nslist as $ns => $prefix ) 
        {
          // FIXME: Plugins need to specify whether they want Enano's regular PageProcessor
          // to handle these pages, and whether such pages from namespaces created by plugins
          // can be stored in the database or not.
          if ( $ns == 'Special' || $ns == 'Admin' || $ns == 'Anonymous' )
            continue;
          $ns = htmlspecialchars($ns);
          $prefix = htmlspecialchars($prefix);
          if ( empty($prefix) )
            $prefix = $lang->get('acppm_ns_article');
          $sel = ( $dataset['namespace'] == $ns ) ? ' selected="selected"' : '';
          $ns_list .= "  <option value=\"$ns\"$sel>$prefix</option>\n                ";
        }
        
        $parser->assign_vars(array(
            'PAGE_NAME' => htmlspecialchars($dataset['name']),
            'PAGE_URLNAME' => htmlspecialchars($dataset['urlname']),
            'NAMESPACE_LIST' => $ns_list,
            'PATHS_KEY' => $pathskey
          ));
        
        $parser->assign_bool(array(
            'comments_enabled' => ( $dataset['comments_on'] == 1 ),
            'special' => ( $dataset['special'] == 1 ),
            'visible' => ( $dataset['visible'] == 1 ),
            'protected_off'   => ( $dataset['protected'] == 0 ),
            'protected_on'    => ( $dataset['protected'] == 1 ),
            'protected_semi'  => ( $dataset['protected'] == 2 ),
            'wikimode_off'    => ( $dataset['wiki_mode'] == 0 ),
            'wikimode_on'     => ( $dataset['wiki_mode'] == 1 ),
            'wikimode_global' => ( $dataset['wiki_mode'] == 2 )
          ));
        
        if ( isset($errors) )
        {
          echo '<div class="error-box">';
          echo $lang->get('acppm_err_header');
          echo '<ul>';
          echo '<li>' . implode('</li><li>', $errors) . '</li>';
          echo '</ul>';
          echo '</div>';
        }
        
        $form_action = makeUrlNS('Special', 'Administration', "module={$paths->nslist['Admin']}PageManager", true);
        
        echo "<form action=\"$form_action\" method=\"post\">";
        echo $parser->run();
        echo "</form>";
        
        $show_select = false;
        break;
    }
  }
  
  if ( $show_select )
  {
    echo '<p>' . $lang->get('acppm_hint') . '</p>';
    
    // Show the search form
    
    $form_action = makeUrlNS('Special', 'Administration', "module={$paths->nslist['Admin']}PageManager", true);
    echo "<form action=\"$form_action\" method=\"post\">";
    echo $lang->get('acppm_lbl_field_search') . ' ';
    echo $template->pagename_field('page_id') . ' ';
    echo '<input type="hidden" name="action" value="select" />';
    echo '<input type="submit" name="pid_search" value="' . $lang->get('search_btn_search') . '" />';
    echo "</form>";
    
    // Grab all pages from the database and show a list of pages on the site
    
    echo '<h3>' . $lang->get('acppm_heading_select_page_from_list') . '</h3>';
    echo '<p>' . $lang->get('acppm_hint_select_page_from_list') . '</p>';
    
    $q = $db->sql_query('SELECT COUNT(name) AS num_pages FROM ' . table_prefix . 'pages;');
    if ( !$q )
      $db->_die('PageManager doing initial page count');
    list($num_pages) = $db->fetchrow_num();
    $db->free_result();
    
    $pg_start = ( isset($_GET['offset']) ) ? intval($_GET['offset']) : 0;
    
    $q = $db->sql_unbuffered_query('SELECT urlname, name, namespace, ' . $num_pages . ' AS num_pages, ' . $pg_start . ' AS offset FROM ' . table_prefix . 'pages ORDER BY name ASC;');
    if ( !$q )
      $db->_die('PageManager doing main select query for page list');
    
    // Paginate results
    $html = paginate(
        $q,
        '{urlname}',
        $num_pages,
        makeUrlNS('Special', 'Administration', "module={$paths->nslist['Admin']}PageManager&offset=%s", false),
        $pg_start,
        99,
        array('urlname' => 'admin_pagemanager_format_listing'),
        '<div class="tblholder" style="height: 300px; clip: rect(0px, auto, auto, 0px); overflow: auto;">
        <table border="0" cellspacing="1" cellpadding="4">',
        '  </table>
         </div>'
      );
    echo $html;
  }
  
}

function admin_pagemanager_format_listing($_, $row)
{
  global $db, $session, $paths, $template, $plugins; // Common objects
  
  static $cell_count = 0;
  static $td_class = 'row1';
  static $run_count = 0;
  static $num_pages_floor = false;
  if ( !$num_pages_floor )
  {
    $num_pages_floor = $row['num_pages'];
    while ( $num_pages_floor % 99 > 0 )
      $num_pages_floor--;
  }
  $return = '';
  $run_count++;
  
  $last_page = ( $row['offset'] == $num_pages_floor );
  $last_run = ( ( $last_page && $run_count == $row['num_pages'] % 99 ) || $run_count == 99 );
  if ( $cell_count == 0 )
  {
    $return .= "<tr>\n";
  }
  $title = get_page_title_ns($row['urlname'], $row['namespace']);
  $pathskey = $paths->nslist[$row['namespace']] . $row['urlname'];
  if ( isset($row['mode']) && $row['mode'] == 'edit' )
  {
    $url = makeUrlNS($row['namespace'], $row['urlname'], false, true) . '#do:edit';
  }
  else
  {
    $url = makeUrlNS('Special', 'Administration', "module={$paths->nslist['Admin']}PageManager&action=select&page_id=$pathskey", true);
  }
  $url = '<a href="' . $url . '">' . htmlspecialchars($title) . '</a>';
  $return .= '  <td class="' . $td_class . '" style="width: 33%;">' . $url . '</td>' . "\n";
  $cell_count++;
  if ( $cell_count == 3 && !$last_run )
  {
    $cell_count = 0;
    $td_class = ( $td_class == 'row2' ) ? 'row1' : 'row2';
    $return .= "</tr>\n";
  }
  else if ( $last_run )
  {
    while ( $cell_count < 3 )
    {
      $return .= "  <td class=\"{$td_class}\"></td>\n";
      $cell_count++;
    }
    $return .= "</tr>\n";
  }
  return $return;
}

?>