Skip to content

Analysis Framework: Implement graphql mutation node for Clone Analysis framework #1476

@susilnem

Description

@susilnem

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:

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:

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
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions