Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions apps/analysis/mutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
AnalysisType,
)
from .serializers import (
AnalysisCloneGqlSerializer,
AnalysisPillarGqlSerializer,
DiscardedEntryGqlSerializer,
AnalysisTopicModelSerializer,
Expand Down Expand Up @@ -113,6 +114,11 @@
serializer_class=AnalysisGqlSerializer,
)

AnalysisCloneInputType = generate_input_type_for_serializer(
'AnalysisCloneInputType',
serializer_class=AnalysisCloneGqlSerializer
)


class RequiredPermissionMixin():
permissions = [
Expand Down Expand Up @@ -314,6 +320,14 @@ class Arguments:
result = graphene.Field(AnalysisPillarType)


class AnalysisClone(AnalysisMutationMixin, PsGrapheneMutation):
class Arguments:
data = AnalysisCloneInputType(required=True)
model = Analysis
serializer_class = AnalysisCloneGqlSerializer
result = graphene.Field(AnalysisType)


class Mutation():
# Analysis Pillar
analysis_pillar_update = UpdateAnalysisPillar.Field()
Expand All @@ -339,3 +353,6 @@ class Mutation():
analysis_create = CreateAnalysis.Field()
analysis_update = UpdateAnalysis.Field()
analysis_delete = DeleteAnalysis.Field()

# AnalysisClone
analysis_clone = AnalysisClone.Field()
32 changes: 31 additions & 1 deletion apps/analysis/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,37 @@ def update(self, instance, validated_data):
return super().update(instance, validated_data)


AnalysisCloneGqlSerializer = AnalysisCloneInputSerializer
class AnalysisCloneGqlSerializer(serializers.Serializer):
analysis_id = IntegerIDField()
title = serializers.CharField(required=True, write_only=True)
start_date = serializers.DateField(write_only=True, required=False, allow_null=True)
end_date = serializers.DateField(required=True, write_only=True)

def validate(self, data):
start_date = data.get('start_date')
end_date = data.get('end_date')
if start_date and start_date > end_date:
raise serializers.ValidationError(
{'end_date': 'End date must occur after start date'}
)
return data

def validate_analysis_id(self, analysis_id):
analysis = Analysis.objects.filter(
project=self.context['request'].active_project,
pk=analysis_id
).first()
if analysis is None:
raise serializers.ValidationError("Analysis does not exists")
return analysis

def create(self, validated_data):
title = validated_data['title']
end_date = validated_data['end_date']
# NOTE validated_data['analysis_id'] is an object of analysis
analysis = validated_data['analysis_id']
analysis.clone_analysis(title, end_date)
return analysis


class AnalysisTopicModelSerializer(UserResourceSerializer, serializers.ModelSerializer):
Expand Down
84 changes: 84 additions & 0 deletions apps/analysis/tests/test_mutations.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@
AnalysisPillarFactory,
AnalysisReportFactory,
AnalysisReportUploadFactory,
AnalyticalStatementFactory,
DiscardedEntryFactory,
)

from analysis.models import (
DiscardedEntry,
TopicModel,
TopicModelCluster,
AutomaticSummary,
Expand Down Expand Up @@ -1732,3 +1735,84 @@ def _query_check(**kwargs):
self.assertEqual(analysis_pillar_resp_data['title'], self.update_minput['analysisPillarUpdate']['title'])
self.assertEqual(analysis_pillar_resp_data['id'], str(self.update_minput['analysisPillarID']))
self.assertEqual(analysis_pillar_resp_data['analysisId'], str(self.analysis.id))


class TestCloneAnalysisMutationSchema(GraphQLTestCase):
ANALYSIS_CLONE_MUTATION = '''
mutation AnalysisClone($projectId: ID!, $data: AnalysisCloneInputType!) {
project(id: $projectId) {
analysisClone(data: $data) {
ok
errors
result {
id
title
endDate
}
__typename
}
__typename
}
}
'''

def setUp(self):
super().setUp()
self.project = ProjectFactory.create()
self.member_user = UserFactory.create()
self.non_member_user = UserFactory.create()
self.readonly_member_user = UserFactory.create()
self.project.add_member(self.readonly_member_user, role=self.project_role_reader_non_confidential)
af = AnalysisFrameworkFactory.create()
project = ProjectFactory.create(analysis_framework=af)
lead = LeadFactory.create(project=project)
self.project.add_member(self.member_user, role=self.project_role_member)
entry = EntryFactory.create(project=project, lead=lead)
EntryFactory.create(project=project, lead=lead)
self.analysis = AnalysisFactory.create(
project=project,
team_lead=self.member_user,
end_date=datetime.date(2022, 4, 1),

)
pillar = AnalysisPillarFactory.create(analysis=self.analysis, title='title1', assignee=self.member_user)
AnalyticalStatementFactory.create(
analysis_pillar=pillar,
statement='Hello from here',
client_id='1',
)
DiscardedEntryFactory.create(
entry=entry,
analysis_pillar=pillar,
tag=DiscardedEntry.TagType.REDUNDANT
)

def test_clone_analysis(self):
def _query_check(**kwargs):
return self.query_check(
self.ANALYSIS_CLONE_MUTATION,
variables=self.minput,
**kwargs
)
self.minput = dict(
data=dict(
analysisId=self.analysis.id,
title='cloned_title',
endDate="2022-04-01",
),
projectId=self.project.id,
)
# without login
_query_check(assert_for_error=True)

# With login (non-member)
self.force_login(self.non_member_user)
_query_check(assert_for_error=True)

# member user (read-only)
self.force_login(self.readonly_member_user)
_query_check(assert_for_error=True)

# member user
self.force_login(self.member_user)
_query_check(assert_for_error=False)
14 changes: 14 additions & 0 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,19 @@ type AnalysisAutomaticSummaryType {
status: AutomaticSummaryStatusEnum!
}

type AnalysisClone {
errors: [GenericScalar!]
ok: Boolean
result: AnalysisType
}

input AnalysisCloneInputType {
analysisId: ID!
title: String!
startDate: Date
endDate: Date!
}

input AnalysisFrameworkCloneInputType {
afId: ID!
title: String!
Expand Down Expand Up @@ -5521,6 +5534,7 @@ type ProjectMutationType {
analysisCreate(data: AnalysisInputType!): CreateAnalysis
analysisUpdate(data: AnalysisInputType!, id: ID!): UpdateAnalysis
analysisDelete(id: ID!): DeleteAnalysis
analysisClone(data: AnalysisCloneInputType!): AnalysisClone
exportCreate(data: ExportCreateInputType!): CreateUserExport
exportUpdate(data: ExportUpdateInputType!, id: ID!): UpdateUserExport
exportCancel(id: ID!): CancelUserExport
Expand Down
Loading