From 0a35e3d2fa3ee796d8c01c952c3ffb95ae6b8371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A1=D1=83=D0=BC?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Sat, 1 Mar 2025 18:23:20 +0300 Subject: [PATCH 1/4] fix: auth not working bugfix --- services/backend/api/v1/user/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/backend/api/v1/user/views.py b/services/backend/api/v1/user/views.py index c4f8c15..2861056 100644 --- a/services/backend/api/v1/user/views.py +++ b/services/backend/api/v1/user/views.py @@ -1,5 +1,6 @@ from http import HTTPStatus as status +from django.contrib.auth.hashers import check_password from django.shortcuts import get_object_or_404 from ninja import Router from ninja.errors import AuthenticationError @@ -46,9 +47,10 @@ def sign_up(request, data: RegisterSchema): ) def sign_in(request, data: LoginSchema): user = User.objects.filter(email=data.email).first() + print(check_password(data.password, user.password)) if not user: raise AuthenticationError - if not user.check_password(data.password): + if not check_password(data.password, user.password): raise AuthenticationError token = BearerAuth.generate_jwt(user) From 4c9b6fac2558720ac4e02f1aec20b5c9bafcd34b Mon Sep 17 00:00:00 2001 From: rngsurrounded Date: Sun, 2 Mar 2025 00:32:53 +0900 Subject: [PATCH 2/4] refactoring: taskstatus --- .../frontend/src/components/layout/header.tsx | 86 ++++++++++++++++++- .../components/SolutionStatus/index.tsx | 10 +-- .../pages/CompetitionSession/utils/utils.ts | 20 ++--- services/frontend/src/shared/mocks/mocks.ts | 26 +++--- services/frontend/src/shared/types.ts | 13 ++- .../frontend/src/widgets/Navbar/index.tsx | 24 ------ 6 files changed, 120 insertions(+), 59 deletions(-) delete mode 100644 services/frontend/src/widgets/Navbar/index.tsx diff --git a/services/frontend/src/components/layout/header.tsx b/services/frontend/src/components/layout/header.tsx index f9a7264..5bc2502 100644 --- a/services/frontend/src/components/layout/header.tsx +++ b/services/frontend/src/components/layout/header.tsx @@ -1,21 +1,99 @@ +import React, { useState } from 'react'; import { DataRush } from "@/components/ui/icons/datarush"; -import { ChevronDown } from "lucide-react"; +import { ChevronDown, User, Settings, BarChart2, LogOut } from "lucide-react"; import { Link } from "react-router"; +import { + Sheet, + SheetContent, + SheetHeader, + SheetTitle, + SheetClose +} from "@/components/ui/sheet"; const Header = () => { + const [isProfileOpen, setIsProfileOpen] = useState(false); + return (
-
- itqdev +
setIsProfileOpen(true)} + > + itqdev
+ + + + + Профиль + + +
+ } + label="Ваш профиль" + onClick={() => { + setIsProfileOpen(false); + }} + /> + + } + label="Настройки" + onClick={() => { + setIsProfileOpen(false); + }} + /> + + } + label="Статистика" + onClick={() => { + setIsProfileOpen(false); + }} + /> + +
+ } + label="Выйти" + onClick={() => { + setIsProfileOpen(false); + }} + /> +
+
+
+
); }; -export { Header }; +interface ProfileOptionProps { + icon: React.ReactNode; + label: string; + onClick: () => void; + className?: string; +} + +const ProfileOption: React.FC = ({ icon, label, onClick, className }) => { + return ( + + + + ); +}; + +export { Header }; \ No newline at end of file diff --git a/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/components/SolutionStatus/index.tsx b/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/components/SolutionStatus/index.tsx index 02b5c8d..008ff8e 100644 --- a/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/components/SolutionStatus/index.tsx +++ b/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/components/SolutionStatus/index.tsx @@ -9,15 +9,15 @@ interface SolutionStatusProps { const SolutionStatus: React.FC = ({ solution }) => { const getStatusText = (status: TaskStatus, score?: number, maxScore?: number) => { switch (status) { - case 'checking': + case TaskStatus.Checking: return 'На проверке'; - case 'wrong': + case TaskStatus.Wrong: return 'Неверный ответ'; - case 'correct': + case TaskStatus.Correct: return `Зачтено ${maxScore}/${maxScore} баллов`; - case 'partial': + case TaskStatus.Partial: return `Зачтено ${score}/${maxScore} баллов`; - case 'uncleared': + case TaskStatus.Uncleared: return 'Не решено'; default: return ''; diff --git a/services/frontend/src/pages/CompetitionSession/utils/utils.ts b/services/frontend/src/pages/CompetitionSession/utils/utils.ts index 22e5420..9ba336e 100644 --- a/services/frontend/src/pages/CompetitionSession/utils/utils.ts +++ b/services/frontend/src/pages/CompetitionSession/utils/utils.ts @@ -1,21 +1,21 @@ import { TaskStatus } from "@/shared/types"; const getTaskBgColor = (status: TaskStatus): string => { switch (status) { - case "uncleared": return "bg-[var(--color-task-uncleared)]"; - case "checking": return "bg-[var(--color-task-checking)]"; - case "correct": return "bg-[var(--color-task-correct)]"; - case "partial": return "bg-[var(--color-task-partial)]"; - case "wrong": return "bg-[var(--color-task-wrong)]"; + case TaskStatus.Uncleared: return "bg-[var(--color-task-uncleared)]"; + case TaskStatus.Checking: return "bg-[var(--color-task-checking)]"; + case TaskStatus.Correct: return "bg-[var(--color-task-correct)]"; + case TaskStatus.Partial: return "bg-[var(--color-task-partial)]"; + case TaskStatus.Wrong: return "bg-[var(--color-task-wrong)]"; } }; const getTaskTextColor = (status: TaskStatus): string => { switch (status) { - case "uncleared": return "text-[var(--color-task-text-uncleared)]"; - case "checking": return "text-[var(--color-task-text-checking)]"; - case "correct": return "text-[var(--color-task-text-correct)]"; - case "partial": return "text-[var(--color-task-text-partial)]"; - case "wrong": return "text-[var(--color-task-text-wrong)]"; + case TaskStatus.Uncleared: return "text-[var(--color-task-text-uncleared)]"; + case TaskStatus.Checking: return "text-[var(--color-task-text-checking)]"; + case TaskStatus.Correct: return "text-[var(--color-task-text-correct)]"; + case TaskStatus.Partial: return "text-[var(--color-task-text-partial)]"; + case TaskStatus.Wrong: return "text-[var(--color-task-text-wrong)]"; } }; diff --git a/services/frontend/src/shared/mocks/mocks.ts b/services/frontend/src/shared/mocks/mocks.ts index d7a543e..b7e2525 100644 --- a/services/frontend/src/shared/mocks/mocks.ts +++ b/services/frontend/src/shared/mocks/mocks.ts @@ -1,4 +1,4 @@ -import { Competition, CompetitionStatus, Solution, Task } from "../types"; +import { Competition, CompetitionStatus, Solution, Task, TaskStatus } from "../types"; const mockCompetitions: Competition[] = [ { @@ -56,49 +56,49 @@ const mockTasks: Task[] = [ { id: "1", number: "1.1", - status: "uncleared", + status: TaskStatus.Uncleared, solutionType: "input" }, { id: "2", number: "1.2", - status: "checking", + status: TaskStatus.Checking, solutionType: "file" }, { id: "3", number: "1.3", - status: "correct", + status: TaskStatus.Correct, solutionType: "code" }, { id: "4", number: "2.1", - status: "partial", + status: TaskStatus.Partial, solutionType: "input" }, { id: "5", number: "2.2", - status: "wrong", + status: TaskStatus.Wrong, solutionType: "file" }, { id: "6", number: "2.3", - status: "uncleared", + status: TaskStatus.Uncleared, solutionType: "code" }, { id: "7", number: "3.1", - status: "checking", + status: TaskStatus.Checking, solutionType: "file" }, { id: "8", number: "3.2", - status: "correct", + status: TaskStatus.Correct, solutionType: "input" }, ]; @@ -107,26 +107,26 @@ const mockTasks: Task[] = [ const mockSolutions: Solution[] = [ { id: '1', - status: 'wrong', + status: TaskStatus.Wrong, date: '1 марта, 08:41', }, { id: '2', - status: 'partial', + status: TaskStatus.Partial, score: 5, maxScore: 10, date: '28 февраля, 15:22', }, { id: '3', - status: 'correct', + status: TaskStatus.Correct, score: 0, maxScore: 10, date: '27 февраля, 12:10', }, { id: '4', - status: 'checking', + status: TaskStatus.Checking, date: '1 марта, 08:41', }, diff --git a/services/frontend/src/shared/types.ts b/services/frontend/src/shared/types.ts index 16741c4..6645a59 100644 --- a/services/frontend/src/shared/types.ts +++ b/services/frontend/src/shared/types.ts @@ -4,6 +4,14 @@ enum CompetitionStatus { Completed = "Завершено", } +enum TaskStatus { + Uncleared = "uncleared", + Checking = "checking", + Correct = "correct", + Partial = "partial", + Wrong = "wrong" +} + interface Competition { id: string; name: string; @@ -13,7 +21,6 @@ interface Competition { description?: string; } -type TaskStatus = "uncleared" | "checking" | "correct" | "partial" | "wrong"; type SolutionType = "input" | "file" | "code"; interface Solution { @@ -30,5 +37,5 @@ interface Task { solutionType: SolutionType; } -export { CompetitionStatus }; -export type { Solution, Competition, TaskStatus, Task }; +export { CompetitionStatus, TaskStatus }; +export type { Solution, Competition, Task }; diff --git a/services/frontend/src/widgets/Navbar/index.tsx b/services/frontend/src/widgets/Navbar/index.tsx deleted file mode 100644 index a1b681a..0000000 --- a/services/frontend/src/widgets/Navbar/index.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { ChevronDown } from "lucide-react"; - -const Navbar = () => { - return ( - - ); -}; - - -export default Navbar From e34c8ae3a71f63c94ec2ebfe963f2da9f4d5571e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A1=D1=83=D0=BC?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Sat, 1 Mar 2025 19:11:45 +0300 Subject: [PATCH 3/4] fix: incorrect token 500 --- services/backend/api/v1/auth.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/services/backend/api/v1/auth.py b/services/backend/api/v1/auth.py index bcc8870..75b571c 100644 --- a/services/backend/api/v1/auth.py +++ b/services/backend/api/v1/auth.py @@ -5,15 +5,19 @@ import jwt from django.conf import settings from django.http import HttpRequest from ninja.security import HttpBearer +from redis.exceptions import AuthorizationError from apps.user.models import User class BearerAuth(HttpBearer): def authenticate(self, request: HttpRequest, token: str) -> Any | None: - data = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"]) - if data["exp"] < datetime.datetime.now().timestamp(): - return None + try: + data = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"]) + if data["exp"] < datetime.datetime.now().timestamp(): + return None + except Exception: + raise AuthorizationError user = User.objects.get(id=data["id"]) return user From c87bace839eed73ec7acd3ac6e7f4343619ea6d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A1=D1=83=D0=BC?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Sat, 1 Mar 2025 20:11:11 +0300 Subject: [PATCH 4/4] fix: fixed bug in auth and me --- services/backend/api/v1/auth.py | 4 ++-- services/backend/api/v1/user/views.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/services/backend/api/v1/auth.py b/services/backend/api/v1/auth.py index 75b571c..1d36ce9 100644 --- a/services/backend/api/v1/auth.py +++ b/services/backend/api/v1/auth.py @@ -4,8 +4,8 @@ from typing import Any import jwt from django.conf import settings from django.http import HttpRequest +from ninja.errors import AuthenticationError from ninja.security import HttpBearer -from redis.exceptions import AuthorizationError from apps.user.models import User @@ -17,7 +17,7 @@ class BearerAuth(HttpBearer): if data["exp"] < datetime.datetime.now().timestamp(): return None except Exception: - raise AuthorizationError + raise AuthenticationError user = User.objects.get(id=data["id"]) return user diff --git a/services/backend/api/v1/user/views.py b/services/backend/api/v1/user/views.py index 6eb821b..ce2588e 100644 --- a/services/backend/api/v1/user/views.py +++ b/services/backend/api/v1/user/views.py @@ -45,7 +45,6 @@ def sign_up(request, data: RegisterSchema): ) def sign_in(request, data: LoginSchema): user = User.objects.filter(email=data.email).first() - print(check_password(data.password, user.password)) if not user: raise AuthenticationError if not check_password(data.password, user.password):