public function updateLastTime($force = false) { $time = $this->storage->read('user_last_datetime'); if (!$time || $force || $time == '0000-00-00 00:00:00' || time() - strtotime($time) > 120) { try { $login_log_model = new waLoginLogModel(); $last_activity = $login_log_model->getCurrent($this->id); } catch (waDbException $e) { if ($e->getCode() == 1146) { waSystem::getInstance()->getAuth()->clearAuth(); header("Location: " . wa()->getConfig()->getBackendUrl(true)); exit; } } $contact_model = new waContactModel(); $contact_info = $contact_model->getById($this->id); $auth = waSystem::getInstance()->getAuth(); if (!$auth->checkAuth($contact_info)) { header("Location: " . wa()->getConfig()->getRequestUrl(false)); exit; } if (!$contact_info || waSystem::getInstance()->getEnv() == 'backend' && !$contact_info['is_user']) { waSystem::getInstance()->getAuth()->clearAuth(); header("Location: " . wa()->getConfig()->getBackendUrl(true)); exit; } else { $this->setCache($contact_info); } if (!$time) { $time = $contact_info['last_datetime']; } if (!$last_activity) { $login_log_model->insert(array('contact_id' => $this->id, 'datetime_in' => date("Y-m-d H:i:s"), 'datetime_out' => $force == 'logout' ? date("Y-m-d H:i:s") : null)); // TODO: insert record in waLog } else { if ($force == 'logout') { $login_log_model->updateById($last_activity['id'], array('datetime_out' => date("Y-m-d H:i:s"))); } elseif ($last_datetime = strtotime($time)) { if (time() - $last_datetime > self::$options['activity_timeout']) { $login_log_model->updateById($last_activity['id'], array('datetime_out' => $time)); $login_log_model->insert(array('contact_id' => $this->id, 'datetime_in' => date("Y-m-d H:i:s"), 'datetime_out' => null)); // TODO: insert record in waLog } } } $t = date("Y-m-d H:i:s"); $contact_model->updateById($this->id, array('last_datetime' => $t)); $this->storage->write('user_last_datetime', $t); } }
public static function getStatusByInfo($info) { $timeout = self::$options['online_timeout']; // in sec if (isset($info['last_datetime']) && $info['last_datetime'] && $info['last_datetime'] != '0000-00-00 00:00:00') { if (time() - strtotime($info['last_datetime']) < $timeout) { $m = new waLoginLogModel(); $datetime_out = $m->select('datetime_out')->where('contact_id = i:0', array($this->id))->order('id DESC')->limit(1)->fetchField(); if (!$datetime_out) { return 'online'; } else { return 'offline'; } } } return 'offline'; }
/** * Get data for contacts in this collection. * @param string|array $fields * @param int $offset * @param int $limit * @return array [contact_id][field] = field value in appropriate field format * @throws waException */ public function getContacts($fields = "id", $offset = 0, $limit = 50) { $sql = "SELECT " . $this->getFields($fields) . " " . $this->getSQL(); $sql .= $this->getGroupBy(); $sql .= $this->getHaving(); $sql .= $this->getOrderBy(); $sql .= " LIMIT " . ($offset ? $offset . ',' : '') . (int) $limit; //header("X-SQL-". mt_rand() . ": ". str_replace("\n", " ", $sql)); $data = $this->getModel()->query($sql)->fetchAll('id'); $ids = array_keys($data); // // Load fields from other storages // if ($ids && $this->post_fields) { // $fill[table][field] = null // needed for all rows to always contain all apropriate keys // in case when we're asked to load all fields from that table $fill = array_fill_keys(array_keys($this->post_fields), array()); foreach (waContactFields::getAll('enabled') as $fid => $field) { /** * @var waContactField $field */ $fill[$field->getStorage(true)][$fid] = false; } foreach ($this->post_fields as $table => $fields) { if ($table == '_internal') { foreach ($fields as $f) { /** * @var $f string */ if ($f == 'photo_url' || substr($f, 0, 10) == 'photo_url_') { if ($f == 'photo_url') { $size = null; } else { $size = substr($f, 10); } $retina = isset($this->options['photo_url_2x']) ? $this->options['photo_url_2x'] : null; foreach ($data as $id => &$v) { $v[$f] = waContact::getPhotoUrl($id, $v['photo'], $size, $size, $v['is_company'] ? 'company' : 'person', $retina); } unset($v); } else { switch ($f) { case '_online_status': $llm = new waLoginLogModel(); $contact_ids_map = $llm->select('DISTINCT contact_id')->where('datetime_out IS NULL')->fetchAll('contact_id'); $timeout = waUser::getOption('online_timeout'); foreach ($data as &$v) { if (isset($v['last_datetime']) && $v['last_datetime'] && $v['last_datetime'] != '0000-00-00 00:00:00') { if (time() - strtotime($v['last_datetime']) < $timeout) { if (isset($contact_ids_map[$v['id']])) { $v['_online_status'] = 'online'; } else { $v['_online_status'] = 'offline'; } } } $v['_online_status'] = 'offline'; } unset($v); break; case '_access': $rm = new waContactRightsModel(); $accessStatus = $rm->getAccessStatus($ids); foreach ($data as $id => &$v) { if (!isset($accessStatus[$id])) { $v['_access'] = ''; continue; } $v['_access'] = $accessStatus[$id]; } unset($v); break; default: throw new waException('Unknown internal field: ' . $f); } } } continue; } $data_fields = $fields; foreach ($data_fields as $k => $field_id) { $f = waContactFields::get($field_id); if ($f && $f instanceof waContactCompositeField) { unset($data_fields[$k]); $data_fields = array_merge($data_fields, $f->getField()); } } $model = $this->getModel($table); $post_data = $model->getData($ids, $data_fields); foreach ($post_data as $contact_id => $contact_data) { foreach ($contact_data as $field_id => $value) { if (!($f = waContactFields::get($field_id))) { continue; } if (!$f->isMulti()) { $post_data[$contact_id][$field_id] = isset($value[0]['data']) ? $value[0]['data'] : (is_array($value[0]) ? $value[0]['value'] : $value[0]); } } } if ($fields) { $fill[$table] = array_fill_keys($fields, ''); } else { if (!isset($fill[$table])) { $fill[$table] = array(); } } foreach ($data as $contact_id => $v) { if (isset($post_data[$contact_id])) { $data[$contact_id] += $post_data[$contact_id]; } $data[$contact_id] += $fill[$table]; } } } return $data; }
/** * Merge given contacts into master contact, save, send merge event, then delete slaves. * * !!! Probably should move it into something like contactsHelper * * @param array $merge_ids list of contact ids * @param int $master_id contact id to merge others into * @return array */ public static function merge($merge_ids, $master_id) { $merge_ids[] = $master_id; // List of contacts to merge $collection = new contactsCollection('id/' . implode(',', $merge_ids)); $contacts_data = $collection->getContacts('*'); // Master contact data if (!$master_id || !isset($contacts_data[$master_id])) { throw new waException('No contact to merge into.'); } $master_data = $contacts_data[$master_id]; unset($contacts_data[$master_id]); $master = new waContact($master_id); $result = array('total_requested' => count($contacts_data) + 1, 'total_merged' => 0, 'error' => '', 'users' => 0); if ($master_data['photo']) { $filename = wa()->getDataPath(waContact::getPhotoDir($master_data['id']) . "{$master_data['photo']}.original.jpg", true, 'contacts'); if (!file_exists($filename)) { $master_data['photo'] = null; } } $data_fields = waContactFields::getAll('enabled'); $check_duplicates = array(); // field_id => true $update_photo = null; // if need to update photo here it is file paths // merge loop foreach ($contacts_data as $id => $info) { if ($info['is_user'] > 0) { $result['users']++; unset($contacts_data[$id]); continue; } foreach ($data_fields as $f => $field) { if (!empty($info[$f])) { if ($field->isMulti()) { $master->add($f, $info[$f]); $check_duplicates[$f] = true; } else { // Field does not allow multiple values. // Set value if no value yet. if (empty($master_data[$f])) { $master[$f] = $master_data[$f] = $info[$f]; } } } } // photo if (!$master_data['photo'] && $info['photo'] && !$update_photo) { $filename_original = wa()->getDataPath(waContact::getPhotoDir($info['id']) . "{$info['photo']}.original.jpg", true, 'contacts'); if (file_exists($filename_original)) { $update_photo = array('original' => $filename_original); $filename_crop = wa()->getDataPath(waContact::getPhotoDir($info['id']) . "{$info['photo']}.jpg", true, 'contacts'); if (file_exists($filename_crop)) { $update_photo['crop'] = $filename_crop; } } } // birthday parts if (!empty($data_fields['birthday'])) { foreach (array('birth_day', 'birth_month', 'birth_year') as $f) { if (empty($master_data[$f]) && !empty($info[$f])) { $master[$f] = $master_data[$f] = $info[$f]; } } } } // Remove duplicates foreach (array_keys($check_duplicates) as $f) { $values = $master[$f]; if (!is_array($values) || count($values) <= 1) { continue; } $unique_values = array(); // md5 => true foreach ($values as $k => $v) { if (is_array($v)) { if (isset($v['value']) && is_string($v['value'])) { $v = $v['value']; } else { unset($v['ext'], $v['status']); ksort($v); $v = serialize($v); } } $hash = md5(mb_strtolower($v)); if (!empty($unique_values[$hash])) { unset($values[$k]); continue; } $unique_values[$hash] = true; } $master[$f] = array_values($values); } // Save master contact $errors = $master->save(array(), 42); // 42 == do not validate anything at all if ($errors) { $errormsg = array(); foreach ($errors as $field => $err) { if (!is_array($err)) { $err = array($err); } foreach ($err as $str) { $errormsg[] = $field . ': ' . $str; } } $result['error'] = implode("\n<br>", $errormsg); return $result; } // Merge categories $category_ids = array(); $ccm = new waContactCategoriesModel(); foreach ($ccm->getContactsCategories($merge_ids) as $cid => $cats) { $category_ids += array_flip($cats); } $category_ids = array_keys($category_ids); $ccm->add($master_id, $category_ids); // update photo if ($update_photo) { $rand = mt_rand(); $path = wa()->getDataPath(waContact::getPhotoDir($master['id']), true, 'contacts', false); // delete old image if (file_exists($path)) { waFiles::delete($path); } waFiles::create($path); $filename = $path . "/" . $rand . ".original.jpg"; waFiles::create($filename); waImage::factory($update_photo['original'])->save($filename, 90); if (!empty($update_photo['crop'])) { $filename = $path . "/" . $rand . ".jpg"; waFiles::create($filename); waImage::factory($update_photo['crop'])->save($filename, 90); } else { waFiles::copy($filename, $path . "/" . $rand . ".jpg"); } $master->save(array('photo' => $rand)); } $result['total_merged'] = count($contacts_data) + 1; $contact_ids = array_keys($contacts_data); // wa_log $log_model = new waLogModel(); $log_model->updateByField('contact_id', $contact_ids, array('contact_id' => $master_id)); // wa_login_log $login_log_model = new waLoginLogModel(); $login_log_model->updateByField('contact_id', $contact_ids, array('contact_id' => $master_id)); // Merge event $params = array('contacts' => $contact_ids, 'id' => $master_data['id']); wa()->event(array('contacts', 'merge'), $params); // Delete all merged contacts $contact_model = new waContactModel(); $contact_model->delete($contact_ids, false); // false == do not trigger event $history_model = new contactsHistoryModel(); foreach ($contact_ids as $contact_id) { $history_model->deleteByField(array('type' => 'add', 'hash' => '/contact/' . $contact_id)); } return $result; }
/** * Returns user's status: "online", "offline" * * @return string */ public function getStatus() { $timeout = self::$options['online_timeout']; // in sec if (($last = $this->get('last_datetime')) && $last != '0000-00-00 00:00:00') { if (time() - strtotime($last) < $timeout) { $m = new waLoginLogModel(); $datetime_out = $m->select('datetime_out')->where('contact_id = i:0', array($this->id))->order('id DESC')->limit(1)->fetchField(); if ($datetime_out === null) { return 'online'; } else { return 'offline'; } } } return 'offline'; }
/** * Delete one or more contacts and fire event сontacts.delete * * @event contacts.delete * * @param int|array $id - contact id or array of contact ids * @return bool */ public function delete($id, $send_event = true) { if ($send_event) { // Fire @event contacts.delete allowing other applications to clean up their data wa()->event(array('contacts', 'delete'), $id); } if (is_array($id)) { $nid = array(); foreach ($id as $i) { $nid[] = -(int) $i; } } else { $nid = -(int) $id; } // Delete rights $right_model = new waContactRightsModel(); $right_model->deleteByField('group_id', $nid); // Delete settings $setting_model = new waContactSettingsModel(); $setting_model->deleteByField('contact_id', $id); // Delete emails $contact_email_model = new waContactEmailsModel(); $contact_email_model->deleteByField('contact_id', $id); // Delete from groups $user_groups_model = new waUserGroupsModel(); $user_groups_model->deleteByField('contact_id', $id); // Delete from contact lists if (class_exists('contactsContactListsModel')) { // @todo: Use plugin for contacts $contact_lists_model = new contactsContactListsModel(); $contact_lists_model->deleteByField('contact_id', $id); } // Delete from contact rights $contact_rights_model = new contactsRightsModel(); $contact_rights_model->deleteByField('group_id', $nid); // Delete data $contact_data_model = new waContactDataModel(); $contact_data_model->deleteByField('contact_id', $id); $contact_data_text_model = new waContactDataTextModel(); $contact_data_text_model->deleteByField('contact_id', $id); // Delete contact from logs $login_log_model = new waLoginLogModel(); $login_log_model->deleteByField('contact_id', $id); // Delete contact return $this->deleteById($id); }