From 500b997f91abeec90df0fceb994edf0ea56ad802 Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Thu, 29 Aug 2024 14:09:18 +0600 Subject: [PATCH 1/8] feat: add addressBook user settings section for nextcloud plugin --- plugins/nextcloud/NextcloudAddressBook.php | 100 +++++++++---- plugins/nextcloud/index.php | 139 +++++++++++++----- plugins/nextcloud/js/addressbook.js | 36 +++++ plugins/nextcloud/langs/de.json | 3 +- plugins/nextcloud/langs/en.json | 3 +- plugins/nextcloud/langs/pl.json | 3 +- plugins/nextcloud/langs/ru.json | 3 +- plugins/nextcloud/langs/zh-TW.json | 3 +- plugins/nextcloud/langs/zh.json | 3 +- .../templates/AddressBookSettings.html | 12 ++ 10 files changed, 232 insertions(+), 73 deletions(-) create mode 100644 plugins/nextcloud/js/addressbook.js create mode 100644 plugins/nextcloud/templates/AddressBookSettings.html diff --git a/plugins/nextcloud/NextcloudAddressBook.php b/plugins/nextcloud/NextcloudAddressBook.php index 2790e4e5c..4d3d06de6 100644 --- a/plugins/nextcloud/NextcloudAddressBook.php +++ b/plugins/nextcloud/NextcloudAddressBook.php @@ -1,38 +1,44 @@ GetSavedAddressBookKey(); + } + + private function GetSavedAddressBookKey(): string { $this->contactsManager = \OC::$server->getContactsManager(); - foreach($this->contactsManager->getUserAddressBooks() as $addressBook) { - if($addressBook->isSystemAddressBook()) { - $this->contactsManager->unregisterAddressBook($addressBook); + foreach ($this->contactsManager->getUserAddressBooks() as $addressBook) { + if ($addressBook->isSystemAddressBook()) { + $this->contactsManager->unregisterAddressBook($addressBook); } } $uid = \OC::$server->getUserSession()->getUser()->getUID(); $cardDavBackend = \OC::$server->get(\OCA\DAV\CardDAV\CardDavBackend::class); - $principalUri = 'principals/users/'. $uid; - $addressBookId = $cardDavBackend->getAddressBooksByUri($principalUri, self::URI); + $principalUri = 'principals/users/' . $uid; + $uri = $this->GetSavedUri(); + $addressBookId = $cardDavBackend->getAddressBooksByUri($principalUri, $uri); if ($addressBookId === null) { - $addressBookId = $cardDavBackend->createAddressBook($principalUri, self::URI, array_filter([ - '{DAV:}displayname' => 'Webmail', - '{urn:ietf:params:xml:ns:carddav}addressbook-description' => 'Recipients from snappymail', - ])); + $addressBookId = $cardDavBackend->createAddressBook($principalUri, $uri, array_filter([ + '{DAV:}displayname' => 'WebMail', + '{urn:ietf:params:xml:ns:carddav}addressbook-description' => 'Recipients from snappymail', + ])); } else { $addressBookId = $addressBookId['id']; } - $this->key = $addressBookId; + return $addressBookId; } - public function IsSupported() : bool { + public function IsSupported(): bool + { // Maybe just return true, contacts app is just a frontend //return \OC::$server->getAppManager()->isEnabledForUser('contacts'); return true; @@ -43,53 +49,63 @@ class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBoo return true; } - public function SetEmail(string $sEmail) : bool { + public function SetEmail(string $sEmail): bool + { return true; } - public function Sync() : bool { + public function Sync(): bool + { return false; } - public function Export(string $sType = 'vcf') : bool { + public function Export(string $sType = 'vcf'): bool + { return false; } - public function ContactSave(Contact $oContact) : bool { + public function ContactSave(Contact $oContact): bool + { return false; } - public function DeleteContacts(array $aContactIds) : bool { + public function DeleteContacts(array $aContactIds): bool + { return false; } - public function DeleteAllContacts(string $sEmail) : bool { + public function DeleteAllContacts(string $sEmail): bool + { return false; } - public function GetContacts(int $iOffset = 0, int $iLimit = 20, string $sSearch = '', int &$iResultCount = 0) : array { + public function GetContacts(int $iOffset = 0, int $iLimit = 20, string $sSearch = '', int &$iResultCount = 0): array + { return []; } - public function GetContactByEmail(string $sEmail) : ?Contact { + public function GetContactByEmail(string $sEmail): ?Contact + { return null; } - public function GetContactByID($mID, bool $bIsStrID = false) : ?Contact { + public function GetContactByID($mID, bool $bIsStrID = false): ?Contact + { return null; } - public function GetSuggestions(string $sSearch, int $iLimit = 20) : array { + public function GetSuggestions(string $sSearch, int $iLimit = 20): array + { return []; } - private function GetEmailObjects(array $aEmails) : array { + private function GetEmailObjects(array $aEmails): array + { $aEmailsObjects = \array_map(function ($mItem) { $oResult = null; try { $oResult = \MailSo\Mime\Email::Parse(\trim($mItem)); - } - catch (\Throwable $oException) { + } catch (\Throwable $oException) { unset($oException); } return $oResult; @@ -105,20 +121,21 @@ class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBoo * Add/increment email address usage * Handy for "most used" sorting suggestions in PdoAddressBook */ - public function IncFrec(array $aEmails, bool $bCreateAuto = true) : bool { + public function IncFrec(array $aEmails, bool $bCreateAuto = true): bool + { if ($bCreateAuto) { $aEmailsObjects = $this->GetEmailObjects($aEmails); if (!count($aEmailsObjects)) { return false; } - foreach ($aEmailsObjects as $oEmail) { + foreach ($aEmailsObjects as $oEmail) { if ('' === \trim($oEmail->GetEmail())) { continue; } $sEmail = \trim($oEmail->GetEmail(true)); $existingResults = $this->contactsManager->search($sEmail, ['EMAIL'], ['strict_search' => true]); - + if (!empty($existingResults)) { continue; } @@ -127,20 +144,39 @@ class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBoo 'EMAIL' => $sEmail, 'FN' => $sEmail ]; - + if ('' !== \trim($oEmail->GetDisplayName())) { $properties['FN'] = $oEmail->GetDisplayName(); } - $this->contactsManager->createOrUpdate($properties, $this->key); + $this->contactsManager->createOrUpdate($properties, $this->GetSavedAddressBookKey()); } return true; } return false; } - public function Test() : string { + public function Test(): string + { return ''; } + private function Account(): \RainLoop\Model\Account + { + return \RainLoop\Api::Actions()->getAccountFromToken(); + } + private function SettingsProvider(): \RainLoop\Providers\Settings + { + return \RainLoop\Api::Actions()->SettingsProvider(true); + } + + private function Settings(): \RainLoop\Settings + { + return $this->SettingsProvider()->Load($this->Account()); + } + + private function GetSavedUri(): string + { + return $this->Settings()->GetConf('NextCloudAddressBookUri', 'webmail'); + } } diff --git a/plugins/nextcloud/index.php b/plugins/nextcloud/index.php index 614f1bcfb..04bc3a084 100644 --- a/plugins/nextcloud/index.php +++ b/plugins/nextcloud/index.php @@ -10,7 +10,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin DESCRIPTION = 'Integrate with Nextcloud v20+', REQUIRED = '2.36.2'; - public function Init() : void + public function Init(): void { if (static::IsIntegrated()) { \SnappyMail\Log::debug('Nextcloud', 'integrated'); @@ -36,11 +36,16 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin $this->addTemplate('templates/PopupsNextcloudFiles.html'); $this->addTemplate('templates/PopupsNextcloudCalendars.html'); -// $this->addHook('login.credentials.step-2', 'loginCredentials2'); -// $this->addHook('login.credentials', 'loginCredentials'); + // $this->addHook('login.credentials.step-2', 'loginCredentials2'); + // $this->addHook('login.credentials', 'loginCredentials'); $this->addHook('imap.before-login', 'beforeLogin'); $this->addHook('smtp.before-login', 'beforeLogin'); $this->addHook('sieve.before-login', 'beforeLogin'); + + $this->addJs('js/addressbook.js'); // add js file + $this->addTemplate('templates/AddressBookSettings.html'); + $this->addJsonHook('JsonGetAddressbooks', 'GetAddressBooks'); + $this->addJsonHook('NextcloudUpdateAddressBook', 'UpdateAddressBook'); } else { \SnappyMail\Log::debug('Nextcloud', 'NOT integrated'); // \OC::$server->getConfig()->getAppValue('snappymail', 'snappymail-no-embed'); @@ -48,6 +53,48 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin } } + public function GetAddressBooks() + { + $addressBooks = []; + + $contactsManager = \OC::$server->getContactsManager(); + + $selectedUri = $this->Settings()->GetConf('NextCloudAddressBookUri', 'webmail'); + + foreach ($contactsManager->getUserAddressBooks() as $addressBook) { + if ($addressBook->isSystemAddressBook()) { + $contactsManager->unregisterAddressBook($addressBook); + continue; + } + + $book = new AddressBook(); + $book->uri = $addressBook->getUri(); + $book->name = $addressBook->getDisplayName(); + if (strcmp($selectedUri, $book->uri) === 0) { + $book->selected = true; + } + + $addressBooks[] = $book; + } + + + return $this->jsonResponse(__FUNCTION__, array( + 'addressbooks' => json_encode($addressBooks) + )); + } + + public function UpdateAddressBook(): array + { + $uri = $this->jsonParam('uri'); + $oSettings = $this->Settings(); + if (\is_string($uri)) { + $oSettings->SetConf('NextCloudAddressBookUri', $uri); + $this->SettingsProvider()->Save($this->Account(), $oSettings); + } + return $this->jsonResponse(__FUNCTION__, true); + } + + public function ContentSecurityPolicy(\SnappyMail\HTTP\CSP $CSP) { if (\method_exists($CSP, 'add')) { @@ -55,7 +102,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin } } - public function Supported() : string + public function Supported(): string { return static::IsIntegrated() ? '' : 'Nextcloud not found to use this plugin'; } @@ -70,24 +117,24 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin return static::IsIntegrated() && \OC::$server->getUserSession()->isLoggedIn(); } - public function loginCredentials(string &$sEmail, string &$sLogin, ?string &$sPassword = null) : void + public function loginCredentials(string &$sEmail, string &$sLogin, ?string &$sPassword = null): void { /** * This has an issue. * When user changes email address, all settings are gone as the new * _data_/_default_/storage/{domain}/{local-part} is used */ -// $ocUser = \OC::$server->getUserSession()->getUser(); -// $sEmail = $ocUser->getEMailAddress() ?: $ocUser->getPrimaryEMailAddress() ?: $sEmail; + // $ocUser = \OC::$server->getUserSession()->getUser(); + // $sEmail = $ocUser->getEMailAddress() ?: $ocUser->getPrimaryEMailAddress() ?: $sEmail; } - public function loginCredentials2(string &$sEmail, ?string &$sPassword = null) : void + public function loginCredentials2(string &$sEmail, ?string &$sPassword = null): void { $ocUser = \OC::$server->getUserSession()->getUser(); $sEmail = $ocUser->getEMailAddress() ?: $ocUser->getPrimaryEMailAddress() ?: $sEmail; } - public function beforeLogin(\RainLoop\Model\Account $oAccount, \MailSo\Net\NetClient $oClient, \MailSo\Net\ConnectSettings $oSettings) : void + public function beforeLogin(\RainLoop\Model\Account $oAccount, \MailSo\Net\NetClient $oClient, \MailSo\Net\ConnectSettings $oSettings): void { // https://apps.nextcloud.com/apps/oidc_login $config = \OC::$server->getConfig(); @@ -104,11 +151,12 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin // Only login with OIDC access token if // it is enabled in config, the user is currently logged in with OIDC, // the current snappymail account is the OIDC account and no account defined explicitly - if (\OC::$server->getConfig()->getAppValue('snappymail', 'snappymail-autologin-oidc', false) - && \OC::$server->getSession()->get('is_oidc') - && $sNcEmail === $oSettings->username - && !$bAccountDefinedExplicitly -// && $oClient->supportsAuthType('OAUTHBEARER') // v2.28 + if ( + \OC::$server->getConfig()->getAppValue('snappymail', 'snappymail-autologin-oidc', false) + && \OC::$server->getSession()->get('is_oidc') + && $sNcEmail === $oSettings->username + && !$bAccountDefinedExplicitly + // && $oClient->supportsAuthType('OAUTHBEARER') // v2.28 ) { $sAccessToken = \OC::$server->getSession()->get('oidc_access_token'); if ($sAccessToken) { @@ -123,7 +171,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin \OC::$server->getLDAPProvider(); */ - public function NextcloudAttachFile() : array + public function NextcloudAttachFile(): array { $aResult = [ 'success' => false, @@ -147,10 +195,10 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin return $this->jsonResponse(__FUNCTION__, $aResult); } - public function NextcloudSaveMsg() : array + public function NextcloudSaveMsg(): array { $sSaveFolder = \ltrim($this->jsonParam('folder', ''), '/'); -// $aValues = \RainLoop\Api::Actions()->decodeRawKey($this->jsonParam('msgHash', '')); + // $aValues = \RainLoop\Api::Actions()->decodeRawKey($this->jsonParam('msgHash', '')); $msgHash = $this->jsonParam('msgHash', ''); $aValues = \json_decode(\MailSo\Base\Utils::UrlSafeBase64Decode($msgHash), true); $aResult = [ @@ -204,14 +252,14 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin foreach ($data->items as $aItem) { $sSavedFileName = empty($aItem['fileName']) ? 'file.dat' : $aItem['fileName']; if (!empty($aItem['data'])) { - $sSavedFileNameFull = static::SmartFileExists($sSaveFolder.'/'.$sSavedFileName, $oFiles); + $sSavedFileNameFull = static::SmartFileExists($sSaveFolder . '/' . $sSavedFileName, $oFiles); if (!$oFiles->file_put_contents($sSavedFileNameFull, $aItem['data'])) { $data->result = false; } } else if (!empty($aItem['fileHash'])) { $fFile = $data->filesProvider->GetFile($data->account, $aItem['fileHash'], 'rb'); if (\is_resource($fFile)) { - $sSavedFileNameFull = static::SmartFileExists($sSaveFolder.'/'.$sSavedFileName, $oFiles); + $sSavedFileNameFull = static::SmartFileExists($sSaveFolder . '/' . $sSavedFileName, $oFiles); if (!$oFiles->file_put_contents($sSavedFileNameFull, $fFile)) { $data->result = false; } @@ -225,19 +273,19 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin } } - public function FilterAppData($bAdmin, &$aResult) : void + public function FilterAppData($bAdmin, &$aResult): void { if (!$bAdmin && \is_array($aResult)) { $ocUser = \OC::$server->getUserSession()->getUser(); $sUID = $ocUser->getUID(); $oUrlGen = \OC::$server->getURLGenerator(); $sWebDAV = $oUrlGen->getAbsoluteURL($oUrlGen->linkTo('', 'remote.php') . '/dav'); -// $sWebDAV = \OCP\Util::linkToRemote('dav'); + // $sWebDAV = \OCP\Util::linkToRemote('dav'); $aResult['Nextcloud'] = [ 'UID' => $sUID, 'WebDAV' => $sWebDAV, 'CalDAV' => $this->Config()->Get('plugin', 'calendar', false) -// 'WebDAV_files' => $sWebDAV . '/files/' . $sUID + // 'WebDAV_files' => $sWebDAV . '/files/' . $sUID ]; if (empty($aResult['Auth'])) { $config = \OC::$server->getConfig(); @@ -259,9 +307,9 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin } if (!$sEmail) { $sEmail = $ocUser->getEMailAddress(); -// ?: $ocUser->getPrimaryEMailAddress(); + // ?: $ocUser->getPrimaryEMailAddress(); } -/* + /* if ($config->getAppValue('snappymail', 'snappymail-autologin-oidc', false)) { if (\OC::$server->getSession()->get('is_oidc')) { $sEmail = "{$sUID}@nextcloud"; @@ -308,7 +356,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin } } - public function FilterLanguage(&$sLanguage, $bAdmin) : void + public function FilterLanguage(&$sLanguage, $bAdmin): void { if (!\RainLoop\Api::Config()->Get('webmail', 'allow_languages_on_settings', true)) { $aResultLang = \SnappyMail\L10n::getLanguages($bAdmin); @@ -331,7 +379,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin * * @return string return locale */ - private function determineLocale(string $langCode, array $languagesArray) : ?string + private function determineLocale(string $langCode, array $languagesArray): ?string { // Direct check for the language code if (\in_array($langCode, $languagesArray)) { @@ -378,7 +426,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin include_once __DIR__ . '/NextcloudAddressBook.php'; $mResult = new NextcloudAddressBook(); } -/* + /* if ($this->Config()->Get('plugin', 'storage', false) && ('storage' === $sName || 'storage-local' === $sName)) { require_once __DIR__ . '/storage.php'; $oDriver = new \NextcloudStorage(APP_PRIVATE_DATA.'storage', $sName === 'storage-local'); @@ -387,7 +435,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin } } - protected function configMapping() : array + protected function configMapping(): array { return array( \RainLoop\Plugins\Property::NewInstance('suggestions')->SetLabel('Suggestions') @@ -396,7 +444,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin \RainLoop\Plugins\Property::NewInstance('ignoreSystemAddressbook')->SetLabel('Ignore system addressbook') ->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL) ->SetDefaultValue(true), -/* + /* \RainLoop\Plugins\Property::NewInstance('storage')->SetLabel('Use Nextcloud user ID in config storage path') ->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL) ->SetDefaultValue(false) @@ -407,7 +455,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin ); } - private static function SmartFileExists(string $sFilePath, $oFiles) : string + private static function SmartFileExists(string $sFilePath, $oFiles): string { $sFilePath = \str_replace('\\', '/', \trim($sFilePath)); @@ -421,11 +469,10 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin while (true) { ++$iIndex; - $sFilePathNew = $aFileInfo['dirname'].'/'. - \preg_replace('/\(\d{1,2}\)$/', '', $aFileInfo['filename']). - ' ('.$iIndex.')'. - (empty($aFileInfo['extension']) ? '' : '.'.$aFileInfo['extension']) - ; + $sFilePathNew = $aFileInfo['dirname'] . '/' . + \preg_replace('/\(\d{1,2}\)$/', '', $aFileInfo['filename']) . + ' (' . $iIndex . ')' . + (empty($aFileInfo['extension']) ? '' : '.' . $aFileInfo['extension']); if (!$oFiles->file_exists($sFilePathNew)) { return $sFilePathNew; } @@ -435,4 +482,26 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin } return $sFilePath; } + + private function Account(): \RainLoop\Model\Account + { + return \RainLoop\Api::Actions()->getAccountFromToken(); + } + + private function SettingsProvider(): \RainLoop\Providers\Settings + { + return \RainLoop\Api::Actions()->SettingsProvider(true); + } + + private function Settings(): \RainLoop\Settings + { + return $this->SettingsProvider()->Load($this->Account()); + } +} + +class AddressBook +{ + public string $uri; + public string $name; + public bool $selected = false; } diff --git a/plugins/nextcloud/js/addressbook.js b/plugins/nextcloud/js/addressbook.js new file mode 100644 index 000000000..1ce7bfc79 --- /dev/null +++ b/plugins/nextcloud/js/addressbook.js @@ -0,0 +1,36 @@ +(rl => { + if (rl) { + class AddressBookSettings /* extends AbstractViewSettings */ { + constructor() { + this.addressBookList = ko.observableArray(); + this.selectedAddressBook = ko.observable(); + + rl.pluginRemoteRequest((iError, oData) => { + if (!iError) { + const books = JSON.parse(oData.Result.addressbooks); + books.forEach(book => { + this.addressBookList.push(book); + + if (book.selected) { + this.selectedAddressBook(book.uri); + } + }); + + this.selectedAddressBook.subscribe(value => { + rl.pluginRemoteRequest(() => { }, 'NextcloudUpdateAddressBook', { + uri: value + }); + }); + } + }, "JsonGetAddressbooks"); + } + } + + rl.addSettingsViewModel( + AddressBookSettings, + 'AddressBookSettings', + 'NEXTCLOUD/ADDRESS_BOOK', + 'addressbook' + ); + } +})(window.rl); diff --git a/plugins/nextcloud/langs/de.json b/plugins/nextcloud/langs/de.json index 5f43f1357..a92d94b3c 100644 --- a/plugins/nextcloud/langs/de.json +++ b/plugins/nextcloud/langs/de.json @@ -9,6 +9,7 @@ "SELECT_CALENDAR": "Kalender auswählen", "FILE_ATTACH": "anfügen", "FILE_INTERNAL": "intern", - "FILE_PUBLIC": "öffentlich" + "FILE_PUBLIC": "öffentlich", + "ADDRESS_BOOK": "Address Book" } } diff --git a/plugins/nextcloud/langs/en.json b/plugins/nextcloud/langs/en.json index 2c19d11c2..b4fb55a97 100644 --- a/plugins/nextcloud/langs/en.json +++ b/plugins/nextcloud/langs/en.json @@ -9,6 +9,7 @@ "SELECT_CALENDAR": "Select calendar", "FILE_ATTACH": "attach", "FILE_INTERNAL": "internal", - "FILE_PUBLIC": "public" + "FILE_PUBLIC": "public", + "ADDRESS_BOOK": "Address Book" } } diff --git a/plugins/nextcloud/langs/pl.json b/plugins/nextcloud/langs/pl.json index 82e0d4f18..57f28aa50 100644 --- a/plugins/nextcloud/langs/pl.json +++ b/plugins/nextcloud/langs/pl.json @@ -9,6 +9,7 @@ "SELECT_CALENDAR": "Wybierz kalendarz", "FILE_ATTACH": "dołącz", "FILE_INTERNAL": "link wewnętrzny", - "FILE_PUBLIC": "link publiczny" + "FILE_PUBLIC": "link publiczny", + "ADDRESS_BOOK": "Address Book" } } diff --git a/plugins/nextcloud/langs/ru.json b/plugins/nextcloud/langs/ru.json index a8b28372d..4e7125770 100644 --- a/plugins/nextcloud/langs/ru.json +++ b/plugins/nextcloud/langs/ru.json @@ -9,6 +9,7 @@ "SELECT_CALENDAR": "Выбрать календарь", "FILE_ATTACH": "Прикрепить с ПК", "FILE_INTERNAL": "Внутреняя", - "FILE_PUBLIC": "Публичная" + "FILE_PUBLIC": "Публичная", + "ADDRESS_BOOK": "Address Book" } } diff --git a/plugins/nextcloud/langs/zh-TW.json b/plugins/nextcloud/langs/zh-TW.json index 292d02286..14f227645 100644 --- a/plugins/nextcloud/langs/zh-TW.json +++ b/plugins/nextcloud/langs/zh-TW.json @@ -9,6 +9,7 @@ "SELECT_CALENDAR": "選擇日曆", "FILE_ATTACH": "附加", "FILE_INTERNAL": "內部", - "FILE_PUBLIC": "公開" + "FILE_PUBLIC": "公開", + "ADDRESS_BOOK": "Address Book" } } diff --git a/plugins/nextcloud/langs/zh.json b/plugins/nextcloud/langs/zh.json index 39b20ac2e..491221392 100644 --- a/plugins/nextcloud/langs/zh.json +++ b/plugins/nextcloud/langs/zh.json @@ -9,6 +9,7 @@ "SELECT_CALENDAR": "选择日历", "FILE_ATTACH": "附加", "FILE_INTERNAL": "内部", - "FILE_PUBLIC": "公开" + "FILE_PUBLIC": "公开", + "ADDRESS_BOOK": "Address Book" } } diff --git a/plugins/nextcloud/templates/AddressBookSettings.html b/plugins/nextcloud/templates/AddressBookSettings.html new file mode 100644 index 000000000..e33682515 --- /dev/null +++ b/plugins/nextcloud/templates/AddressBookSettings.html @@ -0,0 +1,12 @@ +
+
AddressBook
+
+ +
+ + +
+ +
+
From a47cc450e81146ed970b5a919b69e19e59ad9a64 Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Fri, 30 Aug 2024 13:55:55 +0600 Subject: [PATCH 2/8] feat: move nextcloud addressbook user settings under contatcs settings section --- plugins/nextcloud/NextcloudAddressBook.php | 14 +++-- plugins/nextcloud/index.php | 13 +++-- plugins/nextcloud/js/addressbook.js | 58 ++++++++++--------- .../templates/AddressBookSettings.html | 12 ---- 4 files changed, 47 insertions(+), 50 deletions(-) delete mode 100644 plugins/nextcloud/templates/AddressBookSettings.html diff --git a/plugins/nextcloud/NextcloudAddressBook.php b/plugins/nextcloud/NextcloudAddressBook.php index 4d3d06de6..aaccb0b31 100644 --- a/plugins/nextcloud/NextcloudAddressBook.php +++ b/plugins/nextcloud/NextcloudAddressBook.php @@ -7,6 +7,9 @@ class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBoo use RainLoop\Providers\AddressBook\CardDAV; private $contactsManager; + private const DEFAULT_URI = 'webmail'; + private const SETTINGS_KEY = 'nextCloudAddressBookUri'; + function __construct() { $this->GetSavedAddressBookKey(); @@ -21,20 +24,21 @@ class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBoo $this->contactsManager->unregisterAddressBook($addressBook); } } + $uid = \OC::$server->getUserSession()->getUser()->getUID(); $cardDavBackend = \OC::$server->get(\OCA\DAV\CardDAV\CardDavBackend::class); $principalUri = 'principals/users/' . $uid; $uri = $this->GetSavedUri(); $addressBookId = $cardDavBackend->getAddressBooksByUri($principalUri, $uri); + if ($addressBookId === null) { - $addressBookId = $cardDavBackend->createAddressBook($principalUri, $uri, array_filter([ + return $cardDavBackend->createAddressBook($principalUri, $uri, array_filter([ '{DAV:}displayname' => 'WebMail', '{urn:ietf:params:xml:ns:carddav}addressbook-description' => 'Recipients from snappymail', ])); - } else { - $addressBookId = $addressBookId['id']; } - return $addressBookId; + + return $addressBookId['id']; } public function IsSupported(): bool @@ -177,6 +181,6 @@ class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBoo private function GetSavedUri(): string { - return $this->Settings()->GetConf('NextCloudAddressBookUri', 'webmail'); + return $this->Settings()->GetConf(self::SETTINGS_KEY, self::DEFAULT_URI); } } diff --git a/plugins/nextcloud/index.php b/plugins/nextcloud/index.php index 04bc3a084..09164fff0 100644 --- a/plugins/nextcloud/index.php +++ b/plugins/nextcloud/index.php @@ -10,6 +10,10 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin DESCRIPTION = 'Integrate with Nextcloud v20+', REQUIRED = '2.36.2'; + + private const DEFAULT_ADDRESSBOOK_URI = 'webmail'; + private const ADDRESSBOOK_SETTINGS_KEY = 'nextCloudAddressBookUri'; + public function Init(): void { if (static::IsIntegrated()) { @@ -42,9 +46,8 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin $this->addHook('smtp.before-login', 'beforeLogin'); $this->addHook('sieve.before-login', 'beforeLogin'); - $this->addJs('js/addressbook.js'); // add js file - $this->addTemplate('templates/AddressBookSettings.html'); - $this->addJsonHook('JsonGetAddressbooks', 'GetAddressBooks'); + $this->addJs('js/addressbook.js'); + $this->addJsonHook('NextcloudGetAddressBooks', 'GetAddressBooks'); $this->addJsonHook('NextcloudUpdateAddressBook', 'UpdateAddressBook'); } else { \SnappyMail\Log::debug('Nextcloud', 'NOT integrated'); @@ -59,7 +62,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin $contactsManager = \OC::$server->getContactsManager(); - $selectedUri = $this->Settings()->GetConf('NextCloudAddressBookUri', 'webmail'); + $selectedUri = $this->Settings()->GetConf(self::ADDRESSBOOK_SETTINGS_KEY, self::DEFAULT_ADDRESSBOOK_URI); foreach ($contactsManager->getUserAddressBooks() as $addressBook) { if ($addressBook->isSystemAddressBook()) { @@ -88,7 +91,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin $uri = $this->jsonParam('uri'); $oSettings = $this->Settings(); if (\is_string($uri)) { - $oSettings->SetConf('NextCloudAddressBookUri', $uri); + $oSettings->SetConf(self::ADDRESSBOOK_SETTINGS_KEY, $uri); $this->SettingsProvider()->Save($this->Account(), $oSettings); } return $this->jsonResponse(__FUNCTION__, true); diff --git a/plugins/nextcloud/js/addressbook.js b/plugins/nextcloud/js/addressbook.js index 1ce7bfc79..c871c0928 100644 --- a/plugins/nextcloud/js/addressbook.js +++ b/plugins/nextcloud/js/addressbook.js @@ -1,36 +1,38 @@ (rl => { if (rl) { - class AddressBookSettings /* extends AbstractViewSettings */ { - constructor() { - this.addressBookList = ko.observableArray(); - this.selectedAddressBook = ko.observable(); + addEventListener('rl-view-model', e => { + if ('SettingsContacts' === e.detail.viewModelTemplateID) { + const container = e.detail.viewModelDom.querySelector('.form-horizontal'); + if (container) { + rl.pluginRemoteRequest((iError, oData) => { + if (!iError) { + const mainDivElement = Element.fromHTML('
' + + '' + + '
'); - rl.pluginRemoteRequest((iError, oData) => { - if (!iError) { - const books = JSON.parse(oData.Result.addressbooks); - books.forEach(book => { - this.addressBookList.push(book); + const selectElement = Element.fromHTML(''); - if (book.selected) { - this.selectedAddressBook(book.uri); - } - }); - - this.selectedAddressBook.subscribe(value => { - rl.pluginRemoteRequest(() => { }, 'NextcloudUpdateAddressBook', { - uri: value + const books = JSON.parse(oData.Result.addressbooks); + books.forEach(book => { + if (book.selected) { + selectElement.append(Element.fromHTML('')); + } else { + selectElement.append(Element.fromHTML('')); + } }); - }); - } - }, "JsonGetAddressbooks"); - } - } - rl.addSettingsViewModel( - AddressBookSettings, - 'AddressBookSettings', - 'NEXTCLOUD/ADDRESS_BOOK', - 'addressbook' - ); + selectElement.onchange = function() { + rl.pluginRemoteRequest(() => { }, 'NextcloudUpdateAddressBook', { + uri: selectElement.value + }); + } + + mainDivElement.append(selectElement); + container.append(mainDivElement); + } + }, "NextcloudGetAddressBooks"); + } + } + }); } })(window.rl); diff --git a/plugins/nextcloud/templates/AddressBookSettings.html b/plugins/nextcloud/templates/AddressBookSettings.html deleted file mode 100644 index e33682515..000000000 --- a/plugins/nextcloud/templates/AddressBookSettings.html +++ /dev/null @@ -1,12 +0,0 @@ -
-
AddressBook
-
- -
- - -
- -
-
From bda1c28eb76736701cc18605627efe45dc017670 Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Fri, 30 Aug 2024 15:58:34 +0600 Subject: [PATCH 3/8] fix: addressbook translation for nextcloud plugin --- plugins/nextcloud/langs/de.json | 2 +- plugins/nextcloud/langs/es.json | 5 +++++ plugins/nextcloud/langs/fr.json | 5 +++++ plugins/nextcloud/langs/it.json | 5 +++++ plugins/nextcloud/langs/pl.json | 3 +-- plugins/nextcloud/langs/ru.json | 3 +-- plugins/nextcloud/langs/zh-TW.json | 3 +-- plugins/nextcloud/langs/zh.json | 3 +-- 8 files changed, 20 insertions(+), 9 deletions(-) create mode 100644 plugins/nextcloud/langs/es.json create mode 100644 plugins/nextcloud/langs/fr.json create mode 100644 plugins/nextcloud/langs/it.json diff --git a/plugins/nextcloud/langs/de.json b/plugins/nextcloud/langs/de.json index a92d94b3c..35c92421d 100644 --- a/plugins/nextcloud/langs/de.json +++ b/plugins/nextcloud/langs/de.json @@ -10,6 +10,6 @@ "FILE_ATTACH": "anfügen", "FILE_INTERNAL": "intern", "FILE_PUBLIC": "öffentlich", - "ADDRESS_BOOK": "Address Book" + "ADDRESS_BOOK": "Adressbuch" } } diff --git a/plugins/nextcloud/langs/es.json b/plugins/nextcloud/langs/es.json new file mode 100644 index 000000000..652f67891 --- /dev/null +++ b/plugins/nextcloud/langs/es.json @@ -0,0 +1,5 @@ +{ + "NEXTCLOUD": { + "ADDRESS_BOOK": "Libreta de direcciones" + } +} diff --git a/plugins/nextcloud/langs/fr.json b/plugins/nextcloud/langs/fr.json new file mode 100644 index 000000000..6396152e6 --- /dev/null +++ b/plugins/nextcloud/langs/fr.json @@ -0,0 +1,5 @@ +{ + "NEXTCLOUD": { + "ADDRESS_BOOK": "Carnet d'adresses" + } +} diff --git a/plugins/nextcloud/langs/it.json b/plugins/nextcloud/langs/it.json new file mode 100644 index 000000000..7d3f183a1 --- /dev/null +++ b/plugins/nextcloud/langs/it.json @@ -0,0 +1,5 @@ +{ + "NEXTCLOUD": { + "ADDRESS_BOOK": "Rubrica" + } +} diff --git a/plugins/nextcloud/langs/pl.json b/plugins/nextcloud/langs/pl.json index 57f28aa50..82e0d4f18 100644 --- a/plugins/nextcloud/langs/pl.json +++ b/plugins/nextcloud/langs/pl.json @@ -9,7 +9,6 @@ "SELECT_CALENDAR": "Wybierz kalendarz", "FILE_ATTACH": "dołącz", "FILE_INTERNAL": "link wewnętrzny", - "FILE_PUBLIC": "link publiczny", - "ADDRESS_BOOK": "Address Book" + "FILE_PUBLIC": "link publiczny" } } diff --git a/plugins/nextcloud/langs/ru.json b/plugins/nextcloud/langs/ru.json index 4e7125770..a8b28372d 100644 --- a/plugins/nextcloud/langs/ru.json +++ b/plugins/nextcloud/langs/ru.json @@ -9,7 +9,6 @@ "SELECT_CALENDAR": "Выбрать календарь", "FILE_ATTACH": "Прикрепить с ПК", "FILE_INTERNAL": "Внутреняя", - "FILE_PUBLIC": "Публичная", - "ADDRESS_BOOK": "Address Book" + "FILE_PUBLIC": "Публичная" } } diff --git a/plugins/nextcloud/langs/zh-TW.json b/plugins/nextcloud/langs/zh-TW.json index 14f227645..292d02286 100644 --- a/plugins/nextcloud/langs/zh-TW.json +++ b/plugins/nextcloud/langs/zh-TW.json @@ -9,7 +9,6 @@ "SELECT_CALENDAR": "選擇日曆", "FILE_ATTACH": "附加", "FILE_INTERNAL": "內部", - "FILE_PUBLIC": "公開", - "ADDRESS_BOOK": "Address Book" + "FILE_PUBLIC": "公開" } } diff --git a/plugins/nextcloud/langs/zh.json b/plugins/nextcloud/langs/zh.json index 491221392..39b20ac2e 100644 --- a/plugins/nextcloud/langs/zh.json +++ b/plugins/nextcloud/langs/zh.json @@ -9,7 +9,6 @@ "SELECT_CALENDAR": "选择日历", "FILE_ATTACH": "附加", "FILE_INTERNAL": "内部", - "FILE_PUBLIC": "公开", - "ADDRESS_BOOK": "Address Book" + "FILE_PUBLIC": "公开" } } From 19ddcfbf3773aafb2b5d186dc9263d53c4538d59 Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Mon, 2 Sep 2024 18:41:08 +0600 Subject: [PATCH 4/8] feat: add admin settings for nextcloudAddressbook related changes --- plugins/nextcloud/NextcloudAddressBook.php | 28 ++++++--- plugins/nextcloud/index.php | 60 ++++++++++++++++--- .../nextcloud/js/hideInhouseAddressbook.js | 45 ++++++++++++++ 3 files changed, 116 insertions(+), 17 deletions(-) create mode 100644 plugins/nextcloud/js/hideInhouseAddressbook.js diff --git a/plugins/nextcloud/NextcloudAddressBook.php b/plugins/nextcloud/NextcloudAddressBook.php index aaccb0b31..a3d8c41fa 100644 --- a/plugins/nextcloud/NextcloudAddressBook.php +++ b/plugins/nextcloud/NextcloudAddressBook.php @@ -7,11 +7,21 @@ class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBoo use RainLoop\Providers\AddressBook\CardDAV; private $contactsManager; - private const DEFAULT_URI = 'webmail'; private const SETTINGS_KEY = 'nextCloudAddressBookUri'; - function __construct() + private string $defaultUri = 'webmail'; + private string $defaultName = 'WebMail'; + private string $defaultDescription = 'Recipients from snappymail'; + private bool $ignoreSystemAddressBook = true; + + + function __construct(string $defaultUri = 'webmail', string $defaultName = 'WebMail', string $defaultDescription = 'Recipients from snappymail', bool $ignoreSystemAddressBook = true) { + $this->defaultUri = $defaultUri; + $this->defaultName = $defaultName; + $this->defaultDescription = $defaultDescription; + $this->ignoreSystemAddressBook = $ignoreSystemAddressBook; + $this->GetSavedAddressBookKey(); } @@ -19,9 +29,11 @@ class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBoo { $this->contactsManager = \OC::$server->getContactsManager(); - foreach ($this->contactsManager->getUserAddressBooks() as $addressBook) { - if ($addressBook->isSystemAddressBook()) { - $this->contactsManager->unregisterAddressBook($addressBook); + if ($this->ignoreSystemAddressBook) { + foreach ($this->contactsManager->getUserAddressBooks() as $addressBook) { + if ($addressBook->isSystemAddressBook()) { + $this->contactsManager->unregisterAddressBook($addressBook); + } } } @@ -33,8 +45,8 @@ class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBoo if ($addressBookId === null) { return $cardDavBackend->createAddressBook($principalUri, $uri, array_filter([ - '{DAV:}displayname' => 'WebMail', - '{urn:ietf:params:xml:ns:carddav}addressbook-description' => 'Recipients from snappymail', + '{DAV:}displayname' => $this->defaultName, + '{urn:ietf:params:xml:ns:carddav}addressbook-description' => $this->defaultDescription, ])); } @@ -181,6 +193,6 @@ class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBoo private function GetSavedUri(): string { - return $this->Settings()->GetConf(self::SETTINGS_KEY, self::DEFAULT_URI); + return $this->Settings()->GetConf(self::SETTINGS_KEY, $this->defaultUri); } } diff --git a/plugins/nextcloud/index.php b/plugins/nextcloud/index.php index 09164fff0..337a295bb 100644 --- a/plugins/nextcloud/index.php +++ b/plugins/nextcloud/index.php @@ -11,6 +11,8 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin REQUIRED = '2.36.2'; + private const DEFAULT_ADDRESSBOOK_NAME = 'WebMail'; + private const DEFAULT_ADDRESSBOOK_DESCRIPTION = 'Recipients from snappymail'; private const DEFAULT_ADDRESSBOOK_URI = 'webmail'; private const ADDRESSBOOK_SETTINGS_KEY = 'nextCloudAddressBookUri'; @@ -46,9 +48,15 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin $this->addHook('smtp.before-login', 'beforeLogin'); $this->addHook('sieve.before-login', 'beforeLogin'); - $this->addJs('js/addressbook.js'); - $this->addJsonHook('NextcloudGetAddressBooks', 'GetAddressBooks'); - $this->addJsonHook('NextcloudUpdateAddressBook', 'UpdateAddressBook'); + if ($this->Config()->Get('plugin', 'enableNcAddressbook', false)) { + $this->addJs('js/addressbook.js'); + $this->addJsonHook('NextcloudGetAddressBooks', 'GetAddressBooks'); + $this->addJsonHook('NextcloudUpdateAddressBook', 'UpdateAddressBook'); + } + + if ($this->Config()->Get('plugin', 'disableInhouseAddressbook', false)) { + $this->addJs('js/hideInhouseAddressbook.js'); + } } else { \SnappyMail\Log::debug('Nextcloud', 'NOT integrated'); // \OC::$server->getConfig()->getAppValue('snappymail', 'snappymail-no-embed'); @@ -62,10 +70,12 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin $contactsManager = \OC::$server->getContactsManager(); - $selectedUri = $this->Settings()->GetConf(self::ADDRESSBOOK_SETTINGS_KEY, self::DEFAULT_ADDRESSBOOK_URI); + $defaultUri = $this->Config()->Get('plugin', 'defaultNCAddressbookUri', self::DEFAULT_ADDRESSBOOK_URI); + $selectedUri = $this->UserSettings()->GetConf(self::ADDRESSBOOK_SETTINGS_KEY, $defaultUri); + $ignoreSystemAddressbook = $this->Config()->Get('plugin', 'ignoreSystemAddressbook', true); foreach ($contactsManager->getUserAddressBooks() as $addressBook) { - if ($addressBook->isSystemAddressBook()) { + if ($ignoreSystemAddressbook && $addressBook->isSystemAddressBook()) { $contactsManager->unregisterAddressBook($addressBook); continue; } @@ -89,7 +99,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin public function UpdateAddressBook(): array { $uri = $this->jsonParam('uri'); - $oSettings = $this->Settings(); + $oSettings = $this->UserSettings(); if (\is_string($uri)) { $oSettings->SetConf(self::ADDRESSBOOK_SETTINGS_KEY, $uri); $this->SettingsProvider()->Save($this->Account(), $oSettings); @@ -422,12 +432,24 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin $this->Config()->Get('plugin', 'ignoreSystemAddressbook', true) ); } - if ('address-book' === $sName) { + + if ('address-book' === $sName && $this->Config()->Get('plugin', 'enableNcAddressbook', false)) { if (!\is_array($mResult)) { $mResult = array(); } include_once __DIR__ . '/NextcloudAddressBook.php'; - $mResult = new NextcloudAddressBook(); + + $ignoreSystemAddressbook = $this->Config()->Get('plugin', 'ignoreSystemAddressbook', true); + $defaultName = $this->Config()->Get('plugin', 'defaultNCAddressbookName', self::DEFAULT_ADDRESSBOOK_NAME); + $defaultDescription = $this->Config()->Get('plugin', 'defaultNCAddressbookDescription', self::DEFAULT_ADDRESSBOOK_DESCRIPTION); + $defaultUri = $this->Config()->Get('plugin', 'defaultNCAddressbookUri', self::DEFAULT_ADDRESSBOOK_URI); + + $mResult = new NextcloudAddressBook( + $defaultUri, + $defaultName, + $defaultDescription, + $ignoreSystemAddressbook + ); } /* if ($this->Config()->Get('plugin', 'storage', false) && ('storage' === $sName || 'storage-local' === $sName)) { @@ -453,6 +475,26 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin ->SetDefaultValue(false) */ \RainLoop\Plugins\Property::NewInstance('calendar')->SetLabel('Enable "Put ICS in calendar"') + ->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL) + ->SetDefaultValue(false), + + \RainLoop\Plugins\Property::NewInstance('enableNcAddressbook')->SetLabel('Enable User to choose Nextcloud addressbook for recipients') + ->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL) + ->SetDefaultValue(false), + + \RainLoop\Plugins\Property::NewInstance('defaultNCAddressbookUri')->SetLabel('Default nextcloud addressbook URI for recipinets') + ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING) + ->SetDefaultValue('webmail'), + + \RainLoop\Plugins\Property::NewInstance('defaultNCAddressbookName')->SetLabel('Default nextcloud addressbook Name for recipinets') + ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING) + ->SetDefaultValue(self::DEFAULT_ADDRESSBOOK_NAME), + + \RainLoop\Plugins\Property::NewInstance('defaultNCAddressbookDescription')->SetLabel('Default nextcloud addressbook description for recipinets') + ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING) + ->SetDefaultValue(self::DEFAULT_ADDRESSBOOK_DESCRIPTION), + + \RainLoop\Plugins\Property::NewInstance('disableInhouseAddressbook')->SetLabel('Disable SnappyMail internal addressbook. This is recomended if nextcloud addressbook is being used.') ->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL) ->SetDefaultValue(false) ); @@ -496,7 +538,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin return \RainLoop\Api::Actions()->SettingsProvider(true); } - private function Settings(): \RainLoop\Settings + private function UserSettings(): \RainLoop\Settings { return $this->SettingsProvider()->Load($this->Account()); } diff --git a/plugins/nextcloud/js/hideInhouseAddressbook.js b/plugins/nextcloud/js/hideInhouseAddressbook.js new file mode 100644 index 000000000..ed8197e18 --- /dev/null +++ b/plugins/nextcloud/js/hideInhouseAddressbook.js @@ -0,0 +1,45 @@ +(rl => { + if (rl) { + addEventListener('rl-view-model', e => { + if ('MailFolderList' === e.detail.viewModelTemplateID) { + const container = e.detail.viewModelDom.querySelector('.buttonContacts'); + if (container) { + container.remove(); + } + } + }); + + + addEventListener('rl-view-model', e => { + if ('SystemDropDown' === e.detail.viewModelTemplateID) { + const container = e.detail.viewModelDom.querySelector('.dropdown-menu'); + if (container) { + for (i = 0; i < container.children.length; i++) { + const element = container.children[i]; + const attr = element.getAttribute("data-bind"); + if (attr && attr.includes("visible: allowContacts")) { + element.remove(); + break; + } + } + } + } + }); + + addEventListener('rl-view-model', e => { + if ('PopupsCompose' === e.detail.viewModelTemplateID) { + const container = e.detail.viewModelDom.querySelector('.pull-right'); + if (container) { + for (i = 0; i < container.children.length; i++) { + const element = container.children[i]; + const attr = element.getAttribute("data-bind"); + if (attr && attr.includes("visible: allowContacts")) { + element.remove(); + break; + } + } + } + } + }); + } +})(window.rl); From 552a91acc2e7b51c4626d8307c03d9d0268fc48d Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Tue, 3 Sep 2024 12:37:37 +0600 Subject: [PATCH 5/8] chore: refactor nexcloud plugin- related to NC-addressbook --- plugins/nextcloud/NextcloudAddressBook.php | 109 ++++++++------ plugins/nextcloud/index.php | 138 ++++++++++-------- plugins/nextcloud/js/addressbook.js | 38 ----- .../nextcloud/js/hideInhouseAddressbook.js | 36 +++-- plugins/nextcloud/js/nextcloudAddressbook.js | 42 ++++++ 5 files changed, 200 insertions(+), 163 deletions(-) delete mode 100644 plugins/nextcloud/js/addressbook.js create mode 100644 plugins/nextcloud/js/nextcloudAddressbook.js diff --git a/plugins/nextcloud/NextcloudAddressBook.php b/plugins/nextcloud/NextcloudAddressBook.php index 7c8e4afb6..90a8331fe 100644 --- a/plugins/nextcloud/NextcloudAddressBook.php +++ b/plugins/nextcloud/NextcloudAddressBook.php @@ -5,15 +5,15 @@ use RainLoop\Providers\AddressBook\Classes\Contact; class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBookInterface { use RainLoop\Providers\AddressBook\CardDAV; - private $contactsManager; - private const SETTINGS_KEY = 'nextCloudAddressBookUri'; + private const SETTINGS_KEY = 'nextcloudAddressBookUri'; private string $defaultUri = 'webmail'; private string $defaultName = 'WebMail'; private string $defaultDescription = 'Recipients from snappymail'; private bool $ignoreSystemAddressBook = true; + private $contactsManager; function __construct(string $defaultUri = 'webmail', string $defaultName = 'WebMail', string $defaultDescription = 'Recipients from snappymail', bool $ignoreSystemAddressBook = true) { @@ -25,14 +25,21 @@ class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBoo $this->GetSavedAddressBookKey(); } - private function GetSavedAddressBookKey(): string + private function getContactsManager() { - $this->contactsManager = \OC::$server->getContactsManager(); + if ($this->contactsManager == null) { + $this->contactsManager = \OC::$server->getContactsManager(); + } + return $this->contactsManager; + } + + private function GetSavedAddressBookKey() : string + { if ($this->ignoreSystemAddressBook) { - foreach ($this->contactsManager->getUserAddressBooks() as $addressBook) { + foreach ($this->getContactsManager()->getUserAddressBooks() as $addressBook) { if ($addressBook->isSystemAddressBook()) { - $this->contactsManager->unregisterAddressBook($addressBook); + $this->getContactsManager()->unregisterAddressBook($addressBook); } } } @@ -53,63 +60,63 @@ class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBoo return $addressBookId['id']; } - public function IsSupported(): bool + public function IsSupported() : bool { // Maybe just return true, contacts app is just a frontend - //return \OC::$server->getAppManager()->isEnabledForUser('contacts'); + return \OC::$server->getAppManager()->isEnabledForUser('contacts'); + } + + public function SetEmail(string $sEmail) : bool + { return true; } - public function SetEmail(string $sEmail) : bool { - return true; - } - - public function Sync(): bool + public function Sync() : bool { return false; } - public function Export(string $sType = 'vcf'): bool + public function Export(string $sType = 'vcf') : bool { return false; } - public function ContactSave(Contact $oContact): bool + public function ContactSave(Contact $oContact) : bool { return false; } - public function DeleteContacts(array $aContactIds): bool + public function DeleteContacts(array $aContactIds) : bool { return false; } - public function DeleteAllContacts(string $sEmail): bool + public function DeleteAllContacts(string $sEmail) : bool { return false; } - public function GetContacts(int $iOffset = 0, int $iLimit = 20, string $sSearch = '', int &$iResultCount = 0): array + public function GetContacts(int $iOffset = 0, int $iLimit = 20, string $sSearch = '', int &$iResultCount = 0) : array { return []; } - public function GetContactByEmail(string $sEmail): ?Contact + public function GetContactByEmail(string $sEmail) : ?Contact { return null; } - public function GetContactByID($mID, bool $bIsStrID = false): ?Contact + public function GetContactByID($mID, bool $bIsStrID = false) : ?Contact { return null; } - public function GetSuggestions(string $sSearch, int $iLimit = 20): array + public function GetSuggestions(string $sSearch, int $iLimit = 20) : array { return []; } - private function GetEmailObjects(array $aEmails): array + private function GetEmailObjects(array $aEmails) : array { $aEmailsObjects = \array_map(function ($mItem) { $oResult = null; @@ -131,7 +138,7 @@ class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBoo * Add/increment email address usage * Handy for "most used" sorting suggestions in PdoAddressBook */ - public function IncFrec(array $aEmails, bool $bCreateAuto = true): bool + public function IncFrec(array $aEmails, bool $bCreateAuto = true) : bool { if ($bCreateAuto) { $aEmailsObjects = $this->GetEmailObjects($aEmails); @@ -139,53 +146,61 @@ class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBoo if (!count($aEmailsObjects)) { return false; } + foreach ($aEmailsObjects as $oEmail) { - if ('' === \trim($oEmail->GetEmail())) { - continue; - } - $sEmail = \trim($oEmail->GetEmail(true)); - $existingResults = $this->contactsManager->search($sEmail, ['EMAIL'], ['strict_search' => true]); - - if (!empty($existingResults)) { - continue; - } - - $properties = [ - 'EMAIL' => $sEmail, - 'FN' => $sEmail - ]; - - if ('' !== \trim($oEmail->GetDisplayName())) { - $properties['FN'] = $oEmail->GetDisplayName(); - } - $this->contactsManager->createOrUpdate($properties, $this->GetSavedAddressBookKey()); + $this->createOrUpdateContact($oEmail); } + return true; } + return false; } - public function Test(): string + private function createOrUpdateContact($oEmail) + { + if ('' === \trim($oEmail->GetEmail())) { + return; + } + $sEmail = \trim($oEmail->GetEmail(true)); + $existingResults = $this->getContactsManager()->search($sEmail, ['EMAIL'], ['strict_search' => true]); + + if (!empty($existingResults)) { + return; + } + + $properties = [ + 'EMAIL' => $sEmail, + 'FN' => $sEmail + ]; + + if ('' !== \trim($oEmail->GetDisplayName())) { + $properties['FN'] = $oEmail->GetDisplayName(); + } + $this->getContactsManager()->createOrUpdate($properties, $this->GetSavedAddressBookKey()); + } + + public function Test() : string { return ''; } - private function Account(): \RainLoop\Model\Account + private function Account() : \RainLoop\Model\Account { return \RainLoop\Api::Actions()->getAccountFromToken(); } - private function SettingsProvider(): \RainLoop\Providers\Settings + private function SettingsProvider() : \RainLoop\Providers\Settings { return \RainLoop\Api::Actions()->SettingsProvider(true); } - private function Settings(): \RainLoop\Settings + private function Settings() : \RainLoop\Settings { return $this->SettingsProvider()->Load($this->Account()); } - private function GetSavedUri(): string + private function GetSavedUri() : string { return $this->Settings()->GetConf(self::SETTINGS_KEY, $this->defaultUri); } diff --git a/plugins/nextcloud/index.php b/plugins/nextcloud/index.php index 229e534bd..28adf35fb 100644 --- a/plugins/nextcloud/index.php +++ b/plugins/nextcloud/index.php @@ -10,13 +10,27 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin DESCRIPTION = 'Integrate with Nextcloud v20+', REQUIRED = '2.36.2'; + private const IGNORE_SYSTEM_ADDRESSBOOK_KEY = 'ignoreSystemAddressbook'; + private const IGNORE_SYSTEM_ADDRESSBOOK_DEFAULT_VALUE = true; - private const DEFAULT_ADDRESSBOOK_NAME = 'WebMail'; - private const DEFAULT_ADDRESSBOOK_DESCRIPTION = 'Recipients from snappymail'; + private const ENABLE_NC_ADDRESSBOOK_KEY = 'enableNcAddressbook'; + private const ENABLE_NC_ADDRESSBOOK_DEFAULT_VALUE = false; + + private const DISABLE_INHOUSE_ADDRESSBOOK_KEY = 'disableSnappymailContactsUI'; + private const DISABLE_INHOUSE_ADDRESSBOOK_DEFAULT_VALUE = false; + + private const DEFAULT_ADDRESSBOOK_URI_KEY = 'defaultNCAddressbookUri'; private const DEFAULT_ADDRESSBOOK_URI = 'webmail'; - private const ADDRESSBOOK_SETTINGS_KEY = 'nextCloudAddressBookUri'; - public function Init(): void + private const DEFAULT_ADDRESSBOOK_NAME_KEY = 'defaultNCAddressbookName'; + private const DEFAULT_ADDRESSBOOK_NAME = 'WebMail'; + + private const DEFAULT_ADDRESSBOOK_DESCRIPTION_KEY = 'defaultNCAddressbookDescription'; + private const DEFAULT_ADDRESSBOOK_DESCRIPTION = 'Recipients from snappymail'; + + private const ADDRESSBOOK_SETTINGS_KEY = 'nextcloudAddressBookUri'; + + public function Init() : void { if (static::IsIntegrated()) { \SnappyMail\Log::debug('Nextcloud', 'integrated'); @@ -42,19 +56,19 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin $this->addTemplate('templates/PopupsNextcloudFiles.html'); $this->addTemplate('templates/PopupsNextcloudCalendars.html'); - // $this->addHook('login.credentials.step-2', 'loginCredentials2'); - // $this->addHook('login.credentials', 'loginCredentials'); +// $this->addHook('login.credentials.step-2', 'loginCredentials2'); +// $this->addHook('login.credentials', 'loginCredentials'); $this->addHook('imap.before-login', 'beforeLogin'); $this->addHook('smtp.before-login', 'beforeLogin'); $this->addHook('sieve.before-login', 'beforeLogin'); - if ($this->Config()->Get('plugin', 'enableNcAddressbook', false)) { - $this->addJs('js/addressbook.js'); + if ($this->Config()->Get('plugin', self::ENABLE_NC_ADDRESSBOOK_KEY, self::ENABLE_NC_ADDRESSBOOK_DEFAULT_VALUE)) { + $this->addJs('js/nextcloudAddressbook.js'); $this->addJsonHook('NextcloudGetAddressBooks', 'GetAddressBooks'); $this->addJsonHook('NextcloudUpdateAddressBook', 'UpdateAddressBook'); } - if ($this->Config()->Get('plugin', 'disableInhouseAddressbook', false)) { + if ($this->Config()->Get('plugin', self::DISABLE_INHOUSE_ADDRESSBOOK_KEY, self::DISABLE_INHOUSE_ADDRESSBOOK_DEFAULT_VALUE)) { $this->addJs('js/hideInhouseAddressbook.js'); } } else { @@ -70,9 +84,9 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin $contactsManager = \OC::$server->getContactsManager(); - $defaultUri = $this->Config()->Get('plugin', 'defaultNCAddressbookUri', self::DEFAULT_ADDRESSBOOK_URI); + $defaultUri = $this->Config()->Get('plugin', self::DEFAULT_ADDRESSBOOK_URI_KEY, self::DEFAULT_ADDRESSBOOK_URI); $selectedUri = $this->UserSettings()->GetConf(self::ADDRESSBOOK_SETTINGS_KEY, $defaultUri); - $ignoreSystemAddressbook = $this->Config()->Get('plugin', 'ignoreSystemAddressbook', true); + $ignoreSystemAddressbook = $this->Config()->Get('plugin', self::IGNORE_SYSTEM_ADDRESSBOOK_KEY, self::IGNORE_SYSTEM_ADDRESSBOOK_DEFAULT_VALUE); foreach ($contactsManager->getUserAddressBooks() as $addressBook) { if ($ignoreSystemAddressbook && $addressBook->isSystemAddressBook()) { @@ -96,7 +110,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin )); } - public function UpdateAddressBook(): array + public function UpdateAddressBook() : array { $uri = $this->jsonParam('uri'); $oSettings = $this->UserSettings(); @@ -115,7 +129,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin } } - public function Supported(): string + public function Supported() : string { return static::IsIntegrated() ? '' : 'Nextcloud not found to use this plugin'; } @@ -130,24 +144,24 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin return static::IsIntegrated() && \OC::$server->getUserSession()->isLoggedIn(); } - public function loginCredentials(string &$sEmail, string &$sLogin, ?string &$sPassword = null): void + public function loginCredentials(string &$sEmail, string &$sLogin, ?string &$sPassword = null) : void { /** * This has an issue. * When user changes email address, all settings are gone as the new * _data_/_default_/storage/{domain}/{local-part} is used */ - // $ocUser = \OC::$server->getUserSession()->getUser(); - // $sEmail = $ocUser->getEMailAddress() ?: $ocUser->getPrimaryEMailAddress() ?: $sEmail; +// $ocUser = \OC::$server->getUserSession()->getUser(); +// $sEmail = $ocUser->getEMailAddress() ?: $ocUser->getPrimaryEMailAddress() ?: $sEmail; } - public function loginCredentials2(string &$sEmail, ?string &$sPassword = null): void + public function loginCredentials2(string &$sEmail, ?string &$sPassword = null) : void { $ocUser = \OC::$server->getUserSession()->getUser(); $sEmail = $ocUser->getEMailAddress() ?: $ocUser->getPrimaryEMailAddress() ?: $sEmail; } - public function beforeLogin(\RainLoop\Model\Account $oAccount, \MailSo\Net\NetClient $oClient, \MailSo\Net\ConnectSettings $oSettings): void + public function beforeLogin(\RainLoop\Model\Account $oAccount, \MailSo\Net\NetClient $oClient, \MailSo\Net\ConnectSettings $oSettings) : void { // https://apps.nextcloud.com/apps/oidc_login $config = \OC::$server->getConfig(); @@ -164,12 +178,11 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin // Only login with OIDC access token if // it is enabled in config, the user is currently logged in with OIDC, // the current snappymail account is the OIDC account and no account defined explicitly - if ( - \OC::$server->getConfig()->getAppValue('snappymail', 'snappymail-autologin-oidc', false) - && \OC::$server->getSession()->get('is_oidc') - && $sNcEmail === $oSettings->username - && !$bAccountDefinedExplicitly - // && $oClient->supportsAuthType('OAUTHBEARER') // v2.28 + if (\OC::$server->getConfig()->getAppValue('snappymail', 'snappymail-autologin-oidc', false) + && \OC::$server->getSession()->get('is_oidc') + && $sNcEmail === $oSettings->username + && !$bAccountDefinedExplicitly +// && $oClient->supportsAuthType('OAUTHBEARER') // v2.28 ) { $sAccessToken = \OC::$server->getSession()->get('oidc_access_token'); if ($sAccessToken) { @@ -184,7 +197,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin \OC::$server->getLDAPProvider(); */ - public function NextcloudAttachFile(): array + public function NextcloudAttachFile() : array { $aResult = [ 'success' => false, @@ -208,10 +221,10 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin return $this->jsonResponse(__FUNCTION__, $aResult); } - public function NextcloudSaveMsg(): array + public function NextcloudSaveMsg() : array { $sSaveFolder = \ltrim($this->jsonParam('folder', ''), '/'); - // $aValues = \RainLoop\Api::Actions()->decodeRawKey($this->jsonParam('msgHash', '')); +// $aValues = \RainLoop\Api::Actions()->decodeRawKey($this->jsonParam('msgHash', '')); $msgHash = $this->jsonParam('msgHash', ''); $aValues = \json_decode(\MailSo\Base\Utils::UrlSafeBase64Decode($msgHash), true); $aResult = [ @@ -265,14 +278,14 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin foreach ($data->items as $aItem) { $sSavedFileName = empty($aItem['fileName']) ? 'file.dat' : $aItem['fileName']; if (!empty($aItem['data'])) { - $sSavedFileNameFull = static::SmartFileExists($sSaveFolder . '/' . $sSavedFileName, $oFiles); + $sSavedFileNameFull = static::SmartFileExists($sSaveFolder.'/'.$sSavedFileName, $oFiles); if (!$oFiles->file_put_contents($sSavedFileNameFull, $aItem['data'])) { $data->result = false; } } else if (!empty($aItem['fileHash'])) { $fFile = $data->filesProvider->GetFile($data->account, $aItem['fileHash'], 'rb'); if (\is_resource($fFile)) { - $sSavedFileNameFull = static::SmartFileExists($sSaveFolder . '/' . $sSavedFileName, $oFiles); + $sSavedFileNameFull = static::SmartFileExists($sSaveFolder.'/'.$sSavedFileName, $oFiles); if (!$oFiles->file_put_contents($sSavedFileNameFull, $fFile)) { $data->result = false; } @@ -286,19 +299,19 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin } } - public function FilterAppData($bAdmin, &$aResult): void + public function FilterAppData($bAdmin, &$aResult) : void { if (!$bAdmin && \is_array($aResult)) { $ocUser = \OC::$server->getUserSession()->getUser(); $sUID = $ocUser->getUID(); $oUrlGen = \OC::$server->getURLGenerator(); $sWebDAV = $oUrlGen->getAbsoluteURL($oUrlGen->linkTo('', 'remote.php') . '/dav'); - // $sWebDAV = \OCP\Util::linkToRemote('dav'); +// $sWebDAV = \OCP\Util::linkToRemote('dav'); $aResult['Nextcloud'] = [ 'UID' => $sUID, 'WebDAV' => $sWebDAV, 'CalDAV' => $this->Config()->Get('plugin', 'calendar', false) - // 'WebDAV_files' => $sWebDAV . '/files/' . $sUID +// 'WebDAV_files' => $sWebDAV . '/files/' . $sUID ]; if (empty($aResult['Auth'])) { $config = \OC::$server->getConfig(); @@ -320,9 +333,9 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin } if (!$sEmail) { $sEmail = $ocUser->getEMailAddress(); - // ?: $ocUser->getPrimaryEMailAddress(); +// ?: $ocUser->getPrimaryEMailAddress(); } - /* +/* if ($config->getAppValue('snappymail', 'snappymail-autologin-oidc', false)) { if (\OC::$server->getSession()->get('is_oidc')) { $sEmail = "{$sUID}@nextcloud"; @@ -369,7 +382,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin } } - public function FilterLanguage(&$sLanguage, $bAdmin): void + public function FilterLanguage(&$sLanguage, $bAdmin) : void { if (!\RainLoop\Api::Config()->Get('webmail', 'allow_languages_on_settings', true)) { $aResultLang = \SnappyMail\L10n::getLanguages($bAdmin); @@ -392,7 +405,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin * * @return string return locale */ - private function determineLocale(string $langCode, array $languagesArray): ?string + private function determineLocale(string $langCode, array $languagesArray) : ?string { // Direct check for the language code if (\in_array($langCode, $languagesArray)) { @@ -429,20 +442,20 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin } include_once __DIR__ . '/NextcloudContactsSuggestions.php'; $mResult[] = new NextcloudContactsSuggestions( - $this->Config()->Get('plugin', 'ignoreSystemAddressbook', true) + $this->Config()->Get('plugin', self::IGNORE_SYSTEM_ADDRESSBOOK_KEY, self::IGNORE_SYSTEM_ADDRESSBOOK_DEFAULT_VALUE) ); } - if ('address-book' === $sName && $this->Config()->Get('plugin', 'enableNcAddressbook', false)) { + if ('address-book' === $sName && $this->Config()->Get('plugin', self::ENABLE_NC_ADDRESSBOOK_KEY, self::ENABLE_NC_ADDRESSBOOK_DEFAULT_VALUE)) { if (!\is_array($mResult)) { $mResult = array(); } include_once __DIR__ . '/NextcloudAddressBook.php'; - $ignoreSystemAddressbook = $this->Config()->Get('plugin', 'ignoreSystemAddressbook', true); - $defaultName = $this->Config()->Get('plugin', 'defaultNCAddressbookName', self::DEFAULT_ADDRESSBOOK_NAME); - $defaultDescription = $this->Config()->Get('plugin', 'defaultNCAddressbookDescription', self::DEFAULT_ADDRESSBOOK_DESCRIPTION); - $defaultUri = $this->Config()->Get('plugin', 'defaultNCAddressbookUri', self::DEFAULT_ADDRESSBOOK_URI); + $ignoreSystemAddressbook = $this->Config()->Get('plugin', self::IGNORE_SYSTEM_ADDRESSBOOK_KEY, self::IGNORE_SYSTEM_ADDRESSBOOK_DEFAULT_VALUE); + $defaultName = $this->Config()->Get('plugin', self::DEFAULT_ADDRESSBOOK_NAME_KEY, self::DEFAULT_ADDRESSBOOK_NAME); + $defaultDescription = $this->Config()->Get('plugin', self::DEFAULT_ADDRESSBOOK_DESCRIPTION_KEY, self::DEFAULT_ADDRESSBOOK_DESCRIPTION); + $defaultUri = $this->Config()->Get('plugin', self::DEFAULT_ADDRESSBOOK_URI_KEY, self::DEFAULT_ADDRESSBOOK_URI); $mResult = new NextcloudAddressBook( $defaultUri, @@ -460,16 +473,16 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin } } - protected function configMapping(): array + protected function configMapping() : array { return array( \RainLoop\Plugins\Property::NewInstance('suggestions')->SetLabel('Suggestions') ->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL) ->SetDefaultValue(true), - \RainLoop\Plugins\Property::NewInstance('ignoreSystemAddressbook')->SetLabel('Ignore system addressbook') + \RainLoop\Plugins\Property::NewInstance(self::IGNORE_SYSTEM_ADDRESSBOOK_KEY)->SetLabel('Ignore system addressbook') ->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL) - ->SetDefaultValue(true), - /* + ->SetDefaultValue(self::IGNORE_SYSTEM_ADDRESSBOOK_DEFAULT_VALUE), +/* \RainLoop\Plugins\Property::NewInstance('storage')->SetLabel('Use Nextcloud user ID in config storage path') ->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL) ->SetDefaultValue(false) @@ -478,29 +491,29 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin ->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL) ->SetDefaultValue(false), - \RainLoop\Plugins\Property::NewInstance('enableNcAddressbook')->SetLabel('Enable User to choose Nextcloud addressbook for recipients') + \RainLoop\Plugins\Property::NewInstance(self::ENABLE_NC_ADDRESSBOOK_KEY)->SetLabel('Enable User to choose Nextcloud addressbook for recipients') ->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL) - ->SetDefaultValue(false), + ->SetDefaultValue(self::ENABLE_NC_ADDRESSBOOK_DEFAULT_VALUE), - \RainLoop\Plugins\Property::NewInstance('defaultNCAddressbookUri')->SetLabel('Default nextcloud addressbook URI for recipinets') + \RainLoop\Plugins\Property::NewInstance(self::DEFAULT_ADDRESSBOOK_URI_KEY)->SetLabel('Default nextcloud addressbook URI for recipinets') ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING) - ->SetDefaultValue('webmail'), + ->SetDefaultValue(self::DEFAULT_ADDRESSBOOK_URI), - \RainLoop\Plugins\Property::NewInstance('defaultNCAddressbookName')->SetLabel('Default nextcloud addressbook Name for recipinets') + \RainLoop\Plugins\Property::NewInstance(self::DEFAULT_ADDRESSBOOK_NAME_KEY)->SetLabel('Default nextcloud addressbook Name for recipinets') ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING) ->SetDefaultValue(self::DEFAULT_ADDRESSBOOK_NAME), - \RainLoop\Plugins\Property::NewInstance('defaultNCAddressbookDescription')->SetLabel('Default nextcloud addressbook description for recipinets') + \RainLoop\Plugins\Property::NewInstance(self::DEFAULT_ADDRESSBOOK_DESCRIPTION_KEY)->SetLabel('Default nextcloud addressbook description for recipinets') ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING) ->SetDefaultValue(self::DEFAULT_ADDRESSBOOK_DESCRIPTION), - \RainLoop\Plugins\Property::NewInstance('disableInhouseAddressbook')->SetLabel('Disable SnappyMail internal addressbook. This is recomended if nextcloud addressbook is being used.') + \RainLoop\Plugins\Property::NewInstance(self::DISABLE_INHOUSE_ADDRESSBOOK_KEY)->SetLabel('Disable SnappyMail internal addressbook. This is recomended if nextcloud addressbook is being used.') ->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL) - ->SetDefaultValue(false) + ->SetDefaultValue(self::DISABLE_INHOUSE_ADDRESSBOOK_DEFAULT_VALUE) ); } - private static function SmartFileExists(string $sFilePath, $oFiles): string + private static function SmartFileExists(string $sFilePath, $oFiles) : string { $sFilePath = \str_replace('\\', '/', \trim($sFilePath)); @@ -514,10 +527,11 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin while (true) { ++$iIndex; - $sFilePathNew = $aFileInfo['dirname'] . '/' . - \preg_replace('/\(\d{1,2}\)$/', '', $aFileInfo['filename']) . - ' (' . $iIndex . ')' . - (empty($aFileInfo['extension']) ? '' : '.' . $aFileInfo['extension']); + $sFilePathNew = $aFileInfo['dirname'].'/'. + \preg_replace('/\(\d{1,2}\)$/', '', $aFileInfo['filename']). + ' ('.$iIndex.')'. + (empty($aFileInfo['extension']) ? '' : '.'.$aFileInfo['extension']) + ; if (!$oFiles->file_exists($sFilePathNew)) { return $sFilePathNew; } @@ -528,17 +542,17 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin return $sFilePath; } - private function Account(): \RainLoop\Model\Account + private function Account() : \RainLoop\Model\Account { return \RainLoop\Api::Actions()->getAccountFromToken(); } - private function SettingsProvider(): \RainLoop\Providers\Settings + private function SettingsProvider() : \RainLoop\Providers\Settings { return \RainLoop\Api::Actions()->SettingsProvider(true); } - private function UserSettings(): \RainLoop\Settings + private function UserSettings() : \RainLoop\Settings { return $this->SettingsProvider()->Load($this->Account()); } diff --git a/plugins/nextcloud/js/addressbook.js b/plugins/nextcloud/js/addressbook.js deleted file mode 100644 index c871c0928..000000000 --- a/plugins/nextcloud/js/addressbook.js +++ /dev/null @@ -1,38 +0,0 @@ -(rl => { - if (rl) { - addEventListener('rl-view-model', e => { - if ('SettingsContacts' === e.detail.viewModelTemplateID) { - const container = e.detail.viewModelDom.querySelector('.form-horizontal'); - if (container) { - rl.pluginRemoteRequest((iError, oData) => { - if (!iError) { - const mainDivElement = Element.fromHTML('
' - + '' - + '
'); - - const selectElement = Element.fromHTML(''); - - const books = JSON.parse(oData.Result.addressbooks); - books.forEach(book => { - if (book.selected) { - selectElement.append(Element.fromHTML('')); - } else { - selectElement.append(Element.fromHTML('')); - } - }); - - selectElement.onchange = function() { - rl.pluginRemoteRequest(() => { }, 'NextcloudUpdateAddressBook', { - uri: selectElement.value - }); - } - - mainDivElement.append(selectElement); - container.append(mainDivElement); - } - }, "NextcloudGetAddressBooks"); - } - } - }); - } -})(window.rl); diff --git a/plugins/nextcloud/js/hideInhouseAddressbook.js b/plugins/nextcloud/js/hideInhouseAddressbook.js index ed8197e18..37feb7dc9 100644 --- a/plugins/nextcloud/js/hideInhouseAddressbook.js +++ b/plugins/nextcloud/js/hideInhouseAddressbook.js @@ -13,14 +13,16 @@ addEventListener('rl-view-model', e => { if ('SystemDropDown' === e.detail.viewModelTemplateID) { const container = e.detail.viewModelDom.querySelector('.dropdown-menu'); - if (container) { - for (i = 0; i < container.children.length; i++) { - const element = container.children[i]; - const attr = element.getAttribute("data-bind"); - if (attr && attr.includes("visible: allowContacts")) { - element.remove(); - break; - } + if (!container) { + return; + } + + for (i = 0; i < container.children.length; i++) { + const element = container.children[i]; + const attr = element.getAttribute("data-bind"); + if (attr && attr.includes("visible: allowContacts")) { + element.remove(); + break; } } } @@ -29,14 +31,16 @@ addEventListener('rl-view-model', e => { if ('PopupsCompose' === e.detail.viewModelTemplateID) { const container = e.detail.viewModelDom.querySelector('.pull-right'); - if (container) { - for (i = 0; i < container.children.length; i++) { - const element = container.children[i]; - const attr = element.getAttribute("data-bind"); - if (attr && attr.includes("visible: allowContacts")) { - element.remove(); - break; - } + if(!container) { + return; + } + + for (i = 0; i < container.children.length; i++) { + const element = container.children[i]; + const attr = element.getAttribute("data-bind"); + if (attr && attr.includes("visible: allowContacts")) { + element.remove(); + break; } } } diff --git a/plugins/nextcloud/js/nextcloudAddressbook.js b/plugins/nextcloud/js/nextcloudAddressbook.js new file mode 100644 index 000000000..0c3684ce0 --- /dev/null +++ b/plugins/nextcloud/js/nextcloudAddressbook.js @@ -0,0 +1,42 @@ +(rl => { + if (rl) { + addEventListener('rl-view-model', e => { + if ('SettingsContacts' === e.detail.viewModelTemplateID) { + const container = e.detail.viewModelDom.querySelector('.form-horizontal'); + if (!container) { + return; + } + + rl.pluginRemoteRequest((iError, oData) => { + if (iError) { + return; + } + + const mainDivElement = Element.fromHTML('
' + + '' + + '
'); + + const selectElement = Element.fromHTML(''); + + const addressbooks = JSON.parse(oData.Result.addressbooks); + addressbooks.forEach(addressbook => { + if (addressbook.selected) { + selectElement.append(Element.fromHTML('')); + } else { + selectElement.append(Element.fromHTML('')); + } + }); + + selectElement.onchange = function() { + rl.pluginRemoteRequest(() => { }, 'NextcloudUpdateAddressBook', { + uri: selectElement.value + }); + } + + mainDivElement.append(selectElement); + container.append(mainDivElement); + }, "NextcloudGetAddressBooks"); + } + }); + } +})(window.rl); From e5044ff10a5161a479577b790c8a9485434ed635 Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Tue, 3 Sep 2024 13:07:29 +0000 Subject: [PATCH 6/8] Apply suggestions from code review Co-authored-by: Akhil Potukuchi --- plugins/nextcloud/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/nextcloud/index.php b/plugins/nextcloud/index.php index 28adf35fb..5f419c7b2 100644 --- a/plugins/nextcloud/index.php +++ b/plugins/nextcloud/index.php @@ -503,7 +503,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING) ->SetDefaultValue(self::DEFAULT_ADDRESSBOOK_NAME), - \RainLoop\Plugins\Property::NewInstance(self::DEFAULT_ADDRESSBOOK_DESCRIPTION_KEY)->SetLabel('Default nextcloud addressbook description for recipinets') + \RainLoop\Plugins\Property::NewInstance(self::DEFAULT_ADDRESSBOOK_DESCRIPTION_KEY)->SetLabel('Default nextcloud addressbook description for recipients') ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING) ->SetDefaultValue(self::DEFAULT_ADDRESSBOOK_DESCRIPTION), From dff305e64562385b9303a10a60d6dab68645cfa3 Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Tue, 3 Sep 2024 19:15:19 +0600 Subject: [PATCH 7/8] refactor: remove repeated variable initialization --- plugins/nextcloud/NextcloudAddressBook.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/plugins/nextcloud/NextcloudAddressBook.php b/plugins/nextcloud/NextcloudAddressBook.php index 90a8331fe..5e9f27c87 100644 --- a/plugins/nextcloud/NextcloudAddressBook.php +++ b/plugins/nextcloud/NextcloudAddressBook.php @@ -8,11 +8,10 @@ class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBoo private const SETTINGS_KEY = 'nextcloudAddressBookUri'; - private string $defaultUri = 'webmail'; - private string $defaultName = 'WebMail'; - private string $defaultDescription = 'Recipients from snappymail'; - private bool $ignoreSystemAddressBook = true; - + private string $defaultUri; + private string $defaultName; + private string $defaultDescription; + private bool $ignoreSystemAddressBook; private $contactsManager; function __construct(string $defaultUri = 'webmail', string $defaultName = 'WebMail', string $defaultDescription = 'Recipients from snappymail', bool $ignoreSystemAddressBook = true) From 943b2560c1a56f6a038c8873ef39cb578b1b2d7c Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Tue, 3 Sep 2024 19:36:37 +0600 Subject: [PATCH 8/8] chore: add Readme file for nextcloud plugin + fix typo --- plugins/nextcloud/README.md | 14 ++++++++++++++ plugins/nextcloud/index.php | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 plugins/nextcloud/README.md diff --git a/plugins/nextcloud/README.md b/plugins/nextcloud/README.md new file mode 100644 index 000000000..fc2c6ed37 --- /dev/null +++ b/plugins/nextcloud/README.md @@ -0,0 +1,14 @@ +# SnappyMail plugin for nextcloud + +## Nextcloud Addressbook for recipients + +This plugin can let user to choose which nextcloud addressbook to use save recipients. This is opt-in feature (enabled by admin). After admin enable this, user will find a dropdown in his/her SnappyMail's `Contacts` section, containing all his/her addressbook. + +### Admin settings + +- `enableNcAddressbook` : Enable User to choose Nextcloud addressbook for recipients. Default value: `false` +- `disableSnappymailContactsUI` : Disable SnappyMail internal addressbook. This is recomended if nextcloud addressbook is being used. Default value: `false` +- `defaultNCAddressbookUri` : Default nextcloud addressbook URI for recipients. Default value: `webmail` +- `defaultNCAddressbookName` : Default nextcloud addressbook Name for recipients. Default value: `WebMail` +- `defaultNCAddressbookDescription` : Default nextcloud addressbook description for recipients. Default value: `Recipients from snappymail` + diff --git a/plugins/nextcloud/index.php b/plugins/nextcloud/index.php index 5f419c7b2..578604345 100644 --- a/plugins/nextcloud/index.php +++ b/plugins/nextcloud/index.php @@ -495,11 +495,11 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin ->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL) ->SetDefaultValue(self::ENABLE_NC_ADDRESSBOOK_DEFAULT_VALUE), - \RainLoop\Plugins\Property::NewInstance(self::DEFAULT_ADDRESSBOOK_URI_KEY)->SetLabel('Default nextcloud addressbook URI for recipinets') + \RainLoop\Plugins\Property::NewInstance(self::DEFAULT_ADDRESSBOOK_URI_KEY)->SetLabel('Default nextcloud addressbook URI for recipients') ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING) ->SetDefaultValue(self::DEFAULT_ADDRESSBOOK_URI), - \RainLoop\Plugins\Property::NewInstance(self::DEFAULT_ADDRESSBOOK_NAME_KEY)->SetLabel('Default nextcloud addressbook Name for recipinets') + \RainLoop\Plugins\Property::NewInstance(self::DEFAULT_ADDRESSBOOK_NAME_KEY)->SetLabel('Default nextcloud addressbook Name for recipients') ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING) ->SetDefaultValue(self::DEFAULT_ADDRESSBOOK_NAME),