diff --git a/apps/assessment_registry/models.py b/apps/assessment_registry/models.py index 4f215c21fe..2f22180078 100644 --- a/apps/assessment_registry/models.py +++ b/apps/assessment_registry/models.py @@ -291,6 +291,7 @@ class DocumentType(models.IntegerChoices): ) external_link = models.URLField(max_length=500, blank=True) + class ScoreRating(UserResource): class ScoreType(models.IntegerChoices): RELEVANCE = 0, "Fit for purpose -> Relevance" diff --git a/apps/assessment_registry/schema.py b/apps/assessment_registry/schema.py index 60f9130119..053beaf02b 100644 --- a/apps/assessment_registry/schema.py +++ b/apps/assessment_registry/schema.py @@ -2,7 +2,7 @@ from graphene_django import DjangoObjectType from graphene_django_extras import DjangoObjectField -from utils.commons import render_string_for_graphql +from utils.common import render_string_for_graphql from utils.graphene.types import ClientIdMixin, CustomDjangoListObjectType from utils.graphene.fields import DjangoPaginatedListObjectField from utils.graphene.pagination import NoOrderingPageGraphqlPagination @@ -264,14 +264,13 @@ class Meta: class AdditionalDocumentType(DjangoObjectType, UserResourceMixin, ClientIdMixin): - external_link = graphene.String(required=False) - class Meta: model = AdditionalDocument fields = ("id", "file") document_type = graphene.Field(AssessmentRegistryDocumentTypeEnum, required=True) document_type_display = EnumDescription(source='get_document_type_display', required=True) + external_link = graphene.String(required=False) def resolve_external_link(root, info, **kwargs): return render_string_for_graphql(root.external_link) diff --git a/apps/gallery/mutations.py b/apps/gallery/mutations.py new file mode 100644 index 0000000000..385202f7cb --- /dev/null +++ b/apps/gallery/mutations.py @@ -0,0 +1,31 @@ +import graphene + +from utils.graphene.mutation import ( + generate_input_type_for_serializer, + PsGrapheneMutation, +) + +from .models import File +from .schema import GalleryFileType +from .serializers import ( + FileSerializer +) + +FileUploadInputType = generate_input_type_for_serializer( + 'FileUploadInputType', + serializer_class=FileSerializer +) + + +class UploadFile(PsGrapheneMutation): + class Arguments: + data = FileUploadInputType(required=True) + + result = graphene.Field(GalleryFileType) + serializer_class = FileSerializer + model = File + permissions = [] + + +class Mutation(): + file_upload = UploadFile.Field() diff --git a/apps/gallery/tests/test_mutations.py b/apps/gallery/tests/test_mutations.py new file mode 100644 index 0000000000..3a27e4a393 --- /dev/null +++ b/apps/gallery/tests/test_mutations.py @@ -0,0 +1,61 @@ +from utils.graphene.tests import GraphQLTestCase +import json + +from graphene_file_upload.django.testing import GraphQLFileUploadTestCase +from django.core.files.temp import NamedTemporaryFile + +from user.factories import UserFactory + + +class TestUploadFileMutation(GraphQLFileUploadTestCase, GraphQLTestCase): + UPLOAD_FILE = ''' + mutation MyMutation ($data: FileUploadInputType!) { + fileUpload(data: $data) { + ok + errors + result { + id + file { + name + url + } + } + } + } +''' + + def setUp(self): + super().setUp() + self.variables = { + "data": {"title": 'test', "file": None} + } + self.user = UserFactory.create() + self.force_login(self.user) + + def test_upload_preview_image(self): + file_text = b'preview image text' + with NamedTemporaryFile(suffix='.png') as t_file: + t_file.write(file_text) + t_file.seek(0) + response = self._client.post( + '/graphql', + data={ + 'operations': json.dumps({ + 'query': self.UPLOAD_FILE, + 'variables': self.variables + }), + 't_file': t_file, + 'map': json.dumps({ + 't_file': ['variables.data.file'] + }) + } + ) + content = response.json() + self.assertResponseNoErrors(response) + + self.assertTrue(content['data']['fileUpload']['ok'], content) + self.assertTrue(content['data']['fileUpload']['result']['file']["name"]) + file_name = content['data']['fileUpload']['result']['file']["name"] + file_url = content['data']['fileUpload']['result']['file']["url"] + self.assertTrue(file_name.endswith('.png')) + self.assertTrue(file_url.endswith(file_name)) diff --git a/apps/geo/dataloaders.py b/apps/geo/dataloaders.py index 94c54cad61..8b0b93d821 100644 --- a/apps/geo/dataloaders.py +++ b/apps/geo/dataloaders.py @@ -2,8 +2,10 @@ from promise import Promise from django.utils.functional import cached_property +from django.db.models import Prefetch from utils.graphene.dataloaders import DataLoaderWithContext, WithContextMixin +from geo.schema import get_geo_area_queryset_for_project_geo_area_type from .models import ( AdminLevel, @@ -23,7 +25,9 @@ def batch_load_fn(self, keys): class GeoAreaLoader(DataLoaderWithContext): def batch_load_fn(self, keys): ary_geo_area_qs = AssessmentRegistry.locations.through.objects\ - .filter(assessmentregistry__in=keys).prefetch_related('geoarea') + .filter(assessmentregistry__in=keys).prefetch_related( + Prefetch('geoarea', queryset=get_geo_area_queryset_for_project_geo_area_type()) + ) _map = defaultdict(list) for ary_geo_area in ary_geo_area_qs.all(): _map[ary_geo_area.assessmentregistry_id].append(ary_geo_area.geoarea) diff --git a/apps/geo/schema.py b/apps/geo/schema.py index 6261c482ee..29deb6562e 100644 --- a/apps/geo/schema.py +++ b/apps/geo/schema.py @@ -107,13 +107,6 @@ class Meta: region_title = graphene.String(required=True) admin_level_title = graphene.String(required=True) - @staticmethod - def resolve_region_title(root, info, **kwargs): - return root.admin_level.region.title - - def resolve_admin_level_title(root, info, **kwargs): - return root.admin_level.title - class ProjectGeoAreaListType(CustomDjangoListObjectType): class Meta: diff --git a/deep/schema.py b/deep/schema.py index fd90d5189f..94a15a1ed2 100644 --- a/deep/schema.py +++ b/deep/schema.py @@ -23,6 +23,7 @@ from unified_connector import schema as unified_connector_schema from export import schema as export_schema, mutation as export_mutation from deep_explore import schema as deep_explore_schema +from gallery import mutations as gallery_mutation from deep.enums import CustomEnum @@ -61,6 +62,7 @@ class Mutation( pj_mutation.Mutation, notification_mutation.Mutation, export_mutation.Mutation, + gallery_mutation.Mutation, # -- graphene.ObjectType ): diff --git a/schema.graphql b/schema.graphql index cb6ee56cb7..689c3ecf50 100644 --- a/schema.graphql +++ b/schema.graphql @@ -2039,6 +2039,15 @@ type FileFieldType { url: String } +input FileUploadInputType { + clientId: String + file: Upload! + title: String! + isPublic: Boolean + createdBy: ID + projects: [ID!] +} + type GalleryFileType { id: ID! title: String! @@ -2508,6 +2517,7 @@ type MissingPredictionReviewType { } type Mutation { + fileUpload(data: FileUploadInputType!): UploadFile genericExportCreate(data: GenericExportCreateInputType!): CreateUserGenericExport genericExportCancel(id: ID!): CancelUserGenericExport notificationStatusUpdate(data: NotificationStatusInputType!): NotificationStatusUpdate @@ -3661,6 +3671,12 @@ type UpdateUserGroup { scalar Upload +type UploadFile { + errors: [GenericScalar!] + ok: Boolean + result: GalleryFileType +} + type UserDelete { errors: [GenericScalar!] ok: Boolean