summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.editorconfig9
-rw-r--r--.tx (renamed from .tx/config)0
-rw-r--r--appinfo/info.xml5
-rw-r--r--appinfo/routes.php6
-rw-r--r--lib/Controller/PageController.php38
-rw-r--r--lib/Controller/SocialApiController.php48
-rw-r--r--lib/Cron/SocialUpdate.php42
-rw-r--r--lib/Cron/SocialUpdateRegistration.php93
-rw-r--r--lib/Service/SocialApiService.php139
-rw-r--r--lib/Settings/AdminSettings.php3
-rw-r--r--src/components/AdminSettings.vue24
-rw-r--r--src/components/SettingsSection.vue30
-rw-r--r--tests/unit/Controller/PageControllerTest.php12
-rw-r--r--tests/unit/Service/SocialApiServiceTest.php159
14 files changed, 581 insertions, 27 deletions
diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 198996b9..00000000
--- a/.editorconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-root = true
-
-[*]
-charset = utf-8
-indent_style = tab
-indent_size = 4
-end_of_line = lf
-insert_final_newline = true
-trim_trailing_whitespace = true
diff --git a/.tx/config b/.tx
index c437937d..c437937d 100644
--- a/.tx/config
+++ b/.tx
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 5fa7b3bf..1a943d67 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -51,7 +51,12 @@
</navigation>
</navigations>
+ <background-jobs>
+ <job>OCA\Contacts\Cron\SocialUpdateRegistration</job>
+ </background-jobs>
+
<settings>
<admin>OCA\Contacts\Settings\AdminSettings</admin>
</settings>
+
</info>
diff --git a/appinfo/routes.php b/appinfo/routes.php
index 6bdf24a3..88f430cc 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -27,7 +27,9 @@ return [
['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
['name' => 'page#index', 'url' => '/{group}', 'verb' => 'GET', 'postfix' => 'group'],
['name' => 'page#index', 'url' => '/{group}/{contact}', 'verb' => 'GET', 'postfix' => 'group.contact'],
- ['name' => 'social_api#update_contact', 'url' => '/api/v1/social/avatar/{network}/{addressbookId}/{contactId}', 'verb' => 'PUT'],
- ['name' => 'social_api#set_app_config', 'url' => '/api/v1/social/config/{key}', 'verb' => 'POST'],
+ ['name' => 'social_api#update_contact', 'url' => '/api/v1/social/avatar/{network}/{addressbookId}/{contactId}', 'verb' => 'PUT'],
+ ['name' => 'social_api#set_app_config', 'url' => '/api/v1/social/config/global/{key}', 'verb' => 'PUT'],
+ ['name' => 'social_api#set_user_config', 'url' => '/api/v1/social/config/user/{key}', 'verb' => 'PUT'],
+ ['name' => 'social_api#get_user_config', 'url' => '/api/v1/social/config/user/{key}', 'verb' => 'GET'],
]
];
diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php
index e94510cd..60fd2e8b 100644
--- a/lib/Controller/PageController.php
+++ b/lib/Controller/PageController.php
@@ -3,6 +3,7 @@
* @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
+ * @author Matthias Heinisch <nextcloud@matthiasheinisch.de>
*
* @license GNU AGPL version 3 or any later version
*
@@ -23,12 +24,14 @@
namespace OCA\Contacts\Controller;
-use OCA\Contacts\AppInfo\Application;
use OCA\Contacts\Service\SocialApiService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\TemplateResponse;
+
+use OCA\Contacts\AppInfo\Application;
use OCP\IConfig;
use OCP\IInitialStateService;
+use OCP\IUserSession;
use OCP\IRequest;
use OCP\L10N\IFactory;
use OCP\Util;
@@ -43,6 +46,9 @@ class PageController extends Controller {
/** @var IFactory */
private $languageFactory;
+ /** @var IUserSession */
+ private $userSession;
+
/** @var SocialApiService */
private $socialApiService;
@@ -50,12 +56,15 @@ class PageController extends Controller {
IConfig $config,
IInitialStateService $initialStateService,
IFactory $languageFactory,
+ IUserSession $userSession,
SocialApiService $socialApiService) {
parent::__construct(Application::APP_ID, $request);
+ $this->appName = Application::APP_ID;
$this->config = $config;
$this->initialStateService = $initialStateService;
$this->languageFactory = $languageFactory;
+ $this->userSession = $userSession;
$this->socialApiService = $socialApiService;
}
@@ -66,17 +75,30 @@ class PageController extends Controller {
* Default routing
*/
public function index(): TemplateResponse {
+ $user = $this->userSession->getUser();
+ $userId = '';
+ if (!is_null($user)) {
+ $userId = $user->getUid();
+ }
+
$locales = $this->languageFactory->findAvailableLocales();
- $defaultProfile = $this->config->getAppValue(Application::APP_ID, 'defaultProfile', 'HOME');
+ $defaultProfile = $this->config->getAppValue($this->appName, 'defaultProfile', 'HOME');
$supportedNetworks = $this->socialApiService->getSupportedNetworks();
+ $syncAllowedByAdmin = $this->config->getAppValue($this->appName, 'allowSocialSync', 'yes'); // allow users to retrieve avatars from social networks (default: yes)
+ $bgSyncEnabledByUser = $this->config->getUserValue($userId, $this->appName, 'enableSocialSync', 'no'); // automated background syncs for social avatars (default: no)
- $this->initialStateService->provideInitialState(Application::APP_ID, 'locales', $locales);
- $this->initialStateService->provideInitialState(Application::APP_ID, 'defaultProfile', $defaultProfile);
- $this->initialStateService->provideInitialState(Application::APP_ID, 'supportedNetworks', $supportedNetworks);
+ $this->initialStateService->provideInitialState($this->appName, 'locales', $locales);
+ $this->initialStateService->provideInitialState($this->appName, 'defaultProfile', $defaultProfile);
+ $this->initialStateService->provideInitialState($this->appName, 'supportedNetworks', $supportedNetworks);
+ $this->initialStateService->provideInitialState($this->appName, 'locales', $locales);
+ $this->initialStateService->provideInitialState($this->appName, 'defaultProfile', $defaultProfile);
+ $this->initialStateService->provideInitialState($this->appName, 'supportedNetworks', $supportedNetworks);
+ $this->initialStateService->provideInitialState($this->appName, 'allowSocialSync', $syncAllowedByAdmin);
+ $this->initialStateService->provideInitialState($this->appName, 'enableSocialSync', $bgSyncEnabledByUser);
- Util::addScript(Application::APP_ID, 'contacts');
- Util::addStyle(Application::APP_ID, 'contacts');
+ Util::addScript($this->appName, 'contacts');
+ Util::addStyle($this->appName, 'contacts');
- return new TemplateResponse(Application::APP_ID, 'main');
+ return new TemplateResponse($this->appName, 'main');
}
}
diff --git a/lib/Controller/SocialApiController.php b/lib/Controller/SocialApiController.php
index 4898d915..b09eafdb 100644
--- a/lib/Controller/SocialApiController.php
+++ b/lib/Controller/SocialApiController.php
@@ -30,21 +30,29 @@ use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IConfig;
use OCP\IRequest;
+use OCP\IUserSession;
class SocialApiController extends ApiController {
+ protected $appName;
/** @var IConfig */
private $config;
+ /** @var IUserSession */
+ private $userSession;
+
/** @var SocialApiService */
private $socialApiService;
public function __construct(IRequest $request,
IConfig $config,
+ IUserSession $userSession,
SocialApiService $socialApiService) {
parent::__construct(Application::APP_ID, $request);
$this->config = $config;
+ $this->appName = Application::APP_ID;
+ $this->userSession = $userSession;
$this->socialApiService = $socialApiService;
}
@@ -69,6 +77,46 @@ class SocialApiController extends ApiController {
/**
* @NoAdminRequired
*
+ * update appconfig (user setting)
+ *
+ * @param {String} key the identifier to change
+ * @param {String} allow the value to set
+ *
+ * @returns {JSONResponse} an empty JSONResponse with respective http status code
+ */
+ public function setUserConfig($key, $allow) {
+ $user = $this->userSession->getUser();
+ if (is_null($user)) {
+ return new JSONResponse([], Http::STATUS_PRECONDITION_FAILED);
+ }
+ $userId = $user->getUid();
+ $this->config->setUserValue($userId, $this->appName, $key, $allow);
+ return new JSONResponse([], Http::STATUS_OK);
+ }
+
+
+ /**
+ * @NoAdminRequired
+ *
+ * retrieve appconfig (user setting)
+ *
+ * @param {String} key the identifier to retrieve
+ *
+ * @returns {string} the desired value or null if not existing
+ */
+ public function getUserConfig($key) {
+ $user = $this->userSession->getUser();
+ if (is_null($user)) {
+ return null;
+ }
+ $userId = $user->getUid();
+ return $this->config->getUserValue($userId, $this->appName, $key, 'null');
+ }
+
+
+ /**
+ * @NoAdminRequired
+ *
* returns an array of supported social networks
*
* @returns {array} array of the supported social networks
diff --git a/lib/Cron/SocialUpdate.php b/lib/Cron/SocialUpdate.php
new file mode 100644
index 00000000..fe245cdc
--- /dev/null
+++ b/lib/Cron/SocialUpdate.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * @copyright 2020 Matthias Heinisch <nextcloud@matthiasheinisch.de>
+ *
+ * @author Matthias Heinisch <nextcloud@matthiasheinisch.de>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Contacts\Cron;
+
+use OCA\Contacts\Service\SocialApiService;
+
+class SocialUpdate extends \OC\BackgroundJob\QueuedJob {
+ /** @var SocialUpdateService */
+ private $social;
+
+ public function __construct(SocialApiService $social) {
+ $this->social = $social;
+ }
+
+ protected function run($arguments) {
+ $userId = $arguments['userId'];
+
+ // update contacts with first available social media profile
+ $this->social->updateAddressbooks('any', $userId);
+ }
+}
diff --git a/lib/Cron/SocialUpdateRegistration.php b/lib/Cron/SocialUpdateRegistration.php
new file mode 100644
index 00000000..58c7a51a
--- /dev/null
+++ b/lib/Cron/SocialUpdateRegistration.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * @copyright 2017 Georg Ehrke <oc.list@georgehrke.com>
+ *
+ * @author Georg Ehrke <oc.list@georgehrke.com>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Matthias Heinisch <nextcloud@matthiasheinisch.de>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Contacts\Cron;
+
+use OCA\Contacts\AppInfo\Application;
+
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\BackgroundJob\IJobList;
+use OCP\IUser;
+use OCP\IConfig;
+use OCP\IUserManager;
+
+class SocialUpdateRegistration extends \OC\BackgroundJob\TimedJob {
+ private $appName;
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /** @var IJobList */
+ private $jobList;
+
+ /** @var IConfig */
+ private $config;
+
+ /**
+ * RegisterSocialUpdate constructor.
+ *
+ * @param ITimeFactory $time
+ * @param IUserManager $userManager
+ * @param IJobList $jobList
+ */
+ public function __construct(
+ // ITimeFactory $time,
+ IUserManager $userManager,
+ IConfig $config,
+ IJobList $jobList) {
+ //parent::__construct($time);
+
+ $this->appName = Application::APP_ID;
+ $this->userManager = $userManager;
+ $this->config = $config;
+ $this->jobList = $jobList;
+
+ // Run once a week
+ parent::setInterval(7 * 24 * 60 * 60);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function run($arguments) {
+
+ // check if admin allows for social updates:
+ $syncAllowedByAdmin = $this->config->getAppValue($this->appName, 'allowSocialSync', 'yes');
+ if (!($syncAllowedByAdmin === 'yes')) {
+ return;
+ }
+
+ $this->userManager->callForSeenUsers(function (IUser $user) {
+
+ // check that user opted-in:
+ $bgSyncEnabledByUser = $this->config->getUserValue($user->getUID(), $this->appName, 'enableSocialSync', 'no');
+ if ($bgSyncEnabledByUser === 'yes') {
+ $this->jobList->add(SocialUpdate::class, [
+ 'userId' => $user->getUID()
+ ]);
+ }
+ });
+ }
+}
diff --git a/lib/Service/SocialApiService.php b/lib/Service/SocialApiService.php
index 154e0295..f0339c07 100644
--- a/lib/Service/SocialApiService.php
+++ b/lib/Service/SocialApiService.php
@@ -29,13 +29,18 @@ use OCA\Contacts\AppInfo\Application;
use OCP\Contacts\IManager;
use OCP\IAddressBook;
+use OCP\Util;
use OCP\IConfig;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
use OCP\Http\Client\IClientService;
+use OCA\DAV\CardDAV\CardDavBackend;
+use OCA\DAV\CardDAV\ContactsManager;
+use OCP\IURLGenerator;
+use OCP\IL10N;
class SocialApiService {
-
+ private $appName;
/** @var CompositeSocialProvider */
private $socialProvider;
/** @var IManager */
@@ -44,16 +49,30 @@ class SocialApiService {
private $config;
/** @var IClientService */
private $clientService;
+ /** @var IL10N */
+ private $l10n;
+ /** @var IURLGenerator */
+ private $urlGen;
+ /** @var CardDavBackend */
+ private $davBackend;
+
public function __construct(
CompositeSocialProvider $socialProvider,
IManager $manager,
IConfig $config,
- IClientService $clientService) {
+ IClientService $clientService,
+ IL10N $l10n,
+ IURLGenerator $urlGen,
+ CardDavBackend $davBackend) {
+ $this->appName = Application::APP_ID;
$this->socialProvider = $socialProvider;
$this->manager = $manager;
$this->config = $config;
$this->clientService = $clientService;
+ $this->l10n = $l10n;
+ $this->urlGen = $urlGen;
+ $this->davBackend = $davBackend;
}
@@ -65,8 +84,8 @@ class SocialApiService {
* @returns {array} array of the supported social networks
*/
public function getSupportedNetworks() : array {
- $isAdminEnabled = $this->config->getAppValue(Application::APP_ID, 'allowSocialSync', 'yes');
- if ($isAdminEnabled !== 'yes') {
+ $syncAllowedByAdmin = $this->config->getAppValue($this->appName, 'allowSocialSync', 'yes');
+ if ($syncAllowedByAdmin !== 'yes') {
return [];
}
return $this->socialProvider->getSupportedNetworks();
@@ -127,6 +146,20 @@ class SocialApiService {
/**
* @NoAdminRequired
*
+ * Retrieves and initiates all addressbooks from a user
+ *
+ * @param {string} userId the user to query
+ * @param {IManager} the contact manager to load
+ */
+ protected function registerAddressbooks($userId, IManager $manager) {
+ $coma = new ContactsManager($this->davBackend, $this->l10n);
+ $coma->setupContactsProvider($manager, $userId, $this->urlGen);
+ $this->manager = $manager;
+ }
+
+ /**
+ * @NoAdminRequired
+ *
* Retrieves social profile data for a contact and updates the entry
*
* @param {String} addressbookId the addressbook identifier
@@ -182,4 +215,102 @@ class SocialApiService {
}
return new JSONResponse([], Http::STATUS_OK);
}
+
+ /**
+ * @NoAdminRequired
+ *
+ * Stores the result of social avatar updates for each contact
+ * (used during batch updates in updateAddressbooks)
+ *
+ * @param {array} report where the results are added
+ * @param {String} entry the element to add
+ * @param {string} status the (http) status code
+ *
+ * @returns {array} the report including the new entry
+ */
+ protected function registerUpdateResult(array $report, string $entry, string $status) : array {
+ // initialize report on first call
+ if (empty($report)) {
+ $report = [
+ 'updated' => [],
+ 'checked' => [],
+ 'failed' => [],
+ ];
+ }
+ // add entry to respective sub-array
+ switch ($status) {
+ case Http::STATUS_OK:
+ array_push($report['updated'], $entry);
+ break;
+ case Http::STATUS_NOT_MODIFIED:
+ array_push($report['checked'], $entry);
+ break;
+ default:
+ if (!isset($report['failed'][$status])) {
+ $report['failed'][$status] = [];
+ }
+ array_push($report['failed'][$status], $entry);
+ }
+ return $report;
+ }
+
+
+ /**
+ * @NoAdminRequired
+ *
+ * Updates social profile data for all contacts of an addressbook
+ *
+ * @param {String} network the social network to use (fallback: take first match)
+ * @param {String} userId the address book owner
+ *
+ * @returns {JSONResponse} JSONResponse with the list of changed and failed contacts
+ */
+ public function updateAddressbooks(string $network, string $userId) : JSONResponse {
+
+ // double check!
+ $syncAllowedByAdmin = $this->config->getAppValue($this->appName, 'allowSocialSync', 'yes');
+ $bgSyncEnabledByUser = $this->config->getUserValue($userId, $this->appName, 'enableSocialSync', 'no');
+ if (($syncAllowedByAdmin !== 'yes') || ($bgSyncEnabledByUser !== 'yes')) {
+ return new JSONResponse([], Http::STATUS_FORBIDDEN);
+ }
+
+ $delay = 1;
+ $response = [];
+
+ // get corresponding addressbook
+ $this->registerAddressbooks($userId, $this->manager);
+ $addressBooks = $this->manager->getUserAddressBooks();
+
+ foreach ($addressBooks as $addressBook) {
+ if ((is_null($addressBook) ||
+ (Util::getVersion()[0] >= 20) &&
+ //TODO: remove version check ^ when dependency for contacts is min NCv20 (see info.xml)
+ ($addressBook->isShared() || $addressBook->isSystemAddressBook()))) {
+ // TODO: filter out deactivated books, see https://github.com/nextcloud/server/issues/17537
+ continue;
+ }
+
+ // get contacts in that addressbook
+ $contacts = $addressBook->search('', ['UID'], ['types' => true]);
+ // TODO: can be optimized by:
+ // $contacts = $addressBook->search('', ['X-SOCIALPROFILE'], ['types' => true]);
+ // but see https://github.com/nextcloud/contacts/pull/1722#discussion_r463782429
+ // and the referenced PR before activating this (index has to be re-created!)
+
+ // update one contact after another
+ foreach ($contacts as $contact) {
+ // delay to prevent rate limiting issues
+ // TODO: do we need to send an Http::STATUS_PROCESSING ?
+ sleep($delay);
+
+ try {
+ $r = $this->updateContact($addressBook->getURI(), $contact['UID'], $network);
+ $response = $this->registerUpdateResult($response, $contact['FN'], $r->getStatus());
+ } catch (Exception $e) {
+ $response = $this->registerUpdateResult($response, $contact['FN'], '-1');
+ }
+ }
+ }
+ return new JSONResponse([$response], Http::STATUS_OK);
+ }
}
diff --git a/lib/Settings/AdminSettings.php b/lib/Settings/AdminSettings.php
index c8460917..00f987fa 100644
--- a/lib/Settings/AdminSettings.php
+++ b/lib/Settings/AdminSettings.php
@@ -30,8 +30,9 @@ use OCP\IInitialStateService;
use OCP\Settings\ISettings;
class AdminSettings implements ISettings {
+ protected $appName;
- /** @var IConfig */
+ /** @var IConfig */
private $config;
/** @var IInitialStateService */
diff --git a/src/components/AdminSettings.vue b/src/components/AdminSettings.vue
index aa65f096..415048ce 100644
--- a/src/components/AdminSettings.vue
+++ b/src/components/AdminSettings.vue
@@ -1,3 +1,25 @@
+<!--
+ - @copyright Copyright (c) Matthias Heinisch <nextcloud@matthiasheinisch.de>
+ -
+ - @author Matthias Heinisch <nextcloud@matthiasheinisch.de>
+ -
+ - @license GNU AGPL version 3 or any later version
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -
+ -->
+
<template>
<div id="contacts" class="section">
<h2>{{ t('contacts', 'Contacts') }}</h2>
@@ -26,7 +48,7 @@ export default {
},
methods: {
updateSetting(setting) {
- axios.post(generateUrl('apps/contacts/api/v1/social/config/' + setting), {
+ axios.put(generateUrl('apps/contacts/api/v1/social/config/global/' + setting), {
allow: this[setting] ? 'yes' : 'no',
})
},
diff --git a/src/components/SettingsSection.vue b/src/components/SettingsSection.vue
index e0757716..215f2413 100644
--- a/src/components/SettingsSection.vue
+++ b/src/components/SettingsSection.vue
@@ -2,6 +2,7 @@
- @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
-
- @author John Molakvoæ <skjnldsv@protonmail.com>
+ - @author Matthias Heinisch <nextcloud@matthiasheinisch.de>
-
- @license GNU AGPL version 3 or any later version
-
@@ -22,6 +23,16 @@
<template>
<div>
+ <div v-if="allowSocialSync">
+ <input
+ id="socialSyncToggle"
+ class="checkbox"
+ :checked="enableSocialSync"
+ type="checkbox"
+ @change="toggleSocialSync">
+ <label for="socialSyncToggle">{{ t('contacts', 'Update avatars from social media') }}</label>
+ <em for="socialSyncToggle">{{ t('contacts', '(refreshed once per week)') }}</em>
+ </div>
<ul id="addressbook-list">
<SettingsAddressbook v-for="addressbook in addressbooks" :key="addressbook.id" :addressbook="addressbook" />
</ul>
@@ -35,6 +46,9 @@
</template>
<script>
+import axios from '@nextcloud/axios'
+import { generateUrl } from '@nextcloud/router'
+import { loadState } from '@nextcloud/initial-state'
import SettingsAddressbook from './Settings/SettingsAddressbook'
import SettingsNewAddressbook from './Settings/SettingsNewAddressbook'
import SettingsImportContacts from './Settings/SettingsImportContacts'
@@ -48,6 +62,12 @@ export default {
SettingsImportContacts,
SettingsSortContacts,
},
+ data() {
+ return {
+ allowSocialSync: loadState('contacts', 'allowSocialSync') !== 'no',
+ enableSocialSync: loadState('contacts', 'enableSocialSync') !== 'no',
+ }
+ },
computed: {
// store getters
addressbooks() {
@@ -58,6 +78,16 @@ export default {
onClickImport(event) {
this.$emit('clicked', event)
},
+ toggleSocialSync() {
+ this.enableSocialSync = !this.enableSocialSync
+
+ // store value
+ let setting = 'yes'
+ this.enableSocialSync ? setting = 'yes' : setting = 'no'
+ axios.put(generateUrl('apps/contacts/api/v1/social/config/user/enableSocialSync'), {
+ allow: setting,
+ })
+ },
onLoad(event) {
this.$emit('fileLoaded', false)
},
diff --git a/tests/unit/Controller/PageControllerTest.php b/tests/unit/Controller/PageControllerTest.php
index f173ff73..853bc29f 100644
--- a/tests/unit/Controller/PageControllerTest.php
+++ b/tests/unit/Controller/PageControllerTest.php
@@ -3,6 +3,7 @@
* @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
+ * @author Matthias Heinisch <nextcloud@matthiasheinisch.de>
*
* @license GNU AGPL version 3 or any later version
*
@@ -27,6 +28,8 @@ use OCP\AppFramework\Http\TemplateResponse;
use OCP\IConfig;
use PHPUnit\Framework\MockObject\MockObject;
use OCP\IInitialStateService;
+use OCP\IUser;
+use OCP\IUserSession;
use OCP\IRequest;
use OCP\L10N\IFactory;
use OCA\Contacts\Service\SocialApiService;
@@ -47,6 +50,9 @@ class PageControllerTest extends TestCase {
/** @var IFactory|MockObject */
private $languageFactory;
+ /** @var IUserSession|MockObject */
+ private $userSession;
+
/** @var SocialApiService|MockObject*/
private $socialApi;
@@ -57,6 +63,7 @@ class PageControllerTest extends TestCase {
$this->config = $this->createMock(IConfig::class);
$this->initialStateService = $this->createMock(IInitialStateService::class);
$this->languageFactory = $this->createMock(IFactory::class);
+ $this->userSession = $this->createMock(IUserSession::class);
$this->socialApi = $this->createMock(SocialApiService::class);
$this->controller = new PageController(
@@ -64,12 +71,17 @@ class PageControllerTest extends TestCase {
$this->config,
$this->initialStateService,
$this->languageFactory,
+ $this->userSession,
$this->socialApi
);
}
public function testIndex() {
+ $user = $this->createMock(IUser::class);
+ $user->method('getUid')->willReturn('mrstest');
+ $this->userSession->method('getUser')->willReturn($user);
+
$result = $this->controller->index();
$this->assertEquals('main', $result->getTemplateName());
diff --git a/tests/unit/Service/SocialApiServiceTest.php b/tests/unit/Service/SocialApiServiceTest.php
index 076162d2..a2033a41 100644
--- a/tests/unit/Service/SocialApiServiceTest.php
+++ b/tests/unit/Service/SocialApiServiceTest.php
@@ -33,6 +33,10 @@ use OCP\Http\Client\IClientService;
use OCP\IConfig;
use OCP\Contacts\IManager;
use OCP\IAddressBook;
+use OCA\DAV\CardDAV\CardDavBackend;
+use OCP\IURLGenerator;
+use OCP\IL10N;
+use OCP\Util;
use PHPUnit\Framework\MockObject\MockObject;
use ChristophWurst\Nextcloud\Testing\TestCase;
@@ -48,6 +52,12 @@ class SocialApiServiceTest extends TestCase {
private $config;
/** @var IClientService|MockObject */
private $clientService;
+ /** @var IL10N|MockObject */
+ private $l10n;
+ /** @var IURLGenerator|MockObject */
+ private $urlGen;
+ /** @var CardDavBackend|MockObject */
+ private $davBackend;
public function socialProfileProvider() {
return [
@@ -59,6 +69,15 @@ class SocialApiServiceTest extends TestCase {
];
}
+ public function updateAddressbookProvider() {
+ return [
+ 'not user enabled' => ['yes', 'no', Http::STATUS_FORBIDDEN],
+ 'not admin allowed' => ['no', 'yes', Http::STATUS_FORBIDDEN],
+ 'not allowed, not enabled' => ['no', 'no', Http::STATUS_FORBIDDEN],
+ 'allowed and enabled' => ['yes', 'yes', Http::STATUS_OK],
+ ];
+ }
+
public function setUp() {
parent::setUp();
@@ -66,11 +85,17 @@ class SocialApiServiceTest extends TestCase {
$this->config = $this->createMock(IConfig::class);
$this->socialProvider = $this->createMock(CompositeSocialProvider::class);
$this->clientService = $this->creat