Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/mail.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Wurst <christoph@winzerhof-wurst.at>2017-12-04 15:01:57 +0300
committerChristoph Wurst <christoph@winzerhof-wurst.at>2017-12-12 11:10:45 +0300
commit10c7e04d0510f34c337452d3dfac03e2e016b041 (patch)
treefcb5caebc3f2936bf159c58ec7514f3630a730b4
parent1d77fc9761a0001b932397091ead7392fec769ed (diff)
Add opt-out setting for Gravatar integration
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
-rw-r--r--appinfo/routes.php7
-rw-r--r--js/app.js17
-rw-r--r--js/radio.js1
-rw-r--r--js/service/preferenceservice.js74
-rw-r--r--js/templates/settings.html21
-rw-r--r--js/tests/service/preferenceservice_spec.js92
-rw-r--r--js/views/settings.js16
-rw-r--r--lib/AppInfo/Application.php5
-rw-r--r--lib/Contracts/IUserPreferences.php40
-rw-r--r--lib/Controller/PageController.php24
-rw-r--r--lib/Controller/PreferencesController.php76
-rw-r--r--lib/Service/Avatar/AddressbookSource.php9
-rw-r--r--lib/Service/Avatar/CompositeAvatarSource.php10
-rw-r--r--lib/Service/Avatar/FaviconSource.php9
-rw-r--r--lib/Service/Avatar/GravatarSource.php9
-rw-r--r--lib/Service/Avatar/IAvatarSource.php9
-rw-r--r--lib/Service/AvatarService.php25
-rw-r--r--lib/Service/UserPreferenceSevice.php63
-rw-r--r--templates/index.php1
-rw-r--r--tests/Controller/PageControllerTest.php21
-rw-r--r--tests/Controller/PreferencesControllerTest.php74
-rw-r--r--tests/Service/Avatar/CompositeAvatarSourceTest.php43
-rw-r--r--tests/Service/AvatarServiceTest.php51
-rw-r--r--tests/Service/UserPreferenceServiceTest.php70
24 files changed, 730 insertions, 37 deletions
diff --git a/appinfo/routes.php b/appinfo/routes.php
index 678482081..0bcdb712c 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -96,11 +96,12 @@ $app->registerRoutes($this,
],
],
'resources' => [
- 'autoComplete' => ['url' => '/api/autoComplete'],
- 'localAttachments' => ['url' => '/api/attachments'],
'accounts' => ['url' => '/api/accounts'],
+ 'aliases' => ['url' => '/api/accounts/{accountId}/aliases'],
+ 'autoComplete' => ['url' => '/api/autoComplete'],
'folders' => ['url' => '/api/accounts/{accountId}/folders'],
+ 'localAttachments' => ['url' => '/api/attachments'],
'messages' => ['url' => '/api/accounts/{accountId}/folders/{folderId}/messages'],
- 'aliases' => ['url' => '/api/accounts/{accountId}/aliases'],
+ 'preferences' => ['url' => '/api/preferences'],
]
]);
diff --git a/js/app.js b/js/app.js
index 1bb329f49..89a363ddc 100644
--- a/js/app.js
+++ b/js/app.js
@@ -42,26 +42,33 @@ define(function(require) {
require('service/accountservice');
require('service/aliasesservice');
require('service/attachmentservice');
+ require('service/backgroundsyncservice');
require('service/davservice');
require('service/folderservice');
require('service/foldersyncservice');
require('service/messageservice');
- require('service/backgroundsyncservice');
+ require('service/preferenceservice');
require('util/notificationhandler');
var Mail = Marionette.Application.extend({
+ _useExternalAvatars: false,
+
+ getUseExternalAvatars: function() {
+ return this._useExternalAvatars;
+ },
+
/**
* Register the mailto protocol handler
*/
registerProtocolHandler: function() {
if (window.navigator.registerProtocolHandler) {
var url = window.location.protocol + '//' +
- window.location.host +
- OC.generateUrl('apps/mail/compose?uri=%s');
+ window.location.host +
+ OC.generateUrl('apps/mail/compose?uri=%s');
try {
window.navigator
- .registerProtocolHandler('mailto', url, OC.theme.name + ' Mail');
+ .registerProtocolHandler('mailto', url, OC.theme.name + ' Mail');
} catch (e) {
}
}
@@ -91,6 +98,8 @@ define(function(require) {
Mail = new Mail();
Mail.on('start', function() {
+ this._useExternalAvatars = $('#external-avatars').val() === 'true';
+
this.view = new AppView();
Cache.init();
diff --git a/js/radio.js b/js/radio.js
index c26b06a1a..ff1592fef 100644
--- a/js/radio.js
+++ b/js/radio.js
@@ -24,6 +24,7 @@ define(function(require) {
'message',
'navigation',
'notification',
+ 'preference',
'state',
'sync',
'ui'
diff --git a/js/service/preferenceservice.js b/js/service/preferenceservice.js
new file mode 100644
index 000000000..a73c18091
--- /dev/null
+++ b/js/service/preferenceservice.js
@@ -0,0 +1,74 @@
+/* global Promise */
+
+/**
+ * @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @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/>.
+ *
+ */
+
+define(function(require) {
+ 'use strict';
+
+ var $ = require('jquery');
+ var OC = require('OC');
+ var Radio = require('radio');
+
+ Radio.preference.reply('save', savePreference);
+ Radio.preference.reply('get', savePreference);
+
+ function savePreference(key, value) {
+ var url = OC.generateUrl('/apps/mail/api/preferences/{key}', {
+ key: key
+ });
+
+ return new Promise(function(resolve, reject) {
+ return $.ajax(url, {
+ method: 'PUT',
+ data: {
+ key: key,
+ value: value
+ },
+ success: resolve,
+ error: reject
+ });
+ }).then(function(data) {
+ return data.value;
+ });
+ }
+
+ function getPreference(key) {
+ var url = OC.generateUrl('/apps/mail/api/preferences/{key}', {
+ key: key
+ });
+
+ return new Promise(function(resolve, reject) {
+ return $.ajax(url, {
+ success: resolve,
+ error: reject
+ });
+ }).then(function(data) {
+ return data.value;
+ });
+ }
+
+ return {
+ savePreference: savePreference,
+ getPreference: getPreference
+ };
+});
diff --git a/js/templates/settings.html b/js/templates/settings.html
index fb6f9a51c..e46c639fa 100644
--- a/js/templates/settings.html
+++ b/js/templates/settings.html
@@ -6,11 +6,20 @@
class="button new-button"
href="{{addAccountUrl}}">{{ t 'Add mail account' }}</a>
- <p class="app-settings-hint">
- <a id="keyboard-shortcuts"
- href="{{keyboardShortcutUrl}}">{{ t 'Keyboard shortcuts' }}</a></p>
+ <p>
+ <input class="checkbox"
+ id="gravatar-enabled"
+ {{#if useExternalAvatars}}checked="checked"{{/if}}
+ type="checkbox">
+ <label for="gravatar-enabled">{{ t 'Use Gravatar and favicon avatars' }}</label>
+ </p>
<p class="app-settings-hint">
- {{{ t 'Looking to encrypt your emails? Install the <a href="https://www.mailvelope.com/" target="_blank">Mailvelope browser extension</a>!' }}}
- </p>
-</div> \ No newline at end of file
+ <a id="keyboard-shortcuts"
+ href="{{keyboardShortcutUrl}}">{{ t 'Keyboard shortcuts' }}</a>
+ </p>
+
+ <p class="app-settings-hint">
+ {{{ t 'Looking to encrypt your emails? Install the <a href="https://www.mailvelope.com/" target="_blank">Mailvelope browser extension</a>!' }}}
+ </p>
+ </div>
diff --git a/js/tests/service/preferenceservice_spec.js b/js/tests/service/preferenceservice_spec.js
new file mode 100644
index 000000000..d982b1af7
--- /dev/null
+++ b/js/tests/service/preferenceservice_spec.js
@@ -0,0 +1,92 @@
+/* global sinon, expect */
+
+/**
+ * @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @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/>.
+ *
+ */
+
+define([
+ 'service/preferenceservice'
+], function(PreferenceService) {
+ 'use strict';
+
+ describe('PreferenceService', function() {
+ var server;
+
+ beforeEach(function() {
+ server = sinon.fakeServer.create();
+ });
+
+ afterEach(function() {
+ server.restore();
+ });
+
+ it('retrieves a preference from the back-end', function(done) {
+ var retrieving = PreferenceService.getPreference('test');
+
+ expect(server.requests.length).toBe(1);
+ server.requests[0].respond(
+ 200,
+ {
+ 'Content-Type': 'application/json'
+ },
+ JSON.stringify({
+ value: '123'
+ })
+ );
+
+ retrieving.then(function(value) {
+ expect(value).toBe('123');
+
+ done();
+ }).catch(done.fail);
+ });
+
+ it('retrieves an error from the back-end', function(done) {
+ var retrieving = PreferenceService.getPreference('test');
+
+ expect(server.requests.length).toBe(1);
+ server.requests[0].respond(500, null, null);
+
+ retrieving.then(done.fail).catch(done);
+ });
+
+ it('stores a preference on the back-end', function(done) {
+ var storing = PreferenceService.savePreference('test', '123');
+
+ expect(server.requests.length).toBe(1);
+ server.requests[0].respond(
+ 200,
+ {
+ 'Content-Type': 'application/json'
+ },
+ JSON.stringify({
+ value: '123'
+ })
+ );
+
+ storing.then(function(value) {
+ expect(value).toBe('123');
+
+ done();
+ }).catch(done.fail);
+ });
+ });
+});
diff --git a/js/views/settings.js b/js/views/settings.js
index ec15056fc..12eca1e21 100644
--- a/js/views/settings.js
+++ b/js/views/settings.js
@@ -17,28 +17,44 @@ define(function(require) {
var SettingsTemplate = require('templates/settings.html');
return Marionette.View.extend({
+
accounts: null,
+
template: SettingsTemplate,
+
templateContext: function() {
+ var app = require('app');
return {
addAccountUrl: OC.generateUrl('apps/mail/#setup'),
+ useExternalAvatars: app.getUseExternalAvatars(),
keyboardShortcutUrl: OC.generateUrl('apps/mail/#shortcuts')
};
},
+
regions: {
accountsList: '#settings-accounts'
},
+
events: {
'click #new-mail-account': 'addAccount',
+ 'change #gravatar-enabled': 'toggleExternalAvatars',
'click #keyboard-shortcuts': 'showKeyboardShortcuts'
},
+
addAccount: function(e) {
e.preventDefault();
Radio.navigation.trigger('setup');
},
+
+ toggleExternalAvatars: function() {
+ var enabled = this.$('#gravatar-enabled').attr('checked') === 'checked';
+ Radio.preference.request('save', 'external-avatars', enabled ? 'true' : 'false');
+ },
+
showKeyboardShortcuts: function(e) {
e.preventDefault();
Radio.navigation.trigger('keyboardshortcuts');
}
+
});
});
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 3ef9e3d81..15229fab6 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -26,10 +26,12 @@ use OCA\Mail\Contracts\IAttachmentService;
use OCA\Mail\Contracts\IAvatarService;
use OCA\Mail\Contracts\IMailManager;
use OCA\Mail\Contracts\IMailTransmission;
+use OCA\Mail\Contracts\IUserPreferences;
use OCA\Mail\Service\Attachment\AttachmentService;
use OCA\Mail\Service\AvatarService;
use OCA\Mail\Service\MailManager;
use OCA\Mail\Service\MailTransmission;
+use OCA\Mail\Service\UserPreferenceSevice;
use OCP\AppFramework\App;
use OCP\Util;
@@ -48,9 +50,10 @@ class Application extends App {
$testSmtp = $transport === 'smtp';
$container->registerAlias(IAvatarService::class, AvatarService::class);
- $container->registerAlias(IMailManager::class, MailManager::class);
$container->registerAlias(IAttachmentService::class, AttachmentService::class);
+ $container->registerAlias(IMailManager::class, MailManager::class);
$container->registerAlias(IMailTransmission::class, MailTransmission::class);
+ $container->registerAlias(IUserPreferences::class, UserPreferenceSevice::class);
$container->registerService('OCP\ISession', function ($c) {
return $c->getServer()->getSession();
});
diff --git a/lib/Contracts/IUserPreferences.php b/lib/Contracts/IUserPreferences.php
new file mode 100644
index 000000000..55b0d93af
--- /dev/null
+++ b/lib/Contracts/IUserPreferences.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @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\Mail\Contracts;
+
+interface IUserPreferences {
+
+ /**
+ * @param string $key
+ * @param mixed $value
+ */
+ public function setPreference($key, $value);
+
+ /**
+ * @param string $key
+ * @param mixed|null $default
+ */
+ public function getPreference($key, $default = null);
+}
diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php
index 086a5f164..10b2fea2a 100644
--- a/lib/Controller/PageController.php
+++ b/lib/Controller/PageController.php
@@ -24,6 +24,7 @@
namespace OCA\Mail\Controller;
+use OCA\Mail\Contracts\IUserPreferences;
use OCA\Mail\Service\AccountService;
use OCA\Mail\Service\AliasesService;
use OCP\AppFramework\Controller;
@@ -55,6 +56,9 @@ class PageController extends Controller {
/** @var IUserSession */
private $userSession;
+ /** @var IUserPreferences */
+ private $preferences;
+
/**
* @param string $appName
* @param IRequest $request
@@ -63,8 +67,12 @@ class PageController extends Controller {
* @param AccountService $accountService
* @param AliasesService $aliasesService
* @param string $UserId
+ * @param IUserPreferences
*/
- public function __construct($appName, IRequest $request, IURLGenerator $urlGenerator, IConfig $config, AccountService $accountService, AliasesService $aliasesService, $UserId, IUserSession $userSession) {
+ public function __construct($appName, IRequest $request,
+ IURLGenerator $urlGenerator, IConfig $config, AccountService $accountService,
+ AliasesService $aliasesService, $UserId, IUserSession $userSession,
+ IUserPreferences $preferences) {
parent::__construct($appName, $request);
$this->urlGenerator = $urlGenerator;
$this->config = $config;
@@ -72,6 +80,7 @@ class PageController extends Controller {
$this->aliasesService = $aliasesService;
$this->currentUserId = $UserId;
$this->userSession = $userSession;
+ $this->preferences = $preferences;
}
/**
@@ -86,17 +95,21 @@ class PageController extends Controller {
$accountsJson = [];
foreach ($mailAccounts as $mailAccount) {
$json = $mailAccount->jsonSerialize();
- $json['aliases'] = $this->aliasesService->findAll($mailAccount->getId(), $this->currentUserId);
+ $json['aliases'] = $this->aliasesService->findAll($mailAccount->getId(),
+ $this->currentUserId);
$accountsJson[] = $json;
}
$user = $this->userSession->getUser();
- $response = new TemplateResponse($this->appName, 'index', [
+ $response = new TemplateResponse($this->appName, 'index',
+ [
'debug' => $this->config->getSystemValue('debug', false),
'app-version' => $this->config->getAppValue('mail', 'installed_version'),
'accounts' => base64_encode(json_encode($accountsJson)),
+ 'external-avatars' => $this->preferences->getPreference('external-avatars', 'true'),
'prefill_displayName' => $user->getDisplayName(),
- 'prefill_email' => $this->config->getUserValue($user->getUID(), 'settings', 'email', ''),
+ 'prefill_email' => $this->config->getUserValue($user->getUID(), 'settings',
+ 'email', ''),
]);
$csp = new ContentSecurityPolicy();
@@ -124,7 +137,8 @@ class PageController extends Controller {
}
}
- array_walk($params, function (&$value, $key) {
+ array_walk($params,
+ function (&$value, $key) {
$value = "$key=" . urlencode($value);
});
diff --git a/lib/Controller/PreferencesController.php b/lib/Controller/PreferencesController.php
new file mode 100644
index 000000000..cdaa28bcc
--- /dev/null
+++ b/lib/Controller/PreferencesController.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @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\Mail\Controller;
+
+use OCA\Mail\Contracts\IUserPreferences;
+use OCA\Mail\Http\JSONResponse;
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
+use OCP\IRequest;
+
+class PreferencesController extends Controller {
+
+ /** @var IUserPreferences */
+ private $userPreference;
+
+ /**
+ * @param IRequest $request
+ * @param IUserPreferences $userPreference
+ */
+ public function __construct(IRequest $request, IUserPreferences $userPreference) {
+ parent::__construct('mail', $request);
+ $this->userPreference = $userPreference;
+ }
+
+ /**
+ * @NoAdminRequired
+ *
+ * @param string $id
+ * @return JSONResponse
+ */
+ public function show($id) {
+ return new JSONResponse([
+ 'value' => $this->userPreference->getPreference($id)
+ ]);
+ }
+
+ /**
+ * @NoAdminRequired
+ *
+ * @param string $key
+ * @param string $value
+ * @return JSONResponse
+ */
+ public function update($key, $value) {
+ if (is_null($key) || is_null($value)) {
+ return new JSONResponse(null, Http::STATUS_BAD_REQUEST);
+ }
+
+ $this->userPreference->setPreference($key, $value);
+
+ return new JSONResponse();
+ }
+
+}
diff --git a/lib/Service/Avatar/AddressbookSource.php b/lib/Service/Avatar/AddressbookSource.php
index 44b920f92..b65cc69c6 100644
--- a/lib/Service/Avatar/AddressbookSource.php
+++ b/lib/Service/Avatar/AddressbookSource.php
@@ -41,6 +41,15 @@ class AddressbookSource implements IAvatarSource {
}
/**
+ * Does this source query external services?
+ *
+ * @return bool
+ */
+ public function isExternal() {
+ return false;
+ }
+
+ /**
* @param string $email sender email address
* @param AvatarFactory $factory
* @return Avatar|null avatar URL if one can be found
diff --git a/lib/Service/Avatar/CompositeAvatarSource.php b/lib/Service/Avatar/CompositeAvatarSource.php
index 344e63c77..46e2b576f 100644
--- a/lib/Service/Avatar/CompositeAvatarSource.php
+++ b/lib/Service/Avatar/CompositeAvatarSource.php
@@ -27,7 +27,7 @@ namespace OCA\Mail\Service\Avatar;
/**
* Composition of all avatar sources for easier usage
*/
-class CompositeAvatarSource implements IAvatarSource {
+class CompositeAvatarSource {
/** @var IAvatarSource[] */
private $sources;
@@ -49,10 +49,16 @@ class CompositeAvatarSource implements IAvatarSource {
/**
* @param string $email sender email address
* @param AvatarFactory $factory
+ * @param bool $queryExternal
* @return Avatar|null avatar URL if one can be found
*/
- public function fetch($email, AvatarFactory $factory) {
+ public function fetch($email, AvatarFactory $factory, $queryExternal) {
foreach ($this->sources as $source) {
+ if (!$queryExternal && $source->isExternal()) {
+ // Skip this one
+ continue;
+ }
+
$avatar = $source->fetch($email, $factory);
if (is_null($avatar)) {
diff --git a/lib/Service/Avatar/FaviconSource.php b/lib/Service/Avatar/FaviconSource.php
index 9861592dd..f5b02302a 100644
--- a/lib/Service/Avatar/FaviconSource.php
+++ b/lib/Service/Avatar/FaviconSource.php
@@ -50,6 +50,15 @@ class FaviconSource implements IAvatarSource {
}
/**
+ * Does this source query external services?
+ *
+ * @return bool
+ */
+ public function isExternal() {
+ return true;
+ }
+
+ /**
* @param string $email sender email address
* @param AvatarFactory $factory
* @return Avatar|null avatar URL if one can be found
diff --git a/lib/Service/Avatar/GravatarSource.php b/lib/Service/Avatar/GravatarSource.php
index 1c4132597..a22ad13bc 100644
--- a/lib/Service/Avatar/GravatarSource.php
+++ b/lib/Service/Avatar/GravatarSource.php
@@ -39,6 +39,15 @@ class GravatarSource implements IAvatarSource {
}
/**
+ * Does this source query external services?
+ *
+ * @return bool
+ */
+ public function isExternal() {
+ return true;
+ }
+
+ /**
* @param string $email sender email address
* @param AvatarFactory $factory
* @return Avatar|null avatar URL if one can be found
diff --git a/lib/Service/Avatar/IAvatarSource.php b/lib/Service/Avatar/IAvatarSource.php
index 4be65d597..98e1930f7 100644
--- a/lib/Service/Avatar/IAvatarSource.php
+++ b/lib/Service/Avatar/IAvatarSource.php
@@ -24,11 +24,16 @@
namespace OCA\Mail\Service\Avatar;
-use OCP\Files\IMimeTypeDetector;
-
interface IAvatarSource {
/**
+ * Does this source query external services?
+ *
+ * @return bool
+ */
+ public function isExternal();
+
+ /**
* @param string $email sender email address
* @param AvatarFactory $factory
* @return Avatar|null avatar URL if one can be found
diff --git a/lib/Service/AvatarService.php b/lib/Service/AvatarService.php
index d3d5656fc..f9236a879 100644
--- a/lib/Service/AvatarService.php
+++ b/lib/Service/AvatarService.php
@@ -22,12 +22,12 @@
namespace OCA\Mail\Service;
use OCA\Mail\Contracts\IAvatarService;
+use OCA\Mail\Contracts\IUserPreferences;
use OCA\Mail\Service\Avatar\Avatar;
use OCA\Mail\Service\Avatar\AvatarFactory;
use OCA\Mail\Service\Avatar\Cache as AvatarCache;
use OCA\Mail\Service\Avatar\CompositeAvatarSource;
use OCA\Mail\Service\Avatar\Downloader;
-use OCA\Mail\Service\Avatar\IAvatarSource;
use OCP\IURLGenerator;
class AvatarService implements IAvatarService {
@@ -38,7 +38,7 @@ class AvatarService implements IAvatarService {
/** @var Downloader */
private $downloader;
- /** @var IAvatarSource */
+ /** @var CompositeAvatarSource */
private $source;
/** @var IURLGenerator */
@@ -47,19 +47,33 @@ class AvatarService implements IAvatarService {
/** @var AvatarFactory */
private $avatarFactory;
+ /** @var IUserPreferences */
+ private $preferences;
+
/**
* @param CompositeAvatarSource $source
* @param Downloader $downloader
* @param AvatarCache $cache
* @param IURLGenerator $urlGenerator
* @param AvatarFactory $avatarFactory
+ * @param IUserPreferences $preferences
*/
- public function __construct(CompositeAvatarSource $source, Downloader $downloader, AvatarCache $cache, IURLGenerator $urlGenerator, AvatarFactory $avatarFactory) {
+ public function __construct(CompositeAvatarSource $source,
+ Downloader $downloader, AvatarCache $cache, IURLGenerator $urlGenerator,
+ AvatarFactory $avatarFactory, IUserPreferences $preferences) {
$this->source = $source;
$this->cache = $cache;
$this->urlGenerator = $urlGenerator;
$this->downloader = $downloader;
$this->avatarFactory = $avatarFactory;
+ $this->preferences = $preferences;
+ }
+
+ /**
+ * @return bool
+ */
+ private function externalAvatarsAllowed() {
+ return $this->preferences->getPreference('external-avatars', 'true') === 'true';
}
/**
@@ -69,7 +83,8 @@ class AvatarService implements IAvatarService {
if ($avatar->isExternal()) {
$mime = $avatar->getMime();
- return in_array($mime, [
+ return in_array($mime,
+ [
'image/jpeg',
'image/png',
'image/x-icon',
@@ -91,7 +106,7 @@ class AvatarService implements IAvatarService {
return $cachedAvatar;
}
- $avatar = $this->source->fetch($email, $this->avatarFactory);
+ $avatar = $this->source->fetch($email, $this->avatarFactory, $this->externalAvatarsAllowed());
if (is_null($avatar) || !$this->hasAllowedMime($avatar)) {
// Cannot locate any avatar -> nothing to do here
return null;
diff --git a/lib/Service/UserPreferenceSevice.php b/lib/Service/UserPreferenceSevice.php
new file mode 100644
index 000000000..5f45c8438
--- /dev/null
+++ b/lib/Service/UserPreferenceSevice.php
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @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\Mail\Service;
+
+use OCA\Mail\Contracts\IUserPreferences;
+use OCP\IConfig;
+
+class UserPreferenceSevice implements IUserPreferences {
+
+ /** @var IConfig */
+ private $config;
+
+ /** @var string */
+ private $UserId;
+
+ /**
+ * @param IConfig $config
+ * @param string $UserId
+ */
+ public function __construct(IConfig $config, $UserId) {
+ $this->UserId = $UserId;
+ $this->config = $config;
+ }
+
+ /**
+ * @param string $key
+ * @param mixed $value
+ */
+ public function setPreference($key, $value) {
+ $this->config->setUserValue($this->UserId, 'mail', $key, $value);
+ }
+
+ /**
+ * @param string $key
+ * @param mixed|null $default
+ */
+ public function getPreference($key, $default = null) {
+ return $this->config->getUserValue($this->UserId, 'mail', $key, $default);
+ }
+
+}
diff --git a/templates/index.php b/templates/index.php
index 0e78e1236..0ca81710a 100644
--- a/templates/index.php
+++ b/templates/index.php
@@ -31,6 +31,7 @@ script('mail', 'build/build');
<input type="hidden" id="config-installed-version" value="<?php p($_['app-version']); ?>">
<input type="hidden" id="serialized-accounts" value="<?php p($_['accounts']); ?>">
+<input type="hidden" id="external-avatars" value="<?php p($_['external-avatars']); ?>">
<div id="user-displayname"
style="display: none"><?php p($_['prefill_displayName']); ?></div>
diff --git a/tests/Controller/PageControllerTest.php b/tests/Controller/PageControllerTest.php
index 1d0ffca8e..468a6c5f4 100644
--- a/tests/Controller/PageControllerTest.php
+++ b/tests/Controller/PageControllerTest.php
@@ -21,6 +21,7 @@
namespace OCA\Mail\Tests\Controller;
+use OCA\Mail\Contracts\IUserPreferences;
use OCA\Mail\Controller\PageController;
use OCA\Mail\Service\AccountService;
use OCA\Mail\Service\AliasesService;
@@ -62,6 +63,9 @@ class PageControllerTest extends PHPUnit_Framework_TestCase {
/** @var IUserSession|PHPUnit_Framework_MockObject_MockObject */
private $userSession;
+ /** @var IUserPreferences|PHPUnit_Framework_MockObject_MockObject */
+ private $preferences;
+
/** @var PageController */
private $controller;
@@ -76,13 +80,21 @@ class PageControllerTest extends PHPUnit_Framework_TestCase {
$this->accountService = $this->createMock(AccountService::class);
$this->aliasesService = $this->createMock(AliasesService::class);
$this->userSession = $this->createMock(IUserSession::class);
- $this->controller = new PageController($this->appName, $this->request, $this->urlGenerator, $this->config, $this->accountService, $this->aliasesService, $this->userId, $this->userSession);
+ $this->preferences = $this->createMock(IUserPreferences::class);
+
+ $this->controller = new PageController($this->appName, $this->request,
+ $this->urlGenerator, $this->config, $this->accountService,
+ $this->aliasesService, $this->userId, $this->userSession, $this->preferences);
}
public function testIndex() {
$account1 = $this->createMock(IAccount::class);
$account2 = $this->createMock(IAccount::class);
+ $this->preferences->expects($this->once())
+ ->method('getPreference')
+ ->with('external-avatars', 'true')
+ ->willReturn('true');
$this->accountService->expects($this->once())
->method('findByUserId')
->with($this->userId)
@@ -149,11 +161,14 @@ class PageControllerTest extends PHPUnit_Framework_TestCase {
->will($this->returnValue('jane'));
$this->config->expects($this->once())
->method('getUserValue')
- ->with($this->equalTo('jane'), $this->equalTo('settings'), $this->equalTo('email'), $this->equalTo(''))
+ ->with($this->equalTo('jane'), $this->equalTo('settings'),
+ $this->equalTo('email'), $this->equalTo(''))
->will($this->returnValue('jane@doe.cz'));
- $expected = new TemplateResponse($this->appName, 'index', [
+ $expected = new TemplateResponse($this->appName, 'index',
+ [
'debug' => true,
+ 'external-avatars' => 'true',
'app-version' => '1.2.3',
'accounts' => base64_encode(json_encode($accountsJson)),
'prefill_displayName' => 'Jane Doe',
diff --git a/tests/Controller/PreferencesControllerTest.php b/tests/Controller/PreferencesControllerTest.php
new file mode 100644
index 000000000..a8bd9845c
--- /dev/null
+++ b/tests/Controller/PreferencesControllerTest.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @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\Mail\Tests\Controller;
+
+use OCA\Mail\Contracts\IUserPreferences;
+use OCA\Mail\Controller\PreferencesController;
+use OCA\Mail\Http\JSONResponse;
+use OCA\Mail\Tests\TestCase;
+use OCP\IRequest;
+use PHPUnit_Framework_MockObject_MockObject;
+
+class PreferencesControllerTest extends TestCase {
+
+ /** @var IUserPreferences|PHPUnit_Framework_MockObject_MockObject */
+ private $preferences;
+
+ /** @var PreferencesController */
+ private $controller;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $request = $this->createMock(IRequest::class);
+ $this->preferences = $this->createMock(IUserPreferences::class);
+
+ $this->controller = new PreferencesController($request, $this->preferences);
+ }
+
+ public function testGetPreference() {
+ $this->preferences->expects($this->once())
+ ->method('getPreference')
+ ->with('test')
+ ->willReturn(123);
+ $expected = new JSONResponse(['value' => 123]);
+
+ $actual = $this->controller->show('test');
+
+ $this->assertEquals($expected, $actual);
+ }
+
+ public function testSetPreference() {
+ $this->preferences->expects($this->once())
+ ->method('setPreference')
+ ->with('test');
+ $expected = new JSONResponse();
+
+ $actual = $this->controller->update('test', 123);
+
+ $this->assertEquals($expected, $actual);
+ }
+
+}
diff --git a/tests/Service/Avatar/CompositeAvatarSourceTest.php b/tests/Service/Avatar/CompositeAvatarSourceTest.php
index e3511c5ee..37088b20d 100644
--- a/tests/Service/Avatar/CompositeAvatarSourceTest.php
+++ b/tests/Service/Avatar/CompositeAvatarSourceTest.php
@@ -60,20 +60,59 @@ class CompositeAvatarSourceTest extends TestCase {
public function testFetchNoneFound() {
$email = 'jane@doe.com';
$avatarFactory = $this->createMock(AvatarFactory::class);
+ $this->addressbookSource->expects($this->any())
+ ->method('isExternal')
+ ->willReturn(false);
$this->addressbookSource->expects($this->once())
->method('fetch')
->with($email, $avatarFactory)
->willReturn(null);
+ $this->gravatarSource->expects($this->any())
+ ->method('isExternal')
+ ->willReturn(true);
$this->gravatarSource->expects($this->once())
->method('fetch')
->with($email, $avatarFactory)
->willReturn(null);
+ $this->faviconSource->expects($this->any())
+ ->method('isExternal')
+ ->willReturn(true);
$this->faviconSource->expects($this->once())
->method('fetch')
->with($email, $avatarFactory)
->willReturn(null);
- $actualAvatar = $this->source->fetch($email, $avatarFactory);
+ $actualAvatar = $this->source->fetch($email, $avatarFactory, true);
+
+ $this->assertNull($actualAvatar);
+ }
+
+ public function testFetchNoneFoundQueryOnlyInternal() {
+ $email = 'jane@doe.com';
+ $avatarFactory = $this->createMock(AvatarFactory::class);
+ $this->addressbookSource->expects($this->once())
+ ->method('isExternal')
+ ->willReturn(false);
+ $this->addressbookSource->expects($this->once())
+ ->method('fetch')
+ ->with($email, $avatarFactory)
+ ->willReturn(null);
+ $this->gravatarSource->expects($this->once())
+ ->method('isExternal')
+ ->willReturn(true);
+ $this->gravatarSource->expects($this->never())
+ ->method('fetch')
+ ->with($email, $avatarFactory)
+ ->willReturn(null);
+ $this->faviconSource->expects($this->once())
+ ->method('isExternal')
+ ->willReturn(true);
+ $this->faviconSource->expects($this->never())
+ ->method('fetch')
+ ->with($email, $avatarFactory)
+ ->willReturn(null);
+
+ $actualAvatar = $this->source->fetch($email, $avatarFactory, false);
$this->assertNull($actualAvatar);
}
@@ -91,7 +130,7 @@ class CompositeAvatarSourceTest extends TestCase {
->with($email, $avatarFactory)
->willReturn($avatar);
- $actualAvatar = $this->source->fetch($email, $avatarFactory);
+ $actualAvatar = $this->source->fetch($email, $avatarFactory, true);
$this->assertEquals($avatar, $actualAvatar);
}
diff --git a/tests/Service/AvatarServiceTest.php b/tests/Service/AvatarServiceTest.php
index 6a642d628..348efe287 100644
--- a/tests/Service/AvatarServiceTest.php
+++ b/tests/Service/AvatarServiceTest.php
@@ -24,6 +24,7 @@
namespace OCA\Mail\Tests\Service;
+use OCA\Mail\Contracts\IUserPreferences;
use OCA\Mail\Service\Avatar\Avatar;
use OCA\Mail\Service\Avatar\AvatarFactory;
use OCA\Mail\Service\Avatar\Cache;
@@ -54,6 +55,9 @@ class AvatarServiceTest extends TestCase {
/** @var AvatarFactory|PHPUnit_Framework_MockObject_MockObject */
private $avatarFactory;
+ /** @var IUserPreferences */
+ private $preferences;
+
/** @var AvatarService */
private $avatarService;
@@ -65,8 +69,10 @@ class AvatarServiceTest extends TestCase {
$this->cache = $this->createMock(Cache::class);
$this->urlGenerator = $this->createMock(IURLGenerator::class);
$this->avatarFactory = $this->createMock(AvatarFactory::class);
+ $this->preferences = $this->createMock(IUserPreferences::class);
- $this->avatarService = new AvatarService($this->source, $this->downloader, $this->cache, $this->urlGenerator, $this->avatarFactory);
+ $this->avatarService = new AvatarService($this->source, $this->downloader,
+ $this->cache, $this->urlGenerator, $this->avatarFactory, $this->preferences);
}
public function testGetCachedAvatarUrl() {
@@ -85,13 +91,17 @@ class AvatarServiceTest extends TestCase {
public function testGetAvatarNoAvatarFound() {
$email = 'jane@doe.com';
$uid = 'john';
+ $this->preferences->expects($this->once())
+ ->method('getPreference')
+ ->with('external-avatars', 'true')
+ ->willReturn('true');
$this->cache->expects($this->once())
->method('get')
->with($email)
->willReturn(null);
$this->source->expects($this->once())
->method('fetch')
- ->with($email, $this->avatarFactory)
+ ->with($email, $this->avatarFactory, true)
->willReturn(null);
$this->cache->expects($this->never())
->method('add');
@@ -104,6 +114,10 @@ class AvatarServiceTest extends TestCase {
public function testGetAvatarMimeNotAllowed() {
$email = 'jane@doe.com';
$uid = 'john';
+ $this->preferences->expects($this->once())
+ ->method('getPreference')
+ ->with('external-avatars', 'true')
+ ->willReturn('true');
$this->cache->expects($this->once())
->method('get')
->with($email)
@@ -111,7 +125,7 @@ class AvatarServiceTest extends TestCase {
$avatar = new Avatar('http://…', 'application/xml');
$this->source->expects($this->once())
->method('fetch')
- ->with($email, $this->avatarFactory)
+ ->with($email, $this->avatarFactory, true)
->willReturn($avatar);
$this->cache->expects($this->never())
->method('add');
@@ -121,17 +135,46 @@ class AvatarServiceTest extends TestCase {
$this->assertNull($url);
}
+ public function testGetAvatarOnlyInternalAllowed() {
+ $email = 'jane@doe.com';
+ $uid = 'john';
+ $avatar = new Avatar('https://doe.com/favicon.ico', 'image/png');
+ $this->preferences->expects($this->once())
+ ->method('getPreference')
+ ->with('external-avatars', 'true')
+ ->willReturn('false');
+ $this->cache->expects($this->once())
+ ->method('get')
+ ->with($email)
+ ->willReturn(null);
+ $this->source->expects($this->once())
+ ->method('fetch')
+ ->with($email, $this->avatarFactory, false)
+ ->willReturn($avatar);
+ $this->cache->expects($this->once())
+ ->method('add')
+ ->with($email, $uid, $avatar);
+
+ $actualAvatar = $this->avatarService->getAvatar($email, $uid);
+
+ $this->assertEquals($avatar, $actualAvatar);
+ }
+
public function testGetAvatar() {
$email = 'jane@doe.com';
$uid = 'john';
$avatar = new Avatar('https://doe.com/favicon.ico', 'image/png');
+ $this->preferences->expects($this->once())
+ ->method('getPreference')
+ ->with('external-avatars', 'true')
+ ->willReturn('true');
$this->cache->expects($this->once())
->method('get')
->with($email)
->willReturn(null);
$this->source->expects($this->once())
->method('fetch')
- ->with($email, $this->avatarFactory)
+ ->with($email, $this->avatarFactory, true)
->willReturn($avatar);
$this->cache->expects($this->once())
->method('add')
diff --git a/tests/Service/UserPreferenceServiceTest.php b/tests/Service/UserPreferenceServiceTest.php
new file mode 100644
index 000000000..4e5a0e079
--- /dev/null
+++ b/tests/Service/UserPreferenceServiceTest.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @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\Mail\Tests\Service;
+
+use OCA\Mail\Service\UserPreferenceSevice;
+use OCA\Mail\Tests\TestCase;
+use OCP\IConfig;
+
+class UserPreferenceServiceTest extends TestCase {
+
+ /** @var IConfig */
+ private $config;
+
+ /** @var string */
+ private $userId = 'claire';
+
+ /** @var UserPreferenceSevice */
+ private $service;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->config = $this->createMock(IConfig::class);
+ $this->service = new UserPreferenceSevice($this->config, $this->userId);
+ }
+
+ public function testGetPreference() {
+ $this->config->expects($this->once())
+ ->method('getUserValue')
+ ->with($this->userId, 'mail', 'test', null)
+ ->willReturn('123');
+ $expected = '123';
+
+ $actual = $this->service->getPreference('test');
+
+ $this->assertEquals($expected, $actual);
+ }
+
+ public function testSetPreference() {
+ $this->config->expects($this->once())
+ ->method('setUserValue')
+ ->with($this->userId, 'mail', 'test', '123')
+ ->willReturn('123');
+
+ $this->service->setPreference('test', '123');
+ }
+
+}