236 lines
6.8 KiB
Python

from polyphonic.interface.views import AuthorizedResourceMixin
from rest_framework import serializers
from rest_framework.exceptions import APIException
from rest_framework import generics
from rest_framework.views import APIView
from rest_framework.response import Response
from polyphonic.library.models import Collection, Work, Document, Section, WorkMeta
from polyphonic.library.gdrive import sync_collection, sync_work
import requests
import urllib
import shutil
import os.path
from django.db import transaction
from django.core.files.uploadedfile import TemporaryUploadedFile
"""
Views relating to importing and exporting collection items
"""
"""
from polyphonic.interface.views import EnsembleMixin
from polyphonic.library.views import WorkMixin
from django.views.generic import View
from django.http import JsonResponse
from djantic import ModelSchema
from polyphonic.library.models import Work, Document, Section
class DocumentSchema(ModelSchema):
class Config:
model = Document
class WorkSchema(ModelSchema):
docs: DocumentSchema
class Config:
model = Work
exclude = ['licence']
class WorkExportView(EnsembleMixin, WorkMixin, View):
def get(self, request, *args, **kwargs):
obj = self.get_queryset().get(pk=kwargs['pk'])
schema = WorkSchema.from_orm(obj)
return JsonResponse(schema.dict())
"""
class WorkMetaSerializer(serializers.ModelSerializer):
class Meta:
model = WorkMeta
exclude = ["id", "work"]
def to_representation(self, instance):
return f"{instance.name}:{instance.value}"
def to_internal_value(self, data):
name, _, value = data.partition(":")
return super().to_internal_value({"name": name, "value": value})
class SectionSerializer(serializers.ModelSerializer):
class Meta:
model = Section
exclude = ["id", "doc"]
def to_representation(self, instance):
start = instance.start or 0
end = instance.end or 0
return f"{instance.tag}:{start}:{end}"
def to_internal_value(self, data):
tag, start, end = data.split(":")
start = int(start)
end = int(end)
if start < 1:
start = None
if end < 1:
end = None
return super().to_internal_value({"tag": tag, "start": start, "end": end})
class DocumentSerializer(serializers.ModelSerializer):
upload = serializers.URLField()
sections = SectionSerializer(many=True)
# def to_internal_value(self, data):
# r = requests.get(data['upload'], stream=True)
# with tempfile.NamedTemporaryFile('wb') as f:
# shutil.copyfileobj(r.raw, f)
# data['upload'] = f.name
# print(repr(data))
# return super().to_internal_value(data)
def to_representation(self, instance):
data = super().to_representation(instance)
data["upload"] = instance.upload.url
return data
def create(self, validated_data):
print("CREATE", validated_data)
return super().create(validated_data)
def validate(self, data):
print("VALIDATE", data)
return super().validate(data)
def validate_upload(self, value):
print("VALIDATE", value)
return value
class Meta:
model = Document
exclude = ["id", "work", "version", "created"]
# Serializers define the API representation.
class WorkSerializer(serializers.ModelSerializer):
docs = DocumentSerializer(many=True)
meta_info = WorkMetaSerializer(many=True)
class Meta:
model = Work
exclude = ["id", "collection", "projects", "parent"]
def create(self, validated):
with transaction.atomic():
docs = validated.pop("docs", [])
meta = validated.pop("meta_info", [])
work = Work.objects.create(**validated)
for d in docs:
sections = d.pop("sections", [])
url = urllib.parse.urlparse(d["upload"])
filename = os.path.basename(url.path)
r = requests.get(d["upload"], stream=True)
if r.status_code != 200:
raise APIException("Failed to download file")
f = TemporaryUploadedFile(
filename,
r.headers["content-type"],
r.headers.get("content-length"),
r.encoding,
)
shutil.copyfileobj(r.raw, f.file)
r.close()
d["upload"] = f
doc = Document.objects.create(work_id=work.pk, **d)
for s in sections:
Section.objects.create(doc_id=doc.pk, **s)
for m in meta:
WorkMeta.objects.create(work_id=work.pk, **m)
return work
class CollectionSerializer(serializers.Serializer):
works = WorkSerializer(many=True)
def create(self, validated):
s = WorkSerializer()
print(validated)
collection = validated["collection_id"]
with transaction.atomic():
for work in validated["works"]:
work["collection_id"] = collection
s.create(work)
return Collection.objects.get(pk=collection)
class CollectionExportView(AuthorizedResourceMixin, generics.RetrieveAPIView):
serializer_class = CollectionSerializer
def get_queryset(self):
if self.request.user.is_superuser:
return Collection.objects.all()
return Collection.objects.filter(administrators=self.request.user)
class WorkExportView(AuthorizedResourceMixin, generics.RetrieveAPIView):
serializer_class = WorkSerializer
def get_queryset(self):
works = Work.objects.filter(collection=self.kwargs["collection"])
if self.request.user.is_superuser:
return works
return works.filter(collection__administrators=self.request.user)
class WorkImportView(AuthorizedResourceMixin, generics.CreateAPIView):
serializer_class = WorkSerializer
def perform_create(self, serializer):
serializer.save(collection_id=self.kwargs["collection"])
class CollectionImportView(AuthorizedResourceMixin, generics.CreateAPIView):
serializer_class = CollectionSerializer
def perform_create(self, serializer):
serializer.save(collection_id=self.kwargs["pk"])
class WorkSyncView(AuthorizedResourceMixin, APIView):
admin_required = True
def get(self, request, work, format=None):
obj = Work.objects.get(pk=work)
result = sync_work(obj)
return Response(result)
class CollectionSyncView(AuthorizedResourceMixin, APIView):
admin_required = True
def get(self, request, collection, format=None):
obj = Collection.objects.get(pk=collection)
result = sync_collection(obj)
return Response(result)