1: <?php
2: /**
3: * This code is licensed under AGPLv3 license or Afterlogic Software License
4: * if commercial version of the product was purchased.
5: * For full statements of the licenses see LICENSE-AFTERLOGIC and LICENSE-AGPL3 files.
6: */
7:
8: namespace Aurora\Modules\DavContacts\Storages\Sabredav;
9:
10: use Aurora\Modules\Contacts\Enums\StorageType;
11: use Aurora\Modules\Contacts\Models\AddressBook;
12: use Sabre\CardDAV\Plugin;
13: use Sabre\DAV\MkCol;
14: use Sabre\DAV\PropPatch;
15:
16: /**
17: * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
18: * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
19: * @copyright Copyright (c) 2023, Afterlogic Corp.
20: */
21: class Storage extends \Aurora\Modules\DavContacts\Storages\Storage
22: {
23: /**
24: * @var string
25: */
26: public $Principal;
27:
28: /**
29: * @var \Aurora\Modules\StandardAuth\Classes\Account
30: */
31: // protected $Account;
32:
33: /**
34: * @var $oApiUsersManager CApiUsersManager
35: */
36: protected $ApiUsersManager;
37:
38: protected $aAddressBooksCache;
39: protected $aContactItemsCache;
40: protected $aGroupItemsCache;
41: protected $ContactsCache;
42: protected $InitialisedUserId;
43: // protected $AccountsCache;
44: protected $GroupsCache;
45: protected $CoreModuleDecorator;
46:
47: /**
48: *
49: * @param \Aurora\System\Managers\AbstractManager $oManager
50: */
51: public function __construct(\Aurora\System\Managers\AbstractManager &$oManager)
52: {
53: parent::__construct($oManager);
54:
55: // $this->Account = null;
56:
57: $this->aAddressBooksCache = array();
58: $this->aContactItemsCache = array();
59: $this->aGroupItemsCache = array();
60:
61: $this->ContactsCache = array();
62: $this->GroupsCache = array();
63: // $this->AccountsCache = array();
64:
65: $this->CoreModuleDecorator = \Aurora\System\Api::GetModuleDecorator('Core');
66: }
67:
68: /**
69: * @param \Aurora\Modules\StandardAuth\Classes\Account $oAccount
70: */
71: public function InitByUser($oUser = null)
72: {
73: $bResult = false;
74:
75: // if ($oAccount && (!$this->Account || $this->Account->Email !== $oAccount->Email))
76: if ($oUser) {
77: // $this->Account = $oAccount;
78: $this->aAddressBooksCache = array();
79: $this->aContactItemsCache = array();
80: $this->aGroupItemsCache = array();
81:
82: $this->ContactsCache = array();
83: $this->GroupsCache = array();
84:
85: // \Afterlogic\DAV\Server::getInstance()->setAccount($oAccount);
86: // $aPrincipalProperties = \Afterlogic\DAV\Backend::Principal()->getPrincipalByPath(\Afterlogic\DAV\Constants::PRINCIPALS_PREFIX . $oAccount->Email);
87: $aPrincipalProperties = \Afterlogic\DAV\Backend::Principal()->getPrincipalByPath(\Afterlogic\DAV\Constants::PRINCIPALS_PREFIX . $oUser->PublicId);
88: if ($aPrincipalProperties) {
89: if (isset($aPrincipalProperties['uri'])) {
90: $this->Principal = $aPrincipalProperties['uri'];
91: }
92: }
93: $bResult = true;
94: }
95:
96: // if ($this->Account)
97: // {
98: // $bResult = true;
99: // }
100:
101: return $bResult;
102: }
103:
104: // protected function GetDefaultAccountByUserId($iUserId)
105: // {
106: // if (!isset($this->AccountsCache[$iUserId]))
107: // {
108: // $iAccountId = $this->ApiUsersManager->getDefaultAccountId($iUserId);
109: // $oAccount = $this->ApiUsersManager->getAccountById($iAccountId);
110: // $this->AccountsCache[$iUserId] = $oAccount;
111: // }
112: //
113: // return $this->AccountsCache[$iUserId];
114: // }
115:
116:
117: /**
118: * @param int $iUserId
119: */
120: public function init($iUserId)
121: {
122: $bInitialized = true;
123: if ($this->InitialisedUserId !== $iUserId) {
124: // $oAccount = $this->GetDefaultAccountByUserId($iUserId);
125: $oUser = \Aurora\Modules\Core\Module::Decorator()->GetUserUnchecked($iUserId);
126: $this->InitialisedUserId = $iUserId;
127: $bInitialized = $this->InitByUser($oUser);
128: }
129:
130: return $bInitialized;
131: }
132:
133: /**
134: * @param int $iUserId
135: * @param mixed $mContactId
136: * @param string $sAddressBookName
137: * @return \Aurora\Modules\Contacts\Classes\Contact | false
138: */
139: public function getContactById($iUserId, $mContactId, $sAddressBookName = \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME)
140: {
141: $oContact = false;
142:
143: $oContactItem = $this->getVCardObjectById($iUserId, $mContactId, $sAddressBookName);
144:
145: if ($oContactItem) {
146: $sVCardData = $oContactItem->get();
147: if ($sVCardData) {
148: $oContact = new \Aurora\Modules\Contacts\Models\Contact();
149: $oContact->InitFromVCardStr($iUserId, $sVCardData);
150: $oContact->IdContact = $mContactId;
151: $oContact->ETag = trim($oContactItem->getETag(), '"');
152: }
153: }
154:
155: return $oContact;
156: }
157:
158: /**
159: * @param int $iUserId
160: * @param mixed $mContactId
161: * @param string $sAddressBookName
162: * @return \Aurora\Modules\Contacts\Classes\Contact | false
163: */
164: public function getVCardObjectById($iUserId, $mContactId, $sAddressBookName = \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME)
165: {
166: $mResult = false;
167: if ($this->init($iUserId)) {
168: $oAddressBook = $this->getAddressBook($iUserId, $sAddressBookName);
169: $mResult = $this->geItem($iUserId, $oAddressBook, $mContactId . '.vcf');
170: }
171: return $mResult;
172: }
173:
174: /**
175: * @param int $iUserId
176: * @param string $sEmail
177: * @return \Aurora\Modules\Contacts\Classes\Contact|bool
178: */
179: public function getContactByEmail($iUserId, $sEmail)
180: {
181: return false;
182: }
183:
184: /**
185: * @param int $iUserId
186: * @param string $sContactStrId
187: * @param int $iSharedTenantId = null
188: * @return \Aurora\Modules\Contacts\Classes\Contact|bool
189: */
190: public function getContactByStrId($iUserId, $sContactStrId, $iSharedTenantId = null)
191: {
192: return $this->getContactById($iUserId, $sContactStrId);
193: }
194:
195: /**
196: * @param int $iUserId
197: * @param string $sContactStrId
198: * @return \Aurora\Modules\Contacts\Classes\Contact
199: */
200: public function GetSuggestContactByEmail($iUserId, $sContactStrId)
201: {
202: return $this->getContactByEmail($iUserId, $sContactStrId);
203: }
204:
205: /**
206: * @param \Aurora\Modules\Contacts\Classes\Contact $oContact
207: * @return array|bool
208: */
209: public function getContactGroupIds($oContact)
210: {
211: return $oContact->GroupIds;
212: }
213:
214: /**
215: * @param int $iUserId
216: * @param mixed $mGroupId
217: * @return \Aurora\Modules\Contacts\Classes\Group
218: */
219: public function getGroupById($iUserId, $mGroupId)
220: {
221: $bResult = false;
222:
223: if (!isset($this->GroupsCache[$mGroupId])) {
224: if ($this->init($iUserId)) {
225: $oAddressBook = $this->getAddressBook($iUserId, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
226: if ($oAddressBook) {
227: if (!isset($this->aGroupItemsCache[$oAddressBook->getName()])) {
228: $this->getItems($iUserId, $oAddressBook);
229: }
230:
231: if (isset($this->aGroupItemsCache[$oAddressBook->getName()][$mGroupId])) {
232: $bResult = new \Aurora\Modules\Contacts\Models\Group();
233: $bResult->IdUser = $iUserId;
234: $bResult->IdGroup = $mGroupId;
235: $bResult->IdGroupStr = $mGroupId;
236: $bResult->Name = $mGroupId;
237: }
238: }
239: }
240: }
241:
242: if (isset($this->GroupsCache[$mGroupId])) {
243: $bResult = $this->GroupsCache[$mGroupId];
244: }
245:
246: return $bResult;
247: }
248:
249: /**
250: * @param int $iUserId
251: * @param string $sGroupStrId
252: * @return \Aurora\Modules\Contacts\Classes\Group
253: */
254: public function getGroupByStrId($iUserId, $sGroupStrId)
255: {
256: return $this->getGroupById($iUserId, $sGroupStrId);
257: }
258:
259: /**
260: * @param mixed $iUserId
261: * @param string $sName
262: * @return bool|array
263: */
264: public function getAddressBook($iUserId, $sName)
265: {
266: $oAddressBook = false;
267: if ($this->init($iUserId)) {
268: if (!isset($this->aAddressBooksCache[$iUserId][$sName])) {
269: if ($sName === 'gab') {
270: $this->aAddressBooksCache[$iUserId][$sName] = \Afterlogic\DAV\Server::getNodeForPath($sName);
271: } else {
272: $oUserAddressBooks = new \Afterlogic\DAV\CardDAV\AddressBookRoot(
273: \Afterlogic\DAV\Backend::Carddav(),
274: $this->Principal
275: );
276:
277: if ($oUserAddressBooks->childExists($sName)) {
278: $this->aAddressBooksCache[$iUserId][$sName] = $oUserAddressBooks->getChild($sName);
279: }
280: }
281: }
282:
283: if (isset($this->aAddressBooksCache[$iUserId][$sName])) {
284: $oAddressBook = $this->aAddressBooksCache[$iUserId][$sName];
285: }
286: }
287:
288: return $oAddressBook;
289: }
290:
291: public function createAddressBook($iUserId, $sUri, $sName)
292: {
293: $this->init($iUserId);
294:
295: $oUserAddressBooks = new \Afterlogic\DAV\CardDAV\AddressBookRoot(
296: \Afterlogic\DAV\Backend::Carddav(),
297: $this->Principal
298: );
299:
300: $oUserAddressBooks->createExtendedCollection(
301: $sUri,
302: new MkCol(
303: ['{' . Plugin::NS_CARDDAV . '}addressbook'],
304: ['{DAV:}displayname' => $sName]
305: )
306: );
307:
308: return true;
309: }
310:
311: public function updateAddressBook($iUserId, $sName, $sNewName)
312: {
313: $this->init($iUserId);
314:
315: $oUserAddressBooks = new \Afterlogic\DAV\CardDAV\AddressBookRoot(
316: \Afterlogic\DAV\Backend::Carddav(),
317: $this->Principal
318: );
319: if ($oUserAddressBooks->childExists($sName)) {
320: $oAddressBook = $oUserAddressBooks->getChild($sName);
321:
322: if ($oAddressBook) {
323: $oPropPath = new PropPatch([
324: '{DAV:}displayname' => $sNewName
325: ]);
326: $oAddressBook->propPatch($oPropPath);
327: $oPropPath->commit();
328: }
329:
330: return true;
331: }
332:
333: return false;
334: }
335:
336: public function deleteAddressBook($iUserId, $sName)
337: {
338: $this->init($iUserId);
339:
340: $oUserAddressBooks = new \Afterlogic\DAV\CardDAV\AddressBookRoot(
341: \Afterlogic\DAV\Backend::Carddav(),
342: $this->Principal
343: );
344: if ($oUserAddressBooks->childExists($sName)) {
345: $oAddressBook = $oUserAddressBooks->getChild($sName);
346: $oAddressBook->delete();
347:
348: return true;
349: }
350:
351: return false;
352: }
353:
354: /**
355: * @param int $iUserId
356: * @param \Afterlogic\DAV\CardDAV\AddressBook $oAddressBook
357: * @return bool|array
358: */
359: protected function getObjectItems($iUserId, $oAddressBook)
360: {
361: $mResult = false;
362: $sName = null;
363: if ($oAddressBook) {
364: $sName = $oAddressBook->getName();
365: if (!isset($this->aContactItemsCache[$sName])) {
366: $this->init($iUserId);
367:
368: $this->aContactItemsCache[$sName] = array();
369: foreach ($oAddressBook->getChildren() as $oChild) {
370: $this->aContactItemsCache[$sName][$oChild->getName()] = $oChild;
371: }
372: }
373:
374: $mResult = $this->aContactItemsCache[$sName];
375: }
376: return $mResult;
377: }
378:
379: /**
380: * @param int $iUserId
381: * @param \Sabre\CardDAV\AddressBook $oAddressBook
382: * @param string $sId
383: * @return \Sabre\CardDAV\Card | bool
384: */
385: protected function geItem($iUserId, $oAddressBook, $sId)
386: {
387: $bResult = false;
388: $sName = null;
389: if ($oAddressBook) {
390: $sName = $oAddressBook->getName();
391: if (isset($this->aContactItemsCache[$sName][$sId])) {
392: $bResult = $this->aContactItemsCache[$sName][$sId];
393: } else {
394: if ($oAddressBook->childExists($sId)) {
395: $bResult = $oAddressBook->getChild($sId);
396: }
397: }
398: }
399: return $bResult;
400: }
401:
402: /**
403: * @param int $iUserId
404: * @param \Afterlogic\DAV\CardDAV\AddressBook
405: * @param string $sSearch
406: * @param string $sFirstCharacter = ''
407: * @param int $sGroupId
408: * @return bool|array
409: */
410: protected function getItems($iUserId, $oAddressBook, $sSearch = '', $sFirstCharacter = '', $sGroupId = null)
411: {
412: $aResult = array();
413: $sName = null;
414: if ($this->init($iUserId) && $oAddressBook) {
415: $sName = $oAddressBook->getName();
416:
417: if (!empty($sGroupId)) {
418: unset($this->ContactsCache[$sName]);
419: }
420:
421: if (isset($this->ContactsCache[$sName])) {
422: $aResult = $this->ContactsCache[$sName];
423: } else {
424: $aItems = $this->getObjectItems($iUserId, $oAddressBook);
425:
426: foreach ($aItems as $oItem) {
427: $sItemId = $oItem->getName();
428: $oVCard = false;
429: try {
430: $oVCard = \Sabre\VObject\Reader::read($oItem->get());
431: } catch(\Exception $ex) {
432: \Aurora\System\Api::Log('SABREDAV: Invalid VCard with Id='.$sItemId);
433: }
434: if ($oVCard) {
435: $sFullName = $sFirstName = $sLastName = $sTitle = $sNickName = '';
436: if (isset($oVCard->FN)) {
437: $sFullName = (string)$oVCard->FN;
438: }
439: if (isset($oVCard->N)) {
440: $aNames = $oVCard->N->getParts();
441: if (!empty($aNames[0])) {
442: $sLastName = $aNames[0];
443: }
444: if (!empty($aNames[1])) {
445: $sFirstName = $aNames[1];
446: }
447: if (!empty($aNames[3])) {
448: $sTitle = $aNames[3];
449: }
450: }
451: if (isset($oVCard->NICKNAME)) {
452: $sNickName = (string)$oVCard->NICKNAME;
453: }
454:
455: $bFindEmail = false;
456: if (isset($oVCard->EMAIL)) {
457: foreach ($oVCard->EMAIL as $oEmail) {
458: if (stripos((string)$oEmail, $sSearch) !== false) {
459: $bFindEmail = true;
460: break;
461: }
462: }
463: }
464:
465: $sCategories = '';
466: if (isset($oVCard->CATEGORIES)) {
467: $sCategories = (string)$oVCard->CATEGORIES;
468: $aCategories = explode(',', (string)$oVCard->CATEGORIES);
469: foreach ($aCategories as $sCategory) {
470: $sCategory = trim($sCategory);
471: if (!empty($sCategory)) {
472: $this->aGroupItemsCache[$sName][$sCategory][$sItemId] = $sItemId;
473: }
474: }
475: }
476:
477: if (!empty($sItemId) && (empty($sSearch) || stripos($sFullName, $sSearch) !== false ||
478: stripos($sFirstName, $sSearch) !== false ||
479: stripos($sLastName, $sSearch) !== false ||
480: stripos($sNickName, $sSearch) !== false ||
481: stripos($sTitle, $sSearch) !== false || $bFindEmail) &&
482: (empty($sGroupId) || (!empty($sGroupId) && strpos($sCategories, $sGroupId) !== false))) {
483: $oContactItem = new \Aurora\Modules\Contacts\Classes\ContactListItem();
484: $oContactItem->InitBySabreCardDAVCard($oVCard);
485: $oContactItem->Id = $sItemId;
486: $oContactItem->ETag = $oItem->getETag();
487: $aResult[] = $oContactItem;
488: unset($oContactItem);
489: }
490: }
491: unset($oVCard);
492: }
493: $this->ContactsCache[$sName] = $aResult;
494: }
495: }
496:
497: return $aResult;
498: }
499:
500: /**
501: * @param int $iUserId
502: * @param \Afterlogic\DAV\CardDAV\AddressBook
503: * @return void
504: */
505: protected function initGroupItems($iUserId, $oAddressBook)
506: {
507: if ($this->init($iUserId)) {
508: $aItems = $this->getObjectItems($iUserId, $oAddressBook);
509:
510: foreach ($aItems as $oItem) {
511: $sItemId = $oItem->getName();
512: $oVCard = false;
513: try {
514: $oVCard = \Sabre\VObject\Reader::read($oItem->get());
515: } catch(\Exception $ex) {
516: \Aurora\System\Api::Log('SABREDAV: Invalid VCard with Id='.$sItemId);
517: }
518: if ($oVCard) {
519: if (isset($oVCard->CATEGORIES)) {
520: $aCategories = $oVCard->CATEGORIES->getParts();
521: foreach ($aCategories as $sCategory) {
522: $sCategory = trim($sCategory);
523: if (!empty($sCategory)) {
524: $this->aGroupItemsCache[$oAddressBook->getName()][$sCategory][$sItemId] = $sItemId;
525: }
526: }
527: }
528: }
529: unset($oVCard);
530: }
531: }
532: }
533:
534: public function ___qSortCallback($a, $b)
535: {
536: $sSortField = $GLOBALS['ItemsSortField'];
537: $iSortOrder = $GLOBALS['ItemsSortOrder'];
538:
539: if ($a->{$sSortField} === $b->{$sSortField}) {
540: return 0;
541: } elseif (\Aurora\System\Enums\SortOrder::ASC == $iSortOrder) {
542: return ($a->{$sSortField} > $b->{$sSortField}) ? -1 : 1;
543: } else {
544: return ($a->{$sSortField} < $b->{$sSortField}) ? -1 : 1;
545: }
546: }
547:
548:
549: /**
550: * @param array $aItems
551: * @param int $iSortField
552: * @param int $iSortOrder
553: */
554: protected function sortItems(&$aItems, $iSortField, $iSortOrder)
555: {
556: $aMapSortField = array(
557: \Aurora\Modules\Contacts\Enums\SortField::Email => 'Email',
558: \Aurora\Modules\Contacts\Enums\SortField::Name => 'Name',
559: \Aurora\Modules\Contacts\Enums\SortField::Frequency => 'Frequency',
560: \Aurora\Modules\Contacts\Enums\SortField::FirstName => 'FirstName',
561: \Aurora\Modules\Contacts\Enums\SortField::LastName => 'LastName'
562: );
563:
564: if (!isset($aMapSortField[$iSortField])) {
565: return;
566: }
567:
568: $GLOBALS['ItemsSortField'] = $aMapSortField[$iSortField];
569: $GLOBALS['ItemsSortOrder'] = $iSortOrder;
570:
571: // Sort
572: usort($aItems, array(&$this, '___qSortCallback'));
573:
574: unset($GLOBALS['ItemsSortField']);
575: unset($GLOBALS['ItemsSortOrder']);
576: }
577:
578: /**
579: * @param int $iUserId
580: * @param int $iOffset
581: * @param int $iRequestLimit
582: * @return bool|array
583: */
584: public function getContactItemsWithoutOrder($iUserId, $iOffset, $iRequestLimit)
585: {
586: $aResult = array();
587:
588: $oAddressBook = $this->getAddressBook($iUserId, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
589: $aContactItems = $this->getObjectItems($iUserId, $oAddressBook);
590:
591: foreach ($aContactItems as $oItem) {
592: $sItemId = $oItem->getName();
593: $oVCard = null;
594: try {
595: $oVCard = \Sabre\VObject\Reader::read($oItem->get());
596: } catch(\Exception $ex) {
597: \Aurora\System\Api::Log('SABREDAV: Invalid VCard with Id='.$sItemId);
598: }
599: if (isset($oVCard)) {
600: $oContactItem = new \Aurora\Modules\Contacts\Classes\ContactListItem();
601: $oContactItem->InitBySabreCardDAVCard($oVCard);
602: $oContactItem->Id = $oItem->getName();
603:
604: $aResult[] = $oContactItem;
605: unset($oContactItem);
606: }
607: unset($oVCard);
608: }
609:
610: if ($iOffset < 0 && $iRequestLimit < 0) {
611: return $aResult;
612: } else {
613: return array_slice($aResult, $iOffset, $iRequestLimit);
614: }
615: }
616:
617: /**
618: *
619: * @param int $iSortField
620: * @param int $iSortOrder
621: * @param int $iOffset
622: * @param int $iRequestLimit
623: * @param array $aFilters
624: * @param int $iIdGroup
625: * @return array
626: */
627: public function getContactItems($iSortField, $iSortOrder, $iOffset, $iRequestLimit, $aFilters, $iIdGroup)
628: {
629: return array();
630:
631: // $oAddressBook = $this->getAddressBook($iUserId, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
632: // $aResult = $this->getItems($iUserId, $oAddressBook, $sSearch, $sFirstCharacter, $iGroupId);
633: // $this->sortItems($aResult, $iSortField, $iSortOrder);
634: //
635: // return array_slice($aResult, $iOffset, $iRequestLimit);
636: }
637:
638: /**
639: * @param int $iUserId
640: * @return bool|array
641: */
642: public function GetContactItemObjects($iUserId)
643: {
644: $oAddressBook = $this->getAddressBook($iUserId, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
645: return $this->getObjectItems($iUserId, $oAddressBook);
646: }
647:
648: /**
649: * @param int $iUserId
650: * @param string $sSearch
651: * @param string $sFirstCharacter
652: * @param int $iGroupId
653: * @param int $iTenantId
654: * @return int
655: */
656: public function getContactItemsCount($iUserId, $sSearch, $sFirstCharacter, $iGroupId, $iTenantId = null, $bAll = false)
657: {
658: $iCount = 0;
659: $oAddressBook = $this->getAddressBook($iUserId, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
660: if (false !== $oAddressBook) {
661: $iCount = count($this->getItems($iUserId, $oAddressBook, $sSearch, $sFirstCharacter, $iGroupId));
662: }
663: return $iCount;
664: }
665:
666: /**
667: * @param int $iUserId
668: * @param string $sSearch
669: * @param string $sFirstCharacter
670: * @param string $sContactId
671: * @return bool|array
672: */
673: protected function getGroupItemsWithoutOrder($iUserId, $sSearch = '', $sFirstCharacter = '', $sContactId = '')
674: {
675: $aResult = array();
676: $this->init($iUserId);
677:
678: if (!empty($sContactId)) {
679: $oContact = $this->getContactById($iUserId, $sContactId);
680: if ($oContact) {
681: foreach ($oContact->GroupIds as $sGroupId) {
682: $oContactItem = new \Aurora\Modules\Contacts\Classes\ContactListItem();
683: $oContactItem->Id = (string) $sGroupId;
684: $oContactItem->Name = (string) $sGroupId;
685: $oContactItem->IsGroup = true;
686:
687: if ($sSearch == '' || stripos($oContactItem->Name, $sSearch) !== false) {
688: $aResult[] = $oContactItem;
689: }
690: unset($oContactItem);
691: }
692: }
693: } else {
694: $oAddressBook = $this->getAddressBook($iUserId, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
695: if (false !== $oAddressBook) {
696: $sName = $oAddressBook->getName();
697: if (!isset($this->aGroupItemsCache[$sName])) {
698: $this->getItems($iUserId, $oAddressBook);
699: }
700:
701: if (isset($this->aGroupItemsCache[$sName])) {
702: $aItems = $this->aGroupItemsCache[$sName];
703: foreach ($aItems as $sKey => $aIds) {
704: $aContactIds = array();
705: foreach ($aIds as $sContactId) {
706: $aContactIds[] = $sContactId;
707: }
708: $oContactItem = new \Aurora\Modules\Contacts\Classes\ContactListItem();
709: $oContactItem->Id = $sKey;
710: $oContactItem->Name = $sKey;
711: $oContactItem->IsGroup = true;
712:
713: if (empty($sContactId) || !empty($sContactId) && in_array($sContactId, $aContactIds)) {
714: if ($sSearch == '' || stripos($oContactItem->Name, $sSearch) !== false) {
715: $aResult[] = $oContactItem;
716: }
717: }
718: unset($oContactItem);
719: }
720: }
721: }
722: }
723: return $aResult;
724: }
725:
726: protected function searchContactItemsByEmail($sUserId, $sEmail, $oAddressBook)
727: {
728: $aResult = array();
729:
730: $aContactItems = $this->getItems($sUserId, $oAddressBook, $sEmail);
731: foreach ($aContactItems as $oContactItem) {
732: $aResult[] = $oContactItem->Id;
733: }
734:
735: return $aResult;
736: }
737:
738: /**
739: * @param int $iUserId
740: * @param int $iSortField
741: * @param int $iSortOrder
742: * @param int $iOffset
743: * @param int $iRequestLimit
744: * @param string $sSearch
745: * @param string $sFirstCharacter
746: * @param string $sContactId
747: * @return bool|array
748: */
749: public function getGroupItems($iUserId, $iSortField, $iSortOrder, $iOffset, $iRequestLimit, $sSearch, $sFirstCharacter, $sContactId)
750: {
751: $aResult = $this->getGroupItemsWithoutOrder($iUserId, $sSearch, $sFirstCharacter, $sContactId);
752: $this->sortItems($aResult, $iSortField, $iSortOrder);
753: return array_slice($aResult, $iOffset, $iRequestLimit);
754: }
755:
756: /**
757: * @param int $iUserId
758: * @param string $sSearch
759: * @param string $sFirstCharacter
760: * @return int
761: */
762: public function getGroupItemsCount($iUserId, $sSearch, $sFirstCharacter)
763: {
764: return count($this->getGroupItemsWithoutOrder($iUserId, $sSearch, $sFirstCharacter));
765: }
766:
767: /**
768: * @param int $iUserId
769: * @param string $sSearch
770: * @param int $iRequestLimit
771: * @param bool $bPhoneOnly = false
772: * @return bool|array
773: */
774: public function GetSuggestContactItems($iUserId, $sSearch, $iRequestLimit, $bPhoneOnly = false)
775: {
776: $aResult = array();
777: $this->init($iUserId);
778:
779: $oDefaultAB = $this->getAddressBook($iUserId, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
780: $oCollectedAB = $this->getAddressBook($iUserId, \Afterlogic\DAV\Constants::ADDRESSBOOK_COLLECTED_NAME);
781:
782: $aCollectedContactItems = $this->getObjectItems($iUserId, $oCollectedAB);
783: $aDefaultContactItems = $this->getObjectItems($iUserId, $oDefaultAB);
784:
785: $aContactItems = array_merge($aDefaultContactItems, $aCollectedContactItems);
786:
787: foreach ($aContactItems as $oItem) {
788: $sItemId = $oItem->getName();
789: $oVCard = null;
790: try {
791: $oVCard = \Sabre\VObject\Reader::read($oItem->get());
792: } catch(\Exception $ex) {
793: \Aurora\System\Api::Log('SABREDAV: Invalid VCard with Id='.$sItemId);
794: }
795: if (isset($oVCard)) {
796: $oContactItem = new \Aurora\Modules\Contacts\Classes\ContactListItem();
797: $oContactItem->InitBySabreCardDAVCard($oVCard);
798: $oContactItem->Id = $oItem->getName();
799:
800: if (empty($sSearch) ||
801: stripos($oContactItem->Name, $sSearch) !== false ||
802: stripos($oContactItem->Email, $sSearch) !== false) {
803: $aResult[] = $oContactItem;
804: }
805: unset($oContactItem);
806: }
807:
808: unset($oVCard);
809: }
810:
811: $this->sortItems($aResult, \Aurora\Modules\Contacts\Enums\SortField::Frequency, \Aurora\System\Enums\SortOrder::ASC);
812:
813: return array_slice($aResult, 0, $iRequestLimit);
814: }
815:
816: /**
817: * @param \Aurora\Modules\Contacts\Classes\Contact $oContact
818: * @param int $iUserId
819: * @return string
820: */
821: public function updateContactUserId($oContact, $iUserId)
822: {
823: $bResult = false;
824:
825: $sAddressBook = $oContact->Storage === 'shared' ? \Afterlogic\DAV\Constants::ADDRESSBOOK_SHARED_WITH_ALL_NAME : \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME;
826: $oAddressBookFrom = $this->getAddressBook($oContact->IdUser, $sAddressBook);
827: $oContactItem = $this->geItem($oContact->IdUser, $oAddressBookFrom, $oContact->UUID . '.vcf');
828: if ($oContactItem) {
829: $oAddressBookTo = $this->getAddressBook($iUserId, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
830: if ($oAddressBookTo) {
831: try {
832: $sData = $oContactItem->get();
833: $oContactItem->delete();
834: $oAddressBookTo->createFile($oContact->UUID . '.vcf', $sData);
835: $bResult = true;
836: } catch (\Exception $ex) {
837: \Aurora\System\Api::Log($ex->getTraceAsString());
838: $bResult = false;
839: }
840: }
841: }
842: return $bResult;
843: }
844:
845: /**
846: * @param \Aurora\Modules\Contacts\Classes\Contact $oContact
847: * @return bool
848: */
849: public function updateContact($oContact)
850: {
851: $bResult = false;
852: $iUserId = $oContact->IdUser;
853: $oAddressBook = null;
854: if ($oContact->Storage === StorageType::Personal) {
855: $oAddressBook = $this->getAddressBook($oContact->IdUser, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
856: } elseif ($oContact->Storage === StorageType::Shared) {
857: $oAddressBook = $this->getAddressBook($oContact->IdUser, \Afterlogic\DAV\Constants::ADDRESSBOOK_SHARED_WITH_ALL_NAME);
858: } elseif ($oContact->Storage === StorageType::Team) {
859: $bResult = true;
860: } elseif ($oContact->Storage === StorageType::AddressBook) {
861: $oAddressBook = AddressBook::where('Id', $oContact->AddressBookId)
862: ->where('UserId', $oContact->IdUser)->first();
863:
864: if ($oAddressBook) {
865: $oAddressBook = $this->getAddressBook($oContact->IdUser, $oAddressBook->UUID);
866: }
867: }
868:
869: $oContactItem = $oAddressBook ? $this->geItem($iUserId, $oAddressBook, $oContact->{'DavContacts::UID'} . '.vcf') : null;
870: if ($oContactItem) {
871: $sData = $oContactItem->get();
872: /*
873: $sETag = md5($sData);
874: if ($oContact->ETag !== $sETag)
875: {
876: throw new \Aurora\System\Exceptions\BaseException(Errs::Sabre_PreconditionFailed);
877: }
878: */
879:
880: $oVCard = \Sabre\VObject\Reader::read($sData);
881: if ($oVCard) {
882: \Aurora\Modules\Contacts\Classes\VCard\Helper::UpdateVCardFromContact($oContact, $oVCard);
883: $oContactItem->put($oVCard->serialize());
884: $bResult = true;
885: }
886: unset($oVCard);
887: }
888:
889: return $bResult;
890: }
891:
892: /**
893: * @param int $iUserId
894: * @param string $sUID
895: * @param string $sFromAddressBook
896: * @param string $sToAddressBook
897: * @return bool
898: */
899: public function copyContact($iUserId, $sUID, $sFromAddressBook, $sToAddressBook)
900: {
901: $oFromAddressBook = $this->getAddressBook($iUserId, $sFromAddressBook);
902: $oToAddressBook = $this->getAddressBook($iUserId, $sToAddressBook);
903:
904: $sId = $sUID . '.vcf';
905: if ($oFromAddressBook->childExists($sUID . '.vcf')) {
906: $oCard = $oFromAddressBook->getChild($sId);
907: if ($oCard) {
908: $oToAddressBook->createFile($sId, $oCard->get());
909: $oCard->delete();
910: }
911: }
912:
913: return true;
914: }
915:
916: /**
917: * @param \Aurora\Modules\Contacts\Classes\Group $oGroup
918: * @return bool
919: */
920: public function updateGroup($oGroup)
921: {
922: $bResult = false;
923:
924: $oAddressBook = $this->getAddressBook($oGroup->IdUser, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
925: $oGroupItem = $oAddressBook ? $this->geItem($oGroup->IdUser, $oAddressBook, $oGroup->{'DavContacts::UID'} . '.vcf') : null;
926: if ($oGroupItem) {
927: $sData = $oGroupItem->get();
928:
929: $oVCard = \Sabre\VObject\Reader::read($sData);
930: if ($oVCard) {
931: \Aurora\Modules\Contacts\Classes\VCard\Helper::UpdateVCardFromGroup($oGroup, $oVCard);
932: unset($oVCard->MEMBER);
933: unset($oVCard->{'X-ADDRESSBOOKSERVER-MEMBER'});
934: foreach ($oGroup->Contacts as $oGroupContact) {
935: $oContact = \Aurora\Modules\Contacts\Models\Contact::where('UUID', $oGroupContact->UUID)->first();
936: $sVCardUID = null;
937: if ($oContact->Storage !== 'team') {
938: if (!empty($oContact->{'DavContacts::VCardUID'})) {
939: $sVCardUID = $oContact->{'DavContacts::VCardUID'};
940: } else {
941: $sVCardUID = $this->fixContactVCardUid($oAddressBook, $oContact);
942: }
943: } else {
944: $sVCardUID = $oContact->UUID;
945: }
946: if (isset($sVCardUID)) {
947: $oVCard->add('X-ADDRESSBOOKSERVER-MEMBER', 'urn:uuid:' . $sVCardUID);
948: }
949: }
950:
951: $oGroupItem->put($oVCard->serialize());
952: $bResult = true;
953: }
954: unset($oVCard);
955: }
956:
957: return $bResult;
958: }
959:
960: /**
961: * @param \Aurora\Modules\Contacts\Classes\Contact $oContact
962: * @return bool
963: */
964: public function createContact($oContact)
965: {
966: $bResult = false;
967: if (isset($oContact)) {
968: $this->init($oContact->IdUser);
969: $oAddressBook = null;
970: if ($oContact->Storage === StorageType::Personal) {
971: if (!$oContact->Auto) {
972: $oAddressBook = $this->getAddressBook($oContact->IdUser, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
973: } else {
974: $oAddressBook = $this->getAddressBook($oContact->IdUser, \Afterlogic\DAV\Constants::ADDRESSBOOK_COLLECTED_NAME);
975: }
976: } elseif ($oContact->Storage === StorageType::Shared) {
977: $oAddressBook = $this->getAddressBook($oContact->IdUser, \Afterlogic\DAV\Constants::ADDRESSBOOK_SHARED_WITH_ALL_NAME);
978: } elseif ($oContact->Storage === StorageType::AddressBook) {
979: $oAddressBook = AddressBook::where('Id', $oContact->AddressBookId)
980: ->where('UserId', $oContact->IdUser)->first();
981:
982: if ($oAddressBook) {
983: $oAddressBook = $this->getAddressBook($oContact->IdUser, $oAddressBook->UUID);
984: }
985: }
986: if ($oAddressBook) {
987: $oContact->{'DavContacts::UID'} .= '.vcf';
988:
989: $oVCard = new \Sabre\VObject\Component\VCard();
990: \Aurora\Modules\Contacts\Classes\VCard\Helper::UpdateVCardFromContact($oContact, $oVCard);
991: $oAddressBook->createFile($oContact->{'DavContacts::UID'}, $oVCard->serialize());
992: $bResult = true;
993: }
994: /*
995: * for collected addressbook
996: *
997: *
998: $oAddressBook = $this->getAddressBook($oContact->IdUser, \Afterlogic\DAV\Constants::ADDRESSBOOK_COLLECTED_NAME);
999: $aContactIds = $this->searchContactItemsByEmail($oContact->IdUser, $oContact->ViewEmail, $oAddressBook);
1000:
1001: $this->deleteContactsByAddressBook($oContact->IdUser, $aContactIds, $oAddressBook);
1002: *
1003: */
1004: }
1005:
1006: return $bResult;
1007: }
1008:
1009: protected function fixContactVCardUid($oAddressBook, $oContact)
1010: {
1011: $mResult = null;
1012: if ($oAddressBook->childExists($oContact->{'DavContacts::UID'} . '.vcf')) {
1013: $oChild = $oAddressBook->getChild($oContact->{'DavContacts::UID'} . '.vcf');
1014: if ($oChild) {
1015: $oVCard = \Sabre\VObject\Reader::read($oChild->get());
1016: $sVCardUID = $oVCard->UID;
1017: $oContact->setExtendedProp('DavContacts::VCardUID', $sVCardUID);
1018: $oContact->save();
1019:
1020: $mResult = $sVCardUID;
1021: }
1022: } else {
1023: $mResult = $oContact->UUID;
1024: }
1025:
1026: return $mResult;
1027: }
1028:
1029: /**
1030: * @param \Aurora\Modules\Contacts\Classes\Group $oGroup
1031: * @return bool
1032: */
1033: public function createGroup($oGroup)
1034: {
1035: $oVCard = new \Sabre\VObject\Component\VCard();
1036: \Aurora\Modules\Contacts\Classes\VCard\Helper::UpdateVCardFromGroup($oGroup, $oVCard);
1037:
1038: unset($oVCard->{'X-ADDRESSBOOKSERVER-MEMBER'});
1039: $oAddressBook = $this->getAddressBook($oGroup->IdUser, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
1040: foreach ($oGroup->Contacts as $oGroupContact) {
1041: $oContact = \Aurora\Modules\Contacts\Models\Contact::where('UUID', $oGroupContact->UUID)->first();
1042: if ($oContact) {
1043: $sVCardUID = null;
1044: if ($oContact->Storage !== 'team') {
1045: if (!empty($oContact->{'DavContacts::VCardUID'})) {
1046: $sVCardUID = $oContact->{'DavContacts::VCardUID'};
1047: } else {
1048: $sVCardUID = $this->fixContactVCardUid($oAddressBook, $oContact);
1049: }
1050: } else {
1051: $sVCardUID = $oContact->UUID;
1052: }
1053: if (isset($sVCardUID)) {
1054: $oVCard->add('X-ADDRESSBOOKSERVER-MEMBER', 'urn:uuid:' . $sVCardUID);
1055: }
1056: }
1057: }
1058:
1059: $oAddressBook = $this->getAddressBook($oGroup->IdUser, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
1060: $oAddressBook->createFile($oGroup->{'DavContacts::UID'} . '.vcf', $oVCard->serialize());
1061:
1062:
1063: return true; //$this->updateGroup($oGroup);
1064: }
1065:
1066: /**
1067: * @param int $iUserId
1068: * @param array $aContactIds
1069: * @param \Afterlogic\DAV\CardDAV\AddressBook
1070: * @return bool
1071: */
1072: protected function deleteContactsByAddressBook($iUserId, $aContactIds, $oAddressBook)
1073: {
1074: $this->init($iUserId);
1075:
1076: if ($oAddressBook) {
1077: foreach ($aContactIds as $sContactId) {
1078: if (!strripos($sContactId, '.vcf')) {
1079: $sContactId .= '.vcf';
1080: }
1081: if ($oAddressBook->childExists($sContactId)) {
1082: $oContact = $oAddressBook->GetChild($sContactId);
1083: $oContact->delete();
1084: }
1085: }
1086: return true;
1087: }
1088: return false;
1089: }
1090:
1091: /**
1092: * @param int $iUserId
1093: * @param array $aContactIds
1094: * @return bool
1095: */
1096: public function deleteContacts($iUserId, $aContactIds, $sAddressBook = \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME)
1097: {
1098: $this->init($iUserId);
1099: $oAddressBook = $this->getAddressBook($iUserId, $sAddressBook);
1100: return $this->deleteContactsByAddressBook($iUserId, $aContactIds, $oAddressBook);
1101: }
1102:
1103: /**
1104: * @param int $iUserId
1105: * @param array $aContactIds
1106: * @return bool
1107: */
1108: public function deleteSuggestContacts($iUserId, $aContactIds)
1109: {
1110: $this->init($iUserId);
1111: $oAddressBook = $this->getAddressBook($iUserId, \Afterlogic\DAV\Constants::ADDRESSBOOK_COLLECTED_NAME);
1112: return $this->deleteContactsByAddressBook($iUserId, $aContactIds, $oAddressBook);
1113: }
1114:
1115: /**
1116: * @param int $iUserId
1117: * @param string $aGroupIds
1118: * @return bool
1119: */
1120: public function deleteGroup($iUserId, $iGroupId)
1121: {
1122: $this->init($iUserId);
1123:
1124: $oAddressBook = $this->getAddressBook($iUserId, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
1125: if ($oAddressBook) {
1126: if ($oAddressBook->childExists($iGroupId . '.vcf')) {
1127: $oChild = $oAddressBook->getChild($iGroupId . '.vcf');
1128: $oChild->delete();
1129: return true;
1130: }
1131: }
1132: return false;
1133: }
1134:
1135: /**
1136: * @param int $iUserId
1137: * @param array $aEmails
1138: * @return bool
1139: */
1140: public function updateSuggestTable($iUserId, $aEmails)
1141: {
1142: $bResult = false;
1143: $this->init($iUserId);
1144:
1145: $oDefautltAB = $this->getAddressBook($iUserId, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
1146: $oCollectedAB = $this->getAddressBook($iUserId, \Afterlogic\DAV\Constants::ADDRESSBOOK_COLLECTED_NAME);
1147:
1148: $aCollectedContactItems = $this->getObjectItems($iUserId, $oCollectedAB);
1149:
1150: foreach ($aEmails as $sEmail => $sName) {
1151: $mFindContact = false;
1152: if ($aCollectedContactItems) {
1153: foreach ($aCollectedContactItems as $oCollectedContactItem) {
1154: $oVCard = \Sabre\VObject\Reader::read($oCollectedContactItem->get());
1155: if (isset($oVCard->EMAIL)) {
1156: foreach ($oVCard->EMAIL as $oEmail) {
1157: if (strtolower((string)$oEmail) == strtolower($sEmail)) {
1158: $mFindContact = $oCollectedContactItem;
1159: break;
1160: }
1161: }
1162: }
1163: unset($oVCard);
1164: }
1165: }
1166:
1167: $aDefaultContactIds = $this->searchContactItemsByEmail($iUserId, $sEmail, $oDefautltAB);
1168: if (count($aDefaultContactIds) === 0) {
1169: if ($mFindContact === false) {
1170: $sUUID = \Sabre\DAV\UUIDUtil::getUUID();
1171: $oContact = new \Aurora\Modules\Contacts\Models\Contact();
1172: $oContact->FullName = $sName;
1173: $oContact->PersonalEmail = $sEmail;
1174: $oContact->setExtendedProp('DavContacts::UID', $sUUID);
1175:
1176: $oVCard = new \Sabre\VObject\Component\VCard();
1177: $oVCard->{'X-AFTERLOGIC-USE-FREQUENCY'} = '1';
1178: \Aurora\Modules\Contacts\Classes\VCard\Helper::UpdateVCardFromContact($oContact, $oVCard);
1179:
1180: $oCollectedAB->createFile($sUUID . '.vcf', $oVCard->serialize());
1181: $bResult = true;
1182: } elseif ($mFindContact instanceof \Sabre\CardDAV\Card) {
1183: $oVCard = \Sabre\VObject\Reader::read($mFindContact->get());
1184: if (isset($oVCard->{'X-AFTERLOGIC-USE-FREQUENCY'})) {
1185: $oVCard->{'X-AFTERLOGIC-USE-FREQUENCY'} = (int)$oVCard->{'X-AFTERLOGIC-USE-FREQUENCY'}->getValue() + 1;
1186: } else {
1187: $oVCard->{'X-AFTERLOGIC-USE-FREQUENCY'} = '1';
1188: }
1189: $mFindContact->put($oVCard->serialize());
1190: unset($oVCard);
1191: }
1192: } else {
1193: foreach ($aDefaultContactIds as $sDefaultContactId) {
1194: $mDefaultContact = $this->geItem($iUserId, $oDefautltAB, $sDefaultContactId);
1195: if ($mDefaultContact !== false) {
1196: $oVCard = \Sabre\VObject\Reader::read($mDefaultContact->get());
1197: if (isset($oVCard->{'X-AFTERLOGIC-USE-FREQUENCY'})) {
1198: $oVCard->{'X-AFTERLOGIC-USE-FREQUENCY'} = (int)$oVCard->{'X-AFTERLOGIC-USE-FREQUENCY'}->getValue() + 1;
1199: } else {
1200: $oVCard->{'X-AFTERLOGIC-USE-FREQUENCY'} = '1';
1201: }
1202: $mDefaultContact->put($oVCard->serialize());
1203: unset($oVCard);
1204: }
1205: }
1206:
1207: if ($mFindContact instanceof \Sabre\CardDAV\Card) {
1208: $mFindContact->delete();
1209: }
1210: }
1211: }
1212:
1213: return $bResult;
1214: }
1215:
1216: /**
1217: * @param int $iUserId
1218: * @param array $aContactIds
1219: * @return bool
1220: */
1221: // public function DeleteContactsExceptIds($iUserId, $aContactIds)
1222: // {
1223: // $this->init($iUserId);
1224: //
1225: // $oAddressBook = $this->getAddressBook($iUserId, \Afterlogic\DAV\Constants::ADDRESSBOOK_DEFAULT_NAME);
1226: // if ($oAddressBook)
1227: // {
1228: // $aContactItems = $this->getObjectItems($iUserId);
1229: // foreach ($aContactItems as $oContactItem)
1230: // {
1231: // $vCard = \Sabre\VObject\Reader::read($oContactItem->get());
1232: // if (isset($vCard->UID) && !in_array((string)$vCard->UID, $aContactIds))
1233: // {
1234: // $oContactItem->delete();
1235: // }
1236: // }
1237: // return true;
1238: // }
1239: // return false;
1240: // }
1241:
1242: /**
1243: * @param int $iUserId
1244: * @param array $aGroupIds
1245: * @return bool
1246: */
1247: // public function DeleteGroupsExceptIds($iUserId, $aGroupIds)
1248: // {
1249: // return true;
1250: // }
1251:
1252: /**
1253: * @return bool
1254: */
1255: public function flushContacts()
1256: {
1257: return true;
1258: }
1259:
1260: /**
1261: * @param int $iUserId
1262: * @return bool
1263: */
1264: public function clearAllContactsAndGroups($iUserId)
1265: {
1266: $bResult = false;
1267: $this->init($iUserId);
1268:
1269: $oAddressBooks = new \Afterlogic\DAV\CardDAV\AddressBookRoot(
1270: \Afterlogic\DAV\Backend::Carddav(),
1271: $this->Principal
1272: );
1273:
1274: foreach ($oAddressBooks->getChildren() as $oAddressBook) {
1275: if ($oAddressBook && $oAddressBook instanceof \Sabre\CardDAV\AddressBook) {
1276: try {
1277: $oAddressBook->delete();
1278: $bResult = true;
1279: } catch (\Exception $ex) {
1280: \Aurora\System\Api::Log($ex->getTraceAsString());
1281: $bResult = false;
1282: }
1283: }
1284: }
1285: return $bResult;
1286: }
1287:
1288: /**
1289: * @param \Aurora\Modules\Contacts\Classes\Group $oGroup
1290: * @param array $aContactIds
1291: * @return bool
1292: */
1293: public function addContactsToGroup($oGroup, $aContactIds)
1294: {
1295: return $this->updateGroup($oGroup);
1296: }
1297:
1298: /**
1299: * @param \Aurora\Modules\Contacts\Classes\Group $oGroup
1300: * @param array $aContactIds
1301: * @return bool
1302: */
1303: public function removeContactsFromGroup($oGroup, $aContactIds)
1304: {
1305: $bResult = true;
1306:
1307: if ($oGroup && is_array($aContactIds)) {
1308: foreach ($aContactIds as $sContactId) {
1309: $oContact = $this->getContactById($oGroup->IdUser, $sContactId);
1310: if ($oContact) {
1311: $aGroupIds = $oContact->GroupIds;
1312: $oContact->GroupIds = array_diff($aGroupIds, array($oGroup->Name));
1313: $bResult = $this->updateContact($oContact);
1314: }
1315: }
1316: } else {
1317: $bResult = false;
1318: }
1319:
1320: return (bool) $bResult;
1321: }
1322: }
1323: