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

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

Open
Tracked by #997
susilnem opened this issue Apr 9, 2024 · 0 comments
Open
Tracked by #997
Assignees
Milestone

Comments

@susilnem
Copy link
Member

susilnem commented Apr 9, 2024

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
}
@susilnem susilnem added this to the April 2024 milestone Apr 9, 2024
@susilnem susilnem self-assigned this Apr 9, 2024
@sudan45 sudan45 changed the title Implement graphql mutation node for Clone Analysis framework Analysis Framework: Implement graphql mutation node for Clone Analysis framework Apr 9, 2024
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

No branches or pull requests

1 participant