diff --git a/pyproject.toml b/pyproject.toml
index 6763702..8d3cfad 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -15,6 +15,7 @@ dependencies = [
'PyQt6==6.7.1',
'dishka==1.4.0',
'tomli-w==1.1.0',
+ 'faker==33.1.0',
]
[project.optional-dependencies]
diff --git a/resources/forms/register.ui b/resources/forms/register.ui
index 2083dce..af0dd27 100644
--- a/resources/forms/register.ui
+++ b/resources/forms/register.ui
@@ -92,6 +92,13 @@
+ -
+
+
+ Заполнить тестовыми данными
+
+
+
-
diff --git a/src/student_journal/adapters/load_test_data.py b/src/student_journal/adapters/load_test_data.py
new file mode 100644
index 0000000..d8cb924
--- /dev/null
+++ b/src/student_journal/adapters/load_test_data.py
@@ -0,0 +1,117 @@
+import datetime
+import random
+from dataclasses import dataclass
+from datetime import date, timedelta
+
+from faker import Faker
+
+from student_journal.application.hometask.create_home_task import (
+ CreateHomeTask,
+ NewHomeTask,
+)
+from student_journal.application.lesson.create_lesson import CreateLesson, NewLesson
+from student_journal.application.student.create_student import CreateStudent, NewStudent
+from student_journal.application.student.read_student import ReadStudent
+from student_journal.application.subject.create_subject import CreateSubject, NewSubject
+from student_journal.application.teacher import CreateTeacher, NewTeacher
+from student_journal.domain.value_object.student_id import StudentId
+
+fake = Faker(locale="ru_RU")
+
+SUBJECTS = [
+ "Математика",
+ "Физика",
+ "Информатика",
+ "Химия",
+ "Физкультура",
+ "История",
+ "Обществознание",
+ "Биология",
+ "Английский язык",
+ "Русский язык",
+]
+
+
+@dataclass(slots=True, frozen=True)
+class TestDataLoader:
+ create_student: CreateStudent
+ create_teacher: CreateTeacher
+ create_subject: CreateSubject
+ read_student: ReadStudent
+ create_lesson: CreateLesson
+ create_home_task: CreateHomeTask
+
+ def insert_student(self) -> StudentId:
+ student_name = fake.name()
+ student_address = fake.address()
+ student_age = fake.random_int(min=14, max=18)
+ student_id = self.create_student.execute(
+ NewStudent(
+ age=student_age,
+ name=student_name,
+ home_address=student_address,
+ avatar=None,
+ ),
+ )
+ student = self.read_student.execute(student_id)
+ return student.student_id
+
+ def insert_data(self, student_id: StudentId) -> None:
+ teacher_names = [fake.name() for _ in range(10)]
+ teachers = []
+ student = self.read_student.execute(student_id)
+
+ for name in teacher_names:
+ teacher = self.create_teacher.execute(
+ NewTeacher(
+ full_name=name,
+ avatar=None,
+ ),
+ )
+ teachers.append(teacher)
+
+ subjects = []
+ for teacher_id, subject in zip(teachers, SUBJECTS, strict=True):
+ new_subject = self.create_subject.execute(
+ NewSubject(
+ teacher_id=teacher_id,
+ title=subject,
+ ),
+ )
+ subjects.append(new_subject)
+
+ da_te = date.today() # noqa: DTZ011
+ week_start = da_te - timedelta(days=da_te.weekday())
+ week_end = week_start + timedelta(days=6)
+ week = [
+ week_start + datetime.timedelta(days=x)
+ for x in range((week_end - week_start).days)
+ ]
+
+ for da_te in week:
+ for hour in range(8, 14):
+ time = datetime.time(hour=hour)
+ lesson_subject = random.choice(subjects) # noqa: S311
+ at = datetime.datetime.combine(
+ da_te,
+ time,
+ tzinfo=student.time_zone,
+ )
+ lesson_id = self.create_lesson.execute(
+ NewLesson(
+ subject_id=lesson_subject,
+ at=at,
+ mark=random.randint(2, 5), # noqa: S311
+ note=fake.text(),
+ room=random.randint(1000, 4000), # noqa: S311
+ ),
+ )
+
+ if random.random() > 0.5: # noqa: PLR2004, S311
+ self.create_home_task.execute(
+ NewHomeTask(
+ lesson_id=lesson_id,
+ description="Домашнее задание!",
+ is_done=random.choice([True, False]), # noqa: S311
+ ),
+ )
diff --git a/src/student_journal/application/student/read_current_student.py b/src/student_journal/application/student/read_current_student.py
new file mode 100644
index 0000000..c8ba6c0
--- /dev/null
+++ b/src/student_journal/application/student/read_current_student.py
@@ -0,0 +1,21 @@
+from dataclasses import dataclass
+
+from student_journal.application.common.id_provider import IdProvider
+from student_journal.application.common.student_gateway import StudentGateway
+from student_journal.application.converters.student import convert_student_to_read_model
+from student_journal.application.models.student import StudentReadModel
+
+
+@dataclass(slots=True)
+class ReadCurrentStudent:
+ gateway: StudentGateway
+ idp: IdProvider
+
+ def execute(self) -> StudentReadModel:
+ current_student_id = self.idp.get_id()
+ student = self.gateway.read_student(
+ current_student_id,
+ )
+
+ avg = self.gateway.get_overall_avg_mark()
+ return convert_student_to_read_model(student, avg, student.get_timezone())
diff --git a/src/student_journal/application/student/read_student.py b/src/student_journal/application/student/read_student.py
index 25109df..2a381a2 100644
--- a/src/student_journal/application/student/read_student.py
+++ b/src/student_journal/application/student/read_student.py
@@ -1,21 +1,18 @@
from dataclasses import dataclass
-from student_journal.application.common.id_provider import IdProvider
from student_journal.application.common.student_gateway import StudentGateway
from student_journal.application.converters.student import convert_student_to_read_model
from student_journal.application.models.student import StudentReadModel
+from student_journal.domain.value_object.student_id import StudentId
@dataclass(slots=True)
class ReadStudent:
gateway: StudentGateway
- idp: IdProvider
- def execute(self) -> StudentReadModel:
- current_student_id = self.idp.get_id()
+ def execute(self, student_id: StudentId) -> StudentReadModel:
student = self.gateway.read_student(
- current_student_id,
+ student_id,
)
-
avg = self.gateway.get_overall_avg_mark()
return convert_student_to_read_model(student, avg, student.get_timezone())
diff --git a/src/student_journal/bootstrap/di/adapter_provider.py b/src/student_journal/bootstrap/di/adapter_provider.py
index 33a6c34..965242f 100644
--- a/src/student_journal/bootstrap/di/adapter_provider.py
+++ b/src/student_journal/bootstrap/di/adapter_provider.py
@@ -2,6 +2,7 @@
from student_journal.adapters.error_locator import ErrorLocator, SimpleErrorLocator
from student_journal.adapters.id_provider import FileIdProvider
+from student_journal.adapters.load_test_data import TestDataLoader
from student_journal.application.common.id_provider import IdProvider
@@ -15,3 +16,4 @@ class AdapterProvider(Provider):
provides=ErrorLocator,
scope=Scope.APP,
)
+ data_loader = provide(TestDataLoader)
diff --git a/src/student_journal/bootstrap/di/command_provider.py b/src/student_journal/bootstrap/di/command_provider.py
index cde09f6..bf6b69a 100644
--- a/src/student_journal/bootstrap/di/command_provider.py
+++ b/src/student_journal/bootstrap/di/command_provider.py
@@ -18,6 +18,7 @@
from student_journal.application.lesson.read_lessons_for_week import ReadLessonsForWeek
from student_journal.application.lesson.update_lesson import UpdateLesson
from student_journal.application.student.create_student import CreateStudent
+from student_journal.application.student.read_current_student import ReadCurrentStudent
from student_journal.application.student.read_student import ReadStudent
from student_journal.application.student.update_student import UpdateStudent
from student_journal.application.subject.create_subject import CreateSubject
@@ -39,6 +40,7 @@ class CommandProvider(Provider):
commands = provide_all(
CreateStudent,
+ ReadCurrentStudent,
ReadStudent,
UpdateStudent,
CreateTeacher,
diff --git a/src/student_journal/presentation/ui/edit_lesson.py b/src/student_journal/presentation/ui/edit_lesson.py
index e9fcac4..3f08a5d 100644
--- a/src/student_journal/presentation/ui/edit_lesson.py
+++ b/src/student_journal/presentation/ui/edit_lesson.py
@@ -14,6 +14,7 @@ def setupUi(self, *args, **kwargs):
def set_invariants(self):
self.room_spinbox.setMinimum(MIN_ROOM)
+ self.room_spinbox.setMaximum(1_000_000)
self.mark_spinbox.setMinimum(0)
self.mark_spinbox.setValue(0)
diff --git a/src/student_journal/presentation/ui/raw/register_ui.py b/src/student_journal/presentation/ui/raw/register_ui.py
index 2982353..aad16f0 100644
--- a/src/student_journal/presentation/ui/raw/register_ui.py
+++ b/src/student_journal/presentation/ui/raw/register_ui.py
@@ -1,6 +1,6 @@
# Form implementation generated from reading ui file 'register.ui'
#
-# Created by: PyQt6 UI code generator 6.4.2
+# Created by: PyQt6 UI code generator 6.7.1
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
@@ -58,6 +58,9 @@ def setupUi(self, Register):
self.submit_btn.setSizePolicy(sizePolicy)
self.submit_btn.setObjectName("submit_btn")
self.formLayout.setWidget(6, QtWidgets.QFormLayout.ItemRole.FieldRole, self.submit_btn)
+ self.insert_test_data = QtWidgets.QPushButton(parent=Register)
+ self.insert_test_data.setObjectName("insert_test_data")
+ self.formLayout.setWidget(7, QtWidgets.QFormLayout.ItemRole.FieldRole, self.insert_test_data)
self.gridLayout.addLayout(self.formLayout, 5, 0, 1, 1)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setContentsMargins(-1, -1, -1, 15)
@@ -112,5 +115,6 @@ def retranslateUi(self, Register):
self.label_5.setText(_translate("Register", "Предпросмотр"))
self.avatar_preview.setText(_translate("Register", "TextLabel"))
self.submit_btn.setText(_translate("Register", "Создать аккаунт"))
+ self.insert_test_data.setText(_translate("Register", "Заполнить тестовыми данными"))
self.label_7.setText(_translate("Register", "Добро пожаловать"))
self.label_8.setText(_translate("Register", "Расскажите нам о себе"))
diff --git a/src/student_journal/presentation/widget/lesson/edit_lesson.py b/src/student_journal/presentation/widget/lesson/edit_lesson.py
index 8752362..8c79a01 100644
--- a/src/student_journal/presentation/widget/lesson/edit_lesson.py
+++ b/src/student_journal/presentation/widget/lesson/edit_lesson.py
@@ -16,7 +16,7 @@
UpdatedLesson,
UpdateLesson,
)
-from student_journal.application.student.read_student import ReadStudent
+from student_journal.application.student.read_current_student import ReadCurrentStudent
from student_journal.application.subject.read_subject import ReadSubject
from student_journal.application.subject.read_subjects import ReadSubjects
from student_journal.domain.value_object.lesson_id import LessonId
@@ -39,7 +39,7 @@ def __init__(
self.setup_ui()
with self.container() as r_container:
- command = r_container.get(ReadStudent)
+ command = r_container.get(ReadCurrentStudent)
student = command.execute()
self.tzinfo = student.time_zone
diff --git a/src/student_journal/presentation/widget/lesson/schedule.py b/src/student_journal/presentation/widget/lesson/schedule.py
index ad94363..4b23a18 100644
--- a/src/student_journal/presentation/widget/lesson/schedule.py
+++ b/src/student_journal/presentation/widget/lesson/schedule.py
@@ -195,6 +195,7 @@ def copy_lesson_to_new_date(self, lesson_id: LessonId, column: int) -> None:
),
mark=None,
note=None,
+ room=lesson.room,
)
create_command = r_container.get(CreateLesson)
@@ -334,8 +335,8 @@ def copy_to_next_week(self) -> None:
new_lesson = NewLesson(
subject_id=lesson.subject_id,
at=lesson.at + timedelta(weeks=1),
- mark=lesson.mark,
- note=lesson.note,
+ mark=None,
+ note=None,
room=lesson.room,
)
command.execute(new_lesson)
diff --git a/src/student_journal/presentation/widget/main_window.py b/src/student_journal/presentation/widget/main_window.py
index 15fd93b..d5fdbb5 100644
--- a/src/student_journal/presentation/widget/main_window.py
+++ b/src/student_journal/presentation/widget/main_window.py
@@ -1,13 +1,10 @@
-from uuid import UUID
-
from dishka import Container
from PyQt6.QtWidgets import QMainWindow, QStackedWidget
-from student_journal.adapters.id_provider import FileIdProvider
+from student_journal.application.common.id_provider import IdProvider
from student_journal.application.exceptions.student import (
StudentIsNotAuthenticatedError,
)
-from student_journal.domain.value_object.student_id import StudentId
from student_journal.presentation.widget.dashboard import Dashboard
from student_journal.presentation.widget.student.register import Register
@@ -19,7 +16,7 @@ def __init__(self, container: Container) -> None:
self.container = container
with self.container() as r_container:
- self.idp = r_container.get(FileIdProvider)
+ self.idp: IdProvider = r_container.get(IdProvider)
self.dashboard: None | Dashboard = None
self.register_form = Register(container)
@@ -46,7 +43,5 @@ def display_dashboard(self) -> None:
self.stacked_widget.addWidget(self.dashboard)
self.stacked_widget.setCurrentWidget(self.dashboard)
- def finish_register(self, student_id: str) -> None:
- student_id_uuid = StudentId(UUID(student_id))
- self.idp.save(student_id_uuid)
+ def finish_register(self) -> None:
self.display_dashboard()
diff --git a/src/student_journal/presentation/widget/student/edit_student.py b/src/student_journal/presentation/widget/student/edit_student.py
index 1151a7c..aa1298d 100644
--- a/src/student_journal/presentation/widget/student/edit_student.py
+++ b/src/student_journal/presentation/widget/student/edit_student.py
@@ -3,7 +3,7 @@
from PyQt6.QtWidgets import QFileDialog, QWidget
from student_journal.adapters.error_locator import ErrorLocator
-from student_journal.application.student.read_student import ReadStudent
+from student_journal.application.student.read_current_student import ReadCurrentStudent
from student_journal.application.student.update_student import (
UpdatedStudent,
UpdateStudent,
@@ -38,7 +38,7 @@ def __init__(self, container: Container) -> None:
def load_student(self) -> None:
with self.container() as r_container:
- command = r_container.get(ReadStudent)
+ command = r_container.get(ReadCurrentStudent)
student = command.execute()
self.ui.name_input.setText(student.name)
@@ -58,7 +58,7 @@ def load_student(self) -> None:
def refresh_avg_mark(self) -> None:
with self.container() as r_container:
- command = r_container.get(ReadStudent)
+ command = r_container.get(ReadCurrentStudent)
student = command.execute()
self.ui.avg_mark.setValue(student.student_overall_avg_mark)
diff --git a/src/student_journal/presentation/widget/student/register.py b/src/student_journal/presentation/widget/student/register.py
index cab7941..dbb834c 100644
--- a/src/student_journal/presentation/widget/student/register.py
+++ b/src/student_journal/presentation/widget/student/register.py
@@ -1,9 +1,12 @@
from dishka import Container
from PyQt6.QtCore import pyqtSignal
from PyQt6.QtGui import QPixmap
-from PyQt6.QtWidgets import QFileDialog, QWidget
+from PyQt6.QtWidgets import QFileDialog, QMessageBox, QWidget
from student_journal.adapters.exceptions.ui.student import NameNotSpecifiedError
+from student_journal.adapters.id_provider import FileIdProvider
+from student_journal.adapters.load_test_data import TestDataLoader
+from student_journal.application.common.id_provider import IdProvider
from student_journal.application.student.create_student import CreateStudent, NewStudent
from student_journal.presentation.ui.register import RegisterUI
@@ -31,6 +34,7 @@ def __init__(
self.ui.age_input.valueChanged.connect(self.on_age_input)
self.ui.address_input.textChanged.connect(self.on_address_input)
self.ui.avatar_upload_btn.clicked.connect(self.on_avatar_upload_btn)
+ self.ui.insert_test_data.clicked.connect(self.on_insert_test_data)
self.update_avatar_preview()
@@ -46,6 +50,7 @@ def on_submit_btn(self) -> None:
raise NameNotSpecifiedError
with self.container() as r_container:
+ idp = r_container.get(FileIdProvider)
data = NewStudent(
age=self.age,
name=self.name,
@@ -54,6 +59,41 @@ def on_submit_btn(self) -> None:
)
command = r_container.get(CreateStudent)
student_id = command.execute(data)
+ idp.save(student_id)
+ self.finish.emit(student_id.hex)
+
+ def on_insert_test_data(self) -> None:
+ reply = QMessageBox.question(
+ self,
+ "Вы уверены?",
+ "Эта операция заполнит приложение тестовыми данными "
+ "(операция может занять какое-то время). "
+ "Атомарность операции не гарантируется",
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ QMessageBox.StandardButton.No,
+ )
+
+ if reply == QMessageBox.StandardButton.No:
+ return
+
+ with self.container() as r_container:
+ loader = r_container.get(TestDataLoader)
+ idp = r_container.get(FileIdProvider)
+ student_id = loader.insert_student()
+ idp.save(student_id)
+
+ with self.container() as r_container:
+ loader = r_container.get(TestDataLoader)
+ idp = r_container.get(IdProvider)
+ loader.insert_data(idp.get_id())
+
+ QMessageBox.information(
+ self,
+ "Операция завершена",
+ "Данные загружены",
+ QMessageBox.StandardButton.Ok,
+ )
+
self.finish.emit(student_id.hex)
def on_name_input(self) -> None:
diff --git a/tests/unit/student/conftest.py b/tests/unit/student/conftest.py
index 1d21a0c..e70961a 100644
--- a/tests/unit/student/conftest.py
+++ b/tests/unit/student/conftest.py
@@ -4,7 +4,7 @@
from student_journal.application.common.student_gateway import StudentGateway
from student_journal.application.common.transaction_manager import TransactionManager
from student_journal.application.student.create_student import CreateStudent
-from student_journal.application.student.read_student import ReadStudent
+from student_journal.application.student.read_current_student import ReadCurrentStudent
from student_journal.application.student.update_student import UpdateStudent
from unit.student.mock.student_gateway import MockedStudentGateway
@@ -29,8 +29,8 @@ def create_student(
def read_student(
student_gateway: StudentGateway,
idp: IdProvider,
-) -> ReadStudent:
- return ReadStudent(
+) -> ReadCurrentStudent:
+ return ReadCurrentStudent(
gateway=student_gateway,
idp=idp,
)
diff --git a/tests/unit/student/test_student.py b/tests/unit/student/test_student.py
index f6dbbd5..96a5614 100644
--- a/tests/unit/student/test_student.py
+++ b/tests/unit/student/test_student.py
@@ -18,7 +18,7 @@
NAME_MIN_LENGTH,
)
from student_journal.application.student.create_student import CreateStudent, NewStudent
-from student_journal.application.student.read_student import ReadStudent
+from student_journal.application.student.read_current_student import ReadCurrentStudent
from student_journal.application.student.update_student import (
UpdatedStudent,
UpdateStudent,
@@ -87,7 +87,7 @@ def test_create_student_bad_invariants(
def test_read_student(
- read_student: ReadStudent,
+ read_student: ReadCurrentStudent,
student_gateway: MockedStudentGateway,
) -> None:
student_gateway.write_student(STUDENT)