Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nextcloud address book #1227

Open
wants to merge 35 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
edb1bf2
Attempt to add basic nextcloud addressbook
akhil1508 Aug 3, 2023
65521c5
Check if array
akhil1508 Aug 3, 2023
1ee07bb
Remove unused imports
akhil1508 Aug 3, 2023
5d04ca5
convert results from nc to sm contacts
akhil1508 Aug 3, 2023
2f7d121
Copy incfrec from kolab
akhil1508 Aug 3, 2023
147ba65
Keep only incfrec
akhil1508 Aug 3, 2023
dc6e93a
create addressbook if not already exists
Niveshkrishna Aug 15, 2023
b0a6d3b
fix addressbookid
Niveshkrishna Aug 15, 2023
6f61b06
add firstname to contacts
Niveshkrishna Aug 24, 2023
8a4eabe
Add IsExternal for external contact sources
akhil1508 Aug 31, 2023
b84487f
Fix IncFrec logic to actually create or update
akhil1508 Aug 31, 2023
ae7e008
Merge branch 'master' of https://github.com/Murena-SAS/snappymail int…
akhil1508 Sep 4, 2023
d77e863
Bump version to 3.0
akhil1508 Sep 4, 2023
46cfa9f
Unregister system addressbook
akhil1508 Sep 4, 2023
cc25129
Fix namespace and FN default
akhil1508 Sep 8, 2023
3c7ef4d
Fix issue when contact is found in some other addressbook
akhil1508 Jan 19, 2024
cdaa4b1
Do not save contact if it already exists
akhil1508 Jan 19, 2024
957654c
Merge branch 'upstream/master' into dev/sync-nextcloud-addressbook
Aug 23, 2024
500b997
feat: add addressBook user settings section for nextcloud plugin
Aug 29, 2024
a47cc45
feat: move nextcloud addressbook user settings under contatcs setting…
Aug 30, 2024
bda1c28
fix: addressbook translation for nextcloud plugin
Aug 30, 2024
0c9e471
Remove IsExternal
akhil1508 Sep 2, 2024
022bf43
Remove extra space
akhil1508 Sep 2, 2024
f4ad959
Resolve merge conflicts
akhil1508 Sep 2, 2024
19ddcfb
feat: add admin settings for nextcloudAddressbook related changes
Sep 2, 2024
2e3fbe0
Merge branch 'dev/sync-nextcloud-addressbook' into draft/dev_sync-nex…
Sep 3, 2024
552a91a
chore: refactor nexcloud plugin- related to NC-addressbook
Sep 3, 2024
e5044ff
Apply suggestions from code review
fahim44 Sep 3, 2024
dff305e
refactor: remove repeated variable initialization
Sep 3, 2024
943b256
chore: add Readme file for nextcloud plugin + fix typo
Sep 3, 2024
098cc82
Merge pull request #2 from Murena-SAS/draft/dev_sync-nextcloud-addres…
fahim44 Sep 3, 2024
cf870df
fix: remove Nextcloud contacts app direct dependency on nextcloud plugin
Sep 5, 2024
2b8f49f
Merge branch 'master' into dev/sync-nextcloud-addressbook
fahim44 Sep 24, 2024
8b6adb3
Update README.md
fahim44 Sep 24, 2024
721a849
Merge branch 'master' into dev/sync-nextcloud-addressbook
fahim44 Oct 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 206 additions & 0 deletions plugins/nextcloud/NextcloudAddressBook.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
<?php

use RainLoop\Providers\AddressBook\Classes\Contact;

class NextcloudAddressBook implements \RainLoop\Providers\AddressBook\AddressBookInterface
{
use RainLoop\Providers\AddressBook\CardDAV;

private const SETTINGS_KEY = 'nextcloudAddressBookUri';

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)
{
$this->defaultUri = $defaultUri;
$this->defaultName = $defaultName;
$this->defaultDescription = $defaultDescription;
$this->ignoreSystemAddressBook = $ignoreSystemAddressBook;

$this->GetSavedAddressBookKey();
}

private function getContactsManager()
{
if ($this->contactsManager == null) {
$this->contactsManager = \OC::$server->getContactsManager();
}

return $this->contactsManager;
}

private function GetSavedAddressBookKey() : string
{
if ($this->ignoreSystemAddressBook) {
foreach ($this->getContactsManager()->getUserAddressBooks() as $addressBook) {
if ($addressBook->isSystemAddressBook()) {
$this->getContactsManager()->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) {
return $cardDavBackend->createAddressBook($principalUri, $uri, array_filter([
'{DAV:}displayname' => $this->defaultName,
'{urn:ietf:params:xml:ns:carddav}addressbook-description' => $this->defaultDescription,
]));
}

return $addressBookId['id'];
}

public function IsSupported() : bool
{
// Maybe just return true, contacts app is just a frontend
akhil1508 marked this conversation as resolved.
Show resolved Hide resolved
return \OC::$server->getAppManager()->isEnabledForUser('contacts');
}

public function SetEmail(string $sEmail) : bool
{
return true;
}

public function Sync() : bool
{
return false;
}

public function Export(string $sType = 'vcf') : bool
{
return false;
}

public function ContactSave(Contact $oContact) : bool
{
return false;
}

public function DeleteContacts(array $aContactIds) : bool
{
return false;
}

public function DeleteAllContacts(string $sEmail) : bool
{
return false;
}

public function GetContacts(int $iOffset = 0, int $iLimit = 20, string $sSearch = '', int &$iResultCount = 0) : array
{
return [];
}

public function GetContactByEmail(string $sEmail) : ?Contact
{
return null;
}

public function GetContactByID($mID, bool $bIsStrID = false) : ?Contact
{
return null;
}

public function GetSuggestions(string $sSearch, int $iLimit = 20) : array
{
return [];
}

private function GetEmailObjects(array $aEmails) : array
{
$aEmailsObjects = \array_map(function ($mItem) {
$oResult = null;
try {
$oResult = \MailSo\Mime\Email::Parse(\trim($mItem));
} catch (\Throwable $oException) {
unset($oException);
}
return $oResult;
}, $aEmails);

$aEmailsObjects = \array_filter($aEmailsObjects, function ($oItem) {
return !!$oItem;
});
return $aEmailsObjects;
}

/**
* Add/increment email address usage
* Handy for "most used" sorting suggestions in PdoAddressBook
*/
public function IncFrec(array $aEmails, bool $bCreateAuto = true) : bool
{
if ($bCreateAuto) {
$aEmailsObjects = $this->GetEmailObjects($aEmails);

if (!count($aEmailsObjects)) {
return false;
}

foreach ($aEmailsObjects as $oEmail) {
$this->createOrUpdateContact($oEmail);
}

return true;
}

return false;
}

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
{
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(self::SETTINGS_KEY, $this->defaultUri);
}
}
14 changes: 14 additions & 0 deletions plugins/nextcloud/README.md
Original file line number Diff line number Diff line change
@@ -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.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fahim44 Could be nice to mention that it works best with Nextcloud Contacts where contacts app is used as the frontend for contacts(browsing, editing etc) and SnappyMail seamlessly integrates with it to provide email autocomplete suggestions when drafting emails (not in this PR) and save emails to Nextcloud Contacts upon sending.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akhil1508 updated the README


### 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`

Loading