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

feat(get): get more infos from user (DEV-641) #181

Merged
merged 9 commits into from Apr 25, 2022

Conversation

jnussbaum
Copy link
Collaborator

resolves DEV-641

@jnussbaum jnussbaum self-assigned this Apr 7, 2022
@jnussbaum jnussbaum changed the title get: get more infos from user (DEV-641) feat(get): get more infos from user (DEV-641) Apr 7, 2022
@jnussbaum
Copy link
Collaborator Author

Open concerns:

  • user.py, line 725: The method User.fromJsonObj() wants the project and the groups to be inside the user[permissions] as dict. It ignores the fields "groups" and "projects" in the API-retrieved user-JSON-objects. I suspect that User.fromJsonObj() should be adapted, but I don't really understand how. So I decided to make a "hack": I add the "groups" and "projects" two times: first to the API-retrieved object, and then to the models.user.User objects.
  • In the original onto, the ontos of the current file are not listed in the "prefixes" section (because we made them optional some weeks ago). But in the retrieved one, they are. In the GET-process, I think it would make sense to eliminate all prefixes of the current onto file. What do you think?
  • In users>groups and users>projects, The prefixes could be omitted as well.

Copy link

@irinaschubert irinaschubert left a comment

Choose a reason for hiding this comment

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

A question: how are users treated if they are members of several projects and members of groups of other projects, are these projects and groups retrieved as well? If so, should this information be provided in with the dsp-tools get command?

About your questions:

  • user.py, line 725: I'm not sure if I understand your question: The API route that is used on line 692 does not return the groups and projects, so you need to get the groups and users separately, like you did. What do you mean with "I add the groups and projects two times"? You only add them once to the user you retrieved from the API. Not sure if I miss something here...
  • Prefixes of the acutal ontology: I would leave them there. It is correct and it's a useful information. Or is there a reason why it shouldn't be in the ontology? --> I don't really have a strong opinion on that - do what you prefer
  • I would leave them there, to me they aren't disturbing. --> I don't really have a strong opinion on that - do what you prefer

knora/dsplib/models/user.py Outdated Show resolved Hide resolved
knora/dsplib/models/user.py Outdated Show resolved Hide resolved
knora/dsplib/models/user.py Outdated Show resolved Hide resolved
@@ -689,7 +690,7 @@ def getAllUsersForProject(con: Connection, proj_shortcode: str) -> list[Any]:

result = con.get(User.ROUTE)

Choose a reason for hiding this comment

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

Now that I think about it, there is a route to get all users for a specific project, it's:
/admin/projects/shortcode/{{project_shortcode}}/members

It's probably easier to use this for getAllUsersForProject directly. There are also groups and projects for the user.

Copy link
Collaborator

@BalduinLandolt BalduinLandolt left a comment

Choose a reason for hiding this comment

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

I don't have much to add to this one, beyond the comments Irina has already made

knora/dsplib/models/user.py Outdated Show resolved Hide resolved
jnussbaum and others added 5 commits April 19, 2022 09:55
Co-authored-by: irinaschubert <irina.schubert@dasch.swiss>
Co-authored-by: Balduin Landolt <33053745+BalduinLandolt@users.noreply.github.com>
@sonarcloud
Copy link

sonarcloud bot commented Apr 19, 2022

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 1 Code Smell

No Coverage information No Coverage information
0.0% 0.0% Duplication

@jnussbaum
Copy link
Collaborator Author

Thanks to Irina's comment (#181 (comment)) I managed to considerably simplify the code and to resolve the concern I had in #181 (comment).

Besides, I implemented your feedback and I also did some refactorings where it seemed useful.

The PR has now changed considerably, so I ask you again for a review.

Comment on lines -478 to +489
project_groups = json_obj['permissions']['groupsPerProject']
for project in project_groups:
if project == Project.SYSTEM_PROJECT:
if Group.PROJECT_SYSTEMADMIN_GROUP in project_groups[project]:
for project_iri, group_memberships in json_obj['permissions']['groupsPerProject'].items():
if project_iri == Project.SYSTEM_PROJECT:
if Group.PROJECT_SYSTEMADMIN_GROUP in group_memberships:
sysadmin = True
else:
for group in project_groups[project]:
for group in group_memberships:
if group == Group.PROJECT_MEMBER_GROUP:
if in_projects.get(project) is None:
in_projects[project] = False
if in_projects.get(project_iri) is None:
in_projects[project_iri] = False
elif group == Group.PROJECT_ADMIN_GROUP:
in_projects[project] = True
in_projects[project_iri] = True
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is just a refactoring, without semantic modification.

