+ public function setPerms($perms)
+ {
+ $this->perms = $perms;
+ $this->perm_flags = null;
+ }
+
+ /** Retrieve the 'general' read visibility.
+ * This is the maximum level of fields that may be viewed by the current user on other profiles.
+ *
+ * Rules are:
+ * - Everyone can view 'public'
+ * - directory_ax gives access to 'AX' level
+ * - directory_private gives access to 'private' level
+ * - admin gives access to 'hidden' level
+ */
+ public function readVisibility()
+ {
+ $level = Visibility::VIEW_NONE;
+ if ($this->is_admin) {
+ $level = Visibility::VIEW_ADMIN;
+ } elseif ($this->checkPerms('directory_private')) {
+ $level = Visibility::VIEW_PRIVATE;
+ } elseif ($this->checkPerms('directory_ax')) {
+ $level = Visibility::VIEW_AX;
+ } else {
+ $level = Visibility::VIEW_PUBLIC;
+ }
+ return Visibility::get($level);
+ }
+
+ /** Retrieve the 'general' edit visibility.
+ * This is the maximum level of fields that may be edited by the current user on other profiles.
+ *
+ * Rules are:
+ * - Only admins can edit the 'hidden' fields
+ * - If someone has 'directory_edit' (which is actually directory_ax_edit): AX level
+ * - Otherwise, nothing.
+ */
+ public function editVisibility()
+ {
+ $level = Visibility::VIEW_NONE;
+ if ($this->is_admin) {
+ $level = Visibility::VIEW_ADMIN;
+ } elseif ($this->checkPerms('directory_edit')) {
+ $level = Visibility::VIEW_AX;
+ }
+ return Visibility::get($level);
+ }
+
+ // We do not want to store the password in the object.
+ // So, fetch it 'on demand'
+ public function password()
+ {
+ return XDB::fetchOneCell('SELECT a.password
+ FROM accounts AS a
+ WHERE a.uid = {?}', $this->id());
+ }
+
+ public function isActive()
+ {
+ return $this->state == 'active';
+ }
+
+ /** Overload PlUser::promo(): there no promo defined for a user in the current
+ * schema. The promo is a field from the profile.
+ */
+ public function promo()
+ {
+ if (!$this->hasProfile()) {
+ return '';
+ }
+ return $this->profile()->promo();
+ }
+
+ public function category()
+ {
+ $promo = $this->promo();
+ if (!empty($promo)) {
+ return $promo;
+ } else {
+ return $this->type_description;
+ }
+ }
+
+ public function firstName()
+ {
+ if (!$this->hasProfile()) {
+ return $this->firstname;
+ }
+ return $this->profile()->firstName();
+ }
+
+ public function lastName()
+ {
+ if (!$this->hasProfile()) {
+ return $this->lastname;
+ }
+ return $this->profile()->lastName();
+ }
+
+ public function displayName()
+ {
+ if (!$this->hasProfile()) {
+ return $this->display_name;
+ }
+ return $this->profile()->yourself;
+ }
+
+ public function fullName($with_promo = false)
+ {
+ if (!$this->hasProfile()) {
+ return $this->full_name;
+ }
+ return $this->profile()->fullName($with_promo);
+ }
+
+ public function shortName($with_promo = false)
+ {
+ if (!$this->hasProfile()) {
+ return $this->full_name;
+ }
+ return $this->profile()->shortName($with_promo);
+ }
+
+ public function directoryName()
+ {
+ if (!$this->hasProfile()) {
+ return $this->directory_name;
+ }
+ return $this->profile()->directory_name;
+ }
+
+ static public function compareDirectoryName($a, $b)
+ {
+ return strcasecmp(replace_accent($a->directoryName()), replace_accent($b->directoryName()));
+ }
+
+ /** Return the main profile attached with this account if any.
+ */
+ public function profile($forceFetch = false, $fields = 0x0000, $visibility = null)
+ {
+ if (!$this->_profile_fetched || $forceFetch) {
+ $this->_profile_fetched = true;
+ $this->_profile = Profile::get($this, $fields, $visibility);
+ } else if ($this->_profile !== null && $visibility !== null && !$this->_profile->visibility->equals($visibility)) {
+ return Profile::get($this, $fields, $visibility);
+ }
+ return $this->_profile;
+ }
+
+ public function setPrefetchedProfile(Profile $profile)
+ {
+ $this->_profile_fetched = true;
+ $this->_profile = $profile;
+ }
+
+ /** Return true if the user has an associated profile.
+ */
+ public function hasProfile()
+ {
+ return !is_null($this->profile());
+ }
+
+ /** Return true if given a reference to the profile of this user.
+ */
+ public function isMyProfile($other)
+ {
+ if (!$other) {
+ return false;
+ } else if ($other instanceof Profile) {
+ $profile = $this->profile();
+ return $profile && $profile->id() == $other->id();
+ }
+ return false;
+ }
+
+ /** Check if the user can edit to given profile.
+ */
+ public function canEdit(Profile $profile)
+ {
+ if ($this->checkPerms(User::PERM_EDIT_DIRECTORY)) {
+ return true;
+ }
+ return XDB::fetchOneCell('SELECT pid
+ FROM account_profiles
+ WHERE uid = {?} AND pid = {?}',
+ $this->id(), $profile->id());
+ }
+
+ /** Determines main email domain for this user.
+ */
+ public function mainEmailDomain()
+ {
+ if (array_key_exists($this->type, self::$sub_mail_domains)) {
+ return self::$sub_mail_domains[$this->type] . Platal::globals()->mail->domain;
+ }
+ }
+
+ /** Determines alternate email domain for this user.
+ */
+ public function alternateEmailDomain()
+ {
+ if (array_key_exists($this->type, self::$sub_mail_domains)) {
+ return self::$sub_mail_domains[$this->type] . Platal::globals()->mail->domain2;
+ }
+ }
+
+ public function forlifeEmailAlternate()
+ {
+ if (!empty($this->forlife_alternate)) {
+ return $this->forlife_alternate;
+ }
+ return $this->email;
+ }
+
+ /** Fetch existing auxiliary alias.
+ */
+ public function emailAlias()
+ {
+ $aliases = $this->emailAliases();
+ if (count($aliases)) {
+ return $aliases[0];
+ }
+ return null;
+ }
+
+ /** Fetch existing auxiliary aliases.
+ */
+ public function emailAliases()
+ {
+ return XDB::fetchColumn('SELECT CONCAT(s.email, \'@\', d.name)
+ FROM email_source_account AS s
+ INNER JOIN email_virtual_domains AS m ON (s.domain = m.id)
+ INNER JOIN email_virtual_domains AS d ON (d.aliasing = m.id)
+ WHERE s.uid = {?} AND s.type = \'alias_aux\'
+ ORDER BY d.name',
+ $this->id());
+ }
+
+ /** Get all group aliases the user belongs to.
+ */
+ public function emailGroupAliases($domain = null)
+ {
+ if (is_null($domain)) {
+ return XDB::fetchColumn('SELECT CONCAT(v.email, \'@\', dv.name) AS alias
+ FROM email_virtual AS v
+ INNER JOIN email_virtual_domains AS dv ON (v.domain = dv.id)
+ INNER JOIN email_source_account AS s ON (s.uid = {?})
+ INNER JOIN email_virtual_domains AS ms ON (s.domain = ms.id)
+ INNER JOIN email_virtual_domains AS ds ON (ds.aliasing = ms.id)
+ WHERE v.redirect = CONCAT(s.email, \'@\', ds.name) AND v.type = \'alias\'',
+ $this->id());
+ } else {
+ return XDB::fetchAllAssoc('alias',
+ 'SELECT CONCAT(v.email, \'@\', dv.name) AS alias, MAX(v.redirect = CONCAT(s.email, \'@\', ds.name)) AS sub
+ FROM email_virtual AS v
+ INNER JOIN email_virtual_domains AS dv ON (v.domain = dv.id AND dv.name = {?})
+ INNER JOIN email_source_account AS s ON (s.uid = {?})
+ INNER JOIN email_virtual_domains AS ms ON (s.domain = ms.id)
+ INNER JOIN email_virtual_domains AS ds ON (ds.aliasing = ms.id)
+ WHERE v.type = \'alias\'
+ GROUP BY v.email
+ ORDER BY v.email',
+ $domain, $this->id());
+ }
+ }
+
+ /** Get marketing informations
+ */
+ private function fetchMarketingData()
+ {
+ if (isset($this->pending_registration_date)) {
+ return;
+ }
+ $infos = XDB::fetchOneAssoc('SELECT rp.date AS pending_registration_date, rp.email AS pending_registration_email,
+ rm.last AS last_marketing_date, rm.email AS last_marketing_email
+ FROM accounts AS a
+ LEFT JOIN register_pending AS rp ON (rp.uid = a.uid)
+ LEFT JOIN register_marketing AS rm ON (rm.uid = a.uid AND rm.last != \'0000-00-00\')
+ WHERE a.uid = {?}
+ ORDER BY rm.last DESC', $this->id());
+ if (is_null($infos)) {
+ $infos = array(
+ 'pending_registration_date' => null,
+ 'pending_registration_email' => null,
+ 'last_marketing_date' => null,
+ 'last_marketing_email' => null
+ );
+ }
+ $this->fillFromArray($infos);
+ }
+
+ public function pendingRegistrationDate()
+ {
+ $this->fetchMarketingData();
+ return $this->pending_registration_date;
+ }
+
+ public function pendingRegistrationEmail()
+ {
+ $this->fetchMarketingData();
+ return $this->pending_registration_email;
+ }
+
+ public function lastMarketingDate()
+ {
+ $this->fetchMarketingData();
+ return $this->last_marketing_date;
+ }
+
+ public function lastMarketingEmail()
+ {
+ $this->fetchMarketingData();
+ return $this->last_marketing_email;
+ }
+
+ public function lastKnownEmail()
+ {
+ $this->fetchMarketingData();
+ if ($this->pending_registration_email > $this->last_marketing_date) {
+ return $this->pending_registration_email;
+ }
+ return $this->last_marketing_email;
+ }
+
+
+ /** Format of the emails sent by the site
+ */
+ public function setEmailFormat($format)
+ {
+ Platal::assert($format == self::FORMAT_HTML || $format == self::FORMAT_TEXT,
+ "Invalid email format \"$format\"");
+ XDB::execute("UPDATE accounts
+ SET email_format = {?}
+ WHERE uid = {?}",
+ $format, $this->uid);
+ $this->email_format = $format;
+ }
+
+ /** Get watch informations
+ */
+ private function fetchWatchData()
+ {
+ if (isset($this->watch_actions)) {
+ return;
+ }
+ $watch = XDB::fetchOneAssoc('SELECT flags AS watch_flags, actions AS watch_actions,
+ UNIX_TIMESTAMP(last) AS watch_last
+ FROM watch
+ WHERE uid = {?}', $this->id());
+ $watch['watch_flags'] = new PlFlagSet($watch['watch_flags']);
+ $watch['watch_actions'] = new PlFlagSet($watch['watch_actions']);
+ $watch['watch_promos'] = XDB::fetchColumn('SELECT promo
+ FROM watch_promo
+ WHERE uid = {?}', $this->id());
+ $watch['watch_groups'] = XDB::fetchColumn("SELECT w.groupid
+ FROM watch_group AS w
+ INNER JOIN groups AS g ON (w.groupid = g.id AND NOT FIND_IN_SET('private', pub))
+ WHERE w.uid = {?}", $this->id());
+ $watch['watch_users'] = XDB::fetchColumn('SELECT ni_id
+ FROM watch_nonins
+ WHERE uid = {?}', $this->id());
+ $this->fillFromArray($watch);
+ }
+
+ public function watchType($type)
+ {
+ $this->fetchWatchData();
+ return $this->watch_actions->hasFlag($type);
+ }
+
+ public function watchContacts()
+ {
+ $this->fetchWatchData();
+ return $this->watch_flags->hasFlag('contacts');
+ }
+
+ public function watchEmail()
+ {
+ $this->fetchWatchData();
+ return $this->watch_flags->hasFlag('mail');
+ }
+
+ public function watchPromos()
+ {
+ $this->fetchWatchData();
+ return $this->watch_promos;
+ }
+
+ public function watchGroups()
+ {
+ $this->fetchWatchData();
+ return $this->watch_groups;
+ }
+
+ public function watchUsers()
+ {
+ $this->fetchWatchData();
+ return $this->watch_users;
+ }
+
+ public function watchLast()
+ {
+ $this->fetchWatchData();
+ return $this->watch_last;
+ }
+
+ public function invalidWatchCache()
+ {
+ unset($this->watch_actions);
+ unset($this->watch_users);
+ unset($this->watch_last);
+ unset($this->watch_promos);
+ unset($this->watch_groups);
+ }
+
+
+ // Contacts
+ private $contacts = null;
+ private function fetchContacts()
+ {
+ if (is_null($this->contacts)) {
+ $this->contacts = XDB::fetchAllAssoc('contact', 'SELECT *
+ FROM contacts
+ WHERE uid = {?}',
+ $this->id());
+ }
+ }
+
+ public function iterContacts()
+ {
+ $this->fetchContacts();
+ return Profile::iterOverPIDs(array_keys($this->contacts));
+ }
+
+ public function getContacts()
+ {
+ $this->fetchContacts();
+ return Profile::getBulkProfilesWithPIDs(array_keys($this->contacts));
+ }
+
+ public function isContact(Profile $profile)
+ {
+ $this->fetchContacts();
+ return isset($this->contacts[$profile->id()]);
+ }
+
+ public function isWatchedUser(Profile $profile)
+ {
+ return in_array($profile->id(), $this->watchUsers());
+ }
+
+ // Groupes X
+ private $groups = null;
+ public function groups($institutions = false, $onlyPublic = false)
+ {
+ if (is_null($this->groups)) {
+ $this->groups = XDB::fetchAllAssoc('asso_id', 'SELECT gm.asso_id, gm.perms, gm.comm,
+ g.diminutif, g.nom, g.site, g.cat,
+ g.pub
+ FROM group_members AS gm
+ INNER JOIN groups AS g ON (g.id = gm.asso_id)
+ WHERE uid = {?}',
+ $this->id());
+ }
+ if (!$institutions && !$onlyPublic) {
+ return $this->groups;
+ } else {
+ $result = array();
+ foreach ($this->groups as $id=>$data) {
+ if ($institutions) {
+ if ($data['cat'] != Group::CAT_GROUPESX && $data['cat'] != Group::CAT_INSTITUTIONS) {
+ continue;
+ }
+ }
+ if ($onlyPublic) {
+ if ($data['pub'] != 'public') {
+ continue;
+ }
+ }
+ $result[$id] = $data;
+ }
+ return $result;
+ }
+ }
+
+ public function groupCount()
+ {
+ return XDB::fetchOneCell('SELECT COUNT(DISTINCT(asso_id))
+ FROM group_members
+ WHERE uid = {?}',
+ $this->id());
+ }
+
+ public function inGroup($asso_id)