Fixed multiple things

This commit is contained in:
Mawoka
2023-06-09 13:38:36 +02:00
parent c220e3ae18
commit 09a09cf1cf
13 changed files with 170 additions and 37 deletions
+11 -10
View File
@@ -8,6 +8,7 @@ from datetime import datetime
from typing import Optional
import ormar
from ormar import ReferentialAction
from pydantic import BaseModel, Json, validator
from enum import Enum
from . import metadata, database
@@ -58,7 +59,7 @@ class FidoCredentials(ormar.Model):
id: bytes = ormar.LargeBinary(max_length=256)
public_key: bytes = ormar.LargeBinary(max_length=256)
sign_count: int = ormar.Integer()
user: Optional[User] = ormar.ForeignKey(User)
user: Optional[User] = ormar.ForeignKey(User, ondelete=ReferentialAction.CASCADE)
class Meta:
tablename = "fido_credentials"
@@ -68,7 +69,7 @@ class FidoCredentials(ormar.Model):
class ApiKey(ormar.Model):
key: str = ormar.String(max_length=48, min_length=48, primary_key=True)
user: Optional[User] = ormar.ForeignKey(User)
user: Optional[User] = ormar.ForeignKey(User, ondelete=ReferentialAction.CASCADE)
class Meta:
tablename = "api_keys"
@@ -82,7 +83,7 @@ class UserSession(ormar.Model):
"""
id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4())
user: Optional[User] = ormar.ForeignKey(User)
user: Optional[User] = ormar.ForeignKey(User, ondelete=ReferentialAction.CASCADE)
session_key: str = ormar.String(unique=True, max_length=64)
created_at: datetime = ormar.DateTime(default=datetime.now())
ip_address: str = ormar.String(max_length=100, nullable=True)
@@ -181,7 +182,7 @@ class Quiz(ormar.Model):
description: str = ormar.Text(nullable=True)
created_at: datetime = ormar.DateTime(default=datetime.now())
updated_at: datetime = ormar.DateTime(default=datetime.now())
user_id: uuid.UUID = ormar.ForeignKey(User)
user_id: uuid.UUID = ormar.ForeignKey(User, ondelete=ReferentialAction.CASCADE)
questions: Json[list[QuizQuestion]] = ormar.JSON(nullable=False)
imported_from_kahoot: Optional[bool] = ormar.Boolean(default=False, nullable=True)
cover_image: Optional[str] = ormar.Text(nullable=True, unique=False)
@@ -307,8 +308,8 @@ class GameInLobby(BaseModel):
class GameResults(ormar.Model):
id: uuid.UUID = ormar.UUID(primary_key=True)
quiz: uuid.UUID | Quiz = ormar.ForeignKey(Quiz)
user: uuid.UUID | User = ormar.ForeignKey(User)
quiz: uuid.UUID | Quiz = ormar.ForeignKey(Quiz, ondelete=ReferentialAction.CASCADE)
user: uuid.UUID | User = ormar.ForeignKey(User, ondelete=ReferentialAction.CASCADE)
timestamp: datetime = ormar.DateTime(default=datetime.now(), nullable=False)
player_count: int = ormar.Integer(nullable=False, default=0)
note: str | None = ormar.Text(nullable=True)
@@ -334,7 +335,7 @@ class QuizTivity(ormar.Model):
id: uuid.UUID = ormar.UUID(primary_key=True)
title: str = ormar.Text(nullable=False)
created_at: datetime = ormar.DateTime(nullable=False, server_default=func.now())
user: User | None = ormar.ForeignKey(User)
user: User | None = ormar.ForeignKey(User, ondelete=ReferentialAction.CASCADE)
pages: list[QuizTivityPage] = ormar.JSON(nullable=False)
class Meta:
@@ -347,8 +348,8 @@ class QuizTivityShare(ormar.Model):
id: uuid.UUID = ormar.UUID(primary_key=True)
name: str | None = ormar.Text(nullable=True)
expire_at: datetime | None = ormar.DateTime(nullable=True)
quiztivity: QuizTivity | None = ormar.ForeignKey(QuizTivity)
user: User | None = ormar.ForeignKey(User)
quiztivity: QuizTivity | None = ormar.ForeignKey(QuizTivity, ondelete=ReferentialAction.CASCADE)
user: User | None = ormar.ForeignKey(User, ondelete=ReferentialAction.CASCADE)
class Meta:
tablename = "quiztivityshares"
@@ -386,7 +387,7 @@ class StorageItem(ormar.Model):
uploaded_at: datetime = ormar.DateTime(nullable=False, default=datetime.now())
mime_type: str = ormar.Text(nullable=False)
hash: bytes | None = ormar.LargeBinary(nullable=True, min_length=16, max_length=16)
user: User | None = ormar.ForeignKey(User)
user: User | None = ormar.ForeignKey(User, ondelete=ReferentialAction.SET_NULL)
size: int = ormar.BigInteger(nullable=False)
storage_path: str | None = ormar.Text(nullable=True)
deleted_at: datetime | None = ormar.DateTime(nullable=True, default=None)
+9 -6
View File
@@ -65,12 +65,15 @@ async def generate_spreadsheet(quiz_results: dict, quiz: Quiz, player_fields: di
worksheet.write(i + 1, 1, question["time"])
try:
async with ClientSession() as session, session.get(question["image"]) as response:
img_data = BytesIO(await response.read())
worksheet.insert_image(i + 1, 2, question["image"], {"image_data": img_data})
image = Image.open(img_data)
worksheet.set_row(i + 1, image.height)
worksheet.set_column(2, 2, image.width)
async with ClientSession() as session, session.get(
f"{settings.root_address}/api/v1/storage/download/{question['image']}"
) as response:
if "image" in response.headers.get("Content-Type"):
img_data = BytesIO(await response.read())
worksheet.insert_image(i + 1, 2, question["image"], {"image_data": img_data})
image = Image.open(img_data)
worksheet.set_row(i + 1, image.height)
worksheet.set_column(2, 2, image.width)
except TypeError:
pass
answer_amount = len(answer_data)
+29 -6
View File
@@ -1,6 +1,7 @@
# 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 io
import json
import uuid
from datetime import datetime
@@ -10,10 +11,11 @@ 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
from classquiz.config import storage, settings, arq
from classquiz.db.models import Quiz, User, StorageItem
import gzip
import urllib.parse
import magic
router = APIRouter()
settings = settings()
@@ -49,7 +51,9 @@ async def export_quiz(quiz_id: uuid.UUID, user: User = Depends(get_current_user)
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:
async with ClientSession() as session, session.get(
f"{settings.root_address}/api/v1/storage/download/{image_urls[image_key]}"
) as resp:
image_data = await resp.read()
bin_data = bin_data + image_data
@@ -68,6 +72,8 @@ async def export_quiz(quiz_id: uuid.UUID, user: User = Depends(get_current_user)
@router.post("/")
async def import_quiz(file: UploadFile = File(), user: User = Depends(get_current_user)):
if user.storage_used > settings.free_storage_limit:
raise HTTPException(status_code=409, detail="Storage limit reached")
data = await file.read()
[split_data, images] = data.split(quiz_delimiter)
decompressed_quiz = gzip.decompress(split_data)
@@ -75,15 +81,32 @@ async def import_quiz(file: UploadFile = File(), user: User = Depends(get_curren
image_splits = images.split(image_delimiter)
quiz_id = uuid.uuid4()
image_urls = {}
print(len(data))
for image_split in image_splits:
res = image_split.split(image_index_delimiter)
if len(res) != 2:
continue
[index, image_data] = res
print(len(image_data))
img_data = io.BytesIO(image_data)
mime_type = magic.from_buffer(img_data.read(2048), mime=True)
print(mime_type)
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}"
file_id = uuid.uuid4()
file_obj = StorageItem(
id=file_id,
uploaded_at=datetime.now(),
mime_type=mime_type,
hash=None,
user=user,
size=0,
deleted_at=None,
alt_text=None,
)
await storage.upload(file_name=file_id.hex, file_data=img_data, mime_type=mime_type)
await file_obj.save()
await arq.enqueue_job("calculate_hash", file_id.hex)
image = file_id.hex
image_urls[index] = image
quiz_dict["created_at"] = datetime.fromisoformat(quiz_dict["created_at"])
quiz_dict["updated_at"] = datetime.fromisoformat(quiz_dict["updated_at"])
+3 -1
View File
@@ -209,7 +209,9 @@ async def delete_quiz(quiz_id: str, user: User = Depends(get_current_user)):
for question in quiz.questions:
try:
if question["image"] is not None and not str(question["image"]).startswith("https://i.imgur.com/"):
pics_to_delete.append(pic_name_regex.match(question["image"]).group(1))
old_image_to_delete = pic_name_regex.match(question["image"])
if old_image_to_delete is not None:
pics_to_delete.append(old_image_to_delete.group(1))
except KeyError:
pass
if len(pics_to_delete) != 0:
+4 -2
View File
@@ -131,7 +131,7 @@ async def upload_file(file: UploadFile = File(), user: User = Depends(get_curren
deleted_at=None,
alt_text=None,
)
await storage.upload(file_name=file_id.hex, file_data=file.file)
await storage.upload(file_name=file_id.hex, file_data=file.file, mime_type=file.content_type)
await file_obj.save()
await arq.enqueue_job("calculate_hash", file_id.hex)
return PublicStorageItem.from_db_model(file_obj)
@@ -157,7 +157,9 @@ async def upload_raw_file(request: Request, user: User = Depends(get_current_use
alt_text=None,
)
# https://github.com/VirusTotal/vt-py/issues/119#issuecomment-1261246867
await storage.upload(file_name=file_id.hex, file_data=data_file._file)
await storage.upload(
file_name=file_id.hex, file_data=data_file._file, mime_type=request.headers.get("Content-Type")
)
await file_obj.save()
await arq.enqueue_job("calculate_hash", file_id.hex)
return PublicStorageItem.from_db_model(file_obj)