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: | ' |
358: | CASE |
359: | WHEN ' . Capsule::connection()->getTablePrefix() . 'adav_cards.addressbookid IN (' . implode(',', $ids) . ') THEN true |
360: | ELSE false |
361: | END as Shared' |
362: | )); |
363: | } else { |
364: | $aArgs['Query']->addSelect(Capsule::connection()->raw( |
365: | 'false as Shared' |
366: | )); |
367: | } |
368: | } |
369: | } |
370: | } |
371: | |
372: | public function onAfterUpdateSharedContacts($aArgs, &$mResult) |
373: | { |
374: | $oContacts = ContactsModule::Decorator(); |
375: | $aUUIDs = isset($aArgs['UUIDs']) ? $aArgs['UUIDs'] : []; |
376: | |
377: | foreach ($aUUIDs as $sUUID) { |
378: | $oContact = $oContacts->GetContact($sUUID, $aArgs['UserId']); |
379: | if ($oContact instanceof Contact) { |
380: | $FromStorage = $oContact->Storage; |
381: | $ToStorage = $FromStorage; |
382: | if ($oContact->Storage === StorageType::Shared) { |
383: | $ToStorage = StorageType::Personal; |
384: | } elseif ($oContact->Storage === StorageType::Personal) { |
385: | $ToStorage = StorageType::Shared; |
386: | } |
387: | $oContacts->MoveContactsToStorage($aArgs['UserId'], $FromStorage, $ToStorage, [$sUUID]); |
388: | } |
389: | } |
390: | } |
391: | |
392: | public function onAfterCheckAccessToObject(&$aArgs, &$mResult) |
393: | { |
394: | $oUser = $aArgs['User']; |
395: | $oContact = isset($aArgs['Contact']) ? $aArgs['Contact'] : null; |
396: | $Access = isset($aArgs['Access']) ? (int) $aArgs['Access'] : null; |
397: | |
398: | if ($oContact instanceof Contact) { |
399: | if ($oContact->IdUser === $oUser->Id) { |
400: | $mResult = true; |
401: | return true; |
402: | } |
403: | if ($oContact->Storage === StorageType::Shared) { |
404: | $sharedWithAllAddressBook = self::Decorator()->GetSharedWithAllAddressbook($oUser->Id); |
405: | if ($oUser->Role === UserRole::SuperAdmin || ($sharedWithAllAddressBook && $oContact->AddressBookId == $sharedWithAllAddressBook['id'])) { |
406: | $mResult = true; |
407: | } else { |
408: | $mResult = false; |
409: | } |
410: | return true; |
411: | } elseif ($oContact->Storage === StorageType::Personal || $oContact->Storage === StorageType::AddressBook) { |
412: | $dBPrefix = Api::GetSettings()->DBPrefix; |
413: | $sql = "select ab.*, sab.access, ab.id as addressbook_id, cu.Id as UserId from " . $dBPrefix . "adav_shared_addressbooks sab |
414: | left join " . $dBPrefix . "adav_addressbooks ab on sab.addressbook_id = ab.id |
415: | left join " . $dBPrefix . "core_users cu on ab.principaluri = CONCAT('principals/', cu.PublicId) |
416: | where sab.principaluri = ? and cu.Id = ? and ab.id = ?"; |
417: | |
418: | $stmt = Api::GetPDO()->prepare($sql); |
419: | |
420: | $stmt->execute([ |
421: | Constants::PRINCIPALS_PREFIX . $oUser->PublicId, |
422: | $oContact->IdUser, |
423: | $oContact->AddressBookId |
424: | ]); |
425: | |
426: | $abook = $stmt->fetch(\PDO::FETCH_ASSOC); |
427: | if ($abook) { |
428: | if ((int) $abook['access'] === Access::NoAccess) { |
429: | $mResult = false; |
430: | } elseif (isset($Access)) { |
431: | if ($Access === (int) $abook['access'] && $Access === Access::Write) { |
432: | $mResult = true; |
433: | } else { |
434: | $mResult = false; |
435: | } |
436: | } else { |
437: | $mResult = true; |
438: | } |
439: | |
440: | return true; |
441: | } |
442: | } |
443: | } |
444: | } |
445: | |
446: | public function onGetContactSuggestions(&$aArgs, &$mResult) |
447: | { |
448: | if ($aArgs['Storage'] === 'all' || $aArgs['Storage'] === StorageType::Shared) { |
449: | $mResult[StorageType::Shared] = ContactsModule::Decorator()->GetContacts( |
450: | $aArgs['UserId'], |
451: | StorageType::Shared, |
452: | 0, |
453: | $aArgs['Limit'], |
454: | $aArgs['SortField'], |
455: | $aArgs['SortOrder'], |
456: | $aArgs['Search'] |
457: | ); |
458: | } |
459: | } |
460: | |
461: | |
462: | |
463: | |
464: | public function onGetContacts(&$aArgs, &$mResult) |
465: | { |
466: | if ($aArgs['Storage'] === 'all' || $aArgs['Storage'] === StorageType::Shared) { |
467: | $aSharedBooks = $this->GetAddressbooks($aArgs['UserId']); |
468: | foreach ($mResult['List'] as &$aContact) { |
469: | $aStorageParts = explode('-', $aContact['Storage']); |
470: | |
471: | if (in_array($aStorageParts[0], [ StorageType::Personal,StorageType::AddressBook ])) { |
472: | foreach ($aSharedBooks as $aBook) { |
473: | |
474: | if ($aBook['EntityId'] === $aContact['AddressBookId']) { |
475: | $aContact['Storage'] = StorageType::Shared . '-' . $aContact['AddressBookId']; |
476: | } |
477: | } |
478: | } |
479: | } |
480: | } |
481: | } |
482: | |
483: | |
484: | |
485: | |
486: | public function onGetContactsByUids(&$aArgs, &$mResult) |
487: | { |
488: | if (is_array($mResult)) { |
489: | $aSharedBooks = $this->GetAddressbooks($aArgs['UserId']); |
490: | foreach ($mResult as &$oContact) { |
491: | $aStorageParts = explode('-', $oContact->Storage); |
492: | |
493: | if (in_array($aStorageParts[0], [ StorageType::Personal, StorageType::AddressBook ])) { |
494: | foreach ($aSharedBooks as $aBook) { |
495: | |
496: | if ($aBook['EntityId'] === $oContact->AddressBookId) { |
497: | $oContact->Storage = StorageType::Shared . '-' . $oContact->AddressBookId; |
498: | } |
499: | } |
500: | } |
501: | } |
502: | } |
503: | } |
504: | |
505: | public function GetSharedWithAllAddressbook($UserId) |
506: | { |
507: | Api::CheckAccess($UserId); |
508: | |
509: | $addressbook = false; |
510: | |
511: | $oUser = Api::getUserById($UserId); |
512: | if ($oUser) { |
513: | $sPrincipalUri = Constants::PRINCIPALS_PREFIX . $oUser->IdTenant . '_' . Constants::DAV_TENANT_PRINCIPAL; |
514: | $addressbook = Backend::Carddav()->getAddressBookForUser($sPrincipalUri, Constants::ADDRESSBOOK_SHARED_WITH_ALL_NAME); |
515: | if (!$addressbook) { |
516: | if (Backend::Carddav()->createAddressBook($sPrincipalUri, Constants::ADDRESSBOOK_SHARED_WITH_ALL_NAME, ['{DAV:}displayname' => Constants::ADDRESSBOOK_SHARED_WITH_ALL_DISPLAY_NAME])) { |
517: | $addressbook = Backend::Carddav()->getAddressBookForUser($sPrincipalUri, Constants::ADDRESSBOOK_SHARED_WITH_ALL_NAME); |
518: | } |
519: | } |
520: | } |
521: | |
522: | return $addressbook; |
523: | } |
524: | |
525: | public function onAfterGetAddressBooks(&$aArgs, &$mResult) |
526: | { |
527: | if (!is_array($mResult)) { |
528: | $mResult = []; |
529: | } |
530: | foreach ($mResult as $key => $abook) { |
531: | $mResult[$key]['Shares'] = self::Decorator()->GetSharesForAddressbook($aArgs['UserId'], $abook['Id']); |
532: | } |
533: | $mResult = array_merge( |
534: | $mResult, |
535: | $this->GetAddressbooks($aArgs['UserId']) |
536: | ); |
537: | |
538: | $addressbook = $this->GetSharedWithAllAddressbook($aArgs['UserId']); |
539: | if ($addressbook) { |
540: | |
541: | |
542: | |
543: | $mResult[] = [ |
544: | 'Id' => 'shared', |
545: | 'EntityId' => (int) $addressbook['id'], |
546: | 'CTag' => (int) $addressbook['{http://sabredav.org/ns}sync-token'], |
547: | 'Display' => true, |
548: | 'Order' => 1, |
549: | 'DisplayName' => $addressbook['{DAV:}displayname'], |
550: | 'Uri' => $addressbook['uri'], |
551: | 'Url' => 'addressbooks/' . $addressbook['uri'], |
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: | |
578: | |
579: | |
580: | public function UpdateAddressbookShare($UserId, $Id, $Shares) |
581: | { |
582: | $mResult = true; |
583: | |
584: | Api::checkUserRoleIsAtLeast(UserRole::NormalUser); |
585: | Api::CheckAccess($UserId); |
586: | |
587: | if (!isset($Id) || !is_array($Shares)) { |
588: | throw new InvalidArgumentException("", Notifications::InvalidInputParameter); |
589: | } |
590: | |
591: | try { |
592: | $oUser = Api::getUserById($UserId); |
593: | $currentABookShares = $this->_getSharesForAddressbook($UserId, $Id); |
594: | |
595: | $newABookShares = []; |
596: | foreach ($Shares as $share) { |
597: | if (isset($share['GroupId'])) { |
598: | $aUsers = CoreModule::Decorator()->GetGroupUsers($oUser->IdTenant, (int) $share['GroupId']); |
599: | foreach ($aUsers as $aUser) { |
600: | $newABookShares[] = [ |
601: | 'PublicId' => $aUser['PublicId'], |
602: | 'Access' => (int) $share['Access'], |
603: | 'GroupId' => (int) $share['GroupId'], |
604: | ]; |
605: | } |
606: | } else { |
607: | $share['GroupId'] = 0; |
608: | $newABookShares[] = $share; |
609: | } |
610: | } |
611: | |
612: | $currentShares = array_map(function ($share) { |
613: | return \json_encode([ |
614: | basename($share['principaluri']), |
615: | $share['group_id'] |
616: | ]); |
617: | }, $currentABookShares); |
618: | |
619: | $newShares = array_map(function ($share) { |
620: | return \json_encode([ |
621: | $share['PublicId'], |
622: | $share['GroupId'] |
623: | ]); |
624: | }, $newABookShares); |
625: | |
626: | $sharesToDelete = array_diff($currentShares, $newShares); |
627: | $sharesToCreate = array_diff($newShares, $currentShares); |
628: | $sharesToUpdate = array_intersect($currentShares, $newShares); |
629: | |
630: | if (count($sharesToDelete) > 0) { |
631: | $this->deleteShareByPublicIds($UserId, $Id, $sharesToDelete); |
632: | } |
633: | |
634: | foreach ($newABookShares as $share) { |
635: | $sharePublicIdAndGroupId = \json_encode([ |
636: | $share['PublicId'], |
637: | $share['GroupId'] |
638: | ]); |
639: | if (in_array($sharePublicIdAndGroupId, $sharesToCreate)) { |
640: | $this->createShare($UserId, $Id, $share); |
641: | } |
642: | if (in_array($sharePublicIdAndGroupId, $sharesToUpdate)) { |
643: | $this->updateShare($UserId, $Id, $share); |
644: | } |
645: | } |
646: | |
647: | $mResult = true; |
648: | } catch (\Exception $oException) { |
649: | Api::LogException($oException); |
650: | $mResult = false; |
651: | } |
652: | |
653: | return $mResult; |
654: | } |
655: | |
656: | public function LeaveShare($UserId, $Id) |
657: | { |
658: | Api::checkUserRoleIsAtLeast(UserRole::NormalUser); |
659: | Api::CheckAccess($UserId); |
660: | |
661: | $userPublicId = Api::getUserPublicIdById($UserId); |
662: | |
663: | $sharedAddressBook = Capsule::connection()->table('adav_shared_addressbooks') |
664: | ->where('principaluri', Constants::PRINCIPALS_PREFIX . $userPublicId) |
665: | ->where('addressbook_id', $Id) |
666: | ->where('group_id', 0) |
667: | ->first(); |
668: | |
669: | if ($sharedAddressBook) { |
670: | Capsule::connection()->table('adav_shared_addressbooks') |
671: | ->where('principaluri', Constants::PRINCIPALS_PREFIX . $userPublicId) |
672: | ->where('addressbook_id', $Id) |
673: | ->where('group_id', 0) |
674: | ->update(['access' => Access::NoAccess]); |
675: | } else { |
676: | $stmt = Api::GetPDO()->prepare("insert into " . Api::GetSettings()->DBPrefix . "adav_shared_addressbooks |
677: | (principaluri, access, addressbook_id, addressbookuri, group_id) |
678: | values (?, ?, ?, ?, ?)"); |
679: | $stmt->execute([Constants::PRINCIPALS_PREFIX . $userPublicId, Access::NoAccess, $Id, UUIDUtil::getUUID(), 0]); |
680: | } |
681: | |
682: | return true; |
683: | } |
684: | |
685: | public function onAfterDeleteGroup($aArgs, &$mResult) |
686: | { |
687: | if ($mResult) { |
688: | $dBPrefix = Api::GetSettings()->DBPrefix; |
689: | $stmt = Api::GetPDO()->prepare("delete from " . $dBPrefix . "adav_shared_addressbooks where group_id = ?"); |
690: | $stmt->execute([$aArgs['GroupId']]); |
691: | } |
692: | } |
693: | |
694: | |
695: | |
696: | |
697: | |
698: | |
699: | public function onBeforeDeleteUser($aArgs, &$mResult) |
700: | { |
701: | if (isset($aArgs['UserId'])) { |
702: | $this->oBeforeDeleteUser = Api::getUserById($aArgs['UserId']); |
703: | } |
704: | } |
705: | |
706: | |
707: | |
708: | |
709: | |
710: | |
711: | public function onAfterDeleteUser($aArgs, $mResult) |
712: | { |
713: | if ($mResult && $this->oBeforeDeleteUser instanceof User) { |
714: | $dBPrefix = Api::GetSettings()->DBPrefix; |
715: | $stmt = Api::GetPDO()->prepare("delete from " . $dBPrefix . "adav_shared_addressbooks where principaluri = ?"); |
716: | $stmt->execute([Constants::PRINCIPALS_PREFIX . $this->oBeforeDeleteUser->PublicId]); |
717: | } |
718: | } |
719: | |
720: | public function onAfterAddUsersToGroup($aArgs, &$mResult) |
721: | { |
722: | if ($mResult) { |
723: | foreach ($aArgs['UserIds'] as $iUserId) { |
724: | $userPublicId = Api::getUserPublicIdById($iUserId); |
725: | $sUserPrincipalUri = Constants::PRINCIPALS_PREFIX . $userPublicId; |
726: | |
727: | $dBPrefix = Api::GetSettings()->DBPrefix; |
728: | $stmt = Api::GetPDO()->prepare("select distinct addressbook_id, access from " . $dBPrefix . "adav_shared_addressbooks where group_id = ?"); |
729: | $stmt->execute([$aArgs['GroupId']]); |
730: | $shares = $stmt->fetchAll(\PDO::FETCH_ASSOC); |
731: | foreach ($shares as $share) { |
732: | if (is_array($share)) { |
733: | $stmt = Api::GetPDO()->prepare("insert into " . $dBPrefix . "adav_shared_addressbooks |
734: | (principaluri, access, addressbook_id, addressbookuri, group_id) |
735: | values (?, ?, ?, ?, ?)"); |
736: | $stmt->execute([$sUserPrincipalUri, $share['access'], $share['addressbook_id'], UUIDUtil::getUUID(), $aArgs['GroupId']]); |
737: | } |
738: | } |
739: | } |
740: | } |
741: | } |
742: | |
743: | public function onAfterCreateUser($aArgs, &$mResult) |
744: | { |
745: | if ($mResult) { |
746: | $oUser = User::find($mResult); |
747: | if ($oUser) { |
748: | $oGroup = CoreModule::getInstance()->GetAllGroup($oUser->IdTenant); |
749: | if ($oGroup) { |
750: | $newArgs = [ |
751: | 'GroupId' => $oGroup->Id, |
752: | 'UserIds' => [$mResult] |
753: | ]; |
754: | $newResult = true; |
755: | $this->onAfterAddUsersToGroup($newArgs, $newResult); |
756: | } |
757: | } |
758: | } |
759: | } |
760: | |
761: | public function onAfterUpdateUser($aArgs, &$mResult) |
762: | { |
763: | if ($mResult) { |
764: | $groupIds = $aArgs['GroupIds'] ?? null; |
765: | $userId = $aArgs['UserId']; |
766: | |
767: | if ($groupIds !== null) { |
768: | $userPublicId = Api::getUserPublicIdById($userId); |
769: | $sUserPrincipalUri = Constants::PRINCIPALS_PREFIX . $userPublicId; |
770: | |
771: | $dBPrefix = Api::GetSettings()->DBPrefix; |
772: | $stmt = Api::GetPDO()->prepare("select * from " . $dBPrefix . "adav_shared_addressbooks where group_id <> 0 and principaluri = ?"); |
773: | $stmt->execute([$sUserPrincipalUri]); |
774: | $shares = $stmt->fetchAll(\PDO::FETCH_ASSOC); |
775: | |
776: | $currentGroupsIds = []; |
777: | if (is_array($shares)) { |
778: | $currentGroupsIds = array_map(function ($share) { |
779: | return $share['group_id']; |
780: | }, $shares); |
781: | } |
782: | |
783: | $groupsIdsToDelete = array_diff($currentGroupsIds, $groupIds); |
784: | $groupsIdsToCreate = array_diff($groupIds, $currentGroupsIds); |
785: | |
786: | if (count($groupsIdsToDelete) > 0) { |
787: | $stmt = Api::GetPDO()->prepare("delete from " . $dBPrefix . "adav_shared_addressbooks |
788: | where group_id in (" . \implode(',', $groupsIdsToDelete) . ") and principaluri = ?"); |
789: | $stmt->execute([$sUserPrincipalUri]); |
790: | } |
791: | |
792: | if (count($groupsIdsToCreate) > 0) { |
793: | $stmt = Api::GetPDO()->prepare("select distinct addressbook_id, access, group_id from " . $dBPrefix . "adav_shared_addressbooks where group_id in (" . \implode(',', $groupsIdsToCreate) . ")"); |
794: | $stmt->execute(); |
795: | $shares = $stmt->fetchAll(\PDO::FETCH_ASSOC); |
796: | foreach ($shares as $share) { |
797: | if (is_array($share)) { |
798: | $stmt = Api::GetPDO()->prepare("insert into " . $dBPrefix . "adav_shared_addressbooks |
799: | (principaluri, access, addressbook_id, addressbookuri, group_id) |
800: | values (?, ?, ?, ?, ?)"); |
801: | $stmt->execute([$sUserPrincipalUri, $share['access'], $share['addressbook_id'], UUIDUtil::getUUID(), $share['group_id']]); |
802: | } |
803: | } |
804: | } |
805: | } |
806: | } |
807: | } |
808: | |
809: | public function onAfterRemoveUsersFromGroup($aArgs, &$mResult) |
810: | { |
811: | if ($mResult) { |
812: | $principals = []; |
813: | foreach ($aArgs['UserIds'] as $iUserId) { |
814: | $oUser = Api::getUserById($iUserId); |
815: | $principals[] = Constants::PRINCIPALS_PREFIX . $oUser->PublicId; |
816: | } |
817: | |
818: | if (count($principals) > 0) { |
819: | $dBPrefix = Api::GetSettings()->DBPrefix; |
820: | $principals = array_map(function ($principal) { |
821: | return \Illuminate\Support\Str::padBoth($principal, strlen($principal) + 2, "'"); |
822: | }, $principals); |
823: | $stmt = Api::GetPDO()->prepare("delete from " . $dBPrefix . "adav_shared_addressbooks where principaluri in (" . \implode(',', $principals) . ") and group_id = ?"); |
824: | $stmt->execute([$aArgs['GroupId']]); |
825: | } |
826: | } |
827: | } |
828: | |
829: | public function onContactQueryBuilder(&$aArgs, &$query) |
830: | { |
831: | $userPublicId = Api::getUserPublicIdById($aArgs['UserId']); |
832: | |
833: | if (isset($aArgs['Query'])) { |
834: | $aArgs['Query']->leftJoin('adav_shared_addressbooks', 'adav_cards.addressbookid', '=', 'adav_shared_addressbooks.addressbook_id'); |
835: | } |
836: | $query->orWhere(function ($q) use ($userPublicId, $aArgs) { |
837: | $q->where('adav_shared_addressbooks.principaluri', Constants::PRINCIPALS_PREFIX . $userPublicId); |
838: | if (is_array($aArgs['UUID'])) { |
839: | $ids = $aArgs['UUID']; |
840: | if (count($aArgs['UUID']) === 0) { |
841: | $ids = [null]; |
842: | } |
843: | $q->whereIn('adav_cards.id', $ids); |
844: | } else { |
845: | $q->where('adav_cards.id', $aArgs['UUID']); |
846: | } |
847: | }); |
848: | |
849: | $addressbook = $this->GetSharedWithAllAddressbook($aArgs['UserId']); |
850: | $query->orWhere(function ($q) use ($addressbook, $aArgs) { |
851: | $q->where('adav_addressbooks.id', $addressbook['id']); |
852: | if (is_array($aArgs['UUID'])) { |
853: | if (count($aArgs['UUID']) > 0) { |
854: | $q->whereIn('adav_cards.id', $aArgs['UUID']); |
855: | } |
856: | } else { |
857: | $q->where('adav_cards.id', $aArgs['UUID']); |
858: | } |
859: | }); |
860: | } |
861: | |
862: | public function onBeforeCreateContact(&$aArgs, &$mResult) |
863: | { |
864: | if (isset($aArgs['Contact'])) { |
865: | if (isset($aArgs['UserId'])) { |
866: | $aArgs['Contact']['UserId'] = $aArgs['UserId']; |
867: | } |
868: | $this->populateContactArguments($aArgs['Contact'], $mResult); |
869: | } |
870: | } |
871: | |
872: | |
873: | |
874: | |
875: | public function populateContactArguments(&$aArgs, &$mResult) |
876: | { |
877: | if (isset($aArgs['Storage'], $aArgs['UserId'])) { |
878: | $aStorageParts = \explode('-', $aArgs['Storage']); |
879: | if (count($aStorageParts) > 1) { |
880: | $iAddressBookId = $aStorageParts[1]; |
881: | if ($aStorageParts[0] === StorageType::Shared) { |
882: | if (!is_numeric($iAddressBookId)) { |
883: | return; |
884: | } |
885: | $aArgs['Storage'] = $aStorageParts[0]; |
886: | $aArgs['AddressBookId'] = $iAddressBookId; |
887: | |
888: | $mResult = true; |
889: | } |
890: | } else { |
891: | if ($aStorageParts[0] === StorageType::Shared) { |
892: | $abook = $this->GetSharedWithAllAddressbook($aArgs['UserId']); |
893: | if ($abook) { |
894: | $aArgs['AddressBookId'] = $abook['id']; |
895: | |
896: | $mResult = true; |
897: | } |
898: | } |
899: | } |
900: | } |
901: | } |
902: | |
903: | public function onBeforeDeleteContacts(&$aArgs, &$mResult) |
904: | { |
905: | $this->populateContactArguments($aArgs, $mResult); |
906: | if (isset($aArgs['AddressBookId'])) { |
907: | $aArgs['Storage'] = $aArgs['AddressBookId']; |
908: | } |
909: | } |
910: | |
911: | public function onAfterCheckAccessToAddressBook(&$aArgs, &$mResult) |
912: | { |
913: | if (isset($aArgs['User'], $aArgs['AddressBookId'])) { |
914: | $query = Capsule::connection()->table('adav_addressbooks') |
915: | ->select('adav_addressbooks.id', 'adav_shared_addressbooks.access', 'adav_shared_addressbooks.group_id') |
916: | ->leftJoin('adav_shared_addressbooks', 'adav_addressbooks.id', '=', 'adav_shared_addressbooks.addressbook_id') |
917: | ->where('adav_shared_addressbooks.principaluri', Constants::PRINCIPALS_PREFIX . $aArgs['User']->PublicId) |
918: | ->where('adav_addressbooks.id', $aArgs['AddressBookId']); |
919: | $abooks = $query->get(); |
920: | |
921: | $val = null; |
922: | foreach ($abooks as $abook) { |
923: | if ($val) { |
924: | $iAccess = $val['Access']; |
925: | if ($val['GroupId'] === 0 && $iAccess === Access::NoAccess) { |
926: | continue; |
927: | } |
928: | $iNewAccess = $abook->access; |
929: | if ((int) $abook->group_id === 0) { |
930: | $val['Access'] = $iNewAccess; |
931: | } else { |
932: | if ($iNewAccess !== Access::Read) { |
933: | if ($iAccess < $iNewAccess || $iNewAccess === Access::NoAccess) { |
934: | $val['Access'] = $iNewAccess; |
935: | } |
936: | } elseif ($iAccess !== Access::Write) { |
937: | $val['Access'] = $iNewAccess; |
938: | } |
939: | } |
940: | } |
941: | |
942: | $val = [ |
943: | 'Access' => (int) $abook->access, |
944: | 'GroupId' => (int) $abook->group_id |
945: | ]; |
946: | } |
947: | if ($val) { |
948: | $access = $val['Access']; |
949: | $mResult = ($access === Access::Write || $access === $aArgs['Access']); |
950: | |
951: | return true; |
952: | } else { |
953: | if (isset($aArgs['User'], $aArgs['AddressBookId'])) { |
954: | $addressbook = $this->GetSharedWithAllAddressbook($aArgs['User']->Id); |
955: | if ($addressbook && $addressbook['id'] == $aArgs['AddressBookId']) { |
956: | $mResult = true; |
957: | |
958: | return $mResult; |
959: | } |
960: | } |
961: | } |
962: | }; |
963: | } |
964: | |
965: | |
966: | |
967: | |
968: | public function onBeforeUpdateAddressbookShare(&$aArgs) |
969: | { |
970: | if (isset($aArgs['Id'], $aArgs['UserId'])) { |
971: | $aStorageParts = \explode('-', $aArgs['Id']); |
972: | if (count($aStorageParts) > 1) { |
973: | $iAddressBookId = $aStorageParts[1]; |
974: | |
975: | if (!is_numeric($iAddressBookId)) { |
976: | return; |
977: | } |
978: | $aArgs['Id'] = $iAddressBookId; |
979: | } elseif (isset($aStorageParts[0])) { |
980: | $storagesMapToAddressbooks = ContactsModule::Decorator()->GetStoragesMapToAddressbooks(); |
981: | if (isset($storagesMapToAddressbooks[$aStorageParts[0]])) { |
982: | $addressbookUri = $storagesMapToAddressbooks[$aStorageParts[0]]; |
983: | $userPublicId = Api::getUserPublicIdById($aArgs['UserId']); |
984: | if ($userPublicId) { |
985: | $row = Capsule::connection()->table('adav_addressbooks') |
986: | ->where('principaluri', Constants::PRINCIPALS_PREFIX . $userPublicId) |
987: | ->where('uri', $addressbookUri) |
988: | ->select('adav_addressbooks.id as addressbook_id')->first(); |
989: | if ($row) { |
990: | $aArgs['Id'] = $row->addressbook_id; |
991: | } |
992: | } |
993: | } |
994: | } |
995: | } |
996: | } |
997: | |
998: | public function onAfterGetStoragesMapToAddressbooks(&$aArgs, &$mResult) |
999: | { |
1000: | $mResult = array_merge($mResult, $this->storagesMapToAddressbooks); |
1001: | } |
1002: | } |
1003: | |