Added system tags data structure and PHP side managers
Added SystemTagManager and SystemTagObjectMapper
This commit is contained in:
parent
129ec4fb40
commit
b666367a79
124
db_structure.xml
124
db_structure.xml
|
@ -1063,6 +1063,130 @@
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<!--
|
||||||
|
List of system-wide tags
|
||||||
|
-->
|
||||||
|
<name>*dbprefix*systemtag</name>
|
||||||
|
|
||||||
|
<declaration>
|
||||||
|
|
||||||
|
<field>
|
||||||
|
<name>id</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default>0</default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<autoincrement>1</autoincrement>
|
||||||
|
<unsigned>true</unsigned>
|
||||||
|
<length>4</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<!-- Tag name -->
|
||||||
|
<field>
|
||||||
|
<name>name</name>
|
||||||
|
<type>text</type>
|
||||||
|
<default></default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>64</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<!-- Visibility: 0 user-not-visible, 1 user-visible -->
|
||||||
|
<field>
|
||||||
|
<name>visibility</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default>1</default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>1</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<!-- Editable: 0 user-not-editable, 1 user-editable -->
|
||||||
|
<field>
|
||||||
|
<name>editable</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default>1</default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>1</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<index>
|
||||||
|
<name>tag_ident</name>
|
||||||
|
<unique>true</unique>
|
||||||
|
<field>
|
||||||
|
<name>name</name>
|
||||||
|
<sorting>ascending</sorting>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>visibility</name>
|
||||||
|
<sorting>ascending</sorting>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>editable</name>
|
||||||
|
<sorting>ascending</sorting>
|
||||||
|
</field>
|
||||||
|
</index>
|
||||||
|
|
||||||
|
</declaration>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
System tag to object associations per object type.
|
||||||
|
-->
|
||||||
|
<name>*dbprefix*systemtag_object_mapping</name>
|
||||||
|
|
||||||
|
<declaration>
|
||||||
|
|
||||||
|
<!-- object id (ex: file id for files)-->
|
||||||
|
<field>
|
||||||
|
<name>objectid</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default>0</default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<unsigned>true</unsigned>
|
||||||
|
<length>4</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<!-- object type (ex: "files")-->
|
||||||
|
<field>
|
||||||
|
<name>objecttype</name>
|
||||||
|
<type>text</type>
|
||||||
|
<default></default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>64</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<!-- Foreign Key systemtag::id -->
|
||||||
|
<field>
|
||||||
|
<name>systemtagid</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default>0</default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<unsigned>true</unsigned>
|
||||||
|
<length>4</length>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<index>
|
||||||
|
<unique>true</unique>
|
||||||
|
<name>mapping</name>
|
||||||
|
<field>
|
||||||
|
<name>objecttype</name>
|
||||||
|
<sorting>ascending</sorting>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>objectid</name>
|
||||||
|
<sorting>ascending</sorting>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>systemtagid</name>
|
||||||
|
<sorting>ascending</sorting>
|
||||||
|
</field>
|
||||||
|
</index>
|
||||||
|
|
||||||
|
</declaration>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|
|
@ -138,6 +138,12 @@ class Server extends SimpleContainer implements IServerContainer {
|
||||||
$tagMapper = $c->query('TagMapper');
|
$tagMapper = $c->query('TagMapper');
|
||||||
return new TagManager($tagMapper, $c->getUserSession());
|
return new TagManager($tagMapper, $c->getUserSession());
|
||||||
});
|
});
|
||||||
|
$this->registerService('SystemTagManager', function (Server $c) {
|
||||||
|
return new SystemTag\SystemTagManager($c->getDatabaseConnection());
|
||||||
|
});
|
||||||
|
$this->registerService('SystemTagObjectMapper', function (Server $c) {
|
||||||
|
return new SystemTag\SystemTagObjectMapper($c->getDatabaseConnection(), $c->getSystemTagManager());
|
||||||
|
});
|
||||||
$this->registerService('RootFolder', function (Server $c) {
|
$this->registerService('RootFolder', function (Server $c) {
|
||||||
// TODO: get user and user manager from container as well
|
// TODO: get user and user manager from container as well
|
||||||
$user = \OC_User::getUser();
|
$user = \OC_User::getUser();
|
||||||
|
@ -581,6 +587,29 @@ class Server extends SimpleContainer implements IServerContainer {
|
||||||
return $this->query('TagManager');
|
return $this->query('TagManager');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the system-tag manager
|
||||||
|
*
|
||||||
|
* @return \OCP\SystemTag\ISystemTagManager
|
||||||
|
*
|
||||||
|
* @since 9.0.0
|
||||||
|
*/
|
||||||
|
public function getSystemTagManager() {
|
||||||
|
return $this->query('SystemTagManager');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the system-tag object mapper
|
||||||
|
*
|
||||||
|
* @return \OCP\SystemTag\ISystemTagObjectMapper
|
||||||
|
*
|
||||||
|
* @since 9.0.0
|
||||||
|
*/
|
||||||
|
public function getSystemTagObjectMapper() {
|
||||||
|
return $this->query('SystemTagObjectMapper');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the avatar manager, used for avatar functionality
|
* Returns the avatar manager, used for avatar functionality
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Vincent Petry <pvince81@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 OC\SystemTag;
|
||||||
|
|
||||||
|
use \OCP\IDBConnection;
|
||||||
|
|
||||||
|
class SystemTag implements \OCP\SystemTag\ISystemTag {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $userVisible;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $userAssignable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param string $id tag id
|
||||||
|
* @param string $name tag name
|
||||||
|
* @param bool $userVisible whether the tag is user visible
|
||||||
|
* @param bool $userAssignable whether the tag is user assignable
|
||||||
|
*/
|
||||||
|
public function __construct($id, $name, $userVisible, $userAssignable) {
|
||||||
|
$this->id = $id;
|
||||||
|
$this->name = $name;
|
||||||
|
$this->userVisible = $userVisible;
|
||||||
|
$this->userAssignable = $userAssignable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getId() {
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getName() {
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function isUserVisible() {
|
||||||
|
return $this->userVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function isUserAssignable() {
|
||||||
|
return $this->userAssignable;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,264 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Vincent Petry <pvince81@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 OC\SystemTag;
|
||||||
|
|
||||||
|
use \OCP\IDBConnection;
|
||||||
|
use \OCP\SystemTag\TagNotFoundException;
|
||||||
|
use \OCP\SystemTag\TagAlreadyExistsException;
|
||||||
|
|
||||||
|
use \Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||||
|
|
||||||
|
class SystemTagManager implements \OCP\SystemTag\ISystemTagManager {
|
||||||
|
|
||||||
|
const TAG_TABLE = 'systemtag';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var IDBConnection
|
||||||
|
*/
|
||||||
|
private $connection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepared query for selecting tags directly
|
||||||
|
*
|
||||||
|
* @var \OCP\DB\QueryBuilder\IQueryBuilder
|
||||||
|
*/
|
||||||
|
private $selectTagQuery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param IDBConnection $connection database connection
|
||||||
|
*/
|
||||||
|
public function __construct(IDBConnection $connection) {
|
||||||
|
$this->connection = $connection;
|
||||||
|
|
||||||
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
$this->selectTagQuery = $query->select('*')
|
||||||
|
->from(self::TAG_TABLE)
|
||||||
|
->where($query->expr()->eq('name', $query->createParameter('name')))
|
||||||
|
->andWhere($query->expr()->eq('visibility', $query->createParameter('visibility')))
|
||||||
|
->andWhere($query->expr()->eq('editable', $query->createParameter('editable')));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getTagsById($tagIds) {
|
||||||
|
if (!is_array($tagIds)) {
|
||||||
|
$tagIds = [$tagIds];
|
||||||
|
}
|
||||||
|
|
||||||
|
$tags = [];
|
||||||
|
|
||||||
|
// note: not all databases will fail if it's a string or starts with a number
|
||||||
|
foreach ($tagIds as $tagId) {
|
||||||
|
if (!is_numeric($tagId)) {
|
||||||
|
throw new \InvalidArgumentException('Tag id must be integer');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
$query->select('*')
|
||||||
|
->from(self::TAG_TABLE)
|
||||||
|
->where($query->expr()->in('id', $query->createParameter('tagids')))
|
||||||
|
->addOrderBy('name', 'ASC')
|
||||||
|
->addOrderBy('visibility', 'ASC')
|
||||||
|
->addOrderBy('editable', 'ASC')
|
||||||
|
->setParameter('tagids', $tagIds, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY);
|
||||||
|
|
||||||
|
$result = $query->execute();
|
||||||
|
while ($row = $result->fetch()) {
|
||||||
|
$tags[$row['id']] = $this->createSystemTagFromRow($row);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result->closeCursor();
|
||||||
|
|
||||||
|
if (count($tags) !== count($tagIds)) {
|
||||||
|
throw new TagNotFoundException(
|
||||||
|
'Tag(s) with id(s) ' . json_encode(array_diff($tagIds, array_keys($tags))) . ' not found'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getAllTags($visibilityFilter = null, $nameSearchPattern = null) {
|
||||||
|
$tags = [];
|
||||||
|
|
||||||
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
$query->select('*')
|
||||||
|
->from(self::TAG_TABLE);
|
||||||
|
|
||||||
|
if (!is_null($visibilityFilter)) {
|
||||||
|
$query->andWhere($query->expr()->eq('visibility', $query->createNamedParameter((int)$visibilityFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($nameSearchPattern)) {
|
||||||
|
$query->andWhere(
|
||||||
|
$query->expr()->like(
|
||||||
|
'name',
|
||||||
|
$query->expr()->literal('%' . $this->connection->escapeLikeParameter($nameSearchPattern). '%')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$query
|
||||||
|
->addOrderBy('name', 'ASC')
|
||||||
|
->addOrderBy('visibility', 'ASC')
|
||||||
|
->addOrderBy('editable', 'ASC');
|
||||||
|
|
||||||
|
$result = $query->execute();
|
||||||
|
while ($row = $result->fetch()) {
|
||||||
|
$tags[$row['id']] = $this->createSystemTagFromRow($row);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result->closeCursor();
|
||||||
|
|
||||||
|
return $tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getTag($tagName, $userVisible, $userAssignable) {
|
||||||
|
$userVisible = (int)$userVisible;
|
||||||
|
$userAssignable = (int)$userAssignable;
|
||||||
|
|
||||||
|
$result = $this->selectTagQuery
|
||||||
|
->setParameter('name', $tagName)
|
||||||
|
->setParameter('visibility', $userVisible)
|
||||||
|
->setParameter('editable', $userAssignable)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$row = $result->fetch();
|
||||||
|
$result->closeCursor();
|
||||||
|
if (!$row) {
|
||||||
|
throw new TagNotFoundException(
|
||||||
|
'Tag ("' . $tagName . '", '. $userVisible . ', ' . $userAssignable . ') does not exist'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->createSystemTagFromRow($row);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function createTag($tagName, $userVisible, $userAssignable) {
|
||||||
|
$userVisible = (int)$userVisible;
|
||||||
|
$userAssignable = (int)$userAssignable;
|
||||||
|
|
||||||
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
$query->insert(self::TAG_TABLE)
|
||||||
|
->values([
|
||||||
|
'name' => $query->createNamedParameter($tagName),
|
||||||
|
'visibility' => $query->createNamedParameter($userVisible),
|
||||||
|
'editable' => $query->createNamedParameter($userAssignable),
|
||||||
|
]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$query->execute();
|
||||||
|
} catch (UniqueConstraintViolationException $e) {
|
||||||
|
throw new TagAlreadyExistsException(
|
||||||
|
'Tag ("' . $tagName . '", '. $userVisible . ', ' . $userAssignable . ') already exists',
|
||||||
|
0,
|
||||||
|
$e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tagId = $this->connection->lastInsertId('*PREFIX*' . self::TAG_TABLE);
|
||||||
|
|
||||||
|
return new SystemTag(
|
||||||
|
(int)$tagId,
|
||||||
|
$tagName,
|
||||||
|
(bool)$userVisible,
|
||||||
|
(bool)$userAssignable
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function updateTag($tagId, $tagName, $userVisible, $userAssignable) {
|
||||||
|
$userVisible = (int)$userVisible;
|
||||||
|
$userAssignable = (int)$userAssignable;
|
||||||
|
|
||||||
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
$query->update(self::TAG_TABLE)
|
||||||
|
->set('name', $query->createParameter('name'))
|
||||||
|
->set('visibility', $query->createParameter('visibility'))
|
||||||
|
->set('editable', $query->createParameter('editable'))
|
||||||
|
->where($query->expr()->eq('id', $query->createParameter('tagid')))
|
||||||
|
->setParameter('name', $tagName)
|
||||||
|
->setParameter('visibility', $userVisible)
|
||||||
|
->setParameter('editable', $userAssignable)
|
||||||
|
->setParameter('tagid', $tagId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($query->execute() === 0) {
|
||||||
|
throw new TagNotFoundException(
|
||||||
|
'Tag ("' . $tagName . '", '. $userVisible . ', ' . $userAssignable . ') does not exist'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (UniqueConstraintViolationException $e) {
|
||||||
|
throw new TagAlreadyExistsException(
|
||||||
|
'Tag ("' . $tagName . '", '. $userVisible . ', ' . $userAssignable . ') already exists',
|
||||||
|
0,
|
||||||
|
$e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function deleteTags($tagIds) {
|
||||||
|
if (!is_array($tagIds)) {
|
||||||
|
$tagIds = [$tagIds];
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete relationships first
|
||||||
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
$query->delete(SystemTagObjectMapper::RELATION_TABLE)
|
||||||
|
->where($query->expr()->in('systemtagid', $query->createParameter('tagids')))
|
||||||
|
->setParameter('tagids', $tagIds, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
$query->delete(self::TAG_TABLE)
|
||||||
|
->where($query->expr()->in('id', $query->createParameter('tagids')))
|
||||||
|
->setParameter('tagids', $tagIds, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY);
|
||||||
|
|
||||||
|
if ($query->execute() === 0) {
|
||||||
|
throw new TagNotFoundException(
|
||||||
|
'Tag does not exist'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createSystemTagFromRow($row) {
|
||||||
|
return new SystemTag((int)$row['id'], $row['name'], (bool)$row['visibility'], (bool)$row['editable']);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,213 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Vincent Petry <pvince81@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 OC\SystemTag;
|
||||||
|
|
||||||
|
use \OCP\SystemTag\ISystemTagManager;
|
||||||
|
use \OCP\IDBConnection;
|
||||||
|
use \OCP\SystemTag\TagNotFoundException;
|
||||||
|
use \Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||||
|
|
||||||
|
class SystemTagObjectMapper implements \OCP\SystemTag\ISystemTagObjectMapper {
|
||||||
|
|
||||||
|
const RELATION_TABLE = 'systemtag_object_mapping';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ISystemTagManager
|
||||||
|
*/
|
||||||
|
private $tagManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var IDBConnection
|
||||||
|
*/
|
||||||
|
private $connection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param IDBConnection $connection database connection
|
||||||
|
* @param ISystemTagManager $tagManager system tag manager
|
||||||
|
*/
|
||||||
|
public function __construct(IDBConnection $connection, ISystemTagManager $tagManager) {
|
||||||
|
$this->connection = $connection;
|
||||||
|
$this->tagManager = $tagManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getTagIdsForObjects($objIds, $objectType) {
|
||||||
|
if (!is_array($objIds)) {
|
||||||
|
$objIds = [$objIds];
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
$query->select(['systemtagid', 'objectid'])
|
||||||
|
->from(self::RELATION_TABLE)
|
||||||
|
->where($query->expr()->in('objectid', $query->createParameter('objectids')))
|
||||||
|
->andWhere($query->expr()->eq('objecttype', $query->createParameter('objecttype')))
|
||||||
|
->setParameter('objectids', $objIds, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
|
||||||
|
->setParameter('objecttype', $objectType)
|
||||||
|
->addOrderBy('objectid', 'ASC')
|
||||||
|
->addOrderBy('systemtagid', 'ASC');
|
||||||
|
|
||||||
|
$mapping = [];
|
||||||
|
foreach ($objIds as $objId) {
|
||||||
|
$mapping[$objId] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $query->execute();
|
||||||
|
while ($row = $result->fetch()) {
|
||||||
|
$objectId = $row['objectid'];
|
||||||
|
$mapping[$objectId][] = $row['systemtagid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$result->closeCursor();
|
||||||
|
|
||||||
|
return $mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getObjectIdsForTags($tagIds, $objectType) {
|
||||||
|
if (!is_array($tagIds)) {
|
||||||
|
$tagIds = [$tagIds];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertTagsExist($tagIds);
|
||||||
|
|
||||||
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
$query->select($query->createFunction('DISTINCT(objectid)'))
|
||||||
|
->from(self::RELATION_TABLE)
|
||||||
|
->where($query->expr()->in('systemtagid', $query->createParameter('tagids')))
|
||||||
|
->andWhere($query->expr()->eq('objecttype', $query->createParameter('objecttype')))
|
||||||
|
->setParameter('tagids', $tagIds, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
|
||||||
|
->setParameter('objecttype', $objectType);
|
||||||
|
|
||||||
|
$objectIds = [];
|
||||||
|
|
||||||
|
$result = $query->execute();
|
||||||
|
while ($row = $result->fetch()) {
|
||||||
|
$objectIds[] = $row['objectid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $objectIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function assignTags($objId, $objectType, $tagIds) {
|
||||||
|
if (!is_array($tagIds)) {
|
||||||
|
$tagIds = [$tagIds];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertTagsExist($tagIds);
|
||||||
|
|
||||||
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
$query->insert(self::RELATION_TABLE)
|
||||||
|
->values([
|
||||||
|
'objectid' => $query->createNamedParameter($objId),
|
||||||
|
'objecttype' => $query->createNamedParameter($objectType),
|
||||||
|
'systemtagid' => $query->createParameter('tagid'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
foreach ($tagIds as $tagId) {
|
||||||
|
try {
|
||||||
|
$query->setParameter('tagid', $tagId);
|
||||||
|
$query->execute();
|
||||||
|
} catch (UniqueConstraintViolationException $e) {
|
||||||
|
// ignore existing relations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function unassignTags($objId, $objectType, $tagIds) {
|
||||||
|
if (!is_array($tagIds)) {
|
||||||
|
$tagIds = [$tagIds];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertTagsExist($tagIds);
|
||||||
|
|
||||||
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
$query->delete(self::RELATION_TABLE)
|
||||||
|
->where($query->expr()->eq('objectid', $query->createParameter('objectid')))
|
||||||
|
->andWhere($query->expr()->eq('objecttype', $query->createParameter('objecttype')))
|
||||||
|
->andWhere($query->expr()->in('systemtagid', $query->createParameter('tagids')))
|
||||||
|
->setParameter('objectid', $objId)
|
||||||
|
->setParameter('objecttype', $objectType)
|
||||||
|
->setParameter('tagids', $tagIds, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function haveTag($objIds, $objectType, $tagId, $all = true) {
|
||||||
|
$this->assertTagsExist([$tagId]);
|
||||||
|
|
||||||
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
$query->select($query->createFunction('COUNT(1)'))
|
||||||
|
->from(self::RELATION_TABLE)
|
||||||
|
->where($query->expr()->in('objectid', $query->createParameter('objectids')))
|
||||||
|
->andWhere($query->expr()->eq('objecttype', $query->createParameter('objecttype')))
|
||||||
|
->andWhere($query->expr()->eq('systemtagid', $query->createParameter('tagid')))
|
||||||
|
->setParameter('objectids', $objIds, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
|
||||||
|
->setParameter('tagid', $tagId)
|
||||||
|
->setParameter('objecttype', $objectType)
|
||||||
|
->setMaxResults(1);
|
||||||
|
|
||||||
|
$result = $query->execute();
|
||||||
|
$row = $result->fetch(\PDO::FETCH_NUM);
|
||||||
|
$result->closeCursor();
|
||||||
|
if ($all) {
|
||||||
|
return ((int)$row[0] === count($objIds));
|
||||||
|
} else {
|
||||||
|
return (int)$row[0] > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that all the given tag ids exist.
|
||||||
|
*
|
||||||
|
* @param string[] $tagIds tag ids to check
|
||||||
|
*
|
||||||
|
* @throws \OCP\SystemTag\TagNotFoundException if at least one tag did not exist
|
||||||
|
*/
|
||||||
|
private function assertTagsExist($tagIds) {
|
||||||
|
$tags = $this->tagManager->getTagsById($tagIds);
|
||||||
|
if (count($tags) !== count($tagIds)) {
|
||||||
|
// at least one tag missing, bail out
|
||||||
|
$foundTagIds = array_map(
|
||||||
|
function($tag) {
|
||||||
|
return $tag->getId();
|
||||||
|
},
|
||||||
|
$tags
|
||||||
|
);
|
||||||
|
$missingTagIds = array_diff($tagIds, $foundTagIds);
|
||||||
|
throw new TagNotFoundException('Tags ' . json_encode($missingTagIds) . ' do not exist');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -470,4 +470,22 @@ interface IServerContainer {
|
||||||
* @since 8.2.0
|
* @since 8.2.0
|
||||||
*/
|
*/
|
||||||
public function getNotificationManager();
|
public function getNotificationManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the system-tag manager
|
||||||
|
*
|
||||||
|
* @return \OCP\SystemTag\ISystemTagManager
|
||||||
|
*
|
||||||
|
* @since 9.0.0
|
||||||
|
*/
|
||||||
|
public function getSystemTagManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the system-tag object mapper
|
||||||
|
*
|
||||||
|
* @return \OCP\SystemTag\ISystemTagObjectMapper
|
||||||
|
*
|
||||||
|
* @since 9.0.0
|
||||||
|
*/
|
||||||
|
public function getSystemTagObjectMapper();
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ interface ISystemTag {
|
||||||
*
|
*
|
||||||
* @since 9.0.0
|
* @since 9.0.0
|
||||||
*/
|
*/
|
||||||
public function isUserAsssignable();
|
public function isUserAssignable();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,9 +31,11 @@ interface ISystemTagManager {
|
||||||
/**
|
/**
|
||||||
* Returns the tag objects matching the given tag ids.
|
* Returns the tag objects matching the given tag ids.
|
||||||
*
|
*
|
||||||
* @param array|string $tagIds The ID or array of IDs of the tags to retrieve
|
* @param array|string $tagIds id or array of unique ids of the tag to retrieve
|
||||||
*
|
*
|
||||||
* @return \OCP\SystemTag\ISystemTag[] array of system tags or empty array if none found
|
* @return \OCP\SystemTag\ISystemTag[] array of system tags with tag id as key
|
||||||
|
*
|
||||||
|
* @throws \OCP\SystemTag\TagNotFoundException if at least one given tag id did no exist
|
||||||
*
|
*
|
||||||
* @since 9.0.0
|
* @since 9.0.0
|
||||||
*/
|
*/
|
||||||
|
@ -72,14 +74,14 @@ interface ISystemTagManager {
|
||||||
/**
|
/**
|
||||||
* Returns all known tags, optionally filtered by visibility.
|
* Returns all known tags, optionally filtered by visibility.
|
||||||
*
|
*
|
||||||
* @param bool $visibleOnly whether to only return user visible tags
|
* @param bool|null $visibilityFilter filter by visibility if non-null
|
||||||
* @param string $nameSearchPattern optional search pattern for the tag name
|
* @param string $nameSearchPattern optional search pattern for the tag name
|
||||||
*
|
*
|
||||||
* @return \OCP\SystemTag\ISystemTag[] array of system tags or empty array if none found
|
* @return \OCP\SystemTag\ISystemTag[] array of system tags or empty array if none found
|
||||||
*
|
*
|
||||||
* @since 9.0.0
|
* @since 9.0.0
|
||||||
*/
|
*/
|
||||||
public function getAllTags($visibleOnly = false, $nameSearchPattern = null);
|
public function getAllTags($visibilityFilter = null, $nameSearchPattern = null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the given tag
|
* Updates the given tag
|
|
@ -69,6 +69,11 @@ interface ISystemTagObjectMapper {
|
||||||
/**
|
/**
|
||||||
* Assign the given tags to the given object.
|
* Assign the given tags to the given object.
|
||||||
*
|
*
|
||||||
|
* If at least one of the given tag ids doesn't exist, none of the tags
|
||||||
|
* will be assigned.
|
||||||
|
*
|
||||||
|
* If the relationship already existed, fail silently.
|
||||||
|
*
|
||||||
* @param string $objId object id
|
* @param string $objId object id
|
||||||
* @param string $objectType object type
|
* @param string $objectType object type
|
||||||
* @param string|array $tagIds tag id or array of tag ids to assign
|
* @param string|array $tagIds tag id or array of tag ids to assign
|
||||||
|
@ -83,6 +88,11 @@ interface ISystemTagObjectMapper {
|
||||||
/**
|
/**
|
||||||
* Unassign the given tags from the given object.
|
* Unassign the given tags from the given object.
|
||||||
*
|
*
|
||||||
|
* If at least one of the given tag ids doesn't exist, none of the tags
|
||||||
|
* will be unassigned.
|
||||||
|
*
|
||||||
|
* If the relationship did not exist in the first place, fail silently.
|
||||||
|
*
|
||||||
* @param string $objId object id
|
* @param string $objId object id
|
||||||
* @param string $objectType object type
|
* @param string $objectType object type
|
||||||
* @param string|array $tagIds tag id or array of tag ids to unassign
|
* @param string|array $tagIds tag id or array of tag ids to unassign
|
||||||
|
|
|
@ -0,0 +1,396 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
|
||||||
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
|
* later.
|
||||||
|
* See the COPYING-README file.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Test\SystemTag;
|
||||||
|
|
||||||
|
use \OCP\SystemTag\ISystemTagManager;
|
||||||
|
use \OCP\SystemTag\TagNotFoundException;
|
||||||
|
use \OCP\SystemTag\TagAlreadyExistsException;
|
||||||
|
use \OCP\IDBConnection;
|
||||||
|
|
||||||
|
class TestSystemTagManager extends \Test\TestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ISystemTagManager
|
||||||
|
**/
|
||||||
|
private $tagManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var IDBConnection
|
||||||
|
*/
|
||||||
|
private $connection;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->connection = \OC::$server->getDatabaseConnection();
|
||||||
|
$this->tagManager = new \OC\SystemTag\SystemTagManager($this->connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tearDown() {
|
||||||
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
$query->delete(\OC\SystemTag\SystemTagObjectMapper::RELATION_TABLE)->execute();
|
||||||
|
$query->delete(\OC\SystemTag\SystemTagManager::TAG_TABLE)->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllTagsDataProvider() {
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
// no tags at all
|
||||||
|
[]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// simple
|
||||||
|
[
|
||||||
|
['one', false, false],
|
||||||
|
['two', false, false],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// duplicate names, different flags
|
||||||
|
[
|
||||||
|
['one', false, false],
|
||||||
|
['one', true, false],
|
||||||
|
['one', false, true],
|
||||||
|
['one', true, true],
|
||||||
|
['two', false, false],
|
||||||
|
['two', false, true],
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider getAllTagsDataProvider
|
||||||
|
*/
|
||||||
|
public function testGetAllTags($testTags) {
|
||||||
|
$testTagsById = [];
|
||||||
|
foreach ($testTags as $testTag) {
|
||||||
|
$tag = $this->tagManager->createTag($testTag[0], $testTag[1], $testTag[2]);
|
||||||
|
$testTagsById[$tag->getId()] = $tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tagList = $this->tagManager->getAllTags();
|
||||||
|
|
||||||
|
$this->assertCount(count($testTags), $tagList);
|
||||||
|
|
||||||
|
foreach ($testTagsById as $testTagId => $testTag) {
|
||||||
|
$this->assertTrue(isset($tagList[$testTagId]));
|
||||||
|
$this->assertSameTag($tagList[$testTagId], $testTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllTagsFilteredDataProvider() {
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
[
|
||||||
|
// no tags at all
|
||||||
|
],
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
[]
|
||||||
|
],
|
||||||
|
// filter by visibile only
|
||||||
|
[
|
||||||
|
// none visible
|
||||||
|
[
|
||||||
|
['one', false, false],
|
||||||
|
['two', false, false],
|
||||||
|
],
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
[]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// one visible
|
||||||
|
[
|
||||||
|
['one', true, false],
|
||||||
|
['two', false, false],
|
||||||
|
],
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
['one', true, false],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// one invisible
|
||||||
|
[
|
||||||
|
['one', true, false],
|
||||||
|
['two', false, false],
|
||||||
|
],
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
['two', false, false],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
// filter by name pattern
|
||||||
|
[
|
||||||
|
[
|
||||||
|
['one', true, false],
|
||||||
|
['one', false, false],
|
||||||
|
['two', true, false],
|
||||||
|
],
|
||||||
|
null,
|
||||||
|
'on',
|
||||||
|
[
|
||||||
|
['one', true, false],
|
||||||
|
['one', false, false],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
// filter by name pattern and visibility
|
||||||
|
[
|
||||||
|
// one visible
|
||||||
|
[
|
||||||
|
['one', true, false],
|
||||||
|
['two', true, false],
|
||||||
|
['one', false, false],
|
||||||
|
],
|
||||||
|
true,
|
||||||
|
'on',
|
||||||
|
[
|
||||||
|
['one', true, false],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
// filter by name pattern in the middle
|
||||||
|
[
|
||||||
|
// one visible
|
||||||
|
[
|
||||||
|
['abcdefghi', true, false],
|
||||||
|
['two', true, false],
|
||||||
|
],
|
||||||
|
null,
|
||||||
|
'def',
|
||||||
|
[
|
||||||
|
['abcdefghi', true, false],
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider getAllTagsFilteredDataProvider
|
||||||
|
*/
|
||||||
|
public function testGetAllTagsFiltered($testTags, $visibilityFilter, $nameSearch, $expectedResults) {
|
||||||
|
foreach ($testTags as $testTag) {
|
||||||
|
$tag = $this->tagManager->createTag($testTag[0], $testTag[1], $testTag[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$testTagsById = [];
|
||||||
|
foreach ($expectedResults as $expectedTag) {
|
||||||
|
$tag = $this->tagManager->getTag($expectedTag[0], $expectedTag[1], $expectedTag[2]);
|
||||||
|
$testTagsById[$tag->getId()] = $tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tagList = $this->tagManager->getAllTags($visibilityFilter, $nameSearch);
|
||||||
|
|
||||||
|
$this->assertCount(count($testTagsById), $tagList);
|
||||||
|
|
||||||
|
foreach ($testTagsById as $testTagId => $testTag) {
|
||||||
|
$this->assertTrue(isset($tagList[$testTagId]));
|
||||||
|
$this->assertSameTag($tagList[$testTagId], $testTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function oneTagMultipleFlagsProvider() {
|
||||||
|
return [
|
||||||
|
['one', false, false],
|
||||||
|
['one', true, false],
|
||||||
|
['one', false, true],
|
||||||
|
['one', true, true],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider oneTagMultipleFlagsProvider
|
||||||
|
* @expectedException \OCP\SystemTag\TagAlreadyExistsException
|
||||||
|
*/
|
||||||
|
public function testCreateDuplicate($name, $userVisible, $userAssignable) {
|
||||||
|
try {
|
||||||
|
$this->tagManager->createTag($name, $userVisible, $userAssignable);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->assertTrue(false, 'No exception thrown for the first create call');
|
||||||
|
}
|
||||||
|
$this->tagManager->createTag($name, $userVisible, $userAssignable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider oneTagMultipleFlagsProvider
|
||||||
|
*/
|
||||||
|
public function testGetExistingTag($name, $userVisible, $userAssignable) {
|
||||||
|
$tag1 = $this->tagManager->createTag($name, $userVisible, $userAssignable);
|
||||||
|
$tag2 = $this->tagManager->getTag($name, $userVisible, $userAssignable);
|
||||||
|
|
||||||
|
$this->assertSameTag($tag1, $tag2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider oneTagMultipleFlagsProvider
|
||||||
|
*/
|
||||||
|
public function testGetExistingTagById($name, $userVisible, $userAssignable) {
|
||||||
|
$tag1 = $this->tagManager->createTag('one', true, false);
|
||||||
|
$tag2 = $this->tagManager->createTag('two', false, true);
|
||||||
|
|
||||||
|
$tagList = $this->tagManager->getTagsById([$tag1->getId(), $tag2->getId()]);
|
||||||
|
|
||||||
|
$this->assertCount(2, $tagList);
|
||||||
|
|
||||||
|
$this->assertSameTag($tag1, $tagList[$tag1->getId()]);
|
||||||
|
$this->assertSameTag($tag2, $tagList[$tag2->getId()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \OCP\SystemTag\TagNotFoundException
|
||||||
|
*/
|
||||||
|
public function testGetNonExistingTag() {
|
||||||
|
$this->tagManager->getTag('nonexist', false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \OCP\SystemTag\TagNotFoundException
|
||||||
|
*/
|
||||||
|
public function testGetNonExistingTagsById() {
|
||||||
|
$tag1 = $this->tagManager->createTag('one', true, false);
|
||||||
|
$this->tagManager->getTagsById([$tag1->getId(), 100, 101]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testGetInvalidTagIdFormat() {
|
||||||
|
$tag1 = $this->tagManager->createTag('one', true, false);
|
||||||
|
$this->tagManager->getTagsById([$tag1->getId() . 'suffix']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateTagProvider() {
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
// update name
|
||||||
|
['one', true, true],
|
||||||
|
['two', true, true]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// update one flag
|
||||||
|
['one', false, true],
|
||||||
|
['one', true, true]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// update all flags
|
||||||
|
['one', false, false],
|
||||||
|
['one', true, true]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// update all
|
||||||
|
['one', false, false],
|
||||||
|
['two', true, true]
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider updateTagProvider
|
||||||
|
*/
|
||||||
|
public function testUpdateTag($tagCreate, $tagUpdated) {
|
||||||
|
$tag1 = $this->tagManager->createTag(
|
||||||
|
$tagCreate[0],
|
||||||
|
$tagCreate[1],
|
||||||
|
$tagCreate[2]
|
||||||
|
);
|
||||||
|
$this->tagManager->updateTag(
|
||||||
|
$tag1->getId(),
|
||||||
|
$tagUpdated[0],
|
||||||
|
$tagUpdated[1],
|
||||||
|
$tagUpdated[2]
|
||||||
|
);
|
||||||
|
$tag2 = $this->tagManager->getTag(
|
||||||
|
$tagUpdated[0],
|
||||||
|
$tagUpdated[1],
|
||||||
|
$tagUpdated[2]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($tag2->getId(), $tag1->getId());
|
||||||
|
$this->assertEquals($tag2->getName(), $tagUpdated[0]);
|
||||||
|
$this->assertEquals($tag2->isUserVisible(), $tagUpdated[1]);
|
||||||
|
$this->assertEquals($tag2->isUserAssignable(), $tagUpdated[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider updateTagProvider
|
||||||
|
* @expectedException \OCP\SystemTag\TagAlreadyExistsException
|
||||||
|
*/
|
||||||
|
public function testUpdateTagDuplicate($tagCreate, $tagUpdated) {
|
||||||
|
$this->tagManager->createTag(
|
||||||
|
$tagCreate[0],
|
||||||
|
$tagCreate[1],
|
||||||
|
$tagCreate[2]
|
||||||
|
);
|
||||||
|
$tag2 = $this->tagManager->createTag(
|
||||||
|
$tagUpdated[0],
|
||||||
|
$tagUpdated[1],
|
||||||
|
$tagUpdated[2]
|
||||||
|
);
|
||||||
|
|
||||||
|
// update to match the first tag
|
||||||
|
$this->tagManager->updateTag(
|
||||||
|
$tag2->getId(),
|
||||||
|
$tagCreate[0],
|
||||||
|
$tagCreate[1],
|
||||||
|
$tagCreate[2]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDeleteTags() {
|
||||||
|
$tag1 = $this->tagManager->createTag('one', true, false);
|
||||||
|
$tag2 = $this->tagManager->createTag('two', false, true);
|
||||||
|
|
||||||
|
$this->tagManager->deleteTags([$tag1->getId(), $tag2->getId()]);
|
||||||
|
|
||||||
|
$this->assertEmpty($this->tagManager->getAllTags());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \OCP\SystemTag\TagNotFoundException
|
||||||
|
*/
|
||||||
|
public function testDeleteNonExistingTag() {
|
||||||
|
$this->tagManager->deleteTags([100]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDeleteTagRemovesRelations() {
|
||||||
|
$tag1 = $this->tagManager->createTag('one', true, false);
|
||||||
|
$tag2 = $this->tagManager->createTag('two', true, true);
|
||||||
|
|
||||||
|
$tagMapper = new \OC\SystemTag\SystemTagObjectMapper($this->connection, $this->tagManager);
|
||||||
|
|
||||||
|
$tagMapper->assignTags(1, 'testtype', $tag1->getId());
|
||||||
|
$tagMapper->assignTags(1, 'testtype', $tag2->getId());
|
||||||
|
$tagMapper->assignTags(2, 'testtype', $tag1->getId());
|
||||||
|
|
||||||
|
$this->tagManager->deleteTags($tag1->getId());
|
||||||
|
|
||||||
|
$tagIdMapping = $tagMapper->getTagIdsForObjects(
|
||||||
|
[1, 2],
|
||||||
|
'testtype'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals([
|
||||||
|
1 => [$tag2->getId()],
|
||||||
|
2 => [],
|
||||||
|
], $tagIdMapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function assertSameTag($tag1, $tag2) {
|
||||||
|
$this->assertEquals($tag1->getId(), $tag2->getId());
|
||||||
|
$this->assertEquals($tag1->getName(), $tag2->getName());
|
||||||
|
$this->assertEquals($tag1->isUserVisible(), $tag2->isUserVisible());
|
||||||
|
$this->assertEquals($tag1->isUserAssignable(), $tag2->isUserAssignable());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,327 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
|
||||||
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
|
* later.
|
||||||
|
* See the COPYING-README file.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Test\SystemTag;
|
||||||
|
|
||||||
|
use \OCP\SystemTag\ISystemTag;
|
||||||
|
use \OCP\SystemTag\ISystemTagManager;
|
||||||
|
use \OCP\SystemTag\ISystemTagObjectMapper;
|
||||||
|
use \OCP\SystemTag\TagNotFoundException;
|
||||||
|
use \OCP\SystemTag\TagAlreadyExistsException;
|
||||||
|
use \OCP\IDBConnection;
|
||||||
|
use \OC\SystemTag\SystemTag;
|
||||||
|
|
||||||
|
class TestSystemTagObjectMapper extends \Test\TestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ISystemTagManager
|
||||||
|
**/
|
||||||
|
private $tagManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ISystemTagObjectMapper
|
||||||
|
**/
|
||||||
|
private $tagMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var IDBConnection
|
||||||
|
*/
|
||||||
|
private $connection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ISystemTag
|
||||||
|
*/
|
||||||
|
private $tag1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ISystemTag
|
||||||
|
*/
|
||||||
|
private $tag2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ISystemTag
|
||||||
|
*/
|
||||||
|
private $tag3;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->connection = \OC::$server->getDatabaseConnection();
|
||||||
|
|
||||||
|
$this->tagManager = $this->getMockBuilder('OCP\SystemTag\ISystemTagManager')
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$this->tagMapper = new \OC\SystemTag\SystemTagObjectMapper($this->connection, $this->tagManager);
|
||||||
|
|
||||||
|
$this->tag1 = new SystemTag(1, 'testtag1', false, false);
|
||||||
|
$this->tag2 = new SystemTag(2, 'testtag2', true, false);
|
||||||
|
$this->tag3 = new SystemTag(3, 'testtag3', false, false);
|
||||||
|
|
||||||
|
$this->tagManager->expects($this->any())
|
||||||
|
->method('getTagsById')
|
||||||
|
->will($this->returnCallback(function($tagIds) {
|
||||||
|
$result = [];
|
||||||
|
if (in_array(1, $tagIds)) {
|
||||||
|
$result[1] = $this->tag1;
|
||||||
|
}
|
||||||
|
if (in_array(2, $tagIds)) {
|
||||||
|
$result[2] = $this->tag2;
|
||||||
|
}
|
||||||
|
if (in_array(3, $tagIds)) {
|
||||||
|
$result[3] = $this->tag3;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}));
|
||||||
|
|
||||||
|
$this->tagMapper->assignTags(1, 'testtype', $this->tag1->getId());
|
||||||
|
$this->tagMapper->assignTags(1, 'testtype', $this->tag2->getId());
|
||||||
|
$this->tagMapper->assignTags(2, 'testtype', $this->tag1->getId());
|
||||||
|
$this->tagMapper->assignTags(3, 'anothertype', $this->tag1->getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tearDown() {
|
||||||
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
$query->delete(\OC\SystemTag\SystemTagObjectMapper::RELATION_TABLE)->execute();
|
||||||
|
$query->delete(\OC\SystemTag\SystemTagManager::TAG_TABLE)->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetTagsForObjects() {
|
||||||
|
$tagIdMapping = $this->tagMapper->getTagIdsForObjects(
|
||||||
|
[1, 2, 3, 4],
|
||||||
|
'testtype'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals([
|
||||||
|
1 => [$this->tag1->getId(), $this->tag2->getId()],
|
||||||
|
2 => [$this->tag1->getId()],
|
||||||
|
3 => [],
|
||||||
|
4 => [],
|
||||||
|
], $tagIdMapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetObjectsForTags() {
|
||||||
|
$objectIds = $this->tagMapper->getObjectIdsForTags(
|
||||||
|
[$this->tag1->getId(), $this->tag2->getId(), $this->tag3->getId()],
|
||||||
|
'testtype'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals([
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
], $objectIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \OCP\SystemTag\TagNotFoundException
|
||||||
|
*/
|
||||||
|
public function testGetObjectsForNonExistingTag() {
|
||||||
|
$this->tagMapper->getObjectIdsForTags(
|
||||||
|
[100],
|
||||||
|
'testtype'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAssignUnassignTags() {
|
||||||
|
$this->tagMapper->unassignTags(1, 'testtype', [$this->tag1->getId()]);
|
||||||
|
|
||||||
|
$tagIdMapping = $this->tagMapper->getTagIdsForObjects(1, 'testtype');
|
||||||
|
$this->assertEquals([
|
||||||
|
1 => [$this->tag2->getId()],
|
||||||
|
], $tagIdMapping);
|
||||||
|
|
||||||
|
$this->tagMapper->assignTags(1, 'testtype', [$this->tag1->getId()]);
|
||||||
|
$this->tagMapper->assignTags(1, 'testtype', $this->tag3->getId());
|
||||||
|
|
||||||
|
$tagIdMapping = $this->tagMapper->getTagIdsForObjects(1, 'testtype');
|
||||||
|
|
||||||
|
$this->assertEquals([
|
||||||
|
1 => [$this->tag1->getId(), $this->tag2->getId(), $this->tag3->getId()],
|
||||||
|
], $tagIdMapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testReAssignUnassignTags() {
|
||||||
|
// reassign tag1
|
||||||
|
$this->tagMapper->assignTags(1, 'testtype', [$this->tag1->getId()]);
|
||||||
|
|
||||||
|
// tag 3 was never assigned
|
||||||
|
$this->tagMapper->unassignTags(1, 'testtype', [$this->tag3->getId()]);
|
||||||
|
|
||||||
|
$this->assertTrue(true, 'No error when reassigning/unassigning');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \OCP\SystemTag\TagNotFoundException
|
||||||
|
*/
|
||||||
|
public function testAssignNonExistingTags() {
|
||||||
|
$this->tagMapper->assignTags(1, 'testtype', [100]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAssignNonExistingTagInArray() {
|
||||||
|
$caught = false;
|
||||||
|
try {
|
||||||
|
$this->tagMapper->assignTags(1, 'testtype', [100, $this->tag3->getId()]);
|
||||||
|
} catch (TagNotFoundException $e) {
|
||||||
|
$caught = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertTrue($caught, 'Exception thrown');
|
||||||
|
|
||||||
|
$tagIdMapping = $this->tagMapper->getTagIdsForObjects(
|
||||||
|
[1],
|
||||||
|
'testtype'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals([
|
||||||
|
1 => [$this->tag1->getId(), $this->tag2->getId()],
|
||||||
|
], $tagIdMapping, 'None of the tags got assigned');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \OCP\SystemTag\TagNotFoundException
|
||||||
|
*/
|
||||||
|
public function testUnassignNonExistingTags() {
|
||||||
|
$this->tagMapper->unassignTags(1, 'testtype', [100]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUnassignNonExistingTagsInArray() {
|
||||||
|
$caught = false;
|
||||||
|
try {
|
||||||
|
$this->tagMapper->unassignTags(1, 'testtype', [100, $this->tag1->getId()]);
|
||||||
|
} catch (TagNotFoundException $e) {
|
||||||
|
$caught = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertTrue($caught, 'Exception thrown');
|
||||||
|
|
||||||
|
$tagIdMapping = $this->tagMapper->getTagIdsForObjects(
|
||||||
|
[1],
|
||||||
|
'testtype'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals([
|
||||||
|
1 => [$this->tag1->getId(), $this->tag2->getId()],
|
||||||
|
], $tagIdMapping, 'None of the tags got unassigned');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHaveTagAllMatches() {
|
||||||
|
$this->assertTrue(
|
||||||
|
$this->tagMapper->haveTag(
|
||||||
|
[1],
|
||||||
|
'testtype',
|
||||||
|
$this->tag1->getId(),
|
||||||
|
true
|
||||||
|
),
|
||||||
|
'object 1 has the tag tag1'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertTrue(
|
||||||
|
$this->tagMapper->haveTag(
|
||||||
|
[1, 2],
|
||||||
|
'testtype',
|
||||||
|
$this->tag1->getId(),
|
||||||
|
true
|
||||||
|
),
|
||||||
|
'object 1 and object 2 ALL have the tag tag1'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse(
|
||||||
|
$this->tagMapper->haveTag(
|
||||||
|
[1, 2],
|
||||||
|
'testtype',
|
||||||
|
$this->tag2->getId(),
|
||||||
|
true
|
||||||
|
),
|
||||||
|
'object 1 has tag2 but not object 2, so not ALL of them'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse(
|
||||||
|
$this->tagMapper->haveTag(
|
||||||
|
[2],
|
||||||
|
'testtype',
|
||||||
|
$this->tag2->getId(),
|
||||||
|
true
|
||||||
|
),
|
||||||
|
'object 2 does not have tag2'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse(
|
||||||
|
$this->tagMapper->haveTag(
|
||||||
|
[3],
|
||||||
|
'testtype',
|
||||||
|
$this->tag2->getId(),
|
||||||
|
true
|
||||||
|
),
|
||||||
|
'object 3 does not have tag1 due to different type'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHaveTagAtLeastOneMatch() {
|
||||||
|
$this->assertTrue(
|
||||||
|
$this->tagMapper->haveTag(
|
||||||
|
[1],
|
||||||
|
'testtype',
|
||||||
|
$this->tag1->getId(),
|
||||||
|
false
|
||||||
|
),
|
||||||
|
'object1 has the tag tag1'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertTrue(
|
||||||
|
$this->tagMapper->haveTag(
|
||||||
|
[1, 2],
|
||||||
|
'testtype',
|
||||||
|
$this->tag1->getId(),
|
||||||
|
false
|
||||||
|
),
|
||||||
|
'object 1 and object 2 both the tag tag1'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertTrue(
|
||||||
|
$this->tagMapper->haveTag(
|
||||||
|
[1, 2],
|
||||||
|
'testtype',
|
||||||
|
$this->tag2->getId(),
|
||||||
|
false
|
||||||
|
),
|
||||||
|
'at least object 1 has the tag tag2'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse(
|
||||||
|
$this->tagMapper->haveTag(
|
||||||
|
[2],
|
||||||
|
'testtype',
|
||||||
|
$this->tag2->getId(),
|
||||||
|
false
|
||||||
|
),
|
||||||
|
'object 2 does not have tag2'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse(
|
||||||
|
$this->tagMapper->haveTag(
|
||||||
|
[3],
|
||||||
|
'testtype',
|
||||||
|
$this->tag2->getId(),
|
||||||
|
false
|
||||||
|
),
|
||||||
|
'object 3 does not have tag1 due to different type'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \OCP\SystemTag\TagNotFoundException
|
||||||
|
*/
|
||||||
|
public function testHaveTagNonExisting() {
|
||||||
|
$this->tagMapper->haveTag(
|
||||||
|
[1],
|
||||||
|
'testtype',
|
||||||
|
100
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue