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\PersonalContacts;
9:
10: use Aurora\Api;
11: use Aurora\Modules\Contacts\Enums\SortField;
12: use Aurora\Modules\Contacts\Enums\StorageType;
13: use Aurora\Modules\Contacts\Models\Contact;
14: use Aurora\Modules\Contacts\Module as ContactsModule;
15:
16: /**
17: * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
18: * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
19: * @copyright Copyright (c) 2023, Afterlogic Corp.
20: *
21: * @package Modules
22: */
23: class Module extends \Aurora\System\Module\AbstractModule
24: {
25: public static $sStorage = StorageType::Personal;
26: protected static $iStorageOrder = 0;
27:
28: public function init()
29: {
30: $this->subscribeEvent('Contacts::GetStorages', array($this, 'onGetStorages'));
31: $this->subscribeEvent('Contacts::IsDisplayedStorage::after', array($this, 'onAfterIsDisplayedStorage'));
32: $this->subscribeEvent('Core::DeleteUser::after', array($this, 'onAfterDeleteUser'));
33: $this->subscribeEvent('Contacts::CreateContact::before', array($this, 'onBeforeCreateContact'));
34: $this->subscribeEvent('Contacts::PrepareFiltersFromStorage', array($this, 'prepareFiltersFromStorage'));
35: $this->subscribeEvent('Mail::ExtendMessageData', array($this, 'onExtendMessageData'));
36: $this->subscribeEvent('Contacts::CheckAccessToObject::after', array($this, 'onAfterCheckAccessToObject'));
37: $this->subscribeEvent('Contacts::GetContactSuggestions', array($this, 'onGetContactSuggestions'));
38: }
39:
40: public function onGetStorages(&$aStorages)
41: {
42: $aStorages[self::$iStorageOrder] = self::$sStorage;
43: $aStorages[self::$iStorageOrder + 1] = StorageType::Collected;
44: }
45:
46: public function onAfterIsDisplayedStorage($aArgs, &$mResult)
47: {
48: if ($aArgs['Storage'] === StorageType::Collected) {
49: $mResult = false;
50: }
51: }
52:
53: public function onAfterDeleteUser(&$aArgs, &$mResult)
54: {
55: Contact::where('IdUser', '=', $aArgs['UserId'])
56: ->where(function ($query) {
57: $query->where('Storage', '=', self::$sStorage)
58: ->orWhere('Storage', '=', StorageType::AddressBook);
59: })->delete();
60: }
61:
62: public function onBeforeCreateContact(&$aArgs, &$mResult)
63: {
64: if (isset($aArgs['Contact'])) {
65: if (!isset($aArgs['Contact']['Storage']) || $aArgs['Contact']['Storage'] === '') {
66: $aArgs['Contact']['Storage'] = self::$sStorage;
67: }
68: }
69: }
70:
71: public function prepareFiltersFromStorage(&$aArgs, &$mResult)
72: {
73: $iAddressBookId = 0;
74: if (isset($aArgs['Storage'])) {
75: $aStorageParts = \explode('-', $aArgs['Storage']);
76: if (isset($aStorageParts[0]) && $aStorageParts[0] === StorageType::AddressBook) {
77: $iAddressBookId = $aStorageParts[1];
78: if (!is_numeric($iAddressBookId)) {
79: return;
80: }
81:
82: $iAddressBookId = (int) $iAddressBookId;
83: $aArgs['Storage'] = StorageType::AddressBook;
84: }
85: $sStorage = $aArgs['Storage'];
86:
87: if ($sStorage === self::$sStorage || $sStorage === StorageType::All ||
88: $sStorage === StorageType::Collected || $sStorage === StorageType::AddressBook) {
89: $aArgs['IsValid'] = true;
90: $iUserId = isset($aArgs['UserId']) ? $aArgs['UserId'] : Api::getAuthenticatedUserId();
91:
92: if (!isset($mResult)) {
93: $mResult = Contact::query();
94: }
95:
96: $bAuto = ($sStorage === StorageType::Collected);
97: if ($bAuto) {
98: $sStorage = StorageType::Personal;
99: }
100:
101: $bSuggestions = isset($aArgs['Suggestions']) ? !!$aArgs['Suggestions'] : false;
102:
103: $mResult = $mResult->orWhere(function ($query) use ($iUserId, $sStorage, $bAuto, $bSuggestions, $iAddressBookId, $aArgs) {
104: $query = $query->where('IdUser', $iUserId);
105:
106: if ($sStorage === StorageType::All) {
107: $query = $query->whereIn('Storage', [StorageType::Personal, StorageType::AddressBook]);
108: } else {
109: $query = $query->where('Storage', $sStorage);
110: if ($sStorage === StorageType::AddressBook && $iAddressBookId > 0) {
111: $query = $query->where('AddressBookId', $iAddressBookId);
112: }
113: }
114: // if (isset($aArgs['SortField']) && $aArgs['SortField'] === SortField::Frequency) {
115: // $query->whereNotNull('DateModified');
116: // } else
117: if (!$bSuggestions) {
118: $query->where('Auto', $bAuto)->orWhereNull('Auto');
119: }
120: });
121: }
122: }
123: }
124:
125: public function onExtendMessageData($aData, &$oMessage)
126: {
127: $oApiFileCache = new \Aurora\System\Managers\Filecache();
128:
129: $oUser = Api::getAuthenticatedUser();
130:
131: foreach ($aData as $aDataItem) {
132: $oPart = $aDataItem['Part'];
133: $bVcard = $oPart instanceof \MailSo\Imap\BodyStructure &&
134: ($oPart->ContentType() === 'text/vcard' || $oPart->ContentType() === 'text/x-vcard');
135: $sData = $aDataItem['Data'];
136: if ($bVcard && !empty($sData)) {
137: $oContact = new Contact();
138: try {
139: $oContact->InitFromVCardStr($oUser->Id, $sData);
140:
141: $oContact->UUID = '';
142:
143: $bContactExists = false;
144: if (0 < strlen($oContact->ViewEmail)) {
145: $aLocalContacts = ContactsModule::Decorator()->GetContactsByEmails(
146: $oUser->Id,
147: self::$sStorage,
148: [$oContact->ViewEmail],
149: null,
150: false
151: );
152: $oLocalContact = count($aLocalContacts) > 0 ? $aLocalContacts[0] : null;
153: if ($oLocalContact) {
154: $oContact->UUID = $oLocalContact->UUID;
155: $bContactExists = true;
156: }
157: }
158:
159: $sTemptFile = md5($sData).'.vcf';
160: if ($oApiFileCache && $oApiFileCache->put($oUser->UUID, $sTemptFile, $sData)) { // Temp files with access from another module should be stored in System folder
161: if (class_exists('\Aurora\Modules\Mail\Classes\Vcard')) {
162: $oVcard = \Aurora\Modules\Mail\Classes\Vcard::createInstance();
163:
164: $oVcard->Uid = $oContact->UUID;
165: $oVcard->File = $sTemptFile;
166: $oVcard->Exists = !!$bContactExists;
167: $oVcard->Name = $oContact->FullName;
168: $oVcard->Email = $oContact->ViewEmail;
169:
170: $oMessage->addExtend('VCARD', $oVcard);
171: }
172: } else {
173: Api::Log('Can\'t save temp file "'.$sTemptFile.'"', \Aurora\System\Enums\LogLevel::Error);
174: }
175: } catch(\Exception $oEx) {
176: Api::LogException($oEx);
177: }
178: }
179: }
180: }
181:
182: public function onAfterCheckAccessToObject(&$aArgs, &$mResult)
183: {
184: $oUser = $aArgs['User'];
185: $oContact = isset($aArgs['Contact']) ? $aArgs['Contact'] : null;
186:
187: if ($oContact instanceof Contact && $oContact->Storage === self::$sStorage) {
188: if ($oUser->Role !== \Aurora\System\Enums\UserRole::SuperAdmin && $oUser->Id !== $oContact->IdUser) {
189: $mResult = false;
190: } else {
191: $mResult = true;
192: }
193: }
194: }
195:
196: public function onGetContactSuggestions(&$aArgs, &$mResult)
197: {
198: if ($aArgs['Storage'] === 'all' || $aArgs['Storage'] === self::$sStorage) {
199: $mResult['personal'] = ContactsModule::Decorator()->GetContacts(
200: $aArgs['UserId'],
201: self::$sStorage,
202: 0,
203: $aArgs['Limit'],
204: $aArgs['SortField'],
205: $aArgs['SortOrder'],
206: $aArgs['Search']
207: );
208: }
209: }
210: }
211: