Overview

Packages

  • awl
    • AuthPlugin
    • AwlDatabase
    • Browser
    • classEditor
    • DataEntry
    • DataUpdate
    • EMail
    • iCalendar
    • MenuSet
    • PgQuery
    • Session
    • Translation
    • User
    • Utilities
    • Validation
    • vCalendar
    • vComponent
    • XMLDocument
    • XMLElement
  • None

Classes

  • AuthPlugin
  • AwlCache
  • AwlDatabase
  • AwlDBDialect
  • AwlQuery
  • AwlUpgrader
  • Browser
  • BrowserColumn
  • DBRecord
  • Editor
  • EditorField
  • EMail
  • EntryField
  • EntryForm
  • iCalComponent
  • iCalProp
  • MenuOption
  • MenuSet
  • Multipart
  • PgQuery
  • Session
  • SinglePart
  • User
  • Validation
  • vCalendar
  • vComponent
  • vObject
  • vProperty
  • XMLDocument
  • XMLElement

Functions

  • _awl_connect_configured_database
  • _CompareMenuSequence
  • auth_external
  • auth_other_awl
  • awl_get_fields
  • awl_replace_sql_args
  • awl_set_locale
  • awl_version
  • BuildXMLTree
  • check_by_regex
  • check_temporary_passwords
  • clean_string
  • connect_configured_database
  • dbg_error_log
  • dbg_log_array
  • define_byte_mappings
  • deprecated
  • duration
  • fatal
  • force_utf8
  • getCacheInstance
  • gzdecode
  • i18n
  • init_gettext
  • olson_from_tzstring
  • param_to_global
  • qpg
  • quoted_printable_encode
  • replace_uri_params
  • session_salted_md5
  • session_salted_sha1
  • session_simple_md5
  • session_validate_password
  • sql_from_object
  • sql_from_post
  • trace_bug
  • translate
  • uuid
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  • Todo
  1:   2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19:  20:  21:  22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33:  34:  35:  36:  37:  38:  39:  40:  41:  42:  43:  44:  45:  46:  47:  48:  49:  50:  51:  52:  53:  54:  55:  56:  57:  58:  59:  60:  61:  62:  63:  64:  65:  66:  67:  68:  69:  70:  71:  72:  73:  74:  75:  76:  77:  78:  79:  80:  81:  82:  83:  84:  85:  86:  87:  88:  89:  90:  91:  92:  93:  94:  95:  96:  97:  98:  99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 
<?php
/**
* A class to handle reading, writing, viewing, editing and validating
* usr records.
*
* @package   awl
* @author Andrew McMillan <andrew@mcmillan.net.nz>
* @copyright Catalyst IT Ltd, Morphoss Ltd <http://www.morphoss.com/>
* @license   http://gnu.org/copyleft/gpl.html GNU GPL v2 or later
*/
require_once("AWLUtilities.php");

/**
* We need to access some session information.
*/
require_once("Session.php");

/**
* We use the DataEntry class for data display and updating
*/
require_once("DataEntry.php");

/**
* We use the DataUpdate class and inherit from DBRecord
*/
require_once("DataUpdate.php");

/**
* A class to handle reading, writing, viewing, editing and validating
* usr records.
* @package   awl
* @subpackage   User
*/
class User extends DBRecord {
  /**#@+
  * @access private
  */
  /**
  * A unique user number that is auto assigned on creation and invariant thereafter
  * @var string
  */
  var $user_no;

  /**
  * Something to prefix all field names with before rendering them.
  * @var string
  */
  var $prefix;

  /**#@-*/

  /**
  * The constructor initialises a new record, potentially reading it from the database.
  * @param int $id The user_no, or 0 if we are creating a new one
  * @param string $prefix The prefix for entry fields
  */
  function __construct( $id , $prefix = "") {
    global $session;

    // Call the parent constructor
    parent::__construct();

    $this->prefix = $prefix;

    $this->user_no = 0;
    $keys = array();

    $id = intval("$id");
    if ( $id > 0 ) {
      // Initialise
      $keys['user_no'] = $id;
      $this->user_no = $id;
    }

    // Initialise the record, possibly from the file.
    $this->Initialise('usr',$keys);
    $this->Read();
    $this->GetRoles();

    $this->EditMode = ( (isset($_GET['edit']) && $_GET['edit'] && $this->AllowedTo($this->WriteType))
                    || (0 == $this->user_no && $this->AllowedTo("insert") ) );

    if ( $this->user_no == 0 ) {
      dbg_error_log("User", "Initialising new user values");

      // Initialise to standard default values
      $this->active = true;

    }
  }


