Skip to content
Snippets Groups Projects
Commit 6aee5d8f authored by LouisGendron's avatar LouisGendron
Browse files

Merge branch...

Merge branch '186-datafile-annotation-return-as-json-in-graphql-output-instead-of-jsonstring' into 'dev'

Resolve "Datafile annotation return as json in graphql output instead of jsonstring"

Closes #186

See merge request !108
parents cc1a810e 9fc3aca8
3 merge requests!111Populate /secure/my-sharegroups/ with the same groups that are available to a...,!109Populate /secure/my-sharegroups/ with the same groups that are available to a...,!108Resolve "Datafile annotation return as json in graphql output instead of jsonstring"
......@@ -183,10 +183,10 @@ SESSION_COOKIE_AGE = config('SESSION_COOKIE_AGE', default=86400, cast=int)
# django-auth-ldap ##############################
AUTH_LDAP_SERVER_URI = config('AUTH_LDAP_SERVER_URI')
AUTH_LDAP_USER_QUERY_FIELD = 'email'
AUTH_LDAP_BIND_DN = config('AUTH_LDAP_BIND_DN')
AUTH_LDAP_BIND_PASSWORD = config('AUTH_LDAP_BIND_PASSWORD')
AUTH_LDAP_BIND_DN = config('AUTH_LDAP_BIND_DN', default=None)
AUTH_LDAP_BIND_PASSWORD = config('AUTH_LDAP_BIND_PASSWORD', default=None)
AUTH_LDAP_BIND_AS_AUTHENTICATING_USER = config('AUTH_LDAP_BIND_AS_AUTHENTICATING_USER', cast=bool)
# AUTH_LDAP_USER_DN_TEMPLATE = "mail=%(user)s,ou=people,dc=sim,dc=umontreal,dc=ca" # config('AUTH_LDAP_USER_DN_TEMPLATE')
AUTH_LDAP_USER_DN_TEMPLATE = config('AUTH_LDAP_USER_DN_TEMPLATE')
AUTH_LDAP_USER_SEARCH = LDAPSearch(config('AUTH_LDAP_SEARCH'), ldap.SCOPE_SUBTREE, "(|(samaccountname=%(user)s)(mail=%(user)s))")
AUTH_LDAP_USER_ATTR_MAP = {
"first_name": "givenName",
......
......@@ -160,6 +160,14 @@ class InstitutionForm(forms.ModelForm):
fields = ('__all__')
class DataFileGraphQLForm(forms.ModelForm):
"""Only enables modification of annotations, iric_data_id is used as a lookup key
"""
class Meta:
model = DataFile
fields = ('iric_data_id', 'annotations')
class DataFileForm(forms.ModelForm):
class Meta:
model = DataFile
......@@ -229,7 +237,7 @@ class DataFileServletUploadForm(forms.ModelForm):
class DataFileAnnotationForm(forms.Form):
dropzone_files = forms.CharField(required=False, widget=forms.HiddenInput)
annotations = HStoreField(required=False, label=_('Attach these annotations with the uploaded files:'), help_text=_('Pro Tip: You can also drop a tab separated value file onto this field'),
widget=forms.Textarea(attrs={'placeholder':'{"key": "value"}'}))
widget=forms.Textarea(attrs={'placeholder': '{"key": "value"}'}))
lab = forms.ChoiceField(required=False, label=_('Attach uploaded files to this lab:'))
def __init__(self, request, *args, **kwargs):
......@@ -280,7 +288,7 @@ class DataSetForm(forms.ModelForm):
is_valid = super().is_valid()
if not is_valid:
return is_valid
elif self.instance.id and self.request_profile: # Apply only to DS update
elif self.instance.id and self.request_profile: # Apply only to DS update
is_valid = self.instance in DataSet.objects.writable_by_profile(self.request_profile)
return is_valid
......
......@@ -7,12 +7,13 @@ from django.db import connection
from django.utils import timezone
from graphql.error import GraphQLError
from graphene_django.types import DjangoObjectType
from graphene.types.json import JSONString
from graphene_django.views import GraphQLView
from graphene_django.forms.mutation import DjangoModelFormMutation
from portal.models import DataFile, DataSet, Lab, Profile, ProfileToken, ShareGroup
from portal.views import TokenLoginMixin
from portal.forms import DataSetForm
from portal.forms import DataSetForm, DataFileGraphQLForm
# Protect graphql API page
......@@ -20,6 +21,15 @@ class PrivateGraphQLView(TokenLoginMixin, GraphQLView):
pass
class IRICDataJSONString(JSONString):
"""
Overrides JSONString to avoid the stringification of the JSON object on serialize().
"""
@staticmethod
def serialize(dt):
return dt
# Create a GraphQL type for the various models
class DataFileType(DjangoObjectType):
class Meta:
......@@ -27,6 +37,7 @@ class DataFileType(DjangoObjectType):
fields = "__all__"
created_by_user = graphene.Boolean()
annotations = IRICDataJSONString()
def resolve_created_by_user(self, info):
return self.uploaded_by == info.context.user.profile
......@@ -175,7 +186,7 @@ class Query(graphene.ObjectType):
qs = DataSet.objects.accessible_to_profile(info.context.user.profile)
if id_list is not None:
qs = qs.filter(iric_data_id__in=id_list)
qs = qs.filter(iric_data_id__in=id_list)
return qs.distinct()
......@@ -229,6 +240,26 @@ class Query(graphene.ObjectType):
return qs.distinct()
class DataFileAnnotationMutation(DjangoModelFormMutation):
"""Enable the modification of a DataFile
Makes use of the DataFileForm, so all exposed fields from that form are available"""
class Meta:
form_class = DataFileGraphQLForm
model_operations = ['update']
return_field_name = 'datafile'
@classmethod
def get_form_kwargs(cls, root, info, **input) -> dict:
kwargs = super().get_form_kwargs(root, info, **input)
if 'instance' not in kwargs.keys():
iric_data_id = input.pop("iric_data_id", None)
instance = cls._meta.model._default_manager.get(iric_data_id=iric_data_id)
kwargs["instance"] = instance
return kwargs
class DataSetMutation(DjangoModelFormMutation):
"""Enable the creation or modification of a DataSet
Makes use of the DataSetForm, so all exposed fields from that form are available"""
......@@ -264,7 +295,7 @@ class DataFileAttachMutation(graphene.Mutation):
file_hash = graphene.String(required=True)
filename = graphene.String(required=True)
target_user_email = graphene.String(required=True)
annotations = graphene.JSONString()
annotations = IRICDataJSONString()
@classmethod
def mutate(cls, root, info, file_hash, filename, target_user_email, annotations=None):
......@@ -301,6 +332,7 @@ class DataFileAttachMutation(graphene.Mutation):
class Mutation(graphene.ObjectType):
datafile = DataFileAnnotationMutation.Field()
dataset = DataSetMutation.Field()
attach_datafile_by_hash = DataFileAttachMutation.Field()
......
This diff is collapsed.
# Generated by Django 2.2.17 on 2023-07-11 20:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('portal', '0032_auto_20230620_1628'),
]
operations = [
migrations.AlterField(
model_name='datafile',
name='iric_data_id',
field=models.CharField(max_length=10, null=True, unique=True, verbose_name='ID'),
),
migrations.AlterField(
model_name='dataset',
name='iric_data_id',
field=models.CharField(max_length=10, null=True, unique=True, verbose_name='ID'),
),
]
......@@ -183,7 +183,7 @@ class DataFile(models.Model):
filename = models.CharField(max_length=256, verbose_name=_('Filename'))
iric_data_id = models.CharField(max_length=10, verbose_name=_('ID'), null=True)
iric_data_id = models.CharField(max_length=10, verbose_name=_('ID'), null=True, unique=True)
uploaded_by = models.ForeignKey(Profile, on_delete=models.PROTECT, verbose_name=_('Uploaded by'), related_name='uploaded_files')
lab = models.ForeignKey(Lab, null=True, blank=True, on_delete=models.PROTECT, related_name='files', verbose_name=_('Belongs to this lab'), default=None)
......@@ -348,7 +348,7 @@ class DataSet(models.Model):
files = models.ManyToManyField(DataFile, related_name='datasets', verbose_name=_('Files'), blank=True)
read_only = models.BooleanField(default=True, verbose_name=_('Read only'), help_text=_('Prevent edits from users with which you share this DataSet'))
iric_data_id = models.CharField(max_length=10, verbose_name=_('ID'), null=True)
iric_data_id = models.CharField(max_length=10, verbose_name=_('ID'), null=True, unique=True)
objects = DataSetManager()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment