if ($fqdn == $globals->mail->domain || $fqdn == $globals->mail->domain2) {
$res = XDB::query('SELECT a.uid
FROM accounts AS a
- INNER JOIN aliases AS al ON (al.id = a.uid AND al.type IN (\'alias\', \'a_vie\'))
+ INNER JOIN aliases AS al ON (al.uid = a.uid AND al.type IN (\'alias\', \'a_vie\'))
WHERE al.alias = {?}', $mbox);
if ($res->numRows()) {
return $res->fetchOneCell();
list($alias, $alias_fqdn) = explode('@', $redir);
$res = XDB::query("SELECT a.uid
FROM accounts AS a
- LEFT JOIN aliases AS al ON (al.id = a.uid AND al.type IN ('alias', 'a_vie'))
+ LEFT JOIN aliases AS al ON (al.uid = a.uid AND al.type IN ('alias', 'a_vie'))
WHERE al.alias = {?}", $alias);
if ($res->numRows()) {
return $res->fetchOneCell();
throw new UserNotFoundException($res->fetchColumn(1));
}
- protected static function loadMainFieldsFromUIDs(array $uids)
+ protected static function loadMainFieldsFromUIDs(array $uids, $respect_order = true)
{
global $globals;
$joins = '';
} else {
$fields = '';
}
+
+ if ($respect_order) {
+ $order = 'ORDER BY ' . XDB::formatCustomOrder('a.uid', $uids);
+ } else {
+ $order = '';
+ }
+
$uids = array_map(array('XDB', 'escape'), $uids);
- return XDB::iterator('SELECT a.uid, a.hruid, a.registration_date,
- CONCAT(af.alias, \'@' . $globals->mail->domain . '\') AS forlife,
- CONCAT(ab.alias, \'@' . $globals->mail->domain . '\') AS bestalias,
+
+ return XDB::iterator('SELECT a.uid, a.hruid, a.registration_date, ah.alias AS homonym,
+ IF (af.alias IS NULL, a.email, CONCAT(af.alias, \'@' . $globals->mail->domain . '\')) AS forlife,
+ CONCAT(af.alias, \'@' . $globals->mail->domain2 . '\') AS forlife_alternate,
+ IF (ab.alias IS NULL, a.email, CONCAT(ab.alias, \'@' . $globals->mail->domain . '\')) AS bestalias,
+ CONCAT(ab.alias, \'@' . $globals->mail->domain2 . '\') AS bestalias_alternate,
a.full_name, a.display_name, a.sex = \'female\' AS gender,
IF(a.state = \'active\', at.perms, \'\') AS perms,
a.email_format, a.is_admin, a.state, a.type, a.skin,
' . $fields . '
FROM accounts AS a
INNER JOIN account_types AS at ON (at.type = a.type)
- LEFT JOIN aliases AS af ON (af.id = a.uid AND af.type = \'a_vie\')
- LEFT JOIN aliases AS ab ON (ab.id = a.uid AND FIND_IN_SET(\'bestalias\', ab.flags))
+ LEFT JOIN aliases AS af ON (af.uid = a.uid AND af.type = \'a_vie\')
+ LEFT JOIN aliases AS ab ON (ab.uid = a.uid AND FIND_IN_SET(\'bestalias\', ab.flags))
+ LEFT JOIN aliases AS ah ON (ah.uid = a.uid AND ah.type = \'homonyme\')
LEFT JOIN emails AS e ON (e.uid = a.uid AND e.flags = \'active\')
LEFT JOIN email_options AS eo ON (eo.uid = a.uid)
' . $joins . '
WHERE a.uid IN (' . implode(', ', $uids) . ')
- GROUP BY a.uid');
+ GROUP BY a.uid
+ ' . $order);
}
// Implementation of the data loader.
&& $this->gender !== null && $this->email_format !== null) {
return;
}
- $this->fillFromArray(self::loadMainFieldsFromUIDs(array($this->user_id))->next());
+ $this->fillFromArray(self::loadMainFieldsFromUIDs(array($this->uid))->next());
}
// Specialization of the fillFromArray method, to implement hacks to enable
// stop being used actively.
protected function fillFromArray(array $values)
{
- // It might happen that the 'user_id' field is called uid in some places
- // (eg. in sessions), so we hard link uid to user_id to prevent useless
- // SQL requests.
- if (!isset($values['user_id']) && isset($values['uid'])) {
- $values['user_id'] = $values['uid'];
- }
-
// Also, if display_name and full_name are not known, but the user's
// surname and last name are, we can construct the former two.
if (isset($values['prenom']) && isset($values['nom'])) {
if (isset($this->last_known_email)) {
return;
}
+ // FIXME: We should fetch the last known email as well as the pending registration email (they aren't the same !)
$infos = XDB::fetchOneAssoc('SELECT IF (MAX(m.last) > p.relance, MAX(m.last), p.relance) AS last_relance,
p.email AS last_known_email
FROM register_pending AS p
}
+ /** 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()
$this->fillFromArray($watch);
}
- public function watch($type)
+ public function watchType($type)
{
$this->fetchWatchData();
return $this->watch_actions->hasFlag($type);
return $this->watch_last;
}
+ public function invalidWatchCache()
+ {
+ unset($this->watch_actions);
+ unset($this->watch_users);
+ unset($this->watch_last);
+ unset($this->watch_promos);
+ }
+
// Contacts
private $contacts = null;
- public function isContact(PlUser &$user)
+ private function fetchContacts()
{
if (is_null($this->contacts)) {
$this->contacts = XDB::fetchAllAssoc('contact', 'SELECT *
WHERE uid = {?}',
$this->id());
}
- return isset($this->contacts[$user->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()
+ {
+ if (is_null($this->groups)) {
+ $this->groups = XDB::fetchAllAssoc('asso_id', 'SELECT asso_id, perms, comm
+ FROM group_members
+ WHERE uid = {?}',
+ $this->id());
+ }
+ return $this->groups;
+ }
+
+ public function groupNames($institutions = false)
+ {
+ if ($institutions) {
+ $where = ' AND (g.cat = \'GroupesX\' OR g.cat = \'Institutions\')';
+ } else {
+ $where = '';
+ }
+ return XDB::fetchAllAssoc('SELECT g.diminutif, g.nom, g.site
+ FROM group_members AS gm
+ LEFT JOIN groups AS g ON (g.id = gm.asso_id)
+ WHERE gm.uid = {?}' . $where,
+ $this->id());
+ }
+
+ /**
+ * Clears a user.
+ * *always deletes in: account_lost_passwords, register_marketing,
+ * register_pending, register_subs, watch_nonins, watch, watch_promo
+ * *always keeps in: account_types, accounts, aliases, axletter_ins, carvas,
+ * group_members, homonyms, newsletter_ins, register_mstats,
+ * *deletes if $clearAll: account_auth_openid, announce_read, contacts,
+ * email_options, email_send_save, emails, forum_innd, forum_profiles,
+ * forum_subs, gapps_accounts, gapps_nicknames, group_announces_read,
+ * group_member_sub_requests, reminder, requests, requests_hidden,
+ * virtual, virtual_redirect, ML
+ * *modifies if $clearAll: accounts
+ *
+ * Use cases:
+ * *$clearAll == false: when a user dies, her family still needs to keep in
+ * touch with the community.
+ * *$clearAll == true: in every other case we want the account to be fully
+ * deleted so that it can not be used anymore.
+ */
+ public function clear($clearAll = true)
+ {
+ XDB::execute('DELETE FROM account_lost_passwords, register_marketing,
+ register_pending, register_subs, watch_nonins,
+ watch, watch_promo
+ WHERE uid = {?}',
+ $this->id());
+
+ if ($clearAll) {
+ $groupIds = XDB::iterator('SELECT asso_id
+ FROM group_members
+ WHERE uid = {?}',
+ $this->id());
+ while ($groupId = $groupIds->next()) {
+ $group = Group::get($groupId);
+ if ($group->notif_unsub) {
+ $mailer = new PlMailer('xnetgrp/unsubscription-notif.mail.tpl');
+ $admins = $group->iterAdmins();
+ while ($admin = $admins->next()) {
+ $mailer->addTo($admin);
+ }
+ $mailer->assign('group', $group->shortname);
+ $mailer->assign('user', $this);
+ $mailer->assign('selfdone', false);
+ $mailer->send();
+ }
+ }
+
+ XDB::execute('DELETE FROM account_auth_openid, announce_read, contacts,
+ email_options, email_send_save, emails,
+ forum_innd, forum_profiles, forum_subs,
+ gapps_accounts, gapps_nicknames, group_announces_read,
+ group_members, group_member_sub_requests, reminder, requests,
+ requests_hidden
+ WHERE uid = {?}',
+ $this->id());
+ XDB::execute("UPDATE accounts
+ SET registration_date = 0, state = 'pending', password = NULL,
+ weak_password = NULL, token = NULL, is_admin = 0
+ WHERE uid = {?}",
+ $this->id());
+
+ XDB::execute('DELETE v.*
+ FROM virtual AS v
+ INNER JOIN virtual_redirect AS r ON (v.vid = r.vid)
+ WHERE redirect = {?} OR redirect = {?}',
+ $this->forlifeEmail(), $this->m4xForlifeEmail());
+ XDB::execute('DELETE FROM virtual_redirect
+ WHERE redirect = {?} OR redirect = {?}',
+ $this->forlifeEmail(), $this->m4xForlifeEmail());
+
+ if ($globals->mailstorage->googleapps_domain) {
+ require_once 'googleapps.inc.php';
+
+ if (GoogleAppsAccount::account_status($uid)) {
+ $account = new GoogleAppsAccount($user);
+ $account->suspend();
+ }
+ }
+ }
+
+ $mmlist = new MMList($this);
+ $mmlist->kill($alias, $clearAll);
+ }
+
+ // Merge all infos in other user and then clean this one
+ public function mergeIn(User &$newuser) {
+ if ($this->profile() || !$newuser->id()) {
+ // don't disable user with profile in this way
+ return false;
+ }
+ // TODO check all tables to see if there is no other info to use
+
+ $newemail = $newuser->forlifeEmail();
+ if (!$newemail && $this->forlifeEmail()) {
+ XDB::execute("UPDATE accounts
+ SET email = {?}
+ WHERE uid = {?} AND email IS NULL",
+ $this->forlifeEmail(), $newuser->id());
+ $newemail = $this->forlifeEmail();
+ }
+
+ // change email used in aliases and mailing lists
+ if ($this->forlifeEmail() != $newemail && $this->forlifeEmail()) {
+ // virtual_redirect (email aliases)
+ XDB::execute("DELETE v1
+ FROM virtual_redirect AS v1, virtual_redirect AS v2
+ WHERE v1.vid = v2.vid AND v1.redirect = {?} AND v2.redirect = {?}",
+ $this->forlifeEmail(), $newemail);
+ XDB::execute("UPDATE virtual_redirect
+ SET redirect = {?}
+ WHERE redirect = {?}",
+ $newemail, $this->forlifeEmail());
+
+ // require_once 'mmlist.php';
+
+ // group mailing lists
+ $group_domains = XDB::fetchColumn("SELECT g.mail_domain
+ FROM groups AS g
+ INNER JOIN group_members AS gm ON(g.id = gm.asso_id)
+ WHERE g.mail_domain != '' AND gm.uid = {?}",
+ $this->id());
+ foreach ($group_domains as $mail_domain) {
+ $mmlist = new MMList($this, $mail_domain);
+ $mmlist->replace_email_in_all($this->forlifeEmail(), $newmail);
+ }
+ // main domain lists
+ $mmlist = new MMList($this);
+ $mmlist->replace_email_in_all($this->forlifeEmail(), $newmail);
+ }
+
+ // group_members (xnet group membership)
+ XDB::execute("DELETE g1
+ FROM group_members AS g1, group_members AS g2
+ WHERE g1.uid = {?} AND g2.uid = {?} AND g1.asso_id = g2.asso_id",
+ $this->id(), $newuser->id());
+ XDB::execute("UPDATE group_members
+ SET uid = {?}
+ WHERE uid = {?}",
+ $this->id(), $newuser->id());
+
+ XDB::execute("DELETE FROM accounts WHERE uid = {?}", $this->id());
+
+ return true;
}
// Return permission flags for a given permission level.
|| $dom == $globals->mail->alias_dom2;
}
- // Fetch a set of users from a list of UIDs
+ /* Tries to find pending accounts with an hruid close to $login. */
+ public static function getPendingAccounts($login, $iterator = false)
+ {
+ global $globals;
+
+ if (strpos($login, '@') === false) {
+ return null;
+ }
+
+ list($login, $domain) = explode('@', $login);
+
+ if ($domain && $domain != $globals->mail->domain && $domain != $globals->mail->domain2) {
+ return null;
+ }
+
+ $sql = "SELECT uid, full_name
+ FROM accounts
+ WHERE state = 'pending' AND REPLACE(hruid, '-', '') LIKE
+ CONCAT('%', REPLACE(REPLACE(REPLACE({?}, ' ', ''), '-', ''), '\'', ''), '%')
+ ORDER BY full_name";
+ if ($iterator) {
+ return XDB::iterator($sql, $login);
+ } else {
+ $res = XDB::query($sql, $login);
+ return $res->fetchAllAssoc();
+ }
+ }
+
+
+ public static function iterOverUIDs($uids, $respect_order = true)
+ {
+ return new UserIterator(self::loadMainFieldsFromUIDs($uids, $respect_order));
+ }
+
+ /** Fetch a set of users from a list of UIDs
+ * @param $data The list of uids to fetch, or an array of arrays
+ * @param $orig If $data is an array of arrays, the subfield where uids are stored
+ * @param $dest If $data is an array of arrays, the subfield to fill with Users
+ * @param $fetchProfile Whether to fetch Profiles as well
+ * @return either an array of $uid => User, or $data with $data[$i][$dest] = User
+ */
public static function getBulkUsersWithUIDs(array $data, $orig = null, $dest = null, $fetchProfile = true)
{
// Fetch the list of uids
if (count($uids) == 0) {
return $data;
}
- $fields = self::loadMainFieldsFromUIDs($uids);
+ $users = self::iterOverUIDs($uids, true);
+
$table = array();
if ($fetchProfile) {
- $profiles = Profile::getBulkProfilesWithUIDS($uids);
+ $profiles = Profile::iterOverUIDS($uids, true);
+ if ($profiles != null) {
+ $profile = $profiles->next();
+ } else {
+ $profile = null;
+ }
}
- while (($list = $fields->next())) {
- $uid = $list['uid'];
- $user = User::getSilentWithValues(null, $list);
+
+ /** We iterate through the users, moving in
+ * profiles when they match the user ID :
+ * there can be users without a profile, but not
+ * the other way around.
+ */
+ while (($user = $users->next())) {
if ($fetchProfile) {
- if (isset($profiles[$uid])) {
- $user->_profile = $profiles[$uid];
+ if ($profile != null && $profile->owner_id == $user->id()) {
+ $user->_profile = $profile;
+ $profile = $profiles->next();
}
$user->_profile_fetched = true;
}
- $table[$list['uid']] = $user;
+ $table[$user->id()] = $user;
}
// Build the result with respect to input order.
if (is_null($orig)) {
- $users = array();
- foreach ($uids as $key=>$uid) {
- $users[$key] = $table[$uid];
- }
- return $users;
+ return $table;
} else {
foreach ($data as $key=>$entry) {
if (isset($entry[$orig])) {
}
}
+/** Iterator over a set of Users
+ * @param an XDB::Iterator obtained from a User::loadMainFieldsFromUIDs
+ */
+class UserIterator implements PlIterator
+{
+ private $dbiter;
+
+ public function __construct($dbiter)
+ {
+ $this->dbiter = $dbiter;
+ }
+
+ public function next()
+ {
+ $data = $this->dbiter->next();
+ if ($data == null) {
+ return null;
+ } else {
+ return User::getSilentWithValues(null, $data);
+ }
+ }
+
+ public function total()
+ {
+ return $this->dbiter->total();
+ }
+
+ public function first()
+ {
+ return $this->dbiter->first();
+ }
+
+ public function last()
+ {
+ return $this->dbiter->last();
+ }
+}
+
// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
?>