From 5f24068b53c117adf000ed0ad2b4e1233c296694 Mon Sep 17 00:00:00 2001 From: Allen Lee Date: Wed, 29 May 2024 00:55:12 -0700 Subject: [PATCH] fix(WIP): remove affiliations and unneeded logic TODO: go through how `is_mutable` and related guards should work with @asuworks and @sgfost --- django/library/serializers.py | 99 ++++++------------- .../releaseEditor/ContributorEditForm.vue | 30 +++--- 2 files changed, 43 insertions(+), 86 deletions(-) diff --git a/django/library/serializers.py b/django/library/serializers.py index 86e139d25..bf865f25e 100644 --- a/django/library/serializers.py +++ b/django/library/serializers.py @@ -66,22 +66,19 @@ class ContributorSerializer(serializers.ModelSerializer): # Need an ID for Vue-Multiselect id = serializers.IntegerField(read_only=True) user = RelatedUserSerializer(required=False, allow_null=True) - affiliations = TagSerializer(many=True) - json_affiliations = models.JSONField( default=list, help_text=_("JSON-LD list of affiliated institutions") ) - mutable = serializers.SerializerMethodField(read_only=True) + mutable = serializers.SerializerMethodField(method_name="is_mutable") - profile_url = serializers.SerializerMethodField(read_only=True) + profile_url = serializers.SerializerMethodField() - def get_mutable(self, obj): + def is_mutable(self, obj): return self._is_exclusive_to_one_codebase(obj) def _trying_to_modify_attributes(self, instance, validated_data): try: for key in [ - "id", "user_id", "given_name", "middle_name", @@ -95,55 +92,26 @@ def _trying_to_modify_attributes(self, instance, validated_data): and getattr(instance, key) != validated_data[key] ): logger.debug( - f"{key} is not the same! {getattr(instance, key)} != {validated_data[key]}. Contributors can only be updated when they are exclusive to one codebase" + "[key %s] has different incoming value %s != %s - Contributors can only be updated when exclusive to one codebase", + key, + instance_dict[key], + validated_data[key], ) return True - logger.debug(f"not trying to update, all attributes match!") + logger.debug("no update detected, all attributes match") return False except Exception as e: - logger.error(f"Some Exception here {e}") + logger.exception(e) return True def _is_exclusive_to_one_codebase(self, obj): - distinct_codebases = ( - ReleaseContributor.objects.filter(contributor=obj) - .values_list("release__codebase", flat=True) - .distinct() + return ( + Codebase.objects.filter( + releases__codebase_contributors__contributor=obj + ).count() + <= 1 ) - times_used_in_codebases = distinct_codebases.count() - return times_used_in_codebases <= 1 - - def _is_not_used_or_used_by_current_release_only(self, contributor): - # codebase instead of release so we allow a submitter to update a contributor on their own codebase - release_id = self.context.get("release_id") - if not release_id: - return False - - distinct_codebases = ( - ReleaseContributor.objects.filter(contributor=contributor) - .values_list("release__codebase", flat=True) - .distinct() - ) - - times_used_in_codebases = distinct_codebases.count() - logger.debug(f"distinct_codebases={distinct_codebases}") - - if times_used_in_codebases == 0: - return True - elif times_used_in_codebases == 1: - if ( - ReleaseContributor.objects.filter(contributor=contributor) - .first() - .release_id - == release_id - ): - return True - else: - return False - else: - return False - def get_existing_contributor(self, validated_data): user = validated_data.get("user") username = user.get("username") if user else None @@ -152,10 +120,13 @@ def get_existing_contributor(self, validated_data): # attempt to find contributor by username, then email, then name without an email if username: user = User.objects.filter(username=username).first() - contributor = Contributor.objects.filter(user__username=username).first() + if user: + contributor = Contributor.objects.filter(user=user).first() elif email: + user = User.objects.filter(email=email).first() contributor = Contributor.objects.filter(email=email).first() - user = contributor.user if contributor else None + if not user: + user = contributor.user if contributor else None else: contrib_filter = { k: validated_data.get(k, "") @@ -188,22 +159,22 @@ def get_profile_url(self, instance): ) def update(self, instance, validated_data): - if not self._is_not_used_or_used_by_current_release_only(instance): - if self._trying_to_modify_attributes(instance, validated_data): - raise ValidationError( - _( - "Contributors can only be updated when they are exclusive to one codebase" - ) + if not self.is_mutable(instance) and self._trying_to_modify_attributes( + instance, validated_data + ): + raise ValidationError( + _( + "Contributors can only be updated when they are exclusive to one codebase" ) + ) # Server side validation: - # if a contributor is made from a user, do not allow to modify it's data. + # if a contributor proxies a User, do not allow modification of its data. # POP following: # 'given_name' # 'middle_name' # 'family_name' # 'email' # 'type' - # 'affiliations' # 'json_affiliations' user_id = validated_data.pop("user_id", None) if user_id: @@ -212,27 +183,15 @@ def update(self, instance, validated_data): validated_data.pop("family_name", None) validated_data.pop("email", None) validated_data.pop("type", None) - validated_data.pop("affiliations", None) validated_data.pop("json_affiliations", None) instance = super().update(instance, validated_data) - # affiliations = validated_data.pop("affiliations", None) - # - # if affiliations: # dont overwrite affiliations if not provided - # affiliations_serializer = TagSerializer( - # many=True, data=affiliations, context=self.context - # ) - # set_tags(instance, affiliations_serializer, "affiliations") instance.save() return instance def create(self, validated_data): - print(f"CREATE TRIGGERED with: {validated_data}") - affiliations_serializer = TagSerializer( - many=True, data=validated_data.pop("affiliations") - ) + logger.debug("CREATE with: %s", validated_data) instance = super().create(validated_data) - set_tags(instance, affiliations_serializer, "affiliations") instance.save() return instance @@ -247,9 +206,7 @@ class Meta: "email", "user", "type", - "affiliations", "json_affiliations", - "primary_affiliation_name", "primary_json_affiliation_name", "profile_url", "mutable", diff --git a/frontend/src/components/releaseEditor/ContributorEditForm.vue b/frontend/src/components/releaseEditor/ContributorEditForm.vue index 4a2117bd2..2e09a40ed 100644 --- a/frontend/src/components/releaseEditor/ContributorEditForm.vue +++ b/frontend/src/components/releaseEditor/ContributorEditForm.vue @@ -269,27 +269,27 @@ const hasName = computed(() => values.user || values.givenName); // used to disable UI inputs if prefilled from existing user or contributor is not mutable (some other release uses the contributor) const fromUser = computed(() => !!values.user || !values.mutable); -function populateFromReleaseContributor(contributor: ReleaseContributor) { - const user = contributor.contributor.user; +function populateFromReleaseContributor(releaseContributor: ReleaseContributor) { + const user = releaseContributor.contributor.user; - // Contributor has an associated user! Take values from the user. - const givenName = user ? user.memberProfile.givenName : contributor.contributor.givenName; - const familyName = user ? user.memberProfile.familyName : contributor.contributor.familyName; + // releaseContributor has an associated user! Take values from the user. + const givenName = user ? user.memberProfile.givenName : releaseContributor.contributor.givenName; + const familyName = user ? user.memberProfile.familyName : releaseContributor.contributor.familyName; setValues({ // set this to get the id from autocomplete contributor - // id: contributor.contributor.id, - user: contributor.contributor.user || null, - email: contributor.contributor.email, + // id: releaseContributor.contributor.id, + user: releaseContributor.contributor.user || null, + email: releaseContributor.contributor.email, givenName: givenName, familyName: familyName, - middleName: contributor.contributor.middleName, - affiliations: contributor.contributor.affiliations, - jsonAffiliations: contributor.contributor.jsonAffiliations, - mutable: contributor.contributor.mutable, - type: contributor.contributor.type, - roles: contributor.roles, - includeInCitation: contributor.includeInCitation, + middleName: releaseContributor.contributor.middleName, + affiliations: releaseContributor.contributor.affiliations, + jsonAffiliations: releaseContributor.contributor.jsonAffiliations, + mutable: releaseContributor.contributor.mutable, + type: releaseContributor.contributor.type, + roles: releaseContributor.roles, + includeInCitation: releaseContributor.includeInCitation, }); }