Newer
Older
import hashlib
from django.contrib.auth import get_user_model
from django.db import connection
from django.utils import timezone
from graphql.error import GraphQLError
from graphene_django.types import DjangoObjectType
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
# Protect graphql API page
class PrivateGraphQLView(TokenLoginMixin, GraphQLView):
pass
# Create a GraphQL type for the various models
class DataFileType(DjangoObjectType):
class Meta:
model = DataFile
fields = "__all__"
created_by_user = graphene.Boolean()
def resolve_created_by_user(self, info):
return self.uploaded_by == info.context.user.profile
class DataSetType(DjangoObjectType):
class Meta:
model = DataSet
fields = "__all__"
created_by_user = graphene.Boolean()
def resolve_created_by_user(self, info):
return self.created_by == info.context.user.profile
class ProfileType(DjangoObjectType):
class Meta:
model = Profile
fields = ['id', 'accountname', 'unix_username', 'user', 'labs']
class ProfileTokenType(DjangoObjectType):
class Meta:
model = ProfileToken
fields = ['id', 'user', 'api_token']
class UserType(DjangoObjectType):
class Meta:
model = get_user_model()
fields = ['id', 'username', 'first_name', 'last_name', 'email', 'is_staff']
class LabType(DjangoObjectType):
class Meta:
model = Lab
fields = ['id', 'name', 'pi', 'data_managers', 'institution']
class ShareGroupType(DjangoObjectType):
class Meta:
model = ShareGroup
fields = ['id', 'name', 'profiles']
# Create a Query type
class Query(graphene.ObjectType):
datafile = graphene.Field(DataFileType, id=graphene.String(), dbid=graphene.ID())
dataset = graphene.Field(DataSetType, id=graphene.String(), dbid=graphene.ID())
datafiles = graphene.List(
DataFileType,
key=graphene.String(),
value=graphene.String(),
key_values=graphene.JSONString(),
keys=graphene.List(graphene.String),
values=graphene.List(graphene.String),
dataset=graphene.String(),
file_hash=graphene.String(),
in_id_list=graphene.List(graphene.String)
datasets = graphene.List(DataSetType, in_id_list=graphene.List(graphene.String))
lab = graphene.Field(
LabType,
name=graphene.String(),
dbid=graphene.ID()
)
labs = graphene.List(
LabType,
LouisGendron
committed
in_name_list=graphene.List(graphene.String)
)
my_profile = graphene.Field(
ProfileType
)
profiles = graphene.List(
ProfileType,
LouisGendron
committed
in_email_list=graphene.List(graphene.String)
)
profiles_token = graphene.List(
ProfileTokenType,
in_email_list=graphene.List(graphene.String)
)
sharegroups = graphene.List(
ShareGroupType,
LouisGendron
committed
in_name_list=graphene.List(graphene.String)
)
def resolve_datafile(self, info, **kwargs):
id = kwargs.get('id')
dbid = kwargs.get('dbid')
qs = DataFile.objects.accessible_to_profile(info.context.user.profile)
return qs.filter(iric_data_id=id).first()
elif dbid is not None:
return qs.filter(pk=dbid).first()
def resolve_dataset(self, info, **kwargs):
id = kwargs.get('id')
dbid = kwargs.get('dbid')
qs = DataSet.objects.accessible_to_profile(info.context.user.profile)
if id is not None:
return qs.filter(iric_data_id=id).first()
return qs.filter(pk=dbid).first()
return None
def resolve_datafiles(self, info, **kwargs):
qs = DataFile.objects.accessible_to_profile(info.context.user.profile)
key_values = kwargs.get('key_values', None)
keys = kwargs.get('keys', None)
values = kwargs.get('values', None)
dataset = kwargs.get('dataset', None)
file_hash = kwargs.get('file_hash', None)
id_list = kwargs.get('in_id_list', None)
if key_values is not None:
for k, v in key_values.items():
qs = qs.filter(annotations__contains={k: v})
if keys is not None:
for k in keys:
qs = qs.filter(annotations__has_key=k)
if values is not None:
for v in values:
qs = qs.filter(annotations__values__icontains=v)
if dataset is not None:
qs = qs.filter(datasets__iric_data_id=dataset)
if file_hash is not None:
iric_data_file_hash = os.path.join(file_hash[:3], file_hash)
qs = qs.filter(file=iric_data_file_hash)
if id_list is not None:
qs = qs.filter(iric_data_id__in=id_list)
return qs.distinct()
def resolve_datasets(self, info, **kwargs):
LouisGendron
committed
id_list = kwargs.get('in_id_list')
qs = DataSet.objects.accessible_to_profile(info.context.user.profile)
LouisGendron
committed
if id_list is not None:
qs = qs.filter(iric_data_id__in=id_list)
return qs.distinct()
def resolve_lab(self, info, **kwargs):
name = kwargs.get('name')
dbid = kwargs.get('dbid')
if name is not None:
return Lab.objects.get(name=name)
elif dbid is not None:
return Lab.objects.get(pk=dbid)
def resolve_labs(self, info, **kwargs):
name_list = kwargs.get('in_name_list')
LouisGendron
committed
qs = Lab.objects.all()
if name_list is not None:
qs = qs.filter(name__in=name_list)
return qs.distinct()
def resolve_my_profile(self, info, **kwargs):
def resolve_profiles(self, info, **kwargs):
email_list = kwargs.get('in_email_list')
if email_list is not None:
return qs.filter(user__email__in=email_list)
return qs.distinct()
def resolve_profiles_token(self, info, **kwargs):
email_list = kwargs.get('in_email_list')
qs = ProfileToken.objects.none()
if info.context.user.is_staff:
qs = ProfileToken.objects.all()
if email_list:
qs = qs.filter(user__email__in=email_list)
return qs.distinct()
def resolve_sharegroups(self, info, **kwargs):
name_list = kwargs.get('in_name_list')
if name_list is not None:
qs = qs.filter(name__in=name_list)
return qs.distinct()
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"""
class Meta:
form_class = DataSetForm
return_field_name = 'dataset'
@classmethod
def get_form_kwargs(cls, root, info, **input) -> dict:
kwargs = super().get_form_kwargs(root, info, **input)
kwargs['request_profile'] = info.context.user.profile
LouisGendron
committed
if 'read_only' not in kwargs['data'] and 'instance' not in kwargs.keys():
kwargs['data']['read_only'] = True
return kwargs
@classmethod
def perform_mutate(cls, form, info):
object = form.save(commit=False)
if not object.pk:
object.created_by = info.context.user.profile
object.last_update_by = info.context.user.profile
object.save()
return super().perform_mutate(form, info)
class DataFileAttachMutation(graphene.Mutation):
attached_datafile = graphene.Field(DataFileType)
class Arguments:
# The input arguments for this mutation
file_hash = graphene.String(required=True)
filename = graphene.String(required=True)
target_user_email = graphene.String(required=True)
annotations = graphene.JSONString()
@classmethod
def mutate(cls, root, info, file_hash, filename, target_user_email, annotations=None):
# check that calling user is staff:
if not info.context.user.is_staff:
raise GraphQLError("You are not allowed to use this API function")
# transform file_hash
iric_data_file_hash = os.path.join(file_hash[:3], file_hash)
target_profile = Profile.objects.get(user__email=target_user_email)
if not DataFile.objects.filter(file=iric_data_file_hash).exists():
raise GraphQLError("No datafile associated with the provided hash")
with connection.cursor() as cursor:
cursor.execute(
"INSERT INTO portal_datafile(file, filename, uploaded_by_id, upload_timestamp, annotations) VALUES (%s, %s, %s, %s, %s)",
[
iric_data_file_hash,
filename,
target_profile.id,
timezone.now(),
]
)
df = DataFile.objects.latest('id')
df.iric_data_id = "DF{}".format(hashlib.md5(str(df.id).encode()).hexdigest()[:8]).upper()
df.save()
return DataFileAttachMutation(attached_datafile=df)
class Mutation(graphene.ObjectType):
dataset = DataSetMutation.Field()
attach_datafile_by_hash = DataFileAttachMutation.Field()
schema = graphene.Schema(query=Query, mutation=Mutation, auto_camelcase=False)