🔀 Merged ClassQuizController

This commit is contained in:
Mawoka
2023-06-30 01:36:48 +02:00
183 changed files with 10232 additions and 3260 deletions
+43 -6
View File
@@ -3,6 +3,7 @@
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
import asyncio
import uuid
from typing import Optional
import ormar.exceptions
@@ -64,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)
@@ -175,3 +179,36 @@ def check_hashcash(data: str, input_data: str, claim_in: Optional[str] = "19") -
return False
some_error = [version == "1", claim == claim_in, res == input_data, ext == ""]
return all(el is True for el in some_error)
def check_image_string(image: str) -> (bool, uuid.UUID | None):
# Valid formats: {uuid} and {uuid}--{uuid}
try:
parsed_uuid = uuid.UUID(image)
return True, parsed_uuid
except ValueError:
pass
split_image = image.split("--")
if len(split_image) != 2:
return False, None
try:
uuid.UUID(split_image[0])
uuid.UUID(split_image[1])
return True, None
except ValueError:
return False, None
def extract_image_ids_from_quiz(quiz: Quiz) -> list[str | uuid.UUID]:
quiz_images = []
if quiz.background_image is not None:
quiz_images.append(quiz.background_image)
if quiz.cover_image is not None:
quiz_images.append(quiz.cover_image)
for question in quiz.questions:
if question["image"] is None:
continue
quiz_images.append(question["image"])
return quiz_images
-21
View File
@@ -1,21 +0,0 @@
# 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/.
from classquiz.config import redis, storage
from classquiz.storage.errors import DeletionFailedError
async def clean_editor_images_up():
print("Cleaning images up")
edit_sessions = await redis.smembers("edit_sessions")
for session_id in edit_sessions:
session = await redis.get(f"edit_session:{session_id}")
if session is None:
images = await redis.lrange(f"edit_session:{session_id}:images", 0, 3000)
if len(images) != 0:
try:
await storage.delete(images)
except DeletionFailedError:
print("Deletion Error", images)
await redis.srem("edit_sessions", session_id)
await redis.delete(f"edit_session:{session_id}:images")
+136
View File
@@ -0,0 +1,136 @@
# 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/.
# 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 enum
from aiohttp import ClientSession
from pydantic import BaseModel
class ImageType(str, enum.Enum):
all = "all"
photo = "photo"
illustration = "illustration"
vector = "vector"
class Orientation(str, enum.Enum):
all = ("all",)
horizontal = "horizontal"
vertical = "vertical"
class Category(str, enum.Enum):
background = "background"
fashion = "fashion"
nature = "nature"
science = "science"
education = "education"
feelings = "feelings"
health = "health"
people = "people"
religion = "religion"
places = "places"
animals = "animals"
industry = "industry"
computer = "computer"
food = "food"
sports = "sports"
transportation = "transportation"
travel = "travel"
buildings = "buildings"
business = "business"
music = "music"
class Colors(str, enum.Enum):
grayscale = "grayscale"
transparent = "transparent"
red = "red"
orange = "orange"
yellow = "yellow"
green = "green"
turquoise = "turquoise"
blue = "blue"
lilac = "lilac"
pink = "pink"
white = "white"
gray = "gray"
black = "black"
brown = "brown"
class Order(str, enum.Enum):
popular = "popular"
latest = "latest"
class BoolInput(str, enum.Enum):
true = "true"
false = "false"
class GetImagesParams(BaseModel):
q: str = ""
lang: str = "en"
id: str = ""
image_type: ImageType = ImageType.all
orientation: Orientation = Orientation.all
category: Category | str = ""
min_width: int = 0
min_height: int = 0
colors: Colors | str = ""
editors_choice: BoolInput = BoolInput.false
safesearch: BoolInput = BoolInput.false
order: Order = Order.popular
page: int = 1
pretty: BoolInput = BoolInput.false
class Hit(BaseModel):
id: int
pageURL: str
type: str
tags: str
previewURL: str
previewWidth: int
previewHeight: int
webformatURL: str
webformatWidth: int
webformatHeight: int
largeImageURL: str
imageWidth: int
imageHeight: int
imageSize: int
views: int
downloads: int
collections: int
likes: int
comments: int
user_id: int
user: str
userImageURL: str
class GetImagesResponse(BaseModel):
total: int
totalHits: int
hits: list[Hit]
class NotFoundError(Exception):
pass
async def get_images(api_key: str, params: GetImagesParams) -> GetImagesResponse:
async with ClientSession() as session, session.get(
"https://pixabay.com/api/", params={"key": api_key, **params.dict()}
) as resp:
if resp.status == 200:
return GetImagesResponse.parse_obj(await resp.json())
else:
raise NotFoundError