Skip to content

Commit 97f0b54

Browse files
authored
Merge pull request #53888 from nextcloud/backport/53875/stable31
2 parents d4cede3 + 13253f5 commit 97f0b54

File tree

3 files changed

+97
-39
lines changed

3 files changed

+97
-39
lines changed

cypress/e2e/systemtags/files-bulk-action.cy.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,4 +411,58 @@ describe('Systemtags: Files bulk action', { testIsolation: false }, () => {
411411
cy.runOccCommand('config:app:set systemtags restrict_creation_to_admin --value 0')
412412
})
413413
})
414+
415+
it('Can search for tags with insensitive case', () => {
416+
let tagId: string
417+
resetTags()
418+
419+
cy.runOccCommand('tag:add TESTTAG public --output json').then(({ stdout }) => {
420+
const tag = JSON.parse(stdout)
421+
tagId = tag.id
422+
})
423+
424+
cy.createRandomUser().then((user1) => {
425+
files.forEach((file) => {
426+
cy.uploadContent(user1, new Blob([]), 'text/plain', '/' + file)
427+
})
428+
429+
cy.login(user1)
430+
cy.visit('/apps/files')
431+
432+
files.forEach((file) => {
433+
getRowForFile(file).should('be.visible')
434+
})
435+
selectAllFiles()
436+
437+
triggerTagManagementDialogAction()
438+
439+
cy.findByRole('textbox', { name: 'Search or create tag' }).should('be.visible')
440+
cy.findByRole('textbox', { name: 'Search tag' }).should('not.exist')
441+
442+
cy.get('[data-cy-systemtags-picker-input]').type('testtag')
443+
444+
cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 1)
445+
cy.get(`[data-cy-systemtags-picker-tag="${tagId}"]`).should('be.visible')
446+
.findByRole('checkbox').should('not.be.checked')
447+
448+
// Assign the tag
449+
cy.intercept('PROPFIND', '/remote.php/dav/systemtags/*/files').as('getTagData')
450+
cy.intercept('PROPPATCH', '/remote.php/dav/systemtags/*/files').as('assignTagData')
451+
452+
cy.get(`[data-cy-systemtags-picker-tag="${tagId}"]`).should('be.visible')
453+
.findByRole('checkbox').click({ force: true })
454+
cy.get('[data-cy-systemtags-picker-button-submit]').click()
455+
456+
cy.wait('@getTagData')
457+
cy.wait('@assignTagData')
458+
459+
expectInlineTagForFile('file1.txt', ['TESTTAG'])
460+
expectInlineTagForFile('file2.txt', ['TESTTAG'])
461+
expectInlineTagForFile('file3.txt', ['TESTTAG'])
462+
expectInlineTagForFile('file4.txt', ['TESTTAG'])
463+
expectInlineTagForFile('file5.txt', ['TESTTAG'])
464+
465+
cy.get('[data-cy-systemtags-picker]').should('not.exist')
466+
})
467+
})
414468
})

lib/private/SystemTag/SystemTagManager.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public function getAllTags($visibilityFilter = null, $nameSearchPattern = null):
108108

