From db6fd87958a2cd55c198ebf574fc7cc6af7ee5f1 Mon Sep 17 00:00:00 2001 From: codEnjoyer Date: Sat, 16 Dec 2023 18:52:59 +0500 Subject: [PATCH 1/3] =?UTF-8?q?=D0=A2=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D0=B7=D0=B0=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BA=D1=83=20=D0=BD=D0=B0=D1=87=D0=B8=D1=81=D0=BB?= =?UTF-8?q?=D1=8F=D1=8E=D1=82=D1=81=D1=8F=20=D0=BC=D0=BE=D0=BD=D0=B5=D1=82?= =?UTF-8?q?=D1=8B=20=D0=B0=D0=B2=D1=82=D0=BE=D1=80=D0=B8=D0=B7=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D0=BE=D0=BC=D1=83=20=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...20\264\320\275\320\270\320\272\321\203.py" | 47 ++++++++++++++++ ...\270\320\272\320\260\320\274_\320\270_.py" | 30 ++++++++++ backend/src/game/units/tasks/router.py | 56 +++++++++++++------ backend/src/users/employees/models.py | 6 +- backend/src/users/employees/schemas.py | 5 +- backend/src/users/tutors/models.py | 6 +- backend/src/users/tutors/schemas.py | 8 ++- 7 files changed, 133 insertions(+), 25 deletions(-) create mode 100644 "backend/migrations/versions/2023_12_16_1826-753c2ee49c0d_\320\264\320\276\320\261\320\260\320\262\320\273\321\217\320\265\321\202_\320\274\320\276\320\275\320\265\321\202\321\213_\321\201\320\276\321\202\321\200\321\203\320\264\320\275\320\270\320\272\321\203.py" create mode 100644 "backend/migrations/versions/2023_12_16_1832-ee38e6a7803e_\320\264\320\276\320\261\320\260\320\262\320\273\321\217\320\265\321\202_\320\276\321\202\321\207\320\265\321\201\321\202\320\262\320\276_\321\201\320\276\321\202\321\200\320\264\321\203\320\275\320\270\320\272\320\260\320\274_\320\270_.py" diff --git "a/backend/migrations/versions/2023_12_16_1826-753c2ee49c0d_\320\264\320\276\320\261\320\260\320\262\320\273\321\217\320\265\321\202_\320\274\320\276\320\275\320\265\321\202\321\213_\321\201\320\276\321\202\321\200\321\203\320\264\320\275\320\270\320\272\321\203.py" "b/backend/migrations/versions/2023_12_16_1826-753c2ee49c0d_\320\264\320\276\320\261\320\260\320\262\320\273\321\217\320\265\321\202_\320\274\320\276\320\275\320\265\321\202\321\213_\321\201\320\276\321\202\321\200\321\203\320\264\320\275\320\270\320\272\321\203.py" new file mode 100644 index 0000000..d7230ac --- /dev/null +++ "b/backend/migrations/versions/2023_12_16_1826-753c2ee49c0d_\320\264\320\276\320\261\320\260\320\262\320\273\321\217\320\265\321\202_\320\274\320\276\320\275\320\265\321\202\321\213_\321\201\320\276\321\202\321\200\321\203\320\264\320\275\320\270\320\272\321\203.py" @@ -0,0 +1,47 @@ +"""добавляет монеты сотруднику + +Revision ID: 753c2ee49c0d +Revises: 920ca0aa0ea3 +Create Date: 2023-12-16 18:26:49.202369 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '753c2ee49c0d' +down_revision: Union[str, None] = '920ca0aa0ea3' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index('ix_oauth_account_account_id', table_name='oauth_account') + op.drop_index('ix_oauth_account_oauth_name', table_name='oauth_account') + op.drop_table('oauth_account') + op.add_column('employees', sa.Column('coins', sa.Integer(), nullable=False)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('employees', 'coins') + op.create_table('oauth_account', + sa.Column('user_id', sa.UUID(), autoincrement=False, nullable=False), + sa.Column('id', sa.UUID(), autoincrement=False, nullable=False), + sa.Column('oauth_name', sa.VARCHAR(length=100), autoincrement=False, nullable=False), + sa.Column('access_token', sa.VARCHAR(length=1024), autoincrement=False, nullable=False), + sa.Column('expires_at', sa.INTEGER(), autoincrement=False, nullable=True), + sa.Column('refresh_token', sa.VARCHAR(length=1024), autoincrement=False, nullable=True), + sa.Column('account_id', sa.VARCHAR(length=320), autoincrement=False, nullable=False), + sa.Column('account_email', sa.VARCHAR(length=320), autoincrement=False, nullable=False), + sa.ForeignKeyConstraint(['user_id'], ['users.id'], name='oauth_account_user_id_fkey', ondelete='CASCADE'), + sa.PrimaryKeyConstraint('id', name='oauth_account_pkey') + ) + op.create_index('ix_oauth_account_oauth_name', 'oauth_account', ['oauth_name'], unique=False) + op.create_index('ix_oauth_account_account_id', 'oauth_account', ['account_id'], unique=False) + # ### end Alembic commands ### diff --git "a/backend/migrations/versions/2023_12_16_1832-ee38e6a7803e_\320\264\320\276\320\261\320\260\320\262\320\273\321\217\320\265\321\202_\320\276\321\202\321\207\320\265\321\201\321\202\320\262\320\276_\321\201\320\276\321\202\321\200\320\264\321\203\320\275\320\270\320\272\320\260\320\274_\320\270_.py" "b/backend/migrations/versions/2023_12_16_1832-ee38e6a7803e_\320\264\320\276\320\261\320\260\320\262\320\273\321\217\320\265\321\202_\320\276\321\202\321\207\320\265\321\201\321\202\320\262\320\276_\321\201\320\276\321\202\321\200\320\264\321\203\320\275\320\270\320\272\320\260\320\274_\320\270_.py" new file mode 100644 index 0000000..f5ad1c3 --- /dev/null +++ "b/backend/migrations/versions/2023_12_16_1832-ee38e6a7803e_\320\264\320\276\320\261\320\260\320\262\320\273\321\217\320\265\321\202_\320\276\321\202\321\207\320\265\321\201\321\202\320\262\320\276_\321\201\320\276\321\202\321\200\320\264\321\203\320\275\320\270\320\272\320\260\320\274_\320\270_.py" @@ -0,0 +1,30 @@ +"""добавляет отчество сотрдуникам и куратору + +Revision ID: ee38e6a7803e +Revises: 753c2ee49c0d +Create Date: 2023-12-16 18:32:42.403504 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = 'ee38e6a7803e' +down_revision: Union[str, None] = '753c2ee49c0d' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('tutors', sa.Column('patronymic', sa.String(length=255), nullable=False)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('tutors', 'patronymic') + # ### end Alembic commands ### diff --git a/backend/src/game/units/tasks/router.py b/backend/src/game/units/tasks/router.py index 24e2408..d1f04b3 100644 --- a/backend/src/game/units/tasks/router.py +++ b/backend/src/game/units/tasks/router.py @@ -4,12 +4,14 @@ from fastapi import APIRouter from game.units.tasks.enums import TaskStates -from game.units.tasks.questions.answers.schemas import EmployeeAnswerRead +from game.units.tasks.questions.answers.schemas import EmployeeAnswerRead, EmployeeAnswerPost from game.units.tasks.questions.schemas import EmployeeTestQuestionPost, EmployeeTestQuestionRead, \ EmployeeOpenQuestionPost from game.units.tasks.schemas import TestTaskUnitRead, TestTaskUnitCreate, TestTaskUnitUpdate, DiscussionTaskUnitCreate, \ DiscussionTaskUnitRead, DiscussionTaskUnitUpdate, EmployeeTaskRead -from utils.types import TaskUnitServiceType, AnswerOptionServiceType, EmployeeTaskServiceType +from users.employees.schemas import EmployeeUpdate +from utils.types import TaskUnitServiceType, AnswerOptionServiceType, EmployeeTaskServiceType, CurrentUser, \ + EmployeeServiceType router = APIRouter(tags=["Task"]) @@ -34,24 +36,44 @@ async def autocheck_task_unit(map_id: UUID, level_id: UUID, task_id: UUID, employee_questions_answers: list[EmployeeTestQuestionPost], - answer_option_service: AnswerOptionServiceType) -> list[EmployeeTestQuestionRead]: - result = [] + answer_option_service: AnswerOptionServiceType, + task_unit_service: TaskUnitServiceType, + user: CurrentUser, + employee_service: EmployeeServiceType) -> list[EmployeeTestQuestionRead]: + result, answers_correctness = await get_all_answers(employee_questions_answers, answer_option_service, task_id) + if all(answers_correctness): + + reward = (await task_unit_service.get_one(task_id)).score_reward + await employee_service.update_one(user.employee.id, EmployeeUpdate(coins=user.employee.coins + reward)) + return result + + +async def get_all_answers( + employee_questions_answers: list[EmployeeTestQuestionPost], + answer_option_service: AnswerOptionServiceType, + task_id: UUID) -> (list[EmployeeTestQuestionRead], list[bool]): + result, answers_correctness = [], [] for question_answer in employee_questions_answers: - user_answers_on_question = question_answer.answers correct_answers_ids_on_question = await answer_option_service.get_all_correct(question_answer.id) - correct_answers_ids_on_question = set(correct_answers_ids_on_question) question_read_answers = [] - for answer in user_answers_on_question: - correct_answer_selected = answer.is_selected and answer.id in correct_answers_ids_on_question - incorrect_answer_not_selected = not answer.is_selected and answer.id not in correct_answers_ids_on_question - answer_was_selected_correct = correct_answer_selected or incorrect_answer_not_selected - answer_read = EmployeeAnswerRead(answer=answer.answer, was_selected_correct=answer_was_selected_correct) - question_read_answers.append(answer_read) - question_read = EmployeeTestQuestionRead(type=question_answer.type, - question=question_answer.question, - results=question_read_answers) - result.append(question_read) - return result + for answer in question_answer.answers: + answer_was_selected_correct = is_answer_selected_correct(answer, set(correct_answers_ids_on_question)) + + answers_correctness.append(answer_was_selected_correct) + question_read_answers.append(EmployeeAnswerRead(answer=answer.answer, + was_selected_correct=answer_was_selected_correct)) + result.append(EmployeeTestQuestionRead(id=question_answer.id, + task_id=task_id, + type=question_answer.type, + question=question_answer.question, + results=question_read_answers)) + return result, answers_correctness + + +def is_answer_selected_correct(answer: EmployeeAnswerPost, correct_answers_ids_on_question: set[UUID]) -> bool: + correct_answer_selected = answer.is_selected and answer.id in correct_answers_ids_on_question + incorrect_answer_not_selected = not answer.is_selected and answer.id not in correct_answers_ids_on_question + return correct_answer_selected or incorrect_answer_not_selected @router.post("/maps/{map_id}/modules/{module_id}/levels/{level_id}/tasks/{task_id}/review/") diff --git a/backend/src/users/employees/models.py b/backend/src/users/employees/models.py index 12d8aa4..ad49572 100644 --- a/backend/src/users/employees/models.py +++ b/backend/src/users/employees/models.py @@ -2,7 +2,7 @@ import uuid import datetime -from sqlalchemy import UUID, String, Date, func, ForeignKey +from sqlalchemy import UUID, String, Date, func, ForeignKey, Integer from sqlalchemy.orm import Mapped, mapped_column, relationship from database import BaseModel @@ -25,6 +25,7 @@ class Employee(BaseModel): last_name: Mapped[str] = mapped_column(String(length=255), nullable=False) patronymic: Mapped[str] = mapped_column(String(length=255)) hired_at: Mapped[datetime.date] = mapped_column(Date, server_default=func.current_date(), nullable=False) + coins: Mapped[int] = mapped_column(Integer, default=0) user: Mapped["User"] = relationship(back_populates='employee', lazy='selectin') tutor: Mapped["Tutor"] = relationship(back_populates='employees', lazy='selectin') @@ -38,5 +39,6 @@ def to_read_schema(self) -> EmployeeRead: tutor_id=self.tutor_id, name=self.name, last_name=self.last_name, + patronymic=self.patronymic, hired_at=self.hired_at, - ) + coins=self.coins) diff --git a/backend/src/users/employees/schemas.py b/backend/src/users/employees/schemas.py index 072dfd0..da0b5f1 100644 --- a/backend/src/users/employees/schemas.py +++ b/backend/src/users/employees/schemas.py @@ -11,6 +11,8 @@ class __EmployeeBase(BaseModel): name: str last_name: str hired_at: dt.date + patronymic: str + coins: int model_config = ConfigDict(from_attributes=True) @@ -25,8 +27,9 @@ class EmployeeCreate(__EmployeeBase): class EmployeeUpdate(__EmployeeBase): - user_id: UUID | None = None tutor_id: UUID | None = None name: str | None = None last_name: str | None = None + patronymic: str | None = None hired_at: dt.date | None = None + coins: int | None = None diff --git a/backend/src/users/tutors/models.py b/backend/src/users/tutors/models.py index 2aab717..75c65a4 100644 --- a/backend/src/users/tutors/models.py +++ b/backend/src/users/tutors/models.py @@ -19,6 +19,7 @@ class Tutor(BaseModel): user_id: Mapped[uuid.UUID] = mapped_column(UUID, ForeignKey('users.id'), nullable=False) name: Mapped[str] = mapped_column(String(length=255), nullable=False) last_name: Mapped[str] = mapped_column(String(length=255), nullable=False) + patronymic: Mapped[str] = mapped_column(String(length=255)) user: Mapped["User"] = relationship(back_populates='tutor', lazy='selectin') employees: Mapped[list["Employee"]] = relationship(back_populates='tutor', lazy='selectin') @@ -26,5 +27,6 @@ class Tutor(BaseModel): def to_read_schema(self) -> TutorRead: return TutorRead(id=self.id, name=self.name, - user=self.user, - last_name=self.last_name) + last_name=self.last_name, + patronymic=self.patronymic, + user=self.user) diff --git a/backend/src/users/tutors/schemas.py b/backend/src/users/tutors/schemas.py index e25d24d..6c594c1 100644 --- a/backend/src/users/tutors/schemas.py +++ b/backend/src/users/tutors/schemas.py @@ -8,6 +8,7 @@ class __TutorBase(BaseModel): name: str last_name: str + patronymic: str model_config = ConfigDict(from_attributes=True) @@ -22,6 +23,7 @@ class TutorCreate(__TutorBase): class TutorUpdate(__TutorBase): - name: str | None = None - last_name: str | None = None - user_id: UUID | None = None + name: str | None + last_name: str | None + user_id: UUID | None + patronymic: str | None From e107fb7e7cc5ceec090ebfbfb30ff37331c40c81 Mon Sep 17 00:00:00 2001 From: codEnjoyer Date: Sun, 17 Dec 2023 13:03:00 +0500 Subject: [PATCH 2/3] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D1=8F?= =?UTF-8?q?=D0=B5=D1=82=20=D0=B3=D0=BE=D0=BB=D0=BE=D0=B2=D0=BD=D1=83=D1=8E?= =?UTF-8?q?=20=D0=BC=D0=B8=D0=B3=D1=80=D0=B0=D1=86=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/docker-launch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/docker-launch.sh b/backend/docker-launch.sh index 01991fa..7f271b5 100644 --- a/backend/docker-launch.sh +++ b/backend/docker-launch.sh @@ -1,6 +1,6 @@ #!/bin/bash # При запуске стоит указывать здесь номер последней миграции alembic revision --autogenerate -alembic upgrade head || alembic upgrade 1d75241f340c +alembic upgrade head || alembic upgrade ee38e6a7803e cd src || exit gunicorn main:app --workers 1 --worker-class uvicorn.workers.UvicornWorker --bind=0.0.0.0:"$BACK_APP_PORT" --timeout 300 \ No newline at end of file From 7f5ab7094a42c2a9b89364c48ceb4a72d0a6924d Mon Sep 17 00:00:00 2001 From: codEnjoyer Date: Mon, 18 Dec 2023 11:16:15 +0500 Subject: [PATCH 3/3] =?UTF-8?q?=D0=94=D0=B5=D0=BB=D0=B0=D0=B5=D1=82=20?= =?UTF-8?q?=D1=8D=D0=BD=D0=B4=D0=BF=D0=BE=D0=B8=D0=BD=D1=82=20=D0=B0=D0=B2?= =?UTF-8?q?=D1=82=D0=BE=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD=D0=B8=D0=B9=20=D0=BD=D0=B5=D0=B7?= =?UTF-8?q?=D0=B0=D1=89=D0=B8=D1=89=D0=B5=D0=BD=D0=BD=D1=8B=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/game/units/tasks/router.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/backend/src/game/units/tasks/router.py b/backend/src/game/units/tasks/router.py index d1f04b3..6129e3d 100644 --- a/backend/src/game/units/tasks/router.py +++ b/backend/src/game/units/tasks/router.py @@ -38,13 +38,12 @@ async def autocheck_task_unit(map_id: UUID, employee_questions_answers: list[EmployeeTestQuestionPost], answer_option_service: AnswerOptionServiceType, task_unit_service: TaskUnitServiceType, - user: CurrentUser, employee_service: EmployeeServiceType) -> list[EmployeeTestQuestionRead]: result, answers_correctness = await get_all_answers(employee_questions_answers, answer_option_service, task_id) - if all(answers_correctness): - - reward = (await task_unit_service.get_one(task_id)).score_reward - await employee_service.update_one(user.employee.id, EmployeeUpdate(coins=user.employee.coins + reward)) + # if all(answers_correctness): + # + # reward = (await task_unit_service.get_one(task_id)).score_reward + # await employee_service.update_one(user.employee.id, EmployeeUpdate(coins=user.employee.coins + reward)) return result