-
Notifications
You must be signed in to change notification settings - Fork 5
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
Feature add tc #467
Conversation
…n case of confirmation
… a logged non-admin user
…d keeping irrelevant tokens
… pending users, to allow sending additional email requests
…ages + fix test for 'pending' display on ui
Codecov Report
@@ 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
Continue to review full report at Codecov.
|
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.
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 |
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.
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.
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.
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.
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. 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.
<td>Terms and conditions:</td> | ||
<td> | ||
<label> | ||
<input type="text" name="terms" value="${form_terms}" /> |
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.
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.
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.
Good idea, I didn't think to test for long blocks of text, I will look into it!
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 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!
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'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 :
Here is an example with the minimal size (the default width is a bit larger) :
Here is an example with the expanded textarea (the optional
labels and the Add Group
are still aligned in the right way):
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 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.
…ing T&C, but not as pending
@dbyrns @fmigneault |
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.
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) | ||
|
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.
Instead of adding has_pending_group
here, move it within format_user
to always make it available.
It should be within this block
Magpie/magpie/api/management/user/user_formats.py
Lines 42 to 44 in a54c89f
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)) |
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.
Alright, it's good idea, I will move it!
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.
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?
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.
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 (
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.
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
.
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.
To be clear, when you mention User
, do you mean in this class?
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.
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.
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.
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.
Thanks for the feedback, it helps! I will try and implement it this way.
magpie/alembic/versions/2021-06-09_cb92ff1f81bb_add_group_terms.py
Outdated
Show resolved
Hide resolved
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): |
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.
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, |
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.
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.
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.
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.
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.
@ChaamC
All good.
Thanks for your work.
Features / Changes
Terms and conditions
field forgroup
creation. When a request is made to assign auser
to agroup
with terms and conditions, an email is now sent to theuser
with the terms and conditions. Theuser
is assigned to the
group
when receiving theuser
's approval of terms and conditions, and another email isthen sent to notify the
user
of the successful operation./groups/{group_name}/users
,/users/current/groups
and/users/{user_name}/groups
endpoints witha new parameter to either get active, pending or all
users
orgroups
. This new parameter is useful todisplay any pending
users
/groups
on the UI.Bug Fixes
Internal Server Error [500]
on the page to edit a group when deleting the lastuser
of agroup
.Other references