2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
38 /*********************************************************************************
40 * Description: TODO: To be written.
41 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
42 * All Rights Reserved.
43 * Contributor(s): ______________________________________..
44 ********************************************************************************/
46 require_once('include/SugarObjects/templates/person/Person.php');
49 // User is used to store customer information.
50 class User extends Person {
62 var $modified_user_id;
65 var $modified_by_name;
77 var $address_postalcode;
83 var $authenticated = false;
90 var $accept_status; // to support Meetings
91 //adding a property called team_id so we can populate it for use in the team widget
94 var $receive_notifications;
98 var $team_exists = false;
99 var $table_name = "users";
100 var $module_dir = 'Users';
101 var $object_name = "User";
102 var $user_preferences;
104 var $importable = true;
105 var $_userPreferenceFocus;
107 var $encodeFields = Array ("first_name", "last_name", "description");
109 // This is used to retrieve related fields from form posts.
110 var $additional_column_fields = array ('reports_to_name'
116 var $new_schema = true;
121 $this->_loadUserPreferencesFocus();
124 protected function _loadUserPreferencesFocus()
126 $this->_userPreferenceFocus = new UserPreference($this);
130 * returns an admin user
132 public function getSystemUser()
134 if (null === $this->retrieve('1'))
135 // handle cases where someone deleted user with id "1"
136 $this->retrieve_by_string_fields(array(
137 'status' => 'Active',
146 * convenience function to get user's default signature
148 function getDefaultSignature() {
149 if($defaultId = $this->getPreference('signature_default')) {
150 return $this->getSignature($defaultId);
157 * retrieves the signatures for a user
158 * @param string id ID of user_signature
159 * @return array ID, signature, and signature_html
161 public function getSignature($id)
163 $signatures = $this->getSignaturesArray();
165 return $signatures[$id];
168 function getSignaturesArray() {
169 $q = 'SELECT * FROM users_signatures WHERE user_id = \''.$this->id.'\' AND deleted = 0 ORDER BY name ASC';
170 $r = $this->db->query($q);
173 $sig = array(""=>"");
175 while($a = $this->db->fetchByAssoc($r)) {
183 * retrieves any signatures that the User may have created as <select>
185 public function getSignatures(
191 $sig = $this->getSignaturesArray();
193 foreach ($sig as $key => $arr)
195 $sigs[$key] = !empty($arr['name']) ? $arr['name'] : '';
200 $change = ($forSettings) ? "onChange='displaySignatureEdit();'" : "onChange='setSigEditButtonVisibility();'";
203 $id = (!$forSettings) ? 'signature_id' : 'signature_idDisplay';
205 $out = "<select {$change} id='{$id}' name='{$id}'>";
206 $out .= get_select_options_with_id($sigs, $defaultSig).'</select>';
212 * returns buttons and JS for signatures
214 function getSignatureButtons($jscall='', $defaultDisplay=false) {
217 $jscall = empty($jscall) ? 'open_email_signature_form' : $jscall;
219 $butts = "<input class='button' onclick='javascript:{$jscall}(\"\", \"{$this->id}\");' value='{$mod_strings['LBL_BUTTON_CREATE']}' type='button'> ";
220 if($defaultDisplay) {
221 $butts .= '<span name="edit_sig" id="edit_sig" style="visibility:inherit;"><input class="button" onclick="javascript:'.$jscall.'(document.getElementById(\'signature_id\', \'\').value)" value="'.$mod_strings['LBL_BUTTON_EDIT'].'" type="button" tabindex="392">
224 $butts .= '<span name="edit_sig" id="edit_sig" style="visibility:hidden;"><input class="button" onclick="javascript:'.$jscall.'(document.getElementById(\'signature_id\', \'\').value)" value="'.$mod_strings['LBL_BUTTON_EDIT'].'" type="button" tabindex="392">
231 * performs a rudimentary check to verify if a given user has setup personal
236 public function hasPersonalEmail()
238 $focus = new InboundEmail;
239 $focus->retrieve_by_string_fields(array('group_id' => $this->id));
241 return !empty($focus->id);
244 /* Returns the User's private GUID; this is unassociated with the User's
245 * actual GUID. It is used to secure file names that must be HTTP://
246 * accesible, but obfusicated.
248 function getUserPrivGuid() {
249 $userPrivGuid = $this->getPreference('userPrivGuid', 'global', $this);
251 return $userPrivGuid;
253 $this->setUserPrivGuid();
254 if (!isset ($_SESSION['setPrivGuid'])) {
255 $_SESSION['setPrivGuid'] = true;
256 $userPrivGuid = $this->getUserPrivGuid();
257 return $userPrivGuid;
259 sugar_die("Breaking Infinite Loop Condition: Could not setUserPrivGuid.");
264 function setUserPrivGuid() {
265 $privGuid = create_guid();
266 //($name, $value, $nosession=0)
267 $this->setPreference('userPrivGuid', $privGuid, 0, 'global', $this);
271 * Interface for the User object to calling the UserPreference::setPreference() method in modules/UserPreferences/UserPreference.php
273 * @see UserPreference::setPreference()
275 * @param string $name Name of the preference to set
276 * @param string $value Value to set preference to
277 * @param null $nosession For BC, ignored
278 * @param string $category Name of the category to retrieve
280 public function setPreference(
288 if ( func_num_args() > 4 ) {
289 $user = func_get_arg(4);
290 $GLOBALS['log']->deprecated('User::setPreferences() should not be used statically.');
295 $user->_userPreferenceFocus->setPreference($name, $value, $category);
299 * Interface for the User object to calling the UserPreference::resetPreferences() method in modules/UserPreferences/UserPreference.php
301 * @see UserPreference::resetPreferences()
303 * @param string $category category to reset
305 public function resetPreferences(
310 if ( func_num_args() > 1 ) {
311 $user = func_get_arg(1);
312 $GLOBALS['log']->deprecated('User::resetPreferences() should not be used statically.');
317 $user->_userPreferenceFocus->resetPreferences($category);
321 * Interface for the User object to calling the UserPreference::savePreferencesToDB() method in modules/UserPreferences/UserPreference.php
323 * @see UserPreference::savePreferencesToDB()
325 public function savePreferencesToDB()
328 if ( func_num_args() > 0 ) {
329 $user = func_get_arg(0);
330 $GLOBALS['log']->deprecated('User::savePreferencesToDB() should not be used statically.');
335 $user->_userPreferenceFocus->savePreferencesToDB();
339 * Unconditionally reloads user preferences from the DB and updates the session
340 * @param string $category name of the category to retreive, defaults to global scope
341 * @return bool successful?
343 public function reloadPreferences($category = 'global')
345 return $this->_userPreferenceFocus->reloadPreferences($category = 'global');
349 * Interface for the User object to calling the UserPreference::getUserDateTimePreferences() method in modules/UserPreferences/UserPreference.php
351 * @see UserPreference::getUserDateTimePreferences()
353 * @return array 'date' - date format for user ; 'time' - time format for user
355 public function getUserDateTimePreferences()
358 if ( func_num_args() > 0 ) {
359 $user = func_get_arg(0);
360 $GLOBALS['log']->deprecated('User::getUserDateTimePreferences() should not be used statically.');
365 return $user->_userPreferenceFocus->getUserDateTimePreferences();
369 * Interface for the User object to calling the UserPreference::loadPreferences() method in modules/UserPreferences/UserPreference.php
371 * @see UserPreference::loadPreferences()
373 * @param string $category name of the category to retreive, defaults to global scope
374 * @return bool successful?
376 public function loadPreferences(
381 if ( func_num_args() > 1 ) {
382 $user = func_get_arg(1);
383 $GLOBALS['log']->deprecated('User::loadPreferences() should not be used statically.');
388 return $user->_userPreferenceFocus->loadPreferences($category);
392 * Interface for the User object to calling the UserPreference::setPreference() method in modules/UserPreferences/UserPreference.php
394 * @see UserPreference::getPreference()
396 * @param string $name name of the preference to retreive
397 * @param string $category name of the category to retreive, defaults to global scope
398 * @return mixed the value of the preference (string, array, int etc)
400 public function getPreference(
406 if ( func_num_args() > 2 ) {
407 $user = func_get_arg(2);
408 $GLOBALS['log']->deprecated('User::getPreference() should not be used statically.');
413 return $user->_userPreferenceFocus->getPreference($name, $category);
416 function save($check_notify = false) {
418 $query = "SELECT count(id) as total from users WHERE status='Active' AND deleted=0 AND is_group=0 AND portal_only=0";
421 // wp: do not save user_preferences in this table, see user_preferences module
422 $this->user_preferences = '';
424 // if this is an admin user, do not allow is_group or portal_only flag to be set.
425 if ($this->is_admin) {
427 $this->portal_only = 0;
434 parent::save($check_notify);
438 $this->savePreferencesToDB();
443 * @return boolean true if the user is a member of the role_name, false otherwise
444 * @param string $role_name - Must be the exact name of the acl_role
445 * @param string $user_id - The user id to check for the role membership, empty string if current user
446 * @desc Determine whether or not a user is a member of an ACL Role. This function caches the
447 * results in the session or to prevent running queries after the first time executed.
448 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc..
449 * All Rights Reserved..
450 * Contributor(s): ______________________________________..
452 function check_role_membership($role_name, $user_id = ''){
454 global $current_user;
457 $user_id = $current_user->id;
459 // Check the Sugar External Cache to see if this users memberships were cached
460 $role_array = sugar_cache_retrieve("RoleMemberships_".$user_id);
462 // If we are pulling the roles for the current user
463 if($user_id == $current_user->id){
464 // If the Session doesn't contain the values
465 if(!isset($_SESSION['role_memberships'])){
466 // This means the external cache already had it loaded
467 if(!empty($role_array))
468 $_SESSION['role_memberships'] = $role_array;
470 $_SESSION['role_memberships'] = ACLRole::getUserRoleNames($user_id);
471 $role_array = $_SESSION['role_memberships'];
474 // else the session had the values, so we assign to the role array
476 $role_array = $_SESSION['role_memberships'];
480 // If the external cache didn't contain the values, we get them and put them in cache
482 $role_array = ACLRole::getUserRoleNames($user_id);
483 sugar_cache_put("RoleMemberships_".$user_id, $role_array);
487 // If the role doesn't exist in the list of the user's roles
488 if(!empty($role_array) && in_array($role_name, $role_array))
494 function get_summary_text() {
495 //$this->_create_proper_name_field();
500 * @return string encrypted password for storage in DB and comparison against DB password.
501 * @param string $user_name - Must be non null and at least 2 characters
502 * @param string $user_password - Must be non null and at least 1 character.
503 * @desc Take an unencrypted username and password and return the encrypted password
504 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc..
505 * All Rights Reserved..
506 * Contributor(s): ______________________________________..
508 function encrypt_password($user_password) {
509 // encrypt the password.
510 $salt = substr($this->user_name, 0, 2);
511 $encrypted_password = crypt($user_password, $salt);
513 return $encrypted_password;
517 * Authenicates the user; returns true if successful
522 public function authenticate_user(
526 $password = $GLOBALS['db']->quote($password);
527 $user_name = $GLOBALS['db']->quote($this->user_name);
528 $query = "SELECT * from $this->table_name where user_name='$user_name' AND user_hash='$password' AND (portal_only IS NULL OR portal_only !='1') AND (is_group IS NULL OR is_group !='1') ";
529 //$result = $this->db->requireSingleResult($query, false);
530 $result = $this->db->limitQuery($query,0,1,false);
531 $a = $this->db->fetchByAssoc($result);
532 // set the ID in the seed user. This can be used for retrieving the full user record later
534 // already logging this in load_user() method
535 //$GLOBALS['log']->fatal("SECURITY: failed login by $this->user_name");
538 $this->id = $a['id'];
544 * retrieves an User bean
545 * preformat name & full_name attribute with first/last
546 * loads User's preferences
548 * @param string id ID of the User
549 * @param bool encode encode the result
550 * @return object User bean
551 * @return null null if no User found
553 function retrieve($id, $encode = true) {
554 $ret = parent::retrieve($id, $encode);
556 if (isset ($_SESSION)) {
557 $this->loadPreferences();
563 function retrieve_by_email_address($email) {
565 $email1= strtoupper($email);
568 select id from users where id in ( SELECT er.bean_id AS id FROM email_addr_bean_rel er,
569 email_addresses ea WHERE ea.id = er.email_address_id
570 AND ea.deleted = 0 AND er.deleted = 0 AND er.bean_module = 'Users' AND email_address_caps IN ('{$email}') )
574 $res=$this->db->query($q);
575 $row=$this->db->fetchByAssoc($res);
577 if (!empty($row['id'])) {
578 return $this->retrieve($row['id']);
583 function bean_implements($interface) {
585 case 'ACL':return true;
592 * Load a user based on the user_name in $this
593 * @return -- this if load was successul and null if load failed.
594 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc..
595 * All Rights Reserved..
596 * Contributor(s): ______________________________________..
598 function load_user($user_password) {
600 unset($GLOBALS['login_error']);
601 if(isset ($_SESSION['loginattempts'])) {
602 $_SESSION['loginattempts'] += 1;
604 $_SESSION['loginattempts'] = 1;
606 if($_SESSION['loginattempts'] > 5) {
607 $GLOBALS['log']->fatal('SECURITY: '.$this->user_name.' has attempted to login '.$_SESSION['loginattempts'].' times from IP address: '.$_SERVER['REMOTE_ADDR'].'.');
610 $GLOBALS['log']->debug("Starting user load for $this->user_name");
612 if (!isset ($this->user_name) || $this->user_name == "" || !isset ($user_password) || $user_password == "")
615 $user_hash = strtolower(md5($user_password));
616 if($this->authenticate_user($user_hash)) {
617 $query = "SELECT * from $this->table_name where id='$this->id'";
619 $GLOBALS['log']->fatal('SECURITY: User authentication for '.$this->user_name.' failed');
622 $r = $this->db->limitQuery($query, 0, 1, false);
623 $a = $this->db->fetchByAssoc($r);
624 if(empty($a) || !empty ($GLOBALS['login_error'])) {
625 $GLOBALS['log']->fatal('SECURITY: User authentication for '.$this->user_name.' failed - could not Load User from Database');
629 // Get the fields for the user
632 // If there is no user_hash is not present or is out of date, then create a new one.
633 if (!isset ($row['user_hash']) || $row['user_hash'] != $user_hash) {
634 $query = "UPDATE $this->table_name SET user_hash='$user_hash' where id='{$row['id']}'";
635 $this->db->query($query, true, "Error setting new hash for {$row['user_name']}: ");
638 // now fill in the fields.
639 foreach ($this->column_fields as $field) {
640 $GLOBALS['log']->info($field);
642 if (isset ($row[$field])) {
643 $GLOBALS['log']->info("=".$row[$field]);
645 $this-> $field = $row[$field];
649 $this->loadPreferences();
652 require_once ('modules/Versions/CheckVersions.php');
653 $invalid_versions = get_invalid_versions();
655 if (!empty ($invalid_versions)) {
656 if (isset ($invalid_versions['Rebuild Relationships'])) {
657 unset ($invalid_versions['Rebuild Relationships']);
659 // flag for pickup in DisplayWarnings.php
660 $_SESSION['rebuild_relationships'] = true;
663 if (isset ($invalid_versions['Rebuild Extensions'])) {
664 unset ($invalid_versions['Rebuild Extensions']);
666 // flag for pickup in DisplayWarnings.php
667 $_SESSION['rebuild_extensions'] = true;
670 $_SESSION['invalid_versions'] = $invalid_versions;
672 $this->fill_in_additional_detail_fields();
673 if ($this->status != "Inactive")
674 $this->authenticated = true;
676 unset ($_SESSION['loginattempts']);
681 * Verify that the current password is correct and write the new password to the DB.
683 * @param string $user name - Must be non null and at least 1 character.
684 * @param string $user_password - Must be non null and at least 1 character.
685 * @param string $new_password - Must be non null and at least 1 character.
686 * @return boolean - If passwords pass verification and query succeeds, return true, else return false.
688 function change_password(
691 $system_generated = '0'
695 global $current_user;
696 $GLOBALS['log']->debug("Starting password change for $this->user_name");
698 if (!isset ($new_password) || $new_password == "") {
699 $this->error_string = $mod_strings['ERR_PASSWORD_CHANGE_FAILED_1'].$current_user['user_name'].$mod_strings['ERR_PASSWORD_CHANGE_FAILED_2'];
703 $old_user_hash = strtolower(md5($user_password));
705 if (!is_admin($current_user) && !is_admin_for_module($current_user,'Users')) {
706 //check old password first
707 $query = "SELECT user_name FROM $this->table_name WHERE user_hash='$old_user_hash' AND id='$this->id'";
708 $result = $this->db->query($query, true);
709 $row = $this->db->fetchByAssoc($result);
710 $GLOBALS['log']->debug("select old password query: $query");
711 $GLOBALS['log']->debug("return result of $row");
713 $GLOBALS['log']->warn("Incorrect old password for ".$this->user_name."");
714 $this->error_string = $mod_strings['ERR_PASSWORD_INCORRECT_OLD_1'].$this->user_name.$mod_strings['ERR_PASSWORD_INCORRECT_OLD_2'];
719 $user_hash = strtolower(md5($new_password));
720 $this->setPreference('loginexpiration','0');
722 $now = TimeDate::getInstance()->nowDb();
723 $query = "UPDATE $this->table_name SET user_hash='$user_hash', system_generated_password='$system_generated', pwd_last_changed='$now' where id='$this->id'";
724 $this->db->query($query, true, "Error setting new password for $this->user_name: ");
725 $_SESSION['hasExpiredPassword'] = '0';
729 function is_authenticated() {
730 return $this->authenticated;
733 function fill_in_additional_list_fields() {
734 $this->fill_in_additional_detail_fields();
737 function fill_in_additional_detail_fields() {
740 $query = "SELECT u1.first_name, u1.last_name from users u1, users u2 where u1.id = u2.reports_to_id AND u2.id = '$this->id' and u1.deleted=0";
741 $result = $this->db->query($query, true, "Error filling in additional detail fields");
743 $row = $this->db->fetchByAssoc($result);
744 $GLOBALS['log']->debug("additional detail query results: $row");
747 $this->reports_to_name = stripslashes($row['first_name'].' '.$row['last_name']);
749 $this->reports_to_name = '';
752 $this->_create_proper_name_field();
755 public function retrieve_user_id(
759 $userFocus = new User;
760 $userFocus->retrieve_by_string_fields(array('user_name'=>$user_name));
761 if ( empty($userFocus->id) )
764 return $userFocus->id;
768 * @return -- returns a list of all users in the system.
769 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc..
770 * All Rights Reserved..
771 * Contributor(s): ______________________________________..
773 function verify_data($ieVerified=true) {
774 global $mod_strings, $current_user;
777 if (!empty ($this->id)) {
778 // Make sure the user doesn't report to themselves.
779 $reports_to_self = 0;
780 $check_user = $this->reports_to_id;
781 $already_seen_list = array ();
782 while (!empty ($check_user)) {
783 if (isset ($already_seen_list[$check_user])) {
784 // This user doesn't actually report to themselves
785 // But someone above them does.
786 $reports_to_self = 1;
789 if ($check_user == $this->id) {
790 $reports_to_self = 1;
793 $already_seen_list[$check_user] = 1;
794 $query = "SELECT reports_to_id FROM users WHERE id='".$this->db->quote($check_user)."'";
795 $result = $this->db->query($query, true, "Error checking for reporting-loop");
796 $row = $this->db->fetchByAssoc($result);
797 echo ("fetched: ".$row['reports_to_id']." from ".$check_user."<br>");
798 $check_user = $row['reports_to_id'];
801 if ($reports_to_self == 1) {
802 $this->error_string .= $mod_strings['ERR_REPORT_LOOP'];
807 $query = "SELECT user_name from users where user_name='$this->user_name' AND deleted=0";
808 if(!empty($this->id))$query .= " AND id<>'$this->id'";
809 $result = $this->db->query($query, true, "Error selecting possible duplicate users: ");
810 $dup_users = $this->db->fetchByAssoc($result);
812 if (!empty($dup_users)) {
813 $this->error_string .= $mod_strings['ERR_USER_NAME_EXISTS_1'].$this->user_name.$mod_strings['ERR_USER_NAME_EXISTS_2'];
817 if (($current_user->is_admin == "on")) {
818 if($this->db->dbType == 'mssql'){
819 $query = "SELECT user_name from users where is_admin = 1 AND deleted=0";
821 $query = "SELECT user_name from users where is_admin = 'on' AND deleted=0";
823 $result = $this->db->query($query, true, "Error selecting possible duplicate users: ");
824 $remaining_admins = $this->db->getRowCount($result);
826 if (($remaining_admins <= 1) && ($this->is_admin != "on") && ($this->id == $current_user->id)) {
827 $GLOBALS['log']->debug("Number of remaining administrator accounts: {$remaining_admins}");
828 $this->error_string .= $mod_strings['ERR_LAST_ADMIN_1'].$this->user_name.$mod_strings['ERR_LAST_ADMIN_2'];
832 ///////////////////////////////////////////////////////////////////////
833 //// InboundEmail verification failure
836 $this->error_string .= '<br />'.$mod_strings['ERR_EMAIL_NO_OPTS'];
842 function get_list_view_data() {
844 global $current_user;
846 $user_fields = $this->get_list_view_array();
848 $user_fields['IS_ADMIN_IMAGE'] = SugarThemeRegistry::current()->getImage('check_inline', '');
849 elseif (!$this->is_admin) $user_fields['IS_ADMIN'] = '';
851 $user_fields['IS_GROUP_IMAGE'] = SugarThemeRegistry::current()->getImage('check_inline', '');
853 $user_fields['IS_GROUP_IMAGE'] = '';
854 $user_fields['NAME'] = empty ($this->name) ? '' : $this->name;
856 $user_fields['REPORTS_TO_NAME'] = $this->reports_to_name;
858 $user_fields['EMAIL1'] = $this->emailAddress->getPrimaryAddress($this);
863 function list_view_parse_additional_sections(& $list_form, $xTemplateSection) {
867 function save_relationship_changes($is_update) {
873 function create_export_query($order_by, $where) {
874 include('modules/Users/field_arrays.php');
877 foreach($fields_array['User']['export_fields'] as $field) {
878 $cols .= (empty($cols)) ? '' : ', ';
882 $query = "SELECT {$cols} FROM users ";
884 $where_auto = " users.deleted = 0";
887 $query .= " WHERE $where AND ".$where_auto;
889 $query .= " WHERE ".$where_auto;
891 // admin for module user is not be able to export a super-admin
892 global $current_user;
893 if(!$current_user->is_admin){
894 $query .= " AND users.is_admin=0";
898 $query .= " ORDER BY $order_by";
900 $query .= " ORDER BY users.user_name";
905 /** Returns a list of the associated users
906 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc..
907 * All Rights Reserved..
908 * Contributor(s): ______________________________________..
910 function get_meetings() {
911 // First, get the list of IDs.
912 $query = "SELECT meeting_id as id from meetings_users where user_id='$this->id' AND deleted=0";
913 return $this->build_related_list($query, new Meeting());
915 function get_calls() {
916 // First, get the list of IDs.
917 $query = "SELECT call_id as id from calls_users where user_id='$this->id' AND deleted=0";
918 return $this->build_related_list($query, new Call());
922 * generates Javascript to display I-E mail counts, both personal and group
924 function displayEmailCounts() {
926 $new = translate('LBL_NEW', 'Emails');
927 $default = 'index.php?module=Emails&action=ListView&assigned_user_id='.$this->id;
929 $verts = array('Love', 'Links', 'Pipeline', 'RipCurl', 'SugarLite');
931 if($this->hasPersonalEmail()) {
932 $r = $this->db->query('SELECT count(*) AS c FROM emails WHERE deleted=0 AND assigned_user_id = \''.$this->id.'\' AND type = \'inbound\' AND status = \'unread\'');
933 $a = $this->db->fetchByAssoc($r);
934 if(in_array($theme, $verts)) {
937 $count .= ' ';
939 $count .= '<a href='.$default.'&type=inbound>'.translate('LBL_LIST_TITLE_MY_INBOX', 'Emails').': ('.$a['c'].' '.$new.')</a>';
941 if(!in_array($theme, $verts)) {
946 $r = $this->db->query('SELECT id FROM users WHERE users.is_group = 1 AND deleted = 0');
949 while($a = $this->db->fetchByAssoc($r)) {
950 if($groupIds != '') {$groupIds .= ', ';}
951 $groupIds .= "'".$a['id']."'";
955 if(strlen($groupIds) > 0) {
956 $groupQuery = 'SELECT count(*) AS c FROM emails ';
957 $groupQuery .= ' WHERE emails.deleted=0 AND emails.assigned_user_id IN ('.$groupIds.') AND emails.type = \'inbound\' AND emails.status = \'unread\'';
958 $r = $this->db->query($groupQuery);
959 if(is_resource($r)) {
960 $a = $this->db->fetchByAssoc($r);
966 if(in_array($theme, $verts)) $count .= '<br />';
967 if(empty($count)) $count .= ' ';
968 $count .= '<a href=index.php?module=Emails&action=ListViewGroup>'.translate('LBL_LIST_TITLE_GROUP_INBOX', 'Emails').': ('.$total.' '.$new.')</a>';
970 $out = '<script type="text/javascript" language="Javascript">';
971 $out .= 'var welcome = document.getElementById("welcome");';
972 $out .= 'var welcomeContent = welcome.innerHTML;';
973 $out .= 'welcome.innerHTML = welcomeContent + "'.$count.'";';
979 function getPreferredEmail() {
981 $nameEmail = $this->getUsersNameAndEmail();
982 $prefAddr = $nameEmail['email'];
983 $fullName = $nameEmail['name'];
984 if (empty ($prefAddr)) {
985 $nameEmail = $this->getSystemDefaultNameAndEmail();
986 $prefAddr = $nameEmail['email'];
987 $fullName = $nameEmail['name'];
989 $fullName = from_html($fullName);
990 $ret['name'] = $fullName;
991 $ret['email'] = $prefAddr;
995 function getUsersNameAndEmail() {
998 if(!empty($this->salutation)) $salutation = $this->salutation;
1000 if(!empty($this->first_name)) {
1001 $fullName = trim($salutation.' '.$this->first_name.' '.$this->last_name);
1002 } elseif(!empty($this->name)) {
1003 $fullName = $this->name;
1005 $prefAddr = $this->emailAddress->getPrimaryAddress($this);
1007 if (empty ($prefAddr)) {
1008 $prefAddr = $this->emailAddress->getReplyToAddress($this);
1010 return array('email' => $prefAddr , 'name' => $fullName);
1014 function getSystemDefaultNameAndEmail() {
1016 $email = new Email();
1017 $return = $email->getSystemDefaultEmail();
1018 $prefAddr = $return['email'];
1019 $fullName = $return['name'];
1020 return array('email' => $prefAddr , 'name' => $fullName);
1024 * sets User email default in config.php if not already set by install - i.
1027 function setDefaultsInConfig() {
1028 global $sugar_config;
1029 $sugar_config['email_default_client'] = 'sugar';
1030 $sugar_config['email_default_editor'] = 'html';
1031 ksort($sugar_config);
1032 write_array_to_file('sugar_config', $sugar_config, 'config.php');
1033 return $sugar_config;
1037 * returns User's email address based on descending order of preferences
1039 * @param string id GUID of target user if needed
1040 * @return array Assoc array for an email and name
1042 function getEmailInfo($id='') {
1046 $user->retrieve($id);
1050 $fromName = $user->getPreference('mail_fromname');
1051 if(empty($fromName)) {
1052 // cn: bug 8586 - localized name format
1053 $fromName = $user->full_name;
1057 $fromaddr = $user->getPreference('mail_fromaddress');
1058 if(empty($fromaddr)) {
1059 if(!empty($user->email1) && isset($user->email1)) {
1060 $fromaddr = $user->email1;
1061 } elseif(!empty($user->email2) && isset($user->email2)) {
1062 $fromaddr = $user->email2;
1064 $r = $user->db->query("SELECT value FROM config WHERE name = 'fromaddress'");
1065 $a = $user->db->fetchByAssoc($r);
1066 $fromddr = $a['value'];
1070 $ret['name'] = $fromName;
1071 $ret['email'] = $fromaddr;
1077 * returns opening <a href=xxxx for a contact, account, etc
1078 * cascades from User set preference to System-wide default
1079 * @return string link
1080 * @param attribute the email addy
1081 * @param focus the parent bean
1083 * @param return_module
1084 * @param return_action
1088 function getEmailLink2($emailAddress, &$focus, $contact_id='', $ret_module='', $ret_action='DetailView', $ret_id='', $class='') {
1090 global $sugar_config;
1092 if(!isset($sugar_config['email_default_client'])) {
1093 $this->setDefaultsInConfig();
1096 $userPref = $this->getPreference('email_link_type');
1097 $defaultPref = $sugar_config['email_default_client'];
1098 if($userPref != '') {
1099 $client = $userPref;
1101 $client = $defaultPref;
1104 if($client == 'sugar') {
1109 $to_addrs_names = '';
1110 $to_addrs_emails = '';
1112 if(!empty($focus->salutation)) $salutation = $focus->salutation;
1114 if(!empty($focus->first_name)) {
1115 $fullName = trim($salutation.' '.$focus->first_name.' '.$focus->last_name);
1116 } elseif(!empty($focus->name)) {
1117 $fullName = $focus->name;
1120 if(empty($ret_module)) $ret_module = $focus->module_dir;
1121 if(empty($ret_id)) $ret_id = $focus->id;
1122 if($focus->object_name == 'Contact') {
1123 $contact_id = $focus->id;
1124 $to_addrs_ids = $focus->id;
1125 $to_addrs_names = $fullName;
1126 $to_addrs_emails = $focus->email1;
1129 $emailLinkUrl = 'contact_id='.$contact_id.
1130 '&parent_type='.$focus->module_dir.
1131 '&parent_id='.$focus->id.
1132 '&parent_name='.urlencode($fullName).
1133 '&to_addrs_ids='.$to_addrs_ids.
1134 '&to_addrs_names='.urlencode($to_addrs_names).
1135 '&to_addrs_emails='.urlencode($to_addrs_emails).
1136 '&to_email_addrs='.urlencode($fullName . ' <' . $emailAddress . '>').
1137 '&return_module='.$ret_module.
1138 '&return_action='.$ret_action.
1139 '&return_id='.$ret_id;
1141 //Generate the compose package for the quick create options.
1142 //$json = getJSONobj();
1143 //$composeOptionsLink = $json->encode( array('composeOptionsLink' => $emailLinkUrl,'id' => $focus->id) );
1144 require_once('modules/Emails/EmailUI.php');
1145 $eUi = new EmailUI();
1146 $j_quickComposeOptions = $eUi->generateComposePackageForQuickCreateFromComposeUrl($emailLinkUrl, true);
1148 $emailLink = "<a href='javascript:void(0);' onclick='SUGAR.quickCompose.init($j_quickComposeOptions);' class='$class'>";
1152 $emailLink = '<a href="mailto:'.$emailAddress.'" class="'.$class.'">';
1159 * returns opening <a href=xxxx for a contact, account, etc
1160 * cascades from User set preference to System-wide default
1161 * @return string link
1162 * @param attribute the email addy
1163 * @param focus the parent bean
1165 * @param return_module
1166 * @param return_action
1170 function getEmailLink($attribute, &$focus, $contact_id='', $ret_module='', $ret_action='DetailView', $ret_id='', $class='') {
1172 global $sugar_config;
1174 if(!isset($sugar_config['email_default_client'])) {
1175 $this->setDefaultsInConfig();
1178 $userPref = $this->getPreference('email_link_type');
1179 $defaultPref = $sugar_config['email_default_client'];
1180 if($userPref != '') {
1181 $client = $userPref;
1183 $client = $defaultPref;
1186 if($client == 'sugar') {
1191 $to_addrs_names = '';
1192 $to_addrs_emails = '';
1194 if(!empty($focus->salutation)) $salutation = $focus->salutation;
1196 if(!empty($focus->first_name)) {
1197 $fullName = trim($salutation.' '.$focus->first_name.' '.$focus->last_name);
1198 } elseif(!empty($focus->name)) {
1199 $fullName = $focus->name;
1201 if(!empty($focus->$attribute)) {
1202 $email = $focus->$attribute;
1206 if(empty($ret_module)) $ret_module = $focus->module_dir;
1207 if(empty($ret_id)) $ret_id = $focus->id;
1208 if($focus->object_name == 'Contact') {
1209 $contact_id = $focus->id;
1210 $to_addrs_ids = $focus->id;
1211 $to_addrs_names = $fullName;
1212 $to_addrs_emails = $focus->email1;
1215 $emailLinkUrl = 'contact_id='.$contact_id.
1216 '&parent_type='.$focus->module_dir.
1217 '&parent_id='.$focus->id.
1218 '&parent_name='.urlencode($fullName).
1219 '&to_addrs_ids='.$to_addrs_ids.
1220 '&to_addrs_names='.urlencode($to_addrs_names).
1221 '&to_addrs_emails='.urlencode($to_addrs_emails).
1222 '&to_email_addrs='.urlencode($fullName . ' <' . $email . '>').
1223 '&return_module='.$ret_module.
1224 '&return_action='.$ret_action.
1225 '&return_id='.$ret_id;
1227 //Generate the compose package for the quick create options.
1228 require_once('modules/Emails/EmailUI.php');
1229 $eUi = new EmailUI();
1230 $j_quickComposeOptions = $eUi->generateComposePackageForQuickCreateFromComposeUrl($emailLinkUrl, true);
1231 $emailLink = "<a href='javascript:void(0);' onclick='SUGAR.quickCompose.init($j_quickComposeOptions);' class='$class'>";
1235 $emailLink = '<a href="mailto:'.$focus->$attribute.'" class="'.$class.'">';
1243 * gets a human-readable explanation of the format macro
1244 * @return string Human readable name format
1246 function getLocaleFormatDesc() {
1248 global $mod_strings;
1249 global $app_strings;
1251 $format['f'] = $mod_strings['LBL_LOCALE_DESC_FIRST'];
1252 $format['l'] = $mod_strings['LBL_LOCALE_DESC_LAST'];
1253 $format['s'] = $mod_strings['LBL_LOCALE_DESC_SALUTATION'];
1254 $format['t'] = $mod_strings['LBL_LOCALE_DESC_TITLE'];
1256 $name['f'] = $app_strings['LBL_LOCALE_NAME_EXAMPLE_FIRST'];
1257 $name['l'] = $app_strings['LBL_LOCALE_NAME_EXAMPLE_LAST'];
1258 $name['s'] = $app_strings['LBL_LOCALE_NAME_EXAMPLE_SALUTATION'];
1259 $name['t'] = $app_strings['LBL_LOCALE_NAME_EXAMPLE_TITLE'];
1261 $macro = $locale->getLocaleFormatMacro();
1265 for($i=0; $i<strlen($macro); $i++) {
1266 if(array_key_exists($macro{$i}, $format)) {
1267 $ret1 .= "<i>".$format[$macro{$i}]."</i>";
1268 $ret2 .= "<i>".$name[$macro{$i}]."</i>";
1270 $ret1 .= $macro{$i};
1271 $ret2 .= $macro{$i};
1274 return $ret1."<br />".$ret2;
1279 * Whether or not based on the user's locale if we should show the last name first.
1283 public function showLastNameFirst(){
1285 $localeFormat = $locale->getLocaleFormatMacro($this);
1286 if ( strpos($localeFormat,'l') > strpos($localeFormat,'f') ) {
1295 function create_new_list_query($order_by, $where,$filter=array(),$params=array(), $show_deleted = 0,$join_type='', $return_array = false,$parentbean=null, $singleSelect = false)
1296 { //call parent method, specifying for array to be returned
1297 $ret_array = parent::create_new_list_query($order_by, $where,$filter,$params, $show_deleted,$join_type, true,$parentbean, $singleSelect);
1299 //if this is being called from webservices, then run additional code
1300 if(!empty($GLOBALS['soap_server_object'])){
1302 //if this is a single select, then secondary queries are being run that may result in duplicate rows being returned through the
1303 //left joins with meetings/tasks/call. Add a group by to return one user record (bug 40250)
1306 $ret_array['order_by'] = ' Group By '.$this->table_name.'.id '.$ret_array['order_by'];
1310 //return array or query string
1316 return $ret_array['select'] . $ret_array['from'] . $ret_array['where']. $ret_array['order_by'];