public function execute()
 {
     // only allowed to global admin
     if (!wa()->getUser()->getRights('webasyst', 'backend')) {
         throw new waRightsException('Access denied.');
     }
     $collection = new contactsCollection('users/all');
     $group = null;
     $memberIds = array();
     if ($id = waRequest::get('id')) {
         $group_model = new waGroupModel();
         $group = $group_model->getById($id);
     }
     if ($group) {
         $user_groups_model = new waUserGroupsModel();
         $memberIds = $user_groups_model->getContactIds($id);
     }
     $users = $collection->getContacts('id,name');
     // array(id => array(id=>...,name=>...))
     $members = array();
     foreach ($memberIds as $mid) {
         if (isset($users[$mid])) {
             $members[$mid] = $users[$mid];
             unset($users[$mid]);
         }
     }
     usort($members, array($this, '_cmp'));
     usort($users, array($this, '_cmp'));
     $this->view->assign('group', $group);
     $this->view->assign('notIncluded', $users);
     $this->view->assign('members', $members);
 }
 public function execute()
 {
     $term = waRequest::request('term');
     $limit = waRequest::request('limit', 30, 'int');
     if (mb_strlen($term) < 2) {
         return;
     }
     $type = waRequest::request('type', null, waRequest::TYPE_STRING_TRIM);
     $model = new waModel();
     if (strpos($term, '@') !== FALSE) {
         $contacts = new contactsCollection('/search/email*=' . $term);
     } else {
         $contacts = new contactsCollection();
         $t_a = preg_split("/\\s+/", $term);
         $cond = array();
         foreach ($t_a as $t) {
             $t = trim($t);
             if ($t) {
                 $t = $model->escape($t, 'like');
                 if ($type === 'person') {
                     $cond[] = "(c.firstname LIKE '{$t}%' OR c.middlename LIKE '{$t}%' OR c.lastname LIKE '{$t}%')";
                 } else {
                     if ($type === 'company') {
                         $cond[] = "c.name LIKE '{$t}%'";
                     } else {
                         $cond[] = "(c.firstname LIKE '{$t}%' OR c.middlename LIKE '{$t}%' OR c.lastname LIKE '{$t}%' OR c.name LIKE '{$t}%')";
                     }
                 }
             }
         }
         if ($cond) {
             $contacts->addWhere(implode(" AND ", $cond));
         }
     }
     if ($type) {
         if ($type === 'person') {
             $contacts->addWhere("is_company = 0");
         } else {
             if ($type === 'company') {
                 $contacts->addWhere("is_company = 1");
             }
         }
     }
     $this->response = array();
     $term_safe = htmlspecialchars($term);
     foreach ($contacts->getContacts('id,name,company,email', 0, $limit) as $c) {
         $name = $this->prepare($c['name'], $term_safe);
         $email = $this->prepare(ifset($c['email'][0], ''), $term_safe);
         $company = $this->prepare($c['company'], $term_safe);
         $this->response[] = array('label' => implode(', ', array_filter(array($name, $company, $email))), 'value' => $c['id'], 'name' => $c['name'], 'email' => ifset($c['email'][0], ''), 'company' => $c['company']);
     }
 }
 public function execute()
 {
     $this->view->assign('views', null);
     $this->view->assign('settings', $this->getUser()->getSettings('contacts'));
     $historyModel = new contactsHistoryModel();
     $this->view->assign('history', $historyModel->get());
     $cc = new contactsCollection();
     $this->view->assign('totalContacts', $cc->count());
     // only show categories available to current user
     //        $crm = new contactsRightsModel();
     $wcrm = new waContactRightsModel();
     $ccm = new waContactCategoryModel();
     //        $allowed = $crm->getAllowedCategories();
     //        $categories = array();
     //        if($allowed === true) {
     //            $categories = $ccm->getAll();
     //        } else if ($allowed) {
     //            foreach($ccm->getAll() as $cat) {
     //                if (isset($allowed[$cat['id']])) {
     //                    $categories[] = $cat;
     //                }
     //            }
     //        }
     $categories = $ccm->getAll();
     $this->view->assign('categories', $categories);
     // User views are only available to global admin
     $r = new waContactRightsModel();
     $this->view->assign('superadmin', FALSE);
     $this->view->assign('admin', FALSE);
     if (wa()->getUser()->getRights('webasyst', 'backend')) {
         $this->view->assign('superadmin', TRUE);
         $this->view->assign('admin', TRUE);
         //            $group_model = new waGroupModel();
         //            $this->view->assign('groups', $group_model->getAll());
         $cc = new contactsCollection('/users/all/');
         $this->view->assign('totalUsers', $cc->count());
     } else {
         if (wa()->getUser()->getRights('contacts', 'backend') >= 2) {
             $this->view->assign('admin', TRUE);
         }
     }
     // is user allowed to add contacts?
     $this->view->assign('show_create', $wcrm->get(null, null, 'create'));
     $event_params = array();
     $this->view->assign('backend_sidebar', wa()->event('backend_sidebar', $event_params, array('top_li')));
 }
 public function execute()
 {
     $term = waRequest::request('term');
     $limit = waRequest::request('limit', 30, 'int');
     if (mb_strlen($term) < 2) {
         return;
     }
     if (strpos($term, '@') !== FALSE) {
         $contacts = new contactsCollection('/search/email*=' . $term);
     } else {
         $contacts = new contactsCollection('/search/name*=' . $term);
     }
     $this->response = array();
     $term_safe = htmlspecialchars($term);
     foreach ($contacts->getContacts('id,name,company,email', 0, $limit) as $c) {
         $name = $this->prepare($c['name'], $term_safe);
         $email = $this->prepare(ifset($c['email'][0], ''), $term_safe);
         $company = $this->prepare($c['company'], $term_safe);
         $this->response[] = array('label' => implode(', ', array_filter(array($name, $company, $email))), 'value' => $c['id'], 'name' => $c['name'], 'email' => ifset($c['email'][0], ''), 'company' => $c['company']);
     }
 }
 public function getLastViewContext()
 {
     if ($this->getRequest()->get('last_hash') === null) {
         return null;
     }
     $params = array('hash' => $this->getRequest()->get('last_hash', ''), 'sort' => $this->getRequest()->get('sort', ''), 'order' => $this->getRequest()->get('order', 1, 'int') ? ' ASC' : ' DESC', 'offset' => $this->getRequest()->get('offset', 0));
     $context = null;
     $plugins_context = wa()->event('backend_last_view_context', $params);
     foreach ($plugins_context as $cntx) {
         if (!empty($cntx)) {
             $context = $cntx;
             break;
         }
     }
     if (!$context) {
         $hash = $params['hash'];
         $sort = $params['sort'];
         $order = $params['order'];
         $offset = $params['offset'];
         $collection = new contactsCollection($hash);
         if ($sort) {
             $collection->orderBy($sort, $order);
         }
         $total_count = $collection->count();
         $ids = array_keys($collection->getContacts('id', max($offset - 1, 0), 3));
         $prev = null;
         $next = null;
         if ($offset > 0) {
             $prev = $ids[0];
             if ($offset < $total_count - 1) {
                 $next = $ids[2];
             }
         } else {
             if ($offset < $total_count - 1) {
                 $next = $ids[1];
             }
         }
         $context = array('total_count' => $total_count, 'offset' => $offset, 'prev' => $prev, 'next' => $next);
     }
     return $context;
 }
 /**
  * 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;
 }
 public function execute()
 {
     // only allowed to admin
     if ($this->getRights('backend') <= 1) {
         throw new waRightsException(_w('Access denied'));
     }
     $ids = waRequest::request('ids', array(), 'array_int');
     $collection = new contactsCollection('id/' . implode(',', $ids));
     $collection->orderBy('~data', 'DESC');
     $contacts = $collection->getContacts('*,photo_url_96', 0, 500);
     foreach ($contacts as &$c) {
         $c['name'] = waContactNameField::formatName($c);
     }
     unset($c);
     // Field names
     $fields = array();
     // field id => field name
     foreach (waContactFields::getAll('enabled') as $field_id => $field) {
         $fields[$field_id] = $field->getName();
         // Format data for template if needed
         foreach ($contacts as &$c) {
             if (empty($c[$field_id])) {
                 continue;
             }
             if (!is_array($c[$field_id]) || $this->is_assoc($c[$field_id])) {
                 $c[$field_id] = $field->format($c[$field_id], 'html');
             } else {
                 foreach ($c[$field_id] as &$v) {
                     $v = $field->format($v, 'html');
                 }
                 unset($v);
                 $c[$field_id] = implode(', ', $c[$field_id]);
             }
         }
         unset($c);
     }
     // skip some fields in the list
     $fields = array_diff_key($fields, array('title' => true, 'name' => true, 'photo' => true, 'firstname' => true, 'middlename' => true, 'lastname' => true, 'locale' => true, 'timezone' => true));
     // Initialize 'master_only' key
     foreach ($contacts as &$c) {
         $c['master_only'] = '';
     }
     unset($c);
     // Event to allow other applications to add their data if needed
     $params = array_keys($contacts);
     $links = wa()->event('links', $params);
     $apps = wa()->getApps();
     foreach ($links as $app_id => $app_links) {
         foreach ($app_links as $contact_id => $contact_links) {
             foreach ($contact_links as $l) {
                 // Show information about links
                 $field_name = $apps[$app_id]['name'] . '/' . $l['role'];
                 $fields[$field_name] = $field_name;
                 $contacts[$contact_id][$field_name] = _w("%d link", "%d links", $l['links_number']);
                 // Show warning if this contact cannot be merged into other contacts.
                 if (!empty($l['forbid_merge_reason'])) {
                     if (!empty($contacts[$contact_id]['master_only'])) {
                         $contacts[$contact_id]['master_only'] .= '<br>';
                     } else {
                         $contacts[$contact_id]['master_only'] = '';
                     }
                     $contacts[$contact_id]['master_only'] .= $l['forbid_merge_reason'];
                 }
             }
         }
     }
     // List of contacts that can be safely merged into other contacts
     $slave_ids = array();
     foreach ($contacts as &$c) {
         if ($c['is_user'] > 0) {
             $c['master_only'] = ($c['master_only'] ? $c['master_only'] . '<br>' : '') . _w('Users can not be merged into other contacts.');
         } else {
             if (empty($c['master_only'])) {
                 $slave_ids[] = $c['id'];
             }
         }
         $author = array('name' => '');
         if ($c['create_contact_id']) {
             $author_contact = new waContact($c['create_contact_id']);
             if ($author_contact->exists()) {
                 $author = $author_contact;
             }
         }
         $c['author'] = $author;
     }
     unset($c);
     $this->view->assign('slave_ids', $slave_ids);
     $this->view->assign('contacts', $contacts);
     $this->view->assign('fields', $fields);
 }
 public function execute()
 {
     $this->prepare();
     if ($query = trim(waRequest::post('query'), '/')) {
         if (strpos($query, '/') === false) {
             $h = $hash = 'search/' . $query;
         } else {
             $h = $hash = $query;
             if (substr($hash, 0, 14) == 'import/results') {
                 $h = str_replace('import/results', 'import', $hash);
             }
         }
     } else {
         $h = $hash = '';
     }
     $h_parts = explode('/', $h, 2);
     $add_fields = array();
     if ($h_parts[0] == 'explore') {
         $collection = new contactsCollection();
         $event_params = array('collection' => $collection, 'hash' => $h_parts[1]);
         $result = wa()->event('explore', $event_params);
         if ($result) {
             $result = reset($result);
             $add_fields = ifset($result['fields']);
             $this->response['add_fields'] = $add_fields;
             $this->response['name'] = $result['name'];
         }
     } else {
         $collection = new contactsCollection($h);
     }
     $this->response['fields'] = array();
     $fields = '*,photo_url_32,photo_url_96';
     if ($h_parts[0] === 'users') {
         $fields .= ',_access';
         $this->response['fields']['_access'] = array('id' => '_access', 'name' => _w('Access'), 'type' => 'Access', 'vertical' => true);
     }
     $collection->orderBy($this->sort, $this->order);
     $this->response['count'] = $collection->count();
     $view = waRequest::post('view');
     if ($view == 'list') {
         // Preload info to cache to avoid excess DB access
         $cm = new waCountryModel();
         $cm->preload();
     }
     $this->response['contacts'] = array_values($collection->getContacts($fields, $this->offset, $this->limit));
     $this->workupContacts($this->response['contacts']);
     $this->response['total_count'] = $collection->count();
     foreach ($this->response['contacts'] as $i => &$c) {
         $c['offset'] = $this->offset + $i;
     }
     unset($c);
     if ($view == 'list') {
         // Need to format field values correctly for this view.
         foreach ($this->response['contacts'] as &$cdata) {
             $c = new waContact($cdata['id']);
             $c->setCache($cdata);
             $data = $c->load('list,js') + $cdata;
             contactsHelper::normalzieContactFieldValues($data, waContactFields::getInfo($c['is_company'] ? 'company' : 'person', true));
             if (isset($data['photo'])) {
                 $data['photo'] = $c->getPhoto();
             }
             $c->removeCache(array_keys($cdata));
             $cdata = $data;
         }
         $this->response['fields'] = array_merge($this->response['fields'], contactsHelper::getFieldsDescription(array('title', 'name', 'photo', 'firstname', 'middlename', 'lastname', 'locale', 'timezone', 'jobtitle', 'company', 'sex', 'company_contact_id'), true));
         unset($cdata);
     }
     // for companies set name to company name
     // for contacts with empty name, set it to <no name>
     foreach ($this->response['contacts'] as &$c) {
         if (isset($c['name']) && trim($c['name'])) {
             continue;
         }
         if (isset($c['company']) && trim($c['company'])) {
             $c['name'] = $c['company'];
             unset($c['company']);
             continue;
         }
         $c['name'] = '<' . _w('no name') . '>';
     }
     unset($c);
     $title = $collection->getTitle();
     $hm = new contactsHistoryModel();
     if ($hash) {
         $type = explode('/', $hash);
         $hash = substr($hash, 0, 1) == '/' ? $hash : '/contacts/' . $hash;
         $type = $type[0];
         // if search query looks like a quick search then remove field name from header
         if ($type == 'search' && preg_match('~^/contacts/search/(name\\*=[^/]*|email\\*=[^/]*@[^/]*)/?$~i', $hash)) {
             $title = preg_replace("~^[^=]+=~", '', $title);
         }
         // save history
         if ($type == 'search') {
             $hm->save($hash, $title, $type, $this->response['count']);
             $this->logAction('search');
         }
         // Information about system category in categories view
         if (substr($hash, 0, 19) === '/contacts/category/') {
             $category_id = (int) substr($hash, 19);
             $cm = new waContactCategoryModel();
             $category = $cm->getById($category_id);
             if ($category && $category['system_id']) {
                 $this->response['system_category'] = $category['system_id'];
             }
         }
     }
     // Update history in user's browser
     $this->response['history'] = $hm->get();
     $this->response['title'] = $title;
 }
 /** Get all history for current user, or a single history record
  * @param int $id (defaults to null) id of a record to fetch
  * @return array if $id is specified, then null (if not found) or a single array with keys: id, type, name, hash, contact_id, position, accessed, cnt; if no $id, then a list of such arrays is returned. */
 public function get($id = null)
 {
     if ($id) {
         $sql = "SELECT * FROM {$this->table} WHERE id=i:id";
         return $this->query($sql, array('id' => $id))->fetchRow();
     }
     $currentUserId = wa()->getUser()->getId();
     $sql = "SELECT *\n                FROM {$this->table}\n                WHERE contact_id=:uid\n                ORDER BY position, accessed DESC";
     $history = $this->query($sql, array('uid' => $currentUserId))->fetchAll();
     $contact_ids = array();
     foreach ($history as $h) {
         if ($h['type'] === 'add') {
             $contact_id = (int) str_replace('/contact/', '', $h['hash']);
             if ($contact_id) {
                 $contact_ids[] = $contact_id;
             }
         }
     }
     $contacts = array();
     if ($contact_ids) {
         $col = new contactsCollection('id/' . implode(',', $contact_ids));
         $contacts = $col->getContacts('id,is_company,photo_url_20');
     }
     foreach ($history as &$h) {
         if ($h['type'] === 'add') {
             $contact_id = (int) str_replace('/contact/', '', $h['hash']);
             $contact = ifset($contacts[$contact_id], array('is_company' => 0, 'photo_url_20' => waContact::getPhotoUrl(null, null, 20, 20, 'person')));
             $h['icon'] = $contact['photo_url_20'];
         }
     }
     unset($h);
     // leave only NUM_HISTORY_SHOW temporary items (i.e. position == 0 and type != import)
     $ra_limit = self::NUM_HISTORY_SHOW;
     // recently added
     $s_limit = self::NUM_HISTORY_SHOW;
     // search history
     $not_shown = array();
     foreach ($history as $k => $v) {
         if ($v['position'] > 0) {
             break;
         }
         if ($v['type'] != 'search') {
             if ($ra_limit <= 0) {
                 $not_shown[] = $v['id'];
                 unset($history[$k]);
                 continue;
             }
             $ra_limit--;
         } else {
             if ($s_limit <= 0) {
                 $not_shown[] = $v['id'];
                 unset($history[$k]);
                 continue;
             }
             $s_limit--;
         }
     }
     if ($not_shown) {
         $sql = "DELETE FROM {$this->table} WHERE id IN (i:id)";
         $this->exec($sql, array('id' => $not_shown));
         // reset holes in key sequence
         $history = array_merge($history);
     }
     return $history;
 }