Copy link
Collaborator

Choose a reason for hiding this comment

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

nice!


def createDefinitionFileObj(self):
user = {
members = con.get(f'/admin/projects/shortcode/{proj_shortcode}/members')
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

With this route, the same task can be achieved with less code

Copy link
Collaborator

@BalduinLandolt BalduinLandolt left a comment

Choose a reason for hiding this comment

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

one can always find more to change and improve... but I think this should be good for now. (I added some minor remarks nonetheless)

@@ -475,18 +476,17 @@ def fromJsonObj(cls, con: Connection, json_obj: Any):
in_groups: set[str] = set()
if json_obj.get('permissions') is not None and json_obj['permissions'].get('groupsPerProject') is not None:
Copy link
Collaborator

Choose a reason for hiding this comment

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

generally, if x is not None can normally be rewritten as if not x (but that doesn't need to be done in this PR... I know it's all over the place in dsp-tools)

Comment on lines +481 to 482
if Group.PROJECT_SYSTEMADMIN_GROUP in group_memberships:
sysadmin = True
Copy link
Collaborator

Choose a reason for hiding this comment

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

this could be simplified even further (I think): sysadmin = (Group.PROJECT_SYSTEMADMIN_GROUP in group_memberships)

Comment on lines -478 to +489
project_groups = json_obj['permissions']['groupsPerProject']
for project in project_groups:
if project == Project.SYSTEM_PROJECT:
if Group.PROJECT_SYSTEMADMIN_GROUP in project_groups[project]:
for project_iri, group_memberships in json_obj['permissions']['groupsPerProject'].items():
if project_iri == Project.SYSTEM_PROJECT:
if Group.PROJECT_SYSTEMADMIN_GROUP in group_memberships:
sysadmin = True
else:
for group in project_groups[project]:
for group in group_memberships:
if group == Group.PROJECT_MEMBER_GROUP:
if in_projects.get(project) is None:
in_projects[project] = False
if in_projects.get(project_iri) is None:
in_projects[project_iri] = False
elif group == Group.PROJECT_ADMIN_GROUP:
in_projects[project] = True
in_projects[project_iri] = True
Copy link
Collaborator

Choose a reason for hiding this comment

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

nice!

def createDefinitionFileObj(self):
user = {
members = con.get(f'/admin/projects/shortcode/{proj_shortcode}/members')
if members is None or len(members) < 1:
Copy link
Collaborator

Choose a reason for hiding this comment

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

this can be simplified to if not members: (both None and empty lists/dicts/sets evaluate as false in an if-clause)

if members is None or len(members) < 1:
return None
res: list[User] = [User.fromJsonObj(con, a) for a in members['members']]
res.reverse()
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure the order of the objects you get from the API is deterministic (at least if the cache is rebuilt), so this may not reliably reproduce the initial order. But if it works in the cases you tested, feel free to leave it in.

Choose a reason for hiding this comment

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

In order to find out if it works as expected (also in the future), you could add a test for this method.

Comment on lines +66 to +71
for usr in users:
users_obj.append(usr.createDefinitionFileObj(
con=con, proj_shortname=project.shortname, proj_shortcode=project.shortcode
))
if verbose:
print(f"\tGot user '{usr.username}'")
Copy link
Collaborator

Choose a reason for hiding this comment

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

is usr intentional?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

no, rather random

@jnussbaum jnussbaum merged commit 407f5c5 into main Apr 25, 2022
@jnussbaum jnussbaum deleted the wip/dev-641-get-more-infos-from-user branch April 25, 2022 06:42
Copy link

@irinaschubert irinaschubert left a comment

Choose a reason for hiding this comment

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

LGTM

if members is None or len(members) < 1:
return None
res: list[User] = [User.fromJsonObj(con, a) for a in members['members']]
res.reverse()

Choose a reason for hiding this comment

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

In order to find out if it works as expected (also in the future), you could add a test for this method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants