1: | <?php |
2: | |
3: | |
4: | |
5: | |
6: | |
7: | namespace Aurora\Modules\SharedContacts; |
8: | |
9: | use Afterlogic\DAV\Backend; |
10: | use Afterlogic\DAV\Constants; |
11: | use Aurora\Api; |
12: | use Aurora\Modules\Contacts\Enums\Access; |
13: | use Aurora\Modules\Contacts\Enums\SortField; |
14: | use Aurora\Modules\Contacts\Enums\StorageType; |
15: | use Aurora\Modules\Contacts\Classes\Contact; |
16: | use Aurora\Modules\Contacts\Module as ContactsModule; |
17: | use Aurora\Modules\Core\Models\User; |
18: | use Aurora\System\Enums\UserRole; |
19: | use Aurora\System\Exceptions\InvalidArgumentException; |
20: | use Aurora\System\Notifications; |
21: | use Illuminate\Database\Capsule\Manager as Capsule; |
22: | use Sabre\DAV\UUIDUtil; |
23: | use Aurora\Modules\Core\Module as CoreModule; |
24: | |
25: | |
26: | |
27: | |
28: | |
29: | |
30: | |
31: | |
32: | |
33: | class Module extends \Aurora\System\Module\AbstractModule |
34: | { |
35: | protected static $iStorageOrder = 10; |
36: | |
37: | protected $oBeforeDeleteUser = null; |
38: | |
39: | protected $storagesMapToAddressbooks = [ |
40: | StorageType::Shared => Constants::ADDRESSBOOK_SHARED_WITH_ALL_NAME |
41: | ]; |
42: | |
43: | public function init() |
44: | { |
45: | $this->subscribeEvent('Contacts::PrepareFiltersFromStorage', array($this, 'onPrepareFiltersFromStorage')); |
46: | $this->subscribeEvent('Contacts::UpdateSharedContacts::after', array($this, 'onAfterUpdateSharedContacts')); |
47: | |
48: | $this->subscribeEvent('Contacts::CheckAccessToObject::after', array($this, 'onAfterCheckAccessToObject')); |
49: | $this->subscribeEvent('Contacts::GetContactSuggestions', array($this, 'onGetContactSuggestions')); |
50: | $this->subscribeEvent('Contacts::GetAddressBooks::after', array($this, 'onAfterGetAddressBooks'), 1000); |
51: | |
52: | |
53: | $this->subscribeEvent('Contacts::ContactQueryBuilder', array($this, 'onContactQueryBuilder')); |
54: | $this->subscribeEvent('Contacts::CreateContact::before', array($this, 'onBeforeCreateContact')); |
55: | $this->subscribeEvent('Contacts::CheckAccessToAddressBook::after', array($this, 'onAfterCheckAccessToAddressBook')); |
56: | |
57: | $this->subscribeEvent(self::GetName() . '::UpdateAddressbookShare::before', array($this, 'onBeforeUpdateAddressbookShare')); |
58: | $this->subscribeEvent(self::GetName() . '::GetSharesForAddressbook::before', array($this, 'onBeforeUpdateAddressbookShare')); |
59: | $this->subscribeEvent(self::GetName() . '::LeaveShare::before', array($this, 'onBeforeUpdateAddressbookShare')); |
60: | |
61: | $this->subscribeEvent('Contacts::GetContacts::before', array($this, 'populateContactArguments')); |
62: | $this->subscribeEvent('Contacts::GetContactsByEmails::before', array($this, 'populateContactArguments')); |
63: | $this->subscribeEvent('Contacts::GetContacts::after', array($this, 'onGetContacts')); |
64: | $this->subscribeEvent('Contacts::GetContactsByUids::after', array($this, 'onGetContactsByUids')); |
65: | $this->subscribeEvent('Contacts::PopulateContactArguments', array($this, 'populateContactArguments')); |
66: | $this->subscribeEvent('Contacts::DeleteContacts::before', array($this, 'onBeforeDeleteContacts')); |
67: | $this->subscribeEvent('Contacts::GetStoragesMapToAddressbooks::after', array($this, 'onAfterGetStoragesMapToAddressbooks')); |
68: | $this->subscribeEvent('Contacts::Export::before', array($this, 'populateContactArguments')); |
69: | |
70: | $this->subscribeEvent('Core::AddUsersToGroup::after', [$this, 'onAfterAddUsersToGroup']); |
71: | $this->subscribeEvent('Core::RemoveUsersFromGroup::after', [$this, 'onAfterRemoveUsersFromGroup']); |
72: | $this->subscribeEvent('Core::CreateUser::after', [$this, 'onAfterCreateUser']); |
73: | $this->subscribeEvent('Core::UpdateUser::after', [$this, 'onAfterUpdateUser']); |
74: | $this->subscribeEvent('Core::DeleteUser::before', [$this, 'onBeforeDeleteUser']); |
75: | $this->subscribeEvent('Core::DeleteUser::after', [$this, 'onAfterDeleteUser']); |
76: | $this->subscribeEvent('Core::DeleteGroup::after', [$this, 'onAfterDeleteGroup']); |
77: | } |
78: | |
79: | |
80: | |
81: | |
82: | public static function getInstance() |
83: | { |
84: | return parent::getInstance(); |
85: | } |
86: | |
87: | |
88: | |
89: | |
90: | public static function Decorator() |
91: | { |
92: | return parent::Decorator(); |
93: | } |
94: | |
95: | |
96: | |
97: | |
98: | public function getModuleSettings() |
99: | { |
100: | return $this->oModuleSettings; |
101: | } |
102: | |
103: | public function GetAddressbooks($UserId) |
104: | { |
105: | $mResult = []; |
106: | |
107: | Api::checkUserRoleIsAtLeast(UserRole::NormalUser); |
108: | Api::CheckAccess($UserId); |
109: | |
110: | $dBPrefix = Api::GetSettings()->DBPrefix; |
111: | $stmt = Api::GetPDO()->prepare(" |
112: | select ab.*, sab.access, sab.group_id, sab.addressbookuri from " . $dBPrefix . "adav_shared_addressbooks sab |
113: | left join " . $dBPrefix . "adav_addressbooks ab on sab.addressbook_id = ab.id |
114: | where sab.principaluri = ? |
115: | "); |
116: | |
117: | $principalUri = Constants::PRINCIPALS_PREFIX . Api::getUserPublicIdById($UserId); |
118: | $stmt->execute([ |
119: | $principalUri |
120: | ]); |
121: | |
122: | $abooks = $stmt->fetchAll(\PDO::FETCH_ASSOC); |
123: | |
124: | foreach ($abooks as $abook) { |
125: | if ($abook['principaluri'] !== $principalUri) { |
126: | if (isset($abook['id'])) { |
127: | $storage = StorageType::Shared . '-' . $abook['id']; |
128: | } else { |
129: | $storage = StorageType::Shared . '-' . StorageType::Personal; |
130: | } |
131: | |
132: | if (count($mResult) > 0) { |
133: | foreach ($mResult as $key => $val) { |
134: | if ($val['Id'] === $storage) { |
135: | $iAccess = $mResult[$key]['Access']; |
136: | if ($val['GroupId'] === 0 && $iAccess === Access::NoAccess) { |
137: | continue 2; |
138: | } |
139: | $iNewAccess = $abook['access']; |
140: | if ((int) $abook['group_id'] === 0) { |
141: | $mResult[$key]['Access'] = $iNewAccess; |
142: | } else { |
143: | if ($iNewAccess !== Access::Read) { |
144: | if ($iAccess < $iNewAccess || $iNewAccess === Access::NoAccess) { |
145: | $mResult[$key]['Access'] = $iNewAccess; |
146: | } |
147: | } elseif ($iAccess !== Access::Write) { |
148: | $mResult[$key]['Access'] = $iNewAccess; |
149: | } |
150: | } |
151: | continue 2; |
152: | } |
153: | } |
154: | } |
155: | |
156: | $prevState = Api::skipCheckUserRole(true); |
157: | Api::skipCheckUserRole($prevState); |
158: | |
159: | $mResult[] = [ |
160: | 'Id' => $storage, |
161: | 'EntityId' => isset($abook['id']) ? (int) $abook['id'] : null, |
162: | 'CTag' => isset($abook['synctoken']) ? (int) $abook['synctoken'] : 0, |
163: | 'Display' => true, |
164: | 'Order' => 1, |
165: | 'DisplayName' => $abook['displayname'] . ' (' . basename($abook['principaluri']) . ')', |
166: | 'Uri' => $abook['addressbookuri'], |
167: | 'Url' => 'addressbooks/' . $abook['addressbookuri'], |
168: | 'Shared' => true, |
169: | 'Access' => (int) $abook['access'], |
170: | 'Owner' => basename($abook['principaluri']), |
171: | 'GroupId' => (int) $abook['group_id'] |
172: | ]; |
173: | } |
174: | } |
175: | |
176: | return array_filter($mResult, function ($item) { |
177: | return ($item['Access'] !== Access::NoAccess); |
178: | }); |
179: | } |
180: | |
181: | public function GetSharesForAddressbook($UserId, $Id) |
182: | { |
183: | Api::checkUserRoleIsAtLeast(UserRole::NormalUser); |
184: | Api::CheckAccess($UserId); |
185: | |
186: | $aResult = []; |
187: | |
188: | $shares = $this->_getSharesForAddressbook($UserId, $Id); |
189: | if (count($shares) > 0) { |
190: | $oUser = Api::getUserById($UserId); |
191: | $groups = []; |
192: | foreach ($shares as $share) { |
193: | if ($share['group_id'] != 0) { |
194: | if (!in_array($share['group_id'], $groups)) { |
195: | $oGroup = CoreModule::Decorator()->GetGroup((int) $share['group_id']); |
196: | if ($oGroup) { |
197: | $groups[] = $share['group_id']; |
198: | $aResult[] = [ |
199: | 'PublicId' => $oGroup->getName(), |
200: | 'Access' => (int) $share['access'], |
201: | 'IsGroup' => true, |
202: | 'IsAll' => !!$oGroup->IsAll, |
203: | 'GroupId' => (int) $share['group_id'] |
204: | ]; |
205: | } |
206: | } |
207: | } else { |
208: | $aResult[] = [ |
209: | 'PublicId' => basename($share['principaluri']), |
210: | 'Access' => (int) $share['access'] |
211: | ]; |
212: | } |
213: | } |
214: | } |
215: | |
216: | return $aResult; |
217: | } |
218: | |
219: | protected function _getSharesForAddressbook($iUserId, $abookComplexId) |
220: | { |
221: | $dBPrefix = Api::GetSettings()->DBPrefix; |
222: | $stmt = Api::GetPDO()->prepare(" |
223: | select sab.* from " . $dBPrefix . "adav_shared_addressbooks sab |
224: | left join " . $dBPrefix . "adav_addressbooks ab on sab.addressbook_id = ab.id |
225: | left join " . $dBPrefix . "core_users cu on ab.principaluri = CONCAT('principals/', cu.PublicId) |
226: | where cu.Id = ? AND ab.id = ? |
227: | "); |
228: | |
229: | $stmt->execute([ |
230: | $iUserId, |
231: | $abookComplexId |
232: | ]); |
233: | |
234: | return $stmt->fetchAll(\PDO::FETCH_ASSOC); |
235: | } |
236: | |
237: | protected function getShareForAddressbook($iUserId, $abookComplexId, $principalUri, $groupId = 0) |
238: | { |
239: | $dBPrefix = Api::GetSettings()->DBPrefix; |
240: | $stmt = Api::GetPDO()->prepare(" |
241: | select sab.* |
242: | from " . $dBPrefix . "adav_shared_addressbooks sab |
243: | left join " . $dBPrefix . "adav_addressbooks ab on sab.addressbook_id = ab.id |
244: | left join " . $dBPrefix . "core_users cu on ab.principaluri = CONCAT('principals/', cu.PublicId) |
245: | where cu.Id = ? and sab.principaluri = ? and sab.group_id = ? and ab.id = ? |
246: | "); |
247: | |
248: | $stmt->execute([ |
249: | $iUserId, |
250: | $principalUri, |
251: | $groupId, |
252: | $abookComplexId |
253: | ]); |
254: | |
255: | return $stmt->fetchAll(\PDO::FETCH_ASSOC); |
256: | } |
257: | |
258: | protected function deleteShareByPublicIds($userId, $abookComplexId, $publicIds) |
259: | { |
260: | $dBPrefix = Api::GetSettings()->DBPrefix; |
261: | |
262: | $sharesIds = []; |
263: | foreach ($publicIds as $publicId) { |
264: | $publicId = \json_decode($publicId); |
265: | $shares = $this->getShareForAddressbook($userId, $abookComplexId, Constants::PRINCIPALS_PREFIX . $publicId[0], $publicId[1]); |
266: | if (is_array($shares) && count($shares) > 0) { |
267: | $ids = array_map(function ($share) { |
268: | return $share['id']; |
269: | }, $shares); |
270: | $sharesIds = array_merge($sharesIds, $ids); |
271: | } |
272: | } |
273: | if (count($sharesIds) > 0) { |
274: | $stmt = Api::GetPDO()->prepare("delete from " . $dBPrefix . "adav_shared_addressbooks where id in (" . \implode(',', $sharesIds) . ")"); |
275: | $stmt->execute(); |
276: | } |
277: | } |
278: | |
279: | protected function getAddressbook($iUserId, $abookId) |
280: | { |
281: | $mResult = false; |
282: | |
283: | $dBPrefix = Api::GetSettings()->DBPrefix; |
284: | |
285: | $userPublicId = Api::getUserPublicIdById($iUserId); |
286: | if (!empty($abookId) && $userPublicId) { |
287: | $stmt = Api::GetPDO()->prepare("select * from " . $dBPrefix . "adav_addressbooks where principaluri = ? and id = ?"); |
288: | $stmt->execute([Constants::PRINCIPALS_PREFIX . $userPublicId, $abookId]); |
289: | $mResult = $stmt->fetch(\PDO::FETCH_ASSOC); |
290: | } |
291: | |
292: | return $mResult; |
293: | } |
294: | |
295: | protected function createShare($iUserId, $abookComplexId, $share) |
296: | { |
297: | $dBPrefix = Api::GetSettings()->DBPrefix; |
298: | |
299: | $book = $this->getAddressbook($iUserId, $abookComplexId); |
300: | if ($book) { |
301: | $shareePublicId = $share['PublicId']; |
302: | $access = $share['Access']; |
303: | $groupId = $share['GroupId']; |
304: | $stmt = Api::GetPDO()->prepare("insert into " . $dBPrefix . "adav_shared_addressbooks |
305: | (principaluri, access, addressbook_id, addressbookuri, group_id) |
306: | values (?, ?, ?, ?, ?)"); |
307: | $stmt->execute([Constants::PRINCIPALS_PREFIX . $shareePublicId, $access, $book['id'], UUIDUtil::getUUID(), $groupId]); |
308: | } |
309: | } |
310: | |
311: | protected function updateShare($iUserId, $abookComplexId, $share) |
312: | { |
313: | $dBPrefix = Api::GetSettings()->DBPrefix; |
314: | $book = $this->getAddressbook($iUserId, $abookComplexId); |
315: | if ($book) { |
316: | $shareePublicId = $share['PublicId']; |
317: | $access = $share['Access']; |
318: | $groupId = $share['GroupId']; |
319: | $stmt = Api::GetPDO()->prepare("update " . $dBPrefix . "adav_shared_addressbooks |
320: | set access = ? where principaluri = ? and addressbook_id = ? and group_id = ?"); |
321: | $stmt->execute([$access, Constants::PRINCIPALS_PREFIX . $shareePublicId, $book['id'], $groupId]); |
322: | } |
323: | } |
324: | |
325: | public function onPrepareFiltersFromStorage(&$aArgs, &$mResult) |
326: | { |
327: | if (isset($aArgs['Storage']) && ($aArgs['Storage'] === StorageType::Shared || $aArgs['Storage'] === StorageType::All)) { |
328: | $oUser = Api::getUserById($aArgs['UserId']); |
329: | $aArgs['IsValid'] = true; |
330: | |
331: | $query = Capsule::connection()->table('adav_shared_addressbooks') |
332: | ->select('addressbook_id') |
333: | ->from('adav_shared_addressbooks') |
334: | ->leftJoin('adav_addressbooks', 'adav_shared_addressbooks.addressbook_id', '=', 'adav_addressbooks.id') |
335: | ->where('adav_addressbooks.principaluri', '<>', Constants::PRINCIPALS_PREFIX . $oUser->PublicId) |
336: | ->where('adav_shared_addressbooks.principaluri', Constants::PRINCIPALS_PREFIX . $oUser->PublicId); |
337: | |
338: | if ($aArgs['Storage'] === StorageType::Shared && isset($aArgs['AddressBookId'])) { |
339: | $query->where('addressbook_id', (int) $aArgs['AddressBookId']); |
340: | } |
341: | $ids = $query->pluck('addressbook_id')->all(); |
342: | |
343: | if ($aArgs['Storage'] === StorageType::All && empty($aArgs['AddressBookId'])) { |
344: | $addressbook = $this->GetSharedWithAllAddressbook($oUser->Id); |
345: | if ($addressbook) { |
346: | $ids[] = (int) $addressbook['id']; |
347: | } |
348: | } |
349: | |
350: | if ($ids) { |
351: | $mResult->whereIn('adav_cards.addressbookid', $ids, 'or'); |
352: | } |
353: | |
354: | if (isset($aArgs['Query'])) { |
355: | if ($ids) { |
356: | $aArgs['Query']->addSelect(Capsule::connection()->raw(' |
357: | CASE |
358: | WHEN ' . Capsule::connection()->getTablePrefix() . 'adav_cards.addressbookid IN (' . implode(',', $ids) . ') THEN true |
359: | ELSE false |
360: | END as Shared' |
361: | )); |
362: | } else { |
363: | $aArgs['Query']->addSelect(Capsule::connection()->raw( |
364: | 'false as Shared' |
365: | )); |
366: | } |
367: | } |
368: | } |
369: | } |
370: | |
371: | public function onAfterUpdateSharedContacts($aArgs, &$mResult) |
372: | { |
373: | $oContacts = ContactsModule::Decorator(); |
374: | $aUUIDs = isset($aArgs['UUIDs']) ? $aArgs['UUIDs'] : []; |
375: | |
376: | foreach ($aUUIDs as $sUUID) { |
377: | $oContact = $oContacts->GetContact($sUUID, $aArgs['UserId']); |
378: | if ($oContact instanceof Contact) { |
379: | $FromStorage = $oContact->Storage; |
380: | $ToStorage = $FromStorage; |
381: | if ($oContact->Storage === StorageType::Shared) { |
382: | $ToStorage = StorageType::Personal; |
383: | } elseif ($oContact->Storage === StorageType::Personal) { |
384: | $ToStorage = StorageType::Shared; |
385: | } |
386: | $oContacts->MoveContactsToStorage($aArgs['UserId'], $FromStorage, $ToStorage, [$sUUID]); |
387: | } |
388: | } |
389: | } |
390: | |
391: | public function onAfterCheckAccessToObject(&$aArgs, &$mResult) |
392: | { |
393: | $oUser = $aArgs['User']; |
394: | $oContact = isset($aArgs['Contact']) ? $aArgs['Contact'] : null; |
395: | $Access = isset($aArgs['Access']) ? (int) $aArgs['Access'] : null; |
396: | |
397: | if ($oContact instanceof Contact) { |
398: | if ($oContact->IdUser === $oUser->Id) { |
399: | $mResult = true; |
400: | return true; |
401: | } |
402: | if ($oContact->Storage === StorageType::Shared) { |
403: | if ($oUser->Role !== UserRole::SuperAdmin && $oUser->IdTenant !== $oContact->IdTenant) { |
404: | $mResult = false; |
405: | } else { |
406: | $mResult = true; |
407: | } |
408: | } elseif ($oContact->Storage === StorageType::Personal || $oContact->Storage === StorageType::AddressBook) { |
409: | $dBPrefix = Api::GetSettings()->DBPrefix; |
410: | $sql = "select ab.*, sab.access, ab.id as addressbook_id, cu.Id as UserId from " . $dBPrefix . "adav_shared_addressbooks sab |
411: | left join " . $dBPrefix . "adav_addressbooks ab on sab.addressbook_id = ab.id |
412: | left join " . $dBPrefix . "core_users cu on ab.principaluri = CONCAT('principals/', cu.PublicId) |
413: | where sab.principaluri = ? and cu.Id = ? and ab.id = ?"; |
414: | |
415: | $stmt = Api::GetPDO()->prepare($sql); |
416: | |
417: | $stmt->execute([ |
418: | Constants::PRINCIPALS_PREFIX . $oUser->PublicId, |
419: | $oContact->IdUser, |
420: | $oContact->AddressBookId |
421: | ]); |
422: | |
423: | $abook = $stmt->fetch(\PDO::FETCH_ASSOC); |
424: | if ($abook) { |
425: | if ((int) $abook['access'] === Access::NoAccess) { |
426: | $mResult = false; |
427: | } elseif (isset($Access)) { |
428: | if ($Access === (int) $abook['access'] && $Access === Access::Write) { |
429: | $mResult = true; |
430: | } else { |
431: | $mResult = false; |
432: | } |
433: | } else { |
434: | $mResult = true; |
435: | } |
436: | |
437: | return true; |
438: | } |
439: | } |
440: | } |
441: | } |
442: | |
443: | public function onGetContactSuggestions(&$aArgs, &$mResult) |
444: | { |
445: | if ($aArgs['Storage'] === 'all' || $aArgs['Storage'] === StorageType::Shared) { |
446: | $mResult[StorageType::Shared] = ContactsModule::Decorator()->GetContacts( |
447: | $aArgs['UserId'], |
448: | StorageType::Shared, |
449: | 0, |
450: | $aArgs['Limit'], |
451: | $aArgs['SortField'], |
452: | $aArgs['SortOrder'], |
453: | $aArgs['Search'] |
454: | ); |
455: | } |
456: | } |
457: | |
458: | |
459: | |
460: | |
461: | public function onGetContacts(&$aArgs, &$mResult) |
462: | { |
463: | if ($aArgs['Storage'] === 'all' || $aArgs['Storage'] === StorageType::Shared) { |
464: | $aSharedBooks = $this->GetAddressbooks($aArgs['UserId']); |
465: | foreach ($mResult['List'] as &$aContact) { |
466: | $aStorageParts = explode('-', $aContact['Storage']); |
467: | |
468: | if (in_array($aStorageParts[0], [ StorageType::Personal,StorageType::AddressBook ])) { |
469: | foreach ($aSharedBooks as $aBook) { |
470: | |
471: | if ($aBook['EntityId'] === $aContact['AddressBookId']) { |
472: | $aContact['Storage'] = StorageType::Shared . '-' . $aContact['AddressBookId']; |
473: | } |
474: | } |
475: | } |
476: | } |
477: | } |
478: | } |
479: | |
480: | |
481: | |
482: | |
483: | public function onGetContactsByUids(&$aArgs, &$mResult) |
484: | { |
485: | if (is_array($mResult)) { |
486: | $aSharedBooks = $this->GetAddressbooks($aArgs['UserId']); |
487: | foreach ($mResult as &$oContact) { |
488: | $aStorageParts = explode('-', $oContact->Storage); |
489: | |
490: | if (in_array($aStorageParts[0], [ StorageType::Personal, StorageType::AddressBook ])) { |
491: | foreach ($aSharedBooks as $aBook) { |
492: | |
493: | if ($aBook['EntityId'] === $oContact->AddressBookId) { |
494: | $oContact->Storage = StorageType::Shared . '-' . $oContact->AddressBookId; |
495: | } |
496: | } |
497: | } |
498: | } |
499: | } |
500: | } |
501: | |
502: | public function GetSharedWithAllAddressbook($UserId) |
503: | { |
504: | Api::CheckAccess($UserId); |
505: | |
506: | $addressbook = false; |
507: | |
508: | $oUser = Api::getUserById($UserId); |
509: | if ($oUser) { |
510: | $sPrincipalUri = Constants::PRINCIPALS_PREFIX . $oUser->IdTenant . '_' . Constants::DAV_TENANT_PRINCIPAL; |
511: | $addressbook = Backend::Carddav()->getAddressBookForUser($sPrincipalUri, Constants::ADDRESSBOOK_SHARED_WITH_ALL_NAME); |
512: | if (!$addressbook) { |
513: | if (Backend::Carddav()->createAddressBook($sPrincipalUri, Constants::ADDRESSBOOK_SHARED_WITH_ALL_NAME, ['{DAV:}displayname' => Constants::ADDRESSBOOK_SHARED_WITH_ALL_DISPLAY_NAME])) { |
514: | $addressbook = Backend::Carddav()->getAddressBookForUser($sPrincipalUri, Constants::ADDRESSBOOK_SHARED_WITH_ALL_NAME); |
515: | } |
516: | } |
517: | } |
518: | |
519: | return $addressbook; |
520: | } |
521: | |
522: | public function onAfterGetAddressBooks(&$aArgs, &$mResult) |
523: | { |
524: | if (!is_array($mResult)) { |
525: | $mResult = []; |
526: | } |
527: | foreach ($mResult as $key => $abook) { |
528: | $mResult[$key]['Shares'] = self::Decorator()->GetSharesForAddressbook($aArgs['UserId'], $abook['Id']); |
529: | } |
530: | $mResult = array_merge( |
531: | $mResult, |
532: | $this->GetAddressbooks($aArgs['UserId']) |
533: | ); |
534: | |
535: | $addressbook = $this->GetSharedWithAllAddressbook($aArgs['UserId']); |
536: | if ($addressbook) { |
537: | |
538: | |
539: | |
540: | $mResult[] = [ |
541: | 'Id' => 'shared', |
542: | 'EntityId' => (int) $addressbook['id'], |
543: | 'CTag' => (int) $addressbook['{http://sabredav.org/ns}sync-token'], |
544: | 'Display' => true, |
545: | 'Order' => 1, |
546: | 'DisplayName' => $addressbook['{DAV:}displayname'], |
547: | 'Uri' => $addressbook['uri'], |
548: | 'Url' => 'addressbooks/' . $addressbook['uri'], |
549: | ]; |
550: | } |
551: | } |
552: | |
553: | |
554: | |
555: | |
556: | |
557: | |
558: | |
559: | |
560: | |
561: | |
562: | |
563: | |
564: | |
565: | |
566: | |
567: | |
568: | |
569: | |
570: | |
571: | |
572: | |
573: | |
574: | |
575: | |
576: | |
577: | public function UpdateAddressbookShare($UserId, $Id, $Shares) |
578: | { |
579: | $mResult = true; |
580: | |
581: | Api::checkUserRoleIsAtLeast(UserRole::NormalUser); |
582: | Api::CheckAccess($UserId); |
583: | |
584: | if (!isset($Id) || !is_array($Shares)) { |
585: | throw new InvalidArgumentException("", Notifications::InvalidInputParameter); |
586: | } |
587: | |
588: | try { |
589: | $oUser = Api::getUserById($UserId); |
590: | $currentABookShares = $this->_getSharesForAddressbook($UserId, $Id); |
591: | |
592: | $newABookShares = []; |
593: | foreach ($Shares as $share) { |
594: | if (isset($share['GroupId'])) { |
595: | $aUsers = CoreModule::Decorator()->GetGroupUsers($oUser->IdTenant, (int) $share['GroupId']); |
596: | foreach ($aUsers as $aUser) { |
597: | $newABookShares[] = [ |
598: | 'PublicId' => $aUser['PublicId'], |
599: | 'Access' => (int) $share['Access'], |
600: | 'GroupId' => (int) $share['GroupId'], |
601: | ]; |
602: | } |
603: | } else { |
604: | $share['GroupId'] = 0; |
605: | $newABookShares[] = $share; |
606: | } |
607: | } |
608: | |
609: | $currentShares = array_map(function ($share) { |
610: | return \json_encode([ |
611: | basename($share['principaluri']), |
612: | $share['group_id'] |
613: | ]); |
614: | }, $currentABookShares); |
615: | |
616: | $newShares = array_map(function ($share) { |
617: | return \json_encode([ |
618: | $share['PublicId'], |
619: | $share['GroupId'] |
620: | ]); |
621: | }, $newABookShares); |
622: | |
623: | $sharesToDelete = array_diff($currentShares, $newShares); |
624: | $sharesToCreate = array_diff($newShares, $currentShares); |
625: | $sharesToUpdate = array_intersect($currentShares, $newShares); |
626: | |
627: | if (count($sharesToDelete) > 0) { |
628: | $this->deleteShareByPublicIds($UserId, $Id, $sharesToDelete); |
629: | } |
630: | |
631: | foreach ($newABookShares as $share) { |
632: | $sharePublicIdAndGroupId = \json_encode([ |
633: | $share['PublicId'], |
634: | $share['GroupId'] |
635: | ]); |
636: | if (in_array($sharePublicIdAndGroupId, $sharesToCreate)) { |
637: | $this->createShare($UserId, $Id, $share); |
638: | } |
639: | if (in_array($sharePublicIdAndGroupId, $sharesToUpdate)) { |
640: | $this->updateShare($UserId, $Id, $share); |
641: | } |
642: | } |
643: | |
644: | $mResult = true; |
645: | } catch (\Exception $oException) { |
646: | Api::LogException($oException); |
647: | $mResult = false; |
648: | } |
649: | |
650: | return $mResult; |
651: | } |
652: | |
653: | public function LeaveShare($UserId, $Id) |
654: | { |
655: | Api::checkUserRoleIsAtLeast(UserRole::NormalUser); |
656: | Api::CheckAccess($UserId); |
657: | |
658: | $userPublicId = Api::getUserPublicIdById($UserId); |
659: | |
660: | $sharedAddressBook = Capsule::connection()->table('adav_shared_addressbooks') |
661: | ->where('principaluri', Constants::PRINCIPALS_PREFIX . $userPublicId) |
662: | ->where('addressbook_id', $Id) |
663: | ->where('group_id', 0) |
664: | ->first(); |
665: | |
666: | if ($sharedAddressBook) { |
667: | Capsule::connection()->table('adav_shared_addressbooks') |
668: | ->where('principaluri', Constants::PRINCIPALS_PREFIX . $userPublicId) |
669: | ->where('addressbook_id', $Id) |
670: | ->where('group_id', 0) |
671: | ->update(['access' => Access::NoAccess]); |
672: | } else { |
673: | $stmt = Api::GetPDO()->prepare("insert into " . Api::GetSettings()->DBPrefix . "adav_shared_addressbooks |
674: | (principaluri, access, addressbook_id, addressbookuri, group_id) |
675: | values (?, ?, ?, ?, ?)"); |
676: | $stmt->execute([Constants::PRINCIPALS_PREFIX . $userPublicId, Access::NoAccess, $Id, UUIDUtil::getUUID(), 0]); |
677: | } |
678: | |
679: | return true; |
680: | } |
681: | |
682: | public function onAfterDeleteGroup($aArgs, &$mResult) |
683: | { |
684: | if ($mResult) { |
685: | $dBPrefix = Api::GetSettings()->DBPrefix; |
686: | $stmt = Api::GetPDO()->prepare("delete from " . $dBPrefix . "adav_shared_addressbooks where group_id = ?"); |
687: | $stmt->execute([$aArgs['GroupId']]); |
688: | } |
689: | } |
690: | |
691: | |
692: | |
693: | |
694: | |
695: | |
696: | public function onBeforeDeleteUser($aArgs, &$mResult) |
697: | { |
698: | if (isset($aArgs['UserId'])) { |
699: | $this->oBeforeDeleteUser = Api::getUserById($aArgs['UserId']); |
700: | } |
701: | } |
702: | |
703: | |
704: | |
705: | |
706: | |
707: | |
708: | public function onAfterDeleteUser($aArgs, $mResult) |
709: | { |
710: | if ($mResult && $this->oBeforeDeleteUser instanceof User) { |
711: | $dBPrefix = Api::GetSettings()->DBPrefix; |
712: | $stmt = Api::GetPDO()->prepare("delete from " . $dBPrefix . "adav_shared_addressbooks where principaluri = ?"); |
713: | $stmt->execute([Constants::PRINCIPALS_PREFIX . $this->oBeforeDeleteUser->PublicId]); |
714: | } |
715: | } |
716: | |
717: | public function onAfterAddUsersToGroup($aArgs, &$mResult) |
718: | { |
719: | if ($mResult) { |
720: | foreach ($aArgs['UserIds'] as $iUserId) { |
721: | $userPublicId = Api::getUserPublicIdById($iUserId); |
722: | $sUserPrincipalUri = Constants::PRINCIPALS_PREFIX . $userPublicId; |
723: | |
724: | $dBPrefix = Api::GetSettings()->DBPrefix; |
725: | $stmt = Api::GetPDO()->prepare("select distinct addressbook_id, access from " . $dBPrefix . "adav_shared_addressbooks where group_id = ?"); |
726: | $stmt->execute([$aArgs['GroupId']]); |
727: | $shares = $stmt->fetchAll(\PDO::FETCH_ASSOC); |
728: | foreach ($shares as $share) { |
729: | if (is_array($share)) { |
730: | $stmt = Api::GetPDO()->prepare("insert into " . $dBPrefix . "adav_shared_addressbooks |
731: | (principaluri, access, addressbook_id, addressbookuri, group_id) |
732: | values (?, ?, ?, ?, ?)"); |
733: | $stmt->execute([$sUserPrincipalUri, $share['access'], $share['addressbook_id'], UUIDUtil::getUUID(), $aArgs['GroupId']]); |
734: | } |
735: | } |
736: | } |
737: | } |
738: | } |
739: | |
740: | public function onAfterCreateUser($aArgs, &$mResult) |
741: | { |
742: | if ($mResult) { |
743: | $oUser = User::find($mResult); |
744: | if ($oUser) { |
745: | $oGroup = CoreModule::getInstance()->GetAllGroup($oUser->IdTenant); |
746: | if ($oGroup) { |
747: | $newArgs = [ |
748: | 'GroupId' => $oGroup->Id, |
749: | 'UserIds' => [$mResult] |
750: | ]; |
751: | $newResult = true; |
752: | $this->onAfterAddUsersToGroup($newArgs, $newResult); |
753: | } |
754: | } |
755: | } |
756: | } |
757: | |
758: | public function onAfterUpdateUser($aArgs, &$mResult) |
759: | { |
760: | if ($mResult) { |
761: | $groupIds = $aArgs['GroupIds'] ?? null; |
762: | $userId = $aArgs['UserId']; |
763: | |
764: | if ($groupIds !== null) { |
765: | $userPublicId = Api::getUserPublicIdById($userId); |
766: | $sUserPrincipalUri = Constants::PRINCIPALS_PREFIX . $userPublicId; |
767: | |
768: | $dBPrefix = Api::GetSettings()->DBPrefix; |
769: | $stmt = Api::GetPDO()->prepare("select * from " . $dBPrefix . "adav_shared_addressbooks where group_id <> 0 and principaluri = ?"); |
770: | $stmt->execute([$sUserPrincipalUri]); |
771: | $shares = $stmt->fetchAll(\PDO::FETCH_ASSOC); |
772: | |
773: | $currentGroupsIds = []; |
774: | if (is_array($shares)) { |
775: | $currentGroupsIds = array_map(function ($share) { |
776: | return $share['group_id']; |
777: | }, $shares); |
778: | } |
779: | |
780: | $groupsIdsToDelete = array_diff($currentGroupsIds, $groupIds); |
781: | $groupsIdsToCreate = array_diff($groupIds, $currentGroupsIds); |
782: | |
783: | if (count($groupsIdsToDelete) > 0) { |
784: | $stmt = Api::GetPDO()->prepare("delete from " . $dBPrefix . "adav_shared_addressbooks |
785: | where group_id in (" . \implode(',', $groupsIdsToDelete) . ") and principaluri = ?"); |
786: | $stmt->execute([$sUserPrincipalUri]); |
787: | } |
788: | |
789: | if (count($groupsIdsToCreate) > 0) { |
790: | $stmt = Api::GetPDO()->prepare("select distinct addressbook_id, access, group_id from " . $dBPrefix . "adav_shared_addressbooks where group_id in (" . \implode(',', $groupsIdsToCreate) . ")"); |
791: | $stmt->execute(); |
792: | $shares = $stmt->fetchAll(\PDO::FETCH_ASSOC); |
793: | foreach ($shares as $share) { |
794: | if (is_array($share)) { |
795: | $stmt = Api::GetPDO()->prepare("insert into " . $dBPrefix . "adav_shared_addressbooks |
796: | (principaluri, access, addressbook_id, addressbookuri, group_id) |
797: | values (?, ?, ?, ?, ?)"); |
798: | $stmt->execute([$sUserPrincipalUri, $share['access'], $share['addressbook_id'], UUIDUtil::getUUID(), $share['group_id']]); |
799: | } |
800: | } |
801: | } |
802: | } |
803: | } |
804: | } |
805: | |
806: | public function onAfterRemoveUsersFromGroup($aArgs, &$mResult) |
807: | { |
808: | if ($mResult) { |
809: | $principals = []; |
810: | foreach ($aArgs['UserIds'] as $iUserId) { |
811: | $oUser = Api::getUserById($iUserId); |
812: | $principals[] = Constants::PRINCIPALS_PREFIX . $oUser->PublicId; |
813: | } |
814: | |
815: | if (count($principals) > 0) { |
816: | $dBPrefix = Api::GetSettings()->DBPrefix; |
817: | $principals = array_map(function ($principal) { |
818: | return \Illuminate\Support\Str::padBoth($principal, strlen($principal) + 2, "'"); |
819: | }, $principals); |
820: | $stmt = Api::GetPDO()->prepare("delete from " . $dBPrefix . "adav_shared_addressbooks where principaluri in (" . \implode(',', $principals) . ") and group_id = ?"); |
821: | $stmt->execute([$aArgs['GroupId']]); |
822: | } |
823: | } |
824: | } |
825: | |
826: | public function onContactQueryBuilder(&$aArgs, &$query) |
827: | { |
828: | $userPublicId = Api::getUserPublicIdById($aArgs['UserId']); |
829: | |
830: | if (isset($aArgs['Query'])) { |
831: | $aArgs['Query']->leftJoin('adav_shared_addressbooks', 'adav_cards.addressbookid', '=', 'adav_shared_addressbooks.addressbook_id'); |
832: | } |
833: | $query->orWhere(function ($q) use ($userPublicId, $aArgs) { |
834: | $q->where('adav_shared_addressbooks.principaluri', Constants::PRINCIPALS_PREFIX . $userPublicId); |
835: | if (is_array($aArgs['UUID'])) { |
836: | $ids = $aArgs['UUID']; |
837: | if (count($aArgs['UUID']) === 0) { |
838: | $ids = [null]; |
839: | } |
840: | $q->whereIn('adav_cards.id', $ids); |
841: | } else { |
842: | $q->where('adav_cards.id', $aArgs['UUID']); |
843: | } |
844: | }); |
845: | |
846: | $addressbook = $this->GetSharedWithAllAddressbook($aArgs['UserId']); |
847: | $query->orWhere(function ($q) use ($addressbook, $aArgs) { |
848: | $q->where('adav_addressbooks.id', $addressbook['id']); |
849: | if (is_array($aArgs['UUID'])) { |
850: | if (count($aArgs['UUID']) > 0) { |
851: | $q->whereIn('adav_cards.id', $aArgs['UUID']); |
852: | } |
853: | } else { |
854: | $q->where('adav_cards.id', $aArgs['UUID']); |
855: | } |
856: | }); |
857: | } |
858: | |
859: | public function onBeforeCreateContact(&$aArgs, &$mResult) |
860: | { |
861: | if (isset($aArgs['Contact'])) { |
862: | if (isset($aArgs['UserId'])) { |
863: | $aArgs['Contact']['UserId'] = $aArgs['UserId']; |
864: | } |
865: | $this->populateContactArguments($aArgs['Contact'], $mResult); |
866: | } |
867: | } |
868: | |
869: | |
870: | |
871: | |
872: | public function populateContactArguments(&$aArgs, &$mResult) |
873: | { |
874: | if (isset($aArgs['Storage'], $aArgs['UserId'])) { |
875: | $aStorageParts = \explode('-', $aArgs['Storage']); |
876: | if (count($aStorageParts) > 1) { |
877: | $iAddressBookId = $aStorageParts[1]; |
878: | if ($aStorageParts[0] === StorageType::Shared) { |
879: | if (!is_numeric($iAddressBookId)) { |
880: | return; |
881: | } |
882: | $aArgs['Storage'] = $aStorageParts[0]; |
883: | $aArgs['AddressBookId'] = $iAddressBookId; |
884: | |
885: | $mResult = true; |
886: | } |
887: | } else { |
888: | if ($aStorageParts[0] === StorageType::Shared) { |
889: | $abook = $this->GetSharedWithAllAddressbook($aArgs['UserId']); |
890: | if ($abook) { |
891: | $aArgs['AddressBookId'] = $abook['id']; |
892: | |
893: | $mResult = true; |
894: | } |
895: | } |
896: | } |
897: | } |
898: | } |
899: | |
900: | public function onBeforeDeleteContacts(&$aArgs, &$mResult) |
901: | { |
902: | $this->populateContactArguments($aArgs, $mResult); |
903: | if (isset($aArgs['AddressBookId'])) { |
904: | $aArgs['Storage'] = $aArgs['AddressBookId']; |
905: | } |
906: | } |
907: | |
908: | public function onAfterCheckAccessToAddressBook(&$aArgs, &$mResult) |
909: | { |
910: | if (isset($aArgs['User'], $aArgs['AddressBookId'])) { |
911: | $query = Capsule::connection()->table('adav_addressbooks') |
912: | ->select('adav_addressbooks.id', 'adav_shared_addressbooks.access', 'adav_shared_addressbooks.group_id') |
913: | ->leftJoin('adav_shared_addressbooks', 'adav_addressbooks.id', '=', 'adav_shared_addressbooks.addressbook_id') |
914: | ->where('adav_shared_addressbooks.principaluri', Constants::PRINCIPALS_PREFIX . $aArgs['User']->PublicId) |
915: | ->where('adav_addressbooks.id', $aArgs['AddressBookId']); |
916: | $abooks = $query->get(); |
917: | |
918: | $val = null; |
919: | foreach ($abooks as $abook) { |
920: | if ($val) { |
921: | $iAccess = $val['Access']; |
922: | if ($val['GroupId'] === 0 && $iAccess === Access::NoAccess) { |
923: | continue; |
924: | } |
925: | $iNewAccess = $abook->access; |
926: | if ((int) $abook->group_id === 0) { |
927: | $val['Access'] = $iNewAccess; |
928: | } else { |
929: | if ($iNewAccess !== Access::Read) { |
930: | if ($iAccess < $iNewAccess || $iNewAccess === Access::NoAccess) { |
931: | $val['Access'] = $iNewAccess; |
932: | } |
933: | } elseif ($iAccess !== Access::Write) { |
934: | $val['Access'] = $iNewAccess; |
935: | } |
936: | } |
937: | } |
938: | |
939: | $val = [ |
940: | 'Access' => (int) $abook->access, |
941: | 'GroupId' => (int) $abook->group_id |
942: | ]; |
943: | } |
944: | if ($val) { |
945: | $access = $val['Access']; |
946: | $mResult = ($access === Access::Write || $access === $aArgs['Access']); |
947: | |
948: | return true; |
949: | } else { |
950: | if (isset($aArgs['User'], $aArgs['AddressBookId'])) { |
951: | $addressbook = $this->GetSharedWithAllAddressbook($aArgs['User']->Id); |
952: | if ($addressbook && $addressbook['id'] == $aArgs['AddressBookId']) { |
953: | $mResult = true; |
954: | |
955: | return $mResult; |
956: | } |
957: | } |
958: | } |
959: | }; |
960: | } |
961: | |
962: | |
963: | |
964: | |
965: | public function onBeforeUpdateAddressbookShare(&$aArgs) |
966: | { |
967: | if (isset($aArgs['Id'], $aArgs['UserId'])) { |
968: | $aStorageParts = \explode('-', $aArgs['Id']); |
969: | if (count($aStorageParts) > 1) { |
970: | $iAddressBookId = $aStorageParts[1]; |
971: | |
972: | if (!is_numeric($iAddressBookId)) { |
973: | return; |
974: | } |
975: | $aArgs['Id'] = $iAddressBookId; |
976: | } elseif (isset($aStorageParts[0])) { |
977: | $storagesMapToAddressbooks = ContactsModule::Decorator()->GetStoragesMapToAddressbooks(); |
978: | if (isset($storagesMapToAddressbooks[$aStorageParts[0]])) { |
979: | $addressbookUri = $storagesMapToAddressbooks[$aStorageParts[0]]; |
980: | $userPublicId = Api::getUserPublicIdById($aArgs['UserId']); |
981: | if ($userPublicId) { |
982: | $row = Capsule::connection()->table('adav_addressbooks') |
983: | ->where('principaluri', Constants::PRINCIPALS_PREFIX . $userPublicId) |
984: | ->where('uri', $addressbookUri) |
985: | ->select('adav_addressbooks.id as addressbook_id')->first(); |
986: | if ($row) { |
987: | $aArgs['Id'] = $row->addressbook_id; |
988: | } |
989: | } |
990: | } |
991: | } |
992: | } |
993: | } |
994: | |
995: | public function onAfterGetStoragesMapToAddressbooks(&$aArgs, &$mResult) |
996: | { |
997: | $mResult = array_merge($mResult, $this->storagesMapToAddressbooks); |
998: | } |
999: | } |
1000: | |