Files
classquiz-ai/classquiz/routers/eximport.py
T
2022-12-10 12:39:32 +01:00

101 lines
3.8 KiB
Python

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
import json
import uuid
from datetime import datetime
import ormar.exceptions
from aiohttp import ClientSession
from fastapi import APIRouter, Depends, File, UploadFile, HTTPException
from fastapi.responses import StreamingResponse
from classquiz.auth import get_current_user
from classquiz.config import storage, settings
from classquiz.db.models import Quiz, User
import gzip
import urllib.parse
router = APIRouter()
settings = settings()
quiz_delimiter = b"\xc7\xc7\xc7\x00"
image_delimiter = b"\xc6\xc6\xc6\x00"
image_index_delimiter = b"\xc5\xc5\x00"
@router.get("/{quiz_id}")
async def export_quiz(quiz_id: uuid.UUID, user: User = Depends(get_current_user)):
try:
quiz: Quiz = await Quiz.objects.filter(Quiz.id == quiz_id).first()
except ormar.exceptions.NoMatch:
raise HTTPException(status_code=404, detail="Quiz not found")
image_urls = {}
for i, question in enumerate(quiz.questions):
if question["image"] is None:
continue
else:
image_urls[i] = question["image"]
question["image"] = i
if quiz.cover_image is not None:
image_urls[-1] = quiz.cover_image
quiz.cover_image = -1
quiz_dict = quiz.dict()
del quiz_dict["user_id"], quiz_dict["id"]
quiz_dict["created_at"] = quiz_dict["created_at"].isoformat()
quiz_dict["updated_at"] = quiz_dict["updated_at"].isoformat()
quiz_json = json.dumps(quiz_dict)
bin_data = gzip.compress(quiz_json.encode("utf-8"), compresslevel=9)
# bin_data = quiz_json.encode("utf-8")
bin_data = bin_data + quiz_delimiter
for image_key in image_urls.keys():
bin_data = bin_data + image_delimiter + str(image_key).encode("utf-8") + image_index_delimiter
image_data = None
async with ClientSession() as session, session.get(image_urls[image_key]) as resp:
image_data = await resp.read()
bin_data = bin_data + image_data
def stream_response():
yield bin_data
return StreamingResponse(
stream_response(),
media_type="application/octet-stream",
headers={
"Content-Disposition": f"attachment;filename={urllib.parse.quote(quiz.title)}.cqa"
# noqa: E501
},
)
@router.post("/")
async def import_quiz(file: UploadFile = File(), user: User = Depends(get_current_user)):
data = await file.read()
[split_data, images] = data.split(quiz_delimiter)
decompressed_quiz = gzip.decompress(split_data)
quiz_dict = json.loads(decompressed_quiz.decode("utf-8"))
image_splits = images.split(image_delimiter)
quiz_id = uuid.uuid4()
image_urls = {}
for image_split in image_splits:
res = image_split.split(image_index_delimiter)
if len(res) != 2:
continue
[index, image_data] = res
index = int(index.decode("utf-8"))
image_name = f"{quiz_id}--{uuid.uuid4()}"
await storage.upload(file_name=image_name, file_data=image_data)
image = f"{settings.root_address}/api/v1/storage/download/{image_name}"
image_urls[index] = image
quiz_dict["created_at"] = datetime.fromisoformat(quiz_dict["created_at"])
quiz_dict["updated_at"] = datetime.fromisoformat(quiz_dict["updated_at"])
quiz_dict["id"] = quiz_id
for question in quiz_dict["questions"]:
if question["image"] is not None:
question["image"] = image_urls[question["image"]]
if quiz_dict["cover_image"] is not None:
quiz_dict["cover_image"] = image_urls[-1]
quiz = Quiz.parse_obj(quiz_dict)
quiz.user_id = user.id
quiz.imported_from_kahoot = None
await quiz.save()
return quiz