Skip to content

XWIKI-22344: When renaming a tag, the same tags but with different ca… #3685

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ public Map<String, Integer> getTagCountForQuery(String fromHql, String whereHql,
*/
public List<String> getDocumentsWithTag(String tag, XWikiContext context) throws XWikiException
{
return TagQueryUtils.getDocumentsWithTag(tag, context);
return TagQueryUtils.getDocumentsWithTag(tag, false, false);
}

/**
Expand All @@ -349,7 +349,13 @@ public List<String> getDocumentsWithTag(String tag, XWikiContext context) throws
public List<String> getDocumentsWithTag(String tag, boolean includeHiddenDocuments, XWikiContext context)
throws XWikiException
{
return TagQueryUtils.getDocumentsWithTag(tag, includeHiddenDocuments, context);
return getDocumentsWithTag(tag, includeHiddenDocuments, false);
}

private List<String> getDocumentsWithTag(String tag, boolean includeHiddenDocuments, boolean caseSensitive)
throws XWikiException
{
return TagQueryUtils.getDocumentsWithTag(tag, includeHiddenDocuments, caseSensitive);
}

/**
Expand Down Expand Up @@ -560,10 +566,13 @@ public TagOperationResult removeTagFromDocument(String tag, XWikiDocument docume
*/
protected TagOperationResult renameTag(String tag, String newTag, XWikiContext context) throws XWikiException
{
// if the user is renaming a tag to change its case, we want to ensure that we only retrieve tags based on
// the case. Else we want to rename the tag for all pages whatever the case.
boolean caseSensitive = StringUtils.equalsIgnoreCase(tag, newTag);
// Since we're renaming a tag, we want to rename it even if the document is hidden. A hidden document is still
// accessible to users, it's just not visible for simple users; it doesn't change permissions.
List<String> docNamesToProcess = getDocumentsWithTag(tag, true, context);
if (StringUtils.equals(tag, newTag) || docNamesToProcess.size() == 0 || StringUtils.isBlank(newTag)) {
List<String> docNamesToProcess = getDocumentsWithTag(tag, true, caseSensitive);
if (StringUtils.equals(tag, newTag) || docNamesToProcess.isEmpty() || StringUtils.isBlank(newTag)) {
return TagOperationResult.NO_EFFECT;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Map;

import org.xwiki.query.internal.HiddenDocumentFilter;
import org.xwiki.stability.Unstable;
import org.xwiki.tag.internal.TagException;
import org.xwiki.tag.internal.TagsSelector;

Expand Down Expand Up @@ -145,9 +146,29 @@ public static List<String> getDocumentsWithTag(String tag, XWikiContext context)
*/
public static List<String> getDocumentsWithTag(String tag, boolean includeHiddenDocuments, XWikiContext context)
throws XWikiException
{
return getDocumentsWithTag(tag, includeHiddenDocuments, false);
}

/**
* Get documents with the passed tags with the result depending on whether the caller decides to include hidden
* documents or not.
*
* @param tag a list of tags to match.
* @param includeHiddenDocuments if true then include hidden documents
* @param caseSensitive {@code true} if the case of the tag should be used in the query {@code false} for getting
* results whatever the case of the tag.
* @return list of docNames.
* @throws XWikiException if search query fails (possible failures: DB access problems, etc).
* @since 17.0.0RC1
* @since 16.10.1
*/
@Unstable
public static List<String> getDocumentsWithTag(String tag, boolean includeHiddenDocuments, boolean caseSensitive)
throws XWikiException
{
try {
return getTagsSelector().getDocumentsWithTag(tag, includeHiddenDocuments);
return getTagsSelector().getDocumentsWithTag(tag, includeHiddenDocuments, caseSensitive);
} catch (TagException e) {
throw new XWikiException(MODULE_XWIKI_STORE, ERROR_XWIKI_UNKNOWN,
String.format("Failed to get all documents with tag [%s]", tag), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,11 @@ Map<String, Integer> getTagCountForQuery(String fromHql, String whereHql, Map<St
*
* @param tag the tag to list documents for
* @param includeHiddenDocuments when {@code true} hidden document are returned as well
* @param caseSensitive {@code true} if the case of the tag should be used in the query {@code false} for getting
* results whatever the case of the tag.
* @return the list of serialized document reference of document containing a given tag
* @throws TagException in cas of issue where retrieving the documents
*/
List<String> getDocumentsWithTag(String tag, boolean includeHiddenDocuments) throws TagException;
List<String> getDocumentsWithTag(String tag, boolean includeHiddenDocuments, boolean caseSensitive)
throws TagException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@

/**
* Common abstract class for the implementation of {@link TagsSelector}. Provides an implementation of
* {@link TagsSelector#getDocumentsWithTag(String, boolean)} taking into account whether the implementation can be
* considered as safe.
* {@link TagsSelector#getDocumentsWithTag(String, boolean, boolean)} taking into account whether the implementation
* can be considered as safe.
*
* @version $Id$
* @since 15.0RC1
Expand Down Expand Up @@ -72,11 +72,16 @@ public abstract class AbstractTagsSelector implements TagsSelector
protected DocumentReferenceResolver<String> stringDocumentReferenceResolver;

@Override
public List<String> getDocumentsWithTag(String tag, boolean includeHiddenDocuments) throws TagException
public List<String> getDocumentsWithTag(String tag, boolean includeHiddenDocuments, boolean caseSensitive)
throws TagException
{
String hql = ", BaseObject as obj, DBStringListProperty as prop join prop.list item"
+ " where obj.className=:className and obj.name=doc.fullName and obj.id=prop.id.id and prop.id.name='tags'"
+ " and lower(item)=lower(:item)";
+ " where obj.className=:className and obj.name=doc.fullName and obj.id=prop.id.id and prop.id.name='tags'";
if (caseSensitive) {
hql += " and item = :item";
} else {
hql += " and lower(item)=lower(:item)";
}

try {
Query query = this.contextProvider.get().getWiki().getStore().getQueryManager().createQuery(hql, Query.HQL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,9 @@ public Map<String, Integer> getTagCountForQuery(String fromHql, String whereHql,
}

@Override
public List<String> getDocumentsWithTag(String tag, boolean includeHiddenDocuments) throws TagException
public List<String> getDocumentsWithTag(String tag, boolean includeHiddenDocuments, boolean caseSensitive)
throws TagException
{
return this.tagsSelector.getDocumentsWithTag(tag, includeHiddenDocuments);
return this.tagsSelector.getDocumentsWithTag(tag, includeHiddenDocuments, caseSensitive);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ void getDocumentsWithTag(Map<DocumentReference, Boolean> viewRightsMap, List<Str
.forEach((key, value) -> when(this.contextualAuthorizationManager.hasAccess(VIEW, key)).thenReturn(value));
when(this.query.<String>execute()).thenReturn(results);

assertEquals(expected, this.tagsSelector.getDocumentsWithTag("Tag0", false));
assertEquals(expected, this.tagsSelector.getDocumentsWithTag("Tag0", false, false));
}

private void initializeDocumentReferenceResolver()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ void getDocumentsWithTag(List<String> results, List<String> expected) throws Exc
{
when(this.query.<String>execute()).thenReturn(results);

assertEquals(expected, this.tagsSelector.getDocumentsWithTag("Tag0", false));
assertEquals(expected, this.tagsSelector.getDocumentsWithTag("Tag0", false, false));
verifyNoInteractions(this.stringDocumentReferenceResolver);
verifyNoInteractions(this.contextualAuthorizationManager);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@
*/
package org.xwiki.tag.test.ui;

import java.util.List;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.SpaceReference;
import org.xwiki.tag.test.po.AddTagsPane;
import org.xwiki.tag.test.po.TagPage;
import org.xwiki.tag.test.po.TaggablePage;
Expand All @@ -31,6 +34,7 @@
import org.xwiki.test.ui.TestUtils;

import static org.apache.commons.lang3.RandomStringUtils.secure;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

Expand All @@ -49,9 +53,12 @@ class TagIT
private TagPage tagPage;

@BeforeEach
void setUp(TestUtils setup)
void setUp(TestUtils setup, TestReference testReference) throws Exception
{
setup.loginAsSuperAdmin();
// Create a new test page.
setup.rest().delete(testReference);
setup.rest().savePage(testReference, "", "");
}

/**
Expand All @@ -61,7 +68,7 @@ void setUp(TestUtils setup)
@Order(1)
void addRemoveTag(TestUtils setup, TestReference testReference)
{
TaggablePage taggablePage = resetTaggablePage(setup, testReference);
TaggablePage taggablePage = TaggablePage.gotoPage(testReference);
String tag = secure().nextAlphanumeric(4);
assertFalse(taggablePage.hasTag(tag));
AddTagsPane addTagsPane = taggablePage.addTags();
Expand All @@ -79,7 +86,7 @@ void addRemoveTag(TestUtils setup, TestReference testReference)
@Order(2)
void cancelAddTag(TestUtils setup, TestReference testReference)
{
TaggablePage taggablePage = resetTaggablePage(setup, testReference);
TaggablePage taggablePage = TaggablePage.gotoPage(testReference);
String firstTag = secure().nextAlphanumeric(4);
assertFalse(taggablePage.hasTag(firstTag));
AddTagsPane addTagsPane = taggablePage.addTags();
Expand All @@ -102,7 +109,7 @@ void cancelAddTag(TestUtils setup, TestReference testReference)
@Order(3)
void addManyRemoveOneTag(TestUtils setup, TestReference testReference)
{
TaggablePage taggablePage = resetTaggablePage(setup, testReference);
TaggablePage taggablePage = TaggablePage.gotoPage(testReference);
String firstTag = secure().nextAlphanumeric(4);
assertFalse(taggablePage.hasTag(firstTag));
String secondTag = secure().nextAlphanumeric(4);
Expand All @@ -125,7 +132,7 @@ void addManyRemoveOneTag(TestUtils setup, TestReference testReference)
@Order(4)
void addExistingTag(TestUtils setup, TestReference testReference)
{
TaggablePage taggablePage = resetTaggablePage(setup, testReference);
TaggablePage taggablePage = TaggablePage.gotoPage(testReference);
String tag = secure().nextAlphanumeric(4);
assertFalse(taggablePage.hasTag(tag));
AddTagsPane addTagsPane = taggablePage.addTags();
Expand All @@ -146,7 +153,7 @@ void addExistingTag(TestUtils setup, TestReference testReference)
@Order(5)
void testAddTagContainingPipe(TestUtils setup, TestReference testReference)
{
TaggablePage taggablePage = resetTaggablePage(setup, testReference);
TaggablePage taggablePage = TaggablePage.gotoPage(testReference);
String tag = secure().nextAlphanumeric(3) + "|" + secure().nextAlphanumeric(3);
assertFalse(taggablePage.hasTag(tag));
AddTagsPane addTagsPane = taggablePage.addTags();
Expand All @@ -168,7 +175,7 @@ void testAddTagContainingPipe(TestUtils setup, TestReference testReference)
@Order(6)
void stripLeadingAndTrailingSpacesFromTags(TestUtils setup, TestReference testReference)
{
TaggablePage taggablePage = resetTaggablePage(setup, testReference);
TaggablePage taggablePage = TaggablePage.gotoPage(testReference);
String firstTag = secure().nextAlphanumeric(4);
assertFalse(taggablePage.hasTag(firstTag));
String secondTag = secure().nextAlphanumeric(4);
Expand All @@ -189,7 +196,7 @@ void stripLeadingAndTrailingSpacesFromTags(TestUtils setup, TestReference testRe
@Order(7)
void testTagCaseIsIgnored(TestUtils setup, TestReference testReference)
{
TaggablePage taggablePage = resetTaggablePage(setup, testReference);
TaggablePage taggablePage = TaggablePage.gotoPage(testReference);
String firstTag = "taG1";
assertFalse(taggablePage.hasTag(firstTag));
// Second tag is same as first tag but with different uppercase/lowercase chars.
Expand All @@ -204,30 +211,69 @@ void testTagCaseIsIgnored(TestUtils setup, TestReference testReference)
assertTrue(taggablePage.hasTag(firstTag));
assertFalse(taggablePage.hasTag(secondTag));
assertTrue(taggablePage.hasTag(thirdTag));

SpaceReference testSpace = testReference.getLastSpaceReference();
String subPageTitle = "SubPage";
DocumentReference otherPage = new DocumentReference(subPageTitle, testSpace);
setup.createPage(otherPage, "Some content", subPageTitle);
taggablePage = new TaggablePage();
addTagsPane = taggablePage.addTags();
addTagsPane.setTags(secondTag);
assertTrue(addTagsPane.add());
assertFalse(taggablePage.hasTag(firstTag));
assertTrue(taggablePage.hasTag(secondTag));
TagPage tagPage = taggablePage.clickOnTag(secondTag);
assertEquals(List.of(subPageTitle, testSpace.getName()), tagPage.getTaggedPages());

setup.gotoPage(testReference);
taggablePage = new TaggablePage();
tagPage = taggablePage.clickOnTag(firstTag);
assertEquals(List.of(subPageTitle, testSpace.getName()), tagPage.getTaggedPages());
tagPage = tagPage.renameTag(secondTag);
assertEquals(List.of(subPageTitle, testSpace.getName()), tagPage.getTaggedPages());

taggablePage = TaggablePage.gotoPage(testReference);
assertFalse(taggablePage.hasTag(firstTag));
assertTrue(taggablePage.hasTag(secondTag));
assertTrue(taggablePage.hasTag(thirdTag));

tagPage = taggablePage.clickOnTag(secondTag);
assertEquals(List.of(subPageTitle, testSpace.getName()), tagPage.getTaggedPages());
String tag4 = "tag4";
tagPage = tagPage.renameTag(tag4);
assertEquals(List.of(subPageTitle, testSpace.getName()), tagPage.getTaggedPages());
taggablePage = TaggablePage.gotoPage(testReference);
assertFalse(taggablePage.hasTag(firstTag));
assertFalse(taggablePage.hasTag(secondTag));
assertTrue(taggablePage.hasTag(thirdTag));
assertTrue(taggablePage.hasTag(tag4));

taggablePage = TaggablePage.gotoPage(otherPage);
assertFalse(taggablePage.hasTag(firstTag));
assertFalse(taggablePage.hasTag(secondTag));
assertFalse(taggablePage.hasTag(thirdTag));
assertTrue(taggablePage.hasTag(tag4));
}

@Test
@Order(8)
void addAndRenameTagFromTagPage(TestUtils setup, TestReference testReference)
{
TaggablePage taggablePage = resetTaggablePage(setup, testReference);
TaggablePage taggablePage = TaggablePage.gotoPage(testReference);
String tag = "MyTag";
AddTagsPane addTagsPane = taggablePage.addTags();
addTagsPane.setTags(tag);
assertTrue(addTagsPane.add());
assertTrue(taggablePage.hasTag(tag));
this.tagPage = taggablePage.clickOnTag(tag);
this.tagPage.clickRenameButton();
this.tagPage.setNewTagName("MyTagRenamed");
this.tagPage.clickConfirmRenameTagButton();
assertTrue(this.tagPage.hasTagHighlight("MyTagRenamed"));
this.tagPage.renameTag("MyTagRenamed");
}

@Test
@Order(9)
void addAndDeleteTagFromTagPage(TestUtils setup, TestReference testReference)
{
TaggablePage taggablePage = resetTaggablePage(setup, testReference);
TaggablePage taggablePage = TaggablePage.gotoPage(testReference);
String tag = "MyTagToBeDeleted";
AddTagsPane addTagsPane = taggablePage.addTags();
addTagsPane.setTags(tag);
Expand All @@ -236,14 +282,6 @@ void addAndDeleteTagFromTagPage(TestUtils setup, TestReference testReference)
this.tagPage = taggablePage.clickOnTag(tag);
this.tagPage.clickDeleteButton();
this.tagPage.clickConfirmDeleteTag();
assertTrue(this.tagPage.hasConfirmationMessage(tag));
}

private TaggablePage resetTaggablePage(TestUtils setup, DocumentReference entityReference)
{
// Create a new test page.
setup.deletePage(entityReference);
setup.createPage(entityReference, "");
return new TaggablePage();
assertTrue(this.tagPage.hasConfirmationMessage());
}
}
Loading
Loading