requireLogin();
App::sslOn();
require_once 'codebase/lib/PageNumbers.inc.php';
require_once 'codebase/lib/SessionCache.inc.php';
require_once 'codebase/lib/FormValidator.inc.php';
require_once 'codebase/lib/SortOrder.inc.php';
require_once 'codebase/lib/TemplateGlue.inc.php';
require_once 'codebase/lib/Prefs.inc.php';
require_once 'codebase/lib/RecordLock.inc.php';
require_once 'codebase/lib/RecordVersion.inc.php';
/******************************************************************************
 * CODE CONFIG
 *****************************************************************************/
 
// Titles and navigation header.
$nav->addPage(_("Administrators"), $_SERVER['PHP_SELF']);
    
// The object to validate form input.
$fv = new FormValidator();
// Instantiate a sorting object with the default sort and order. Add SQL for each column.
$so = new SortOrder('admin_id', 'DESC');
$so->setColumn('admin_id', 'admin_id ASC', 'admin_id DESC');
$so->setColumn('username', 'username ASC', 'username DESC');
$so->setColumn('userpass', 'userpass ASC', 'userpass DESC');
$so->setColumn('first_name', 'first_name ASC', 'first_name DESC');
$so->setColumn('last_name', 'last_name ASC', 'last_name DESC');
$so->setColumn('phone', 'phone ASC', 'phone DESC');
$so->setColumn('email', 'email ASC', 'email DESC');
$so->setColumn('priv', 'priv ASC', 'priv DESC');
$so->setColumn('seconds_online', 'seconds_online ASC', 'seconds_online DESC');
$so->setColumn('added_datetime', 'added_datetime ASC', 'added_datetime DESC');
$so->setColumn('last_login_datetime', 'last_login_datetime ASC', 'last_login_datetime DESC');
$so->setColumn('last_access_datetime', 'last_access_datetime ASC', 'last_access_datetime DESC');
$so->setColumn('last_login_ip', 'last_login_ip ASC', 'last_login_ip DESC');
// Instantiate page numbers. Total items are set and calculation is done in the getRecordList function.
$page = new PageNumbers();
$page->setPerPage(getFormData('per_page'), 50);
$page->setPageNumber(getFormData('page_number'));
/******************************************************************************
 * MAIN
 *****************************************************************************/
 