109109
if (!empty($nameSearchPattern)) {
110110
$query->andWhere(
111-
$query->expr()->like(
111+
$query->expr()->iLike(
112112
'name',
113113
$query->createNamedParameter('%' . $this->connection->escapeLikeParameter($nameSearchPattern) . '%')
114114
)
@@ -120,7 +120,7 @@ public function getAllTags($visibilityFilter = null, $nameSearchPattern = null):
120120
->addOrderBy('visibility', 'ASC')
121121
->addOrderBy('editable', 'ASC');
122122

123-
$result = $query->execute();
123+
$result = $query->executeQuery();
124124
while ($row = $result->fetch()) {
125125
$tags[$row['id']] = $this->createSystemTagFromRow($row);
126126
}
@@ -156,6 +156,14 @@ public function createTag(string $tagName, bool $userVisible, bool $userAssignab
156156
throw new TagCreationForbiddenException();
157157
}
158158

159+
// Check if tag already exists (case-insensitive)
160+
$existingTags = $this->getAllTags(null, $tagName);
161+
foreach ($existingTags as $existingTag) {
162+
if (mb_strtolower($existingTag->getName()) === mb_strtolower($tagName)) {
163+
throw new TagAlreadyExistsException('Tag ' . $tagName . ' already exists');
164+
}
165+
}
166+
159167
// Length of name column is 64
160168
$truncatedTagName = substr($tagName, 0, 64);
161169
$query = $this->connection->getQueryBuilder();
@@ -226,6 +234,15 @@ public function updateTag(
226234
$color
227235
);
228236

237+
// Check if tag already exists (case-insensitive)
238+
$existingTags = $this->getAllTags(null, $truncatedNewName);
239+
foreach ($existingTags as $existingTag) {
240+
if (mb_strtolower($existingTag->getName()) === mb_strtolower($truncatedNewName)
241+
&& $existingTag->getId() !== $tagId) {
242+
throw new TagAlreadyExistsException('Tag ' . $truncatedNewName . ' already exists');
243+
}
244+
}
245+
229246
$query = $this->connection->getQueryBuilder();
230247
$query->update(self::TAG_TABLE)
231248
->set('name', $query->createParameter('name'))

tests/lib/SystemTag/SystemTagManagerTest.php

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use OCP\IUserSession;
1919
use OCP\SystemTag\ISystemTag;
2020
use OCP\SystemTag\ISystemTagManager;
21+
use OCP\SystemTag\TagAlreadyExistsException;
2122
use Test\TestCase;
2223

2324
/**
@@ -79,17 +80,6 @@ public static function getAllTagsDataProvider() {
7980
['two', false, false],
8081
]
8182
],
82-
[
83-
// duplicate names, different flags
84-
[
85-
['one', false, false],
86-
['one', true, false],
87-
['one', false, true],
88-
['one', true, true],
89-
['two', false, false],
90-
['two', false, true],
91-
]
92-
]
9383
];
9484
}
9585

@@ -162,14 +152,14 @@ public static function getAllTagsFilteredDataProvider() {
162152
[
163153
[
164154
['one', true, false],
165-
['one', false, false],
155+
['one_different', false, false],
166156
['two', true, false],
167157
],
168158
null,
169159
'on',
170160
[
171161
['one', true, false],
172-
['one', false, false],
162+
['one_different', false, false],
173163
]
174164
],
175165
// filter by name pattern and visibility
@@ -178,7 +168,7 @@ public static function getAllTagsFilteredDataProvider() {
178168
[
179169
['one', true, false],
180170
['two', true, false],
181-
['one', false, false],
171+
['one_different', false, false],
182172
],
183173
true,
184174
'on',
@@ -239,7 +229,7 @@ public static function oneTagMultipleFlagsProvider() {
239229
* @dataProvider oneTagMultipleFlagsProvider
240230
*/
241231
public function testCreateDuplicate($name, $userVisible, $userAssignable): void {
242-
$this->expectException(\OCP\SystemTag\TagAlreadyExistsException::class);
232+
$this->expectException(TagAlreadyExistsException::class);
243233

244234
try {
245235
$this->tagManager->createTag($name, $userVisible, $userAssignable);
@@ -249,6 +239,15 @@ public function testCreateDuplicate($name, $userVisible, $userAssignable): void
249239
$this->tagManager->createTag($name, $userVisible, $userAssignable);
250240
}
251241

242+
public function testCreateDuplicateWithDifferentFlags(): void {
243+
$this->expectException(TagAlreadyExistsException::class);
244+
245+
// Create a tag with specific flags
246+
$this->tagManager->createTag('duplicate', true, false);
247+
// Try to create a tag with the same name but different flags - should fail
248+
$this->tagManager->createTag('duplicate', false, true);
249+
}
250+
252251
public function testCreateOverlongName(): void {
253252
$tag = $this->tagManager->createTag('Zona circundante do Palácio Nacional da Ajuda (Jardim das Damas, Salão de Física, Torre Sineira, Paço Velho e Jardim Botânico)', true, true);
254253
$this->assertSame('Zona circundante do Palácio Nacional da Ajuda (Jardim das Damas', $tag->getName()); // 63 characters but 64 bytes due to "á"
@@ -356,32 +355,20 @@ public function testUpdateTag($tagCreate, $tagUpdated): void {
356355

357356
}
358357

359-
/**
360-
* @dataProvider updateTagProvider
361-
*/
362-
public function testUpdateTagDuplicate($tagCreate, $tagUpdated): void {
363-
$this->expectException(\OCP\SystemTag\TagAlreadyExistsException::class);
358+
public function testUpdateTagToExistingName(): void {
359+
$this->expectException(TagAlreadyExistsException::class);
364360

365-
$this->tagManager->createTag(
366-
$tagCreate[0],
367-
$tagCreate[1],
368-
$tagCreate[2],
369-
$tagCreate[3],
370-
);
371-
$tag2 = $this->tagManager->createTag(
372-
$tagUpdated[0],
373-
$tagUpdated[1],
374-
$tagUpdated[2],
375-
$tagUpdated[3],
376-
);
361+
// Create two different tags
362+
$tag1 = $this->tagManager->createTag('first', true, true);
363+
$tag2 = $this->tagManager->createTag('second', false, false);
377364

378-
// update to match the first tag
365+
// Try to update tag2 to have the same name as tag1 - should fail
379366
$this->tagManager->updateTag(
380367
$tag2->getId(),
381-
$tagCreate[0],
382-
$tagCreate[1],
383-
$tagCreate[2],
384-
$tagCreate[3],
368+
'first',
369+
false,
370+
false,
371+
null
385372
);
386373
}
387374

0 commit comments

Comments
 (0)