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

Feature add tc #467

Merged
merged 69 commits into from
Oct 27, 2021
Merged

Feature add tc #467

merged 69 commits into from
Oct 27, 2021

Conversation

ChaamC
Copy link
Contributor

@ChaamC ChaamC commented Sep 21, 2021

Features / Changes

  • Add new Terms and conditions field for group creation. When a request is made to assign a user to a
    group with terms and conditions, an email is now sent to the user with the terms and conditions. The user
    is assigned to the group when receiving the user's approval of terms and conditions, and another email is
    then sent to notify the user of the successful operation.
  • Changed /groups/{group_name}/users, /users/current/groups and /users/{user_name}/groups endpoints with
    a new parameter to either get active, pending or all users or groups. This new parameter is useful to
    display any pending users/groups on the UI.

Bug Fixes

  • Fix HTTP Internal Server Error [500] on the page to edit a group when deleting the last user of a group.

Other references

… pending users, to allow sending additional email requests
@github-actions github-actions bot added api Something related to the API operations db Issues related to database connection, migration or data models doc Documentation improvements or building problem tests Test execution or additional use cases ui Something related to the UI operations or display labels Sep 21, 2021
@codecov-commenter
Copy link

codecov-commenter commented Sep 21, 2021

Codecov Report

Merging #467 (decc9e2) into master (0c3ea91) will increase coverage by 0.03%.
The diff coverage is 73.13%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #467      +/-   ##
==========================================
+ Coverage   79.45%   79.49%   +0.03%     
==========================================
  Files          70       70              
  Lines        8909     9061     +152     
  Branches     1211     1226      +15     
==========================================
+ Hits         7079     7203     +124     
- Misses       1544     1573      +29     
+ Partials      286      285       -1     
Impacted Files Coverage Δ
magpie/api/notifications.py 65.27% <ø> (ø)
magpie/register.py 46.47% <ø> (ø)
magpie/ui/management/views.py 46.55% <13.33%> (-1.84%) ⬇️
magpie/ui/user/views.py 63.96% <47.36%> (-3.75%) ⬇️
magpie/services.py 81.20% <73.68%> (-0.14%) ⬇️
magpie/__meta__.py 100.00% <100.00%> (ø)
magpie/adapter/__init__.py 62.79% <100.00%> (ø)
magpie/adapter/magpieowssecurity.py 69.72% <100.00%> (+0.56%) ⬆️
magpie/adapter/magpieservice.py 63.63% <100.00%> (ø)
magpie/api/management/group/group_formats.py 100.00% <100.00%> (ø)
... and 16 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5c07b5b...decc9e2. Read the comment docs.

Copy link
Collaborator

@fmigneault fmigneault left a comment

Choose a reason for hiding this comment

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

Very nice PR and great tests!
I would like only a modification regarding the API endpoints (see comment in CHANGES).
Need a missing section in docs.
Code of the feature look all good.

CHANGES.rst Outdated
``group`` with terms and conditions, an email is now sent to the ``user`` with the terms and conditions. The ``user``
is assigned to the ``group`` when receiving the ``user``'s approval of terms and conditions, and another email is
then sent to notify the ``user`` of the successful operation.
* Add new requests under ``/groups/{group_name}/pending_users``, ``/users/current/pending_groups`` and
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of adding a new paths, I would prefer that existing ones receive a query parameter similar to the one for pending users.
This would allow us to either query "active" users/groups, pending ones, or both.
A field pending: true|false could to be added to returned user objects to indicate the pending state when querying "all" ("active"+pending).
The default when the query is omitted should be to return only active users/groups.

Copy link
Contributor Author

@ChaamC ChaamC Sep 22, 2021

Choose a reason for hiding this comment

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

So if I understand, for example, I can move the code of /groups/{group_name}/pending_users to /groups/{group_name}/users, and add a new input parameter to the /groups/{group_name}/users query, indicating what type of users to get.
I could make an ExtendedEnum with different usergroup types :
ALL_USERGROUPS (which adds to each returned user the boolean pending field you mentioned)
ACTIVE_USERGROUPS
PENDING_USERGROUPS

I can add a user_type parameter to the input of the GET query, which contains an user_type enum value corresponding to one of the entry above.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes. Exactly what I add in mind. You should only need to remap the detected "pending" to your function that was defined in current pending_users endpoint, and if "all" was requested, extend the result with the usual operation.

docs/glossary.rst Outdated Show resolved Hide resolved
magpie/api/schemas.py Outdated Show resolved Hide resolved
magpie/api/schemas.py Outdated Show resolved Hide resolved
magpie/api/management/user/user_utils.py Show resolved Hide resolved
<td>Terms and conditions:</td>
<td>
<label>
<input type="text" name="terms" value="${form_terms}" />
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hard to know with static analysis.
Is this field sufficiently large for convivial writing of long blocks of T&C text?
I think the field is by default not expandable and single line.

Might need to increase its size for this case + ensure text wrapping is used to help writing paragraphs instead of horizontally scrolling text box.
You can make a specific CSS class to apply needed styles to apply this behaviour if other similar cases arise.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea, I didn't think to test for long blocks of text, I will look into it!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am currently checking to make it better for multiline text. I use a textarea, that can be resized only vertically. By default, it displays 4 rows, but can be resized to display more, and can be scrolled through too. What do you think of the layout?

This is just a fast draft, but I think I should make the Terms and conditions and its associated (optional) label aligned with the top of the textarea.

Also, I should align the (optional) label of the description beside its input text box, and not aligned with the textarea of the T&C.

There is the Add Group button that should stay aligned as before, with the input text boxes of Group name and Description, or it will move depending of the horizontal size of the textarea. You can see it has a weird alignment on the current screenshot.

Also, what do you think of the horizontal size of the textarea? I didn't want to make the same size as the others, as it should contain more text and should be larger. I think I should leave the horizontal resizing enabled too, so the user can use the width he wants.

Let me know if my idea makes sense or if you have any better suggestion so I can work on a proper version of the ui!

image

Copy link
Contributor Author

@ChaamC ChaamC Sep 22, 2021

Choose a reason for hiding this comment

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

I've added a minimal width and height, to avoid weird formatting, and realigned the different elements.

Here is how it looks, by default, when opening the page :
image

Here is an example with the minimal size (the default width is a bit larger) :
image

Here is an example with the expanded textarea (the optional labels and the Add Group are still aligned in the right way):
image

Copy link
Collaborator

Choose a reason for hiding this comment

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

I use a textarea, that can be resized only vertically. By default, it displays 4 rows, but can be resized to display more, and can be scrolled through too. What do you think of the layout?

Excellent!

This is just a fast draft, but I think I should make the Terms and conditions and its associated (optional) label aligned with the top of the textarea.

I totally agree.

Also, I should align the (optional) label of the description beside its input text box, and not aligned with the textarea of the T&C.
Also, what do you think of the horizontal size of the textarea? I didn't want to make the same size as the others, as it should contain more text and should be larger. I think I should leave the horizontal resizing enabled too, so the user can use the width he wants.

The last screenshot looks perfect.
If (optional) works by automatically following resizes of T&C, let's keep that design.

magpie/ui/management/templates/edit_user.mako Show resolved Hide resolved
@ChaamC
Copy link
Contributor Author

ChaamC commented Oct 19, 2021

@dbyrns @fmigneault
PR updated according to latest feedback. Let me know if it is okay, or if the latest changes require further adjustments!

@ChaamC ChaamC requested a review from fmigneault October 19, 2021 14:52
dbyrns
dbyrns previously approved these changes Oct 19, 2021
Copy link
Collaborator

@fmigneault fmigneault left a comment

Choose a reason for hiding this comment

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

Only minor tweaks left. The overall features is valid.

(optional) should stick to the left (closer to its text field) in this case.

image

Comment on lines 93 to 98
user_info = uf.format_user(user)

# indicate if user has any pending T&C groups
group_names = uu.get_user_groups(user, UserGroupStatus.PENDING, request.db)
user_info["has_pending_group"] = bool(group_names)

Copy link
Collaborator

@fmigneault fmigneault Oct 20, 2021

Choose a reason for hiding this comment

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

Instead of adding has_pending_group here, move it within format_user to always make it available.
It should be within this block

if not basic_info:
grp_names = group_names if group_names else [grp.group_name for grp in user.groups]
user_info["group_names"] = list(sorted(grp_names))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alright, it's good idea, I will move it!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A thing that bugs me here, is that the code to get the pending_groups uses a db_session :
group_names = uu.get_user_groups(user, UserGroupStatus.PENDING, request.db).
But we don't have a db_session in the format_user method. Is there a way to obtain a db_session just for the format_user method, or should I maybe find a way to get pending users without using a session?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Mmhm, also getting a circular import error with from magpie.api.management.user.user_utils import get_user_groups :

magpie/api/webhooks.py:16: in <module>
    from magpie.api.management.user.user_formats import format_user
magpie/api/management/user/user_formats.py:7: in <module>
    from magpie.api.management.user.user_utils import get_user_groups
