-
Notifications
You must be signed in to change notification settings - Fork 330
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
[ENG-2814] Allow Read-only and Read/Write contributors to view a project's draft registrations #10660
[ENG-2814] Allow Read-only and Read/Write contributors to view a project's draft registrations #10660
Conversation
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.
Sorry, there's some history to this ticket that isn't well documented (I did the dumb thing of just assuming that I'd own this whenever it came back up) >_<
data = res.json['data'] | ||
assert len(data) == 1 | ||
|
||
@pytest.mark.skip('Old OSF Groups code') |
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.
Feel free to just delete all of the tests for osf groups
api/draft_registrations/views.py
Outdated
@@ -50,7 +50,7 @@ def check_resource_permissions(self, resource): | |||
|
|||
class DraftRegistrationList(NodeDraftRegistrationsList): | |||
permission_classes = ( | |||
IsContributorOrAdminContributor, | |||
DraftRegistrationPermission, |
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 don't think the Permissions class actually does anything here. It only defines has_object_permission
, which is only invoked by default on detail views. That makes sense here, considering the endpoint specifically surfaces the active drafts for the requesting user.
if request.method in permissions.SAFE_METHODS: | ||
if isinstance(obj, DraftRegistration): | ||
node_permission = obj.branched_from.has_permission(auth.user, READ) | ||
return obj.has_permission(auth.user, READ) or node_permission | ||
elif request.method == 'POST': # Only Admin can create a draft registration | ||
if isinstance(obj, DraftRegistration): | ||
node_permission = obj.branched_from.has_permission(auth.user, ADMIN) | ||
return obj.has_permission(auth.user, ADMIN) or node_permission | ||
else: | ||
if isinstance(obj, DraftRegistration): | ||
node_permission = obj.branched_from.has_permission(auth.user, WRITE) | ||
return obj.has_permission(auth.user, WRITE) or node_permission |
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.
Making all permissions inheritable from the branched_from
node can lead to some confusing situations down the line -- notably, when a Draft is Registered and suddenly a user who thought they had a certain permission level doesn't have those permissions anymore, but there are probably also other edge cases just because there are lots of skeletons in the registration workflow.
There is a plan to some day kill off DraftRegistrationContributors
(which were only created due to a confusion in requirements when No Project Registratsions were implemented).
For now, let's constrain this PR to the specific issue identified in the ticket:
Users who view a Project's DraftRegistrations should see the Drafts on which they are contributors.
@@ -625,7 +625,7 @@ class NodeDraftRegistrationsList(JSONAPIBaseView, generics.ListCreateAPIView, No | |||
Use DraftRegistrationsList endpoint instead. | |||
""" | |||
permission_classes = ( | |||
IsAdminContributor, | |||
DraftRegistrationPermission, |
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 can't comment on the actually relevant line:
My instinct is that the get_queryset
should change to support the ticket requirements. Instead of listing all of the Drafts, this should list the Drafts on which the user is a contributor.
i.e., the queryset should return user.draft_registractions_active.filter(branched_from=node)
Existing behavior for the anonymous user would be to 401 -- which would redirect them to the login page -- but
We should probably get some additional clarification from Product about a couple of things:
First: Should users who are contributors on the Draft but not the branched_from
Project be able to see their Drafts on the list of the Project's Drafts (so long as the Project is public)?
Second: Should Project Admins be able to view all Drafts, even if they aren't contributors, or should that wait until the related ticket to give branched_from
Project Admins implicit read permissions on Drafts even when they aren't contributors?
Third: What should the behavior be for Unauthenticated users? Should we 401, implicitly redirecting them to the login page? Or should we just return the Empty queryset?
I'm happy to own this communication if you would like.
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 unaddressed. Let me know if you want a quick Zoom to clarify.
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 discussed the questions you raised with Mark.
- If a user is a contributor to a draft registration but not to the main project, they should still be able to see their drafts if the project is public.
- For now, we'll wait to implement a feature that gives project admins implicit read permissions on all related drafts.
- Users who are not logged in should be redirected to the login page if they try to view draft registrations. If they don't have an account, they should be sent to a create an account page.
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 sorting this out!
All of that being true, there's a bit of work left to do. Mostly, this endpoint (NodeDraftRegistrationList
) is currently returning the full list of DraftRegistrations to all Node contributors.
Two fixes to get the correct behavior:
First, you'll need to update this get_queryset
function to return something like user.active_draft_registrations.filter(branched_from=node)
.
Second, you'll need to update your Permission class to use can_view
instead of has_permission(READ)
so that non-contributors on the Project can still see their associated Drafts.
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 added some redundant-ish comments on tests to highlight where these requirements were being missed; we'll want/need to expand the test coverage, 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.
There are some unaddressed comments here regarding the queryset.
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.
Sorry, I had missed this comment. I have updated the PR.
@@ -659,9 +659,9 @@ class NodeDraftRegistrationDetail(JSONAPIBaseView, generics.RetrieveUpdateDestro | |||
Use DraftRegistrationDetail endpoint instead. | |||
""" | |||
permission_classes = ( | |||
DraftRegistrationPermission, |
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.
Given everything else I've said, I think the Detail views can go untouched for now.
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 still need to update the permission of the detail view?
…enforce correct permissions
…enforce correct permissions
…enforce correct permissions
api/draft_registrations/views.py
Outdated
return DraftRegistration.objects.filter( | ||
Q(_contributors=user) & | ||
Q(deleted__isnull=True) & | ||
(Q(registered_node__isnull=True) | Q(registered_node__deleted__isnull=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.
Why the explicit query instead of reusing the user.draft_registrations_active
?
@@ -625,7 +625,7 @@ class NodeDraftRegistrationsList(JSONAPIBaseView, generics.ListCreateAPIView, No | |||
Use DraftRegistrationsList endpoint instead. | |||
""" | |||
permission_classes = ( | |||
IsAdminContributor, | |||
DraftRegistrationPermission, |
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 unaddressed. Let me know if you want a quick Zoom to clarify.
def test_admin_can_view_draft_list( | ||
self, app, user, draft_registration, project_public, | ||
schema, url_draft_registrations): | ||
def test_draft_admin_can_view_draft_list( |
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
here is also a Project admin, as they are the creator
of project_public
.
group = OSFGroupFactory(creator=group_mem) | ||
project_public.add_osf_group(group, permissions.ADMIN) | ||
res = app.get(url_draft_registrations, auth=group_mem.auth, expect_errors=True) | ||
def test_node_admin_can_view_draft_list( |
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 test is confirming that a Project Admin can view the draft list even if they are not a contributor on the draft -- and, in fact, confirms that they can see the Draft in the list, even if they are not a contributor on the Draft, which was identified as work for a different ticket.
url_draft_registrations, | ||
auth=user_non_contrib.auth, | ||
expect_errors=True) | ||
def test_logged_in_non_contributor_cannot_view_draft_list(self, app, user_non_contrib, url_draft_registrations): |
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.
Non-contributor on the project who is a contributor on the Draft should still see the draft in the list. This shows that they will 403 instead (because we're checking has_permission(user, READ)
instead of can_view(user)
)
user_read_contrib, user_non_contrib, | ||
project_public, payload, group, | ||
url_draft_registrations, group_mem): | ||
def test_write_only_contributor_cannot_create_draft( |
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.
Thank you for breaking this into distinct tests!!
) | ||
|
||
@pytest.fixture() | ||
def metaschema_open_ended(self): |
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.
nit/honest question: why the separate schema?
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 think the separate metaschema_open_ended
fixture is there to ensure draft registrations are tested with the right schema for consistency.
@@ -625,7 +625,7 @@ class NodeDraftRegistrationsList(JSONAPIBaseView, generics.ListCreateAPIView, No | |||
Use DraftRegistrationsList endpoint instead. | |||
""" | |||
permission_classes = ( | |||
IsAdminContributor, | |||
DraftRegistrationPermission, |
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 sorting this out!
All of that being true, there's a bit of work left to do. Mostly, this endpoint (NodeDraftRegistrationList
) is currently returning the full list of DraftRegistrations to all Node contributors.
Two fixes to get the correct behavior:
First, you'll need to update this get_queryset
function to return something like user.active_draft_registrations.filter(branched_from=node)
.
Second, you'll need to update your Permission class to use can_view
instead of has_permission(READ)
so that non-contributors on the Project can still see their associated Drafts.
@@ -625,7 +625,7 @@ class NodeDraftRegistrationsList(JSONAPIBaseView, generics.ListCreateAPIView, No | |||
Use DraftRegistrationsList endpoint instead. | |||
""" | |||
permission_classes = ( | |||
IsAdminContributor, | |||
DraftRegistrationPermission, |
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 added some redundant-ish comments on tests to highlight where these requirements were being missed; we'll want/need to expand the test coverage, too)
drf_permissions.IsAuthenticatedOrReadOnly, | ||
base_permissions.TokenHasScope, | ||
DraftRegistrationPermission, |
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 still a noop, since DraftRegistrationPermission only defines has_object_permission
-- and this endpoint doesn't need any extra permissions, since it's just surfacing the current user's drafts (https://media1.tenor.com/m/j5TI9U8hISQAAAAC/emperors-new-groove-why.gif)
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.
Without it, a bunch of our tests are failing because it is letting unauthorized users create draft registrations.
The following tests failed when it was removed:
test_write_only_contributor_cannot_create_draft
test_read_only_contributor_cannot_create_draft
test_draft_registration_attributes_copied_from_node
test_logged_in_non_contributor_cannot_create_draft
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.
Some nitpicks and unaddressed comments from @jwalz . Also there seems to be some merge conflicts.
if request.method in permissions.SAFE_METHODS: | ||
if isinstance(obj, DraftRegistration): | ||
return obj.is_contributor(auth.user) or obj.has_permission(auth.user, READ) | ||
return obj.has_permission(auth.user, READ) |
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'd like this to be more specific. Maybe add an isinstance(obj, NodeModel)
here, since we are checking the permission of the node?
elif request.method == 'POST': # Only Admin can create a draft registration | ||
if isinstance(obj, DraftRegistration): | ||
return obj.is_contributor(auth.user) and obj.has_permission(auth.user, ADMIN) | ||
return obj.has_permission(auth.user, ADMIN) |
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
else: | ||
if isinstance(obj, DraftRegistration): | ||
return obj.is_contributor(auth.user) and obj.has_permission(auth.user, WRITE) | ||
return obj.has_permission(auth.user, WRITE) |
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.
@@ -625,7 +625,7 @@ class NodeDraftRegistrationsList(JSONAPIBaseView, generics.ListCreateAPIView, No | |||
Use DraftRegistrationsList endpoint instead. | |||
""" | |||
permission_classes = ( | |||
IsAdminContributor, | |||
DraftRegistrationPermission, |
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 are some unaddressed comments here regarding the queryset.
… refined querysets and permissions handling.
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.
LGTM. Just one small question.
@@ -659,9 +659,9 @@ class NodeDraftRegistrationDetail(JSONAPIBaseView, generics.RetrieveUpdateDestro | |||
Use DraftRegistrationDetail endpoint instead. | |||
""" | |||
permission_classes = ( | |||
DraftRegistrationPermission, |
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 still need to update the permission of the detail view?
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.
lgtm
0b6a3da
into
CenterForOpenScience:feature/b-and-i-24-14
…ect's draft registrations (CenterForOpenScience#10660) ## Purpose Change permissions for DraftRegistrations so Read/Write contributors can view all listed DraftRegistrations for a node. GET for reading, POST for DR creation and PATCH for editing ## Changes - Add new permissions class NodeDraftRegistrationsListPermission to NodeDraftRegistrationsList - Break up test runner into separate classes - Split apart large single test functions into individual cases - add more to testing matrix test_<user_permission>_draft_not_node has all cases CenterForOpenScience#10468 ## QA Notes ## Ticket https://openscience.atlassian.net/browse/ENG-2814
…penScience/osf.io into fix-source-tags * 'feature/b-and-i-24-14' of https://github.com/CenterForOpenScience/osf.io: refactor handle_duplicate_notifications and add tests Shorten lines; rename script for test clarity fix flake8 errors add admin screen to manage duplicate notifications [ENG-2814] Allow Read-only and Read/Write contributors to view a project's draft registrations (CenterForOpenScience#10660) [CR][ENG-5997] merge develop into b-and-i branch (CenterForOpenScience#10691) add exception handling in case state doesn't change [ENG-4527] Fix citation to use registered date (CenterForOpenScience#10678) restrict state changes more and allow no-ops split apart change provider views from general preprint view and machine_state change viewa Re-add permissions changes for files on withdrawn registrations (CenterForOpenScience#10671) [ENG-4903] Fixes issue with email confirmation links failing due to database congestion (CenterForOpenScience#10662) # Conflicts: # addons/boa/requirements.txt # addons/box/requirements.txt # addons/dataverse/requirements.txt # addons/dropbox/requirements.txt # addons/github/requirements.txt # addons/gitlab/requirements.txt # addons/mendeley/requirements.txt # addons/owncloud/requirements.txt # addons/s3/requirements.txt # addons/twofactor/requirements.txt # addons/wiki/requirements.txt # addons/zotero/requirements.txt # api/base/utils.py # api/users/serializers.py # api_tests/draft_registrations/views/test_draft_registration_list.py # api_tests/nodes/views/test_node_draft_registration_list.py # api_tests/users/views/test_user_draft_registration_list.py # api_tests/users/views/test_user_settings.py # docker-compose.yml # poetry.lock # pyproject.toml # requirements.txt # requirements/dev.txt # requirements/release.txt # tests/test_views.py # website/util/metrics.py
…penScience/osf.io into fix-source-tags * 'feature/b-and-i-24-14' of https://github.com/CenterForOpenScience/osf.io: refactor handle_duplicate_notifications and add tests Shorten lines; rename script for test clarity fix flake8 errors add admin screen to manage duplicate notifications [ENG-2814] Allow Read-only and Read/Write contributors to view a project's draft registrations (CenterForOpenScience#10660) [CR][ENG-5997] merge develop into b-and-i branch (CenterForOpenScience#10691) add exception handling in case state doesn't change [ENG-4527] Fix citation to use registered date (CenterForOpenScience#10678) restrict state changes more and allow no-ops split apart change provider views from general preprint view and machine_state change viewa Re-add permissions changes for files on withdrawn registrations (CenterForOpenScience#10671) [ENG-4903] Fixes issue with email confirmation links failing due to database congestion (CenterForOpenScience#10662) # Conflicts: # addons/boa/requirements.txt # addons/box/requirements.txt # addons/dataverse/requirements.txt # addons/dropbox/requirements.txt # addons/github/requirements.txt # addons/gitlab/requirements.txt # addons/mendeley/requirements.txt # addons/owncloud/requirements.txt # addons/s3/requirements.txt # addons/twofactor/requirements.txt # addons/wiki/requirements.txt # addons/zotero/requirements.txt # api/base/utils.py # api/users/serializers.py # api_tests/draft_registrations/views/test_draft_registration_list.py # api_tests/nodes/views/test_node_draft_registration_list.py # api_tests/users/views/test_user_draft_registration_list.py # api_tests/users/views/test_user_settings.py # docker-compose.yml # poetry.lock # pyproject.toml # requirements.txt # requirements/dev.txt # requirements/release.txt # tests/test_views.py # website/util/metrics.py
…penScience/osf.io into fix-source-tags * 'feature/b-and-i-24-14' of https://github.com/CenterForOpenScience/osf.io: refactor handle_duplicate_notifications and add tests Shorten lines; rename script for test clarity fix flake8 errors add admin screen to manage duplicate notifications [ENG-2814] Allow Read-only and Read/Write contributors to view a project's draft registrations (CenterForOpenScience#10660) [CR][ENG-5997] merge develop into b-and-i branch (CenterForOpenScience#10691) add exception handling in case state doesn't change [ENG-4527] Fix citation to use registered date (CenterForOpenScience#10678) restrict state changes more and allow no-ops split apart change provider views from general preprint view and machine_state change viewa Re-add permissions changes for files on withdrawn registrations (CenterForOpenScience#10671) [ENG-4903] Fixes issue with email confirmation links failing due to database congestion (CenterForOpenScience#10662) # Conflicts: # addons/boa/requirements.txt # addons/box/requirements.txt # addons/dataverse/requirements.txt # addons/dropbox/requirements.txt # addons/github/requirements.txt # addons/gitlab/requirements.txt # addons/mendeley/requirements.txt # addons/owncloud/requirements.txt # addons/s3/requirements.txt # addons/twofactor/requirements.txt # addons/wiki/requirements.txt # addons/zotero/requirements.txt # api/base/utils.py # api/users/serializers.py # api_tests/draft_registrations/views/test_draft_registration_list.py # api_tests/nodes/views/test_node_draft_registration_list.py # api_tests/users/views/test_user_draft_registration_list.py # api_tests/users/views/test_user_settings.py # docker-compose.yml # poetry.lock # pyproject.toml # requirements.txt # requirements/dev.txt # requirements/release.txt # tests/test_views.py # website/util/metrics.py
…penScience/osf.io into fix-preprint-emails * 'feature/b-and-i-24-14' of https://github.com/CenterForOpenScience/osf.io: Make resubmissions more like submissions (CenterForOpenScience#10709) renamed files with travis in their names fixed case where it was more appropriate removed all travis mentions and replaced them with CI [ENG-2562] add system tags to users created via institutional sign up system (CenterForOpenScience#10696) refactor handle_duplicate_notifications and add tests Shorten lines; rename script for test clarity fix flake8 errors add admin screen to manage duplicate notifications [ENG-2814] Allow Read-only and Read/Write contributors to view a project's draft registrations (CenterForOpenScience#10660) [CR][ENG-5997] merge develop into b-and-i branch (CenterForOpenScience#10691) add exception handling in case state doesn't change [ENG-4527] Fix citation to use registered date (CenterForOpenScience#10678) restrict state changes more and allow no-ops split apart change provider views from general preprint view and machine_state change viewa Re-add permissions changes for files on withdrawn registrations (CenterForOpenScience#10671) [ENG-4903] Fixes issue with email confirmation links failing due to database congestion (CenterForOpenScience#10662) # Conflicts: # osf/utils/notifications.py # website/templates/emails/reviews_resubmission_confirmation.html.mako
…penScience/osf.io into fix-preprint-emails * 'feature/b-and-i-24-14' of https://github.com/CenterForOpenScience/osf.io: Make resubmissions more like submissions (CenterForOpenScience#10709) renamed files with travis in their names fixed case where it was more appropriate removed all travis mentions and replaced them with CI [ENG-2562] add system tags to users created via institutional sign up system (CenterForOpenScience#10696) refactor handle_duplicate_notifications and add tests Shorten lines; rename script for test clarity fix flake8 errors add admin screen to manage duplicate notifications [ENG-2814] Allow Read-only and Read/Write contributors to view a project's draft registrations (CenterForOpenScience#10660) [CR][ENG-5997] merge develop into b-and-i branch (CenterForOpenScience#10691) add exception handling in case state doesn't change [ENG-4527] Fix citation to use registered date (CenterForOpenScience#10678) restrict state changes more and allow no-ops split apart change provider views from general preprint view and machine_state change viewa Re-add permissions changes for files on withdrawn registrations (CenterForOpenScience#10671) [ENG-4903] Fixes issue with email confirmation links failing due to database congestion (CenterForOpenScience#10662) # Conflicts: # osf/utils/notifications.py # website/templates/emails/reviews_resubmission_confirmation.html.mako
…ect's draft registrations (CenterForOpenScience#10660) ## Purpose Change permissions for DraftRegistrations so Read/Write contributors can view all listed DraftRegistrations for a node. GET for reading, POST for DR creation and PATCH for editing ## Changes - Add new permissions class NodeDraftRegistrationsListPermission to NodeDraftRegistrationsList - Break up test runner into separate classes - Split apart large single test functions into individual cases - add more to testing matrix test_<user_permission>_draft_not_node has all cases CenterForOpenScience#10468 ## QA Notes ## Ticket https://openscience.atlassian.net/browse/ENG-2814
Purpose
Change permissions for DraftRegistrations so Read/Write contributors can view all listed DraftRegistrations for a node.
GET for reading, POST for DR creation and PATCH for editing
Changes
#10468
QA Notes
Ticket
<(https://openscience.atlassian.net/browse/ENG-2814)>