Skip to content

Commit 778ae6a

Browse files
committed
feat(systemtags): add commands to manage tags on files
Resolve #32735 Signed-off-by: schaarsc <schaarsc@users.noreply.github.com>
1 parent 5ba9ece commit 778ae6a

File tree

6 files changed

+238
-0
lines changed

6 files changed

+238
-0
lines changed

apps/systemtags/appinfo/info.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
<dependencies>
2626
<nextcloud min-version="31" max-version="31"/>
2727
</dependencies>
28+
<commands>
29+
<command>OCA\SystemTags\Command\Files\Add</command>
30+
<command>OCA\SystemTags\Command\Files\Delete</command>
31+
<command>OCA\SystemTags\Command\Files\DeleteAll</command>
32+
</commands>
2833
<settings>
2934
<admin>OCA\SystemTags\Settings\Admin</admin>
3035
</settings>

apps/systemtags/composer/composer/autoload_classmap.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
'OCA\\SystemTags\\Activity\\Setting' => $baseDir . '/../lib/Activity/Setting.php',
1313
'OCA\\SystemTags\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php',
1414
'OCA\\SystemTags\\Capabilities' => $baseDir . '/../lib/Capabilities.php',
15+
'OCA\\SystemTags\\Command\\Files\\Add' => $baseDir . '/../lib/Command/Files/Add.php',
16+
'OCA\\SystemTags\\Command\\Files\\Delete' => $baseDir . '/../lib/Command/Files/Delete.php',
17+
'OCA\\SystemTags\\Command\\Files\\DeleteAll' => $baseDir . '/../lib/Command/Files/DeleteAll.php',
1518
'OCA\\SystemTags\\Controller\\LastUsedController' => $baseDir . '/../lib/Controller/LastUsedController.php',
1619
'OCA\\SystemTags\\Listeners\\BeforeSabrePubliclyLoadedListener' => $baseDir . '/../lib/Listeners/BeforeSabrePubliclyLoadedListener.php',
1720
'OCA\\SystemTags\\Listeners\\BeforeTemplateRenderedListener' => $baseDir . '/../lib/Listeners/BeforeTemplateRenderedListener.php',