magpie/api/management/user/user_utils.py:30: in <module>
    from magpie.api.webhooks import (

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is why I proposed last time that this operation should be a method within User.
The User object will have an handle to the current db session and the method will be accessible from within format_user. It should behave similarly to the other available method user.groups.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To be clear, when you mention User, do you mean in this class?

Magpie/magpie/models.py

Lines 173 to 175 in a54c89f

class User(UserMixin, Base):
def __str__(self):
return "<User: name={} id={}>".format(self.user_name, self.id)

So, I would have to add a method has_pending_group with @declared_attr decorator, which could be accessed as user.has_pending_group in the format_user function?
Let me know if I understand properly.

But I checked briefly and am not sure where the session is accessible from there. I see that other attributes that use a session require a session as input parameter. Or do I have to use the get_db_session() method?

Also, including from magpie.api.management.user.user_utils import get_user_groups in that file also creates the circular import error.

tests/test_magpie_api.py:15: in <module>
    import tests.interfaces as ti
tests/interfaces.py:19: in <module>
    from magpie.api import schemas as s
magpie/api/schemas.py:29: in <module>
    from magpie.models import UserGroupStatus, UserStatuses
magpie/models.py:32: in <module>
    from magpie.api.management.user.user_utils import get_user_groups
magpie/api/management/user/__init__.py:2: in <module>
    from magpie.models import UserFactory

Anyway, I will look into it tomorrow, but let me know if I understood properly where you would see the location of the has_pending_group code, to be sure I am on the right track. We can figure out the rest after, or call each other tomorrow if needed.

Copy link
Collaborator

Choose a reason for hiding this comment

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

So, I would have to add a method has_pending_group with @declared_attr decorator, which could be accessed as user.has_pending_group in the format_user function?

Exactly.

For the session, you can use get_db_session(obj=self).

The get_user_groups could also be a method added to Users.
Something like groups_by_status to avoid conflict with groups attribute.
You could probably even improve user.has_pending_group by simply having it call this user.groups_by_status method with bool() on the result.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the feedback, it helps! I will try and implement it this way.

magpie/api/schemas.py Outdated Show resolved Hide resolved
@ChaamC
Copy link
Contributor Author

ChaamC commented Oct 20, 2021

@fmigneault

(optional) should stick to the left (closer to its text field) in this case.

Mmhm, I just tested the ui to be sure, and I don't get the same result. It seems to be working fine on my setup, using Google Chrome Version 90.0.4430.212 (Build officiel) (64 bits) and Firefox 78.8.0esr (64 bits). There are other things different in your screenshot : Terms and conditions label and related (optional) label are not aligned with the top of the T&C box, and the Add Group button is not aligned with the left of the T&C box.

Here is what I currently have on my setup :
image

Actually, your screenshot looks more similar to the ui result I would get before I added the html/css adjustments.
See the screenshot I had done a few weeks ago on the PR here :

image

Are sure you had the latest changes, or what setup did you use to test the ui? Is there something that could cause the ui to fail only on certain specific setups?

@fmigneault
Copy link
Collaborator

@ChaamC
I was on commit a54c89f but maybe some css caching was happening.
I retried with dev-toolbox/no-cache and it looks fine now.

@github-actions github-actions bot added the ci Something related to code tests, deployment and packaging label Oct 25, 2021
@ChaamC ChaamC requested a review from fmigneault October 25, 2021 18:59
magpie/models.py Outdated
@@ -174,6 +174,43 @@ class User(UserMixin, Base):
def __str__(self):
return "<User: name={} id={}>".format(self.user_name, self.id)

def get_user_groups_by_status(self, status, db_session=None):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Rename to only get_groups_by_status. Don't need to repeat "user" since it is contextual to it.

@@ -205,7 +205,7 @@ def update_user(user, request, new_user_name=None, new_password=None, new_email=
if update_email_admin_only and not (update_username or update_status):
err_msg = "User email update not permitted by non-administrators when email registration is enabled."
ax.verify_param(get_constant("MAGPIE_ADMIN_GROUP", request), is_in=True,
param_compare=get_user_groups_checked(request.user, request.db), with_param=False,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Revert this change.
All "<>_checked" operations imply more validations than just fetching relations between models.
They also imply raising HTTP errors which are irrelevant if raised in another context that within this kind of call. These checks should not be placed within the User model.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, I put the get_user_groups_checked function back to user_utils.py.
I had to import it directly into the get_groups_by_status function in models.py in order to avoid another circular import error.

magpie/ui/home/static/style.css Outdated Show resolved Hide resolved
@ChaamC ChaamC requested a review from fmigneault October 27, 2021 12:56
Copy link
Collaborator

@fmigneault fmigneault left a comment

Choose a reason for hiding this comment

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

@ChaamC
All good.
Thanks for your work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api Something related to the API operations ci Something related to code tests, deployment and packaging db Issues related to database connection, migration or data models doc Documentation improvements or building problem tests Test execution or additional use cases ui Something related to the UI operations or display
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants