<?php
/**
* Display a module for user management.
*
* This action allows admins to display information on registered users.
* Users can be searched, paged, filtered. User-related statistics are given,
* showing the number of commented, created and modified pages. A feedback
* handler allows admins to send an email to single users. If the current user
* is not an administrator, then the lastuser action is displayed instead.
*
* @package Actions
* @name Useradmin
*
* @author {@link http://wikka.jsnx.com/DarTar Dario Taraborelli}
* @version 0.5
* @since Wikka 1.1.X.X
*
* @input integer $colcolor optional: enables color for statistics columns
* 1: enables colored columns;
* 0: disables colored columns;
* default: 1;
* @input integer $rowcolor optional: enables alternate row colors
* 1: enables colored rows;
* 0: disables colored rows;
* default: 1;
*
* @output A list of users registered on the current server.
*
* @todo
* - mass-operations;
* - deleting/banning users;
* - integrate with other admin modules.
*/
//utilities
/**
* Build an array of numbers consisting of 'ranges' with increasing step size in each 'range'.
*
* A list of numbers like this is useful for instance for a dropdown to choose
* a period expressed in number of days: a difference between 2 and 5 days may
* be significant while that between 92 and 95 may not be.
*
* @author {@link http://wikka.jsnx.com/JavaWoman JavaWoman}
* @copyright Copyright (c) 2005, Marjolein Katsma
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
* @version 1.0
*
* @param mixed $limits required: single integer or array of integers;
* defines the upper limits of the ranges as well as the next step size
* @param int $max required: upper limit for the whole list
* (will be included if smaller than the largest limit)
* @param int $firstinc optional: increment for the first range; default 1
* @return array resulting list of numbers
*/
// utilities
function optionRanges($limits, $max, $firstinc = 1)
{
// initializations
if ($firstinc < 1) $firstinc = 1;
$inc = $firstinc;
// first element is the first increment
$opts[] = $inc;
// each $limit is the upper limit of a 'range'
foreach ($limits as $limit)
{
for ($i = $inc + $inc; $i <= $limit && $i < $max; $i += $inc)
{
$opts[] = $i;
}
// we quit at $max, even if there are more $limit elements
if ($limit >= $max)
{
// add $max to the list; then break out of the loop
$opts[] = $max;
break;
}
// when $limit is reached, it becomes the new start and increment for the next 'range'
$inc = $limit;
}
return $opts;
}
// restrict access to admins
if ($this->IsAdmin($this->GetUser())) {
// -------------------------------------
// set default values as constants
define('DEFAULT_RECORDS_LIMIT',
'10');
# number of records per page
define('DEFAULT_MIN_RECORDS_DISPLAY',
'5');
# min number of records
define('DEFAULT_RECORDS_RANGE',
serialize(array('10',
'50',
'100',
'500',
'1000')));
#range array for records pager
define('DEFAULT_SORT_FIELD',
'signuptime');
# sort field
define('DEFAULT_SORT_ORDER',
'desc');
# sort order, ascendant or descendant
define('DEFAULT_START',
'0');
# start record
define('DEFAULT_SEARCH',
'');
# keyword to restrict search
define('ALTERNATE_ROW_COLOR',
'1');
# switch alternate row color
define('STAT_COLUMN_COLOR',
'1');
# switch color for statistics columns
// -------------------------------------
// User-interface: icons
define('OWNED_ICON',
'images/icons/16x16/stock_keyring.png');
define('EDITS_ICON',
'images/icons/16x16/text-editor.png');
define('COMMENTS_ICON',
'images/icons/16x16/stock_help-agent.png');
// -------------------------------------
// User-interface: strings
define('PAGE_TITLE',
'User Administration');
define('FORM_LEGEND',
'Filter view:');
define('FORM_SEARCH_STRING_LABEL',
'Search user:');
define('FORM_SEARCH_STRING_TITLE',
'Enter a search string');
define('FORM_SEARCH_SUBMIT',
'Submit');
define('FORM_PAGER_LABEL_BEFORE',
'Show');
define('FORM_PAGER_TITLE',
'Select records-per-page limit');
define('FORM_PAGER_LABEL_AFTER',
'records per page');
define('FORM_PAGER_SUBMIT',
'Apply');
define('FORM_PAGER_LINK',
'Show records from %d to %d');
define('FORM_RESULT_INFO',
'Records');
define('FORM_RESULT_SORTED_BY',
'Sorted by:');
define('TABLE_HEADING_USERNAME',
'User Name');
define('TABLE_HEADING_USERNAME_TITLE',
'Sort by user name');
define('TABLE_HEADING_EMAIL',
'Email');
define('TABLE_HEADING_EMAIL_TITLE',
'Sort by email');
define('TABLE_HEADING_SIGNUPTIME',
'Signup Time');
define('TABLE_HEADING_SIGNUPTIME_TITLE',
'Sort by signup time');
define('TABLE_HEADING_SIGNUPIP',
'Signup IP');
define('TABLE_HEADING_SIGNUPIP_TITLE',
'Sort by signup IP');
define('TABLE_SUMMARY',
'List of users registered on this server');
define('TABLE_HEADING_OWNED_TITLE',
'Owned Pages');
define('TABLE_HEADING_EDITS_TITLE',
'Page Edits');
define('TABLE_HEADING_COMMENTS_TITLE',
'Comments');
define('ACTION_DELETE_LINK_TITLE',
'Remove user %s');
define('ACTION_FEEDBACK_LINK_TITLE',
'Send feedback to user %s');
define('ACTION_DELETE_LINK',
'delete');
define('ACTION_FEEDBACK_LINK',
'feedback');
define('TABLE_CELL_OWNED_TITLE',
'Display pages owned by %s (%d)');
define('TABLE_CELL_EDITS_TITLE',
'Display page edits by %s (%d)');
define('TABLE_CELL_COMMENTS_TITLE',
'Display comments by %s (%d)');
define('SELECT_RECORD_TITLE',
'Select %s');
define('CHECK_ALL_TITLE',
'Check all records');
define('CHECK_ALL',
'Check all');
define('UNCHECK_ALL_TITLE',
'Uncheck all records');
define('UNCHECK_ALL',
'Uncheck all');
define('FORM_MASSACTION_LEGEND',
'Mass-action');
define('FORM_MASSACTION_LABEL',
'With selected');
define('FORM_MASSACTION_SELECT_TITLE',
'Choose action to apply to selected records');
define('FORM_MASSACTION_OPT_DELETE',
'Remove all');
define('FORM_MASSACTION_OPT_FEEDBACK',
'Send feedback to all');
define('FORM_MASSACTION_SUBMIT',
'Submit');
define('ERROR_NO_MATCHES',
'Sorry, there are no users matching "%s"');
//initialize row & column colors variables
$r = 1; #initialize row counter
$r_color = ALTERNATE_ROW_COLOR; #get alternate row color option
$c_color = STAT_COLUMN_COLOR; #get column color option
// record dropdown
// pager
$prev = '';
$next = '';
//override defaults with action parameters
{
foreach ($vars as $param => $value)
{
switch ($param)
{
case 'colcolor':
$c_color =
(preg_match('/[01]/',
$value))?
$value : STAT_COLUMN_COLOR;
break;
case 'rowcolor':
$r_color =
(preg_match('/[01]/',
$value))?
$value : ALTERNATE_ROW_COLOR;
break;
}
}
}
//perform actions if required
if ($_GET['action'] == 'feedback' || $_REQUEST['mail'])
{
echo $this->
Action('userfeedback');
}
elseif ($_GET['action'] == 'owned')
{
echo $this->
Action('userpages');
}
elseif ($_GET['action'] == 'changes')
{
echo $this->
Action('userchanges');
}
elseif ($_GET['action'] == 'comments')
{
echo $this->
Action('usercomments');
}
else
{
// process URL variables
# JW 2005-07-19 some modifications to avoid notices but these are still not actually secure
// number of records per page
$l = $_POST['l'];
elseif (isset($_GET['l']))
$l = $_GET['l'];
else
$l = DEFAULT_RECORDS_LIMIT;
// sort field
$sort =
(isset($_GET['sort'])) ?
$_GET['sort'] : DEFAULT_SORT_FIELD;
// sort order
$d =
(isset($_GET['d'])) ?
$_GET['d'] : DEFAULT_SORT_ORDER;
// start record
$s =
(isset($_GET['s'])) ?
$_GET['s'] : DEFAULT_START;
// search string
$q = $_POST['q'];
elseif (isset($_GET['q']))
$q = $_GET['q'];
else
$q = DEFAULT_SEARCH;
// select all
$checked = '';
if (isset($_GET['selectall']))
{
$checked = (1 == $_GET['selectall']) ? ' checked="checked"' : '';
}
// restrict MySQL query by search string
$where = ('' == $q) ? "1" : "`name` LIKE '%".$q."%'";
// get total number of users
$numusers = $this->getCount('users', $where);
// print page header
echo $this->
Format('==== '.PAGE_TITLE.
' ==== --- ');
// build pager form
$form = $this->FormOpen('','','post','user_admin_panel');
$form .= '<fieldset><legend>'.FORM_LEGEND.'</legend>'."\n";
$form .= '<label for="q">'.FORM_SEARCH_STRING_LABEL.'</label> <input type ="text" id="q" name="q" title="'.FORM_SEARCH_STRING_TITLE.'" size="20" maxlength="50" value="'.$q.'"/> <input type="submit" value="'.FORM_SEARCH_SUBMIT.'" /><br />'."\n";
// ranged drop-down
$users_opts = optionRanges($user_limits,$numusers,DEFAULT_MIN_RECORDS_DISPLAY);
$form .= '<label for="l">'.FORM_PAGER_LABEL_BEFORE.'</label> '."\n";
$form .= '<select name="l" id="l" title="'.FORM_PAGER_TITLE.'">'."\n";
// build drop-down
foreach ($users_opts as $opt) {
$selected = ($opt == $l) ? ' selected="selected"' : '';
$form .= '<option value="'.$opt.'"'.$selected.'>'.$opt.'</option>'."\n";
}
$form .= '</select> <label for="l">'.FORM_PAGER_LABEL_AFTER.'</label> <input type="submit" value="'.FORM_PAGER_SUBMIT.'" /><br />'."\n";
// build pager links
if ($s > 0)
$prev = '<a href="' .$this->Href('','','l='.$l.'&sort='.$sort.'&d='.$d.'&s='.($s-$l)).'&q='.$q.'" title="'.sprintf(FORM_PAGER_LINK, ($s-$l+1), $s).'">'.($s-$l+1).'-'.$s.'</a> | '."\n";
if ($numusers > ($s + $l))
$next = ' | <a href="'.$this->Href('','','l='.$l.'&sort='.$sort.'&d='.$d.'&s='.($s+$l)).'&q='.$q.'" title="'.sprintf(FORM_PAGER_LINK, ($s+$l+1), ($s+2*$l)).'">'.($s+$l+1).'-'.($s+2*$l).'</a>'."\n";
$form .= FORM_RESULT_INFO.' ('.$numusers.'): '.$prev.($s+1).'-'.($s+$l).$next.'<br />'."\n";
$form .= '('.FORM_RESULT_SORTED_BY.'<em>'.$sort.', '.$d.'</em>)'."\n";
$form .= '</fieldset>'.$this->FormClose()."\n";
// print form
// get user list
$userdata = $this->LoadAll("SELECT * FROM ".$this->config["table_prefix"]."users WHERE ".
$where." ORDER BY ".$sort." ".$d." limit ".$s.", ".$l);
if ($userdata) {
// build header links
$nameheader = '<a href="'.$this->Href('','', (($sort == 'name' && $d == 'asc')? 'l='.$l.'&sort=name&d=desc' : 'l='.$l.'&sort=name&d=asc')).'" title="'.TABLE_HEADING_USERNAME_TITLE.'">'.TABLE_HEADING_USERNAME.'</a>';
$emailheader = '<a href="'.$this->Href('','', (($sort == 'email' && $d == 'asc')? 'l='.$l.'&sort=email&d=desc' : 'l='.$l.'&sort=email&d=asc')).'" title="'.TABLE_HEADING_EMAIL_TITLE.'">'.TABLE_HEADING_EMAIL.'</a>';
$timeheader = '<a href="'.$this->Href('','', (($sort == 'signuptime' && $d == 'desc')? 'l='.$l.'&sort=signuptime&d=asc' : 'l='.$l.'')).'" title="'.TABLE_HEADING_SIGNUPTIME_TITLE.'">'.TABLE_HEADING_SIGNUPTIME.'</a>';
/*$ipheader = '<a href="'.$this->Href('','', (($sort == 'ipaddress' && $d == 'desc')? 'l='.$l.'&sort=ipaddress&d=asc' : 'l='.$l.'&sort=ipaddress&d=desc')).'" title="'.TABLE_HEADING_SIGNUPIP_TITLE.'">'.TABLE_HEADING_SIGNUPIP.'</a>'; # installed as beta feature at wikka.jsnx.com */
// build table headers
$htmlout = "<table summary=\"".TABLE_SUMMARY."\" border=\"1px\" id=\"admin_table\">\n<thead>\n".
" <tr>\n".
" <th> </th>\n".
" <th>".$nameheader."</th>\n".
" <th>".$emailheader."</th>\n".
" <th>".$timeheader."</th>\n".
/* " <th>".$ipheader."</th>\n". # installed as beta feature at wikka.jsnx.com */
" <th class=\"number ".(($c_color == 1)? ' c1' : '')."\" title=\"".TABLE_HEADING_OWNED_TITLE."\">;<img src=\"".OWNED_ICON."\" alt=\"O\"/></th>\n".
" <th class=\"number ".(($c_color == 1)? ' c2' : '')."\" title=\"".TABLE_HEADING_EDITS_TITLE."\"><img src=\"".EDITS_ICON."\" alt=\"E\"/></th>\n".
" <th class=\"number ".(($c_color == 1)? ' c3' : '')."\" title=\"".TABLE_HEADING_COMMENTS_TITLE."\"><img src=\"".COMMENTS_ICON."\" alt=\"C\"/></th>\n".
" <th class=\"center\">Actions</th>\n".
" </tr>\n</thead>\n";
// print user table
foreach($userdata as $user) {
// get counts
$where_owned = "`owner` = '".$user['name']."' AND latest = 'Y'";
$where_changes = "`user` = '".$user['name']."'";
$where_comments = "`user` = '".$user['name']."'";
$numowned = $this->getCount('pages', $where_owned);
$numchanges = $this->getCount('pages', $where_changes);
$numcomments = $this->getCount('comments', $where_comments);
// build statistics links if needed
$ownedlink = ($numowned > 0)? '<a title="'.sprintf(TABLE_CELL_OWNED_TITLE,$user['name'],$numowned).'" href="'.$this->Href('','','user='.$user['name'].'&action=owned').'">'.$numowned.'</a>' : '0';
$changeslink = ($numchanges > 0)? '<a title="'.sprintf(TABLE_CELL_EDITS_TITLE,$user['name'],$numchanges).'" href="'.$this->Href('','','user='.$user['name'].'&action=changes').'">'.$numchanges.'</a>' : '0';
$commentslink = ($numcomments > 0)? '<a title="'.sprintf(TABLE_CELL_COMMENTS_TITLE,$user['name'],$numcomments).'" href="'.$this->Href('','','user='.$user['name'].'&action=comments').'">'.$numcomments.'</a>' : '0';
// build handler links
$deleteuser = '<a title="'.sprintf(ACTION_DELETE_LINK_TITLE, $user['name']).'" href="'.$this->Href('','','user='.$user['name'].'&action=delete').'">'.ACTION_DELETE_LINK.'</a>';
$feedbackuser = '<a title="'.sprintf(ACTION_FEEDBACK_LINK_TITLE, $user['name']).'" href="'.$this->Href('','','user='.$user['name'].'&action=feedback').'">'.ACTION_FEEDBACK_LINK.'</a>';
// build table body
$htmlout .= "<tbody>\n";
if ($r_color == 1) {
$htmlout .= "<tr ".(($r%2)? '' : 'class="alt"').">\n"; #enable alternate row color
} else {
$htmlout .= "<tr>\n"; #disable alternate row color
}
$htmlout .= " <td><input type=\"checkbox\" id=\"".$user['id']."\"".$checked." title=\"".sprintf(SELECT_RECORD_TITLE,$user['name'])."\"/></td>\n".
" <td>".(($this->ExistsPage($user['name']))? $this->Link($user['name']) : $user['name'])."</td>\n". #check if userpage exists
" <td>".$user['email']."</td>\n".
" <td class=\"time\">".$user['signuptime']."</td>\n".
/* " <td>".$user['ipaddress']."</td>\n". # installed as beta feature at wikka.jsnx.com */
" <td class=\"number".(($c_color == 1)? ' c1' : '')."\">".$ownedlink."</td>\n". #set column color
" <td class=\"number".(($c_color == 1)? ' c2' : '')."\">".$changeslink."</td>\n". #set column color
" <td class=\"number".(($c_color == 1)? ' c3' : '')."\">".$commentslink."</td>\n". #set column color
" <td class=\"center\">".$deleteuser." :: ".$feedbackuser."</td>\n";
$htmlout .= " </tr>\n</tbody>\n";
//increase row counter ----- alternate row colors
if ($r_color == 1) $r++;
}
$htmlout .= "</table>\n";
// print the table
echo $this->
FormOpen('',
'',
'get');
// multiple-user operations (forthcoming) JW 2005-07-19 accesskey removed (causes more problems than it solves)
echo '<fieldset><legend>'.FORM_MASSACTION_LEGEND.
'</legend>';
echo '[<a href="'.
$this->
Href('',
'',
'l='.
$l.
'&sort='.
$sort.
'&d='.
$d.
'&s='.
$s.
'&q='.
$q.
'&selectall=1').
'" title="'.CHECK_ALL_TITLE.
'">'.CHECK_ALL.
'</a> | <a href="'.
$this->
Href('',
'',
'l='.
$l.
'&sort='.
$sort.
'&d='.
$d.
'&s='.
$s.
'&q='.
$q.
'&selectall=0').
'" title="'.UNCHECK_ALL_TITLE.
'">'.UNCHECK_ALL.
'</a>]<br />';
echo '<label for="action" >'.FORM_MASSACTION_LABEL.
'</label> <select title="'.FORM_MASSACTION_SELECT_TITLE.
'" id="action" name="action">';
echo '<option value="" selected="selected">---</option>';
echo '<option value="massdelete">'.FORM_MASSACTION_OPT_DELETE.
'</option>';
echo '<option value="massfeedback">'.FORM_MASSACTION_OPT_FEEDBACK.
'</option>';
echo '</select> <input type="submit" value="'.FORM_MASSACTION_SUBMIT.
'" />';
}
else
{
// no records matching the search string: print error message
echo '<p><span class="error">'.sprintf
(ERROR_NO_MATCHES,
$q).
'</span></p>';
}
}
} else {
// user is not admin
echo $this->
Action('lastusers');
}
?>