  /**
  * Can the user do this?
  * @param string $whatever What the user wants to do
  * @return boolean Whether they are allowed to.
  */
  function AllowedTo ( $whatever )
  {
    global $session;

    $rc = false;

    /**
    * First we globally short-circuit the 'admin can do anything'
    */
    if ( $session->AllowedTo("Admin") ) {
      $rc = true;
      dbg_error_log("User",":AllowedTo: Admin is always allowed to %s", $whatever );
      return $rc;
    }

    switch( strtolower($whatever) ) {

      case 'view':
        $rc = ( $this->user_no > 0 && $session->user_no == $this->user_no );
        break;

      case 'update':
        $rc = ( $this->user_no > 0 && $session->user_no == $this->user_no );
        break;

      case 'changepassword':
        $rc = ( ($this->user_no > 0 && $session->user_no == $this->user_no)
                || ("insert" == $this->WriteType) );
        break;

      case 'changeusername':  // Administrator only
      case 'changeactive':    // Administrator only
      case 'admin':

      case 'create':

      case 'insert':
        $rc = false;
        break;

      default:
        $rc = ( isset($session->roles[$whatever]) && $session->roles[$whatever] );
    }
    dbg_error_log("User",":AllowedTo: %s is%s allowed to %s", (isset($this->username)?$this->username:null), ($rc?"":" not"), $whatever );
    return $rc;
  }


  /**
  * Get the group memberships for the user
  */
  function GetRoles () {
    $this->roles = array();
    $qry = new AwlQuery( 'SELECT role_name FROM role_member JOIN roles USING (role_no) WHERE user_no = ? ', $this->user_no );
    if ( $qry->Exec("User") && $qry->rows() > 0 ) {
      while( $role = $qry->Fetch() ) {
        $this->roles[$role->role_name] = 't';
      }
    }
  }


  /**
  * Render the form / viewer as HTML to show the user
  * @return string An HTML fragment to display in the page.
  */
  function Render( ) {
    $html = "";
    dbg_error_log("User", ":Render: type=$this->WriteType, edit_mode=$this->EditMode" );

    $ef = new EntryForm( $REQUEST_URI, $this->Values, $this->EditMode );
    $ef->NoHelp();  // Prefer this style, for the moment

    if ( $ef->EditMode ) {
      $html .= $ef->StartForm( array("autocomplete" => "off" ) );
      if ( $this->user_no > 0 ) $html .= $ef->HiddenField( "user_no", $this->user_no );
    }

    $html .= "<table width=\"100%\" class=\"data\" cellspacing=\"0\" cellpadding=\"0\">\n";

    $html .= $this->RenderFields($ef);
    $html .= $this->RenderRoles($ef);

    $html .= "</table>\n";
    if ( $ef->EditMode ) {
      $html .= '<div id="footer">';
      $html .= $ef->SubmitButton( "submit", (("insert" == $this->WriteType) ? translate("Create") : translate("Update")) );
      $html .= '</div>';
      $html .= $ef->EndForm();
    }

    return $html;
  }