apps/systemtags/composer/composer/autoload_static.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ class ComposerStaticInitSystemTags
2727
'OCA\\SystemTags\\Activity\\Setting' => __DIR__ . '/..' . '/../lib/Activity/Setting.php',
2828
'OCA\\SystemTags\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php',
2929
'OCA\\SystemTags\\Capabilities' => __DIR__ . '/..' . '/../lib/Capabilities.php',
30+
'OCA\\SystemTags\\Command\\Files\\Add' => __DIR__ . '/..' . '/../lib/Command/Files/Add.php',
31+
'OCA\\SystemTags\\Command\\Files\\Delete' => __DIR__ . '/..' . '/../lib/Command/Files/Delete.php',
32+
'OCA\\SystemTags\\Command\\Files\\DeleteAll' => __DIR__ . '/..' . '/../lib/Command/Files/DeleteAll.php',
3033
'OCA\\SystemTags\\Controller\\LastUsedController' => __DIR__ . '/..' . '/../lib/Controller/LastUsedController.php',
3134
'OCA\\SystemTags\\Listeners\\BeforeSabrePubliclyLoadedListener' => __DIR__ . '/..' . '/../lib/Listeners/BeforeSabrePubliclyLoadedListener.php',
3235
'OCA\\SystemTags\\Listeners\\BeforeTemplateRenderedListener' => __DIR__ . '/..' . '/../lib/Listeners/BeforeTemplateRenderedListener.php',
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\SystemTags\Command\Files;
11+
12+
use OC\Core\Command\Info\FileUtils;
13+
use OCP\SystemTag\ISystemTagManager;
14+
use OCP\SystemTag\ISystemTagObjectMapper;
15+
use OCP\SystemTag\TagAlreadyExistsException;
16+
use Symfony\Component\Console\Command\Command;
17+
use Symfony\Component\Console\Input\InputArgument;
18+
use Symfony\Component\Console\Input\InputInterface;
19+
use Symfony\Component\Console\Output\OutputInterface;
20+
21+
class Add extends Command {
22+
23+
public function __construct(
24+
private FileUtils $fileUtils,
25+
private ISystemTagManager $systemTagManager,
26+
private ISystemTagObjectMapper $systemTagObjectMapper,
27+
) {
28+
parent::__construct();
29+
}
30+
31+
protected function configure(): void {
32+
$this->setName('tag:files:add')
33+
->setDescription('Add a system-tag to a file or folder')
34+
->addArgument('target', InputArgument::REQUIRED, 'file id or path')
35+
->addArgument('tags', InputArgument::REQUIRED, 'Name of the tag(s) to add, comma separated')
36+
->addArgument('access', InputArgument::REQUIRED, 'access level of the tag (public, restricted or invisible)');
37+
}
38+
39+
public function execute(InputInterface $input, OutputInterface $output): int {
40+
$targetInput = $input->getArgument('target');
41+
$tagsInput = $input->getArgument('tags');
42+
43+
if ($tagsInput === '') {
44+
$output->writeln('<error>`tags` can\'t be empty</error>');
45+
return 3;
46+
}
47+
48+
$tagNameArray = explode(',', $tagsInput);
49+
50+
$access = $input->getArgument('access');
51+
switch ($access) {
52+
case 'public':
53+
$userVisible = true;
54+
$userAssignable = true;
55+
break;
56+
case 'restricted':
57+
$userVisible = true;
58+
$userAssignable = false;
59+
break;
60+
case 'invisible':
61+
$userVisible = false;
62+
$userAssignable = false;
63+
break;
64+
default:
65+
$output->writeln('<error>`access` property is invalid</error>');
66+
return 1;
67+
}
68+
69+
$targetNode = $this->fileUtils->getNode($targetInput);
70+
71+
if (! $targetNode) {
72+
$output->writeln("<error>file $targetInput not found</error>");
73+
return 1;
74+
}
75+
76+
foreach ($tagNameArray as $tagName) {
77+
try {
78+
$tag = $this->systemTagManager->createTag($tagName, $userVisible, $userAssignable);
79+
$output->writeln("<info>$access</info> tag named <info>$tagName</info> created.");
80+
} catch (TagAlreadyExistsException $e) {
81+
$tag = $this->systemTagManager->getTag($tagName, $userVisible, $userAssignable);
82+
}
83+
84+
$this->systemTagObjectMapper->assignTags((string)$targetNode->getId(), 'files', $tag->getId());
85+
$output->writeln("<info>$access</info> tag named <info>$tagName</info> added.");
86+
}
87+
88+
return 0;
89+
}
90+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\SystemTags\Command\Files;
11+
12+
use OC\Core\Command\Info\FileUtils;
13+
use OCP\SystemTag\ISystemTagManager;
14+
use OCP\SystemTag\ISystemTagObjectMapper;
15+
use OCP\SystemTag\TagNotFoundException;
16+
use Symfony\Component\Console\Command\Command;
17+
use Symfony\Component\Console\Input\InputArgument;
18+
use Symfony\Component\Console\Input\InputInterface;
19+
use Symfony\Component\Console\Output\OutputInterface;
20+
21+
class Delete extends Command {
22+
23+
public function __construct(
24+
private FileUtils $fileUtils,
25+
private ISystemTagManager $systemTagManager,
26+
private ISystemTagObjectMapper $systemTagObjectMapper,
27+
) {
28+
parent::__construct();
29+
}
30+
31+
protected function configure(): void {
32+
$this->setName('tag:files:delete')
33+
->setDescription('Delete a system-tag from a file or folder')
34+
->addArgument('target', InputArgument::REQUIRED, 'file id or path')
35+
->addArgument('tags', InputArgument::REQUIRED, 'Name of the tag(s) to delete, comma separated')
36+
->addArgument('access', InputArgument::REQUIRED, 'access level of the tag (public, restricted or invisible)');
37+
}
38+
39+
public function execute(InputInterface $input, OutputInterface $output): int {
40+
$targetInput = $input->getArgument('target');
41+
$tagsInput = $input->getArgument('tags');
42+
43+
if ($tagsInput === '') {
44+
$output->writeln('<error>`tags` can\'t be empty</error>');
45+
return 3;
46+
}
47+
48+
$tagNameArray = explode(',', $tagsInput);
49+
50+
$access = $input->getArgument('access');
51+
switch ($access) {
52+
case 'public':
53+
$userVisible = true;
54+
$userAssignable = true;
55+
break;
56+
case 'restricted':
57+
$userVisible = true;
58+
$userAssignable = false;
59+
break;
60+
case 'invisible':
61+
$userVisible = false;
62+
$userAssignable = false;
63+
break;
64+
default:
65+
$output->writeln('<error>`access` property is invalid</error>');
66+
return 1;
67+
}
68+
69+
$targetNode = $this->fileUtils->getNode($targetInput);
70+
71+
if (! $targetNode) {
72+
$output->writeln("<error>file $targetInput not found</error>");
73+
return 1;
74+
}
75+
76+
foreach ($tagNameArray as $tagName) {
77+
try {
78+
$tag = $this->systemTagManager->getTag($tagName, $userVisible, $userAssignable);
79+
$this->systemTagObjectMapper->unassignTags((string)$targetNode->getId(), 'files', $tag->getId());
80+
$output->writeln("<info>$access</info> tag named <info>$tagName</info> removed.");
81+
} catch (TagNotFoundException $e) {
82+
$output->writeln("<info>$access</info> tag named <info>$tagName</info> does not exist!");
83+
}
84+
}
85+
86+
return 0;
87+
}
88+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\SystemTags\Command\Files;
11+
12+
use OC\Core\Command\Info\FileUtils;
13+
use OCP\SystemTag\ISystemTagObjectMapper;
14+
use Symfony\Component\Console\Command\Command;
15+
use Symfony\Component\Console\Input\InputArgument;
16+
use Symfony\Component\Console\Input\InputInterface;
17+
use Symfony\Component\Console\Output\OutputInterface;
18+
19+
class DeleteAll extends Command {
20+
21+
public function __construct(
22+
private FileUtils $fileUtils,
23+
private ISystemTagObjectMapper $systemTagObjectMapper,
24+
) {
25+
parent::__construct();
26+
}
27+
28+
protected function configure(): void {
29+
$this->setName('tag:files:delete-all')
30+
->setDescription('Delete all system-tags from a file or folder')
31+
->addArgument('target', InputArgument::REQUIRED, 'file id or path');
32+
}
33+
34+
public function execute(InputInterface $input, OutputInterface $output): int {
35+
$targetInput = $input->getArgument('target');
36+
$targetNode = $this->fileUtils->getNode($targetInput);
37+
38+
if (! $targetNode) {
39+
$output->writeln("<error>file $targetInput not found</error>");
40+
return 1;
41+
}
42+
43+
$tags = $this->systemTagObjectMapper->getTagIdsForObjects([$targetNode->getId()], 'files');
44+
$this->systemTagObjectMapper->unassignTags((string)$targetNode->getId(), 'files', $tags[$targetNode->getId()]);
45+
$output->writeln('<info>all tags removed.</info>');
46+
47+
return 0;
48+
}
49+
}

0 commit comments

Comments
 (0)