Copyright (C) 2005 James Grant Copyright (C) 2007 David Grant This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ?> _status_update() functions, to determine who's complete and who isn't //these are called on user_save for each role, if the function exists. The functions themselves //shoudln't change anything, just return the results, the user_save does the updating require_once('judge.inc.php'); require_once('volunteer.inc.php'); require_once('participant.inc.php'); function user_valid_role($role) { global $roles; if(!is_array($role)) $role = array($role); foreach($role as $r) { if(!array_key_exists($r, $roles)) return false; } return true; } function user_load($users_id, $accounts_id = false) { global $conference; /* Load user, join accounts so we also load the email, superuser flag */ //hand-code the list here because we dont want all the old stuff that hasnt been removed yet like username/password access_*, etc. if($accounts_id != false) { $accounts_id = intval($accounts_id); //get the user record for the current conference, if they have one //hmm this should be conference specific, but what if we cant find them? $q = mysql_query("SELECT users.id FROM users WHERE accounts_id = $accounts_id AND conferences_id='{$conference['id']}' LIMIT 1"); //$q = mysql_query("SELECT users.id FROM users WHERE accounts_id = $accounts_id ORDER BY conferences_id DESC LIMIT 1"); $r=mysql_fetch_object($q); $users_id=$r->id; //if we don't find a users id, then return false, means they dont have a record for this conference yet if(!$users_id) return false; } else { $users_id = intval($users_id); } $count = mysql_result(mysql_query("SELECT COUNT(*) FROM users WHERE id = $users_id"), 0); if($count == 0){ return false; } if($count > 1){ echo "ERROR: More than one user.\n"; return false; } // Load the user, we'll start with a blank slate $u = array(); // Get roles, and active/complete status for each role $u['roles'] = array(); $query = "SELECT user_roles.roles_id, user_roles.active, user_roles.complete, roles.type,roles.name FROM user_roles LEFT JOIN roles ON roles.id=user_roles.roles_id WHERE user_roles.users_id=$users_id"; $q = mysql_query($query); while(($roledata = mysql_fetch_assoc($q))) { $u['roles'][$roledata['type']] = $roledata; } // not sure if this is the best place to add it, but if the user is a student, add their emergency contacts if(array_key_exists('participant', $u['roles'])){ $u['emergencycontacts'] = array(); $fields = array('firstname', 'lastname', 'relation', 'phone1', 'phone2', 'phone3', 'phone4', 'email'); $q = mysql_query("SELECT " . implode(',', $fields) . " FROM emergencycontact WHERE users_id = $users_id ORDER BY id"); while($row = mysql_fetch_assoc($q)){ $u['emergencycontacts'][] = $row; } } // get a list of all fields relevant to this user $fieldDat = user_get_fields(array_keys($u['roles'])); // we need to separate the fields that are in the users table from those in separate tables //if its a participant, we want the registrations_id as well if(array_key_exists('participant', $u['roles'])){ $startfields=array('id', 'accounts_id', 'conferences_id','registrations_id'); } else { $startfields=array('id', 'accounts_id', 'conferences_id'); } $fields = array_unique(array_merge(array_keys($fieldDat), $startfields)); $userFields = array(); $q = mysql_query("DESCRIBE users"); while($row = mysql_fetch_assoc($q)){ $userFields[] = $row['Field']; } $userFields = array_intersect($fields, $userFields); $specialFields = array_diff($fields, $userFields); // we can start by populating the array with data out of the users table $query = "SELECT users." . implode(", users.", $userFields) . ", accounts.email FROM users JOIN accounts ON accounts.id=users.accounts_id WHERE `users`.`id`='$users_id'"; // echo "query=$query"; $q = mysql_query($query); echo mysql_error(); // Sanitize the user data $userDat = mysql_fetch_assoc($q); if(!$userDat) { echo "DEBUG: Couldnt find user/account match for users_id=$users_id"; return false; } $u = array_merge($u, $userDat); $u['id'] = intval($u['id']); $u['accounts_id'] = intval($u['accounts_id']); // Convenience $u['name'] = ($u['firstname'] ? "{$u['firstname']} " : '').$u['lastname']; // Email recipient for "to" field on emails if( ($u['firstname'] || $u['lastname']) && $u['email']) { //use their full name if we have it //if the name contains anything non-standard, we need to quote it. if(eregi("[^a-z0-9 ]",$u['name'])) $u['emailrecipient']="\"{$u['name']}\" <{$u['email']}>"; else $u['emailrecipient']="{$u['name']} <{$u['email']}>"; } else if($u['email']) { //otherwise, just their email address $u['emailrecipient']=$u['email']; } else { $u['emailrecipient']=""; } /* we dont want them thinking they can change the email, so dont include it here, its part of the account, not the user, this way they still get the 'emailrecipient' convenience variable, not not the email itself, for that, they need to access the account. */ unset($u['email']); $should_be_arrays=array(); foreach(array_keys($u['roles']) as $r) { /* Do the load routines inline, the explosion of user roles * means it's just silly to have a different function for each * one. If we get one that has a crazy amount of stuff to do, * we could move it all to a function and call it in the * switch below */ switch($r) { case 'committee': $u['ord'] = intval($u['ord']); $u['displayemail'] = ($u['displayemail'] == 'yes') ? 'yes' : 'no'; break; case 'judge': if(in_array('years_school', $fields)) $u['years_school'] = intval($u['years_school']); if(in_array('years_regional', $fields)) $u['years_regional'] = intval($u['years_regional']); if(in_array('years_national', $fields)) $u['years_national'] = intval($u['years_national']); if(in_array('willing_chair', $fields)) $u['willing_chair'] = ($u['willing_chair'] == 'yes') ? 'yes' : 'no'; if(in_array('special_award_only', $fields)) $u['special_award_only'] = ($u['special_award_only'] == 'yes') ? 'yes' : 'no'; if(in_array('cat_prefs', $fields)) $u['cat_prefs'] = (strlen($u['cat_prefs']) > 0) ? unserialize($u['cat_prefs']) : array(); if(in_array('div_prefs', $fields)) $u['div_prefs'] = (strlen($u['div_prefs']) > 0) ? unserialize($u['div_prefs']) : array(); if(in_array('divsub_prefs', $fields)) $u['divsub_prefs'] = (strlen($u['divsub_prefs']) > 0) ? unserialize($u['divsub_prefs']) : array(); // $u['expertise_other'] = $u['expertise_other']; //if it hasnt been parsed/converted yet if(!is_array($u['languages'])) $u['languages'] = (strlen($u['languages']) > 0) ? unserialize($u['languages']) : array(); // $u['highest_psd'] = $u['highest_psd']; /* Sanity check the arrays, make sure they are arrays */ $should_be_arrays = array('cat_prefs','div_prefs', 'divsub_prefs','languages','special_awards','time_availability'); break; case 'sponsor': $u['sponsors_id'] = intval($u['sponsors_id']); if($u['sponsors_id']) { $q=mysql_query("SELECT * FROM sponsors WHERE id='{$u['sponsors_id']}'"); $u['sponsor']=mysql_fetch_assoc($q); } break; case 'volunteer': //if it hasnt been parsed/converted yet if(!is_array($u['languages'])) $u['languages'] = (strlen($u['languages']) > 0) ? unserialize($u['languages']) : array(); $should_be_arrays = array('languages'); break; default: /* Nothing to do for all other roles */ break; } } foreach($should_be_arrays as $k) { if(in_array($val, $fields)){ if(!is_array($u[$k])) $u[$k] = array(); } } // now let's populate the fields that are not stored in the users table foreach($specialFields as $field){ switch($field){ case 'special_awards': $selected = array(); $q = mysql_query("SELECT award_awards_id aaid FROM judges_specialaward_sel WHERE users_id = {$u['id']}"); while($r = mysql_fetch_assoc($q)){ $selected[] = $r['aaid']; } $u['special_awards'] = $selected; break; case 'available_times': // a rather complicated match-up, as they're linked by time values, not by record id's $times = get_judging_timeslots($u['conferences_id']); $q = mysql_query("SELECT * FROM judges_availability WHERE users_id=\"{$u['id']}\""); $sel = array(); while($r=mysql_fetch_object($q)) { foreach($times as $t) { if($r->start == $t['starttime'] && $r->end == $t['endtime'] && $r->date == $t['date']) $sel[] = $t['id']; } } $items = array(); foreach($times as $t) { $st = substr($t['starttime'], 0, 5); $end = substr($t['endtime'], 0, 5); if(in_array($t['id'], $sel)){ $items[] = $t['id']; } } $u['available_times'] = $items; break; case 'available_events': $q1 = mysql_query("SELECT schedule_id FROM `schedule_users_availability_link` sual JOIN schedule ON schedule.id = sual.schedule_id WHERE users_id = {$u['id']} AND schedule.conferences_id = '{$u['conferences_id']}'"); $ids = array(); while($row = mysql_fetch_assoc($q1)){ $ids[] = $row['schedule_id']; } $u['available_events'] = $ids; break; case 'volunteer_positions': $q1 = mysql_query("SELECT volunteer_positions_id AS vpid FROM volunteer_positions_signup WHERE users_id = {$u['id']} AND conferences_id = {$u['conferences_id']}"); $ids = array(); while($row = mysql_fetch_assoc($q1)){ $ids[] = $row['vpid']; } $u['volunteer_positions'] = $ids; break; } } // the role completion check must be done at this end of the code, because // the check itself depends on other elements of the user object being defined foreach($u['roles'] as $roleType => $data){ user_check_role_complete($u, $roleType); } /* Do this assignment without recursion :) */ unset($u['orig']); $orig = $u; $u['orig'] = $orig; $u['required_fields']=user_all_fields_required(array_keys($u['roles'])); return $u; } function user_load_by_accounts_id($accounts_id) { return user_load(0, $accounts_id); } function user_load_by_email($email) { /* Find the accounts_id for the email, regardless of deleted status */ $e = mysql_real_escape_string($email); $q = mysql_query("SELECT accounts_id FROM users WHERE email='$e' OR username='$e'"); if(mysql_num_rows($q) == 1) { $i = mysql_fetch_assoc($q); return user_load_by_accounts_id($i['accounts_id']); } return false; } function user_get_role_fields($role){ global $conference, $config; switch($role){ case 'committee': $fields = array('emailprivate','ord','displayemail'); break; case 'judge': if($conference['type'] == 'scienceolympics'){ $fields = array('languages'); }else{ $fields = array('years_school','years_regional','years_national', 'willing_chair','special_award_only', 'cat_prefs','div_prefs','divsub_prefs', 'expertise_other','languages', 'highest_psd'); } break; case 'participant': $fields = array('grade', 'schools_id', 'medicalalert');//, 'registrations_id'); if($config['participant_student_tshirt'] == "yes"){ $fields[] = 'tshirt'; } if($config['participant_student_foodreq'] == "yes"){ $fields[] = 'foodreq'; } if($config['participant_student_pronunciation'] == "yes"){ $fields[] = 'pronunciation'; } break; case 'fair': $fields = array('fairs_id'); break; case 'sponsor': $fields = array('sponsors_id','primary','position','notes'); break; case 'teacher': $fields = array('schools_id'); break; case 'principal': $fields = array('schools_id'); break; case 'volunteer': $fields = array('languages'); break; default: $fields = array(); } return $fields; } function user_get_field_info($noConference = false){ global $conference; $returnval = array( 'salutation' => array('label' => 'Salutation', 'group' => 'Personal Information'), 'firstname' => array('label' => 'First Name', 'group' => 'Personal Information'), 'lastname' => array('label' => 'Last Name', 'group' => 'Personal Information'), 'sex' => array('label' => 'Sex', 'group' => 'Personal Information'), 'phonehome' => array('label' => 'Home Phone', 'group' => 'Contact Information'), 'phonework' => array('label' => 'Work Phone', 'group' => 'Contact Information'), 'phonecell' => array('label' => 'Cell Phone', 'group' => 'Contact Information'), 'fax' => array('label' => 'Fax Number', 'group' => 'Contact Information'), 'organization' => array('label' => 'Organization', 'group' => 'Contact Information'), 'birthdate' => array('label' => 'Date of Birth', 'group' => 'Personal Information'), 'lang' => array('label' => 'Primary Language', 'group' => 'Contact Information'), 'address' => array('label' => 'Address', 'group' => 'Contact Information'), 'address2' => array('label' => '', 'group' => 'Contact Information'), 'city' => array('label' => 'City', 'group' => 'Contact Information'), 'province' => array('label' => 'Province', 'group' => 'Contact Information'), 'postalcode' => array('label' => 'Postal Code', 'group' => 'Contact Information'), 'firstaid' => array('label' => 'First Aid', 'group' => 'Personal Information'), 'cpr' => array('label' => 'CPR', 'group' => 'Personal Information'), 'displayemail' => array('label' => 'Display Email', 'group' => 'Personal Information'), 'sponsors_id' => array('label' => 'Sponsor', 'group' => 'Sponsors'), 'primary' => array('label' => 'Primary Contact', 'group' => 'Sponsors'), 'position' => array('label' => 'Position', 'group' => 'Sponsors'), 'notes' => array('label' => 'Notes', 'group' => 'Sponsors'), 'schools_id' => array('label' => 'School', 'group' => 'Personal Information'), 'grade' => array('label' => 'Grade', 'group' => 'Personal Information'), 'special_awards' => array('label' => 'Special Awards', 'group' => 'Judges'), 'volunteer_positions' => array('label' => 'Volunteer Positions', 'group' => 'Volunteers'), 'foodreq' => array('label' => 'Special Food Requirements', 'group' => 'Personal Information'), 'tshirt' => array('label' => 'T-shirt Size', 'group' => 'Personal Information'), 'medicalalert' => array('label' => 'Medical Alert Info', 'group' => 'Personal Information'), 'emergencycontacts' => array('label' => 'Emergency Contacts', 'group' => 'Personal Information'), 'pronunciation' => array('label' => 'Name Pronunciation Key', 'group' => 'Personal Information') ); if($noConference){ $returnval['cat_prefs'] = array('label' => 'Category Preferences', 'group' => 'Judges'); $returnval['div_prefs'] = array('label' => 'Division Preferences', 'group' => 'Judges'); $returnval['divsub_prefs'] = array('label' => 'Subdivision Preferences', 'group' => 'Judges'); $returnval['years_school'] = array('label' => 'Years experience judging at school level', 'group' => 'Judges'); $returnval['years_regional'] = array('label' => 'Years experience judging at regional level', 'group' => 'Judges'); $returnval['years_national'] = array('label' => 'Years experience judging at national level', 'group' => 'Judges'); $returnval['willing_chair'] = array('label' => 'Willing to lead a judging team', 'group' => 'Judges'); $returnval['special_award_only'] = array('label' => 'Judging only for a special award', 'group' => 'Judges'); $returnval['highest_psd'] = array('label' => 'Highest post-secondary degree', 'group' => 'Judges'); $returnval['expertise_other'] = array('label' => 'Other areas of expertise', 'group' => 'Judges'); $returnval['available_times'] = array('label' => 'Times Available', 'group' => 'Judges'); $returnval['available_events'] = array('label' => 'Event Availability', 'group' => 'Judges,Volunteers'); }else{ switch($conference['type']){ case 'sciencefair': $returnval['cat_prefs'] = array('label' => 'Category Preferences', 'group' => 'Judges'); $returnval['div_prefs'] = array('label' => 'Division Preferences', 'group' => 'Judges'); $returnval['divsub_prefs'] = array('label' => 'Subdivision Preferences', 'group' => 'Judges'); $returnval['years_school'] = array('label' => 'Years experience judging at school level', 'group' => 'Judges'); $returnval['years_regional'] = array('label' => 'Years experience judging at regional level', 'group' => 'Judges'); $returnval['years_national'] = array('label' => 'Years experience judging at national level', 'group' => 'Judges'); $returnval['willing_chair'] = array('label' => 'Willing to lead a judging team', 'group' => 'Judges'); $returnval['special_award_only'] = array('label' => 'Judging only for a special award', 'group' => 'Judges'); $returnval['highest_psd'] = array('label' => 'Highest post-secondary degree', 'group' => 'Judges'); $returnval['expertise_other'] = array('label' => 'Other areas of expertise', 'group' => 'Judges'); $returnval['available_times'] = array('label' => 'Times Available', 'group' => 'Judges'); $returnval['available_events'] = array('label' => 'Event Availability', 'group' => 'Volunteers'); $returnval['languages'] = array('label' => 'Spoken Languages', 'group' => 'Judges,Volunteers'); break; case 'scienceolympics': $returnval['available_events'] = array('label' => 'Event Availability', 'group' => 'Judges,Volunteers'); $returnval['languages'] = array('label' => 'Spoken Languages', 'group' => 'Judges,Volunteers'); break; } } return $returnval; } function user_role_field_required($role, $fieldname){ $returnval = 0; $requiredFields = array( 'judge' => array('years_school','years_regional','years_national','languages'), 'participant' => array('grade','schools_id'), 'fair' => array('fairs_id'), 'sponsor' => array('sponsors_id','primary','position'), 'volunteer' => array('languages') ); if(array_key_exists($role, $requiredFields)){ if(in_array($fieldname, $requiredFields[$role])){ $returnval = 1; } } return $returnval; } // accepts either an array of roles (eg. {'judge', 'teacher', 'foo'}), a single one as a string (eg. 'judge'), or a null value (no roles at all) function user_get_fields($userRoles = null){ global $roles, $conference, $config; if($userRoles == null){ $userRoles = array(); }else if(!is_array($userRoles)){ // assume that they passed a string identifying a single role (eg. "judge") $userRoles = array($userRoles); } // scrub for only valid roles, and fetch their special fields $enabledFields = array(); $requiredFields = array('firstname', 'lastname'); $roleFields = array(); foreach($userRoles as $role){ if(array_key_exists($role, $roles)){ $requiredFields = array_merge($requiredFields, user_fields_required($role)); $enabledFields = array_merge($enabledFields, user_fields_enabled($role)); $roleFields[$role] = user_get_role_fields($role); } } // build a list of all fields that are applicable to this user, and assemble them into an array $fields = array(); foreach($requiredFields as $field){ if(!array_key_exists($field, $fields)){ $fields[$field] = array( 'field' => $field, 'required' => 1 ); } } foreach($roleFields as $role => $fieldList){ foreach($fieldList as $field){ if(!array_key_exists($field, $fields)){ $fields[$field] = array( 'field' => $field, 'required' => user_role_field_required($role, $field) ); } } } foreach($enabledFields as $field){ if(!array_key_exists($field, $fields)){ $fields[$field] = array( 'field' => $field, 'required' => 0 ); } } // get the field types $query = mysql_query("DESCRIBE users"); $fieldType = array(); while($row = mysql_fetch_assoc($query)){ $fieldType[$row['Field']] = $row['Type']; } $fieldInfo = user_get_field_info(); foreach($fields as $fieldName => $field){ $ftype = $fieldType[$fieldName]; if(array_key_exists($fieldName, $fieldInfo)){ $fields[$fieldName]['display'] = i18n($fieldInfo[$fieldName]['label']); $fields[$fieldName]['group'] = i18n($fieldInfo[$fieldName]['group']); } switch($fieldName){ case 'languages': $fields[$fieldName]['type'] = 'multiselect'; $fields[$fieldName]['options'] = $config['languages']; break; case 'lang': $fields[$fieldName]['type'] = 'singleselect'; $fields[$fieldName]['options'] = $config['languages']; break; case 'cat_prefs': $fields[$fieldName]['description'] = 'Preference levels for judging individual project categories'; $fields[$fieldName]['type'] = 'singleselectlist'; $fields[$fieldName]['options'] = array(-2 => 'Very Low', -1 => 'Low', 0 => 'Indifferent', 1 => 'Medium', 2 => 'High'); $fields[$fieldName]['entries'] = array(); $query = mysql_query("SELECT id, category FROM projectcategories WHERE conferences_id = {$conference['id']}"); while($row = mysql_fetch_assoc($query)){ $fields[$fieldName]['entries'][$row['id']] = $row['category']; } break; case 'div_prefs': $divquery = mysql_query("SELECT * FROM projectdivisions WHERE conferences_id = {$conference['id']}"); $fields[$fieldName]['entries'] = array(); $fields[$fieldName]['type'] = 'singleselectlist'; $fields[$fieldName]['options'] = array(1 => 'Very Little', 2 => 'Little', 3 => 'Average', 4 => 'Knowledgable', 5 => 'Very Knowledgable'); while($divdata = mysql_fetch_assoc($divquery)){ $divid = $divdata['id']; $fields[$fieldName]['entries'][$divdata['id']] = $divdata['division']; } break; case 'divsub_prefs': $fields[$fieldName]['entries'] = array(); $fields[$fieldName]['description'] = "Preference levels for subdivisions of existing divisions. If a division has subdivisions, they"; $fields[$fieldName]['description'] .= " are listed in an array which is stored within the 'entries' array at the index of the division's id."; $fields[$fieldName]['description'] .= " eg. If a division 'foo' has an id of '3' and the subdivisions 'bar1' and 'bar2', then entries[3]"; $fields[$fieldName]['description'] .= " will be an array: {0 => 'bar1', 1 => 'bar2'}."; $fields[$fieldName]['type'] = 'singleselectlist'; $fields[$fieldName]['options'] = array(1 => 'Very Little', 2 => 'Little', 3 => 'Average', 4 => 'Knowledgable', 5 => 'Very Knowledgable'); $divquery = mysql_query("SELECT * FROM projectdivisions WHERE conferences_id = {$conference['id']}"); while($divdata = mysql_fetch_assoc($divquery)){ $divid = $divdata['id']; $subset = array(); $subdivquery = mysql_query("SELECT * FROM projectsubdivisions WHERE conferences_id = {$conference['id']} AND projectdivisions_id = $divid"); while($subdivdata = mysql_fetch_assoc($subdivquery)){ $subset[] = $subdivdata['subdivision']; } if(count($subset)){ $fields[$fieldName]['entries'][$divdata['id']] = $subset; } } break; case 'tshirt': $fields[$fieldName]['description'] = "T-Shirt size of participant"; $fields[$fieldName]['type'] = 'singleselect'; $fields[$fieldName]['options'] = array( 'none' => 'None', 'xsmall' => 'X-Small', 'small' => 'Small', 'medium' => 'Medium', 'large' => 'Large', 'xlarge' => 'X-large' ); break; default: if(!strncasecmp($ftype, "varchar", 7)){ $parts = explode(')', $ftype); $parts = explode('(', $parts[0]); $fields[$fieldName]['type'] = $parts[0] . ':' . $parts[1]; }elseif(!strncasecmp($ftype, "char", 4)){ $parts = explode(')', $ftype); $parts = explode('(', $parts[0]); $fields[$fieldName]['type'] = $parts[0] . ':' . $parts[1]; }else if(!strncasecmp($ftype, "enum", 4)){ $fields[$fieldName]['type'] = 'singleselect'; $fields[$fieldName]['options'] = array(); $parts = explode("'", $ftype); for($n = 1; $n < count($parts); $n += 2){ $fields[$fieldName]['options'][$parts[$n]] = ucfirst($parts[$n]); } }else if(!strcmp($ftype, "date")){ $fields[$fieldName]['type'] = $fieldType[$fieldName]; }else if(!strncmp($ftype, "tinyint", 7)){ $fields[$fieldName]['type'] = 'integer'; }else if(!strncmp($ftype, "tinytext", 8)){ $fields[$fieldName]['type'] = 'text'; }else if(!strncmp($ftype, "int", 3)){ $fields[$fieldName]['type'] = $fieldType[$fieldName]; }else{ $fields[$fieldName]['type'] = "ERROR:" . $fieldType[$fieldName]; } } } /******* Now we add fields that are not stored directly in the users table ********/ switch($conference['type']){ case 'sciencefair': $specialFieldRoles = array( 'special_awards' => array('judge'), 'available_times' => array('judge'), 'available_events' => array('volunteer'), 'volunteer_positions' => array('volunteer'), 'emergencycontacts' => array('participant') ); break; case 'scienceolympics': $specialFieldRoles = array( 'special_awards' => array(), 'available_times' => array(), 'available_events' => array('judge', 'volunteer'), 'volunteer_positions' => array('volunteer'), 'emergencycontacts' => array('participant') ); break; default: $specialFieldRoles = array(); } // get the special_awards info if necessary if(count(array_intersect($specialFieldRoles['special_awards'], $userRoles)) > 0){ $fields['special_awards'] = array(); $fields['special_awards']['field'] = 'special_awards'; $fields['special_awards']['display'] = i18n($fieldInfo['special_awards']['label']); $fields['special_awards']['group'] = i18n($fieldInfo['special_awards']['group']); $fields['special_awards']['type'] = 'multiselect'; $fields['special_awards']['options'] = get_special_awards($conference['id']); } // get the available_times info if available if(count(array_intersect($specialFieldRoles['available_times'], $userRoles)) > 0){ $fields['available_times'] = array(); $fields['available_times']['field'] = 'available_times'; $fields['available_times']['display'] = i18n($fieldInfo['available_times']['label']); $fields['available_times']['group'] = i18n($fieldInfo['available_times']['group']); $fields['available_times']['type'] = 'multiselect'; $fields['available_times']['options'] = array(); $timeslots = get_judging_timeslots($conference['id']); foreach($timeslots as $slot){ $fields['available_times']['options'][$slot['id']] = $slot; } } // get the available_events if available if(count(array_intersect($specialFieldRoles['available_events'], $userRoles)) > 0){ $fields['available_events'] = array(); $fields['available_events']['field'] = 'available_events'; $fields['available_events']['display'] = i18n($fieldInfo['available_events']['label']); $fields['available_events']['group'] = i18n($fieldInfo['available_events']['group']); $fields['available_events']['type'] = 'multiselect'; $fields['available_events']['options'] = array(); $q=mysql_query("SELECT schedule.id, schedule.date, schedule.hour, schedule.minute, schedule.duration, events.name FROM schedule JOIN events ON schedule.events_id=events.id WHERE schedule.conferences_id='{$conference['id']}'"); while($row = mysql_fetch_assoc($q)){ $fields['available_events']['options'][$row['id']] = $row; //$row['name'] . ' ' . $row['date'] . ', ' . $row['hour'] . ':' . $row['minute'] . ':00 (' . $row['duration'] . ' ' . i18n('minutes') . ')'; } } // get the available volunteer positions as well if(count(array_intersect($specialFieldRoles['volunteer_positions'], $userRoles)) > 0){ $fields['volunteer_positions'] = array(); $fields['volunteer_positions']['field'] = 'volunteer_positions'; $fields['volunteer_positions']['display'] = i18n($fieldInfo['volunteer_positions']['label']); $fields['volunteer_positions']['group'] = i18n($fieldInfo['volunteer_positions']['group']); $fields['volunteer_positions']['type'] = 'multiselect'; $fields['volunteer_positions']['options'] = array(); $q = mysql_query("SELECT * FROM volunteer_positions WHERE conferences_id = {$conference['id']}"); while($row = mysql_fetch_assoc($q)){ $fields['volunteer_positions']['options'][$row['id']] = $row; //$row['name']; } } // and also the emergency contacts info if(count(array_intersect($specialFieldRoles['emergencycontacts'], $userRoles)) > 0){ $fields['emergencycontacts'] = array(); $fields['emergencycontacts']['field'] = 'emergencycontacts'; $fields['emergencycontacts']['display'] = i18n($fieldInfo['emergencycontacts']['label']); $fields['emergencycontacts']['group'] = i18n($fieldInfo['emergencycontacts']['group']); $fields['emergencycontacts']['type'] = 'table'; $fields['emergencycontacts']['tablefields'] = array('firstname', 'lastname', 'relation', 'phone1', 'phone2', 'phone3', 'phone4', 'email'); $fields['emergencycontacts']['description'] = "A list of records for the emergency contact information for a student. Each record has a list of values for the fields listed in the \"tablefields\" record listed here. e.g. [['firstname':'Bob', 'lastname':'Smith', ...],['firstname':'John', 'lastname':'doe' ...], ...]"; } return $fields; } // this depends on the naming convention that any given role that needs a completion check // will have a function called _status_update, which updates their status with the // current session data and returns 'complete' or 'incomplete' accordingly. // I love the fact that this remark took more characters than the function. function user_check_role_complete(&$u, $role){ $func = $role . '_status_update'; if(function_exists($func)){ $result = $func($u); // that's right, func(u)! }else{ $result = 'complete'; } return $result; } // save the user in their current state. returns 'ok' on success, error message otherwise function user_save(&$u) { global $conference; global $roles; $errMessage = ''; /* Sanity check */ if($u['conferences_id'] != $u['orig']['conferences_id']) { return "The user's conference changed. Can't save a user to a difference conference, use user_dupe to copy the user to a new conference."; } // Update 'active' status for all roles $new_roles = array_keys($u['roles']); foreach($new_roles as $r) { mysql_query("UPDATE user_roles SET active='{$u['roles'][$r]['active']}' WHERE roles_id='{$u['roles'][$r]['roles_id']}' AND users_id='{$u['id']}'"); if(mysql_error() != '') break; } if(mysql_error() != '') return "SQLERR1: " . mysql_error(); $fields = array('salutation','firstname','lastname', 'phonehome','phonework','phonecell','fax','organization', 'address','address2','city','province','postalcode','sex', 'firstaid', 'cpr', 'lang', 'notes','birthdate'); /* Merge fields as necessary, build a big list of fields to save */ foreach($new_roles as $r) { $fields = array_merge($fields, user_get_role_fields($r)); } $fields = array_unique($fields); $set = ""; $resetNamecheck = false; foreach($fields as $f) { // re-indexing fields that might be mis-entered. Add additional field names to the array as needed. if(in_array($f, array('languages'))){ $u[$f] = array_values($u[$f]); } if($u[$f] == $u['orig'][$f]) continue; if($f == 'firstname' || $f == 'lastname') $resetNamecheck = true; if($set != "") $set .=','; if($u[$f] == NULL) { $set .= "$f=NULL"; continue; } if(is_array($u[$f])) $data = mysql_real_escape_string(serialize($u[$f])); else $data = mysql_real_escape_string($u[$f]); $set .= "$f='$data'"; } // if they've changed their first or last name, update the "namecheck_complete" flag no "no" if($resetNamecheck){ $set .= ",namecheck_complete = 'no'"; } // now update all of those fields if($set != "") { $query = "UPDATE users SET $set WHERE id='{$u['id']}'"; mysql_query($query); } if(mysql_error() != '') return "SQLERR2: " . mysql_error(); // Save the other user data that is not stored in the users table if( // if this user has an altered special awards selection, it needs to be saved array_key_exists('special_awards', $u) ){ mysql_query("DELETE FROM judges_specialaward_sel WHERE users_id = {$u['id']}"); if(count($u['special_awards']) > 0){ $query = "INSERT INTO judges_specialaward_sel (users_id, award_awards_id) VALUES (" . $u['id'] . ", "; $query .= implode('), (' . $u['id'] . ', ', $u['special_awards']); $query .= ")"; // echo $query; mysql_query($query); } } if(mysql_error() != '') return "SQLERR3: " . mysql_error(); if( // if this user has an altered available judging times selection, we need to save it array_key_exists('available_times', $u) ){ mysql_query("DELETE FROM judges_availability WHERE users_id='{$u['id']}'"); $query = 'SELECT date, starttime, endtime FROM judges_timeslots WHERE id IN ('; $ids = $u['available_times']; $query .= implode(',', $ids) . ')'; if(count($ids) > 0){ $insertVals = array(); $results = mysql_query($query); while($row = mysql_fetch_assoc($results)){ $insertVals[] = "({$u['id']},'{$row['date']}','{$row['starttime']}','{$row['endtime']}')"; } if(count($insertVals) > 0){ $query = "INSERT INTO judges_availability (users_id, `date`,`start`,`end`) VALUES "; $query .= implode(',', $insertVals); } mysql_query($query); } } if(mysql_error() != '') return "SQLERR3: " . mysql_error(); if( // if this user has an altered event availability selection, we need to save it array_key_exists('available_events', $u) ){ mysql_query("DELETE FROM schedule_users_availability_link WHERE users_id = {$u['id']}"); if(count($u['available_events']) > 0){ $eventList = array_unique($u['available_events']); foreach($eventList as $eventId){ $query = "INSERT INTO schedule_users_availability_link (users_id, schedule_id) VALUES (" . $u['id'] . ", " . $eventId . ")"; mysql_query($query); } } } if(mysql_error() != '') return "SQLERR4: " . mysql_error(); if( // if this user has volunteer positions, or at least, an empty array for volunteer positions... array_key_exists('volunteer_positions', $u) ){ mysql_query("DELETE FROM volunteer_positions_signup WHERE users_id = {$u['id']}"); if(count($u['volunteer_positions']) > 0){ $query = "INSERT INTO volunteer_positions_signup (users_id, conferences_id, volunteer_positions_id) VALUES({$u['id']},{$conference['id']},"; $query .= implode('), (' . $u['id'] . ', ' . $conference['id'] . ', ', $u['volunteer_positions']); $query .= ")"; mysql_query($query); } } if(mysql_error() != '') return "SQLERR5: " . mysql_error(); foreach($new_roles as $r) { $result = user_check_role_complete($u, $r); if($result == 'complete'){ mysql_query("UPDATE user_roles SET complete='yes' WHERE roles_id='{$u['roles'][$r]['roles_id']}' AND users_id='{$u['id']}'"); echo mysql_error(); }else{ mysql_query("UPDATE user_roles SET complete='no' WHERE roles_id='{$u['roles'][$r]['roles_id']}' AND users_id='{$u['id']}'"); echo mysql_error(); } } if( // if this user has emergency contacts ... // not sure if this is the best place to add it, but if the user is a student, add their emergency contacts array_key_exists('emergencycontacts', $u) ){ mysql_query("DELETE FROM emergencycontact WHERE users_id = {$u['id']}"); if(mysql_error() != '') return "SQLERR6: " . mysql_error(); if(count($u['emergencycontacts']) > 0){ $query = "INSERT INTO emergencycontact (users_id, firstname, lastname, relation, phone1, phone2, phone3, phone4, email, conferences_id) VALUES "; $queryParts = array(); foreach($u['emergencycontacts'] as $contact){ $queryParts[] = "(". $u['id'] . ",'" . $contact['firstname'] . "','" . $contact['lastname'] . "','" . $contact['relation'] . "','" . $contact['phone1'] . "','" . $contact['phone2'] . "','" . $contact['phone3'] . "','" . $contact['phone4'] . "','" . $contact['email'] . "'," . $conference['id'] . ") "; } $query .= implode(',', $queryParts); mysql_query($query); } if(mysql_error() != '') return "SQLERR7: " . mysql_error(); } if($u['orig']['grade'] != $u['grade'] && $u['registrations_id']){ // their grade has changed and they're connected to a registration. Let's update // the registration's grade level to match if necessary $category = getProjectCategory($u['registrations_id']); if($category !== null){ mysql_query("UPDATE projects SET projectcategories_id = $category WHERE registrations_id = {$u['registrations_id']}"); if(mysql_error() != '') return "SQLERR8: " . mysql_error(); } } /* Record all the data in orig that we saved so subsequent * calls to user_save don't try to overwrite data already * saved to the database */ unset($u['orig']); $orig = $u; $u['orig'] = $orig; // and return a notification of success return 'ok'; } // mark the role as complete if it's qualifications are met function user_complete_role($users_id, $role){ // avoid SQL injections $role = mysql_real_escape_string($role); $users_id *= 1; // get the id of the role $row = mysql_fetch_assoc(mysql_query("SELECT id FROM roles WHERE type = '$role'")); if(!is_array($row)){ return false; } $roles_id = $row['id']; // does this user have the given role? $row = mysql_fetch_array(mysql_query("SELECT * FROM user_roles WHERE users_id = $users_id AND roles_id = $roles_id")); if(!is_array($row)){ return false; } // ok, it's a valid role and the specified user has it. Now let's see if we can mark it as complete $user = user_load($users_id); $result = user_check_role_complete($user, $role); if($result == 'ok'){ return true; }else{ return false; } } // get the display name that would show up on trophies and the like if this is a student function user_get_displayname($users_id){ $returnval = null; $u = user_load($users_id); if(is_array($u)){ $returnval = $u['firstname'] . ' ' . $u['lastname']; } return $returnval; } // mark the user's display name as being correct // TODO - in the future, this should probably be reset to unconfirmed if the user function user_confirm_displayname($users_id){ mysql_query("UPDATE users SET namecheck_complete = 'yes' WHERE id = $users_id"); } // return a yes/no answer as to whether or not the user's display name has been confirmed function user_displayname_confirmed($users_id){ $returnval = null; $q = mysql_query("SELECT namecheck_complete FROM users WHERE id = $users_id"); if($row = mysql_fetch_assoc($q)){ $returnval = $row['namecheck_complete']; } return $returnval; } // mark the role as being incomplete - not a verb sadly function user_uncomplete_role($users_id, $role){ // avoid SQL injections $role = mysql_real_escape_string($role); $users_id *= 1; // get the id of the role $row = mysql_fetch_assoc(mysql_query("SELECT id FROM roles WHERE type = '$role'")); if(!is_array($row)){ return false; } $roles_id = $row['id']; // and update said role for the given user id return mysql_query("UPDATE user_roles SET complete = 'no' WHERE users_id = $users_id AND roles_id = $roles_id"); } // activate the specified role for the specified user if they have that role function user_activate_role($users_id, $roles_id){ // Make sure the role is indeed there $query = "SELECT * FROM user_roles WHERE roles_id = $roles_id AND users_id = $users_id"; $data = mysql_fetch_array(mysql_query($query)); if(!is_array($data)){ // can't be activated if you don't have it! return false; } return mysql_query("UPDATE user_roles SET active='yes' WHERE users_id = $users_id AND roles_id = $roles_id"); } // deactivate the specified role for the specified user if they have that role function user_deactivate_role($users_id, $roles_id){ // Make sure the role is indeed there $query = "SELECT * FROM user_roles WHERE roles_id = $roles_id AND users_id = $users_id"; $data = mysql_fetch_array(mysql_query($query)); if(!is_array($data)){ // can't be deactivated if you don't have it! return false; } return mysql_query("UPDATE user_roles SET active='no' WHERE users_id = $users_id AND roles_id = $roles_id"); } // Remove a role for a user. // now just a skin on top of account_remove_role function user_remove_role(&$u, $role) { global $roles; $result = account_remove_role($u['accounts_id'], $roles[$role]['id'], $u['conferences_id']); // Delete the role if(array_key_exists($role, $u['roles'])) { unset($u['roles'][$role]); } return $result; } /* If role is specified, just delete the role from the user. * If not, delete the whole user, all roles */ function user_delete($u, $role=false) { $finish_delete = false; if(!is_array($u)) { $u = user_load($u); } if($role != false) { account_remove_role($u['accounts_id'], $roles[$role]['id'], $u['conferences_id']); if(array_key_exists($role, $u['roles'])) { unset($u['roles'][$role]); } if(count($u['roles']) == 0) { /* No roles left, finish the delete */ $finish_delete = true; } } else { /* Delete the whole user, every role */ foreach(array_keys($u['roles']) as $r){ account_remove_role($u['accounts_id'], $roles[$r]['id'], $u['conferences_id']); if(array_key_exists($role, $u['roles'])) { unset($u['roles'][$role]); } } $finish_delete = true; } if($finish_delete) { mysql_query("UPDATE users SET deleted='yes', deleteddatetime=NOW() WHERE id='{$u['id']}'"); return true; } /* User had some other role, so delete was not completed. */ return false; } /* Purge functions. These completely eliminate all traces of a user from the * database. This action cannot be undone. We prefer the committee to use the * "delete" functions, which simply mark the account as "deleted". */ function user_purge($u, $role=false) { /* Delete the user, then completely delete them from * the DB if delete returns true, that is, if there's * no other role blocking the delete/purge */ $finish_purge = user_delete($u, $role); if($finish_purge == true) { mysql_query("DELETE FROM users WHERE id='{$u['id']}'"); return true; } /* Not purged, some other role existed */ return false; } /* Duplicate a row in the users table, or any one of the users_* tables. */ function user_dupe_row($db, $key, $val, $newval) { global $conference; $nullfields = array('deleteddatetime'); /* Fields that can be null */ $q = mysql_query("SELECT * FROM $db WHERE $key='$val'"); if(mysql_num_rows($q) != 1) { echo "ERROR duplicating row in $db: $key=$val NOT FOUND.\n"; exit; } $i = mysql_fetch_assoc($q); $i[$key] = $newval; foreach($i as $k=>$v) { if($v == NULL && in_array($k, $nullfields)) $i[$k] = 'NULL'; else if($k == 'conferences_id') $i[$k] = $conference['id']; else $i[$k] = '\''.mysql_escape_string($v).'\''; } $keys = '`'.join('`,`', array_keys($i)).'`'; $vals = join(',', array_values($i)); $q = "INSERT INTO $db ($keys) VALUES ($vals)"; // echo "Dupe Query: [$q]"; $r = mysql_query($q); echo mysql_error(); $id = mysql_insert_id(); return $id; } /* Returns true if loaded user ($u) is allowed to add role $role to their * profile. THis is intended as a last-stop mechanism, preventing, for example * a student from co-existing with any other role . */ function user_add_role_allowed(&$u, $role) { foreach(array_keys($u['orig']['roles']) as $ur) { switch($ur) { case 'participant': /* Student cant' add any other role */ return false; default: if($role == 'particpant') { /* No role can add the participant role */ return false; } /* All other roles can coexist (even the fair role) */ break; } } return true; } // Set the user's school to the one specifed. Verifying the school code is needed // here, as it will be called from both the web interface and the API. // returns true on success, false otherwise function user_set_school($u, $schoolId, $schoolCode){ $returnval = false; // make sure the id and code match $tally = mysql_result(mysql_query("SELECT COUNT(*) FROM schools WHERE id = '$schoolId' AND accesscode = '$schoolCode'"), 0); if($tally == 1){ if(mysql_query("UPDATE users SET schools_id = $schoolId WHERE id = " . $u['id'])){ $u['schools_id'] = $schoolId; $returnval = true; } } return $returnval; } // Add a role for a user. // now just a skin on top of account_add_role function user_add_role(&$u, $role, $password = null){ $row = mysql_fetch_assoc(mysql_query("SELECT conferences_id FROM users WHERE id = " . $u['id'])); $conferences_id = $row['conferences_id']; $row = mysql_fetch_assoc(mysql_query("SELECT id FROM roles WHERE `type` = '$role'")); $roleId = $row['id']; $result = account_add_role($u['accounts_id'], $roleId, $conferences_id, $password); if($result == 'ok'){ // we need this "if" because account_add_role will return "ok" if they already have this role //only update the session if the logged in user is the same as the one we're editing if($u['id']==$_SESSION['users_id']) { if(!in_array($role, $_SESSION['roles'])){ $_SESSION['roles'][] = $role; } } // also, update the user: $u = user_load($u['id']); } return $result; } function user_create($accounts_id, $conferences_id=0) { global $config, $conference; if($conferences_id == 0) $conferences_id = $conference['id']; /* Make sure the user doesn't already exist */ $q = mysql_query("SELECT id FROM users WHERE accounts_id='$accounts_id' AND conferences_id='$conferences_id'"); echo mysql_error(); if(mysql_num_rows($q)) { return "ERROR: user_create called for a user that already exists.\n"; } $fields = array( 'accounts_id' => $accounts_id, 'conferences_id' => $conferences_id, ); /* Get old user data if available */ $results = mysql_fetch_assoc(mysql_query("SELECT * FROM users WHERE accounts_id = '$accounts_id' ORDER BY id DESC LIMIT 1")); if(is_array($results)){ $skipfields = array('id', 'created', 'lastlogin', 'year', 'accounts_id', 'conferences_id', 'deleted', 'deleteddatetime', 'registrations_id', 'grade'); foreach($results as $fname => $value){ if(!in_array($fname, $skipfields) && $value != null){ $fields[$fname] = $value; } } } /* Create the user */ $fieldList = array_keys($fields); $query = "INSERT INTO users(`created`, `" . implode('`,`', $fieldList) . "`) VALUES(NOW(), '" . implode("','", $fields) . "')"; mysql_query($query); $id = mysql_insert_id(); /* Return a loaded user with no roles */ return user_load($id); } /* Perform some checks. Make sure the person is logged in, and that their * password hasn't expired (the password_expired var is set in the login page) */ function user_auth_required($all_required = array(), $one_required = array()) { global $config; $ok = true; unset($_SESSION['request_uri']); if(!isset($_SESSION['roles']) || !isset($_SESSION['accounts_id'])) { message_push(error(i18n("You must login to view that page"))); $_SESSION['request_uri'] = $_SERVER['REQUEST_URI']; header("location: {$config['SFIABDIRECTORY']}/user_login.php"); exit; } /* Make sure the user has each role in $all_required, this returns * an array in the same order as $all_required, with all members * in $all_required that are also in the session roles */ if(!is_array($all_required)) $all_required = array($all_required); //superuser always can access admin and config, even if its not in their SESSION roles if($_SESSION['superuser']=="yes") { $roles=array_merge(array("admin","config"),$_SESSION['roles']); } else { $roles=$_SESSION['roles']; } $match = array_intersect($all_required, $roles); if($all_required != $match) { /* Something is missing */ $ok = false; } /* Make sure the user has one role in $one_required */ if(!is_array($one_required)) $one_required = array($one_required); if(count($one_required)) { $match = array_intersect($one_required, $roles); if(count($match) == 0) { /* Missing any role in $one_required */ $ok = false; } } if(!$ok) { message_push(error(i18n("You do not have permission to view that page"))); header("location: {$config['SFIABDIRECTORY']}/user_login.php"); exit; } /* Forward to password expired, remember the target URI */ if($_SESSION['password_expired'] == true) { $_SESSION['request_uri'] = $_SERVER['REQUEST_URI']; header("location: {$config['SFIABDIRECTORY']}/user_edit.php"); exit; } /* Return the first role that matched, this retains the previous * behaviour */ return $match[0]; } /* Perform some checks. Make sure the person is logged in, and that their * password hasn't expired (the password_expired var is set in the login page) */ function api_user_auth_required($all_required = array(), $one_required = array()) { global $config; $ok = true; $ret=array(); if(!isset($_SESSION['roles']) || !isset($_SESSION['accounts_id'])) { $ret['status']="error"; $ret['error']="Not logged in"; return $ret; } /* Make sure the user has each role in $all_required, this returns * an array in the same order as $all_required, with all members * in $all_required that are also in the session roles */ if(!is_array($all_required)) $all_required = array($all_required); $match = array_intersect($all_required, $_SESSION['roles']); if($all_required != $match) { /* Something is missing */ $ok = false; } /* Make sure the user has one role in $one_required */ if(!is_array($one_required)) $one_required = array($one_required); if(count($one_required)) { $match = array_intersect($one_required, $_SESSION['roles']); if(count($match) == 0) { /* Missing any role in $one_required */ $ok = false; } } if(!$ok) { $ret['status']="error"; $ret['error']="You do not have permission to access that information"; return $ret; } /* Forward to password expired, remember the target URI */ if($_SESSION['password_expired'] == true) { $ret['status']="error"; $ret['error']="Your password has expired"; return $ret; } $ret['status']="ok"; $ret['match']=$match[0]; return $ret; } function user_volunteer_registration_status() { global $config; if($config['volunteer_enable']=="no") return "closed"; // $now = date('Y-m-d H:i:s'); // if($now < $config['dates']['judgeregopen']) return "notopenyet"; // if($now > $config['dates']['judgeregclose']) return "closed"; return "open"; } function user_teacher_registration_status(){ return "open"; } function user_judge_registration_status() { global $config; $now = date('Y-m-d H:i:s'); if(is_array($config['dates']) && array_key_exists('judgeregopen', $config['dates'])){ if($now < $config['dates']['judgeregopen']) return "notopenyet"; if($now > $config['dates']['judgeregclose']) return "closed"; } return "open"; } function user_participant_registration_status(){ global $config; $now = date('Y-m-d H:i:s'); if(is_array($config['dates']) && array_key_exists('regopen', $config['dates'])){ if($now < $config['dates']['regopen']) return "notopenyet"; if($now > $config['dates']['regclose']) return "closed"; } return 'open'; } $user_fields_map = array( /* Account -- Email requirement is set based on username, which * is always required. Password is not required unless they type * in the field, in which case the form validator kicks * (checks pass1==pass2 and all that) */ // 'email' => array('email'), /* Personal */ 'salutation' => array('salutation'), 'name' => array('firstname','lastname'), 'sex' => array('sex'), 'phonehome' => array('phonehome'), 'phonecell' => array('phonecell'), 'birthdate' => array('birthdate'), 'grade' => array('grade'), 'lang' => array('lang'), 'address' => array('address', 'address2', 'postalcode'), 'city' => array('city'), 'province' => array('province'), 'firstaid' => array('firstaid','cpr'), /* Organization */ 'org' => array('organization'), 'phonework' => array('phonework'), 'fax' => array('fax'), ); /* Return fields to show based on role. In the user editor, many * fields are always shown and some have hard-coded requirements, but * any in this list can be made optionally-required or not shown * at all */ function user_fields_enabled($role) { global $config, $user_fields_map; $ret = array('firstname','lastname'); $fields = $config["{$role}_personal_fields"]; //for participants, grade is required if($role=="participant") $ret[]="grade"; if($fields != '') { $fields = explode(',', $fields); foreach($fields as $f) { $ret = array_merge($ret, $user_fields_map[$f]); } } return $ret; } /* Return required fields. Some fields are always shown and can be * set to required. Some have hard-coded requirement status. This is only * for the fields where the requirement can be configured. Not for ALL fields * the user sees */ function user_fields_required($role) { global $config, $user_fields_map; $ret = array('firstname','lastname'); $required = $config["{$role}_personal_required"]; //for participants, grade is required if($role=="participant") $ret[]="grade"; if($required != '') { $fields = explode(',', $required); foreach($fields as $f) { $ret = array_merge($ret, $user_fields_map[$f]); } } /* Filter some elements that are never required. * - address2 */ $ret = array_diff($ret, array('address2')); return $ret; } function user_all_fields_required($roles) { $ret=array(); foreach($roles AS $role) { $ret=array_merge($ret,user_fields_required($role)); } return $ret; } //this function checks if $field is set in the user record, if it is, it returns it, otherwise, it returns false __AND__ redirects to the redirect page. function user_field_required($field,$redirect) { $u=user_load($_SESSION['users_id']); if($u[$field]) return $u[$field]; else { header("Location: $redirect"); } } /* user_{$role}_login() is called with a full $u loaded */ function user_fair_login($u) { /* Double check, make sure the user is of this role */ if(!array_key_exists('fair', $u['roles'])) { echo "ERROR: attempted to login fair on a non-fair user\n"; exit; } $_SESSION['fairs_id'] = $u['fairs_id'];// == 'yes') ? true : false; } function superuser_required() { //first, they have to be logged in user_auth_required(); //next, they need superuser if($_SESSION['superuser']!="yes") { send_header("Superuser access required"); send_footer(); exit; } } function try_login($user, $pass) { /* Ensure sanity of inputs */ /* User could be a username, or could be an email, check */ if(!account_valid_user($user) && !isEmailAddress($user)) { return false; } /* Don't check for a valid password, administrators can set any password they'd like, but * there has to be a password */ if(!strlen($pass)) { return false; } $user = mysql_real_escape_string($user); $q = mysql_query("SELECT id,password,deleted FROM accounts WHERE username='$user'"); echo mysql_error(); if(mysql_num_rows($q) < 1) return false; $r = mysql_fetch_assoc($q); /* See if the user account has been deleted */ if($r['deleted'] == 'yes') return false; /* See if the password matches */ if($r['password'] != $pass) return false; /* Login successful */ return $r['id']; } function updateSessionRoles($u=null) { if(!$u) $u=user_load($_SESSION['users_id']); $_SESSION['roles']=array(); if($u && is_array($u['roles'])) { foreach($u['roles'] AS $r=>$rd) { if($rd['active']=="yes" || $r=='admin' || $r=='config' || $r=='committee') $_SESSION['roles'][]=$r; } } } function user_conference_load($accounts_id,$conferences_id) { global $config; if(! ($accounts_id && $conferences_id)) return $config['SFIABDIRECTORY']."/index.php"; /* Use the active conference to find the user id to load */ /* FIXME: Need to be able to handle the case where there is no * active conference, but one step at a time */ $q = mysql_query("SELECT id FROM users WHERE accounts_id=$accounts_id AND conferences_id=$conferences_id"); if(mysql_num_rows($q) == 0) { /* FIXME: this should probably just return false, but for now, see if there's an error */ // return false; // header("location: user_edit.php"); // echo "No user {$accounts_id} for conference {$_SESSION['conferences_id']}"; return $config['SFIABDIRECTORY']."/user_main.php"; } if(mysql_num_rows($q) > 1) { echo "DATABASE ERROR: More than one user for account $accounts_id conference {$conferences_id}"; exit; } $uid = mysql_fetch_assoc($q); $id = $uid['id']; $u = user_load($id); $_SESSION['name']="{$u['firstname']} {$u['lastname']}"; $_SESSION['users_id']=$u['id']; updateSessionRoles(); /* Load the password expiry for each user role, and * find the longest expiry, which is the one we'll use * for this user to determine if the passwd has * expired. */ $longest_expiry = 0; foreach(array_keys($u['roles']) as $r) { $e = $config["{$r}_password_expiry_days"]; if($e == 0) { /* Catch a never expire case. */ $longest_expiry = 0; break; } else if($e > $longest_expiry) { $longest_expiry = $e; } } if($u['passwordset'] == '0000-00-00') { /* Force the password to expire */ $_SESSION['password_expired'] = true; } else if($longest_expiry == 0) { /* Never expires */ unset($_SESSION['password_expired']); } else { /* Check expiry */ $expires = date('Y-m-d', strtotime("{$u['passwordset']} +$longest_expiry days")); $now = date('Y-m-d'); if($now > $expires) { $_SESSION['password_expired'] = true; } else { unset($_SESSION['password_expired']); } } /* If password_expired == true, the main page (or any * other user page) will catch this and require * them to set a password */ /* Call login functions for each role */ foreach(array_keys($u['roles']) as $r) { if(is_callable("user_{$r}_login")) { call_user_func_array("user_{$r}_login", array($u)); } } // mysql_query("UPDATE accounts SET lastlogin=NOW() // WHERE id={$u['id']}"); /* Setup multirole so a multirole user can switch if they want to * without logging in/out */ /* if(count($u['roes']) > 1) { $_SESSION['multirole'] = true; } else { $_SESSION['multirole'] = false; } */ /* See if there is a redirect, and do that instead of * taking them to their main page */ /* if($redirect != '') { switch($redirect) { case 'roleadd': if(!user_valid_role($multirole_data)) $multirole_data = ''; header("location: user_multirole.php?action=add&role=$multirole_data"); exit; case 'roleattached': message_push(happy(i18n('The %1 role has been attached to your account', array($roles[$role]['name'])))); message_push(notice(i18n('Use the [Switch Roles] link in the upper right to change roles while you are logged in'))); header("location: {$role}_main.php"); exit; } } */ /* Is there a saved requesT_uri from a failed login attempt?, if so * take them there */ if(array_key_exists('request_uri', $_SESSION)) { // header("location: {$_SESSION['request_uri']}"); unset($_SESSION['request_uri']); return $_SESSION['request_uri']; } return "user_main.php"; // header("location: user_main.php"); //exit; } // sends an invitation from the user currently logged in, to the new user info passed in the parameters // returns the created user object on success, error message otherwise function user_invite($username, $password, $email, $roles_id){ global $roles, $conference; $u = user_load($_SESSION['users_id']); $returnval = null; //trim them all up first $username=trim($username); $password=trim($password); $email=trim($email); $roletype = null; //if its numeric, then we got an id, so get the associated roletype if(is_numeric($roles_id)) { foreach($roles as $t => $r){ if($r['id'] == $roles_id){ $roletype = $t; break; } } } else { //if its not numeric, then its a roletype, so set the type and get the id $roletype=$roles_id; $roles_id=$roles[$roletype]['id']; } if($roletype === null){ $returnval = 'Invalid roles_id parameter'; } // find out if this user has the necessary permission to invite another one if(!is_array($u['roles'])){ $returnval = 'You do not have a valid role for inviting users'; } if(array_key_exists('admin', $u['roles'])){ // This is an administrative user; they can invite people to any role they want. $myRole = 'admin'; }else if(array_key_exists('teacher', $u['roles'])){ // This is a teacher; they can add students. $myRole = 'teacher'; if(!(array_key_exists('schools_id', $u) && $u['schools_id'] > 0)){ $returnval = 'You must be associated with a school to add participants'; }else if($roletype != 'participant'){ $returnval = 'You do not have permission to invite this role'; } }else{ $returnval = 'You do not have a role with permission to invite users'; } if($returnval == null){ // good so far, let's see if the account already exists $q = mysql_query("SELECT id FROM accounts WHERE username='".mysql_real_escape_string($username)."' OR email='" . mysql_real_escape_string($username)."'"); $row = mysql_fetch_assoc($q); if(is_array($row)){ // This username is already in use. Let's see if this is a user that // the current one can modify $newUser = user_load(null, $row['id']); if(!is_array($newUser)){ //this just means the user has no roles yet, that could be fine, if its a new user... $newUser = user_create($row['id'], $conference['id']); // $returnval = 'Unable to load user'; }else{ // check for role-specific limitations on who can edit who // we need to query the data manually, as the user_load function only // returns user data relative to their current roles, not the one we want to add if($myRole == 'teacher'){ // we already know that this is a teacher inviting a student $testquery = mysql_fetch_assoc(mysql_query("SELECT schools_id FROM users WHERE id = {$newUser['id']}")); //if they dont have a schools_id, set it to be that of the teacher if(!$testquery['schools_id']) { mysql_query("UPDATE users SET schools_id = {$u['schools_id']} WHERE id = " . $newUser['id']); } else if($testquery['schools_id']==$u['schools_id']) { //they already match, do nothing } else { //they dont match, crappy buzz, you cant just take them over, sorry $returnval = 'This user is not a member of your school'; } } else if($myRole=='admin') { //well, we still need to set the school, but we dont need all the checks that a teacher would mysql_query("UPDATE users SET schools_id = {$u['schools_id']} WHERE id = " . $newUser['id']); } } } else { // ok, this is a new user name, so we'll need to create everything $newAccount = account_create($username, $password); if(is_array($newAccount)){ // if we're inviting someone that doesnt already exist, then their email address __MUST__ //be their username, otherwise, how the *(@&#*(@#& can we send them the invite?! account_set_email($newAccount['id'],$username); // created the account successfully, now do the user $newUser = user_create($newAccount['id'], $conference['id']); if(!is_array($newUser)){ $returnval = 'Error creating user'; }else{ if($roletype == 'participant'){ /* $newUser['schools_id'] = $u['schools_id']; user_save($newUser); */ //user_save doesnt save schools_id, and we cant use the user_set_school either because it relies on the access code being passed in, so, lets just set it manually. mysql_query("UPDATE users SET schools_id = {$u['schools_id']} WHERE id = " . $newUser['id']); } } }else{ $returnval = $newAccount; // it's an error message } } } if($returnval == null){ // if we've gotten this far, then either the user was created successfully, or they've // been loaded and our permission to modify them has been confirmed; we can add the role. // print_r($newUser); $result = account_add_role($newUser['accounts_id'], $roles_id, $conference['id']);//, $password); if($result == 'ok'){ $returnval = user_load($newUser['id']); }else{ $returnval = "Error adding '$roletype' role: $result"; } } return $returnval; } // uninvite the user with the specified user id. // Returns the user object on success, error message otherwise function user_uninvite($uid, $roles_id){ global $roles, $conference; // idiot proofing if(!is_numeric($uid)) return "Invalid user id"; $roletype = null; //if its numeric, then we got an id, so get the associated roletype if(is_numeric($roles_id)) { foreach($roles as $t => $r){ if($r['id'] == $roles_id){ $roletype = $t; break; } } } else { //if its not numeric, then its a roletype, so set the type and get the id $roletype=$roles_id; $roles_id=$roles[$roletype]['id']; } $u = user_load($_SESSION['users_id']); $returnval = null; if($roletype === null){ $returnval = 'Invalid roles_id parameter'; }else if(!user_has_authority($u, $roletype)){ $returnval = 'You can not modify users of ' . $roletype . ' role'; } if($returnval == null){ $user = user_load($uid); if($user == false){ $returnval = 'Could not load specified user'; } } if($returnval == null){ if($_SESSION['superuser']=="yes" || array_key_exists('admin',$u['roles'])) { //superuser or admin, let them do it } else { //else, the school must match if($user['schools_id'] != $u['schools_id']){ $returnval = 'You can not uninvite students form other schools'; } } } if($returnval == null){ // ok, looks like all of the data checks out. Let's remove this user's role mysql_query("DELETE FROM user_roles WHERE users_id = $uid AND roles_id = $roles_id"); $returnval = mysql_error(); } if($returnval == null) $returnval = user_load($uid); return $returnval; } // returns an array of users of the specified role that the currently logged in user has permission to modify function user_list_modifiable($roles_id){ global $roles; $returnval = null; $u = user_load($_SESSION['users_id']); // idiot proofing if(!is_numeric($roles_id)) return "Invalid role id"; $roletype = null; foreach($roles as $t => $r){ if($r['id'] == $roles_id){ $roletype = $t; break; } } if($roletype === null){ $returnval = 'Invalid roles_id parameter'; }else if(!user_has_authority($u, $roletype)){ $returnval = array(); } if($returnval == null){ $returnval = array(); // ok, if we've gotten here, then they have the necessary permissions and such. Let's // go ahead and generate some data // first we'll assemble our WHERE conditions $conditions = array(); $conditions[] = "users.conferences_id = " . $u['conferences_id']; $conditions[] = "user_roles.roles_id = " . $roles_id; if(array_key_exists('admin', $u['roles'])){ // all is allowed }else if(array_key_exists('teacher', $u['roles'])){ $conditions[] = 'schools_id = ' . $u['schools_id']; } $role_fields = 'users.' . implode(', users.', user_get_role_fields($roletype)); $query = "SELECT users.firstname, users.lastname, accounts.username, $role_fields FROM users"; $query .= " JOIN accounts ON users.accounts_id = accounts.id"; $query .= " JOIN user_roles ON user_roles.users_id = users.id"; $query .= " WHERE (" . implode(') AND (', $conditions) . ")"; $query .= " ORDER BY users.id"; $q = mysql_query($query); while($row = mysql_fetch_assoc($q)){ $returnval[] = $row; } } return $returnval; } // determine whethor or not the user $u has the authority to modify users with the specified role function user_has_authority($u, $role){ // find out if this user has the necessary permission to modify another one $returnval = false; if(is_array($u['roles'])){ if(array_key_exists('admin', $u['roles'])){ // This is an administrative user; they can modify people of any role they want. $returnval = true; }else if(array_key_exists('teacher', $u['roles'])){ if(array_key_exists('schools_id', $u) && $u['schools_id'] > 0){ if($role == 'participant'){ $returnval = true; } } } } return $returnval; } ?>