-
Notifications
You must be signed in to change notification settings - Fork 44
NGSTACK-977 tags visibility #169
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
base: master
Are you sure you want to change the base?
Conversation
… in both API and persistence layer
…isible' columns in 'eztags' table
…n DoctrineDatabase, TagsMapper and Mapper classes
…anslation files and display them in admin UI
…show when a tag is hidden by parent
… hidden tags to content
/** | ||
* Hides $tag. | ||
* | ||
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException If the current user is not allowed to delete this tag |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrong exception text If the current user is not allowed to delete this tag
. Shoud be hide instead of delete.
Same goes for unhide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed PHPDocs: c698f26
Will probably rename 'unhide' to 'reveal', as Petar suggested below
@@ -14,6 +14,14 @@ final class TagViewController extends Controller | |||
*/ | |||
public function viewAction(TagView $view): TagView | |||
{ | |||
if ($view->getTag()->isHidden) { | |||
throw $this->createNotFoundException('Tag is hidden.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need the message here. As this is the frontend, we do not want to communicate any revealing info.
As far as the user is concerned, the tag does not exist and that's it.
Also, here, you can only check for visible/invisible since when the tag is hidden, it should automatically be invisible too. That is, it is not possible for the tag to be hidden but not invisible too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the message: c698f26
@@ -226,6 +226,16 @@ public function newTagUpdateStruct(): TagUpdateStruct | |||
return $this->service->newTagUpdateStruct(); | |||
} | |||
|
|||
public function hideTag(Tag $tag): void | |||
{ | |||
$this->service->hideTag($tag); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No event dispatching here and in unhide tag method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot about them... added them now: 69672a5
$query->expr()->like('path_string', ':path_string'), | ||
) | ||
->andWhere( | ||
$query->expr()->neq('id', ':tag_id'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When hiding a tag, the hidden root tag should also be invisible, so we don't need this neq
condition.
This is the way Ibexa works when hiding content, so there is no need to do this differently here. It will only cause confusion in the long run.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, didn't know that this was how Ibexa works.
Removed the neq
: f8bcf8d
$query->expr()->like('path_string', ':path_string'), | ||
) | ||
->andWhere( | ||
$query->expr()->neq('id', ':tag_id'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same remark about root tag invisibility goes here.
Also, I think we need to consider here what happens when some tag is already hidden explicitly below the tag being unhidden here. In that case, we can't really make tags below the already hidden tag invisible to maintain data consistency. We should see how Ibexa does this and just copy the implementation from there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -35,6 +35,8 @@ public function createTagInfoFromRow(array $row): TagInfo | |||
$tagInfo->alwaysAvailable = (bool) ((int) $row['language_mask'] & 1); | |||
$tagInfo->mainLanguageCode = $this->languageHandler->load($row['main_language_id'])->languageCode; | |||
$tagInfo->languageIds = $this->languageMaskGenerator->extractLanguageIdsFromMask((int) $row['language_mask']); | |||
$tagInfo->isHidden = (bool) ((int) $row['is_hidden']); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need double cast here. You probably copied the thing from (bool) ((int) $row['language_mask'] & 1)
, but that has double cast due to bitwise and operator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the double cast, kept only the bool
one: e5b2f5f
@@ -9,3 +9,5 @@ tags: | |||
deletesynonym: ~ | |||
makesynonym: ~ | |||
merge: ~ | |||
hide: ~ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're missing hidesysnonym
and unhidesynonym
policies here. Also do we really need policies for both hide and unhide?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added hidesynonym
and unhidesynonym
policies: 7e88bdd
I also thought that just one policy for hiding tags is enough, but I made two just for clarity.
If you want, I can only leave 'hide' and 'hidesynonym' policies, which will mean that the user can both hide and reveal tags.
> | ||
{{ tag.keyword }} | ||
{% if tag.isHidden %} | ||
(hidden) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs translations too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added translations here for '(hidden)' and '(hidden by parent)': dece52c
…e schemas and fix MapperTest
…g shown to the user
…visible' fields in Mapper
…latable in 'eztags' content field
…sible when revealing a tag
…and descendant hidden tags
Added Implemented the following methods of the
|
…en)' text next to synonym name if the synonym is hidden
… the tag is hidden
98cce00
to
d09d660
Compare
…s for revealTag() and hideTag() methods
…dden' and 'is_invisible' properties
@@ -37,6 +37,7 @@ public function autoCompleteAction(Request $request): JsonResponse | |||
$searchResult = $this->tagsService->searchTags( | |||
$request->query->get('searchString') ?? '', | |||
$request->query->get('locale') ?? '', | |||
showHidden: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be controlled through the configuration as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hardcoded here false because the autoCompleteAction()
method is used for searching a tag to add it in eztags
field. If the showHidden parameter wasn't false here, then the user could add a hidden tag to some content by searching for it when editing a content.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to agree with @AntePrkacin on this one that we should always avoid outputting hidden tags in the autocomplete actions like searching for tags in tag fields, but there can be some quite silly edge-cases where editor would hide the tag so tags/view page is not visible yet, but they would like to start filling in the content with those hidden tags before revealing the tag all-together.
For sure this configuration parameter must be set to false as default, but for those pesky edge-cases, a parameter is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, parameter is definitely needed.
Also, please do not use named parameters, at least not mixed like this, it just looks wrong :D Either change all of them to use named parameters, or none.
{ | ||
$this->denyAccessUnlessGranted('ibexa:tags:hide' . ($tag->isSynonym() ? 'synonym' : '')); | ||
|
||
$this->tagsService->hideTag($tag); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to check the submitted button and CSRF token here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we do. There is an example in deleteTagAction
method.
{ | ||
$this->denyAccessUnlessGranted('ibexa:tags:reveal' . ($tag->isSynonym() ? 'synonym' : '')); | ||
|
||
$this->tagsService->revealTag($tag); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to check the submitted button and CSRF token here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we do. There is an example in deleteTagAction
method.
@@ -76,7 +76,7 @@ public function loadTagByUrl(string $url, array $languages): Tag; | |||
* | |||
* @return \Netgen\TagsBundle\API\Repository\Values\Tags\TagList | |||
*/ | |||
public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true): TagList; | |||
public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly we should have a default value for $showHidden
here, instead of resolving it in the Persistence implementation. @emodric I'll leave that up to you :)
(Then the same applies for the similar cases below)
Edit: ignore the above, I think the parameter should not be optional in the Persistence layer, we probably need it to be optional here so we can properly handle it in the siteaccess-aware implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @pspanja , however, nullable bool seems weird. Either we show or hide hidden tags, there's no third option for null
. So bool $showHidden = false
is probably good enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@emodric one question though, if here the default is not null
, how do we detect explicitly passed value in the siteaccess-aware layer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm. Good point. Although, do we even have the need for explicit API layer control of this flag? Can we rely only on siteaccess aware config?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say we do, this is not only for rendering, it might be used in import for example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import scripts can be run in admin siteaccess if needed.
It's just weird design, is all, since API interface presumes that somwhere down below, the value we give to the method might be overriden.
But okay, if there are valid usecases, I can live with it.
@AntePrkacin you can add upgrade instructions in Use |
Updated the |
@@ -666,6 +706,60 @@ public function deleteTagsAction(Request $request, ?Tag $parentTag = null): Resp | |||
); | |||
} | |||
|
|||
public function hideTagsAction(Request $request, ?Tag $parentTag = null): Response |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here with CSRF. What we need to do here is create a Symfony multiselect form for selecting the tags in lieu of moveTagsAction
method. Same goes for revealTagsAction
.
], | ||
], | ||
]; | ||
} | ||
|
||
private function escape(string $string): string | ||
private function formatTagTreeText(Tag $tag): string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't mix escaping and formating. That is, leave escape
method as is, and just reuse is in the new formatTagTreeText
method. After all, all of the text should be escaped AFTER formatting it, and not just the starting text.
@@ -154,6 +161,13 @@ public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array | |||
} | |||
|
|||
$query = $this->createTagFindQuery($translations, $useAlwaysAvailable); | |||
|
|||
if ($showHidden !== null && $showHidden === false) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If $showHidden
were not nullable, as mentioned before, you wouldn't need double check here and in other places.
@@ -155,6 +155,10 @@ public function getConfigTreeBuilder(): TreeBuilder | |||
->defaultValue(25) | |||
->end() | |||
->end() | |||
->end() | |||
->booleanNode('show_hidden') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be explicit and name this show_hidden_tags
.
@@ -9,6 +9,8 @@ CREATE TABLE `eztags` ( | |||
`remote_id` varchar(100) NOT NULL default '', | |||
`main_language_id` int(11) NOT NULL default '0', | |||
`language_mask` int(11) NOT NULL default '0', | |||
`is_hidden` tinyint NOT NULL DEFAULT '0', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also need MySQL and PostgreSQL upgrade scripts (see bundle/Resources/sql/upgrade
folder).
If you're using MySQL, run the commands below: | ||
|
||
```sql | ||
ALTER TABLE `eztags` ADD COLUMN `is_hidden` TINYINT NOT NULL DEFAULT 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should go to an upgrade SQL script as mentioned before and just referenced here.
Added
isHidden
andisInvisible
fields to Tag objects. Updated the database schema and updated the whole workflow for hiding and unhiding a tag (Service, Mapper, Handler, Gateway, ...).Added columns 'Hidden' and 'Invisible' to table that show children tags of some tag in admin interface.
In admin interface added button for hiding a tag (or if a tag is already hidden, then this button will unhide it).
Also added buttons 'Hide selected tags' and 'Unhide selected tags' for the checked children tags.
When a tag is hidden, the route
/tags/view/Topics/{tag_name}
will throw 404 and return information that 'Tag is hidden' or 'Tag is hidden by parent'.If a tag is hidden, then the user won't be able to add that tag to some 'eztags' content field for some content.
If some content already has a hidden tag, then this tag will have ' (hidden)' appended to it and it will be in gray color.