// We may want to use the add/edit interface from another script, so this
// allows us to remember which page we came from so we can go back there.
if (getFormData('boomerang', false)) {
    App::setBoomerangURL($_SERVER['HTTP_REFERER'], 'admins');
}
if (getFormData('break_list_cache', false)) {
    // Break the cache because we are changing the list data.
    SessionCache::breakCache($_SERVER['PHP_SELF']);
}
// What action to take.
switch (getFormData('op')) {
case 'add' :
    // Initialize variables for the form template.
    $frm =& addRecordForm();
    $nav->addPage(_("Add Admin"));
    $main_template = 'admin_form.ihtml';
    break;
case 'edit' :
    // Initialize variables for the form template.
    $frm =& editRecordForm(getFormData('admin_id'));
    $nav->addPage(_("Edit Admin"));
    $main_template = 'admin_form.ihtml';
    break;
case 'del' :
    deleteRecord(getFormData('admin_id'));
    if (App::validBoomerangURL('admins')) {
        // Display boomerang page.
        App::dieBoomerangURL('admins');
    }
    // Display default page.
    App::dieURL($_SERVER['PHP_SELF']);
    break;
case 'insert' :
    if (getFormdata('cancel', false)) {
        App::dieURL($_SERVER['PHP_SELF']);
    }
    validateInput();
    if ($fv->anyErrors()) {
        $frm =& addRecordForm();
        $frm = array_merge($frm, getFormData());
        $nav->addPage(_("Add Admin"));
        $main_template = 'admin_form.ihtml';
    } else {
        $admin_id = insertRecord(getFormData());
        if (getFormdata('repeat', false)) {
            // Display function again.
            App::dieURL($_SERVER['PHP_SELF'] . '?op=add');
        } else if (App::validBoomerangURL('admins')) {
            // Display boomerang page.
            App::dieBoomerangURL('admins');
        }
        // Display default page.
        App::dieURL($_SERVER['PHP_SELF']);
    }
    break;
case 'update' :
    if (getFormdata('reset', false)) {
        App::raiseMsg(_("Saved values have been reloaded."), MSG_NOTICE, __FILE__, __LINE__);
        App::dieURL($_SERVER['PHP_SELF'] . '?op=edit&admin_id=' . getFormData('admin_id'));
    }
    if (getFormdata('cancel', false)) {
        // Remove lock
        $lock =& RecordLock::getInstance($GLOBALS['auth']);
        $lock->select('admin_tbl', 'admin_id', getFormData('admin_id'));
        $lock->remove();
        if (App::validBoomerangURL('admins')) {
            // Display boomerang page.
            App::dieBoomerangURL('admins');
        }
        // Display default page.
        App::dieURL($_SERVER['PHP_SELF']);
    }
    validateInput();
    if ($fv->anyErrors()) {
        $frm =& editRecordForm(getFormData('admin_id'));
        $frm = array_merge($frm, getFormData());
        $nav->addPage(_("Edit Admin"));
        $main_template = 'admin_form.ihtml';
    } else {
        updateRecord(getFormData());
        if (getFormdata('repeat', false)) {
            // Display edit function with next available ID.
            $qid = DB::query("SELECT admin_id FROM admin_tbl WHERE admin_id > '" . addslashes(getFormData('admin_id')) . "' ORDER BY admin_id ASC LIMIT 1");
            if (list($next_id) = mysql_fetch_row($qid)) {
                App::dieURL($_SERVER['PHP_SELF'] . '?op=edit&admin_id=' . $next_id);
            } else {
                App::raiseMsg(_("Cannot edit next, the end of the list was reached"), MSG_NOTICE, __FILE__, __LINE__);
            }
        } else if (App::validBoomerangURL('admins')) {
            // Display boomerang page.
            App::dieBoomerangURL('admins');
        }
        // Display default page.
        App::dieURL($_SERVER['PHP_SELF']);
    }
    break;
default :
    $list =& getRecordList();
    $main_template = 'admin_list.ihtml';
    break;
}
/******************************************************************************
 * TEMPLATE INITIALIZATION
 *****************************************************************************/
include 'header.ihtml';
include 'codebase/services/templates/' . $main_template;
include 'footer.ihtml';
/******************************************************************************
 * FUNCTIONS
 *****************************************************************************/
