-
Notifications
You must be signed in to change notification settings - Fork 5
Open
Milestone
Description
Problem Statement
The 'Clone analysis framework' features uses a Rest API.
Acceptance Criteria
The 'Clone analysis framework ' feature works with a graphql mutation.
Existing
ApiView:
server/apps/analysis_framework/views.py
Lines 88 to 135 in bbfdef2
| class AnalysisFrameworkCloneView(views.APIView): | |
| permission_classes = [permissions.IsAuthenticated] | |
| def post(self, request, af_id, version=None): | |
| if not AnalysisFramework.objects.filter( | |
| id=af_id | |
| ).exists(): | |
| raise exceptions.NotFound() | |
| analysis_framework = AnalysisFramework.objects.get( | |
| id=af_id | |
| ) | |
| if not analysis_framework.can_clone(request.user): | |
| raise exceptions.PermissionDenied() | |
| cloned_title = request.data.get('title') | |
| if not cloned_title: | |
| raise exceptions.ValidationError({ | |
| 'title': 'Title should be present', | |
| }) | |
| new_af = analysis_framework.clone( | |
| request.user, | |
| request.data or {}, | |
| ) | |
| # Set the requesting user as owner member, don't create other memberships of old framework | |
| new_af.add_member(request.user, new_af.get_or_create_owner_role()) | |
| serializer = AnalysisFrameworkSerializer( | |
| new_af, | |
| context={'request': request}, | |
| ) | |
| project = request.data.get('project') | |
| if project: | |
| project = Project.objects.get(id=project) | |
| if not project.can_modify(request.user): | |
| raise exceptions.ValidationError({ | |
| 'project': 'Invalid project', | |
| }) | |
| project.analysis_framework = new_af | |
| project.modified_by = request.user | |
| project.save() | |
| return response.Response( | |
| serializer.data, | |
| status=status.HTTP_201_CREATED, | |
| ) |
Used Serializer:
server/apps/analysis_framework/serializers.py
Lines 173 to 300 in bbfdef2
| class AnalysisFrameworkSerializer(RemoveNullFieldsMixin, | |
| DynamicFieldsMixin, | |
| UserResourceSerializer): | |
| """ | |
| Analysis Framework Model Serializer | |
| """ | |
| widgets = SimpleWidgetSerializer(source='widget_set', many=True, required=False) | |
| filters = SimpleFilterSerializer(source='get_active_filters', many=True, read_only=True) | |
| exportables = SimpleExportableSerializer(source='exportable_set', many=True, read_only=True) | |
| questions = FrameworkQuestionSerializer(source='frameworkquestion_set', many=True, required=False, read_only=True) | |
| entries_count = serializers.IntegerField( | |
| source='get_entries_count', | |
| read_only=True, | |
| ) | |
| is_admin = serializers.SerializerMethodField() | |
| users_with_add_permission = serializers.SerializerMethodField() | |
| visible_projects = serializers.SerializerMethodField() | |
| all_projects_count = serializers.IntegerField(source='project_set.count', read_only=True) | |
| project = serializers.IntegerField( | |
| write_only=True, | |
| required=False, | |
| ) | |
| role = serializers.SerializerMethodField() | |
| organization_details = SimpleOrganizationSerializer(source='organization', read_only=True) | |
| class Meta: | |
| model = AnalysisFramework | |
| fields = ('__all__') | |
| def get_visible_projects(self, obj): | |
| from project.serializers import SimpleProjectSerializer | |
| user = None | |
| if 'request' in self.context: | |
| user = self.context['request'].user | |
| projects = obj.project_set.exclude(models.Q(is_private=True) & ~models.Q(members=user)) | |
| return SimpleProjectSerializer(projects, context=self.context, many=True, read_only=True).data | |
| def get_users_with_add_permission(self, obj): | |
| """ | |
| AF members with access to add other users to AF | |
| """ | |
| return SimpleUserSerializer( | |
| User.objects.filter( | |
| id__in=obj.analysisframeworkmembership_set.filter(role__can_add_user=True).values('member'), | |
| ).all(), | |
| context=self.context, | |
| many=True, | |
| ).data | |
| def get_role(self, obj): | |
| user = self.context['request'].user | |
| membership = AnalysisFrameworkMembership.objects.filter( | |
| framework=obj, | |
| member=user | |
| ).first() | |
| role = None | |
| if not membership and not obj.is_private: | |
| role = obj.get_or_create_default_role() | |
| elif membership: | |
| role = membership.role | |
| else: | |
| return {} | |
| return AnalysisFrameworkRoleSerializer(role, context=self.context).data | |
| def validate_project(self, project): | |
| try: | |
| project = Project.objects.get(id=project) | |
| except Project.DoesNotExist: | |
| raise serializers.ValidationError( | |
| 'Project matching query does not exist' | |
| ) | |
| if not project.can_modify(self.context['request'].user): | |
| raise serializers.ValidationError('Invalid project') | |
| return project.id | |
| def create(self, validated_data): | |
| project = validated_data.pop('project', None) | |
| private = validated_data.get('is_private', False) | |
| # Check if user has access to private project feature | |
| user = self.context['request'].user | |
| private_access = user.profile.get_accessible_features().filter( | |
| key=Feature.FeatureKey.PRIVATE_PROJECT | |
| ).exists() | |
| if private and not private_access: | |
| raise exceptions.PermissionDenied({ | |
| "message": "You don't have permission to create private framework" | |
| }) | |
| af = super().create(validated_data) | |
| if project: | |
| project = Project.objects.get(id=project) | |
| project.analysis_framework = af | |
| project.modified_by = user | |
| project.save() | |
| owner_role = af.get_or_create_owner_role() | |
| af.add_member(self.context['request'].user, owner_role) | |
| return af | |
| def update(self, instance, validated_data): | |
| if 'is_private' not in validated_data: | |
| return super().update(instance, validated_data) | |
| if instance.is_private != validated_data['is_private']: | |
| raise exceptions.PermissionDenied({ | |
| "message": "You don't have permission to change framework's privacy" | |
| }) | |
| return super().update(instance, validated_data) | |
| def get_is_admin(self, analysis_framework): | |
| return analysis_framework.can_modify(self.context['request'].user) | |
| # ------------------ Graphql seriazliers ----------------------------------- | |
| def validate_items_limit(items, limit, error_message='Only %d items are allowed. Provided: %d'): | |
| if items: | |
| count = len(items) | |
| if count > limit: | |
| raise serializers.ValidationError(error_message % (limit, count)) |
Additional Information
Rest Framework urls
method: POST
url: /api/v1/clone-analysis-framework/3/
request payload:{"title":"New framework test (cloned)2","description":"New framework testing"}
response: {
"id" :int,
"title": str,
"description":str,
}
Purposed
type CloneAnalysisFramework {
errors: [GenericScalar!]
ok: Boolean
result: AnalysisFrameworkDetailType
}
input AnalysisFrameworkCloneInputType {
title: String!
description: String
project: Int
}
Metadata
Metadata
Assignees
Labels
No labels