Skip to content
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

Enhance static page with group user accessibility #7707

Merged

Conversation

wangf1122
Copy link
Collaborator

@wangf1122 wangf1122 commented Feb 6, 2024

This enhanced feature gives the administrative user the capability to config the static page to some specific user in some groups.

image

I have two static page, one for the "sandbox" or "my_org" group users. One for all logged users
image

Either the sandbox_editor or org_editor logged in, the "org" page will display:
image

But when the "other_editor who has no access to sandbox or my_org group logged in, this user cannot see "org" page
image

So this feature is fully expandable to some other security measure scenario because the backend table column is named as access expression and will store JSON string by parsing from Java object AccessExpression. We can customize it by change the java business model itself.
image

@wangf1122 wangf1122 marked this pull request as ready for review February 6, 2024 22:05
@@ -76,6 +81,9 @@ public class PagesAPI {

private final PageRepository pageRepository;

@Autowired
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest to move autowire to the constructor

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't find such practice within the whole Geonetwork project. Also the GN is using some old Spring version which I am little afraid of it does not support constructor type of injection. I would leave it for now to be consistent of overall geonetwork's coding standard.

web-ui/src/main/resources/catalog/locales/en-v4.json Outdated Show resolved Hide resolved
domain/src/main/java/org/fao/geonet/domain/page/Page.java Outdated Show resolved Hide resolved
domain/src/main/java/org/fao/geonet/domain/page/Page.java Outdated Show resolved Hide resolved
@ianwallen ianwallen added this to the 4.4.3 milestone Feb 7, 2024
@wangf1122 wangf1122 marked this pull request as draft February 7, 2024 21:42
@wangf1122
Copy link
Collaborator Author

I am amending the feature to have multiple group selection option. Will post another version soon

@wangf1122 wangf1122 marked this pull request as ready for review February 9, 2024 15:05
@ianwallen ianwallen requested a review from josegar74 February 26, 2024 11:56
@josegar74
Copy link
Member

@wangf1122 I'm testing the UI, but the groups panel doesn't seem enabled properly.

I create a new static page, the groups panel is disabled, but when selecting the value Visible to users belonging to the groups is not enabled, I have to select the value again.

The same when selecting other value, it's not disabled until I selected the value again.

@wangf1122
Copy link
Collaborator Author

@wangf1122 I'm testing the UI, but the groups panel doesn't seem enabled properly.

I create a new static page, the groups panel is disabled, but when selecting the value Visible to users belonging to the groups is not enabled, I have to select the value again.

The same when selecting other value, it's not disabled until I selected the value again.

@josegar74

Did you refreshed your local CSS/JS cache? I dont seem to have such issue at my localhost. See below

image

image

@josegar74
Copy link
Member

@wangf1122 yes, I did that and cleanup also the browser cache.

See the attached screencast.

static-pages.webm

@@ -114,4 +123,12 @@ public String getIcon() {
public void setIcon(String icon) {
this.icon = icon;
}

public List<String> getGroups() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main concern is about not using referential integrity with the groups table.

Could be maybe check as a similar example the User -> Address relationship:

  • /**
    * Get all the user's addresses.
    *
    * @return all the user's addresses.
    */
    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinTable(name = "UserAddress", joinColumns = @JoinColumn(name = "userid"), inverseJoinColumns = {@JoinColumn(name = "addressid",
    referencedColumnName = "ID", unique = true)})
    public Set<Address> getAddresses() {
    return _addresses;
    }
    /**
    * Set all the user's addresses.
    *
    * @param addresses all the user's addresses.
    * @return this user object
    */
    protected User setAddresses(Set<Address> addresses) {
    this._addresses = addresses;
    return this;
    }

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The challenge is the group is from JSON representation. We cannot just build the backend in pure JPA representation. The JSON representation will need to expand to future security representation not limited to groups but something else.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wangf1122 - @josegar74 is suggesting that the json expression be replaced with a new pageGroup table that would be used to link the pages to the groups within the database. This will ensure that if a group or page is removed then the database will cascade the delete causing it to clean itself.

Otherwise with the json expression, there could be issues where it references groups that no longer exist.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@josegar74 @ianwallen

I have added the page/group joint table and the entity mapping. I got rid of the accessexpression JSON in this case. Please retest from your local.

@wangf1122
Copy link
Collaborator Author

@wangf1122 yes, I did that and cleanup also the browser cache.

See the attached screencast.

static-pages.webm

@josegar74

I see what you mean. I change the ui code from ng-click to ng-change. The javascript change will fit here better than click behavior

@fxprunayre fxprunayre removed this from the 4.4.3 milestone Mar 13, 2024
@@ -4,3 +4,13 @@ INSERT INTO Settings (name, value, datatype, position, internal) VALUES ('system

UPDATE Settings SET value='4.4.3' WHERE name='system/platform/version';
UPDATE Settings SET value='0' WHERE name='system/platform/subVersion';

CREATE TABLE spg_page_group
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wangf1122
I'm not sure if create tables are required in the migration as I think JPA will take care of creating any missing tables.

@josegar74
Can you confirm if this is required?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@josegar74 @ianwallen

I had confirmed myself. It is not required. The JPA will automatically create the table. I will update the script.

Copy link
Member

@josegar74 josegar74 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wangf1122 I tested the feature and looks fine. The only thing that was that I could delete a group that had pages linked to it, the group in the page it's still there.

It can be good when removing the group to delete the relation or just show some message when deleting the group to inform that has static pages related and need to remove that relation first.

domain/src/main/java/org/fao/geonet/domain/page/Page.java Outdated Show resolved Hide resolved
@@ -203,6 +227,30 @@ private ResponseEntity<Void> updatePageInternal(@NotNull String language,
String newLabel = pageProperties.getLabel();
String newIcon = pageProperties.getIcon();

Set<Group> _groups = new LinkedHashSet<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this variable with the _groups and another with the name groups. I would rename them to have more meaningful names and remove the _ from this one.

Copy link
Collaborator Author

@wangf1122 wangf1122 Apr 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed to pageGroups. Please check

for (String groupName : pageProperties.getGroups()) {
Group group = groupRepository.findByName(groupName);

Group groupToAdd= new Group();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason to do a copy of the group?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had trouble with the JPA not adding group if not doing copy. Cannot guarantee if the code will work without the copying

@wangf1122
Copy link
Collaborator Author

@wangf1122 I tested the feature and looks fine. The only thing that was that I could delete a group that had pages linked to it, the group in the page it's still there.

It can be good when removing the group to delete the relation or just show some message when deleting the group to inform that has static pages related and need to remove that relation first.

@josegar74

I have added the logic in group delete API to prevent the deletion if the group has associate with static pages. Similar logic like users and groups

@ianwallen ianwallen requested a review from josegar74 May 8, 2024 10:42
@josegar74 josegar74 modified the milestones: 4.4.5, 4.4.6 Jun 3, 2024
Copy link
Member

@josegar74 josegar74 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice also issues when saving the pages:

  1. Create a page that has a status not related to groups.
  2. Edit it and change to related to groups and assign it to 1 group --> it works
  3. Edit it and change to related to groups and assign it to 2 group --> it doesn't work, it maintains the previous configuration. No error reported.

It seems happening also when creating a page assigned to 2 or more groups.

@@ -541,6 +547,21 @@ public void deleteGroup(
));
}

List<Page> staticPages = pageRepository.findAll();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add this method in the repository:

List<Page> findPageByStatus(Page.PageStatus status);

And update the code to the following to at least only process the pages that are assigned to groups:

List<Page> staticPages = pageRepository.findPageByStatus(Page.PageStatus.GROUPS);
List<Page> staticPagesAssignedToGroup =
    staticPages.stream().filter(p ->
            !p.getGroups().stream().filter(g -> g.getId() == groupIdentifier).collect(Collectors.toList()).isEmpty())
        .collect(Collectors.toList());

if (!staticPagesAssignedToGroup.isEmpty()) {
    throw new NotAllowedException(String.format(
        "Group %s is associated with '%s' static page(s). Please remove the static page(s) associated with that group first.",
        group.get().getName(), staticPagesAssignedToGroup.stream().map(p -> p.getLabel()).collect(Collectors.joining())
    ));
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@josegar74

I have added the code. Also the issue you are experiencing "Edit it and change to related to groups and assign it to 2 group --> it doesn't work, it maintains the previous configuration. No error reported." was due to the backend entity relation. It's supposed to be ManyToMany relation. Otherwise, the groupId in the spg_page_group table will be unique. So once one page occupied groupId_1, this groupId_1 will not be available to other pages. Once I have the ManyToMany relation, it does. Here is some example of my local database after the fix:

image

@wangf1122 wangf1122 requested a review from josegar74 July 11, 2024 20:53
Copy link
Member

@josegar74 josegar74 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested the latest changes and look ok.

@ianwallen ianwallen modified the milestones: 4.4.6, 4.4.7 Oct 8, 2024
@ianwallen ianwallen merged commit bedfe3d into geonetwork:main Nov 7, 2024
6 checks passed
@geonetworkbuild
Copy link
Collaborator

The backport to 4.2.x failed:

The process '/usr/bin/git' failed with exit code 1
stderr
error: could not apply 6d1fd4c529... Add group/accessExpression field to static page feature
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".
hint: Disable this message with "git config advice.mergeConflict false"

stdout
Auto-merging domain/src/main/java/org/fao/geonet/domain/page/Page.java
CONFLICT (content): Merge conflict in domain/src/main/java/org/fao/geonet/domain/page/Page.java
Auto-merging services/src/main/java/org/fao/geonet/api/pages/PageProperties.java
CONFLICT (content): Merge conflict in services/src/main/java/org/fao/geonet/api/pages/PageProperties.java
Auto-merging services/src/main/java/org/fao/geonet/api/pages/PagesAPI.java
CONFLICT (content): Merge conflict in services/src/main/java/org/fao/geonet/api/pages/PagesAPI.java
Auto-merging web-ui/src/main/resources/catalog/locales/en-v4.json
Auto-merging web-ui/src/main/resources/catalog/templates/admin/settings/static-pages.html
CONFLICT (modify/delete): web/src/main/webapp/WEB-INF/classes/setup/sql/migrate/v443/migrate-default.sql deleted in HEAD and modified in 6d1fd4c529 (Add group/accessExpression field to static page feature).  Version 6d1fd4c529 (Add group/accessExpression field to static page feature) of web/src/main/webapp/WEB-INF/classes/setup/sql/migrate/v443/migrate-default.sql left in tree.

To backport manually, run these commands in your terminal:

# Fetch latest updates from GitHub
git fetch
# Create a new working tree
git worktree add .worktrees/backport-4.2.x 4.2.x
# Navigate to the new working tree
cd .worktrees/backport-4.2.x
# Create a new branch
git switch --create backport-7707-to-4.2.x
# Cherry-pick the merged commit of this pull request and resolve the conflicts
git cherry-pick 6d1fd4c5294d5398d49d96c535782cd3f08879b7,99e1e5486e83818aae6b8ce96efbbfcc23d14990,04a25216fe531dddfb50b6fc724f123f7f394923,214af08ef35cde02b1660b4c219c57da49216a80,e09d0c204a39ce58727ed6cffd5f2e037239853b,47a5ee200daf9a878d12cf85baf17e01a2d09727,db1b7db3c8c4cb97d487bf1498b6363cbd4afb3f,fd7c7b125de114437e02e7e27c02e799513d7967,c98548ab4325c20b528ae71eacd5d6b5738dc363,de04d9a052e450c653c6c052f8acdb49ab29001d,30a0b2b6597488b2af57f835c8962564e6d446bd,bc3ffb344b42190682cbc5c9abcb5a3fc487cad1,246b184e4fb3a7e5c55fdc334eff00a64936f0cb,8b10f742f2155d833f631f0beb86939f0ec3711b,864c2cbba01c5959e76c53bd4be063e7355cb4a9,a0a5534b18b8699e237efaadf636e375d2e4cbdd,7d8e03d18482180ef63181732dff3ad207b473bb,c93bade75516e2d6af099faab3171ebb662ceb61,7c056cf2c4f2b4e20ccd50faadbf57679b22b58b,9ca02c8784176e0f1c437b4a57ed109f2c0bf27d,262fa60115fe62817a1671d529bcd77f5430a25c,2d82af005440808ccbc3b23d3036fd4b350dcd81,56ac85c552ae4e2cf0ecb23b99915ad48e4d2730,292d127de196f944ef5ac29390c2141d1edc517c
# Push it to GitHub
git push --set-upstream origin backport-7707-to-4.2.x
# Go back to the original working tree
cd ../..
# Delete the working tree
git worktree remove .worktrees/backport-4.2.x

Then, create a pull request where the base branch is 4.2.x and the compare/head branch is backport-7707-to-4.2.x.

wangf1122 added a commit to wangf1122/core-geonetwork that referenced this pull request Nov 7, 2024
* Add group/accessExpression field to static page feature

* Filter none group member access to page belong to certain group

* code improvement

* multi selections for groups

* multi selections for groups.

* Refactoring group checking logic

* Update services/src/main/java/org/fao/geonet/api/pages/model/GroupAccessExpression.java

Co-authored-by: Jose García <[email protected]>

* ui change menu behavior

* Fixing ui issue

* pageGroup joint relation in page entity

* pageGroup joint relation in page entity (add SQL)

* remove page creation script

* Update domain/src/main/java/org/fao/geonet/domain/page/Page.java

Co-authored-by: Jose García <[email protected]>

* rename group

* prevent group remove if it has association with static pages

* JPA ManyToMany bug fix

---------

Co-authored-by: Jose García <[email protected]>
ianwallen pushed a commit that referenced this pull request Nov 7, 2024
* Add group/accessExpression field to static page feature

* Filter none group member access to page belong to certain group

* code improvement

* multi selections for groups

* multi selections for groups.

* Refactoring group checking logic

* Update services/src/main/java/org/fao/geonet/api/pages/model/GroupAccessExpression.java



* ui change menu behavior

* Fixing ui issue

* pageGroup joint relation in page entity

* pageGroup joint relation in page entity (add SQL)

* remove page creation script

* Update domain/src/main/java/org/fao/geonet/domain/page/Page.java



* rename group

* prevent group remove if it has association with static pages

* JPA ManyToMany bug fix

---------

Co-authored-by: Jose García <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants