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/ENG-6134 #10951

Conversation

ihorsokhanexoft
Copy link

Purpose

Contributors added to a registration should be able to edit title. Admins should be able to edit contributors on registration page

Changes

  1. Common perform_destroy for NodeContributorDetail and RegistrationContributorDetail views moved to a separate NodeContributorRemoveMixin
  2. Added has_permission method to ContributorDetailPermissions for RegistrationList so that contributors cannot do POST request (adding contributors)
  3. Title field of Registration is not read only right now and added in WRITABLE_WHITELIST of Registration
  4. Added tests

Notes:

  1. In RegistrationContributorsList.get_serializer_context I set default email = default assuming this is correct as we don't have a separate email template for registrations
  2. I inherited from CreateModelMixin and DestroyModelMixin for some classes because didn't want to update base class as it may impact on v1 version

Ticket

https://openscience.atlassian.net/jira/software/c/projects/ENG/boards/145?assignee=712020%3A7c7368dc-40cb-475f-bae8-b07a8bd2dd6c&selectedIssue=ENG-6134

@brianjgeiger brianjgeiger changed the base branch from develop to feature/b-and-i-25-01 January 30, 2025 15:03
Copy link
Contributor

@Johnetordoff Johnetordoff left a comment

Choose a reason for hiding this comment

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

Very good tests and diligent work, I have one suggestion about class inheritance, but otherwise good.

Also I see some unit test failures. Fix those before putting it back in review.

api/nodes/permissions.py Show resolved Hide resolved
@@ -361,6 +361,19 @@ def perform_destroy(self, instance):
raise PermissionDenied(str(err))


class NodeContributorRemoveMixin:
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't add this add a Mixin just over write for the classes you want individually.

def perform_destroy(self, instance):
node = self.get_resource()
auth = get_user_auth(self.request)
if len(node.visible_contributors) == 1 and instance.visible:
Copy link
Contributor

Choose a reason for hiding this comment

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

use node.visible_contributors.count()

Copy link
Author

Choose a reason for hiding this comment

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

yeah, just copied this block from another place ;)

Copy link
Contributor

Choose a reason for hiding this comment

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

It is okay to copy, I copy a lot, but only from good developers! :)

@@ -521,16 +534,6 @@ class NodeContributorDetail(BaseContributorDetail, generics.RetrieveUpdateDestro
def get_resource(self):
return self.get_node()

# overrides DestroyAPIView
def perform_destroy(self, instance):
Copy link
Contributor

Choose a reason for hiding this comment

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

As I said above don't bother using a mixin, it's okay to repeat yourself a little across views. It's just easier to see new behavior when you have a small number of methods for a view.

}
}
}
payload = {'data': {'attributes': attrs, 'relationships': relationships, 'type': 'contributors'}}
Copy link
Contributor

Choose a reason for hiding this comment

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

just a small thing but I would like everything to be indented like the relationships dictionary.

@@ -267,7 +268,7 @@ def get_serializer_context(self):
return context


class RegistrationContributorsList(BaseContributorList, RegistrationMixin, UserMixin):
class RegistrationContributorsList(BaseContributorList, mixins.CreateModelMixin, RegistrationMixin, UserMixin):
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a good use of mixin. this class looks correct.

Copy link
Collaborator

@brianjgeiger brianjgeiger left a comment

Choose a reason for hiding this comment

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

Just a couple of things from me, plus handle the failing tests please.

api/registrations/serializers.py Show resolved Hide resolved
creator=self.user, project=self.project)

self.public_project = ProjectFactory(is_public=True, creator=self.user)
self.public_registration_project = RegistrationFactory(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Minor: I would call this public_registration instead of public_registration_project

Copy link
Author

Choose a reason for hiding this comment

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

yeah, agree, just copied from another place

@ihorsokhanexoft
Copy link
Author

ihorsokhanexoft commented Jan 31, 2025

Fixed flake8 related errors and will fix others as you review it again because some of them don't fail locally. I assume most of the errors are related to the functionality that was prohibited (e.g. title was unchangable, impossible to update contributors of the registrations, etc) but now is allowed

@brianjgeiger
Copy link
Collaborator

@ihorsokhanexoft Looks like you still have a Flake8 problem, and at least one more failing test.

…ializer_context, fixed flake and tests where title is not writable
@ihorsokhanexoft
Copy link
Author

@brianjgeiger pushed the last fix. Review please and I'll check the result of tests

@brianjgeiger
Copy link
Collaborator

@ihorsokhanexoft Looks like we're getting about 75 failing tests with a 400 response rather than successful responses. Hopefully there's just a small change to fix all those.

@brianjgeiger
Copy link
Collaborator

If the failing tests are because we're requiring the Title field, then I may have been wrong about that and we can make it not required again.

@ihorsokhanexoft
Copy link
Author

If the failing tests are because we're requiring the Title field, then I may have been wrong about that and we can make it not required again.

@brianjgeiger Yeah, it's because this field is required now. Reverted this change

@ihorsokhanexoft
Copy link
Author

@brianjgeiger 1 test failed because it expected title shouldn't be updated. fixed it

Copy link
Collaborator

@brianjgeiger brianjgeiger left a comment

Choose a reason for hiding this comment

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

One more bit of functionalist that appears to be missing. Almost there.

url = f'/{API_BASE}registrations/{self.public_registration._id}/contributors/{contributor._id}/'
return self.app.delete_json_api(url, auth=auth_user.auth, expect_errors=expect_errors)

def update_attribute_request(self, auth_user, expect_errors=True, **attributes):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Sorry I missed this before. Admins should also be able to modify the contributors permissions and bibliographic status with this PR.

Copy link
Author

@ihorsokhanexoft ihorsokhanexoft Feb 4, 2025

Choose a reason for hiding this comment

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

I see, it means we need to add patch method to RegistrationContributorDetail view

@ihorsokhanexoft
Copy link
Author

ihorsokhanexoft commented Feb 4, 2025

@brianjgeiger @Johnetordoff I've found update method in the last commit in NodeContributorDetailSerializer that is used for draft registrations update, so I reused it

@brianjgeiger
Copy link
Collaborator

Looks like there's at least one problem that needs fixing from CI: api_tests/registrations/views/test_registration_list.py:2094:64: E712 comparison to True should be 'if cond is True:' or 'if cond:'

@ihorsokhanexoft
Copy link
Author

api_tests/registrations/views/test_registration_list.py:2094:64

Yeah, it's quite bad that I can't check the errors before your review. Fixed

Copy link
Collaborator

@brianjgeiger brianjgeiger left a comment

Choose a reason for hiding this comment

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

I think one last thing, to DRY up the update method.

Comment on lines 922 to 943
index = None
if '_order' in validated_data:
index = validated_data.pop('_order')

auth = Auth(self.context['request'].user)
node = self.context['resource']

if 'bibliographic' in validated_data:
bibliographic = validated_data.get('bibliographic')
else:
bibliographic = node.get_visible(instance.user)
permission = validated_data.get('permission') or instance.permission
try:
if index is not None:
node.move_contributor(instance.user, auth, index, save=True)
node.update_contributor(instance.user, permission, bibliographic, auth, save=True)
except node.state_error as e:
raise exceptions.ValidationError(detail=str(e))
except ValueError as e:
raise exceptions.ValidationError(detail=str(e))
instance.refresh_from_db()
return instance
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could you extract this into a helper function and call that function from both places it's used? It's significant enough functionality that it would be nice to have it DRY. Maybe put it in api/base/utils.py

Copy link
Author

Choose a reason for hiding this comment

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

Agree. Followed John's recommendations it's not always required to follow DRY and no need to create a separate mixin

@brianjgeiger
Copy link
Collaborator

Looks like you're missing some commas according to the pre-commit hook.

index f9fc0cc..bef17a7 100644
--- a/api/nodes/serializers.py
+++ b/api/nodes/serializers.py
@@ -18,7 +18,7 @@ from api.base.settings import ADDONS_FOLDER_CONFIGURABLE
 from api.base.utils import (
     absolute_reverse, get_object_or_error,
     get_user_auth, is_truthy,
-    update_contributors_permissions_and_bibliographic_status
+    update_contributors_permissions_and_bibliographic_status,
 )
 from api.base.versioning import get_kebab_snake_case_field
 from api.institutions.utils import update_institutions
@@ -1272,7 +1272,7 @@ class NodeContributorDetailSerializer(NodeContributorsSerializer):
         return update_contributors_permissions_and_bibliographic_status(
             self,
             instance,
-            validated_data
+            validated_data,
         )
 
 
diff --git a/api/registrations/serializers.py b/api/registrations/serializers.py
index 2f3ded4..0e35421 100644
--- a/api/registrations/serializers.py
+++ b/api/registrations/serializers.py
@@ -923,7 +923,7 @@ class RegistrationContributorsSerializer(NodeContributorsSerializer):
         return update_contributors_permissions_and_bibliographic_status(
             self,
             instance,
-            validated_data
+            validated_data,
         )
 

It might be worth automatically getting pre-commit hooks running for you locally.

@ihorsokhanexoft
Copy link
Author

ihorsokhanexoft commented Feb 5, 2025

It might be worth automatically getting pre-commit hooks running for you locally.

Yes, I have installed it, but it doesn't show any warnings, all checks are passed even if I run it manually

@brianjgeiger brianjgeiger merged commit d370e2b into CenterForOpenScience:feature/b-and-i-25-01 Feb 5, 2025
6 checks passed
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.

3 participants