Move tag related code into a helper so we can test the query without a view

This commit is contained in:
Joas Schilling 2015-03-30 17:21:06 +02:00
parent e365ea7ec5
commit 9233d32834
4 changed files with 414 additions and 34 deletions

View File

@ -61,7 +61,9 @@ $templateManager->registerTemplate('application/vnd.oasis.opendocument.spreadshe
\OC::$server->query('L10NFactory'), \OC::$server->query('L10NFactory'),
\OC::$server->getURLGenerator(), \OC::$server->getURLGenerator(),
\OC::$server->getActivityManager(), \OC::$server->getActivityManager(),
\OC::$server->getTagManager(), new \OCA\Files\ActivityHelper(
\OC::$server->getTagManager()
),
\OC::$server->getConfig() \OC::$server->getConfig()
); );
}); });

View File

@ -27,7 +27,6 @@ use OCP\Activity\IExtension;
use OCP\Activity\IManager; use OCP\Activity\IManager;
use OCP\IConfig; use OCP\IConfig;
use OCP\IL10N; use OCP\IL10N;
use OCP\ITagManager;
use OCP\IURLGenerator; use OCP\IURLGenerator;
class Activity implements IExtension { class Activity implements IExtension {
@ -55,22 +54,22 @@ class Activity implements IExtension {
/** @var \OCP\IConfig */ /** @var \OCP\IConfig */
protected $config; protected $config;
/** @var \OCP\ITagManager */ /** @var \OCA\Files\ActivityHelper */
protected $tagManager; protected $helper;
/** /**
* @param Factory $languageFactory * @param Factory $languageFactory
* @param IURLGenerator $URLGenerator * @param IURLGenerator $URLGenerator
* @param IManager $activityManager * @param IManager $activityManager
* @param ITagManager $tagManager * @param ActivityHelper $helper
* @param IConfig $config * @param IConfig $config
*/ */
public function __construct(Factory $languageFactory, IURLGenerator $URLGenerator, IManager $activityManager, ITagManager $tagManager, IConfig $config) { public function __construct(Factory $languageFactory, IURLGenerator $URLGenerator, IManager $activityManager, ActivityHelper $helper, IConfig $config) {
$this->languageFactory = $languageFactory; $this->languageFactory = $languageFactory;
$this->URLGenerator = $URLGenerator; $this->URLGenerator = $URLGenerator;
$this->l = $this->getL10N(); $this->l = $this->getL10N();
$this->activityManager = $activityManager; $this->activityManager = $activityManager;
$this->tagManager = $tagManager; $this->helper = $helper;
$this->config = $config; $this->config = $config;
} }
@ -94,7 +93,7 @@ class Activity implements IExtension {
return [ return [
self::TYPE_SHARE_CREATED => (string) $l->t('A new file or folder has been <strong>created</strong>'), self::TYPE_SHARE_CREATED => (string) $l->t('A new file or folder has been <strong>created</strong>'),
self::TYPE_SHARE_CHANGED => (string) $l->t('A file or folder has been <strong>changed</strong>'), self::TYPE_SHARE_CHANGED => (string) $l->t('A file or folder has been <strong>changed</strong>'),
self::TYPE_FAVORITES => (string) $l->t('Limit notifications about creation and changes to your <strong>favorite files</strong>'), self::TYPE_FAVORITES => (string) $l->t('Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>'),
self::TYPE_SHARE_DELETED => (string) $l->t('A file or folder has been <strong>deleted</strong>'), self::TYPE_SHARE_DELETED => (string) $l->t('A file or folder has been <strong>deleted</strong>'),
self::TYPE_SHARE_RESTORED => (string) $l->t('A file or folder has been <strong>restored</strong>'), self::TYPE_SHARE_RESTORED => (string) $l->t('A file or folder has been <strong>restored</strong>'),
]; ];
@ -250,19 +249,20 @@ class Activity implements IExtension {
*/ */
public function getNavigation() { public function getNavigation() {
return [ return [
'apps' => [ 'top' => [
self::FILTER_FAVORITES => [ self::FILTER_FAVORITES => [
'id' => self::FILTER_FAVORITES, 'id' => self::FILTER_FAVORITES,
'name' => (string) $this->l->t('Favorites'), 'name' => (string) $this->l->t('Favorites'),
'url' => $this->URLGenerator->linkToRoute('activity.Activities.showList', ['filter' => self::FILTER_FAVORITES]), 'url' => $this->URLGenerator->linkToRoute('activity.Activities.showList', ['filter' => self::FILTER_FAVORITES]),
], ],
],
'apps' => [
self::FILTER_FILES => [ self::FILTER_FILES => [
'id' => self::FILTER_FILES, 'id' => self::FILTER_FILES,
'name' => (string) $this->l->t('Files'), 'name' => (string) $this->l->t('Files'),
'url' => $this->URLGenerator->linkToRoute('activity.Activities.showList', ['filter' => self::FILTER_FILES]), 'url' => $this->URLGenerator->linkToRoute('activity.Activities.showList', ['filter' => self::FILTER_FILES]),
], ],
], ],
'top' => [],
]; ];
} }
@ -319,41 +319,38 @@ class Activity implements IExtension {
// Display actions from favorites only // Display actions from favorites only
if ($filter === self::FILTER_FAVORITES || $filter === 'all' && $this->userSettingFavoritesOnly($user)) { if ($filter === self::FILTER_FAVORITES || $filter === 'all' && $this->userSettingFavoritesOnly($user)) {
$tags = $this->tagManager->load('files', [], false, $user); try {
$favorites = $tags->getFavorites(); $favorites = $this->helper->getFavoriteFilePaths($user);
} catch (\RuntimeException $e) {
if (isset($favorites[50])) {
// Too many favorites, can not put them into one query anymore... // Too many favorites, can not put them into one query anymore...
return ['`app` = ?', ['files']]; return ['`app` = ?', ['files']];
} }
// Can not DI because the user is not known on instantiation /*
$rootFolder = \OC::$server->getUserFolder($user); * Display activities only, when they are not `type` create/change
* or `file` is a favorite or in a favorite folder
*/
$parameters = $fileQueryList = []; $parameters = $fileQueryList = [];
foreach ($favorites as $favorite) { $parameters[] = 'files';
$nodes = $rootFolder->getById($favorite);
if ($nodes) {
/** @var \OCP\Files\Node $node */
$node = array_shift($nodes);
$fileQueryList[] = '`type` <> ?';
$parameters[] = self::TYPE_SHARE_CREATED;
$fileQueryList[] = '`type` <> ?';
$parameters[] = self::TYPE_SHARE_CHANGED;
foreach ($favorites['items'] as $favorite) {
$fileQueryList[] = '`file` = ?'; $fileQueryList[] = '`file` = ?';
$parameters[] = substr($node->getPath(), strlen($user . '/files/')); $parameters[] = $favorite;
}
if ($node instanceof \OCP\Files\Folder) { foreach ($favorites['folders'] as $favorite) {
// Also look for subfolders and files
$fileQueryList[] = '`file` LIKE ?'; $fileQueryList[] = '`file` LIKE ?';
$parameters[] = substr($node->getPath(), strlen($user . '/files/')) . '/%'; $parameters[] = $favorite . '/%';
}
}
} }
if (empty($fileQueryList)) { $parameters[] = 'files';
// No favorites...
return ['`app` = ?', ['files']];
}
return [ return [
' CASE WHEN `app` = \'files\' THEN (' . implode(' OR ', $fileQueryList) . ') ELSE `app` <> \'files\' END ', ' CASE WHEN `app` = ? THEN (' . implode(' OR ', $fileQueryList) . ') ELSE `app` <> ? END ',
$parameters, $parameters,
]; ];
} }

View File

@ -0,0 +1,84 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files;
use OCP\Files\Folder;
use OCP\ITagManager;
class ActivityHelper {
/** If a user has a lot of favorites the query might get too slow and long */
const FAVORITE_LIMIT = 50;
/** @var \OCP\ITagManager */
protected $tagManager;
/**
* @param ITagManager $tagManager
*/
public function __construct(ITagManager $tagManager) {
$this->tagManager = $tagManager;
}
/**
* Returns an array with the favorites
*
* @param string $user
* @return array
* @throws \RuntimeException when too many or no favorites where found
*/
public function getFavoriteFilePaths($user) {
$tags = $this->tagManager->load('files', [], false, $user);
$favorites = $tags->getFavorites();
if (empty($favorites)) {
throw new \RuntimeException('No favorites', 1);
} else if (isset($favorites[self::FAVORITE_LIMIT])) {
throw new \RuntimeException('Too many favorites', 2);
}
// Can not DI because the user is not known on instantiation
$rootFolder = \OC::$server->getUserFolder($user);
$folders = $items = [];
foreach ($favorites as $favorite) {
$nodes = $rootFolder->getById($favorite);
if ($nodes) {
/** @var \OCP\Files\Node $node */
$node = array_shift($nodes);
$path = substr($node->getPath(), strlen($user . '/files/'));
$items[] = $path;
if ($node instanceof Folder) {
$folders[] = $path;
}
}
}
if (empty($items)) {
throw new \RuntimeException('No favorites', 1);
}
return [
'items' => $items,
'folders' => $folders,
];
}
}

View File

@ -0,0 +1,297 @@
<?php
/**
* Copyright (c) 2015 Joas Schilling <nickvergessen@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*
*/
namespace OCA\Files\Tests;
use OCA\Files\Activity;
use Test\TestCase;
class ActivityTest extends TestCase {
/** @var \OC\ActivityManager */
private $activityManager;
/** @var \PHPUnit_Framework_MockObject_MockObject */
protected $request;
/** @var \PHPUnit_Framework_MockObject_MockObject */
protected $session;
/** @var \PHPUnit_Framework_MockObject_MockObject */
protected $config;
/** @var \PHPUnit_Framework_MockObject_MockObject */
protected $activityHelper;
/** @var \OCA\Files\Activity */
protected $activityExtension;
protected function setUp() {
parent::setUp();
$this->request = $this->getMockBuilder('OCP\IRequest')
->disableOriginalConstructor()
->getMock();
$this->session = $this->getMockBuilder('OCP\IUserSession')
->disableOriginalConstructor()
->getMock();
$this->config = $this->getMockBuilder('OCP\IConfig')
->disableOriginalConstructor()
->getMock();
$this->activityHelper = $this->getMockBuilder('OCA\Files\ActivityHelper')
->disableOriginalConstructor()
->getMock();
$this->activityManager = new \OC\ActivityManager(
$this->request,
$this->session,
$this->config
);
$this->activityExtension = $activityExtension = new Activity(
new \OC\L10N\Factory(),
$this->getMockBuilder('OCP\IURLGenerator')->disableOriginalConstructor()->getMock(),
$this->activityManager,
$this->activityHelper,
$this->config
);
$this->activityManager->registerExtension(function() use ($activityExtension) {
return $activityExtension;
});
}
public function testNotificationTypes() {
$result = $this->activityExtension->getNotificationTypes('en');
$this->assertTrue(is_array($result), 'Asserting getNotificationTypes() returns an array');
$this->assertCount(5, $result);
$this->assertArrayHasKey(Activity::TYPE_SHARE_CREATED, $result);
$this->assertArrayHasKey(Activity::TYPE_SHARE_CHANGED, $result);
$this->assertArrayHasKey(Activity::TYPE_FAVORITES, $result);
$this->assertArrayHasKey(Activity::TYPE_SHARE_DELETED, $result);
$this->assertArrayHasKey(Activity::TYPE_SHARE_RESTORED, $result);
}
public function testDefaultTypes() {
$result = $this->activityExtension->getDefaultTypes('stream');
$this->assertTrue(is_array($result), 'Asserting getDefaultTypes(stream) returns an array');
$this->assertCount(4, $result);
$result = array_flip($result);
$this->assertArrayHasKey(Activity::TYPE_SHARE_CREATED, $result);
$this->assertArrayHasKey(Activity::TYPE_SHARE_CHANGED, $result);
$this->assertArrayNotHasKey(Activity::TYPE_FAVORITES, $result);
$this->assertArrayHasKey(Activity::TYPE_SHARE_DELETED, $result);
$this->assertArrayHasKey(Activity::TYPE_SHARE_RESTORED, $result);
$result = $this->activityExtension->getDefaultTypes('email');
$this->assertFalse($result, 'Asserting getDefaultTypes(email) returns false');
}
public function testTranslate() {
$this->assertFalse(
$this->activityExtension->translate('files_sharing', '', '', array(), false, false, 'en'),
'Asserting that no translations are set for files_sharing'
);
}
public function testGetSpecialParameterList() {
$this->assertFalse(
$this->activityExtension->getSpecialParameterList('files_sharing', ''),
'Asserting that no special parameters are set for files_sharing'
);
}
public function typeIconData() {
return [
[Activity::TYPE_SHARE_CHANGED, 'icon-change'],
[Activity::TYPE_SHARE_CREATED, 'icon-add-color'],
[Activity::TYPE_SHARE_DELETED, 'icon-delete-color'],
[Activity::TYPE_SHARE_RESTORED, false],
[Activity::TYPE_FAVORITES, false],
['unknown type', false],
];
}
/**
* @dataProvider typeIconData
*
* @param string $type
* @param mixed $expected
*/
public function testTypeIcon($type, $expected) {
$this->assertSame($expected, $this->activityExtension->getTypeIcon($type));
}
public function testGroupParameter() {
$this->assertFalse(
$this->activityExtension->getGroupParameter(['app' => 'files_sharing']),
'Asserting that no group parameters are set for files_sharing'
);
}
public function testNavigation() {
$result = $this->activityExtension->getNavigation();
$this->assertCount(1, $result['top']);
$this->assertArrayHasKey(Activity::FILTER_FAVORITES, $result['top']);
$this->assertCount(1, $result['apps']);
$this->assertArrayHasKey(Activity::FILTER_FILES, $result['apps']);
}
public function testIsFilterValid() {
$this->assertTrue($this->activityExtension->isFilterValid(Activity::FILTER_FAVORITES));
$this->assertTrue($this->activityExtension->isFilterValid(Activity::FILTER_FILES));
$this->assertFalse($this->activityExtension->isFilterValid('unknown filter'));
}
public function filterNotificationTypesData() {
return [
[
Activity::FILTER_FILES,
[
'NT0',
Activity::TYPE_SHARE_CREATED,
Activity::TYPE_SHARE_CHANGED,
Activity::TYPE_SHARE_DELETED,
Activity::TYPE_SHARE_RESTORED,
Activity::TYPE_FAVORITES,
], [
Activity::TYPE_SHARE_CREATED,
Activity::TYPE_SHARE_CHANGED,
Activity::TYPE_SHARE_DELETED,
Activity::TYPE_SHARE_RESTORED,
],
],
[
Activity::FILTER_FILES,
[
'NT0',
Activity::TYPE_SHARE_CREATED,
Activity::TYPE_FAVORITES,
],
[
Activity::TYPE_SHARE_CREATED,
],
],
[
Activity::FILTER_FAVORITES,
[
'NT0',
Activity::TYPE_SHARE_CREATED,
Activity::TYPE_SHARE_CHANGED,
Activity::TYPE_SHARE_DELETED,
Activity::TYPE_SHARE_RESTORED,
Activity::TYPE_FAVORITES,
], [
Activity::TYPE_SHARE_CREATED,
Activity::TYPE_SHARE_CHANGED,
Activity::TYPE_SHARE_DELETED,
Activity::TYPE_SHARE_RESTORED,
],
],
[
'unknown filter',
[
'NT0',
Activity::TYPE_SHARE_CREATED,
Activity::TYPE_SHARE_CHANGED,
Activity::TYPE_SHARE_DELETED,
Activity::TYPE_SHARE_RESTORED,
Activity::TYPE_FAVORITES,
],
false,
],
];
}
/**
* @dataProvider filterNotificationTypesData
*
* @param string $filter
* @param array $types
* @param mixed $expected
*/
public function testFilterNotificationTypes($filter, $types, $expected) {
$result = $this->activityExtension->filterNotificationTypes($types, $filter);
$this->assertEquals($expected, $result);
}
public function queryForFilterData() {
return [
[
new \RuntimeException(),
'`app` = ?',
['files']
],
[
[
'items' => [],
'folders' => [],
],
' CASE WHEN `app` = ? THEN (`type` <> ? OR `type` <> ?) ELSE `app` <> ? END ',
['files', Activity::TYPE_SHARE_CREATED, Activity::TYPE_SHARE_CHANGED, 'files']
],
[
[
'items' => ['file.txt', 'folder'],
'folders' => ['folder'],
],
' CASE WHEN `app` = ? THEN (`type` <> ? OR `type` <> ? OR `file` = ? OR `file` = ? OR `file` LIKE ?) ELSE `app` <> ? END ',
['files', Activity::TYPE_SHARE_CREATED, Activity::TYPE_SHARE_CHANGED, 'file.txt', 'folder', 'folder/%', 'files']
],
];
}
/**
* @dataProvider queryForFilterData
*
* @param mixed $will
* @param string $query
* @param array $parameters
*/
public function testQueryForFilter($will, $query, $parameters) {
$this->mockUserSession('test');
$this->config->expects($this->any())
->method('getUserValue')
->willReturnMap([
['test', 'activity', 'notify_stream_' . Activity::TYPE_FAVORITES, false, true],
]);
if (is_array($will)) {
$this->activityHelper->expects($this->any())
->method('getFavoriteFilePaths')
->with('test')
->willReturn($will);
} else {
$this->activityHelper->expects($this->any())
->method('getFavoriteFilePaths')
->with('test')
->willThrowException($will);
}
$result = $this->activityExtension->getQueryForFilter('all');
$this->assertEquals([$query, $parameters], $result);
}
protected function mockUserSession($user) {
$mockUser = $this->getMockBuilder('\OCP\IUser')
->disableOriginalConstructor()
->getMock();
$mockUser->expects($this->any())
->method('getUID')
->willReturn($user);
$this->session->expects($this->any())
->method('isLoggedIn')
->willReturn(true);
$this->session->expects($this->any())
->method('getUser')
->willReturn($mockUser);
}
}