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\Contacts;
9:
10: use Aurora\Api;
11: use Aurora\Modules\Contacts\Enums\Access;
12: use Aurora\Modules\Contacts\Enums\StorageType;
13: use Aurora\Modules\Contacts\Models\AddressBook;
14: use Aurora\Modules\Contacts\Models\Contact;
15: use Aurora\Modules\Contacts\Models\Group;
16: use Aurora\Modules\Core\Module as CoreModule;
17: use Aurora\System\Exceptions\ApiException;
18: use Aurora\System\Notifications;
19: use Illuminate\Database\Eloquent\Builder;
20: use Sabre\DAV\UUIDUtil;
21:
22: /**
23: * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
24: * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
25: * @copyright Copyright (c) 2023, Afterlogic Corp.
26: *
27: * @package Modules
28: */
29: class Module extends \Aurora\System\Module\AbstractModule
30: {
31: public $oManager = null;
32:
33: protected $aImportExportFormats = ['csv', 'vcf'];
34:
35: /**
36: *
37: * @return Module
38: */
39: public static function getInstance()
40: {
41: return \Aurora\System\Api::GetModule(self::GetName());
42: }
43:
44: public function getManager()
45: {
46: if ($this->oManager === null) {
47: $this->oManager = new Manager($this);
48: }
49:
50: return $this->oManager;
51: }
52:
53: /**
54: * Initializes Contacts Module.
55: *
56: * @ignore
57: */
58: public function init()
59: {
60: $this->subscribeEvent('Mail::AfterUseEmails', array($this, 'onAfterUseEmails'));
61: $this->subscribeEvent('Mail::GetBodyStructureParts', array($this, 'onGetBodyStructureParts'));
62: $this->subscribeEvent('Core::DeleteUser::after', array($this, 'onAfterDeleteUser'));
63:
64: $this->subscribeEvent('Calendar::CreateEvent', array($this, 'onCreateOrUpdateEvent'));
65: $this->subscribeEvent('Calendar::UpdateEvent', array($this, 'onCreateOrUpdateEvent'));
66: }
67:
68: /***** public functions *****/
69: /**
70: * Returns API contacts manager.
71: * @return \CApiContactsManager
72: */
73: public function GetApiContactsManager()
74: {
75: return $this->getManager();
76: }
77: /***** public functions *****/
78:
79: /***** public functions might be called with web API *****/
80: /**
81: * @apiDefine Contacts Contacts Module
82: * Main Contacts module. It provides PHP and Web APIs for managing contacts.
83: */
84:
85: /**
86: * @api {post} ?/Api/ GetSettings
87: * @apiName GetSettings
88: * @apiGroup Contacts
89: * @apiDescription Obtains list of module settings for authenticated user.
90: *
91: * @apiHeader {string} [Authorization] "Bearer " + Authentication token which was received as the result of Core.Login method.
92: * @apiHeaderExample {json} Header-Example:
93: * {
94: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
95: * }
96: *
97: * @apiParam {string=Contacts} Module Module name
98: * @apiParam {string=GetSettings} Method Method name
99: *
100: * @apiParamExample {json} Request-Example:
101: * {
102: * Module: 'Contacts',
103: * Method: 'GetSettings'
104: * }
105: *
106: * @apiSuccess {object[]} Result Array of response objects.
107: * @apiSuccess {string} Result.Module Module name.
108: * @apiSuccess {string} Result.Method Method name.
109: * @apiSuccess {mixed} Result.Result List of module settings in case of success, otherwise **false**.
110: * @apiSuccess {int} Result.Result.ContactsPerPage=20 Count of contacts that will be displayed on one page.
111: * @apiSuccess {string} Result.Result.ImportContactsLink=&quot;&quot; Link for learning more about CSV format.
112: * @apiSuccess {array} Result.Result.Storages='[]' List of storages wich will be shown in the interface.
113: * @apiSuccess {array} Result.Result.ImportExportFormats='[]' List of formats that can be used for import and export contacts.
114: * @apiSuccess {array} Result.Result.\Aurora\Modules\Contacts\Enums\PrimaryEmail='[]' Enumeration with primary email values.
115: * @apiSuccess {array} Result.Result.\Aurora\Modules\Contacts\Enums\PrimaryPhone='[]' Enumeration with primary phone values.
116: * @apiSuccess {array} Result.Result.\Aurora\Modules\Contacts\Enums\PrimaryAddress='[]' Enumeration with primary address values.
117: * @apiSuccess {array} Result.Result.\Aurora\Modules\Contacts\Enums\SortField='[]' Enumeration with sort field values.
118: * @apiSuccess {int} [Result.ErrorCode] Error code
119: *
120: * @apiSuccessExample {json} Success response example:
121: * {
122: * Module: 'Contacts',
123: * Method: 'GetSettings',
124: * Result: { ContactsPerPage: 20, ImportContactsLink: '', Storages: ['personal', 'team'],
125: * ImportExportFormats: ['csv', 'vcf'], \Aurora\Modules\Contacts\Enums\PrimaryEmail: {'Personal': 0, 'Business': 1, 'Other': 2},
126: * \Aurora\Modules\Contacts\Enums\PrimaryPhone: {'Mobile': 0, 'Personal': 1, 'Business': 2},
127: * \Aurora\Modules\Contacts\Enums\PrimaryAddress: {'Personal': 0, 'Business': 1},
128: * \Aurora\Modules\Contacts\Enums\SortField: {'Name': 1, 'Email': 2, 'Frequency': 3} }
129: * }
130: *
131: * @apiSuccessExample {json} Error response example:
132: * {
133: * Module: 'Contacts',
134: * Method: 'GetSettings',
135: * Result: false,
136: * ErrorCode: 102
137: * }
138: */
139:
140: /**
141: * Obtains list of module settings for authenticated user.
142: * @return array
143: */
144: public function GetSettings()
145: {
146: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
147: $oUser = \Aurora\System\Api::getAuthenticatedUser();
148: $aResult = [
149: 'AllowAddressBooksManagement' => $this->getConfig('AllowAddressBooksManagement', false),
150: 'ImportContactsLink' => $this->getConfig('ImportContactsLink', ''),
151: 'PrimaryEmail' => (new Enums\PrimaryEmail())->getMap(),
152: 'PrimaryPhone' => (new Enums\PrimaryPhone())->getMap(),
153: 'PrimaryAddress' => (new Enums\PrimaryAddress())->getMap(),
154: 'SortField' => (new Enums\SortField())->getMap(),
155: 'ImportExportFormats' => $this->aImportExportFormats,
156: 'SaveVcfServerModuleName' => \Aurora\System\Api::GetModuleManager()->ModuleExists('DavContacts') ? 'DavContacts' : '',
157: 'ContactsPerPage' => $this->getConfig('ContactsPerPage', 20),
158: 'ContactsSortBy' => $this->getConfig('ContactsSortBy', [])
159: ];
160:
161: if ($oUser && $oUser->isNormalOrTenant()) {
162: if (isset($oUser->{self::GetName().'::ContactsPerPage'})) {
163: $aResult['ContactsPerPage'] = $oUser->{self::GetName().'::ContactsPerPage'};
164: }
165:
166: $aResult['Storages'] = self::Decorator()->GetStorages();
167: }
168:
169: return $aResult;
170: }
171:
172: public function IsDisplayedStorage($Storage)
173: {
174: return true;
175: }
176:
177: //Depricated
178: public function GetContactStorages()
179: {
180: return $this->Decorator()->GetStorages();
181: }
182:
183: public function GetStorages()
184: {
185: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
186:
187: $aStorages = [];
188: $aStorageNames = [];
189: $this->broadcastEvent('GetStorages', $aStorageNames);
190: \ksort($aStorageNames);
191:
192: $iUserId = \Aurora\System\Api::getAuthenticatedUserId();
193:
194: foreach ($aStorageNames as $iIndex => $sStorageName) {
195: $aStorages[] = [
196: 'Id' => $sStorageName,
197: 'CTag' => $this->Decorator()->GetCTag($iUserId, $sStorageName),
198: 'Display' => $this->Decorator()->IsDisplayedStorage($sStorageName),
199: 'Order' => $iIndex
200: ];
201: }
202:
203: return array_merge($aStorages, $this->Decorator()->GetAddressBooks($iUserId));
204: }
205:
206: /**
207: * @api {post} ?/Api/ UpdateSettings
208: * @apiName UpdateSettings
209: * @apiGroup Contacts
210: * @apiDescription Updates module's settings - saves them to config.json file.
211: *
212: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
213: * @apiHeaderExample {json} Header-Example:
214: * {
215: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
216: * }
217: *
218: * @apiParam {string=Contacts} Module Module name
219: * @apiParam {string=UpdateSettings} Method Method name
220: * @apiParam {string} Parameters JSON.stringified object <br>
221: * {<br>
222: * &emsp; **ContactsPerPage** *int* Count of contacts per page.<br>
223: * }
224: *
225: * @apiParamExample {json} Request-Example:
226: * {
227: * Module: 'Contacts',
228: * Method: 'UpdateSettings',
229: * Parameters: '{ ContactsPerPage: 10 }'
230: * }
231: *
232: * @apiSuccess {object[]} Result Array of response objects.
233: * @apiSuccess {string} Result.Module Module name
234: * @apiSuccess {string} Result.Method Method name
235: * @apiSuccess {bool} Result.Result Indicates if settings were updated successfully.
236: * @apiSuccess {int} [Result.ErrorCode] Error code
237: *
238: * @apiSuccessExample {json} Success response example:
239: * {
240: * Module: 'Contacts',
241: * Method: 'UpdateSettings',
242: * Result: true
243: * }
244: *
245: * @apiSuccessExample {json} Error response example:
246: * {
247: * Module: 'Contacts',
248: * Method: 'UpdateSettings',
249: * Result: false,
250: * ErrorCode: 102
251: * }
252: */
253:
254: /**
255: * Updates module's settings - saves them to config.json file or to user settings in db.
256: * @param int $ContactsPerPage Count of contacts per page.
257: * @return boolean
258: */
259: public function UpdateSettings($ContactsPerPage)
260: {
261: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
262:
263: $bResult = false;
264:
265: $oUser = \Aurora\System\Api::getAuthenticatedUser();
266: if ($oUser) {
267: if ($oUser->isNormalOrTenant()) {
268: $oUser->setExtendedProp(self::GetName().'::ContactsPerPage', $ContactsPerPage);
269: return \Aurora\Modules\Core\Module::Decorator()->UpdateUserObject($oUser);
270: }
271: if ($oUser->isAdmin()) {
272: $this->setConfig('ContactsPerPage', $ContactsPerPage);
273: $bResult = $this->saveModuleConfig();
274: }
275: }
276:
277: return $bResult;
278: }
279:
280: /**
281: * @api {post} ?/Api/ Export
282: * @apiName Export
283: * @apiGroup Contacts
284: * @apiDescription Exports specified contacts to a file with specified format.
285: *
286: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
287: * @apiHeaderExample {json} Header-Example:
288: * {
289: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
290: * }
291: *
292: * @apiParam {string=Contacts} Module Module name
293: * @apiParam {string=Export} Method Method name
294: * @apiParam {string} Parameters JSON.stringified object <br>
295: * {<br>
296: * &emsp; **Format** *string* File format that should be used for export.<br>
297: * &emsp; **Filters** *array* Filters for obtaining specified contacts.<br>
298: * &emsp; **GroupUUID** *string* UUID of group that should contain contacts for export.<br>
299: * &emsp; **ContactUUIDs** *array* List of UUIDs of contacts that should be exported.<br>
300: * }
301: *
302: * @apiParamExample {json} Request-Example:
303: * {
304: * Module: 'Contacts',
305: * Method: 'Export',
306: * Parameters: '{ Format: "csv", Filters: [], GroupUUID: "", ContactUUIDs: [] }'
307: * }
308: *
309: * @apiSuccess {object[]} Result Array of response objects.
310: * @apiSuccess {string} Result.Module Module name
311: * @apiSuccess {string} Result.Method Method name
312: * @apiSuccess {mixed} Result.Result Contents of CSV or VCF file in case of success, otherwise **false**.
313: * @apiSuccess {int} [Result.ErrorCode] Error code
314: *
315: * @apiSuccessExample {json} Success response example:
316: * contents of CSV or VCF file
317: *
318: * @apiSuccessExample {json} Error response example:
319: * {
320: * Module: 'Contacts',
321: * Method: 'Export',
322: * Result: false,
323: * ErrorCode: 102
324: * }
325: */
326:
327: /**
328: * Exports specified contacts to a file with specified format.
329: * @param string $Format File format that should be used for export.
330: * @param array $Filters Filters for obtaining specified contacts.
331: * @param string $GroupUUID UUID of group that should contain contacts for export.
332: * @param array $ContactUUIDs List of UUIDs of contacts that should be exported.
333: */
334: public function Export($UserId, $Storage, $Format, Builder $Filters = null, $GroupUUID = '', $ContactUUIDs = [])
335: {
336: Api::CheckAccess($UserId);
337:
338: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
339:
340: $sOutput = '';
341:
342: if (empty($GroupUUID) && $Format === 'vcf') {
343: $aGroups = $this->getManager()->getGroups($UserId);
344: foreach ($aGroups as $oGroup) {
345: $oVCard = new \Sabre\VObject\Component\VCard();
346: \Aurora\Modules\Contacts\Classes\VCard\Helper::UpdateVCardFromGroup($oGroup, $oVCard);
347: foreach ($oGroup->Contacts as $oContact) {
348: if ($oContact) {
349: $sVCardUID = null;
350: if ($oContact->Storage !== 'team') {
351: if (!empty($oContact->{'DavContacts::VCardUID'})) {
352: $sVCardUID = $oContact->{'DavContacts::VCardUID'};
353: }
354: } else {
355: $sVCardUID = $oContact->UUID;
356: }
357: if (isset($sVCardUID)) {
358: $oVCard->add('X-ADDRESSBOOKSERVER-MEMBER', 'urn:uuid:' . $sVCardUID);
359: }
360: }
361: }
362:
363: $sOutput .= $oVCard->serialize();
364: }
365: }
366:
367: $oQuery = ($Filters instanceof Builder) ? $Filters : Models\Contact::query();
368: $oQuery->where(function ($query) use ($UserId, $Storage) {
369: $this->prepareFiltersFromStorage($UserId, $Storage, Enums\SortField::Name, $query);
370: });
371:
372: if (empty($ContactUUIDs) && !empty($GroupUUID)) {
373: $oGroup = Group::firstWhere('UUID', $GroupUUID);
374: if ($oGroup) {
375: $oQuery->whereHas('Groups', function ($oSubQuery) use ($oGroup) {
376: return $oSubQuery->where('Groups.Id', $oGroup->Id);
377: });
378: }
379: }
380: if (count($ContactUUIDs) > 0) {
381: $oQuery->whereIn('UUID', $ContactUUIDs);
382: }
383:
384: $aContacts = $this->getManager()->getContacts(Enums\SortField::Name, \Aurora\System\Enums\SortOrder::ASC, 0, 0, $oQuery);
385:
386: switch ($Format) {
387: case 'csv':
388: $oSync = new Classes\Csv\Sync();
389: $sOutput = $oSync->Export($aContacts);
390: break;
391: case 'vcf':
392: foreach ($aContacts as $oContact) {
393: // $oContact->GroupsContacts = $this->getManager()->getGroupContacts(null, $oContact->UUID);
394:
395: $sOutput .= self::Decorator()->GetContactAsVCF($UserId, $oContact);
396: }
397: break;
398: }
399:
400: if (is_string($sOutput) && !empty($sOutput)) {
401: header('Pragma: public');
402: header('Content-Type: text/csv');
403: header('Content-Disposition: attachment; filename="export.' . $Format . '";');
404: header('Content-Transfer-Encoding: binary');
405: }
406:
407: echo $sOutput;
408: }
409:
410: public function GetContactAsVCF($UserId, $Contact)
411: {
412: Api::CheckAccess($UserId);
413: $oVCard = new \Sabre\VObject\Component\VCard();
414: Classes\VCard\Helper::UpdateVCardFromContact($Contact, $oVCard);
415: return $oVCard->serialize();
416: }
417:
418: /**
419: * @api {post} ?/Api/ GetGroups
420: * @apiName GetGroups
421: * @apiGroup Contacts
422: * @apiDescription Returns all groups for authenticated user.
423: *
424: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
425: * @apiHeaderExample {json} Header-Example:
426: * {
427: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
428: * }
429: *
430: * @apiParam {string=Contacts} Module Module name
431: * @apiParam {string=GetGroups} Method Method name
432: *
433: * @apiParamExample {json} Request-Example:
434: * {
435: * Module: 'Contacts',
436: * Method: 'GetGroups'
437: * }
438: *
439: * @apiSuccess {object[]} Result Array of response objects.
440: * @apiSuccess {string} Result.Module Module name
441: * @apiSuccess {string} Result.Method Method name
442: * @apiSuccess {mixed} Result.Result List of groups in case of success, otherwise **false**.
443: * @apiSuccess {int} [Result.ErrorCode] Error code
444: *
445: * @apiSuccessExample {json} Success response example:
446: * {
447: * Module: 'Contacts',
448: * Method: 'GetGroups',
449: * Result: [{ City: '', Company: '', Contacts: [], Country: '', Email: '', Fax: '', IdUser: 3,
450: * IsOrganization: false, Name: 'group_name', Phone: '', State: '', Street: '', UUID: 'uuid_value',
451: * Web: '', Zip: '' }]
452: * }
453: *
454: * @apiSuccessExample {json} Error response example:
455: * {
456: * Module: 'Contacts',
457: * Method: 'GetGroups',
458: * Result: false,
459: * ErrorCode: 102
460: * }
461: */
462:
463: /**
464: * Returns all groups for authenticated user.
465: * @return array
466: */
467: public function GetGroups($UserId = null)
468: {
469: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
470:
471: Api::CheckAccess($UserId);
472:
473: return $this->getManager()->getGroups($UserId)->toArray();
474: }
475:
476: /**
477: * @api {post} ?/Api/ GetGroup
478: * @apiName GetGroup
479: * @apiGroup Contacts
480: * @apiDescription Returns group with specified UUID.
481: *
482: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
483: * @apiHeaderExample {json} Header-Example:
484: * {
485: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
486: * }
487: *
488: * @apiParam {string=Contacts} Module Module name
489: * @apiParam {string=GetGroup} Method Method name
490: * @apiParam {string} Parameters JSON.stringified object <br>
491: * {<br>
492: * &emsp; **$UUID** *string* UUID of group to return.<br>
493: * }
494: *
495: * @apiParamExample {json} Request-Example:
496: * {
497: * Module: 'Contacts',
498: * Method: 'GetGroup',
499: * Parameters: '{ UUID: "group_uuid" }'
500: * }
501: *
502: * @apiSuccess {object[]} Result Array of response objects.
503: * @apiSuccess {string} Result.Module Module name
504: * @apiSuccess {string} Result.Method Method name
505: * @apiSuccess {mixed} Result.Result Group object in case of success, otherwise **false**.
506: * @apiSuccess {string} Result.Result.City=&quot;&quot;
507: * @apiSuccess {string} Result.Result.Company=&quot;&quot;
508: * @apiSuccess {array} Result.Result.Contacts='[]'
509: * @apiSuccess {string} Result.Result.Country=&quot;&quot;
510: * @apiSuccess {string} Result.Result.Email=&quot;&quot;
511: * @apiSuccess {string} Result.Result.Fax=&quot;&quot;
512: * @apiSuccess {int} Result.Result.IdUser=0
513: * @apiSuccess {bool} Result.Result.IsOrganization=false
514: * @apiSuccess {string} Result.Result.Name=&quot;&quot;
515: * @apiSuccess {string} Result.Result.Phone=&quot;&quot;
516: * @apiSuccess {string} Result.Result.Street=&quot;&quot;
517: * @apiSuccess {string} Result.Result.UUID=&quot;&quot;
518: * @apiSuccess {string} Result.Result.Web=&quot;&quot;
519: * @apiSuccess {string} Result.Result.Zip=&quot;&quot;
520: * @apiSuccess {int} [Result.ErrorCode] Error code
521: *
522: * @apiSuccessExample {json} Success response example:
523: * {
524: * Module: 'Contacts',
525: * Method: 'GetGroup',
526: * Result: { City: '', Company: 'group_company', Contacts: [], Country: '', Email: '', Fax: '',
527: * IdUser: 3, IsOrganization: true, Name: 'group_name', Phone:'', State:'', Street:'',
528: * UUID: 'group_uuid', Web:'', Zip: '' }
529: *
530: * @apiSuccessExample {json} Error response example:
531: * {
532: * Module: 'Contacts',
533: * Method: 'GetGroup',
534: * Result: false,
535: * ErrorCode: 102
536: * }
537: */
538:
539: /**
540: * Returns group with specified UUID.
541: * @param string $UUID UUID of group to return.
542: * @return \Aurora\Modules\Contacts\Classes\Group
543: */
544: public function GetGroup($UserId, $UUID)
545: {
546: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
547:
548: Api::CheckAccess($UserId);
549:
550: return $this->getManager()->getGroup($UUID);
551: }
552:
553: /**
554: * Returns group item identified by its name.
555: * @param string $sName Group name
556: * @return \Aurora\Modules\Contacts\Classes\Group
557: */
558: public function GetGroupByName($Name, $UserId = null)
559: {
560: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
561:
562: if (isset($UserId) && $UserId !== \Aurora\System\Api::getAuthenticatedUserId()) {
563: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
564: } else {
565: $UserId = \Aurora\System\Api::getAuthenticatedUserId();
566: }
567:
568: Api::CheckAccess($UserId);
569:
570: return $this->getManager()->getGroupByName($Name, $UserId);
571: }
572: /**
573: * @api {post} ?/Api/ GetContacts
574: * @apiName GetContacts
575: * @apiGroup Contacts
576: * @apiDescription Returns list of contacts for specified parameters.
577: *
578: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
579: * @apiHeaderExample {json} Header-Example:
580: * {
581: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
582: * }
583: *
584: * @apiParam {string=Contacts} Module Module name
585: * @apiParam {string=GetContacts} Method Method name
586: * @apiParam {string} Parameters JSON.stringified object <br>
587: * {<br>
588: * &emsp; **Offset** *int* Offset of contacts list.<br>
589: * &emsp; **Limit** *int* Limit of result contacts list.<br>
590: * &emsp; **SortField** *int* Name of field order by.<br>
591: * &emsp; **SortOrder** *int* Sorting direction.<br>
592: * &emsp; **Storage** *string* Storage value.<br>
593: * &emsp; **Search** *string* Search string.<br>
594: * &emsp; **GroupUUID** *string* UUID of group that should contain all returned contacts.<br>
595: * &emsp; **Filters** *array* Other conditions for obtaining contacts list.<br>
596: * }
597: *
598: * @apiParamExample {json} Request-Example:
599: * {
600: * Module: 'Contacts',
601: * Method: 'GetContacts',
602: * Parameters: '{ Offset: 0, Limit: 20, SortField: 1, SortOrder: 0, Storage: "personal",
603: * Search: "", GroupUUID: "", Filters: [] }'
604: * }
605: *
606: * @apiSuccess {object[]} Result Array of response objects.
607: * @apiSuccess {string} Result.Module Module name
608: * @apiSuccess {string} Result.Method Method name
609: * @apiSuccess {mixed} Result.Result Object with contacts data in case of success, otherwise **false**.
610: * @apiSuccess {int} Result.Result.ContactCount Count of contacts that are obtained with specified conditions.
611: * @apiSuccess {array} Result.Result.List List of contacts objects.
612: * @apiSuccess {int} [Result.ErrorCode] Error code
613: *
614: * @apiSuccessExample {json} Success response example:
615: * {
616: * Module: 'Contacts',
617: * Method: 'GetContacts',
618: * Result: '{ "ContactCount": 6, "List": [{ "UUID": "contact_uuid", "IdUser": 3, "Name": "",
619: * "Email": "contact@email.com", "Storage": "personal" }] }'
620: * }
621: *
622: * @apiSuccessExample {json} Error response example:
623: * {
624: * Module: 'Contacts',
625: * Method: 'GetContacts',
626: * Result: false,
627: * ErrorCode: 102
628: * }
629: */
630:
631: /**
632: * Returns list of contacts for specified parameters.
633: * @param string $Storage Storage type of contacts.
634: * @param int $Offset Offset of contacts list.
635: * @param int $Limit Limit of result contacts list.
636: * @param int $SortField Name of field order by.
637: * @param int $SortOrder Sorting direction.
638: * @param string $Search Search string.
639: * @param string $GroupUUID UUID of group that should contain all returned contacts.
640: * @param array $Filters Other conditions for obtaining contacts list.
641: * @param bool $WithGroups Indicates whether contact groups should be included in the contact list
642: * @param bool $WithoutTeamContactsDuplicates Do not show a contact from the global address book if the contact with the same email address already exists in personal address book
643: * @return array
644: */
645: public function GetContacts($UserId, $Storage = '', $Offset = 0, $Limit = 20, $SortField = Enums\SortField::Name, $SortOrder = \Aurora\System\Enums\SortOrder::ASC, $Search = '', $GroupUUID = '', Builder $Filters = null, $WithGroups = false, $WithoutTeamContactsDuplicates = false, $Suggestions = false)
646: {
647: // $Storage is used by subscribers to prepare filters.
648: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
649:
650: Api::CheckAccess($UserId);
651:
652: $oQuery = ($Filters instanceof Builder) ? $Filters : Models\Contact::query();
653: $oQuery->where(function ($query) use ($UserId, $Storage, $SortField, $Suggestions) {
654: $this->prepareFiltersFromStorage($UserId, $Storage, $SortField, $query, $Suggestions);
655: });
656:
657: if (!empty($GroupUUID)) {
658: $oGroup = Group::firstWhere('UUID', $GroupUUID);
659: if ($oGroup) {
660: $oQuery = $oQuery->whereHas('Groups', function ($oSubQuery) use ($oGroup) {
661: return $oSubQuery->where('contacts_groups.Id', $oGroup->Id);
662: });
663: }
664: }
665: if (!empty($Search)) {
666: $oQuery = $oQuery->where(function ($query) use ($Search) {
667: $query->where('FullName', 'LIKE', '%'.$Search.'%')
668: ->orWhere('ViewEmail', 'LIKE', '%'.$Search.'%')
669: ->orWhere('PersonalEmail', 'LIKE', '%'.$Search.'%')
670: ->orWhere('BusinessEmail', 'LIKE', '%'.$Search.'%')
671: ->orWhere('OtherEmail', 'LIKE', '%'.$Search.'%')
672: ->orWhere('BusinessCompany', 'LIKE', '%'.$Search.'%');
673: });
674: }
675:
676: $aGroupUsersList = [];
677:
678: if ($WithGroups) {
679: $oUser = \Aurora\System\Api::getAuthenticatedUser();
680: if ($oUser instanceof \Aurora\Modules\Core\Models\User) {
681: $aGroups = $this->getManager()->getGroups($oUser->Id, Group::where('Name', 'LIKE', "%{$Search}%"));
682: if ($aGroups) {
683: foreach ($aGroups as $oGroup) {
684: $aGroupContactsEmails = $oGroup->Contacts->map(function ($oContact) {
685: return $oContact->FullName ? "\"{$oContact->FullName}\" <{$oContact->ViewEmail}>" : $oContact->ViewEmail;
686: })->toArray();
687:
688: $aGroupUsersList[] = [
689: 'UUID' => $oGroup->UUID,
690: 'IdUser' => $oGroup->IdUser,
691: 'FullName' => $oGroup->Name,
692: 'FirstName' => '',
693: 'LastName' => '',
694: 'ViewEmail' => implode(', ', $aGroupContactsEmails),
695: 'Storage' => '',
696: 'Frequency' => 0,
697: 'DateModified' => '',
698: 'IsGroup' => true,
699: ];
700: }
701: }
702: }
703: }
704:
705: $iCount = $this->getManager()->getContactsCount($oQuery);
706: $aContactsCol = $this->getManager()->getContacts($SortField, $SortOrder, $Offset, $Limit, $oQuery);
707: $aContacts = $aContactsCol->toArray();
708:
709: if ($Storage === StorageType::All && $WithoutTeamContactsDuplicates) {
710: $aPersonalContacsCol = $aContactsCol->map(function ($oContact) {
711: if ($oContact->Storage === StorageType::Personal && $oContact->Auto === false) {
712: return $oContact;
713: }
714: });
715:
716: foreach ($aContacts as $key => $aContact) {
717: $sViewEmail = $aContact['ViewEmail'];
718: $sStorage = $aContact['Storage'];
719: if ($sStorage === StorageType::Team && $aPersonalContacsCol->unique()->contains('ViewEmail', $sViewEmail)) {
720: unset($aContacts[$key]);
721: } elseif ($sStorage === StorageType::Personal && $aContact['Auto'] === true) { // is colllected contact
722: foreach ($aContacts as $subKey => $aSubContact) {
723: if ($aSubContact['Storage'] === StorageType::Team && $aSubContact['ViewEmail'] === $sViewEmail) {
724: $aContacts[$subKey]['AgeScore'] = $aContacts[$key]['AgeScore'];
725: unset($aContacts[$key]);
726: }
727: if ($aSubContact['Storage'] === StorageType::Personal && $aSubContact['Auto'] === false && $aSubContact['ViewEmail'] === $sViewEmail) {
728: unset($aContacts[$key]);
729: }
730: }
731: }
732: }
733: }
734: $aList = array_map(function ($aContact) {
735: if ($aContact['Storage'] === StorageType::AddressBook) {
736: $aContact['Storage'] = $aContact['Storage'] . $aContact['AddressBookId'];
737: }
738: return [
739: 'UUID' => $aContact['UUID'],
740: 'IdUser' => $aContact['IdUser'],
741: 'FullName' => $aContact['FullName'],
742: 'FirstName' => isset($aContact['FirstName']) ? $aContact['FirstName'] : '',
743: 'LastName' => isset($aContact['LastName']) ? $aContact['LastName'] : '',
744: 'ViewEmail' => $aContact['ViewEmail'],
745: 'Storage' => $aContact['Storage'],
746: 'Frequency' => $aContact['Frequency'],
747: 'DateModified' => isset($aContact['DateModified']) ? $aContact['DateModified'] : 0,
748: 'ETag' => isset($aContact['ETag']) ? $aContact['ETag'] : '',
749: 'AgeScore' => isset($aContact['AgeScore']) ? (float) $aContact['AgeScore'] : 0
750: ];
751: }, $aContacts);
752:
753: $aList = array_merge($aList, $aGroupUsersList);
754: return [
755: 'ContactCount' => $iCount + count($aGroupUsersList),
756: 'List' => \Aurora\System\Managers\Response::GetResponseObject($aList)
757: ];
758: }
759:
760: protected function _getContactSuggestions($UserId, $Storage, $Limit = 20, $SortField = Enums\SortField::Name, $SortOrder = \Aurora\System\Enums\SortOrder::ASC, $Search = '', $WithGroups = false, $WithoutTeamContactsDuplicates = false)
761: {
762: // $Storage is used by subscribers to prepare filters.
763: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
764:
765: Api::CheckAccess($UserId);
766:
767: $aResult = array(
768: 'ContactCount' => 0,
769: 'List' => []
770: );
771:
772: $aContacts = $this->Decorator()->GetContacts($UserId, $Storage, 0, $Limit, $SortField, $SortOrder, $Search, '', null, $WithGroups, $WithoutTeamContactsDuplicates, true);
773: $aResultList = $aContacts['List'];
774:
775: $contactsColl = collect($aContacts['List']);
776:
777: // $aViewEmails = $contactsColl->whereIn('Storage', [StorageType::Personal, StorageType::AddressBook])/*->where('Auto', false)*/->all();
778:
779: $aResult['List'] = $aResultList;
780: $aResult['ContactCount'] = count($aResultList);
781: return $aResult;
782: }
783:
784: public function GetContactSuggestions($UserId, $Storage, $Limit = 20, $SortField = Enums\SortField::Name, $SortOrder = \Aurora\System\Enums\SortOrder::ASC, $Search = '', $WithGroups = false, $WithoutTeamContactsDuplicates = false, $WithUserGroups = false)
785: {
786: $aResult = $this->_getContactSuggestions($UserId, $Storage, $Limit, $SortField, $SortOrder, $Search, $WithGroups, $WithoutTeamContactsDuplicates);
787:
788: if ($WithUserGroups) {
789: $oUser = CoreModule::Decorator()->GetUserUnchecked($UserId);
790: if ($oUser) {
791: $aGroups = CoreModule::Decorator()->GetGroups($oUser->IdTenant, $Search);
792: foreach ($aGroups['Items'] as $aGroup) {
793: $aGroup['IsGroup'] = true;
794: $aResult['List'][] = $aGroup;
795:
796: $aResult['ContactCount']++;
797: }
798: }
799: }
800:
801: return $aResult;
802: }
803:
804: /*
805: This method used as trigger for subscibers. Check these modules: PersonalContacts, SharedContacts, TeamContacts
806: */
807:
808: public function CheckAccessToObject($User, $Contact, $Access = null)
809: {
810: return true;
811: }
812:
813: /**
814: * @api {post} ?/Api/ GetContact
815: * @apiName GetContact
816: * @apiGroup Contacts
817: * @apiDescription Returns contact with specified UUID.
818: *
819: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
820: * @apiHeaderExample {json} Header-Example:
821: * {
822: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
823: * }
824: *
825: * @apiParam {string=Contacts} Module Module name
826: * @apiParam {string=GetContact} Method Method name
827: * @apiParam {string} Parameters JSON.stringified object <br>
828: * {<br>
829: * &emsp; **UUID** *string* UUID of contact to return.<br>
830: * }
831: *
832: * @apiParamExample {json} Request-Example:
833: * {
834: * Module: 'Contacts',
835: * Method: 'GetContact',
836: * Parameters: '{ UUID: "contact_uuid" }'
837: * }
838: *
839: * @apiSuccess {object[]} Result Array of response objects.
840: * @apiSuccess {string} Result.Module Module name
841: * @apiSuccess {string} Result.Method Method name
842: * @apiSuccess {mixed} Result.Result Object with contact data in case of success, otherwise **false**.
843: * @apiSuccess {int} [Result.ErrorCode] Error code
844: *
845: * @apiSuccessExample {json} Success response example:
846: * {
847: * Module: 'Contacts',
848: * Method: 'GetContact',
849: * Result: '{ "IdUser": 3, "UUID": "group_uuid", "Storage": "personal", "FullName": "", "PrimaryEmail": 0,
850: * "PrimaryPhone": 1, "PrimaryAddress": 0, "FirstName": "", "LastName": "", "NickName": "", "Skype": "",
851: * "Facebook": "", "PersonalEmail": "contact@email.com", "PersonalAddress": "", "PersonalCity": "",
852: * "PersonalState": "", "PersonalZip": "", "PersonalCountry": "", "PersonalWeb": "", "PersonalFax": "",
853: * "PersonalPhone": "", "PersonalMobile": "123-234-234", "BusinessEmail": "", "BusinessCompany": "",
854: * "BusinessAddress": "", "BusinessCity": "", "BusinessState": "", "BusinessZip": "", "BusinessCountry": "",
855: * "BusinessJobTitle": "", "BusinessDepartment": "", "BusinessOffice": "", "BusinessPhone": "",
856: * "BusinessFax": "", "BusinessWeb": "", "OtherEmail": "", "Notes": "", "BirthDay": 0, "BirthMonth": 0,
857: * "BirthYear": 0, "ETag": "", "GroupUUIDs": ["group1_uuid", "group2_uuid"] }'
858: * }
859: *
860: * @apiSuccessExample {json} Error response example:
861: * {
862: * Module: 'Contacts',
863: * Method: 'GetContact',
864: * Result: false,
865: * ErrorCode: 102
866: * }
867: */
868:
869: /**
870: * Returns contact with specified UUID.
871: * @param string $UUID UUID of contact to return.
872: * @return \Aurora\Modules\Contacts\Classes\Contact
873: */
874: public function GetContact($UUID, $UserId = null)
875: {
876: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
877:
878: Api::CheckAccess($UserId);
879:
880: $oUser = \Aurora\Modules\Core\Module::getInstance()->GetUserUnchecked($UserId);
881:
882: $mResult = false;
883:
884: if ($oUser instanceof \Aurora\Modules\Core\Models\User) {
885: $oContact = $this->getManager()->getContact($UUID);
886: if ($oContact->Storage === StorageType::AddressBook) {
887: $oContact->Storage = $oContact->Storage . '-' . $oContact->AddressBookId;
888: }
889: if (self::Decorator()->CheckAccessToObject($oUser, $oContact)) {
890: $mResult = $oContact;
891: }
892: }
893:
894: return $mResult;
895: }
896:
897: /**
898: * @api {post} ?/Api/ GetContactsByEmails
899: * @apiName GetContactsByEmails
900: * @apiGroup Contacts
901: * @apiDescription Returns list of contacts with specified emails.
902: *
903: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
904: * @apiHeaderExample {json} Header-Example:
905: * {
906: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
907: * }
908: *
909: * @apiParam {string=Contacts} Module Module name
910: * @apiParam {string=GetContactsByEmails} Method Method name
911: * @apiParam {string} Parameters JSON.stringified object <br>
912: * {<br>
913: * &emsp; **Emails** *array* List of emails of contacts to return.<br>
914: * }
915: *
916: * @apiParamExample {json} Request-Example:
917: * {
918: * Module: 'Contacts',
919: * Method: 'GetContactsByEmails',
920: * Parameters: '{ Emails: ["contact@email.com"] }'
921: * }
922: *
923: * @apiSuccess {object[]} Result Array of response objects.
924: * @apiSuccess {string} Result.Module Module name
925: * @apiSuccess {string} Result.Method Method name
926: * @apiSuccess {mixed} Result.Result List of contacts in case of success, otherwise **false**.
927: * @apiSuccess {int} [Result.ErrorCode] Error code
928: *
929: * @apiSuccessExample {json} Success response example:
930: * {
931: * Module: 'Contacts',
932: * Method: 'GetContactsByEmails',
933: * Result: [{ "IdUser": 3, "UUID": "group_uuid", "Storage": "personal", "FullName": "", "PrimaryEmail": 0,
934: * "PrimaryPhone": 1, "PrimaryAddress": 0, "FirstName": "", "LastName": "", "NickName": "", "Skype": "",
935: * "Facebook": "", "PersonalEmail": "contact@email.com", "PersonalAddress": "", "PersonalCity": "",
936: * "PersonalState": "", "PersonalZip": "", "PersonalCountry": "", "PersonalWeb": "", "PersonalFax": "",
937: * "PersonalPhone": "", "PersonalMobile": "123-234-234", "BusinessEmail": "", "BusinessCompany": "",
938: * "BusinessAddress": "", "BusinessCity": "", "BusinessState": "", "BusinessZip": "", "BusinessCountry": "",
939: * "BusinessJobTitle": "", "BusinessDepartment": "", "BusinessOffice": "", "BusinessPhone": "",
940: * "BusinessFax": "", "BusinessWeb": "", "OtherEmail": "", "Notes": "", "BirthDay": 0, "BirthMonth": 0,
941: * "BirthYear": 0, "ETag": "", "GroupUUIDs": ["group1_uuid", "group2_uuid"] }]
942: * }
943: *
944: * @apiSuccessExample {json} Error response example:
945: * {
946: * Module: 'Contacts',
947: * Method: 'GetContactsByEmails',
948: * Result: false,
949: * ErrorCode: 102
950: * }
951: */
952:
953: /**
954: * Returns list of contacts with specified emails.
955: * @param string $Storage storage of contacts.
956: * @param array $Emails List of emails of contacts to return.
957: * @return array
958: */
959: public function GetContactsByEmails($UserId, $Storage, $Emails, $Filters = null, $AsArray = true)
960: {
961: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
962: $aContacts = [];
963:
964: Api::CheckAccess($UserId);
965:
966: $oQuery = ($Filters instanceof Builder) ? $Filters : Contact::query();
967: $oQuery->where(function ($query) use ($UserId, $Storage) {
968: $this->prepareFiltersFromStorage($UserId, $Storage, Enums\SortField::Name, $query);
969: });
970: $oQuery = $oQuery->whereIn('ViewEmail', $Emails);
971: if ($Storage !== StorageType::All) {
972: $oQuery->where('Storage', $Storage);
973: }
974:
975: if ($AsArray) {
976: $aContacts = $this->getManager()->getContactsAsArray(Enums\SortField::Name, \Aurora\System\Enums\SortOrder::ASC, 0, 0, $oQuery);
977: } else {
978: $aContacts = $this->getManager()->getContacts(Enums\SortField::Name, \Aurora\System\Enums\SortOrder::ASC, 0, 0, $oQuery);
979: }
980: return $aContacts;
981: }
982:
983: /**
984: * Returns list of contacts with specified uids.
985: * @param int $UserId
986: * @param array $Uids List of uids of contacts to return.
987: * @return array
988: */
989: public function GetContactsByUids($UserId, $Uids)
990: {
991: $aResult = [];
992: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
993:
994: Api::CheckAccess($UserId);
995:
996: $oUser = \Aurora\Modules\Core\Module::getInstance()->GetUserUnchecked($UserId);
997:
998: if (is_array($Uids) && count($Uids) > 0) {
999: $aContacts = $this->getManager()->getContacts(
1000: Enums\SortField::Name,
1001: \Aurora\System\Enums\SortOrder::ASC,
1002: 0,
1003: 0,
1004: Contact::whereIn('UUID', $Uids)
1005: );
1006:
1007: foreach ($aContacts as $oContact) {
1008: if ($oContact instanceof \Aurora\Modules\Contacts\Models\Contact) {
1009: if (self::Decorator()->CheckAccessToObject($oUser, $oContact)) {
1010: // $oContact->GroupsContacts = $this->getManager()->getGroupContacts(null, $oContact->UUID);
1011: $oContact->Storage = ($oContact->Auto) ? 'collected' : $oContact->Storage;
1012: $aResult[] = $oContact;
1013: }
1014: }
1015: }
1016: } else {
1017: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
1018: }
1019:
1020: return $aResult;
1021: }
1022:
1023: /**
1024: * Returns list of contacts with specified emails.
1025: * @param string $Storage storage of contacts.
1026: * @param array $Uids List of emails of contacts to return.
1027: * @return array
1028: */
1029: public function GetContactsInfo($Storage, $UserId = null, Builder $Filters = null)
1030: {
1031: $aResult = [
1032: 'CTag' => $this->GetCTag($UserId, $Storage),
1033: 'Info' => array()
1034: ];
1035: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1036:
1037: Api::CheckAccess($UserId);
1038:
1039: $oQuery = ($Filters instanceof Builder) ? $Filters : Models\Contact::query();
1040: $oQuery->where(function ($query) use ($UserId, $Storage) {
1041: $this->prepareFiltersFromStorage($UserId, $Storage, Enums\SortField::Name, $query);
1042: });
1043:
1044: $aContacts = $oQuery->get(['UUID', 'ETag', 'Auto', 'Storage']);
1045:
1046: foreach ($aContacts as $oContact) {
1047: $aResult['Info'][] = [
1048: 'UUID' => $oContact->UUID,
1049: 'ETag' => $oContact->ETag,
1050: 'Storage' => $oContact->Auto ? 'collected' : $oContact->getStorageWithId()
1051: ];
1052: }
1053:
1054: return $aResult;
1055: }
1056:
1057: /**
1058: * @api {post} ?/Api/ CreateContact
1059: * @apiName CreateContact
1060: * @apiGroup Contacts
1061: * @apiDescription Creates contact with specified parameters.
1062: *
1063: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1064: * @apiHeaderExample {json} Header-Example:
1065: * {
1066: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1067: * }
1068: *
1069: * @apiParam {string=Contacts} Module Module name
1070: * @apiParam {string=CreateContact} Method Method name
1071: * @apiParam {string} Parameters JSON.stringified object <br>
1072: * {<br>
1073: * &emsp; **Contact** *object* Parameters of contact to create.<br>
1074: * }
1075: *
1076: * @apiParamExample {json} Request-Example:
1077: * {
1078: * Module: 'Contacts',
1079: * Method: 'CreateContact',
1080: * Parameters: '{ "Contact": { "UUID": "", "PrimaryEmail": 0, "PrimaryPhone": 0, "PrimaryAddress": 0,
1081: * "FullName": "second", "FirstName": "", "LastName": "", "NickName": "", "Storage": "personal",
1082: * "Skype": "", "Facebook": "", "PersonalEmail": "contact2@email.com", "PersonalAddress": "",
1083: * "PersonalCity": "", "PersonalState": "", "PersonalZip": "", "PersonalCountry": "", "PersonalWeb": "",
1084: * "PersonalFax": "", "PersonalPhone": "", "PersonalMobile": "", "BusinessEmail": "", "BusinessCompany": "",
1085: * "BusinessJobTitle": "", "BusinessDepartment": "", "BusinessOffice": "", "BusinessAddress": "",
1086: * "BusinessCity": "", "BusinessState": "", "BusinessZip": "", "BusinessCountry": "", "BusinessFax": "",
1087: * "BusinessPhone": "", "BusinessWeb": "", "OtherEmail": "", "Notes": "", "ETag": "", "BirthDay": 0,
1088: * "BirthMonth": 0, "BirthYear": 0, "GroupUUIDs": [] } }'
1089: * }
1090: *
1091: * @apiSuccess {object[]} Result Array of response objects.
1092: * @apiSuccess {string} Result.Module Module name
1093: * @apiSuccess {string} Result.Method Method name
1094: * @apiSuccess {mixed} Result.Result New contact UUID in case of success, otherwise **false**.
1095: * @apiSuccess {int} [Result.ErrorCode] Error code
1096: *
1097: * @apiSuccessExample {json} Success response example:
1098: * {
1099: * Module: 'Contacts',
1100: * Method: 'CreateContact',
1101: * Result: 'new_contact_uuid'
1102: * }
1103: *
1104: * @apiSuccessExample {json} Error response example:
1105: * {
1106: * Module: 'Contacts',
1107: * Method: 'CreateContact',
1108: * Result: false,
1109: * ErrorCode: 102
1110: * }
1111: */
1112:
1113: /**
1114: * Creates contact with specified parameters.
1115: * @param array $Contact Parameters of contact to create.
1116: * @param int $UserId Identifier of user that should own a new contact.
1117: * @return bool|string
1118: * @throws \Aurora\System\Exceptions\ApiException
1119: */
1120: public function CreateContact($Contact, $UserId = null)
1121: {
1122: Api::CheckAccess($UserId);
1123:
1124: $oUser = \Aurora\Modules\Core\Module::getInstance()->GetUserUnchecked($UserId);
1125:
1126: $mResult = false;
1127:
1128: if ($oUser instanceof \Aurora\Modules\Core\Models\User) {
1129: $oContact = new Models\Contact();
1130: $oContact->IdUser = $oUser->Id;
1131: $oContact->IdTenant = $oUser->IdTenant;
1132: $oContact->populate($Contact, true);
1133:
1134: if (self::Decorator()->CheckAccessToObject($oUser, $oContact, Access::Write)) {
1135: $oContact->Frequency = $this->getAutocreatedContactFrequencyAndDeleteIt($oUser->Id, $oContact->ViewEmail);
1136: if ($this->getManager()->createContact($oContact)) {
1137: $oContact->addGroups(
1138: isset($Contact['GroupUUIDs']) ? $Contact['GroupUUIDs'] : null,
1139: isset($Contact['GroupNames']) ? $Contact['GroupNames'] : null,
1140: true
1141: );
1142: $mResult = ['UUID' => $oContact->UUID, 'ETag' => $oContact->ETag];
1143: }
1144: }
1145: }
1146:
1147: return $mResult;
1148: }
1149:
1150: /**
1151: * Obtains autocreated contact frequency if user have already created it.
1152: * Removes autocreated contact.
1153: * @param int $UserId User identifier.
1154: * @param string $sViewEmail View email of contact to create
1155: */
1156: private function getAutocreatedContactFrequencyAndDeleteIt($UserId, $sViewEmail)
1157: {
1158: Api::CheckAccess($UserId);
1159:
1160: $iFrequency = 0;
1161: $sStorage = 'personal';
1162: $oQuery = Contact::where([
1163: ['ViewEmail', '=', $sViewEmail],
1164: ['IdUser', '=', $UserId],
1165: ['Auto', '=', true],
1166: ['Storage', '=', $sStorage]
1167: ]);
1168: $oAutocreatedContacts = $this->getManager()->getContacts(
1169: \Aurora\Modules\Contacts\Enums\SortField::Name,
1170: \Aurora\System\Enums\SortOrder::ASC,
1171: 0,
1172: 1,
1173: $oQuery
1174: );
1175: if (is_array($oAutocreatedContacts) && isset($oAutocreatedContacts[0])) {
1176: $iFrequency = $oAutocreatedContacts[0]->Frequency;
1177: $this->getManager()->deleteContacts($UserId, $sStorage, [$oAutocreatedContacts[0]->UUID]);
1178: $this->getManager()->updateCTag($UserId, $sStorage);
1179: }
1180: return $iFrequency;
1181: }
1182:
1183: /**
1184: * @api {post} ?/Api/ UpdateContact
1185: * @apiName UpdateContact
1186: * @apiGroup Contacts
1187: * @apiDescription Updates contact with specified parameters.
1188: *
1189: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1190: * @apiHeaderExample {json} Header-Example:
1191: * {
1192: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1193: * }
1194: *
1195: * @apiParam {string=Contacts} Module Module name
1196: * @apiParam {string=UpdateContact} Method Method name
1197: * @apiParam {string} Parameters JSON.stringified object <br>
1198: * {<br>
1199: * &emsp; **Contact** *array* Parameters of contact to update.<br>
1200: * }
1201: *
1202: * @apiParamExample {json} Request-Example:
1203: * {
1204: * Module: 'Contacts',
1205: * Method: 'UpdateContact',
1206: * Parameters: '{ "Contact": { "UUID": "contact2_uuid", "PrimaryEmail": 0, "PrimaryPhone": 0,
1207: * "PrimaryAddress": 0, "FullName": "contact2", "FirstName": "", "LastName": "", "NickName": "",
1208: * "Storage": "personal", "Skype": "", "Facebook": "", "PersonalEmail": "contact2@email.com",
1209: * "PersonalAddress": "", "PersonalCity": "", "PersonalState": "", "PersonalZip": "", "PersonalCountry": "",
1210: * "PersonalWeb": "", "PersonalFax": "", "PersonalPhone": "", "PersonalMobile": "", "BusinessEmail": "",
1211: * "BusinessCompany": "", "BusinessJobTitle": "", "BusinessDepartment": "", "BusinessOffice": "",
1212: * "BusinessAddress": "", "BusinessCity": "", "BusinessState": "", "BusinessZip": "", "BusinessCountry": "",
1213: * "BusinessFax": "", "BusinessPhone": "", "BusinessWeb": "", "OtherEmail": "", "Notes": "", "ETag": "",
1214: * "BirthDay": 0, "BirthMonth": 0, "BirthYear": 0, "GroupUUIDs": [] } }'
1215: * }
1216: *
1217: * @apiSuccess {object[]} Result Array of response objects.
1218: * @apiSuccess {string} Result.Module Module name
1219: * @apiSuccess {string} Result.Method Method name
1220: * @apiSuccess {bool} Result.Result Indicates if contact was updated successfully.
1221: * @apiSuccess {int} [Result.ErrorCode] Error code
1222: *
1223: * @apiSuccessExample {json} Success response example:
1224: * {
1225: * Module: 'Contacts',
1226: * Method: 'UpdateContact',
1227: * Result: true
1228: * }
1229: *
1230: * @apiSuccessExample {json} Error response example:
1231: * {
1232: * Module: 'Contacts',
1233: * Method: 'UpdateContact',
1234: * Result: false,
1235: * ErrorCode: 102
1236: * }
1237: */
1238:
1239: /**
1240: * Updates contact with specified parameters.
1241: * @param array $Contact Parameters of contact to update.
1242: * @return bool
1243: */
1244: public function UpdateContact($UserId, $Contact)
1245: {
1246: Api::CheckAccess($UserId);
1247:
1248: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1249:
1250: $oContact = $this->getManager()->getContact($Contact['UUID']);
1251: if ($oContact) {
1252: $oContact->populate($Contact, true);
1253: if ($this->UpdateContactObject($oContact)) {
1254: $oContact->addGroups(
1255: isset($Contact['GroupUUIDs']) ? $Contact['GroupUUIDs'] : null,
1256: isset($Contact['GroupNames']) ? $Contact['GroupNames'] : null,
1257: true
1258: );
1259: return [
1260: 'UUID' => $oContact->UUID,
1261: 'ETag' => $oContact->ETag
1262: ];
1263: } else {
1264: return false;
1265: }
1266: }
1267:
1268: return false;
1269: }
1270:
1271: public function UpdateContactObject($Contact)
1272: {
1273: $mResult = false;
1274:
1275: $oUser = \Aurora\System\Api::getAuthenticatedUser();
1276: $aStorageParts = \explode('-', $Contact->Storage);
1277: if (isset($aStorageParts[0], $aStorageParts[1]) && $aStorageParts[0] === StorageType::AddressBook) {
1278: $Contact->AddressBookId = (int) $aStorageParts[1];
1279: $Contact->Storage = StorageType::AddressBook;
1280: }
1281: if (self::Decorator()->CheckAccessToObject($oUser, $Contact, Enums\Access::Write)) {
1282: $mResult = $this->getManager()->updateContact($Contact);
1283: }
1284:
1285: return $mResult;
1286: }
1287:
1288:
1289: /**
1290: * @api {post} ?/Api/ DeleteContacts
1291: * @apiName DeleteContacts
1292: * @apiGroup Contacts
1293: * @apiDescription Deletes contacts with specified UUIDs.
1294: *
1295: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1296: * @apiHeaderExample {json} Header-Example:
1297: * {
1298: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1299: * }
1300: *
1301: * @apiParam {string=Contacts} Module Module name
1302: * @apiParam {string=DeleteContacts} Method Method name
1303: * @apiParam {string} Parameters JSON.stringified object <br>
1304: * {<br>
1305: * &emsp; **UUIDs** *array* Array of strings - UUIDs of contacts to delete.<br>
1306: * }
1307: *
1308: * @apiParamExample {json} Request-Example:
1309: * {
1310: * Module: 'Contacts',
1311: * Method: 'DeleteContacts',
1312: * Parameters: '{ UUIDs: ["uuid1", "uuid"] }'
1313: * }
1314: *
1315: * @apiSuccess {object[]} Result Array of response objects.
1316: * @apiSuccess {string} Result.Module Module name
1317: * @apiSuccess {string} Result.Method Method name
1318: * @apiSuccess {bool} Result.Result Indicates if contacts were deleted successfully.
1319: * @apiSuccess {int} [Result.ErrorCode] Error code
1320: *
1321: * @apiSuccessExample {json} Success response example:
1322: * {
1323: * Module: 'Contacts',
1324: * Method: 'DeleteContacts',
1325: * Result: true
1326: * }
1327: *
1328: * @apiSuccessExample {json} Error response example:
1329: * {
1330: * Module: 'Contacts',
1331: * Method: 'DeleteContacts',
1332: * Result: false,
1333: * ErrorCode: 102
1334: * }
1335: */
1336:
1337: /**
1338: * Deletes contacts with specified UUIDs.
1339: * @param array $UUIDs Array of strings - UUIDs of contacts to delete.
1340: * @return bool
1341: */
1342: public function DeleteContacts($UserId, $Storage, $UUIDs)
1343: {
1344: $mResult = false;
1345: Api::CheckAccess($UserId);
1346: $oUser = Api::getUserById($UserId);
1347:
1348: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1349:
1350: $sStorage = $Storage;
1351: $aStorageParts = \explode('-', $sStorage);
1352: if (isset($aStorageParts[0]) && $aStorageParts[0] === StorageType::AddressBook) {
1353: $sStorage = StorageType::AddressBook;
1354: }
1355:
1356: $aContacts = Contact::whereIn('UUID', $UUIDs)->get();
1357: $bCheck = true;
1358: foreach ($aContacts as $oContact) {
1359: if (!self::Decorator()->CheckAccessToObject($oUser, $oContact, Enums\Access::Write)) {
1360: $bCheck = false;
1361: break;
1362: }
1363: }
1364:
1365: if ($bCheck && $this->getManager()->deleteContacts($UserId, $sStorage, $UUIDs)) {
1366: $this->getManager()->updateCTag($UserId, $Storage);
1367: $mResult = true;
1368: }
1369:
1370: return $mResult;
1371: }
1372:
1373: /**
1374: * @api {post} ?/Api/ CreateGroup
1375: * @apiName CreateGroup
1376: * @apiGroup Contacts
1377: * @apiDescription Creates group with specified parameters.
1378: *
1379: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1380: * @apiHeaderExample {json} Header-Example:
1381: * {
1382: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1383: * }
1384: *
1385: * @apiParam {string=Contacts} Module Module name
1386: * @apiParam {string=CreateGroup} Method Method name
1387: * @apiParam {string} Parameters JSON.stringified object <br>
1388: * {<br>
1389: * &emsp; **Group** *object* Parameters of group to create.<br>
1390: * }
1391: *
1392: * @apiParamExample {json} Request-Example:
1393: * {
1394: * Module: 'Contacts',
1395: * Method: 'CreateGroup',
1396: * Parameters: '{ "Group": { "UUID": "", "Name": "new_group_name", "IsOrganization": "0", "Email": "",
1397: * "Country": "", "City": "", "Company": "", "Fax": "", "Phone": "", "State": "", "Street": "",
1398: * "Web": "", "Zip": "", "Contacts": [] } }'
1399: * }
1400: *
1401: * @apiSuccess {object[]} Result Array of response objects.
1402: * @apiSuccess {string} Result.Module Module name
1403: * @apiSuccess {string} Result.Method Method name
1404: * @apiSuccess {mixed} Result.Result New group UUID in case of success, otherwise **false**.
1405: * @apiSuccess {int} [Result.ErrorCode] Error code
1406: *
1407: * @apiSuccessExample {json} Success response example:
1408: * {
1409: * Module: 'Contacts',
1410: * Method: 'CreateGroup',
1411: * Result: 'new_group_uuid'
1412: * }
1413: *
1414: * @apiSuccessExample {json} Error response example:
1415: * {
1416: * Module: 'Contacts',
1417: * Method: 'CreateGroup',
1418: * Result: false,
1419: * ErrorCode: 102
1420: * }
1421: */
1422:
1423: /**
1424: * Creates group with specified parameters.
1425: * @param array $Group Parameters of group to create.
1426: * @return string|bool
1427: */
1428: public function CreateGroup($Group, $UserId = null)
1429: {
1430: Api::CheckAccess($UserId);
1431:
1432: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1433:
1434: if (is_array($Group)) {
1435: \Aurora\System\Validator::validate($Group, [
1436: 'Name' => 'required'
1437: ]);
1438:
1439: $oGroup = new Models\Group();
1440: $oGroup->IdUser = (int) $UserId;
1441:
1442: $oGroup->populate($Group);
1443:
1444: $this->getManager()->createGroup($oGroup);
1445: $this->getManager()->updateCTag($UserId, 'personal');
1446:
1447: if (isset($Group['Contacts']) && is_array($Group['Contacts'])) {
1448: $oGroup->Contacts()->sync(
1449: Models\Contact::whereIn('UUID', $Group['Contacts'])->get()
1450: ->map(function ($oContact) {
1451: return $oContact->Id;
1452: })
1453: );
1454: }
1455:
1456: return $oGroup ? $oGroup->UUID : false;
1457: } else {
1458: return false;
1459: }
1460: }
1461:
1462: /**
1463: * @api {post} ?/Api/ UpdateGroup
1464: * @apiName UpdateGroup
1465: * @apiGroup Contacts
1466: * @apiDescription Updates group with specified parameters.
1467: *
1468: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1469: * @apiHeaderExample {json} Header-Example:
1470: * {
1471: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1472: * }
1473: *
1474: * @apiParam {string=Contacts} Module Module name
1475: * @apiParam {string=UpdateGroup} Method Method name
1476: * @apiParam {string} Parameters JSON.stringified object <br>
1477: * {<br>
1478: * &emsp; **Group** *object* Parameters of group to update.<br>
1479: * }
1480: *
1481: * @apiParamExample {json} Request-Example:
1482: * {
1483: * Module: 'Contacts',
1484: * Method: 'UpdateGroup',
1485: * Parameters: '{ "Group": { "UUID": "group_uuid", "Name": "group_name", "IsOrganization": "0",
1486: * "Email": "", "Country": "", "City": "", "Company": "", "Fax": "", "Phone": "", "State": "",
1487: * "Street": "", "Web": "", "Zip": "", "Contacts": [] } }'
1488: * }
1489: *
1490: * @apiSuccess {object[]} Result Array of response objects.
1491: * @apiSuccess {string} Result.Module Module name
1492: * @apiSuccess {string} Result.Method Method name
1493: * @apiSuccess {bool} Result.Result Indicates if group was updated successfully.
1494: * @apiSuccess {int} [Result.ErrorCode] Error code
1495: *
1496: * @apiSuccessExample {json} Success response example:
1497: * {
1498: * Module: 'Contacts',
1499: * Method: 'UpdateGroup',
1500: * Result: true
1501: * }
1502: *
1503: * @apiSuccessExample {json} Error response example:
1504: * {
1505: * Module: 'Contacts',
1506: * Method: 'UpdateGroup',
1507: * Result: false,
1508: * ErrorCode: 102
1509: * }
1510: */
1511:
1512: /**
1513: * Updates group with specified parameters.
1514: * @param array $Group Parameters of group to update.
1515: * @return boolean
1516: */
1517: public function UpdateGroup($UserId, $Group)
1518: {
1519: Api::CheckAccess($UserId);
1520:
1521: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1522:
1523: $oGroup = $this->getManager()->getGroup($Group['UUID']);
1524: if ($oGroup) {
1525: $oGroup->populate($Group);
1526:
1527: if (isset($Group['Contacts']) && is_array($Group['Contacts'])) {
1528: $oGroup->Contacts()->sync(
1529: Models\Contact::whereIn('UUID', $Group['Contacts'])->get()
1530: ->map(function ($oContact) {
1531: return $oContact->Id;
1532: })
1533: );
1534: }
1535:
1536: return $oGroup->save();
1537: }
1538:
1539: return false;
1540: }
1541:
1542: /**
1543: * @api {post} ?/Api/ DeleteGroup
1544: * @apiName DeleteGroup
1545: * @apiGroup Contacts
1546: * @apiDescription Deletes group with specified UUID.
1547: *
1548: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1549: * @apiHeaderExample {json} Header-Example:
1550: * {
1551: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1552: * }
1553: *
1554: * @apiParam {string=Contacts} Module Module name
1555: * @apiParam {string=DeleteGroup} Method Method name
1556: * @apiParam {string} Parameters JSON.stringified object <br>
1557: * {<br>
1558: * &emsp; **UUID** *string* UUID of group to delete.<br>
1559: * }
1560: *
1561: * @apiParamExample {json} Request-Example:
1562: * {
1563: * Module: 'Contacts',
1564: * Method: 'DeleteGroup',
1565: * Parameters: '{ UUID: "group_uuid" }'
1566: * }
1567: *
1568: * @apiSuccess {object[]} Result Array of response objects.
1569: * @apiSuccess {string} Result.Module Module name
1570: * @apiSuccess {string} Result.Method Method name
1571: * @apiSuccess {bool} Result.Result Indicates if group was deleted successfully.
1572: * @apiSuccess {int} [Result.ErrorCode] Error code
1573: *
1574: * @apiSuccessExample {json} Success response example:
1575: * {
1576: * Module: 'Contacts',
1577: * Method: 'DeleteGroup',
1578: * Result: true
1579: * }
1580: *
1581: * @apiSuccessExample {json} Error response example:
1582: * {
1583: * Module: 'Contacts',
1584: * Method: 'DeleteGroup',
1585: * Result: false,
1586: * ErrorCode: 102
1587: * }
1588: */
1589:
1590: /**
1591: * Deletes group with specified UUID.
1592: * @param string $UUID UUID of group to delete.
1593: * @return bool
1594: */
1595: public function DeleteGroup($UserId, $UUID)
1596: {
1597: Api::CheckAccess($UserId);
1598:
1599: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1600: $this->getManager()->updateCTag($UserId, 'personal');
1601: return $this->getManager()->deleteGroups([$UUID]);
1602: }
1603:
1604: /**
1605: * @api {post} ?/Api/ AddContactsToGroup
1606: * @apiName AddContactsToGroup
1607: * @apiGroup Contacts
1608: * @apiDescription Adds specified contacts to specified group.
1609: *
1610: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1611: * @apiHeaderExample {json} Header-Example:
1612: * {
1613: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1614: * }
1615: *
1616: * @apiParam {string=Contacts} Module Module name
1617: * @apiParam {string=AddContactsToGroup} Method Method name
1618: * @apiParam {string} Parameters JSON.stringified object <br>
1619: * {<br>
1620: * &emsp; **GroupUUID** *string* UUID of group.<br>
1621: * &emsp; **ContactUUIDs** *array* Array of strings - UUIDs of contacts to add to group.<br>
1622: * }
1623: *
1624: * @apiParamExample {json} Request-Example:
1625: * {
1626: * Module: 'Contacts',
1627: * Method: 'AddContactsToGroup',
1628: * Parameters: '{ GroupUUID: "group_uuid", ContactUUIDs: ["contact1_uuid", "contact2_uuid"] }'
1629: * }
1630: *
1631: * @apiSuccess {object[]} Result Array of response objects.
1632: * @apiSuccess {string} Result.Module Module name
1633: * @apiSuccess {string} Result.Method Method name
1634: * @apiSuccess {bool} Result.Result Indicates if contacts were successfully added to group.
1635: * @apiSuccess {int} [Result.ErrorCode] Error code
1636: *
1637: * @apiSuccessExample {json} Success response example:
1638: * {
1639: * Module: 'Contacts',
1640: * Method: 'AddContactsToGroup',
1641: * Result: true
1642: * }
1643: *
1644: * @apiSuccessExample {json} Error response example:
1645: * {
1646: * Module: 'Contacts',
1647: * Method: 'AddContactsToGroup',
1648: * Result: false,
1649: * ErrorCode: 102
1650: * }
1651: */
1652:
1653: /**
1654: * Adds specified contacts to specified group.
1655: * @param string $GroupUUID UUID of group.
1656: * @param array $ContactUUIDs Array of strings - UUIDs of contacts to add to group.
1657: * @return boolean
1658: */
1659: public function AddContactsToGroup($UserId, $GroupUUID, $ContactUUIDs)
1660: {
1661: Api::CheckAccess($UserId);
1662:
1663: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1664:
1665: if (is_array($ContactUUIDs) && !empty($ContactUUIDs)) {
1666: return $this->getManager()->addContactsToGroup($GroupUUID, $ContactUUIDs);
1667: }
1668:
1669: return true;
1670: }
1671:
1672: /**
1673: * @api {post} ?/Api/ RemoveContactsFromGroup
1674: * @apiName RemoveContactsFromGroup
1675: * @apiGroup Contacts
1676: * @apiDescription Removes specified contacts from specified group.
1677: *
1678: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1679: * @apiHeaderExample {json} Header-Example:
1680: * {
1681: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1682: * }
1683: *
1684: * @apiParam {string=Contacts} Module Module name
1685: * @apiParam {string=RemoveContactsFromGroup} Method Method name
1686: * @apiParam {string} Parameters JSON.stringified object <br>
1687: * {<br>
1688: * &emsp; **GroupUUID** *string* UUID of group.<br>
1689: * &emsp; **ContactUUIDs** *array* Array of strings - UUIDs of contacts to remove from group.<br>
1690: * }
1691: *
1692: * @apiParamExample {json} Request-Example:
1693: * {
1694: * Module: 'Contacts',
1695: * Method: 'RemoveContactsFromGroup',
1696: * Parameters: '{ GroupUUID: "group_uuid", ContactUUIDs: ["contact1_uuid", "contact2_uuid"] }'
1697: * }
1698: *
1699: * @apiSuccess {object[]} Result Array of response objects.
1700: * @apiSuccess {string} Result.Module Module name
1701: * @apiSuccess {string} Result.Method Method name
1702: * @apiSuccess {bool} Result.Result Indicates if contacts were successfully removed from group.
1703: * @apiSuccess {int} [Result.ErrorCode] Error code
1704: *
1705: * @apiSuccessExample {json} Success response example:
1706: * {
1707: * Module: 'Contacts',
1708: * Method: 'RemoveContactsFromGroup',
1709: * Result: true
1710: * }
1711: *
1712: * @apiSuccessExample {json} Error response example:
1713: * {
1714: * Module: 'Contacts',
1715: * Method: 'RemoveContactsFromGroup',
1716: * Result: false,
1717: * ErrorCode: 102
1718: * }
1719: */
1720:
1721: /**
1722: * Removes specified contacts from specified group.
1723: * @param string $GroupUUID UUID of group.
1724: * @param array $ContactUUIDs Array of strings - UUIDs of contacts to remove from group.
1725: * @return boolean
1726: */
1727: public function RemoveContactsFromGroup($UserId, $GroupUUID, $ContactUUIDs)
1728: {
1729: Api::CheckAccess($UserId);
1730:
1731: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1732:
1733: if (is_array($ContactUUIDs) && !empty($ContactUUIDs)) {
1734: return $this->getManager()->removeContactsFromGroup($GroupUUID, $ContactUUIDs);
1735: }
1736:
1737: return true;
1738: }
1739:
1740: /**
1741: * @api {post} ?/Api/ Import
1742: * @apiName Import
1743: * @apiGroup Contacts
1744: * @apiDescription Imports contacts from file with specified format.
1745: *
1746: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1747: * @apiHeaderExample {json} Header-Example:
1748: * {
1749: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1750: * }
1751: *
1752: * @apiParam {string=Contacts} Module Module name
1753: * @apiParam {string=Import} Method Method name
1754: * @apiParam {string} Parameters JSON.stringified object <br>
1755: * {<br>
1756: * &emsp; **UploadData** *array* Array of uploaded file data.<br>
1757: * &emsp; **Storage** *string* Storage name.<br>
1758: * &emsp; **GroupUUID** *array* Group UUID.<br>
1759: * }
1760: *
1761: * @apiParamExample {json} Request-Example:
1762: * {
1763: * Module: 'Contacts',
1764: * Method: 'Import',
1765: * Parameters: '{ "UploadData": { "tmp_name": "tmp_name_value", "name": "name_value" },
1766: * "Storage": "personal", "GroupUUID": "" }'
1767: * }
1768: *
1769: * @apiSuccess {object[]} Result Array of response objects.
1770: * @apiSuccess {string} Result.Module Module name
1771: * @apiSuccess {string} Result.Method Method name
1772: * @apiSuccess {mixed} Result.Result Object with counts of imported and parsed contacts in case of success, otherwise **false**.
1773: * @apiSuccess {int} [Result.ErrorCode] Error code
1774: *
1775: * @apiSuccessExample {json} Success response example:
1776: * {
1777: * Module: 'Contacts',
1778: * Method: 'Import',
1779: * Result: { "ImportedCount" : 2, "ParsedCount": 3}
1780: * }
1781: *
1782: * @apiSuccessExample {json} Error response example:
1783: * {
1784: * Module: 'Contacts',
1785: * Method: 'Import',
1786: * Result: false,
1787: * ErrorCode: 102
1788: * }
1789: */
1790:
1791: /**
1792: * Imports contacts from file with specified format.
1793: * @param array $UploadData Array of uploaded file data.
1794: * @param array $GroupUUID Group UUID.
1795: * @return array
1796: * @throws \Aurora\System\Exceptions\ApiException
1797: */
1798: public function Import($UserId, $UploadData, $GroupUUID, $Storage = null)
1799: {
1800: Api::CheckAccess($UserId);
1801:
1802: $oUser = \Aurora\Modules\Core\Module::getInstance()->GetUserUnchecked($UserId);
1803:
1804: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1805:
1806: $aResponse = array(
1807: 'ImportedCount' => 0,
1808: 'ParsedCount' => 0
1809: );
1810:
1811: if (is_array($UploadData)) {
1812: $oApiFileCacheManager = new \Aurora\System\Managers\Filecache();
1813: $sTempFileName = 'import-post-' . md5($UploadData['name'] . $UploadData['tmp_name']);
1814: if ($oApiFileCacheManager->moveUploadedFile($oUser->UUID, $sTempFileName, $UploadData['tmp_name'], '', self::GetName())) {
1815: $sTempFilePath = $oApiFileCacheManager->generateFullFilePath($oUser->UUID, $sTempFileName, '', self::GetName());
1816:
1817: $aImportResult = array();
1818:
1819: $sFileExtension = strtolower(\Aurora\System\Utils::GetFileExtension($UploadData['name']));
1820: switch ($sFileExtension) {
1821: case 'csv':
1822: $oSync = new Classes\Csv\Sync();
1823: $aImportResult = $oSync->Import($oUser->Id, $sTempFilePath, $GroupUUID, $Storage);
1824: break;
1825: case 'vcf':
1826: $aImportResult = $this->importVcf($oUser->Id, $sTempFilePath, $Storage);
1827: break;
1828: }
1829:
1830: if (is_array($aImportResult) && isset($aImportResult['ImportedCount']) && isset($aImportResult['ParsedCount'])) {
1831: $aResponse['ImportedCount'] = $aImportResult['ImportedCount'];
1832: $aResponse['ParsedCount'] = $aImportResult['ParsedCount'];
1833: } else {
1834: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::IncorrectFileExtension);
1835: }
1836:
1837: $oApiFileCacheManager->clear($oUser->UUID, $sTempFileName, '', self::GetName());
1838: } else {
1839: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::UnknownError);
1840: }
1841: } else {
1842: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::UnknownError);
1843: }
1844:
1845: return $aResponse;
1846: }
1847:
1848: public function GetGroupEvents($UserId, $UUID)
1849: {
1850: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1851:
1852: Api::CheckAccess($UserId);
1853:
1854: $aResult = [];
1855: $aEvents = $this->_getGroupEvents($UUID);
1856: if (is_array($aEvents) && 0 < count($aEvents)) {
1857: foreach ($aEvents as $oEvent) {
1858: $oCalendarModule = Api::GetModule('Calendar');
1859: if ($oCalendarModule) {
1860: $aResult[] = $oCalendarModule->GetBaseEvent($UserId, $oEvent->CalendarUUID, $oEvent->EventUUID);
1861: }
1862: }
1863: }
1864:
1865: return $aResult;
1866: }
1867:
1868: public function UpdateSharedContacts($UserId, $UUIDs)
1869: {
1870: Api::CheckAccess($UserId);
1871:
1872: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1873: return true;
1874: }
1875:
1876: public function AddContactsFromFile($UserId, $File)
1877: {
1878: Api::CheckAccess($UserId);
1879:
1880: $oUser = \Aurora\Modules\Core\Module::getInstance()->GetUserUnchecked($UserId);
1881:
1882: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1883:
1884: if (empty($File)) {
1885: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
1886: }
1887:
1888: $oApiFileCache = new \Aurora\System\Managers\Filecache();
1889:
1890: $sTempFilePath = $oApiFileCache->generateFullFilePath($oUser->UUID, $File); // Temp files with access from another module should be stored in System folder
1891: $aImportResult = $this->importVcf($oUser->Id, $sTempFilePath);
1892:
1893: return $aImportResult;
1894: }
1895:
1896: public function GetCTag($UserId, $Storage)
1897: {
1898: Api::CheckAccess($UserId);
1899:
1900: $oUser = \Aurora\Modules\Core\Module::getInstance()->GetUserUnchecked($UserId);
1901:
1902: $iResult = 0;
1903: if ($oUser instanceof \Aurora\Modules\Core\Models\User) {
1904: $aStorageParts = \explode('-', $Storage);
1905: $iUserId = $Storage === StorageType::Personal || $Storage === StorageType::Collected || (isset($aStorageParts[0]) && $aStorageParts[0] === StorageType::AddressBook) ? $oUser->Id : $oUser->IdTenant;
1906:
1907: $oCTag = $this->getManager()->getCTag($iUserId, $Storage);
1908: if ($oCTag instanceof Models\CTag) {
1909: $iResult = $oCTag->CTag;
1910: }
1911: }
1912:
1913: return $iResult;
1914: }
1915:
1916: /**
1917: *
1918: * @param type $UserId
1919: * @param type $UUID
1920: * @param type $Storage
1921: * @param type $FileName
1922: */
1923: public function SaveContactAsTempFile($UserId, $UUID, $FileName)
1924: {
1925: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1926:
1927: Api::CheckAccess($UserId);
1928:
1929: $mResult = false;
1930:
1931: $oContact = self::Decorator()->GetContact($UUID, $UserId);
1932: if ($oContact) {
1933: $oVCard = new \Sabre\VObject\Component\VCard();
1934: \Aurora\Modules\Contacts\Classes\VCard\Helper::UpdateVCardFromContact($oContact, $oVCard);
1935: $sVCardData = $oVCard->serialize();
1936: if ($sVCardData) {
1937: $sUUID = \Aurora\System\Api::getUserUUIDById($UserId);
1938: $sTempName = md5($sUUID.$UUID);
1939: $oApiFileCache = new \Aurora\System\Managers\Filecache();
1940:
1941: $oApiFileCache->put($sUUID, $sTempName, $sVCardData);
1942: if ($oApiFileCache->isFileExists($sUUID, $sTempName)) {
1943: $mResult = \Aurora\System\Utils::GetClientFileResponse(
1944: null,
1945: $UserId,
1946: $FileName,
1947: $sTempName,
1948: $oApiFileCache->fileSize($sUUID, $sTempName)
1949: );
1950: }
1951: }
1952: }
1953:
1954: return $mResult;
1955: }
1956: /***** public functions might be called with web API *****/
1957:
1958: /***** private functions *****/
1959: private function importVcf($iUserId, $sTempFilePath, $sStorage = null)
1960: {
1961: $aImportResult = array(
1962: 'ParsedCount' => 0,
1963: 'ImportedCount' => 0,
1964: 'ImportedUids' => []
1965: );
1966: // You can either pass a readable stream, or a string.
1967: $oHandler = fopen($sTempFilePath, 'r');
1968: $oSplitter = new \Sabre\VObject\Splitter\VCard($oHandler, \Sabre\VObject\Reader::OPTION_IGNORE_INVALID_LINES);
1969: $oContactsDecorator = Module::Decorator();
1970: $oApiContactsManager = $oContactsDecorator ? $oContactsDecorator->GetApiContactsManager() : null;
1971: if ($oApiContactsManager) {
1972: while ($oVCard = $oSplitter->getNext()) {
1973: set_time_limit(30);
1974:
1975: $aContactData = Classes\VCard\Helper::GetContactDataFromVcard($oVCard);
1976: $oContact = isset($aContactData['UUID']) ? $oApiContactsManager->getContact($aContactData['UUID']) : null;
1977: $aImportResult['ParsedCount']++;
1978: if (!isset($oContact) || empty($oContact)) {
1979: if (isset($sStorage)) {
1980: $aContactData['Storage'] = $sStorage;
1981: // $aStorageParts = \explode('-', $sStorage);
1982: // if (count($aStorageParts) === 2 && $aStorageParts[0] === StorageType::AddressBook) {
1983: // $aContactData['Storage'] = StorageType::AddressBook;
1984: // $aContactData['AddressBookId'] = $aStorageParts[1];
1985: // }
1986: }
1987: $CreatedContactData = $oContactsDecorator->CreateContact($aContactData, $iUserId);
1988: if ($CreatedContactData) {
1989: $aImportResult['ImportedCount']++;
1990: $aImportResult['ImportedUids'][] = $CreatedContactData['UUID'];
1991: }
1992: }
1993: }
1994: }
1995: return $aImportResult;
1996: }
1997:
1998: private function prepareFiltersFromStorage($UserId, $Storage = '', $SortField = Enums\SortField::Name, $oQuery = null, $bSuggesions = false)
1999: {
2000: $aArgs = [
2001: 'UserId' => $UserId,
2002: 'Storage' => $Storage,
2003: 'SortField' => $SortField,
2004: 'Suggestions' => $bSuggesions,
2005: 'IsValid' => false,
2006: ];
2007:
2008: $this->broadcastEvent('PrepareFiltersFromStorage', $aArgs, $oQuery);
2009: if (!$aArgs['IsValid']) {
2010: throw new ApiException(Notifications::InvalidInputParameter, null, 'Invalid Storage parameter value');
2011: }
2012: return $oQuery;
2013: }
2014:
2015: public function onAfterUseEmails($Args, &$Result)
2016: {
2017: $aAddresses = $Args['Emails'];
2018: $iUserId = $Args['IdUser'];
2019: foreach ($aAddresses as $sEmail => $sName) {
2020: $oContact = $this->getManager()->getContactByEmail($iUserId, $sEmail);
2021: if ($oContact) {
2022: if ($oContact->Frequency !== -1) {
2023: $oContact->Frequency = $oContact->Frequency + 1;
2024: $this->getManager()->updateContact($oContact);
2025: }
2026: } else {
2027: self::Decorator()->CreateContact([
2028: 'FullName' => $sName,
2029: 'PersonalEmail' => $sEmail,
2030: 'Auto' => true,
2031: ], $iUserId);
2032: }
2033: $this->getManager()->updateCTag($iUserId, 'collected');
2034: }
2035: }
2036:
2037: public function onGetBodyStructureParts($aParts, &$aResultParts)
2038: {
2039: foreach ($aParts as $oPart) {
2040: if ($oPart instanceof \MailSo\Imap\BodyStructure &&
2041: ($oPart->ContentType() === 'text/vcard' || $oPart->ContentType() === 'text/x-vcard')) {
2042: $aResultParts[] = $oPart;
2043: break;
2044: }
2045: }
2046: }
2047:
2048: public function onAfterDeleteUser(&$aArgs, &$mResult)
2049: {
2050: $this->getManager()->deleteGroupsByUserId($aArgs['UserId']);
2051: $this->getManager()->deleteCTagsByUserId($aArgs['UserId']);
2052: $this->getManager()->deleteContactsByUserId($aArgs['UserId']);
2053: AddressBook::where('UserId', $aArgs['UserId'])->delete();
2054: }
2055:
2056: public function onCreateOrUpdateEvent(&$aArgs)
2057: {
2058: $oEvent = $aArgs['Event'];
2059: $aGroups = self::findGroupsHashTagsFromString($oEvent->Name);
2060: $aGroupsDescription = self::findGroupsHashTagsFromString($oEvent->Description);
2061: $aGroups = array_merge($aGroups, $aGroupsDescription);
2062: $aGroupsLocation = self::findGroupsHashTagsFromString($oEvent->Location);
2063: $aGroups = array_merge($aGroups, $aGroupsLocation);
2064: $oUser = \Aurora\System\Api::getAuthenticatedUser();
2065:
2066: if ($oUser instanceof \Aurora\Modules\Core\Models\User) {
2067: foreach ($aGroups as $sGroup) {
2068: $sGroupName = ltrim($sGroup, '#');
2069: $oGroup = $this->Decorator()->GetGroupByName($sGroupName, $oUser->Id);
2070: if (!$oGroup) {
2071: $sGroupUUID = $this->Decorator()->CreateGroup(['Name' => $sGroupName], $oUser->Id);
2072: if ($sGroupUUID) {
2073: $oGroup = $this->GetGroup($oUser->Id, $sGroupUUID);
2074: }
2075: }
2076:
2077: if ($oGroup instanceof Models\Group) {
2078: $this->removeEventFromGroup($oGroup->UUID, $oEvent->IdCalendar, $oEvent->Id);
2079: $this->addEventToGroup($oGroup->UUID, $oEvent->IdCalendar, $oEvent->Id);
2080: }
2081: }
2082: }
2083: }
2084:
2085: /**
2086: * @param string $sGroupUUID
2087: *
2088: * @return bool
2089: */
2090: protected function _getGroupEvents($sGroupUUID)
2091: {
2092: $mResult = false;
2093: try {
2094: $mResult = \Aurora\Modules\Contacts\Models\GroupEvent::where(['GroupUUID' => $sGroupUUID])->get();
2095: } catch (\Aurora\System\Exceptions\BaseException $oException) {
2096: $mResult = false;
2097: }
2098: return $mResult;
2099: }
2100:
2101: /**
2102: * @param string $sCalendarUUID
2103: * @param string $sEventUUID
2104: *
2105: * @return bool
2106: */
2107: protected function getGroupEvent($sCalendarUUID, $sEventUUID)
2108: {
2109: $mResult = false;
2110: try {
2111: $mResult = \Aurora\Modules\Contacts\Models\GroupEvent::where('CalendarUUID', $sCalendarUUID)
2112: ->where('EventUUID', $sEventUUID)->first();
2113: } catch (\Aurora\System\Exceptions\BaseException $oException) {
2114: $mResult = false;
2115: }
2116: return $mResult;
2117: }
2118:
2119: /**
2120: * @param string $sGroupUUID
2121: * @param string $sCalendarUUID
2122: * @param string $sEventUUID
2123: *
2124: * @return bool
2125: */
2126: protected function addEventToGroup($sGroupUUID, $sCalendarUUID, $sEventUUID)
2127: {
2128: $bResult = false;
2129: try {
2130: $oGroupEvent = new Models\GroupEvent();
2131: $oGroupEvent->GroupUUID = $sGroupUUID;
2132: $oGroupEvent->CalendarUUID = $sCalendarUUID;
2133: $oGroupEvent->EventUUID = $sEventUUID;
2134: $bResult = $oGroupEvent->save();
2135: } catch (\Aurora\System\Exceptions\BaseException $oException) {
2136: $bResult = false;
2137: }
2138: return $bResult;
2139: }
2140:
2141: /**
2142: * @param string $sGroupUUID
2143: * @param string $sCalendarUUID
2144: * @param string $sEventUUID
2145: *
2146: * @return bool
2147: */
2148: protected function removeEventFromGroup($sGroupUUID, $sCalendarUUID, $sEventUUID)
2149: {
2150: $mResult = false;
2151: try {
2152: $mResult = \Aurora\Modules\Contacts\Models\GroupEvent::where('GroupUUID', $sGroupUUID)
2153: ->where('CalendarUUID', $sCalendarUUID)
2154: ->where('EventUUID', $sEventUUID)->first();
2155:
2156: if ($mResult instanceof Models\GroupEvent) {
2157: $mResult = $mResult->delete();
2158: }
2159: } catch (\Aurora\System\Exceptions\BaseException $oException) {
2160: $mResult = false;
2161: }
2162: return $mResult;
2163: }
2164:
2165: /**
2166: * @param string $sString
2167: *
2168: * @return array
2169: */
2170: protected static function findGroupsHashTagsFromString($sString)
2171: {
2172: $aResult = array();
2173:
2174: preg_match_all("/[#]([^#\s]+)/", $sString, $aMatches);
2175:
2176: if (\is_array($aMatches) && isset($aMatches[0]) && \is_array($aMatches[0]) && 0 < \count($aMatches[0])) {
2177: $aResult = $aMatches[0];
2178: }
2179:
2180: return $aResult;
2181: }
2182:
2183: /**
2184: * @param string $sCalendarUUID
2185: * @param string $sEventUUID
2186: *
2187: * @return bool
2188: */
2189: public function removeEventFromAllGroups($sCalendarUUID, $sEventUUID)
2190: {
2191: $mResult = false;
2192: try {
2193: $mResult = \Aurora\Modules\Contacts\Models\GroupEvent::where('CalendarUUID', $sCalendarUUID)
2194: ->where('EventUUID', $sEventUUID)->first();
2195:
2196: if (is_array($mResult)) {
2197: foreach ($mResult as $oGroupEvent) {
2198: if ($mResult instanceof Models\GroupEvent) {
2199: $mResult->delete();
2200: }
2201: }
2202: }
2203: $mResult = true;
2204: } catch (\Aurora\System\Exceptions\BaseException $oException) {
2205: $mResult = false;
2206: }
2207: return $mResult;
2208: }
2209: /***** private functions *****/
2210:
2211: public function GetAddressBook($UserId, $UUID)
2212: {
2213: Api::CheckAccess($UserId);
2214:
2215: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2216:
2217: return AddressBook::where('UserId', $UserId)
2218: ->where('UUID', $UUID)->first();
2219: }
2220:
2221: public function GetAddressBooks($UserId = null)
2222: {
2223: $aResult = [];
2224:
2225: Api::CheckAccess($UserId);
2226:
2227: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2228:
2229: $aAddressBooks = AddressBook::where('UserId', $UserId)->get();
2230:
2231: foreach ($aAddressBooks as $oAddressBook) {
2232: $aResult[] = [
2233: 'Id' => StorageType::AddressBook . '-' . $oAddressBook->Id,
2234: 'EntityId' => $oAddressBook->Id,
2235: 'CTag' => $this->Decorator()->GetCTag($UserId, StorageType::AddressBook . '-' . $oAddressBook->Id),
2236: 'Display' => true,
2237: 'Order' => 1,
2238: 'DisplayName' => $oAddressBook->Name
2239: ];
2240: }
2241:
2242: // $abRoot = new \Afterlogic\DAV\CardDAV\AddressBookHome(
2243: // \Afterlogic\DAV\Backend::Carddav(),
2244: // \Afterlogic\DAV\Constants::PRINCIPALS_PREFIX . Api::getUserPublicIdById($UserId)
2245: // );
2246:
2247: // $addressbooks = $abRoot->getChildren();
2248:
2249: return $aResult;
2250: }
2251:
2252: public function CreateAddressBook($AddressBookName, $UserId = null, $UUID = null)
2253: {
2254: $mResult = false;
2255:
2256: Api::CheckAccess($UserId);
2257:
2258: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2259:
2260: $oAddressBook = new AddressBook();
2261: $oAddressBook->UserId = (int) $UserId;
2262: $oAddressBook->Name = $AddressBookName;
2263:
2264: if (isset($UUID)) {
2265: $oAddressBook->UUID = $UUID;
2266: } else {
2267: $oAddressBook->UUID = UUIDUtil::getUUID();
2268: }
2269: if ($oAddressBook->save()) {
2270: $mResult = $oAddressBook->Id;
2271: }
2272:
2273: return $mResult;
2274: }
2275:
2276: public function UpdateAddressBook($EntityId, $AddressBookName, $UserId = null)
2277: {
2278: $mResult = false;
2279:
2280: Api::CheckAccess($UserId);
2281:
2282: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2283:
2284: $oAddressBook = AddressBook::where('UserId', $UserId)
2285: ->where('Id', $EntityId)->first();
2286:
2287: if ($oAddressBook) {
2288: $oAddressBook->Name = $AddressBookName;
2289:
2290: $mResult = $oAddressBook->save();
2291: }
2292:
2293: return $mResult;
2294: }
2295:
2296: public function DeleteAddressBook($EntityId, $UserId = null)
2297: {
2298: $mResult = false;
2299:
2300: Api::CheckAccess($UserId);
2301:
2302: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2303:
2304: $oAddressBook = AddressBook::where('UserId', $UserId)
2305: ->where('Id', $EntityId)->first();
2306:
2307: if ($oAddressBook) {
2308: Contact::where('AddressBookId', $EntityId)->delete();
2309: $mResult = $oAddressBook->delete();
2310: }
2311:
2312: return $mResult;
2313: }
2314:
2315: public function DeleteUsersAddressBooks($UserId = null)
2316: {
2317: $mResult = false;
2318:
2319: Api::CheckAccess($UserId);
2320:
2321: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2322:
2323: $mResult = AddressBook::where('UserId', $UserId)->delete();
2324:
2325: return $mResult;
2326: }
2327: }
2328: