diff --git a/classquiz/config.py b/classquiz/config.py index 49a8476..50f8cdd 100644 --- a/classquiz/config.py +++ b/classquiz/config.py @@ -71,6 +71,7 @@ class Settings(BaseSettings): async def initialize_arq(): + # skipcq: PYL-W0603 global arq arq = await create_pool(RedisSettings.from_dsn(settings.redis)) @@ -80,8 +81,6 @@ def settings() -> Settings: return Settings() -# asyncio.run(initialize_arq()) - pool = redis_lib.ConnectionPool().from_url(settings().redis) redis: redis_base_lib.client.Redis = redis_lib.Redis(connection_pool=pool) diff --git a/classquiz/db/models.py b/classquiz/db/models.py index 7d3ef0f..688f851 100644 --- a/classquiz/db/models.py +++ b/classquiz/db/models.py @@ -297,7 +297,7 @@ class GameInLobby(BaseModel): game_id: uuid.UUID -# +# skipcq: PY-W0069 # class UserProfileLinks(ormar.Model): # id: int = ormar.Integer(primary_key=True, autoincrement=True) # user: Optional[User] = ormar.ForeignKey(User) @@ -471,5 +471,5 @@ class PrivateStorageItem(PublicStorageItem): class UpdateStorageItem(BaseModel): - filename: str - alt_text: str + filename: str | None + alt_text: str | None diff --git a/classquiz/db/quiztivity.py b/classquiz/db/quiztivity.py index cf8c295..bc355de 100644 --- a/classquiz/db/quiztivity.py +++ b/classquiz/db/quiztivity.py @@ -41,10 +41,3 @@ class QuizTivityPage(BaseModel): title: str | None type: QuizTivityTypes data: Pdf | Memory | Markdown - - # @validator("type") - # def match_type_to_data_type(cls, v, values, **kwargs): - # print(values) - # if TYPE_CLASS_LIST[v] != type(values["data"]): - # raise ValueError("Specified Type doesn't match real data type") - # pass diff --git a/classquiz/oauth/custom.py b/classquiz/oauth/custom.py index 509515f..5f10c99 100644 --- a/classquiz/oauth/custom.py +++ b/classquiz/oauth/custom.py @@ -88,8 +88,9 @@ async def auth(request: Request, response: Response): google_uid=user_data.sub.hex, avatar=gzipped_user_avatar(), ) + # skipcq: PYL-W0703 except Exception as e: - if type(e) == asyncpg.exceptions.UniqueViolationError: + if type(e) is asyncpg.exceptions.UniqueViolationError: error = True counter = 1 while error: diff --git a/classquiz/oauth/github.py b/classquiz/oauth/github.py index 0bad0e7..80471b4 100644 --- a/classquiz/oauth/github.py +++ b/classquiz/oauth/github.py @@ -116,8 +116,9 @@ async def auth(request: Request, response: Response): auth_type=UserAuthTypes.GITHUB, avatar=gzipped_user_avatar(), ) + # skipcq: PYL-W0703 except Exception as e: - if type(e) == asyncpg.exceptions.UniqueViolationError: + if type(e) is asyncpg.exceptions.UniqueViolationError: error = True counter = 1 while error: diff --git a/classquiz/oauth/google.py b/classquiz/oauth/google.py index 3bf1d88..1c590d0 100644 --- a/classquiz/oauth/google.py +++ b/classquiz/oauth/google.py @@ -90,8 +90,9 @@ async def auth(request: Request, response: Response): google_uid=user_data.sub, avatar=gzipped_user_avatar(), ) + # skipcq: PYL-W0703 except Exception as e: - if type(e) == asyncpg.exceptions.UniqueViolationError: + if type(e) is asyncpg.exceptions.UniqueViolationError: error = True counter = 1 while error: diff --git a/classquiz/routers/avatar.py b/classquiz/routers/avatar.py index 26967fe..e80cf88 100644 --- a/classquiz/routers/avatar.py +++ b/classquiz/routers/avatar.py @@ -80,6 +80,7 @@ async def get_customized_avatar( clothe_color=clothe_color, clothe_graphic_type=clothe_graphic_type, ).render_svg() + # skipcq: PY-W0069 # print(f"skin_color: {len(AvatarItemsAsList.skin_color)},") # print(f"hair_color: {len(AvatarItemsAsList.hair_color)},") # print(f"facial_hair_type: {len(AvatarItemsAsList.facial_hair_type)},") diff --git a/classquiz/routers/box_controller/embedded.py b/classquiz/routers/box_controller/embedded.py index 288d6c3..19bcf42 100644 --- a/classquiz/routers/box_controller/embedded.py +++ b/classquiz/routers/box_controller/embedded.py @@ -109,7 +109,7 @@ button_to_index_map = {"b": 0, "g": 1, "y": 2, "r": 3} @router.websocket("/socket/{id}") async def websocket_endpoint(ws: WebSocket, game_id: str, id: str): try: - if id in wss_clients.keys(): + if id in wss_clients: await ws.close(code=status.WS_1001_GOING_AWAY) print("Client {} already exists.".format(id)) return diff --git a/classquiz/routers/box_controller/web.py b/classquiz/routers/box_controller/web.py index 72afce5..ee6abb2 100644 --- a/classquiz/routers/box_controller/web.py +++ b/classquiz/routers/box_controller/web.py @@ -26,7 +26,7 @@ def generate_code() -> str: "r", ] # Capital stands for long press, lowercase letter for short press resulting_code = "" - for i in range(specified_length): + for _ in range(specified_length): resulting_code += random.choice(buttons) return resulting_code diff --git a/classquiz/routers/editor.py b/classquiz/routers/editor.py index 7704eab..bcb0134 100644 --- a/classquiz/routers/editor.py +++ b/classquiz/routers/editor.py @@ -106,9 +106,6 @@ async def finish_edit(edit_id: str, quiz_input: QuizInput): if quiz_input.cover_image == "": quiz_input.cover_image = None - # if quiz_input.background_image is None and old_quiz_data.background_image is not None: - # mark_image_for_deletion(quiz_input.background_image) - if quiz_input.cover_image is not None and not check_image_string(quiz_input.cover_image)[0]: raise HTTPException(status_code=400, detail="image url is not valid") diff --git a/classquiz/routers/eximport.py b/classquiz/routers/eximport.py index 294548b..af5c264 100644 --- a/classquiz/routers/eximport.py +++ b/classquiz/routers/eximport.py @@ -46,9 +46,8 @@ async def export_quiz(quiz_id: uuid.UUID, user: User = Depends(get_current_user) 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(): + for image_key in image_urls: 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( diff --git a/classquiz/routers/live.py b/classquiz/routers/live.py index 6e9d1b5..9aad7a2 100644 --- a/classquiz/routers/live.py +++ b/classquiz/routers/live.py @@ -134,8 +134,6 @@ async def get_live_game_data( @router.get("/user_count") async def get_game_user_count(game_pin: str, api_key: str, as_string: bool = False, as_array: bool = False): - # if redis_res is None: - # raise HTTPException(status_code=404, detail="Game not found") user_id = await check_api_key(api_key) redis_res = await redis.get(f"game_session:{game_pin}") if redis_res is None: @@ -149,12 +147,6 @@ async def get_game_user_count(game_pin: str, api_key: str, as_string: bool = Fal return {"players": {"count": player_count}} -# class _LivePlayersReturn(BaseModel): -# # players: list[GamePlayer | None] -# answers: list[GameAnswer1 | None] -# players: list[GamePlayer | None] - - @router.get( "/players", ) diff --git a/classquiz/routers/login.py b/classquiz/routers/login.py index 6efd0c1..7c0d1dd 100644 --- a/classquiz/routers/login.py +++ b/classquiz/routers/login.py @@ -149,7 +149,7 @@ class StepInput(BaseModel): @router.post("/step/{step_id}") -async def step_1(session_id: str, data: StepInput, request: Request, response: Response, step_id: int): +async def step_1_endpoint(session_id: str, data: StepInput, request: Request, response: Response, step_id: int): if step_id < 0 or step_id > 2: raise HTTPException(status_code=401) redis_res = await redis.get(f"login_session:{session_id}") diff --git a/classquiz/routers/quiz.py b/classquiz/routers/quiz.py index 3069cb9..6df16cd 100644 --- a/classquiz/routers/quiz.py +++ b/classquiz/routers/quiz.py @@ -83,7 +83,7 @@ def generate_code() -> str: "r", ] # Capital stands for long press, lowercase letter for short press resulting_code = "" - for i in range(specified_length): + for _ in range(specified_length): resulting_code += random.choice(buttons) return resulting_code diff --git a/classquiz/routers/results.py b/classquiz/routers/results.py index dbc8810..dd2e43a 100644 --- a/classquiz/routers/results.py +++ b/classquiz/routers/results.py @@ -49,6 +49,7 @@ async def set_note(id: UUID, data: _SetNoteInput, user: User = Depends(get_curre return await res.update() +# skipcq: PYL-W0105 """ @router.get("/export/{result_id}", response_class=StreamingResponse) async def export_result(result_id: UUID, user: User = Depends(get_current_user)): diff --git a/classquiz/routers/storage.py b/classquiz/routers/storage.py index 36b6a01..c99c686 100644 --- a/classquiz/routers/storage.py +++ b/classquiz/routers/storage.py @@ -197,6 +197,10 @@ async def update_image_data( file_data = await StorageItem.objects.get_or_none(id=file_id, user=user, deleted_at=None) if file_data is None: raise HTTPException(status_code=404, detail="File not found") + if data.alt_text == "": + data.alt_text = None + if data.filename == "": + data.filename = None file_data.filename = data.filename file_data.alt_text = data.alt_text await file_data.update() @@ -221,7 +225,6 @@ async def list_images( raise HTTPException(status_code=404, detail="No items found") return_items: list[PrivateStorageItem] = [] for item in storage_items: - # print(item.quizzes) return_items.append(PrivateStorageItem.from_db_model(item)) return return_items diff --git a/classquiz/routers/users/__init__.py b/classquiz/routers/users/__init__.py index 97f7d06..5417387 100644 --- a/classquiz/routers/users/__init__.py +++ b/classquiz/routers/users/__init__.py @@ -79,7 +79,6 @@ async def create_user(user: RouteUser, background_task: BackgroundTasks) -> User if len(user.username) == 32: return JSONResponse({"details": "Username mustn't be 32 characters long"}, 400) await user.save() - # print(settings.skip_email_verification) if settings.skip_email_verification: user.verify_key = None user.verified = True diff --git a/classquiz/socket_server/__init__.py b/classquiz/socket_server/__init__.py index b2ec89f..7b6c463 100644 --- a/classquiz/socket_server/__init__.py +++ b/classquiz/socket_server/__init__.py @@ -253,7 +253,7 @@ class ReturnQuestion(QuizQuestion): if values["type"] == QuizQuestionType.RANGE and type(v) != RangeQuizAnswerWithoutSolution: raise ValueError("Answer must be from type RangeQuizAnswer if type is RANGE") if values["type"] == QuizQuestionType.VOTING and type(v[0]) != VotingQuizAnswer: - # print("Answer must be from type VotingQuizAnswer if type is VOTING") + # skipcq: PTC-W0047 pass return v @@ -262,7 +262,6 @@ class ReturnQuestion(QuizQuestion): async def set_question_number(sid, data: str): # data is just a number (as a str) of the question session = await sio.get_session(sid) - # print("set_question_number", data, session) if session["admin"]: game_pin = session["game_pin"] game_data = PlayGame.parse_raw(await redis.get(f"game:{session['game_pin']}")) @@ -286,7 +285,6 @@ async def set_question_number(sid, data: str): temp_return["type"] = game_data.questions[int(float(data))].type if temp_return["type"] == QuizQuestionType.ORDER: random.shuffle(temp_return["answers"]) - # print("emitting") await sio.emit( "set_question_number", { @@ -375,8 +373,6 @@ async def submit_answer(sid: str, data: dict): answers = await redis.get(f"game_session:{session['game_pin']}:{data.question_index}") diff = (time_q_started - now).total_seconds() * 1000 # - timedelta(milliseconds=latency) - # print(abs(diff) - latency, latency, abs(diff)) - score = 0 if answer_right: score = calculate_score( @@ -394,6 +390,7 @@ async def submit_answer(sid: str, data: dict): answers, game_pin=session["game_pin"], data=answer_data, q_index=int(float(data.question_index)) ) player_count = await redis.scard(f"game_session:{session['game_pin']}:players") + await sio.emit("player_answer", {}) if len(answers.__root__) == player_count: # await sio.emit( # "question_results", diff --git a/classquiz/storage/local_storage.py b/classquiz/storage/local_storage.py index a352ee8..e473712 100644 --- a/classquiz/storage/local_storage.py +++ b/classquiz/storage/local_storage.py @@ -27,9 +27,10 @@ class LocalStorage: except FileNotFoundError: yield None - async def upload(self, file_name: str, data: BinaryIO, mime_type: str | None = None) -> None: + # skipcq: PYL-W0613 + async def upload(self, file_name: str, file: BinaryIO, mime_type: str | None = None) -> None: async with aiofiles.open(file=os.path.join(self.base_path, file_name), mode="wb") as f: - await aioshutil_copyfileobj(data, f) + await aioshutil_copyfileobj(file, f) async def delete(self, file_names: [str]) -> None: for i in file_names: diff --git a/classquiz/storage/s3_storage.py b/classquiz/storage/s3_storage.py index 6a1470d..50d4f3f 100644 --- a/classquiz/storage/s3_storage.py +++ b/classquiz/storage/s3_storage.py @@ -103,15 +103,13 @@ class S3Storage: + "Signature=" + signature ) - # if expiry is not None: - # authorization_header += f", Expires={expiry}" - # Send the request with the authorization header headers = {"x-amz-date": amz_date, "Authorization": authorization_header} request_url = self.base_url + path + "?" + canonical_querystring return headers, request_url + # skipcq: PYL-W0613 async def upload(self, file: BinaryIO, file_name: str, mime_type: str | None = "application/octet-stream") -> None: headers, url = self._generate_aws_signature_v4(method="PUT", path=f"/{file_name}") async with ClientSession() as session, session.put(url, headers=headers, data=file) as resp: diff --git a/classquiz/worker/storage.py b/classquiz/worker/storage.py index 2328703..01493f7 100644 --- a/classquiz/worker/storage.py +++ b/classquiz/worker/storage.py @@ -16,6 +16,7 @@ from classquiz.storage.errors import DeletionFailedError from thumbhash import image_to_thumbhash +# skipcq: PYL-W0613 async def clean_editor_images_up(ctx): print("Cleaning images up") edit_sessions = await redis.smembers("edit_sessions") @@ -52,10 +53,12 @@ async def calculate_hash(ctx, file_id_as_str: str): try: if 0 < file_data.size < 20_970_000: # greater than 0 but smaller than 20mbytes file_data.thumbhash = image_to_thumbhash(file) + # skipcq: PYL-W0703 except Exception: pass hash_obj = xxhash.xxh3_128() + # skipcq: PY-W0069 # assert hash_obj.block_size == 64 while chunk := file.read(6400): hash_obj.update(chunk) @@ -70,6 +73,7 @@ async def calculate_hash(ctx, file_id_as_str: str): await user.update() +# skipcq: PYL-W0613 async def quiz_update(ctx, old_quiz: Quiz, quiz_id: uuid.UUID): new_quiz: Quiz = await Quiz.objects.get(id=quiz_id) old_images = extract_image_ids_from_quiz(old_quiz) @@ -83,8 +87,6 @@ async def quiz_update(ctx, old_quiz: Quiz, quiz_id: uuid.UUID): removed_images = list(set(old_images) - set(new_images)) added_images = list(set(new_images) - set(old_images)) change_made = False - # print("added:", added_images) - # print("removed:", removed_images) for image in removed_images: if "--" in image: await storage.delete([image]) @@ -92,7 +94,6 @@ async def quiz_update(ctx, old_quiz: Quiz, quiz_id: uuid.UUID): item = await StorageItem.objects.get_or_none(id=uuid.UUID(image)) if item is None: continue - # print("removed item") try: await new_quiz.storageitems.remove(item) except ormar.exceptions.NoMatch: @@ -103,7 +104,6 @@ async def quiz_update(ctx, old_quiz: Quiz, quiz_id: uuid.UUID): item = await StorageItem.objects.get_or_none(id=uuid.UUID(image)) if item is None: continue - # print("added item") await new_quiz.storageitems.add(item) change_made = True if change_made: diff --git a/frontend/package.json b/frontend/package.json index 2b0e6ee..a68720a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,7 +8,7 @@ "preview": "vite preview", "check": "svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch", - "lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . '!src/lib/i18n/locales/*.json' && eslint --ignore-path .gitignore .", + "lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . '!src/lib/i18n/locales/*.json' '!pnpm-lock.yaml' && eslint --ignore-path .gitignore .", "format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. . '!src/lib/i18n/locales/*.json'", "run:prod": "node index.js", "translations-scan": "i18next-scanner --config i18next-scanner.config.engine.cjs src/**/*.svelte" diff --git a/frontend/src/lib/admin.svelte b/frontend/src/lib/admin.svelte index 826e737..3936bf7 100644 --- a/frontend/src/lib/admin.svelte +++ b/frontend/src/lib/admin.svelte @@ -31,6 +31,7 @@ let shown_question_now: number; let final_results_clicked = false; let timer_interval; + let answer_count = 0; export let control_visible: boolean; export let player_scores; @@ -53,6 +54,7 @@ shown_question_now = data.question_index; timer_res = quiz_data.questions[data.question_index].time; selected_question = selected_question + 1; + answer_count = 0; timer(timer_res); }); const get_question_results = () => { @@ -95,6 +97,10 @@ } }); + socket.on('player_answer', (_) => { + answer_count += 1; + }); + const timer = (time: string) => { let seconds = Number(time); timer_interval = setInterval(() => { @@ -179,13 +185,13 @@ {/if} {:else} + on:click={() => { + set_question_number(selected_question + 1); + }} + class='admin-button' + >Next Question ({selected_question + 2} + ) + --> {/if} @@ -215,12 +221,18 @@ {@html quiz_data.questions[selected_question].question} -
- +
+ +
+ +
+

+ {$t('admin_page.answers_submitted', { answer_count: answer_count })} +

{#if quiz_data.questions[selected_question].image !== null} diff --git a/frontend/src/lib/dashboard/useViewportAction.js b/frontend/src/lib/dashboard/useViewportAction.js index fee000b..5704e2d 100644 --- a/frontend/src/lib/dashboard/useViewportAction.js +++ b/frontend/src/lib/dashboard/useViewportAction.js @@ -4,6 +4,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ // Stolen from https://svelte.dev/repl/c6a402704224403f96a3db56c2f48dfc?version=3.55.0 +// skipcq: JS-0119 let intersectionObserver; function ensureIntersectionObserver() { diff --git a/frontend/src/lib/hashcash.ts b/frontend/src/lib/hashcash.ts index 620dcbb..a0bc7be 100644 --- a/frontend/src/lib/hashcash.ts +++ b/frontend/src/lib/hashcash.ts @@ -42,10 +42,12 @@ export const mint = async ( // eslint-disable-next-line no-constant-condition while (true) { + // skipcq: JS-0003 const data = new TextEncoder().encode(`${challenge}:${counter.toString(16)}`); const hashBuffer = await crypto.subtle.digest('SHA-1', data); const hashArray = Array.from(new Uint8Array(hashBuffer)); const digest = hashArray.map((b) => b.toString(16).padStart(2, '0')).join(''); + // skipcq: JS-0050 if (digest.slice(0, hex_digits) == zeros) { result = counter.toString(16); break; diff --git a/frontend/src/lib/helpers.ts b/frontend/src/lib/helpers.ts index aeb6ac9..26c8880 100644 --- a/frontend/src/lib/helpers.ts +++ b/frontend/src/lib/helpers.ts @@ -10,8 +10,8 @@ export const invertColor = (hexTripletColor: string): string => { let color_int = parseInt(color, 16); // convert to integer color_int = 0xffffff ^ color_int; // invert three bytes color = color_int.toString(16); // convert to hex - color = ('000000' + color).slice(-6); // pad with leading zeros - color = '#' + color; // prepend # + color = `000000${color}`.slice(-6); // pad with leading zeros + color = `#${color}`; // prepend # return color; }; @@ -20,13 +20,6 @@ export const calculate_score = (q_time: number, time_taken: number): number => { }; export type RGB = [number, number, number]; -export const getContrast = (foregroundColor: RGB, backgroundColor: RGB) => { - const foregroundLuminance = getLuminance(foregroundColor); - const backgroundLuminance = getLuminance(backgroundColor); - return backgroundLuminance < foregroundLuminance - ? (backgroundLuminance + 0.05) / (foregroundLuminance + 0.05) - : (foregroundLuminance + 0.05) / (backgroundLuminance + 0.05); -}; export const getLuminance = (rgb: RGB): number => { const [r, g, b] = rgb.map((v) => { @@ -36,6 +29,14 @@ export const getLuminance = (rgb: RGB): number => { return r * 0.2126 + g * 0.7152 + b * 0.0722; }; +export const getContrast = (foregroundColor: RGB, backgroundColor: RGB) => { + const foregroundLuminance = getLuminance(foregroundColor); + const backgroundLuminance = getLuminance(backgroundColor); + return backgroundLuminance < foregroundLuminance + ? (backgroundLuminance + 0.05) / (foregroundLuminance + 0.05) + : (foregroundLuminance + 0.05) / (backgroundLuminance + 0.05); +}; + export const getRgbColorFromHex = (hex: string): RGB => { hex = hex.slice(1); const value = parseInt(hex, 16); diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json index 885a16c..6141f8e 100644 --- a/frontend/src/lib/i18n/locales/en.json +++ b/frontend/src/lib/i18n/locales/en.json @@ -181,7 +181,10 @@ "progress": "Progress", "speed": "Speed", "upload": "Upload", - "files_library": "Files Library" + "files_library": "Files Library", + "answer_plural": "Answers", + "yes": "Yes", + "no": "no" }, "editor": { "time_in_seconds": "Time in seconds", @@ -229,7 +232,8 @@ "next_question": "Next Question ({{question}})", "show_results": "Show results", "stop_time_and_solutions": "Stop time and show solutions", - "enter_answer_into_field": "Enter your answer into the input field!" + "enter_answer_into_field": "Enter your answer into the input field!", + "answers_submitted": "{{answer_count}} Answers submitted" }, "password_reset_page": { "reset_password": "Reset password" @@ -407,7 +411,7 @@ "caption": "Caption: {{caption}}", "filename": "Filename: {{filename}}", "uploaded": "Uploaded: {{date}}", - "Imported": "Imported: {{yes_or_no}}", + "imported": "Imported: {{yes_or_no}}", "edit_details": "Edit details", "delete_image": "Delete image", "edit_the_image": "Edit the image", diff --git a/frontend/src/lib/i18n/locales/es.json b/frontend/src/lib/i18n/locales/es.json index dbd4f2e..1e53cc9 100644 --- a/frontend/src/lib/i18n/locales/es.json +++ b/frontend/src/lib/i18n/locales/es.json @@ -175,7 +175,13 @@ "quiz": "Cuestionario", "quiztivity": "Quiztivity", "next": "Siguiente", - "check_choice": "Comprobar la elección" + "check_choice": "Comprobar la elección", + "video": "Vídeo", + "library": "Biblioteca", + "progress": "Progreso", + "speed": "Velocidad", + "upload": "Subir", + "files_library": "Biblioteca de archivos" }, "admin_page": { "export_results": "Exportar resultados", @@ -277,7 +283,11 @@ "search_for_own_quizzes": "Busca tus propios quizzes" }, "uploader": { - "add_image": "Añadir una imagen" + "add_image": "Añadir una imagen", + "select_upload_type": "Seleccione el tipo de carga", + "upload_a_video": "Cargar un vídeo", + "upload_video_popup_notice": "La ventana emergente está abierta; échale un vistazo para obtener más información", + "upload_video": "Subir un vídeo" }, "avatar_settings": { "skin_color": "Color de la piel", @@ -384,5 +394,29 @@ "popover": { "copied_to_clipboard": "¡Copiado al portapapeles!" } + }, + "public_user_page": { + "no_original_quizzes": "Este usuario no tiene cuestionarios originales", + "joined_on": "Ingresó el {{date}}" + }, + "file_dashboard": { + "not_available": "No disponible", + "missing": "¡DESAPARECIDO!", + "unset": "Desactivar", + "size": "Tamaño: {{size}} Mib", + "uploaded": "Subido: {{date}}", + "Imported": "Importado: {{yes_or_no}}", + "edit_details": "Editar los detalles", + "delete_image": "Borrar la imagen", + "edit_the_image": "Editar la imagen", + "filename_word": "Nombre del archivo", + "alt_text": "Texto alternativo / Leyenda", + "caption": "Leyenda: {{caption}}", + "filename": "Nombre del archivo: {{filename}}", + "storage_usage": "Has utilizado {{used}} Mib de {{total}} MiB del almacenamiento. Eso equivale al {{percent}}% de tu almacenamiento." + }, + "video_uploader": { + "time_elapsed": "Tiempo transcurrido", + "time_remaining": "Duración restante" } } diff --git a/frontend/src/lib/yupSchemas.ts b/frontend/src/lib/yupSchemas.ts index 9798626..2bc1f67 100644 --- a/frontend/src/lib/yupSchemas.ts +++ b/frontend/src/lib/yupSchemas.ts @@ -4,6 +4,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +// skipcq: JS-C1003 import * as yup from 'yup'; export const ABCDQuestionSchema = yup @@ -69,23 +70,17 @@ export const dataSchema = yup.object({ answers: yup.lazy((v) => { if (Array.isArray(v)) { if (typeof v[0].right === 'boolean') { - console.log('ABCDQuestionSchema'); return ABCDQuestionSchema; } else if (typeof v[0].case_sensitive === 'boolean') { - console.log('TextQuestionSchema'); return TextQuestionSchema; } else if (v[0].id !== undefined) { - console.log('OrderQuestionSchema'); return VotingQuestionSchema; } else if (v[0].answer !== undefined) { - console.log('VotingQuestionSchema'); return VotingQuestionSchema; } } else if (typeof v === 'string' || v instanceof String) { - console.log('StringQuestionSchema'); return yup.string().required("The slide mustn't be empty").nullable(); } else { - console.log('RangeQuestionSchema'); return RangeQuestionSchema; } }) diff --git a/frontend/src/routes/dashboard/files/+page.ts b/frontend/src/routes/dashboard/files/+page.ts index 92f4a01..17d6edc 100644 --- a/frontend/src/routes/dashboard/files/+page.ts +++ b/frontend/src/routes/dashboard/files/+page.ts @@ -7,7 +7,5 @@ import type { PageLoad } from './$types'; export const load = (async ({ fetch }) => { const res = await fetch('/api/v1/storage/list'); - if (res.ok) { - return { files: await res.json() }; - } + return { files: await res.json() }; }) satisfies PageLoad; diff --git a/migrations/versions/89c4b5d547aa_new_storage.py b/migrations/versions/89c4b5d547aa_new_storage.py index 9a795c7..63c85a7 100644 --- a/migrations/versions/89c4b5d547aa_new_storage.py +++ b/migrations/versions/89c4b5d547aa_new_storage.py @@ -86,18 +86,20 @@ def upgrade() -> None: conn = op.get_bind() session = Session(bind=conn) all_cover_images = session.execute("SELECT cover_image, id from quiz where cover_image is not null;") + stmt = text("UPDATE quiz SET cover_image = :n WHERE id=:i;") for cover_image, id in all_cover_images: try: new_cover_image = re.search(magic_regex, cover_image).group(1) - session.execute(f"UPDATE quiz SET cover_image = '{new_cover_image}' WHERE id='{id}';") + session.execute(stmt, {"n": new_cover_image, "i": id}) except AttributeError: continue all_background_images = session.execute("SELECT background_image, id from quiz where background_image is not null;") + stmt = text("UPDATE quiz SET cover_image = :n WHERE id=:i;") for bg_image, id in all_background_images: try: new_bg_image = re.search(magic_regex, bg_image).group(1) - session.execute(f"UPDATE quiz SET cover_image = '{new_bg_image}' WHERE id='{id}';") + session.execute(stmt, {"n": new_bg_image, "i": id}) except AttributeError: continue s = text("UPDATE quiz SET questions = :q WHERE id=:i;") @@ -138,23 +140,26 @@ def downgrade() -> None: conn = op.get_bind() session = Session(bind=conn) all_cover_images = session.execute("SELECT cover_image, id from quiz where cover_image is not null;") + stmt = text("UPDATE quiz SET cover_image = :n WHERE id=:i;") for cover_image, id in all_cover_images: new_cover_image = f"{settings.root_address}/api/v1/storage/download/{cover_image}" # print(new_cover_image, id) - session.execute(f"UPDATE quiz SET cover_image = '{new_cover_image}' WHERE id='{id}';") + session.execute(stmt, {"n": new_cover_image, "i": id}) all_background_images = session.execute("SELECT background_image, id from quiz where background_image is not null;") + stmt = text("UPDATE quiz SET cover_image = :n WHERE id=:i;") for bg_image, id in all_background_images: new_bg_image = f"{settings.root_address}/api/v1/storage/download/{bg_image}" # print(new_cover_image, id) - session.execute(f"UPDATE quiz SET cover_image = '{new_bg_image}' WHERE id='{id}';") + session.execute(stmt, {"n": new_bg_image, "i": id}) all_questions = session.execute("SELECT questions, id from quiz;") + stmt = text("UPDATE quiz SET questions = :r WHERE id=:i;") question_image_regex = r"(?=.{36}--.{36})" for question, id in all_questions: question_as_json = json.dumps(question) result = re.sub(question_image_regex, f"{settings.root_address}/api/v1/storage/download/", question_as_json) - session.execute(f"UPDATE quiz SET questions = '{result}' WHERE id='{id}';") + session.execute(stmt, {"r": result, "i": id}) ## ADDED STORAGE ITEM op.drop_table("storageitems_quiztivitys") diff --git a/simulate_players.py b/simulate_players.py index a0e093e..d46223c 100644 --- a/simulate_players.py +++ b/simulate_players.py @@ -4,6 +4,7 @@ import random import time +import sys import socketio @@ -63,4 +64,4 @@ if __name__ == "__main__": try: __main__() except KeyboardInterrupt: - exit(1) + sys.exit(1)