Correcting time entry slowness
[wrms.git] / inc / User.class
blobee26246fd59599b3d042a297f5308b42382c12a2
1 <?php
2 /**
3 * Class for users
4 * @package   wrms
5 * @subpackage   Request
6 * @author    Andrew McMillan <andrew@catalyst.net.nz>
7 * @copyright Catalyst IT Ltd
8 * @license   http://gnu.org/copyleft/gpl.html GNU GPL v2
9 */
10 require_once("organisation-selectors-sql.php");
12 class User {
13   var $user_no;
14   var $new_record;
15   var $theme;
17   function User( $id ) {
18     global $session;
20     $this->user_no = 0;
21     $this->new_record = true;
22     $this->theme = '';
24     $id = intval("$id");
25     if ( $id > 0 ) {
26       // Try and load it from file
27       $this->ReadUser($id);
28     }
29     if ( $this->user_no == 0 ) {
30       $session->Dbg("User", "Initialising new user values");
31       $GLOBALS['edit'] = 1;
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;
41       }
42       else {
43         $this->org_code = null;
44       }
45       $this->org_name = null;
46       $this->username = null;
47       $this->active   = true;
48       $this->roles    = null;
50       // Assign some template-based defaults
51       if ( isset($_GET['user_template']) ) {
52         // templates aren't done yet :-(
53       }
54     }
55   }
58   /**
59   * ReadUser - Can the user do that?
60   */
61   function ReadUser ( $id ) {
62     global $session;
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);
81           $this->{$k} = $v;
82         }
83         $this->GetRoles();
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');
92         }
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";
97       }
98       else {
99         $this->user_no = 0;
100         unset( $GLOBALS['user_no'] );
101       }
102     }
103   }
106   /////////////////////////////////////////////////////////////
107   // AllowedTo - Can the user do that?
108   /////////////////////////////////////////////////////////////
109   function AllowedTo ( $whatever )
110   {
111     global $session;
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':
117       case 'update':
118         if ( ($session->AllowedTo("Admin") || $session->AllowedTo("Support") || $session->AllowedTo("OrgMgr") ) )
119           return true;
120         if ( $this->user_no > 0 && $session->user_no == $this->user_no )
121           return true;
122         break;
124       case 'create':
125         if ( ($session->AllowedTo("Admin") || $session->AllowedTo("Support") || $session->AllowedTo("OrgMgr") ) )
126           return true;
127         break;
129       default:
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] );
132     }
133     // By default, they ain't allowed...
134     return false;
135   }
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;
147       }
148     }
149   }
152   /////////////////////////////////////////////////////////////
153   // Render - Return HTML to show the W/R
154   //   A separate function is called for each logical area
155   //   on the W/R.
156   /////////////////////////////////////////////////////////////
157   function Render( ) {
158     global $session;
159     $html = "";
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 );
167     }
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);
176     }
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") );
184       $html .= '</div>';
185       $html .= $ef->EndForm();
186     }
188     return $html;
189   }
192   function RenderDetails( $ef ) {
193     global $session;
194     $html = "";
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.") );
208     }
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." ) );
225       } else {
226         $html .= $ef->DataEntryLine( "Organisation", "$this->org_name");
227       }
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.") );
232     }
233     else {
234       if ( $this->new_record ) $this->org_name = $session->org_name;
235       $html .= $ef->DataEntryLine( "Organisation", "$this->org_name", "", "" );
236     }
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.") );
253     return $html;
254   }
256   function RenderFontChoices( $ef ) {
257     global $c, $session;
258     $html = "";
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.",
266                     "value"  => "$i",
267                     "_label" => sprintf('%spt.',$i)) );
268       }
269     }
270     else {
271       $html .= sprintf( "%d pt.", $this->base_font_size);
272     }
273     $html .= '</td></tr>'."\n";
275     $html .= '<tr><th class="prompt">Entry Boxes</th><td class="entry">';
276     if ( $ef->EditMode ) {
277       $html .= " Rows: ";
278       $html .= $ef->DataEntryField( "", "text", "box_rows",
279               array("title"  => "Choose the number of rows for default text entry.",
280                     "size"   => 4) );
281       $html .= " &nbsp; Columns: ";
282       $html .= $ef->DataEntryField( "", "text", "box_cols",
283               array("title"  => "Choose the number of rows for default text entry.",
284                     "size"   => 4) );
285     }
286     else {
287       $html .= sprintf( "%d rows x %d columns", $this->box_rows, $this->box_cols);
288     }
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" ) );
296     }
297     return $html;
298   }
301   function RenderAccessRoles( $ef ) {
302     global $session;
303     $html = "";
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) ";
309     }
310     else if ( ! $session->AllowedTo('Admin') ) {
311       $sql .= "WHERE roles.role_name != 'Admin' ";
312     }
313     $sql .= "ORDER BY roles.seq, roles.role_no";
316     # Select the records
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">';
321       $i=0;
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" ) );
328         }
329         else {
330           if ( $row->user_no != "" ) {
331             if ( $i++ > 0 ) $html .= ", ";
332             $html .= $row->role_name;
333           }
334         }
335       }
336     }
337     $html .= '</td></tr>'."\n";
339     return $html;
340   }
343   function RenderSystemRoles( $ef ) {
344     global $session;
345     $html = "";
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 --');
353       else
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;
360         }
361         else {
362           if ( ! ($row->lookup_code == 'A' || $row->lookup_code == 'S') )
363             $roles["_$row->lookup_code"] = $row->lookup_desc;
364         }
365       }
366     }
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)) ";
378     }
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");
382     }
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");
386     }
387     else {
388       $sql .= "AND system_usr.user_no = $session->user_no ";
389       $session->Dbg("User", "non Admin/Support/OrgMgr maintains person.  Only assigned systems shown");
390     }
391     $sql .= "ORDER BY lower(work_system.system_desc)";
394     # Select the records
395     $q = new PgQuery($sql);
396     $column = 0;
397     if ( $q && $q->Exec("User::RenderSystemRoles2") && $q->rows ) {
398       $html .= $ef->BreakLine("Active System Roles");
399       $html .= '<tr><th class="prompt">&nbsp;</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">';
403         $html .= <<<SCRIPT
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;
415       }
416     }
417   }
418   return true;
420 </script>
421 SCRIPT;
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>";
442       }
444       while( $row = $q->Fetch() ) {
445         $html .= sprintf( '<tr class="row%d">', $q->rownum % 2);
446         if ( trim($row->system_desc) == "" ) $row->system_desc = "&lt;&lt;&lt;unknown&gt;&gt;&gt;";
447         $html .= '<td class="entry">';
448         $html .= "<a href=\"/system.php?system_id=$row->system_id\">$row->system_desc</a>";
449         $html .= "</td>";
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 );
457           $html .= "</span>";
458         }
459         else {
460           $html .= $row->role . " - " . $display_roles["_$row->role"];
461         }
462         $html .= "</td></tr>";
463       }
464     }
465     $html .= '</table></td></tr>'."\n";
467     return $html;
468   }
471   function Validate( ) {
472     global $session, $client_messages;
473     $session->Dbg("User", "User::Validate: Validating user");
475     if ( isset($_POST) ) {
476       $valid = true;
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.";
481         $valid = false;
482       }
484       if ( !($session->AllowedTo("Admin") || $session->AllowedTo("Support") ) ) {
485         if ( $this->user_no == 0 )
486           $_POST['org_code'] = $session->org_code;
487         else
488           unset($_POST['org_code']);
489       }
490       if ( isset($_POST['org_code']) && intval($_POST['org_code']) == 0 ) {
491         $client_messages[] = "ERROR: The organisation must be selected.";
492         $valid = false;
493       }
495       return $valid;
496     }
498     $client_messages[] = "ERROR: No form data submitted!";
499     return false;
500   }
503   function Write(  ) {
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.";
511       return;
512     }
514     $client_messages[] = "Writing user details to database.";
516     $db_errors = false;
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)
534                        : md5($value)
535                      )
536                  );
538         $_POST['password'] = $value;
539         $session->Dbg("User", "New salted password = $value");
540       }
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.";
543       }
544     }
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";
553       else
554         $client_messages[] = "ERROR: $qry->errorstring";
555       $db_errors = true;
556     }
557     else {
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']);
570       }
571     }
573     if ( isset($_POST['role_member']) && is_array($_POST['role_member']) ) {
574       $roles = "";
575       foreach( $_POST['role_member'] AS $k => $v ) {
576         if ( $v && $v != "off" ) {
577           $roles .= ( "$roles" == "" ? "" : ", " );
578           $roles .= qpg($k);
579         }
580       }
581       if ( $roles == "" )
582         $sql = "DELETE FROM role_member WHERE user_no = '$this->user_no';";
583       else {
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;";
589       }
590       // echo "<p>$sql</p>";
591       $qry = new PgQuery($sql);
592       if ( !$qry->Exec("Sys::Write") ) $client_messages[] = "ERROR: $qry->errorstring";
593     }
595     if ( isset($_POST['role']) && is_array($_POST['role']) ) {
596       $systems = "";
597       $role_update = "";
598       while( list($k,$v) = each($_POST['role']) ) {
599         if ( $v ) {
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)) . "');";
604         }
605       }
606       if ( $systems == "" )
607         $sql = "DELETE FROM system_usr WHERE user_no = '$this->user_no';";
608       else {
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' ) ";
612         }
613         $sql .= ";" . $role_update;
614       }
615       $qry = new PgQuery($sql);
616       if ( !$qry->Exec("Sys::Write") ) $client_messages[] = "ERROR: $qry->errorstring";
617     }
619     $qry = new PgQuery("COMMIT;");  $qry->Exec("Sys::Write");
621     return true;
622   }