  /**
  * Render the core details to show to the user
  * @param object $ef The entry form.
  * @param string $title The title to display above the entry fields.
  * @return string An HTML fragment to display in the page.
  */
  function RenderFields($ef , $title = null ) {
    global $session, $c;

    if ( $title == null ) $title = i18n("User Details");
    $html = ( $title == "" ? "" : $ef->BreakLine(translate($title)) );

    if ( $this->AllowedTo('ChangeUsername') ) {
      $html .= $ef->DataEntryLine( translate("User Name"), "%s", "text", "username",
              array( "size" => 20, "title" => translate("The name this user can log into the system with.")), $this->prefix );
    }
    else {
      $html .= $ef->DataEntryLine( translate("User Name"), $this->Get('username') );
    }
    if ( $ef->EditMode && $this->AllowedTo('ChangePassword') ) {
      $this->Set('new_password','******');
      unset($_POST['new_password']);
      $html .= $ef->DataEntryLine( translate("New Password"), "%s", "password", "new_password",
                array( "size" => 20, "title" => translate("The user's password for logging in.")), $this->prefix );
      $this->Set('confirm_password', '******');
      unset($_POST['confirm_password']);
      $html .= $ef->DataEntryLine( translate("Confirm"), "%s", "password", "confirm_password",
                array( "size" => 20, "title" => translate("Confirm the new password.")), $this->prefix );
    }

    $html .= $ef->DataEntryLine( translate("Full Name"), "%s", "text", "fullname",
              array( "size" => 50, "title" => translate("The user's full name.")), $this->prefix );

    $html .= $ef->DataEntryLine( translate("EMail"), "%s", "text", "email",
              array( "size" => 50, "title" => translate("The user's e-mail address.")), $this->prefix );

    if ( $this->AllowedTo('ChangeActive') ) {
      $html .= $ef->DataEntryLine( translate("Active"), ($this->Get('active') == 't'? translate('Yes') : translate('No')), "checkbox", "active",
                array( "_label" => translate("User is active"),
                      "title" => translate("Is this user active?")), $this->prefix );
    }
    else {
      $html .= $ef->DataEntryLine( translate("Active"), ($this->Get('active') == 't'? translate('Yes') : translate('No')) );
    }

    $html .= $ef->DataEntryLine( translate("Date Style"), ($this->Get('date_format_type') == 'E' ? 'European' : ($this->Get('date_format_type') == 'U' ? 'US of A' : 'ISO 8861')),
                     "select", "date_format_type",
                     array( "title" => translate("The style of dates used for this person."),
                       "_E" => translate("European (d/m/y)"), "_U" => translate("United States of America (m/d/y)"), "_I" => translate("ISO Format (YYYY-MM-DD)") ),
                     $this->prefix );

    if ( isset($c->default_locale) ) {
      if ( $this->Get('locale') == '' ) {
        $this->Set('locale',$c->default_locale);
      }
      $html .= $ef->DataEntryLine( translate("Language"), "%s", "lookup", "locale",
                      array( "title" => translate("The preferred language for this person."),
                        "_sql" => "SELECT locale, locale_name_locale FROM supported_locales ORDER BY locale ASC;" ),
                      $this->prefix );
    }

    $html .= $ef->DataEntryLine( translate("EMail OK"), $session->FormattedDate($this->Get('email_ok'),'timestamp'), "timestamp", "email_ok",
              array( "title" => translate("When the user's e-mail account was validated.")), $this->prefix );

    $html .= $ef->DataEntryLine( translate("Joined"), $session->FormattedDate($this->Get('joined'),'timestamp') );
    $html .= $ef->DataEntryLine( translate("Updated"), $session->FormattedDate($this->Get('updated'),'timestamp') );
    $html .= $ef->DataEntryLine( translate("Last used"), $session->FormattedDate($this->Get('last_used'),'timestamp') );

    return $html;
  }


  /**
  * Render the user's administrative roles
  *
  * @return string The string of html to be output
  */
  function RenderRoles( $ef, $title = null ) {
    global $session;
    $html = "";

    if ( $title == null ) $title = i18n("User Roles");
    $html = ( $title == "" ? "" : $ef->BreakLine(translate($title)) );

    $html .= '<tr><th class="prompt">'.translate("User Roles").'</th><td class="entry">';
    if ( $ef->EditMode ) {
      $sql = "SELECT role_name FROM roles ";
      if ( ! ($session->AllowedTo('Admin') ) ) {
        $sql .= "NATURAL JOIN role_member WHERE user_no=$session->user_no ";
      }
      $sql .= "ORDER BY roles.role_no";

      $ef->record->roles = array();

      // Select the records
      $q = new AwlQuery($sql);
      if ( $q && $q->Exec("User") && $q->rows() ) {
        $i=0;
        while( $row = $q->Fetch() ) {
          @dbg_error_log("User", ":RenderRoles: Is a member of '%s': %s", $row->role_name, $this->roles[$row->role_name] );
          $ef->record->roles[$row->role_name] = ( isset($this->roles[$row->role_name]) ? $this->roles[$row->role_name] : 'f');
          $html .= $ef->DataEntryField( "", "checkbox", "roles[$row->role_name]",
                          array("title" => translate("Does the user have the right to perform this role?"),
                                    "_label" => translate($row->role_name) ) );
        }
      }
    }
    else {
      $i = 0;
      foreach( $this->roles AS $k => $v ) {
        if ( $i++ > 0 ) $html .= ", ";
        $html .= $k;
      }
    }
    $html .= '</td></tr>'."\n";

    return $html;
  }

  /**
  * Validate the information the user submitted
  * @return boolean Whether the form data validated OK.
  */
  function Validate( ) {
    global $session, $c;
    dbg_error_log("User", ":Validate: Validating user");

    $valid = true;

    if ( $this->Get('fullname') == "" ) {
      $c->messages[] = i18n('ERROR: The full name may not be blank.');
      $valid = false;
    }

    // Password changing is a little special...
    unset($_POST['password']);
    if ( $_POST['new_password'] != "******" && $_POST['new_password'] != ""  ) {
      if ( $_POST['new_password'] == $_POST['confirm_password'] ) {
        $this->Set('password',$_POST['new_password']);
      }
      else {
        $c->messages[] = i18n('ERROR: The new password must match the confirmed password.');
        $valid = false;
      }
    }
    else {
      $this->Undefine('password');
    }

    dbg_error_log("User", ":Validate: User %s validation", ($valid ? "passed" : "failed"));
    return $valid;
  }

  /**
  * Write the User record.
  * @return Success.
  */
  function Write() {
    global $c, $session;
    if ( parent::Write() ) {
      $c->messages[] = i18n('User record written.');
      if ( $this->WriteType == 'insert' ) {
        $qry = new AwlQuery( "SELECT currval('usr_user_no_seq');" );
        $qry->Exec("User::Write");
        $sequence_value = $qry->Fetch(true);  // Fetch as an array
        $this->user_no = $sequence_value[0];
      }
      else {
        if ( $this->user_no == $session->user_no && $this->Get("date_format_type") != $session->date_format_type ) {
          // Ensure we match the date style setting
          $session->date_format_type = $this->Get("date_format_type");
          unset($_POST['email_ok']);
          $qry = new AwlQuery( "SET DATESTYLE TO ?;", ($this->Get("date_format_type") == 'E' ? 'European,ISO' : ($this->Get("date_format_type") == 'U' ? 'US,ISO' : 'ISO')) );
          $qry->Exec();
        }
      }
      return $this->WriteRoles();
    }
    return false;
  }

  /**
  * Write the roles associated with the user
  * @return Success.
  */
  function WriteRoles() {
    global $c, $session;

    if ( isset($_POST['roles']) && is_array($_POST['roles']) ) {
      $roles = "";
      $params = array();
      foreach( $_POST['roles'] AS $k => $v ) {
        if ( $v && $v != "off" ) {
          $roles .= ( $roles == '' ? '' : ', ' );
          $roles .= AwlQuery::quote($k);
        }
      }
      $qry = new AwlQuery();
      if ( $roles == '' )
        $succeeded = $qry->QDo('DELETE FROM role_member WHERE user_no = '.$this->user_no);
      else {
        $succeeded = $qry->Begin();
        $sql = 'DELETE FROM role_member WHERE user_no = '.$this->user_no;
        $sql .= ' AND role_no NOT IN (SELECT role_no FROM roles WHERE role_name IN ('.$roles.') )';
        if ( $succeeded ) $succeeded = $qry->QDo($sql);
        $sql = 'INSERT INTO role_member (role_no, user_no)';
        $sql .= ' SELECT role_no, '.$this->user_no.' FROM roles WHERE role_name IN ('.$roles.')';
        $sql .= ' EXCEPT SELECT role_no, user_no FROM role_member';
        if ( $succeeded ) $succeeded = $qry->QDo($sql);
        if ( $succeeded )
          $qry->Commit();
        else
          $qry->Rollback();
      }
      if ( ! $succeeded ) {
        $c->messages[] = i18n('ERROR: There was a database error writing the roles information!');
        $c->messages[] = i18n('Please note the time and advise the administrator of your system.');
        return false;
      }
    }
    return true;
  }
}
AWL API documentation generated by ApiGen