function validateInput()
{
    global $fv, $auth;
    // If the username was changed during edit, verify.
    if (((getFormData('username') != getFormData('old_username')) && 'update' == getFormData('op'))
    || 'insert' == getFormData('op')) {
        if ($auth->usernameExists(getFormData('username'))) {
            $fv->addError('username', sprintf(_("The username %s already exists. Please choose another."), getFormData('username')));
        }
    }
    // If the username was changed during edit, verify.
    if (getFormData('priv') == 'root' && 'root' != $auth->getVal('priv')) {
        $fv->addError('priv', sprintf(_("You do not have clearance to create a user with root privileges."), null));
    }
    $fv->numericRange('admin_id', -32768, 32767, _("Admin id must be a valid number between -32768 and 32767."));
    $fv->isEmpty('username', _("Username cannot be blank."));
    $fv->stringLength('username', 0, 255, _("Username must contain less than 256 characters."));
    
    $fv->isEmpty('userpass', _("Passwords cannot be blank."));
    $fv->stringLength('userpass', 6, 36, _("Passwords must be between 6 and 36 characters long."));
    
    $fv->stringLength('first_name', 0, 255, _("First name must contain less than 256 characters."));
    
    $fv->stringLength('last_name', 0, 255, _("Last name must contain less than 256 characters."));
    
    $fv->stringLength('phone', 0, 255, _("Phone must contain less than 256 characters."));
    $fv->validatePhone('phone');
    
    $fv->stringLength('email', 0, 255, _("Email must contain less than 256 characters."));
    $fv->validateEmail('email');
    
    $fv->stringLength('county', 0, 255, _("County has an invalid selection."));
    
    $fv->stringLength('priv', 0, 255, _("Priv has an invalid selection."));
}
function &addRecordForm()
{
    // set default values for the reset of the fields.
    $frm['priv'] = 'admin';
    $frm['new_op'] = 'insert';
    $frm['submit_caption'] = _("Add admin");
    $frm['repeat_caption'] = _("Add & repeat");
    $frm['cancel_caption'] = _("Cancel");
    return $frm;
}
function &editRecordForm($id)
{
    $lock =& RecordLock::getInstance($GLOBALS['auth']);
    $lock->select('admin_tbl', 'admin_id', $id);
    if ($lock->isLocked() && !$lock->isMine()) {
        $lock->dieErrorPage();
    } else {
        // Get the information for the form.
        $qid = DB::query("
            SELECT * from admin_tbl
            WHERE admin_id = '" . addslashes($id) . "'
        ");
        if (!$frm = mysql_fetch_assoc($qid)) {
            App::logMsg('Could not find record with admin_id: ' . $id, LOG_WARNING, __FILE__, __LINE__);
            App::raiseMsg(sprintf(_("The requested record %s could not be found"), $id), MSG_ERR, __FILE__, __LINE__);
            App::dieBoomerangURL();
        }
        
        // Lock this record.
        $lock->set('admin_tbl', 'admin_id', $id, $frm['address']);
        
        // Set misc values for the form.
        $frm['old_username'] = $frm['username'];
        $frm['userpass'] = '***************';
        $frm['new_op'] = 'update';
        $frm['submit_caption'] = _("Save changes");
        $frm['repeat_caption'] = _("Save & edit next");
        $frm['reset_caption']  = _("Reset");
        $frm['cancel_caption'] = _("Cancel");
        $frm['admin_id'] = $id;
    
        return $frm;
    }
}
function deleteRecord($id)
{
    global $auth;
    
    $lock =& RecordLock::getInstance($GLOBALS['auth']);
    $lock->select('admin_tbl', 'admin_id', $id);
    if ($lock->isLocked() && !$lock->isMine()) {
        $lock->dieErrorPage();
    } else {
        // Break the cache because we are changing the list data.
        SessionCache::breakCache($_SERVER['PHP_SELF']);
        
        // Get the information for this object.
        $qid = DB::query("
            SELECT username, priv from admin_tbl
            WHERE admin_id = '" . addslashes($id) . "'
        ");
        if (! list($name, $priv) = mysql_fetch_row($qid)) {
            App::logMsg('Could not find record with admin_id: ' . $id, LOG_WARNING, __FILE__, __LINE__);
            App::raiseMsg(sprintf(_("The requested record %s could not be found"), $id), MSG_ERR, __FILE__, __LINE__);
            App::dieBoomerangURL();
        }
        
        // Get the information for this object.
        $qid = DB::query("SELECT COUNT(*) from admin_tbl");
        list($num_admins) = mysql_fetch_row($qid);
        if ('root' == $priv && 'root' != $auth->getVal('priv')) {
            // Only root users can delete root users!
            App::raiseMsg(_("You do not have clearance to delete a root administrator."), MSG_NOTICE, __FILE__, __LINE__);
        } else if ($num_admins <= 1) {
            // There must always be at least one admnistrator!
            App::raiseMsg(_("You cannot delete the only administrator in the database. There must be at least one to log in and create other users."), MSG_NOTICE, __FILE__, __LINE__);
        } else if ($auth->getVal('user_id') == $id) {
            // Do not delete yourself!
            App::raiseMsg(_("You cannot delete yourself."), MSG_NOTICE, __FILE__, __LINE__);
        } else {
            // Delete the record.
            DB::query("DELETE FROM admin_tbl WHERE admin_id = '" . addslashes($id) . "'");
            App::raiseMsg(sprintf(_("The admin %s has been deleted."), $name), MSG_SUCCESS, __FILE__, __LINE__);
        }
        // Unlock record.
        $lock->remove();
    }
}
function insertRecord($frm)
{
    global $auth;
    
    // Break the cache because we are changing the list data.
    SessionCache::breakCache($_SERVER['PHP_SELF']);
    
    // Insert record data.
    DB::query("
        INSERT INTO admin_tbl (
            username,
            first_name,
            last_name,
            phone,
            email,
            priv,
            added_datetime
        ) VALUES (
            '" . addslashes($frm['username']) . "',
            '" . addslashes($frm['first_name']) . "',
            '" . addslashes($frm['last_name']) . "',
            '" . addslashes($frm['phone']) . "',
            '" . addslashes($frm['email']) . "',
            '" . addslashes($frm['priv']) . "',
            NOW()
        )
    ");
    $last_insert_id = mysql_insert_id(DB::getDBH());
    
    // Set admin password.
    $auth->setPassword($last_insert_id, $frm['userpass']);
    
    App::raiseMsg(sprintf(_("The admin %s has been added."), $frm['username']), MSG_SUCCESS, __FILE__, __LINE__);
    
    return $last_insert_id;
}
function updateRecord($frm)
{
    global $auth;
    
    $lock =& RecordLock::getInstance($GLOBALS['auth']);
    $lock->select('admin_tbl', 'admin_id', $frm['admin_id']);
    if ($lock->isLocked() && !$lock->isMine()) {
        $lock->dieErrorPage();
    } else {
        // Break the cache because we are changing the list data.
        SessionCache::breakCache($_SERVER['PHP_SELF']);
        
        // If the userpass is left blank or with the filler **** characters, we don't want to update it.
        if (!empty($frm['userpass']) && !preg_match('/[\*]{4,}/', $frm['userpass'])) {
            // Set user password.
            $auth->setPassword($frm['admin_id'], $frm['userpass']);
        }
        
        // Update record data.
        DB::query("
            UPDATE admin_tbl SET
                username = '" . addslashes($frm['username']) . "',
                first_name = '" . addslashes($frm['first_name']) . "',
                last_name = '" . addslashes($frm['last_name']) . "',
                phone = '" . addslashes($frm['phone']) . "',
                email = '" . addslashes($frm['email']) . "',
                priv = '" . addslashes($frm['priv']) . "'
            WHERE admin_id = '" . addslashes($frm['admin_id']) . "'
        ");
        App::raiseMsg(sprintf(_("The admin %s has been updated."), $frm['username']), MSG_SUCCESS, __FILE__, __LINE__);
        // Unlock record.
        $lock->remove();
    }
}
function &getRecordList()
{
    global $page;
    global $so;
    
    // Build search query if $qry is not empty.
    $sql_delim = 'WHERE';
    $search_where_clause = '';
    $qry = getFormData('search_query');
    if (!empty($qry)) {
        $qry_words = preg_split('/[^\w]/', $qry);
        for ($i=0; $isetTotalItems($num_results);
    $page->calculate();
    
    // Final SQL, with sort and page limiters.
    $sql = "
        SELECT * FROM admin_tbl
        $where_clause
        " . $so->getSortOrderSQL() . "
        " . $page->getLimitSQL() . "
    ";
    
    // A unique key for this query, with the total_items in case db records
    // were added since the last cache. This identifies a unique set of
    // cached data, but we must refer to the list that is cached by a more
    // generic name. so that we can flush the cache (if records updated)
    // without knowing the hash.
    $cache_hash = md5($sql . '|' . $page->total_items);
    if (Prefs::getValue('cache_hash', $_SERVER['PHP_SELF']) != $cache_hash) {
        SessionCache::breakCache($_SERVER['PHP_SELF']);
        Prefs::setValue('cache_hash', $cache_hash, $_SERVER['PHP_SELF']);
    }
    
    if (SessionCache::isCached($_SERVER['PHP_SELF']) && FALSE) { ///
        // Get the cached results.
        $list = SessionCache::getCache($_SERVER['PHP_SELF']);
    } else {
        // If the list is not already cached, query now.
        $qid = DB::query($sql);
        // Fill an array with the items for this page.
        while ($row = mysql_fetch_assoc($qid)) {
            $list[] = $row;
        }
            
        // Cache the results.
        SessionCache::putCache($list, $_SERVER['PHP_SELF']);
    }
    return $list;
}
?>