Skip to content

Commit

Permalink
[stable10] Backport of new tag editable added to systemtag
Browse files Browse the repository at this point in the history
Added new tag editable to the systemtag.
This tag could be editable only to admins
and to the groups who have permission to edit.
For all other users, this tag could be used
to assign/unassign.

Signed-off-by: Sujith H <[email protected]>
  • Loading branch information
sharidas committed Nov 5, 2018
1 parent f4f25e1 commit dd27c3c
Show file tree
Hide file tree
Showing 18 changed files with 474 additions and 101 deletions.
5 changes: 3 additions & 2 deletions apps/dav/lib/SystemTag/SystemTagNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,12 @@ public function setName($name) {
* @param string $name new tag name
* @param bool $userVisible user visible
* @param bool $userAssignable user assignable
* @param bool $userEditable user editable
* @throws NotFound whenever the given tag id does not exist
* @throws Forbidden whenever there is no permission to update said tag
* @throws Conflict whenever a tag already exists with the given attributes
*/
public function update($name, $userVisible, $userAssignable) {
public function update($name, $userVisible, $userAssignable, $userEditable = false) {
try {
if (!$this->tagManager->canUserSeeTag($this->tag, $this->user)) {
throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist');
Expand All @@ -134,7 +135,7 @@ public function update($name, $userVisible, $userAssignable) {
}
}

$this->tagManager->updateTag($this->tag->getId(), $name, $userVisible, $userAssignable);
$this->tagManager->updateTag($this->tag->getId(), $name, $userVisible, $userAssignable, $userEditable);
} catch (TagNotFoundException $e) {
throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist');
} catch (TagAlreadyExistsException $e) {
Expand Down
35 changes: 32 additions & 3 deletions apps/dav/lib/SystemTag/SystemTagPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
const ID_PROPERTYNAME = '{http://owncloud.org/ns}id';
const DISPLAYNAME_PROPERTYNAME = '{http://owncloud.org/ns}display-name';
const USERVISIBLE_PROPERTYNAME = '{http://owncloud.org/ns}user-visible';
const USEREDITABLE_PROPERTYNAME = '{http://owncloud.org/ns}user-editable';
const USERASSIGNABLE_PROPERTYNAME = '{http://owncloud.org/ns}user-assignable';
const GROUPS_PROPERTYNAME = '{http://owncloud.org/ns}groups';
const CANASSIGN_PROPERTYNAME = '{http://owncloud.org/ns}can-assign';
const WHITELISTEDINGROUP = '{http://owncloud.org/ns}editable-in-group';

/**
* @var \Sabre\DAV\Server $server
Expand Down Expand Up @@ -172,6 +174,7 @@ private function createTag($data, $contentType = 'application/json') {
$tagName = $data['name'];
$userVisible = true;
$userAssignable = true;
$userEditable = false;

if (isset($data['userVisible'])) {
$userVisible = (bool)$data['userVisible'];
Expand All @@ -181,6 +184,10 @@ private function createTag($data, $contentType = 'application/json') {
$userAssignable = (bool)$data['userAssignable'];
}

if (isset($data['userEditable'])) {
$userEditable = (bool)$data['userEditable'];
}

$groups = [];
if (isset($data['groups'])) {
$groups = $data['groups'];
Expand All @@ -196,7 +203,7 @@ private function createTag($data, $contentType = 'application/json') {
}

try {
$tag = $this->tagManager->createTag($tagName, $userVisible, $userAssignable);
$tag = $this->tagManager->createTag($tagName, $userVisible, $userAssignable, $userEditable);
if (!empty($groups)) {
$this->tagManager->setTagGroups($tag, $groups);
}
Expand Down Expand Up @@ -232,6 +239,11 @@ public function handleGetProperties(
return $node->getSystemTag()->isUserVisible() ? 'true' : 'false';
});

$propFind->handle(self::USEREDITABLE_PROPERTYNAME, function () use ($node) {
// this is the tag's inherent property "is user editable"
return $node->getSystemTag()->isUserEditable() ? 'true' : 'false';
});

$propFind->handle(self::USERASSIGNABLE_PROPERTYNAME, function () use ($node) {
// this is the tag's inherent property "is user assignable"
return $node->getSystemTag()->isUserAssignable() ? 'true' : 'false';
Expand All @@ -249,11 +261,20 @@ public function handleGetProperties(
}
$groups = [];
// no need to retrieve groups for namespaces that don't qualify
if ($node->getSystemTag()->isUserVisible() && !$node->getSystemTag()->isUserAssignable()) {
$restrictedTagCondition = $node->getSystemTag()->isUserVisible() &&
(!$node->getSystemTag()->isUserAssignable());
$editableTagCondition = $node->getSystemTag()->isUserVisible() &&
$node->getSystemTag()->isUserAssignable() &&
(!$node->getSystemTag()->isUserEditable());
if ($restrictedTagCondition || $editableTagCondition) {
$groups = $this->tagManager->getTagGroups($node->getSystemTag());
}
return \implode('|', $groups);
});

$propFind->handle(self::WHITELISTEDINGROUP, function () use ($node) {
return $this->tagManager->canUserUseStaticTagInGroup($node->getSystemTag(), $this->userSession->getUser()) ? 'true' : 'false';
});
}

/**
Expand All @@ -273,12 +294,14 @@ public function handleUpdateProperties($path, PropPatch $propPatch) {
$propPatch->handle([
self::DISPLAYNAME_PROPERTYNAME,
self::USERVISIBLE_PROPERTYNAME,
self::USEREDITABLE_PROPERTYNAME,
self::USERASSIGNABLE_PROPERTYNAME,
self::GROUPS_PROPERTYNAME,
], function ($props) use ($node) {
$tag = $node->getSystemTag();
$name = $tag->getName();
$userVisible = $tag->isUserVisible();
$userEditable = $tag->isUserEditable();
$userAssignable = $tag->isUserAssignable();

$updateTag = false;
Expand All @@ -294,6 +317,12 @@ public function handleUpdateProperties($path, PropPatch $propPatch) {
$updateTag = true;
}

if (isset($props[self::USEREDITABLE_PROPERTYNAME])) {
$propValue = $props[self::USEREDITABLE_PROPERTYNAME];
$userEditable = ($propValue !== 'true' && $propValue !== '1');
$updateTag = true;
}

if (isset($props[self::USERASSIGNABLE_PROPERTYNAME])) {
$propValue = $props[self::USERASSIGNABLE_PROPERTYNAME];
$userAssignable = ($propValue !== 'false' && $propValue !== '0');
Expand All @@ -312,7 +341,7 @@ public function handleUpdateProperties($path, PropPatch $propPatch) {
}

if ($updateTag) {
$node->update($name, $userVisible, $userAssignable);
$node->update($name, $userVisible, $userAssignable, $userEditable);
}

return true;
Expand Down
2 changes: 1 addition & 1 deletion apps/dav/lib/SystemTag/SystemTagsByIdCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public function getChildren() {
$visibilityFilter = null;
}

$tags = $this->tagManager->getAllTags($visibilityFilter);
$tags = $this->tagManager->getAllTags($visibilityFilter, null);
return \array_map(function ($tag) {
return $this->makeNode($tag);
}, $tags);
Expand Down
12 changes: 10 additions & 2 deletions apps/dav/tests/unit/SystemTag/SystemTagPluginTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class SystemTagPluginTest extends \Test\TestCase {
const USERASSIGNABLE_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::USERASSIGNABLE_PROPERTYNAME;
const CANASSIGN_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::CANASSIGN_PROPERTYNAME;
const GROUPS_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::GROUPS_PROPERTYNAME;
const USEREDITABLE_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::USEREDITABLE_PROPERTYNAME;
const WHITELISTEDINGROUP = \OCA\DAV\SystemTag\SystemTagPlugin::WHITELISTEDINGROUP;

/**
* @var \Sabre\DAV\Server
Expand Down Expand Up @@ -114,7 +116,7 @@ public function getPropertiesDataProvider() {
self::DISPLAYNAME_PROPERTYNAME,
self::USERVISIBLE_PROPERTYNAME,
self::USERASSIGNABLE_PROPERTYNAME,
self::CANASSIGN_PROPERTYNAME,
self::CANASSIGN_PROPERTYNAME
],
[
self::ID_PROPERTYNAME => '1',
Expand Down Expand Up @@ -155,16 +157,20 @@ public function getPropertiesDataProvider() {
]
],
[
new SystemTag(1, 'Test', true, true),
new SystemTag(1, 'Test', true, true, true),
['group1', 'group2'],
[
self::ID_PROPERTYNAME,
self::GROUPS_PROPERTYNAME,
self::USEREDITABLE_PROPERTYNAME,
self::WHITELISTEDINGROUP,
],
[
self::ID_PROPERTYNAME => '1',
// groups only returned when userAssignable is false
self::GROUPS_PROPERTYNAME => '',
self::USEREDITABLE_PROPERTYNAME => 'true',
self::WHITELISTEDINGROUP => 'false'
]
],
];
Expand Down Expand Up @@ -297,6 +303,7 @@ public function testUpdatePropertiesAdmin() {
$propPatch = new \Sabre\DAV\PropPatch([
self::DISPLAYNAME_PROPERTYNAME => 'Test changed',
self::USERVISIBLE_PROPERTYNAME => 'false',
self::USEREDITABLE_PROPERTYNAME => 'true',
self::USERASSIGNABLE_PROPERTYNAME => 'true',
self::GROUPS_PROPERTYNAME => 'group1|group2',
]);
Expand All @@ -315,6 +322,7 @@ public function testUpdatePropertiesAdmin() {
$this->assertEquals(200, $result[self::DISPLAYNAME_PROPERTYNAME]);
$this->assertEquals(200, $result[self::USERASSIGNABLE_PROPERTYNAME]);
$this->assertEquals(200, $result[self::USERVISIBLE_PROPERTYNAME]);
$this->assertEquals(200, $result[self::USEREDITABLE_PROPERTYNAME]);
}

/**
Expand Down
43 changes: 43 additions & 0 deletions core/Migrations/Version20181017105216.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
/**
* @author Sujith Haridasan <[email protected]>
*
* @copyright Copyright (c) 2018, ownCloud GmbH
* @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\Migrations;

use Doctrine\DBAL\Schema\Schema;
use OCP\Migration\ISchemaMigration;

class Version20181017105216 implements ISchemaMigration {

/** @var string */
private $prefix;

public function changeSchema(Schema $schema, array $options) {
$this->prefix = $options['tablePrefix'];
$table = $schema->getTable("{$this->prefix}systemtag");
if ($schema->hasTable("{$this->prefix}systemtag")) {
if (!$table->hasColumn('assignable')) {
$table->addColumn('assignable', 'integer');
$assignableColumn = $table->getColumn('assignable');
$assignableColumn->setDefault(0);
}
}
}
}
55 changes: 55 additions & 0 deletions core/Migrations/Version20181017120818.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php
/**
* @author Sujith Haridasan <[email protected]>
*
* @copyright Copyright (c) 2018, ownCloud GmbH
* @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\Migrations;

use OCP\IDBConnection;
use OCP\Migration\ISqlMigration;

/**
* Added extra column assignable to systemtag table, post 10.0.10.1 version
* this is required to identify editable tag. It is only
* set to "1" for visible and editable tags.
*/
class Version20181017120818 implements ISqlMigration {
public function sql(IDBConnection $connection) {
$valueToUpdate = 1;
$qb = $connection->getQueryBuilder();
$qb->update('systemtag')
->set(
'assignable',
$qb->expr()->literal($valueToUpdate)
)
->where(
$qb->expr()->eq(
'visibility',
$qb->expr()->literal($valueToUpdate)
)
)
->andWhere(
$qb->expr()->eq(
'editable',
$qb->expr()->literal($valueToUpdate)
)
);
return [$qb->getSQL()];
}
}
15 changes: 14 additions & 1 deletion core/js/systemtags/systemtagmodel.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
PROPERTY_CAN_ASSIGN:'{' + OC.Files.Client.NS_OWNCLOUD + '}can-assign',
PROPERTY_DISPLAYNAME: '{' + OC.Files.Client.NS_OWNCLOUD + '}display-name',
PROPERTY_USERVISIBLE: '{' + OC.Files.Client.NS_OWNCLOUD + '}user-visible',
PROPERTY_USEREDITABLE:'{' + OC.Files.Client.NS_OWNCLOUD + '}user-editable',
PROPERTY_USERASSIGNABLE:'{' + OC.Files.Client.NS_OWNCLOUD + '}user-assignable',
PROPERTY_WHITELISTEDINGROUP:'{' + OC.Files.Client.NS_OWNCLOUD + '}editable-in-group'
});

/**
Expand All @@ -39,18 +41,29 @@
'id': OC.Files.Client.PROPERTY_FILEID,
'name': OC.Files.Client.PROPERTY_DISPLAYNAME,
'userVisible': OC.Files.Client.PROPERTY_USERVISIBLE,
'userEditable': OC.Files.Client.PROPERTY_USEREDITABLE,
'userAssignable': OC.Files.Client.PROPERTY_USERASSIGNABLE,
'editableInGroup': OC.Files.Client.PROPERTY_WHITELISTEDINGROUP,
// read-only, effective permissions computed by the server,
'canAssign': OC.Files.Client.PROPERTY_CAN_ASSIGN
},

parse: function(data) {
var userEditable;
//If assignable is false, just set editable to false
if (data.userAssignable === false) {
userEditable = false;
} else {
userEditable = (data.userEditable === true || data.userEditable === 'true');
}
return {
id: data.id,
name: data.name,
userVisible: data.userVisible === true || data.userVisible === 'true',
userEditable: userEditable,
userAssignable: data.userAssignable === true || data.userAssignable === 'true',
canAssign: data.canAssign === true || data.canAssign === 'true'
canAssign: data.canAssign === true || data.canAssign === 'true',
editableInGroup: data.editableInGroup === true || data.editableInGroup === 'true'
};
}
});
Expand Down
7 changes: 7 additions & 0 deletions core/js/systemtags/systemtags.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@
// invisible also implicitly means not assignable
scope = t('core', 'invisible');
}
if (tag.userVisible === true && tag.userEditable === false && tag.userAssignable === true) {
/**
* Users can edit the tag, if they are admin or belong to whitelisted
* group by the edit tag.
*/
scope = t('core', 'Static')
}
if (scope) {
var $tag = $('<em>').text(' ' +
t('core', '({scope})', {
Expand Down
Loading

0 comments on commit dd27c3c

Please sign in to comment.