6 * @author Andrew McMillan <andrew@catalyst.net.nz>
7 * @copyright Catalyst IT Ltd
8 * @license http://gnu.org/copyleft/gpl.html GNU GPL v2
10 require_once("organisation-selectors-sql.php");
17 function User( $id ) {
21 $this->new_record = true;
26 // Try and load it from file
29 if ( $this->user_no == 0 ) {
30 $session->Dbg("User", "Initialising new user values");
32 $this->new_record = true;
34 // Initialise to standard default values
35 $this->base_rate = $session->work_rate;
36 $this->box_rows = "10";
37 $this->box_cols = "60";
39 if ( !$session->AllowedTo('see_other_orgs') ) {
40 $this->org_code = $session->org_code;
43 $this->org_code = null;
45 $this->org_name = null;
46 $this->username = null;
50 // Assign some template-based defaults
51 if ( isset($_GET['user_template']) ) {
52 // templates aren't done yet :-(
59 * ReadUser - Can the user do that?
61 function ReadUser ( $id ) {
64 // Try and load it from file
65 $sql = "SELECT usr.*, organisation.org_name ";
66 $sql .= " FROM usr JOIN organisation USING( org_code) ";
67 $sql .= " WHERE usr.user_no = '$id'";
68 if ( !($session->AllowedTo('Admin') || $session->AllowedTo('Support')
69 || $session->AllowedTo('Manage') || $session->AllowedTo('OrgMgr')) )
70 $sql .= " AND usr.user_no = '$session->user_no' ";
71 else if ( ($session->AllowedTo('Manage') || $session->AllowedTo('OrgMgr'))
72 && !($session->AllowedTo('Admin') || $session->AllowedTo('Support')) )
73 $sql .= " AND usr.org_code = '$session->org_code' ";
75 if ( $qry = new PgQuery($sql) ) {
76 if ( $qry->Exec("newUser")
77 && $qry->rows == 1 && $row = $qry->Fetch() ) {
78 $this->new_record = false;
79 while( list($k,$v) = each($row) ) {
80 $session->Dbg("User", "\$this->{'%-25.25s = %s", "$k'}", $v);
85 // Load the settings data
86 $this->settings = new Setting( $this->config_data );
87 if ( is_object( $this->settings ) ) {
88 $this->base_font_size = $this->settings->get('fontsize');
89 $this->box_rows = $this->settings->get('bigboxrows');
90 $this->box_cols = $this->settings->get('bigboxcols');
91 $this->theme = $this->settings->get('theme');
93 if ( "$this->base_font_size" == "" ) $this->base_font_size = "11";
94 if ( "$this->box_rows" == "" ) $this->box_rows = "10";
95 if ( "$this->box_cols" == "" ) $this->box_cols = "60";
100 unset( $GLOBALS['user_no'] );
106 /////////////////////////////////////////////////////////////
107 // AllowedTo - Can the user do that?
108 /////////////////////////////////////////////////////////////
109 function AllowedTo ( $whatever )
113 // fixme: We need to change this to abstract the logic in here of
114 // whether the current user can create, update, view things.
115 switch( $whatever ) {
116 case 'ChangePassword':
118 if ( ($session->AllowedTo("Admin") || $session->AllowedTo("Support") || $session->AllowedTo("OrgMgr") ) )
120 if ( $this->user_no > 0 && $session->user_no == $this->user_no )
125 if ( ($session->AllowedTo("Admin") || $session->AllowedTo("Support") || $session->AllowedTo("OrgMgr") ) )
130 $session->Dbg("User","AllowedTo: '%s' - %d >>%s<<", $whatever, isset($this->roles[$whatever]), $this->roles[$whatever] );
131 return ( isset($this->roles[$whatever]) && $this->roles[$whatever] );
133 // By default, they ain't allowed...
138 /////////////////////////////////////////////////////////////
139 // GetRoles - Get the role memberships
140 /////////////////////////////////////////////////////////////
141 function GetRoles () {
142 $this->roles = array();
143 $qry = new PgQuery( 'SELECT role_name AS role_name FROM role_member m join roles g ON g.role_no = m.role_no WHERE user_no = ? ', $this->user_no );
144 if ( $qry->Exec('Login') && $qry->rows > 0 ) {
145 while( $role = $qry->Fetch() ) {
146 $this->roles[$role->role_name] = true;
152 /////////////////////////////////////////////////////////////
153 // Render - Return HTML to show the W/R
154 // A separate function is called for each logical area
156 /////////////////////////////////////////////////////////////
161 $ef = new EntryForm( $_SERVER['REQUEST_URI'], $this, $GLOBALS['edit'] );
162 $ef->NoHelp(); // Prefer this style, for the moment
164 if ( $ef->EditMode ) {
165 $html .= $ef->StartForm( array("autocomplete" => "off" ) );
166 if ( $this->user_no > 0 ) $html .= $ef->HiddenField( "user_no", $this->user_no );
169 $html .= "<table width=\"100%\" class=\"data\" cellspacing=\"0\" cellpadding=\"0\">\n";
171 $html .= $this->RenderDetails($ef);
173 if ( $session->AllowedTo("Admin") || $session->AllowedTo("Support")
174 || $session->AllowedTo("OrgMgr") || $session->AllowedTo("Manage") ) {
175 $html .= $this->RenderAccessRoles($ef);
177 $html .= $this->RenderFontChoices($ef);
178 $html .= $this->RenderSystemRoles($ef);
180 $html .= "</table>\n";
181 if ( $ef->EditMode ) {
182 $html .= '<div id="footer">';
183 $html .= $ef->SubmitButton( "submit", ($this->new_record ? "Create" : "Update") );
185 $html .= $ef->EndForm();
192 function RenderDetails( $ef ) {
195 $html .= $ef->BreakLine("User Details");
197 $html .= $ef->DataEntryLine( "User Name", $this->username, "text", "username",
198 array( "size" => 20, "title" => "The name this user can log into the system with."), 'xxxx' );
199 if ( $ef->EditMode && $this->AllowedTo('ChangePassword') ) {
200 $this->new_password = '******';
201 unset($_POST['new_password']);
202 $html .= $ef->DataEntryLine( "New Password", "%s", "password", "new_password",
203 array( "size" => 20, "title" => "The user's password for logging in.") );
204 $this->confirm_password = '******';
205 unset($_POST['confirm_password']);
206 $html .= $ef->DataEntryLine( "Confirm", "%s", "password", "confirm_password",
207 array( "size" => 20, "title" => "Confirm the new password.") );
210 $html .= $ef->DataEntryLine( "Full Name", "%s", "text", "fullname",
211 array( "size" => 50, "title" => "The description of the system.") );
213 $html .= $ef->DataEntryLine( "Email", "%s", "text", "email",
214 array( "size" => 50, "title" => "The user's e-mail address.") );
216 // Organisation drop-down
217 if ( $session->AllowedTo("Admin") || $session->AllowedTo("Support") ) {
219 $sql = SqlSelectOrganisations($this->org_code);
220 if ( $this->new_record ) {
221 $html .= $ef->DataEntryLine( "Organisation", "$this->org_name", "lookup", "org_code",
222 array("_sql" => $sql,
223 "_null" => "--- select an organisation ---", "onchange" => "OrganisationChanged();",
224 "title" => "The organisation that this person is a part of." ) );
226 $html .= $ef->DataEntryLine( "Organisation", "$this->org_name");
229 $html .= $ef->DataEntryLine( "Hourly Rate", "%s", "text", "base_rate",
230 array( "size" => 10, "title" => "The base hourly rate that this person is charged at.") );
234 if ( $this->new_record ) $this->org_name = $session->org_name;
235 $html .= $ef->DataEntryLine( "Organisation", "$this->org_name", "", "" );
238 $html .= $ef->DataEntryLine( "Location", "%s", "text", "location",
239 array( "size" => 50, "title" => "The user's normal location within their organisation.") );
241 $html .= $ef->DataEntryLine( "Phone", "%s", "text", "phone",
242 array( "size" => 20, "title" => "The user's normal phone number during business hours.") );
244 $html .= $ef->DataEntryLine( "Mobile", "%s", "text", "mobile",
245 array( "size" => 20, "title" => "The user's mobile phone number.") );
247 $html .= $ef->DataEntryLine( "Active?", ($this->active == "t" ? "Active" : "Inactive"), "checkbox", "active",
248 array("_label" => "Check to make the user active.") );
250 $html .= $ef->DataEntryLine( "Email validated", "%s", "date", "email_ok",
251 array("_label" => "The date that the person's e-mail address was last validated.") );
256 function RenderFontChoices( $ef ) {
260 $html .= '<tr><th class="prompt">Font Size</th><td class="entry">';
262 if ( $ef->EditMode ) {
263 for( $i=7; $i < 22; $i += 2 ) {
264 $html .= $ef->DataEntryField( "", "radio", "base_font_size",
265 array("title" => "Choose the base size for fonts to be displayed for you.",
267 "_label" => sprintf('%spt.',$i)) );
271 $html .= sprintf( "%d pt.", $this->base_font_size);
273 $html .= '</td></tr>'."\n";
275 $html .= '<tr><th class="prompt">Entry Boxes</th><td class="entry">';
276 if ( $ef->EditMode ) {
278 $html .= $ef->DataEntryField( "", "text", "box_rows",
279 array("title" => "Choose the number of rows for default text entry.",
281 $html .= " Columns: ";
282 $html .= $ef->DataEntryField( "", "text", "box_cols",
283 array("title" => "Choose the number of rows for default text entry.",
287 $html .= sprintf( "%d rows x %d columns", $this->box_rows, $this->box_cols);
289 $html .= '</td></tr>'."\n";
291 if ( isset($c->can_set_theme) && $c->can_set_theme ) {
292 $html .= $ef->DataEntryLine( "Theme", $this->theme, "lookup", "theme",
293 array("_type" => "user|theme",
294 "_null" => "--- select a theme ---",
295 "title" => "The theme for this person to use" ) );
301 function RenderAccessRoles( $ef ) {
305 $sql = "SELECT * FROM roles LEFT JOIN role_member ";
306 $sql .= "ON (roles.role_no = role_member.role_no AND role_member.user_no = $this->user_no) ";
307 if ( ! ($session->AllowedTo('Admin') || $session->AllowedTo('Support') ) ) {
308 $sql .= "WHERE EXISTS(SELECT 1 from role_member gm WHERE gm.user_no=$session->user_no AND gm.role_no=roles.role_no) ";
310 else if ( ! $session->AllowedTo('Admin') ) {
311 $sql .= "WHERE roles.role_name != 'Admin' ";
313 $sql .= "ORDER BY roles.seq, roles.role_no";
317 $q = new PgQuery($sql);
318 if ( $q && $q->Exec("User::RndrAccessRoles") && $q->rows ) {
319 $html .= '<tr><th class="prompt">User Roles</th><td class="entry">';
322 while( $row = $q->Fetch() ) {
323 if ( $ef->EditMode ) {
324 if ( $row->user_no != "" ) $this->role_member[$row->role_name] = 't';
325 $html .= $ef->DataEntryField( "", "checkbox", "role_member[$row->role_name]",
326 array("title" => "Is this user a member of this role?",
327 "_label" => "$row->role_name" ) );
330 if ( $row->user_no != "" ) {
331 if ( $i++ > 0 ) $html .= ", ";
332 $html .= $row->role_name;
337 $html .= '</td></tr>'."\n";
343 function RenderSystemRoles( $ef ) {
347 $sql = "SELECT lookup_code, lookup_desc FROM lookup_code ";
348 $sql .= "WHERE source_table = 'system_usr' AND source_field = 'role' ORDER BY lookup_seq;";
349 $q = new PgQuery($sql);
350 if ( $q && $q->Exec("User::RenderSystemRoles1") && $q->rows ) {
351 if ( $this->AllowedTo('Admin') || $this->AllowedTo('Support') )
352 $roles = array('_' => '-- No Access --');
354 $roles = array('_' => '-- No Access --');
355 while( $row = $q->Fetch() ) {
356 $display_roles["_$row->lookup_code"] = $row->lookup_desc;
357 if ( $this->AllowedTo('Admin') || $this->AllowedTo('Support') || $this->AllowedTo('Contractor') ) {
358 if ( $row->lookup_code == 'A' || $row->lookup_code == 'S' || $row->lookup_code == 'E' )
359 $roles["_$row->lookup_code"] = $row->lookup_desc;
362 if ( ! ($row->lookup_code == 'A' || $row->lookup_code == 'S') )
363 $roles["_$row->lookup_code"] = $row->lookup_desc;
368 if ( intval("$this->user_no") == 0 ) return;
369 $sql = "SELECT work_system.*, system_usr.role ";
370 $sql .= "FROM work_system LEFT JOIN system_usr ";
371 $sql .= "ON (work_system.system_id = system_usr.system_id AND system_usr.user_no = $this->user_no) ";
372 $sql .= "WHERE work_system.active ";
373 if ( ($session->AllowedTo('Admin') || $session->AllowedTo('Support'))
374 && ($this->AllowedTo('Admin') || $this->AllowedTo('Support')) ) {
375 // Actually, we do nothing in this case...
376 $session->Dbg("User", "Admin/Support maintains Admin/Support person. Almost all systems shown");
377 // $sql .= "AND (NOT organisation_specific OR EXISTS( SELECT 1 from org_system WHERE org_system.org_code = $this->org_code AND org_system.system_id = work_system.system_id)) ";
379 elseif ( $session->AllowedTo('Admin') || $session->AllowedTo('Support') ) {
380 $sql .= "AND EXISTS( SELECT 1 from org_system WHERE org_system.org_code = $this->org_code AND org_system.system_id = work_system.system_id) ";
381 $session->Dbg("User", "Admin/Support maintains non Admin/Support person. Org related systems only shown");
383 elseif ( $session->AllowedTo('OrgMgr') ) {
384 $sql .= "AND EXISTS( SELECT 1 from org_system WHERE org_system.org_code = $session->org_code AND org_system.system_id = work_system.system_id) ";
385 $session->Dbg("User", "OrgMgr maintains person. Maintainer org related systems only shown");
388 $sql .= "AND system_usr.user_no = $session->user_no ";
389 $session->Dbg("User", "non Admin/Support/OrgMgr maintains person. Only assigned systems shown");
391 $sql .= "ORDER BY lower(work_system.system_desc)";
395 $q = new PgQuery($sql);
397 if ( $q && $q->Exec("User::RenderSystemRoles2") && $q->rows ) {
398 $html .= $ef->BreakLine("Active System Roles");
399 $html .= '<tr><th class="prompt"> </th><td class="entry"><table width="100%">'."\n";
401 if ( $ef->EditMode && ($session->AllowedTo('Admin') || $session->AllowedTo('Support') || $session->AllowedTo('OrgMgr')) ) {
402 $html .= '<tr class="row1">';
404 <th class="prompt" style="width:auto;">
405 <script language="javascript">
406 //////////////////////////////////////////////////////////
407 // Since PHP wants a field returning multiple values to
408 // be named like "variable[]"
409 //////////////////////////////////////////////////////////
410 function ApplyToRoles(to_all) {
411 for ( var i=0; i < document.forms.form.elements.length ; i++ ) {
412 if ( document.forms.form.elements[i].name.match( /^role\[[0-9]+\]$/ ) ) {
413 if ( to_all || document.forms.form.elements[i].value == '' ) {
414 document.forms.form.elements[i].value = document.forms.form.default_role.value;
422 $ef->TempLineFormat('<span class="srchf" style="white-space: nowrap">%s%s</span>' );
423 $btn_all = $ef->DataEntryLine( "", "", "button", "apply_all",
424 array("value" => "All",
425 "onclick" => "ApplyToRoles(true);",
426 "title" => "Click to apply the default to all systems for this user.",
427 "class" => "fsubmit" ) );
428 $btn_some = $ef->DataEntryLine( "", "", "button", "apply_new",
429 array("value" => "Unassigned",
430 "onclick" => "ApplyToRoles(false);",
431 "title" => "Click to apply the default to unassigned systems for this user.",
432 "class" => "fsubmit" ) );
433 $ef->RevertLineFormat( );
435 $html .= "Choose a default and apply to $btn_all or $btn_some systems</th>";
437 $html .= '<td class="entry">';
438 $options = array_merge($roles, array("title" => "Select the role this person has in relation to this system"));
440 $html .= $ef->DataEntryField( "", "select", "default_role", $options );
441 $html .= "</td></tr>";
444 while( $row = $q->Fetch() ) {
445 $html .= sprintf( '<tr class="row%d">', $q->rownum % 2);
446 if ( trim($row->system_desc) == "" ) $row->system_desc = "<<<unknown>>>";
447 $html .= '<td class="entry">';
448 $html .= "<a href=\"/system.php?system_id=$row->system_id\">$row->system_desc</a>";
450 $html .= '<td class="entry">';
451 if ( $ef->EditMode && ($session->AllowedTo('Admin') || $session->AllowedTo('Support') ||
452 ($session->AllowedTo('OrgMgr') && !($row->role == 'A' || $row->role == 'S') ) ) ) {
453 $options = array_merge($roles, array("title" => "Select the role this person has in relation to this system"));
454 $html .= sprintf("<span style=\"color: %s; white-space: normal;\">", ( "$row->role" == "" ? "black" : "red") );
455 $this->role[$row->system_id] = $row->role;
456 $html .= $ef->DataEntryField( "", "select", "role[$row->system_id]", $options );
460 $html .= $row->role . " - " . $display_roles["_$row->role"];
462 $html .= "</td></tr>";
465 $html .= '</table></td></tr>'."\n";
471 function Validate( ) {
472 global $session, $client_messages;
473 $session->Dbg("User", "User::Validate: Validating user");
475 if ( isset($_POST) ) {
477 $_POST['status'] = ( isset($_POST['active']) && ($_POST['active'] != 'off') ? 'A' : 'I' );
479 if ( trim($_POST['fullname']) == "" ) {
480 $client_messages[] = "ERROR: The full name may not be blank.";
484 if ( !($session->AllowedTo("Admin") || $session->AllowedTo("Support") ) ) {
485 if ( $this->user_no == 0 )
486 $_POST['org_code'] = $session->org_code;
488 unset($_POST['org_code']);
490 if ( isset($_POST['org_code']) && intval($_POST['org_code']) == 0 ) {
491 $client_messages[] = "ERROR: The organisation must be selected.";
498 $client_messages[] = "ERROR: No form data submitted!";
504 global $session, $client_messages;
506 $session->Dbg("User", "Writing usr form details to database");
508 $this->chtype = strtolower($_POST['submit']);
509 if ( ! $this->AllowedTo($this->chtype) ) {
510 $client_messages[] = "ERROR: You do not have privileges to $this->chtype - please contact the administrator.";
514 $client_messages[] = "Writing user details to database.";
517 $qry = new PgQuery("BEGIN"); $qry->Exec("User::Write");
519 if ( !is_object($this->settings)) $this->settings = new Setting;
520 $this->settings->set('fontsize', $_POST['base_font_size']);
521 $this->settings->set('bigboxrows', $_POST['box_rows']);
522 $this->settings->set('bigboxcols', $_POST['box_cols']);
523 if ( $_POST['theme'] != "" ) $this->settings->set('theme', $_POST['theme']);
524 if ( is_object( $this->settings ) ) $_POST['config_data'] = $this->settings->to_save();
526 unset($_POST['password']); // Just in case...
527 if ( $this->AllowedTo('ChangePassword') ) {
528 if ( $_POST['new_password'] != '******' && $_POST['new_password'] == $_POST['confirm_password'] ) {
529 $value = $_POST['new_password'];
530 $value = (function_exists("session_salted_sha1")
531 ? session_salted_sha1($value)
532 : (function_exists('session_salted_md5')
533 ? session_salted_md5($value)
538 $_POST['password'] = $value;
539 $session->Dbg("User", "New salted password = $value");
541 else if ( $_POST['new_password'] != '******' && $_POST['new_password'] != $_POST['confirm_password'] ) {
542 $client_messages[] = "WARNING: Confirmation password does not match - the password was not changed.";
546 if ( isset($_POST['base_rate']) ) $_POST['base_rate'] = doubleval($_POST['base_rate']);
548 $sql = sql_from_post( $this->chtype, "usr", "WHERE user_no='$this->user_no'");
549 $qry = new PgQuery($sql);
550 if ( !$qry->Exec("User::Write") ) {
551 if ( preg_match( '/duplicate key/i', $qry->errorstring ) )
552 $client_messages[] = "ERROR: That User Name is already in use";
554 $client_messages[] = "ERROR: $qry->errorstring";
558 // If we are creating a new record, we need to grab the ID that it got
559 if ( "create" == $this->chtype ) {
560 // Fetch the user_no for this record.
561 $sql = "SELECT currval('usr_user_no_seq');";
562 $qry = new PgQuery($sql);
563 $qry->Exec("User::Write");
564 $row = $qry->Fetch(true); // Fetch results as array
565 $GLOBALS['user_no'] = $row[0];
566 $GLOBALS['edit'] = 1; // Assume we want further editing
568 // Fetch the other details for the request and assign them into this object.
569 $this->ReadUser($GLOBALS['user_no']);
573 if ( isset($_POST['role_member']) && is_array($_POST['role_member']) ) {
575 foreach( $_POST['role_member'] AS $k => $v ) {
576 if ( $v && $v != "off" ) {
577 $roles .= ( "$roles" == "" ? "" : ", " );
582 $sql = "DELETE FROM role_member WHERE user_no = '$this->user_no';";
584 $sql = "DELETE FROM role_member WHERE user_no = '$this->user_no' ";
585 $sql .= "AND role_no NOT IN ( SELECT role_no FROM roles WHERE role_name IN ($roles) );";
586 $sql .= "INSERT INTO role_member ( role_no, user_no) ";
587 $sql .= "SELECT role_no, $this->user_no FROM roles WHERE role_name IN ( $roles ) ";
588 $sql .= "EXCEPT SELECT role_no, user_no FROM role_member;";
590 // echo "<p>$sql</p>";
591 $qry = new PgQuery($sql);
592 if ( !$qry->Exec("Sys::Write") ) $client_messages[] = "ERROR: $qry->errorstring";
595 if ( isset($_POST['role']) && is_array($_POST['role']) ) {
598 while( list($k,$v) = each($_POST['role']) ) {
600 $systems .= ( "$systems" == "" ? "" : ", " );
601 $systems .= "'" . str_replace("'","''",str_replace('\\','', $k)) . "'";
602 $role_update .= "SELECT set_system_role($this->user_no,'" . str_replace("'","''",str_replace('\\','', $k))
603 . "','" . str_replace("'","''",str_replace('\\','', $v)) . "');";
606 if ( $systems == "" )
607 $sql = "DELETE FROM system_usr WHERE user_no = '$this->user_no';";
609 $sql = "DELETE FROM system_usr WHERE user_no = '$this->user_no' AND system_id NOT IN ( $systems ) ";
610 if ( ! ($session->AllowedTo('Admin') || $session->AllowedTo('Support')) ) {
611 $sql .= "AND role NOT IN ( 'A', 'S' ) ";
613 $sql .= ";" . $role_update;
615 $qry = new PgQuery($sql);
616 if ( !$qry->Exec("Sys::Write") ) $client_messages[] = "ERROR: $qry->errorstring";
619 $qry = new PgQuery("COMMIT;"); $qry->Exec("Sys::Write");