From f21c4d2a37738568285ad637d75696104c294862 Mon Sep 17 00:00:00 2001 From: sabudilovskiy Date: Thu, 8 Jun 2023 14:11:29 +0300 Subject: [PATCH] Teacher create and approve (#16) --- .gen/objs.txt | 55 ++++++++++ api/api.yaml | 4 + api/types/TeacherInfo.yaml | 9 ++ api/views/admin/create/view.yaml | 2 +- api/views/admin/list/view.yaml | 2 +- api/views/teacher/create/Request.yaml | 3 + api/views/teacher/create/view.yaml | 35 ++++++ .../requests/approve/link/Request.yaml | 5 + .../teacher/requests/approve/link/view.yaml | 35 ++++++ configs/static_config.yaml.in | 30 +++++- postgresql/data/initial_data_timetable1.sql | 4 +- postgresql/data/initial_data_timetable2.sql | 4 +- postgresql/schemas/db_1/000_init.sql | 38 ++++--- .../schemas/db_1/012_add_teacher_info.sql | 11 ++ postgresql/schemas/db_1/013_add_faculty.sql | 17 +++ .../db_1/014_add_group_stage_filter.sql | 17 +++ service/main.cpp | 54 +++++++--- .../controllers/postgres/admin/fwd.cpp | 8 +- .../controllers/postgres/admin/fwd.hpp | 9 +- .../postgres/faculty/controller.cpp | 61 +++++++++++ .../postgres/faculty/controller.hpp | 38 +++++++ .../controllers/postgres/faculty/fwd.cpp | 14 +++ .../controllers/postgres/faculty/fwd.hpp | 9 ++ .../postgres/faculty/sql_queries.hpp | 16 +++ .../postgres/group_stage/controller.cpp | 61 +++++++++++ .../postgres/group_stage/controller.hpp | 38 +++++++ .../controllers/postgres/group_stage/fwd.cpp | 14 +++ .../controllers/postgres/group_stage/fwd.hpp | 9 ++ .../postgres/group_stage/sql_queries.hpp | 45 ++++++++ .../controllers/postgres/lesson/fwd.cpp | 9 +- .../controllers/postgres/lesson/fwd.hpp | 10 +- .../postgres/teacher/controller.cpp | 96 +++++++++++++++++ .../postgres/teacher/controller.hpp | 35 ++++++ .../controllers/postgres/teacher/fwd.cpp | 9 +- .../controllers/postgres/teacher/fwd.hpp | 6 +- .../postgres/teacher/sql_queries.hpp | 21 ++++ .../controllers/postgres/token/fwd.cpp | 8 +- .../controllers/postgres/token/fwd.hpp | 4 +- .../controllers/postgres/user/fwd.cpp | 8 +- .../controllers/postgres/user/fwd.hpp | 4 +- src/models/faculty/fwd.hpp | 6 ++ src/models/faculty/postgre.hpp | 20 ++++ src/models/faculty/type.hpp | 25 +++++ src/models/faculty_filter/fwd.hpp | 6 ++ src/models/faculty_filter/postgre.hpp | 20 ++++ src/models/faculty_filter/type.hpp | 25 +++++ src/models/group_stage/fwd.hpp | 6 ++ src/models/group_stage/postgre.hpp | 21 ++++ src/models/group_stage/type.hpp | 34 ++++++ src/models/group_stage_filter/fwd.hpp | 6 ++ src/models/group_stage_filter/postgre.hpp | 21 ++++ src/models/group_stage_filter/type.hpp | 36 +++++++ src/models/request_privileges/fwd.hpp | 5 + src/models/request_privileges/type.hpp | 15 +++ src/models/teacher_info/parse.hpp | 2 + src/models/teacher_info/postgre.hpp | 22 ++++ src/models/teacher_info/serialize.hpp | 2 + src/models/teacher_info/type.hpp | 19 ++++ src/utils/common_errors.hpp | 25 +++++ .../detail/parse/converter_http_request.hpp | 13 +-- src/utils/perform_common_errors.cpp | 33 ++++++ src/utils/perform_common_errors.hpp | 12 +++ src/utils/postgres_helper.hpp | 35 ++++++ src/views/admin/create/Responses.hpp | 20 ++-- src/views/admin/create/view.cpp | 28 +---- src/views/admin/list/Responses.hpp | 18 +--- src/views/admin/list/view.cpp | 26 +---- src/views/faculty/list/Request.hpp | 22 ++++ src/views/faculty/list/Responses.hpp | 29 +++++ src/views/faculty/list/view.cpp | 55 ++++++++++ src/views/faculty/list/view.hpp | 7 ++ src/views/group-stage/list/Request.hpp | 22 ++++ src/views/group-stage/list/Responses.hpp | 30 ++++++ src/views/group-stage/list/view.cpp | 59 +++++++++++ src/views/group-stage/list/view.hpp | 7 ++ src/views/teacher/create/Request.hpp | 25 +++++ src/views/teacher/create/Responses.hpp | 34 ++++++ src/views/teacher/create/view.cpp | 78 ++++++++++++++ src/views/teacher/create/view.hpp | 7 ++ .../teacher/request/approve/link/Request.hpp | 23 ++++ .../request/approve/link/Responses.hpp | 37 +++++++ .../teacher/request/approve/link/view.cpp | 78 ++++++++++++++ .../teacher/request/approve/link/view.hpp | 7 ++ .../teacher/request/approve/new/Request.hpp | 24 +++++ .../teacher/request/approve/new/Responses.hpp | 37 +++++++ .../teacher/request/approve/new/view.cpp | 78 ++++++++++++++ .../teacher/request/approve/new/view.hpp | 7 ++ src/views/teacher/request/list/Request.hpp | 22 ++++ src/views/teacher/request/list/Responses.hpp | 35 ++++++ src/views/teacher/request/list/view.cpp | 72 +++++++++++++ src/views/teacher/request/list/view.hpp | 7 ++ tests/faculty/list/data_faculty.py | 27 +++++ tests/faculty/list/test_faculty_list.py | 30 ++++++ tests/teacher/conftest.py | 56 ++++++++++ tests/teacher/create/test_teacher_create.py | 100 ++++++++++++++++++ .../static/initial_data_teacher_request.sql | 14 +++ .../link/test_teacher_request_approve_link.py | 81 ++++++++++++++ .../static/initial_data_teacher_request.sql | 11 ++ .../new/test_teacher_request_approve_new.py | 96 +++++++++++++++++ .../static/initial_data_teacher_request.sql | 5 + .../request/list/test_teacher_request_list.py | 49 +++++++++ tests/timetable/get/test_timetable_get.py | 1 - united_api.yaml | 56 +++++++++- 103 files changed, 2524 insertions(+), 162 deletions(-) create mode 100644 api/types/TeacherInfo.yaml create mode 100644 api/views/teacher/create/Request.yaml create mode 100644 api/views/teacher/create/view.yaml create mode 100644 api/views/teacher/requests/approve/link/Request.yaml create mode 100644 api/views/teacher/requests/approve/link/view.yaml create mode 100644 postgresql/schemas/db_1/012_add_teacher_info.sql create mode 100644 postgresql/schemas/db_1/013_add_faculty.sql create mode 100644 postgresql/schemas/db_1/014_add_group_stage_filter.sql create mode 100644 src/components/controllers/postgres/faculty/controller.cpp create mode 100644 src/components/controllers/postgres/faculty/controller.hpp create mode 100644 src/components/controllers/postgres/faculty/fwd.cpp create mode 100644 src/components/controllers/postgres/faculty/fwd.hpp create mode 100644 src/components/controllers/postgres/faculty/sql_queries.hpp create mode 100644 src/components/controllers/postgres/group_stage/controller.cpp create mode 100644 src/components/controllers/postgres/group_stage/controller.hpp create mode 100644 src/components/controllers/postgres/group_stage/fwd.cpp create mode 100644 src/components/controllers/postgres/group_stage/fwd.hpp create mode 100644 src/components/controllers/postgres/group_stage/sql_queries.hpp create mode 100644 src/models/faculty/fwd.hpp create mode 100644 src/models/faculty/postgre.hpp create mode 100644 src/models/faculty/type.hpp create mode 100644 src/models/faculty_filter/fwd.hpp create mode 100644 src/models/faculty_filter/postgre.hpp create mode 100644 src/models/faculty_filter/type.hpp create mode 100644 src/models/group_stage/fwd.hpp create mode 100644 src/models/group_stage/postgre.hpp create mode 100644 src/models/group_stage/type.hpp create mode 100644 src/models/group_stage_filter/fwd.hpp create mode 100644 src/models/group_stage_filter/postgre.hpp create mode 100644 src/models/group_stage_filter/type.hpp create mode 100644 src/models/request_privileges/fwd.hpp create mode 100644 src/models/request_privileges/type.hpp create mode 100644 src/models/teacher_info/parse.hpp create mode 100644 src/models/teacher_info/postgre.hpp create mode 100644 src/models/teacher_info/serialize.hpp create mode 100644 src/models/teacher_info/type.hpp create mode 100644 src/utils/common_errors.hpp create mode 100644 src/utils/perform_common_errors.cpp create mode 100644 src/utils/perform_common_errors.hpp create mode 100644 src/views/faculty/list/Request.hpp create mode 100644 src/views/faculty/list/Responses.hpp create mode 100644 src/views/faculty/list/view.cpp create mode 100644 src/views/faculty/list/view.hpp create mode 100644 src/views/group-stage/list/Request.hpp create mode 100644 src/views/group-stage/list/Responses.hpp create mode 100644 src/views/group-stage/list/view.cpp create mode 100644 src/views/group-stage/list/view.hpp create mode 100644 src/views/teacher/create/Request.hpp create mode 100644 src/views/teacher/create/Responses.hpp create mode 100644 src/views/teacher/create/view.cpp create mode 100644 src/views/teacher/create/view.hpp create mode 100644 src/views/teacher/request/approve/link/Request.hpp create mode 100644 src/views/teacher/request/approve/link/Responses.hpp create mode 100644 src/views/teacher/request/approve/link/view.cpp create mode 100644 src/views/teacher/request/approve/link/view.hpp create mode 100644 src/views/teacher/request/approve/new/Request.hpp create mode 100644 src/views/teacher/request/approve/new/Responses.hpp create mode 100644 src/views/teacher/request/approve/new/view.cpp create mode 100644 src/views/teacher/request/approve/new/view.hpp create mode 100644 src/views/teacher/request/list/Request.hpp create mode 100644 src/views/teacher/request/list/Responses.hpp create mode 100644 src/views/teacher/request/list/view.cpp create mode 100644 src/views/teacher/request/list/view.hpp create mode 100644 tests/faculty/list/data_faculty.py create mode 100644 tests/faculty/list/test_faculty_list.py create mode 100644 tests/teacher/conftest.py create mode 100644 tests/teacher/create/test_teacher_create.py create mode 100644 tests/teacher/request/approve/link/static/initial_data_teacher_request.sql create mode 100644 tests/teacher/request/approve/link/test_teacher_request_approve_link.py create mode 100644 tests/teacher/request/approve/new/static/initial_data_teacher_request.sql create mode 100644 tests/teacher/request/approve/new/test_teacher_request_approve_new.py create mode 100644 tests/teacher/request/list/static/initial_data_teacher_request.sql create mode 100644 tests/teacher/request/list/test_teacher_request_list.py diff --git a/.gen/objs.txt b/.gen/objs.txt index fefd7ebc..25b69653 100644 --- a/.gen/objs.txt +++ b/.gen/objs.txt @@ -2,10 +2,26 @@ src/views/timetable/get/view.hpp src/views/timetable/get/view.cpp src/views/timetable/get/Responses.hpp src/views/timetable/get/Request.hpp +src/views/teacher/request/list/view.hpp +src/views/teacher/request/list/view.cpp +src/views/teacher/request/list/Responses.hpp +src/views/teacher/request/list/Request.hpp +src/views/teacher/request/approve/new/view.hpp +src/views/teacher/request/approve/new/view.cpp +src/views/teacher/request/approve/new/Responses.hpp +src/views/teacher/request/approve/new/Request.hpp +src/views/teacher/request/approve/link/view.hpp +src/views/teacher/request/approve/link/view.cpp +src/views/teacher/request/approve/link/Responses.hpp +src/views/teacher/request/approve/link/Request.hpp src/views/teacher/list/view.hpp src/views/teacher/list/view.cpp src/views/teacher/list/Responses.hpp src/views/teacher/list/Request.hpp +src/views/teacher/create/view.hpp +src/views/teacher/create/view.cpp +src/views/teacher/create/Responses.hpp +src/views/teacher/create/Request.hpp src/views/register/view.hpp src/views/register/view.cpp src/views/register/Responses.hpp @@ -16,6 +32,14 @@ src/views/login/Responses.hpp src/views/login/Request.hpp src/views/hello/view.hpp src/views/hello/view.cpp +src/views/group-stage/list/view.hpp +src/views/group-stage/list/view.cpp +src/views/group-stage/list/Responses.hpp +src/views/group-stage/list/Request.hpp +src/views/faculty/list/view.hpp +src/views/faculty/list/view.cpp +src/views/faculty/list/Responses.hpp +src/views/faculty/list/Request.hpp src/views/admin/list/view.hpp src/views/admin/list/view.cpp src/views/admin/list/Responses.hpp @@ -27,6 +51,8 @@ src/views/admin/create/Request.hpp src/utils/type_holder.hpp src/utils/shared_transaction.hpp src/utils/postgres_helper.hpp +src/utils/perform_common_errors.hpp +src/utils/perform_common_errors.cpp src/utils/parse/uuid/string.hpp src/utils/parse/uuid/string.cpp src/utils/meta.hpp @@ -48,6 +74,7 @@ src/utils/convert/base.hpp src/utils/convert/additional_properties.hpp src/utils/constexpr_string.hpp src/utils/component_list_fwd.hpp +src/utils/common_errors.hpp src/models/user_type/type.hpp src/models/user_type/serialize.hpp src/models/user_type/serialize.cpp @@ -69,6 +96,10 @@ src/models/timestring/parse.hpp src/models/timestring/parse.cpp src/models/timestring/fwd.hpp src/models/timestring/all.hpp +src/models/teacher_info/type.hpp +src/models/teacher_info/serialize.hpp +src/models/teacher_info/postgre.hpp +src/models/teacher_info/parse.hpp src/models/teacher_filter/type.hpp src/models/teacher_filter/postgre.hpp src/models/teacher_filter/fwd.hpp @@ -91,6 +122,8 @@ src/models/subgroup/postgre.hpp src/models/subgroup/parse.hpp src/models/subgroup/parse.cpp src/models/subgroup/all.hpp +src/models/request_privileges/type.hpp +src/models/request_privileges/fwd.hpp src/models/register_request/type.hpp src/models/register_request/fwd.hpp src/models/lesson_week_type/type.hpp @@ -114,6 +147,18 @@ src/models/lesson_type/all.hpp src/models/lesson_filter/type.hpp src/models/lesson_filter/postgre.hpp src/models/lesson_filter/fwd.hpp +src/models/group_stage_filter/type.hpp +src/models/group_stage_filter/postgre.hpp +src/models/group_stage_filter/fwd.hpp +src/models/group_stage/type.hpp +src/models/group_stage/postgre.hpp +src/models/group_stage/fwd.hpp +src/models/faculty_filter/type.hpp +src/models/faculty_filter/postgre.hpp +src/models/faculty_filter/fwd.hpp +src/models/faculty/type.hpp +src/models/faculty/postgre.hpp +src/models/faculty/fwd.hpp src/models/education_type/type.hpp src/models/education_type/serialize.hpp src/models/education_type/serialize.cpp @@ -159,6 +204,16 @@ src/components/controllers/postgres/lesson/fwd.hpp src/components/controllers/postgres/lesson/fwd.cpp src/components/controllers/postgres/lesson/controller.hpp src/components/controllers/postgres/lesson/controller.cpp +src/components/controllers/postgres/group_stage/sql_queries.hpp +src/components/controllers/postgres/group_stage/fwd.hpp +src/components/controllers/postgres/group_stage/fwd.cpp +src/components/controllers/postgres/group_stage/controller.hpp +src/components/controllers/postgres/group_stage/controller.cpp +src/components/controllers/postgres/faculty/sql_queries.hpp +src/components/controllers/postgres/faculty/fwd.hpp +src/components/controllers/postgres/faculty/fwd.cpp +src/components/controllers/postgres/faculty/controller.hpp +src/components/controllers/postgres/faculty/controller.cpp src/components/controllers/postgres/admin/sql_queries.hpp src/components/controllers/postgres/admin/fwd.hpp src/components/controllers/postgres/admin/fwd.cpp diff --git a/api/api.yaml b/api/api.yaml index 31a9eb6b..b261e774 100644 --- a/api/api.yaml +++ b/api/api.yaml @@ -7,6 +7,8 @@ info: name: Apache 2.0 url: 'http://www.apache.org/licenses/LICENSE-2.0.html' tags: + - name: root + description: Доступно суперпользователю - name: admins description: Доступно администраторам сервиса - name: teachers @@ -24,3 +26,5 @@ paths: $ref: 'views/admin/create/view.yaml' /admin/list: $ref: 'views/admin/list/view.yaml' + /teacher/create: + $ref: 'views/teacher/create/view.yaml' diff --git a/api/types/TeacherInfo.yaml b/api/types/TeacherInfo.yaml new file mode 100644 index 00000000..5fb41d91 --- /dev/null +++ b/api/types/TeacherInfo.yaml @@ -0,0 +1,9 @@ +properties: + fio: + type: string + description: ФИО + bio: + type: string + description: биография + department_id: + $ref: Id.yaml diff --git a/api/views/admin/create/view.yaml b/api/views/admin/create/view.yaml index bd17824b..7c820539 100644 --- a/api/views/admin/create/view.yaml +++ b/api/views/admin/create/view.yaml @@ -1,7 +1,7 @@ post: description: Получить список администраторов tags: - - admins + - root requestBody: required: true content: diff --git a/api/views/admin/list/view.yaml b/api/views/admin/list/view.yaml index 84ceddaf..94c576c4 100644 --- a/api/views/admin/list/view.yaml +++ b/api/views/admin/list/view.yaml @@ -1,7 +1,7 @@ post: description: Получить список администраторов tags: - - admins + - root requestBody: required: true content: diff --git a/api/views/teacher/create/Request.yaml b/api/views/teacher/create/Request.yaml new file mode 100644 index 00000000..a96bc2ed --- /dev/null +++ b/api/views/teacher/create/Request.yaml @@ -0,0 +1,3 @@ +properties: + credentials: + $ref: ../../../types/TeacherInfo.yaml diff --git a/api/views/teacher/create/view.yaml b/api/views/teacher/create/view.yaml new file mode 100644 index 00000000..dacb6864 --- /dev/null +++ b/api/views/teacher/create/view.yaml @@ -0,0 +1,35 @@ +post: + description: Создать нового преподавателя + tags: + - admins + requestBody: + required: true + content: + application/json: + schema: + $ref: 'Request.yaml' + parameters: + - in: header + name: authToken + required: true + schema: + $ref: '../../../types/AuthTokenV1.yaml' + responses: + '200': + description: Преподаватель успешно создан + content: + application/json: + schema: + $ref: '../../../types/AdminAccount.yaml' + '401': + description: Отсутствует или истекший токен + content: + application/json: + schema: + $ref: '../../../types/ErrorV1.yaml' + '403': + description: Нет прав на подобные изменения + content: + application/json: + schema: + $ref: '../../../types/ErrorV1.yaml' diff --git a/api/views/teacher/requests/approve/link/Request.yaml b/api/views/teacher/requests/approve/link/Request.yaml new file mode 100644 index 00000000..fd8a8d1e --- /dev/null +++ b/api/views/teacher/requests/approve/link/Request.yaml @@ -0,0 +1,5 @@ +properties: + teacher_id: + $ref: ../../../../../types/Id.yaml + request_id: + $ref: ../../../../../types/Id.yaml diff --git a/api/views/teacher/requests/approve/link/view.yaml b/api/views/teacher/requests/approve/link/view.yaml new file mode 100644 index 00000000..f3a8f295 --- /dev/null +++ b/api/views/teacher/requests/approve/link/view.yaml @@ -0,0 +1,35 @@ +post: + description: Принять запрос на повышение прав до преподавателя + tags: + - admins + requestBody: + required: true + content: + application/json: + schema: + $ref: 'Request.yaml' + parameters: + - in: header + name: authToken + required: true + schema: + $ref: '../../../types/AuthTokenV1.yaml' + responses: + '200': + description: Преподаватель успешно создан + content: + application/json: + schema: + $ref: '../../../types/AdminAccount.yaml' + '401': + description: Отсутствует или истекший токен + content: + application/json: + schema: + $ref: '../../../types/ErrorV1.yaml' + '403': + description: Нет прав на подобные изменения + content: + application/json: + schema: + $ref: '../../../types/ErrorV1.yaml' diff --git a/configs/static_config.yaml.in b/configs/static_config.yaml.in index a9567332..dfa45c5a 100644 --- a/configs/static_config.yaml.in +++ b/configs/static_config.yaml.in @@ -76,13 +76,39 @@ components_manager: handler-teacher-list: path: /teacher/list method: POST - task_processor: main-task-processor + task_processor: main-task-processor + handler-faculty-list: + path: /faculty/list + method: POST + task_processor: main-task-processor + handler-teacher-requests-list: + path: /teacher/requests/list + method: POST + task_processor: main-task-processor + handler-teacher-requests-approve-link: + path: /teacher/requests/approve/link + method: POST + task_processor: main-task-processor + handler-teacher-requests-approve-new: + path: /teacher/requests/approve/new + method: POST + task_processor: main-task-processor + handler-teacher-create: + path: /teacher/create + method: POST + task_processor: main-task-processor + handler-group-stage-list: + path: /group-stage/list + method: POST + task_processor: main-task-processor postgres-db-1: dbconnection: $dbconnection blocking_task_processor: fs-task-processor dns_resolver: async sync-start: true - admin_controller: {} + admin_controller: {} + group_stage_controller: {} + faculty_controller: {} user-controller: root: login: $root_login diff --git a/postgresql/data/initial_data_timetable1.sql b/postgresql/data/initial_data_timetable1.sql index c76dfc48..ac4144c7 100644 --- a/postgresql/data/initial_data_timetable1.sql +++ b/postgresql/data/initial_data_timetable1.sql @@ -11,8 +11,8 @@ INSERT INTO timetable_vsu.teacher (id, fio, bio, id_department) VALUES ('241416c7-9654-4814-b36b-7d39c1ddded2', 'John Doe', 'Professor of Mathematics', '1f93ceb4-d931-4b66-a0e5-7323d6b60f3b'); -- Insert test data into the group table -INSERT INTO timetable_vsu.group (id, name, type) -VALUES ('c1fb3eac-de6d-44ef-bf35-18bebe832e1d', 'MM-21', 'magistracy'); +INSERT INTO timetable_vsu.group (id, name, type, id_faculty) +VALUES ('c1fb3eac-de6d-44ef-bf35-18bebe832e1d', 'MM-21', 'magistracy', 'bbc6312c-f25e-4db3-b2a0-3f5dc6717a8d'); -- Insert test data into the group_stage table INSERT INTO timetable_vsu.group_stage (id, begin, "end", course, id_group) diff --git a/postgresql/data/initial_data_timetable2.sql b/postgresql/data/initial_data_timetable2.sql index c5df505a..803a3780 100644 --- a/postgresql/data/initial_data_timetable2.sql +++ b/postgresql/data/initial_data_timetable2.sql @@ -11,8 +11,8 @@ INSERT INTO timetable_vsu.teacher (id, fio, bio, id_department) VALUES ('dc5bad6f-fcf6-4869-b0e5-5c36aed85cc1', 'УСКОВА О.Ф.', 'ЛУЧШИЙ ПРЕПОД МИРА', '3ec37598-6c49-4a02-8134-d9dbffafa8c4'); -- Insert test data into the group table -INSERT INTO timetable_vsu.group (id, name, type) -VALUES ('c8a34f05-f081-4d78-b971-30d562fd9f1c', '62', 'undergraduate'); +INSERT INTO timetable_vsu.group (id, name, type, id_faculty) +VALUES ('c8a34f05-f081-4d78-b971-30d562fd9f1c', '62', 'undergraduate', 'af8f26b8-afc7-483d-b6cc-ffaec29d4bc7'); -- Insert test data into the group_stage table INSERT INTO timetable_vsu.group_stage (id, begin, "end", course, id_group) diff --git a/postgresql/schemas/db_1/000_init.sql b/postgresql/schemas/db_1/000_init.sql index 8343009f..ab5aeb2b 100755 --- a/postgresql/schemas/db_1/000_init.sql +++ b/postgresql/schemas/db_1/000_init.sql @@ -61,7 +61,7 @@ CREATE TABLE timetable_vsu.department ( ALTER TABLE timetable_vsu.department DROP CONSTRAINT IF EXISTS faculty_fk CASCADE; ALTER TABLE timetable_vsu.department ADD CONSTRAINT faculty_fk FOREIGN KEY (id_faculty) REFERENCES timetable_vsu.faculty (id) MATCH FULL -ON DELETE SET NULL ON UPDATE CASCADE; +ON DELETE CASCADE ON UPDATE CASCADE; @@ -78,7 +78,7 @@ CREATE TABLE timetable_vsu.teacher ( ALTER TABLE timetable_vsu.teacher DROP CONSTRAINT IF EXISTS department_fk CASCADE; ALTER TABLE timetable_vsu.teacher ADD CONSTRAINT department_fk FOREIGN KEY (id_department) REFERENCES timetable_vsu.department (id) MATCH FULL -ON DELETE SET NULL ON UPDATE CASCADE; +ON DELETE CASCADE ON UPDATE CASCADE; @@ -93,9 +93,15 @@ CREATE TABLE timetable_vsu."group" ( id uuid NOT NULL DEFAULT uuid_generate_v4(), name text, type timetable_vsu.grouptype, + id_faculty uuid NOT NULL, CONSTRAINT group_pk PRIMARY KEY (id) ); +ALTER TABLE timetable_vsu.group DROP CONSTRAINT IF EXISTS group_faculty_fk CASCADE; +ALTER TABLE timetable_vsu.group ADD CONSTRAINT group_faculty_fk FOREIGN KEY (id_faculty) +REFERENCES timetable_vsu."faculty" (id) MATCH FULL +ON DELETE CASCADE ON UPDATE CASCADE; + DROP TABLE IF EXISTS timetable_vsu.group_stage CASCADE; @@ -104,7 +110,7 @@ CREATE TABLE timetable_vsu.group_stage ( begin timestamptz, "end" timestamptz, course smallint, - id_group uuid, + id_group uuid NOT NULL, CONSTRAINT group_stage_pk PRIMARY KEY (id) ); @@ -113,7 +119,7 @@ CREATE TABLE timetable_vsu.group_stage ( ALTER TABLE timetable_vsu.group_stage DROP CONSTRAINT IF EXISTS group_fk CASCADE; ALTER TABLE timetable_vsu.group_stage ADD CONSTRAINT group_fk FOREIGN KEY (id_group) REFERENCES timetable_vsu."group" (id) MATCH FULL -ON DELETE SET NULL ON UPDATE CASCADE; +ON DELETE CASCADE ON UPDATE CASCADE; @@ -159,8 +165,8 @@ CREATE TABLE timetable_vsu.lesson ( type_week timetable_vsu.type_of_week, subgroup timetable_vsu.subgroup, day timetable_vsu.day, - id_room uuid, - id_shedule uuid, + id_room uuid NOT NULL, + id_shedule uuid NOT NULL, CONSTRAINT lesson_pk PRIMARY KEY (id) ); @@ -180,16 +186,16 @@ CREATE TABLE timetable_vsu.subject ( ALTER TABLE timetable_vsu.lesson DROP CONSTRAINT IF EXISTS room_fk CASCADE; ALTER TABLE timetable_vsu.lesson ADD CONSTRAINT room_fk FOREIGN KEY (id_room) REFERENCES timetable_vsu.room (id) MATCH FULL -ON DELETE SET NULL ON UPDATE CASCADE; +ON DELETE CASCADE ON UPDATE CASCADE; DROP TABLE IF EXISTS timetable_vsu.shedule CASCADE; CREATE TABLE timetable_vsu.shedule ( id uuid NOT NULL DEFAULT uuid_generate_v4(), - id_teacher uuid, - id_subject uuid, - id_group_stage uuid, + id_teacher uuid NOT NULL, + id_subject uuid NOT NULL, + id_group_stage uuid NOT NULL, CONSTRAINT shedule_pk PRIMARY KEY (id) ); @@ -199,28 +205,28 @@ CREATE TABLE timetable_vsu.shedule ( ALTER TABLE timetable_vsu.shedule DROP CONSTRAINT IF EXISTS teacher_fk CASCADE; ALTER TABLE timetable_vsu.shedule ADD CONSTRAINT teacher_fk FOREIGN KEY (id_teacher) REFERENCES timetable_vsu.teacher (id) MATCH FULL -ON DELETE SET NULL ON UPDATE CASCADE; +ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE timetable_vsu.shedule DROP CONSTRAINT IF EXISTS subject_fk CASCADE; ALTER TABLE timetable_vsu.shedule ADD CONSTRAINT subject_fk FOREIGN KEY (id_subject) REFERENCES timetable_vsu.subject (id) MATCH FULL -ON DELETE SET NULL ON UPDATE CASCADE; +ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE timetable_vsu.shedule DROP CONSTRAINT IF EXISTS group_stage_fk CASCADE; ALTER TABLE timetable_vsu.shedule ADD CONSTRAINT group_stage_fk FOREIGN KEY (id_group_stage) REFERENCES timetable_vsu.group_stage (id) MATCH FULL -ON DELETE SET NULL ON UPDATE CASCADE; +ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE timetable_vsu.lesson DROP CONSTRAINT IF EXISTS shedule_fk CASCADE; ALTER TABLE timetable_vsu.lesson ADD CONSTRAINT shedule_fk FOREIGN KEY (id_shedule) REFERENCES timetable_vsu.shedule (id) MATCH FULL -ON DELETE SET NULL ON UPDATE CASCADE; +ON DELETE CASCADE ON UPDATE CASCADE; @@ -238,13 +244,13 @@ CREATE TABLE timetable_vsu.teacher_link ( ALTER TABLE timetable_vsu.teacher_link DROP CONSTRAINT IF EXISTS user_fk CASCADE; ALTER TABLE timetable_vsu.teacher_link ADD CONSTRAINT user_fk FOREIGN KEY (id_user) REFERENCES timetable_vsu."user" (id) MATCH FULL -ON DELETE SET NULL ON UPDATE CASCADE; +ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE timetable_vsu.teacher_link DROP CONSTRAINT IF EXISTS teacher_fk CASCADE; ALTER TABLE timetable_vsu.teacher_link ADD CONSTRAINT teacher_fk FOREIGN KEY (id_teacher) REFERENCES timetable_vsu.teacher (id) MATCH FULL -ON DELETE SET NULL ON UPDATE CASCADE; +ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE timetable_vsu.teacher_link DROP CONSTRAINT IF EXISTS teacher_link_user_unique CASCADE; diff --git a/postgresql/schemas/db_1/012_add_teacher_info.sql b/postgresql/schemas/db_1/012_add_teacher_info.sql new file mode 100644 index 00000000..43e02bde --- /dev/null +++ b/postgresql/schemas/db_1/012_add_teacher_info.sql @@ -0,0 +1,11 @@ +BEGIN; + +DROP TYPE IF EXISTS timetable_vsu.teacher_info; +CREATE TYPE timetable_vsu.teacher_info AS +( + fio text, + bio text, + id_department uuid +); + +COMMIT; diff --git a/postgresql/schemas/db_1/013_add_faculty.sql b/postgresql/schemas/db_1/013_add_faculty.sql new file mode 100644 index 00000000..12882be9 --- /dev/null +++ b/postgresql/schemas/db_1/013_add_faculty.sql @@ -0,0 +1,17 @@ +BEGIN; + +DROP TYPE IF EXISTS timetable_vsu.faculty_tuple; +CREATE TYPE timetable_vsu.faculty_tuple AS +( + id uuid, + name text +); + +DROP TYPE IF EXISTS timetable_vsu.faculty_filter; +CREATE TYPE timetable_vsu.faculty_filter AS +( + ids text[], + names text[] +); + +COMMIT; diff --git a/postgresql/schemas/db_1/014_add_group_stage_filter.sql b/postgresql/schemas/db_1/014_add_group_stage_filter.sql new file mode 100644 index 00000000..811787a8 --- /dev/null +++ b/postgresql/schemas/db_1/014_add_group_stage_filter.sql @@ -0,0 +1,17 @@ +BEGIN; + +DROP TYPE IF EXISTS timetable_vsu.group_stage_filter; +CREATE TYPE timetable_vsu.group_stage_filter AS +( + group_stage_ids text[], + group_stage_courses SMALLINT[], + group_stage_begin timestamptz, + group_stage_end timestamptz, + group_ids text[], + group_names text[], + group_types timetable_vsu.grouptype[], + faculty_ids text[], + faculty_names text[] +); + +COMMIT; diff --git a/service/main.cpp b/service/main.cpp index 05460454..c0268fe3 100644 --- a/service/main.cpp +++ b/service/main.cpp @@ -11,18 +11,57 @@ #include #include "components/controllers/postgres/admin/fwd.hpp" +#include "components/controllers/postgres/faculty/fwd.hpp" +#include "components/controllers/postgres/group_stage/fwd.hpp" #include "components/controllers/postgres/lesson/fwd.hpp" #include "components/controllers/postgres/teacher/fwd.hpp" #include "components/controllers/postgres/token/fwd.hpp" #include "components/controllers/postgres/user/fwd.hpp" #include "views/admin/create/view.hpp" #include "views/admin/list/view.hpp" +#include "views/faculty/list/view.hpp" +#include "views/group-stage/list/view.hpp" #include "views/hello/view.hpp" #include "views/login/view.hpp" #include "views/register/view.hpp" +#include "views/teacher/create/view.hpp" #include "views/teacher/list/view.hpp" +#include "views/teacher/request/approve/link/view.hpp" +#include "views/teacher/request/approve/new/view.hpp" +#include "views/teacher/request/list/view.hpp" #include "views/timetable/get/view.hpp" +using namespace timetable_vsu_backend; + +void AppendPgControllers(userver::components::ComponentList& component_list) +{ + using namespace components::controllers::postgres; + user::Append(component_list); + token::Append(component_list); + lesson::Append(component_list); + admin::Append(component_list); + teacher::Append(component_list); + faculty::Append(component_list); + group_stage::Append(component_list); +} + +void AppendViews(userver::components::ComponentList& component_list) +{ + using namespace views; + login::Append(component_list); + register_::Append(component_list); + timetable::get::Append(component_list); + admin::create::Append(component_list); + admin::list::Append(component_list); + teacher::list::Append(component_list); + teacher::create::Append(component_list); + teacher::requests::list::Append(component_list); + teacher::requests::approve::link::Append(component_list); + teacher::requests::approve::new_::Append(component_list); + faculty::list::Append(component_list); + group::stage::list::Append(component_list); +} + int main(int argc, char* argv[]) { using namespace timetable_vsu_backend; @@ -35,17 +74,8 @@ int main(int argc, char* argv[]) .Append("postgres-db-1") .Append(); service_template::AppendHello(component_list); - views::login::Append(component_list); - views::register_::Append(component_list); - views::timetable::get::Append(component_list); - views::admin::create::Append(component_list); - views::admin::list::Append(component_list); - views::teacher::list::Append(component_list); - components::controllers::postgres::AppendUserController(component_list); - components::controllers::postgres::AppendTokenController(component_list); - components::controllers::postgres::AppendLessonDetailsController( - component_list); - components::controllers::postgres::AppendAdminController(component_list); - components::controllers::postgres::AppendTeacherController(component_list); + AppendPgControllers(component_list); + AppendViews(component_list); + return userver::utils::DaemonMain(argc, argv, component_list); } diff --git a/src/components/controllers/postgres/admin/fwd.cpp b/src/components/controllers/postgres/admin/fwd.cpp index 122d2796..15bb8d4f 100644 --- a/src/components/controllers/postgres/admin/fwd.cpp +++ b/src/components/controllers/postgres/admin/fwd.cpp @@ -4,10 +4,10 @@ #include "controller.hpp" -namespace timetable_vsu_backend::components::controllers::postgres +namespace timetable_vsu_backend::components::controllers::postgres::admin { -void AppendAdminController(userver::components::ComponentList& component_list) +void Append(userver::components::ComponentList& component_list) { - component_list.Append(); + component_list.Append(); } -} // namespace timetable_vsu_backend::components::controllers::postgres +} // namespace timetable_vsu_backend::components::controllers::postgres::admin diff --git a/src/components/controllers/postgres/admin/fwd.hpp b/src/components/controllers/postgres/admin/fwd.hpp index adebc89c..e2b9f59f 100644 --- a/src/components/controllers/postgres/admin/fwd.hpp +++ b/src/components/controllers/postgres/admin/fwd.hpp @@ -1,11 +1,8 @@ #pragma once #include "utils/component_list_fwd.hpp" -namespace timetable_vsu_backend::components::controllers::postgres -{ -namespace admin +namespace timetable_vsu_backend::components::controllers::postgres::admin { class Controller; -} -void AppendAdminController(userver::components::ComponentList& component_list); -} // namespace timetable_vsu_backend::components::controllers::postgres +void Append(userver::components::ComponentList& component_list); +} // namespace timetable_vsu_backend::components::controllers::postgres::admin diff --git a/src/components/controllers/postgres/faculty/controller.cpp b/src/components/controllers/postgres/faculty/controller.cpp new file mode 100644 index 00000000..638931d4 --- /dev/null +++ b/src/components/controllers/postgres/faculty/controller.cpp @@ -0,0 +1,61 @@ +#include "controller.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "models/admin_account/postgre.hpp" +#include "models/admin_filter/postgre.hpp" +#include "models/faculty/type.hpp" +#include "models/faculty_filter/postgre.hpp" +#include "models/request_privileges/type.hpp" +#include "models/subgroup/serialize.hpp" +#include "models/substring/postgre.hpp" +#include "models/user_credentials/postgre.hpp" +#include "sql_queries.hpp" +#include "userver/storages/postgres/exceptions.hpp" +#include "utils/convert/drop_properties_ref.hpp" +#include "utils/postgres_helper.hpp" +#include "utils/shared_transaction.hpp" + +namespace timetable_vsu_backend::components::controllers::postgres::faculty +{ +timetable_vsu_backend::utils::SharedTransaction Controller::CreateTransaction() +{ + return timetable_vsu_backend::utils::MakeSharedTransaction(pg_cluster_); +} +Controller::Controller(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : LoggableComponentBase(config, context), + pg_cluster_( + context.FindComponent("postgres-db-1") + .GetCluster()) +{ +} + +std::vector Controller::GetByFilter( + const std::optional& filter, + utils::SharedTransaction transaction) const +{ + utils::FillSharedTransaction(transaction, pg_cluster_); + auto pg_result = + utils::PgExecute(transaction, sql::qGetFacultiesByFilter, filter); + return utils::ConvertPgResultToArray(pg_result); +} + +} // namespace + // timetable_vsu_backend::components::controllers::postgres::faculty diff --git a/src/components/controllers/postgres/faculty/controller.hpp b/src/components/controllers/postgres/faculty/controller.hpp new file mode 100644 index 00000000..13d31c91 --- /dev/null +++ b/src/components/controllers/postgres/faculty/controller.hpp @@ -0,0 +1,38 @@ +#pragma once +#include +#include +#include +#include +#include + +#include "models/faculty/type.hpp" +#include "models/faculty_filter/type.hpp" +#include "models/request_privileges/type.hpp" +#include "models/teacher/type.hpp" +#include "models/teacher_filter/type.hpp" +#include "models/teacher_info/type.hpp" +#include "utils/shared_transaction.hpp" + +namespace timetable_vsu_backend::components::controllers::postgres::faculty +{ +class Controller final : public userver::components::LoggableComponentBase +{ + public: + using userver::components::LoggableComponentBase::LoggableComponentBase; + static constexpr inline std::string_view kName = "faculty_controller"; + + Controller(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context); + + std::vector GetByFilter( + const std::optional& filter, + utils::SharedTransaction transaction = nullptr) const; + + public: + timetable_vsu_backend::utils::SharedTransaction CreateTransaction(); + + protected: + userver::storages::postgres::ClusterPtr pg_cluster_; +}; +} // namespace + // timetable_vsu_backend::components::controllers::postgres::faculty diff --git a/src/components/controllers/postgres/faculty/fwd.cpp b/src/components/controllers/postgres/faculty/fwd.cpp new file mode 100644 index 00000000..b69fbd5e --- /dev/null +++ b/src/components/controllers/postgres/faculty/fwd.cpp @@ -0,0 +1,14 @@ +#include "fwd.hpp" + +#include + +#include "controller.hpp" + +namespace timetable_vsu_backend::components::controllers::postgres::faculty +{ +void Append(userver::components::ComponentList& component_list) +{ + component_list.Append(); +} +} // namespace + // timetable_vsu_backend::components::controllers::postgres::faculty diff --git a/src/components/controllers/postgres/faculty/fwd.hpp b/src/components/controllers/postgres/faculty/fwd.hpp new file mode 100644 index 00000000..a1df9981 --- /dev/null +++ b/src/components/controllers/postgres/faculty/fwd.hpp @@ -0,0 +1,9 @@ +#pragma once +#include "utils/component_list_fwd.hpp" + +namespace timetable_vsu_backend::components::controllers::postgres::faculty +{ +class Controller; +void Append(userver::components::ComponentList& component_list); +} // namespace + // timetable_vsu_backend::components::controllers::postgres::faculty diff --git a/src/components/controllers/postgres/faculty/sql_queries.hpp b/src/components/controllers/postgres/faculty/sql_queries.hpp new file mode 100644 index 00000000..762b273b --- /dev/null +++ b/src/components/controllers/postgres/faculty/sql_queries.hpp @@ -0,0 +1,16 @@ +#pragma once +#include + +namespace timetable_vsu_backend::components::controllers::postgres::faculty::sql +{ +const userver::storages::postgres::Query qGetFacultiesByFilter(R"( + SELECT + id, + name + FROM timetable_vsu.faculty + WHERE + ($1.ids IS null OR id::text ILIKE ANY($1.ids)) and + ($1.names IS null OR name ILIKE ANY($1.names)) + ; + )"); +} diff --git a/src/components/controllers/postgres/group_stage/controller.cpp b/src/components/controllers/postgres/group_stage/controller.cpp new file mode 100644 index 00000000..998e410f --- /dev/null +++ b/src/components/controllers/postgres/group_stage/controller.cpp @@ -0,0 +1,61 @@ +#include "controller.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "models/admin_account/postgre.hpp" +#include "models/admin_filter/postgre.hpp" +#include "models/group_stage/type.hpp" +#include "models/group_stage_filter/postgre.hpp" +#include "models/request_privileges/type.hpp" +#include "models/subgroup/serialize.hpp" +#include "models/substring/postgre.hpp" +#include "models/user_credentials/postgre.hpp" +#include "sql_queries.hpp" +#include "userver/storages/postgres/exceptions.hpp" +#include "utils/convert/drop_properties_ref.hpp" +#include "utils/postgres_helper.hpp" +#include "utils/shared_transaction.hpp" + +namespace timetable_vsu_backend::components::controllers::postgres::group_stage +{ +timetable_vsu_backend::utils::SharedTransaction Controller::CreateTransaction() +{ + return timetable_vsu_backend::utils::MakeSharedTransaction(pg_cluster_); +} +Controller::Controller(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : LoggableComponentBase(config, context), + pg_cluster_( + context.FindComponent("postgres-db-1") + .GetCluster()) +{ +} + +std::vector Controller::GetByFilter( + const std::optional& filter, + utils::SharedTransaction transaction) const +{ + utils::FillSharedTransaction(transaction, pg_cluster_); + auto pg_result = + utils::PgExecute(transaction, sql::qGetGroupStages, filter); + return utils::ConvertPgResultToArray(pg_result); +} + +} // namespace + // timetable_vsu_backend::components::controllers::postgres::group_stage diff --git a/src/components/controllers/postgres/group_stage/controller.hpp b/src/components/controllers/postgres/group_stage/controller.hpp new file mode 100644 index 00000000..0a2f5c6f --- /dev/null +++ b/src/components/controllers/postgres/group_stage/controller.hpp @@ -0,0 +1,38 @@ +#pragma once +#include +#include +#include +#include +#include + +#include "models/group_stage/type.hpp" +#include "models/group_stage_filter/type.hpp" +#include "models/request_privileges/type.hpp" +#include "models/teacher/type.hpp" +#include "models/teacher_filter/type.hpp" +#include "models/teacher_info/type.hpp" +#include "utils/shared_transaction.hpp" + +namespace timetable_vsu_backend::components::controllers::postgres::group_stage +{ +class Controller final : public userver::components::LoggableComponentBase +{ + public: + using userver::components::LoggableComponentBase::LoggableComponentBase; + static constexpr inline std::string_view kName = "group_stage_controller"; + + Controller(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context); + + std::vector GetByFilter( + const std::optional& filter, + utils::SharedTransaction transaction = nullptr) const; + + public: + timetable_vsu_backend::utils::SharedTransaction CreateTransaction(); + + protected: + userver::storages::postgres::ClusterPtr pg_cluster_; +}; +} // namespace + // timetable_vsu_backend::components::controllers::postgres::group_stage diff --git a/src/components/controllers/postgres/group_stage/fwd.cpp b/src/components/controllers/postgres/group_stage/fwd.cpp new file mode 100644 index 00000000..a29d0890 --- /dev/null +++ b/src/components/controllers/postgres/group_stage/fwd.cpp @@ -0,0 +1,14 @@ +#include "fwd.hpp" + +#include + +#include "controller.hpp" + +namespace timetable_vsu_backend::components::controllers::postgres::group_stage +{ +void Append(userver::components::ComponentList& component_list) +{ + component_list.Append(); +} +} // namespace + // timetable_vsu_backend::components::controllers::postgres::group_stage diff --git a/src/components/controllers/postgres/group_stage/fwd.hpp b/src/components/controllers/postgres/group_stage/fwd.hpp new file mode 100644 index 00000000..a4da7932 --- /dev/null +++ b/src/components/controllers/postgres/group_stage/fwd.hpp @@ -0,0 +1,9 @@ +#pragma once +#include "utils/component_list_fwd.hpp" + +namespace timetable_vsu_backend::components::controllers::postgres::group_stage +{ +class Controller; +void Append(userver::components::ComponentList& component_list); +} // namespace + // timetable_vsu_backend::components::controllers::postgres::group_stage diff --git a/src/components/controllers/postgres/group_stage/sql_queries.hpp b/src/components/controllers/postgres/group_stage/sql_queries.hpp new file mode 100644 index 00000000..d46b6e38 --- /dev/null +++ b/src/components/controllers/postgres/group_stage/sql_queries.hpp @@ -0,0 +1,45 @@ +#pragma once +#include + +namespace timetable_vsu_backend::components::controllers::postgres:: + group_stage::sql +{ +const userver::storages::postgres::Query qGetGroupStages(R"( + WITH group_stages_info AS(SELECT + gs.id AS group_stage_id, + gs.course AS group_stage_course, + gs.begin AS group_stage_begin, + gs."end" AS group_stage_end, + g.id AS group_id, + g.name AS group_name, + g.type AS group_type, + f.id AS faculty_id, + f.name AS faculty_name + FROM timetable_vsu.group_stage AS gs + LEFT JOIN timetable_vsu.group AS g ON gs.id_group = g.id + LEFT JOIN timetable_vsu.faculty AS f ON g.id_faculty = f.id + ) + SELECT + group_stage_id, + group_stage_course, + group_stage_begin, + group_stage_end, + group_id, + group_name, + group_type, + faculty_id, + faculty_name + FROM group_stages_info + WHERE + ($1.group_stage_ids IS null OR group_stage_id::text ILIKE ANY($1.group_stage_ids)) and + ($1.group_stage_courses IS null or group_stage_course = ANY($1.group_stage_courses)) and + ($1.group_stage_begin IS null OR $1.group_stage_begin <= group_stage_end) and + ($1.group_stage_end IS null OR $1.group_stage_end >= group_stage_begin) and + ($1.group_ids IS null OR group_id::text ILIKE ANY($1.group_ids)) and + ($1.group_names IS null OR group_name ILIKE ANY($1.group_names)) and + ($1.group_types IS null OR group_type = ANY($1.group_types)) and + ($1.faculty_ids IS null OR faculty_id::text ILIKE ANY($1.faculty_ids)) and + ($1.faculty_names IS null OR faculty_name ILIKE ANY($1.faculty_names)) + ; + )"); +} diff --git a/src/components/controllers/postgres/lesson/fwd.cpp b/src/components/controllers/postgres/lesson/fwd.cpp index 39a54267..1a1f8036 100644 --- a/src/components/controllers/postgres/lesson/fwd.cpp +++ b/src/components/controllers/postgres/lesson/fwd.cpp @@ -4,11 +4,10 @@ #include "controller.hpp" -namespace timetable_vsu_backend::components::controllers::postgres +namespace timetable_vsu_backend::components::controllers::postgres::lesson { -void AppendLessonDetailsController( - userver::components::ComponentList& component_list) +void Append(userver::components::ComponentList& component_list) { - component_list.Append(); + component_list.Append(); } -} // namespace timetable_vsu_backend::components::controllers::postgres +} // namespace timetable_vsu_backend::components::controllers::postgres::lesson diff --git a/src/components/controllers/postgres/lesson/fwd.hpp b/src/components/controllers/postgres/lesson/fwd.hpp index 7cb4daee..27c17bd1 100644 --- a/src/components/controllers/postgres/lesson/fwd.hpp +++ b/src/components/controllers/postgres/lesson/fwd.hpp @@ -1,12 +1,8 @@ #pragma once #include "utils/component_list_fwd.hpp" -namespace timetable_vsu_backend::components::controllers::postgres -{ -namespace lesson +namespace timetable_vsu_backend::components::controllers::postgres::lesson { class Controller; -} -void AppendLessonDetailsController( - userver::components::ComponentList& component_list); -} // namespace timetable_vsu_backend::components::controllers::postgres +void Append(userver::components::ComponentList& component_list); +} // namespace timetable_vsu_backend::components::controllers::postgres::lesson diff --git a/src/components/controllers/postgres/teacher/controller.cpp b/src/components/controllers/postgres/teacher/controller.cpp index 0a4765f0..20f3b234 100644 --- a/src/components/controllers/postgres/teacher/controller.cpp +++ b/src/components/controllers/postgres/teacher/controller.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -19,12 +20,15 @@ #include "models/admin_account/postgre.hpp" #include "models/admin_filter/postgre.hpp" +#include "models/request_privileges/type.hpp" #include "models/subgroup/serialize.hpp" #include "models/substring/postgre.hpp" #include "models/teacher/postgre.hpp" #include "models/teacher_filter/postgre.hpp" +#include "models/teacher_info/postgre.hpp" #include "models/user_credentials/postgre.hpp" #include "sql_queries.hpp" +#include "userver/storages/postgres/exceptions.hpp" #include "utils/convert/drop_properties_ref.hpp" #include "utils/postgres_helper.hpp" #include "utils/shared_transaction.hpp" @@ -54,5 +58,97 @@ std::vector Controller::GetByFilter( return utils::ConvertPgResultToArray(pg_result); } +std::optional Controller::CreateTeacher( + const models::TeacherInfo& teacher_info, + timetable_vsu_backend::utils::SharedTransaction transaction) const +{ + try + { + utils::FillSharedTransaction(transaction, pg_cluster_); + auto pg_result = + utils::PgExecute(transaction, sql::qCreateTeacher, teacher_info); + return utils::ConvertPgResultToItem(pg_result); + } + catch (std::exception& exc) + { + LOG_INFO() << fmt::format("Department id : {} not found", + to_string(teacher_info.department_id())); + return std::nullopt; + } +} + +std::optional Controller::ApproveAndLink( + const boost::uuids::uuid& request_id, const boost::uuids::uuid& teacher_id, + timetable_vsu_backend::utils::SharedTransaction transaction) const +{ + utils::FillSharedTransaction(transaction, pg_cluster_); + auto id_user = utils::ConvertPgResultToOptionalItem( + utils::PgExecute(transaction, sql::qGetUserIdFromRequest, request_id)); + if (!id_user) + { + return std::nullopt; + } + auto linked = Link(*id_user, teacher_id, transaction); + if (linked) + { + utils::PgExecute(transaction, sql::qDropRequestById, request_id); + } + return linked; +} + +std::optional Controller::Link( + const boost::uuids::uuid& user_id, const boost::uuids::uuid& teacher_id, + timetable_vsu_backend::utils::SharedTransaction transaction) const +{ + utils::FillSharedTransaction(transaction, pg_cluster_); + auto created = utils::PgSafeExecute(transaction, sql::qCreateLink, user_id, + teacher_id); + return utils::ConvertPgResultToOptionalItem(created); +} + +std::optional Controller::ApproveAndCreateAccount( + const boost::uuids::uuid& request_id, + const models::TeacherInfo& teacher_info, + timetable_vsu_backend::utils::SharedTransaction transaction) const +{ + utils::FillSharedTransaction(transaction, pg_cluster_); + auto id_user_result = + utils::PgExecute(transaction, sql::qGetUserIdFromRequest, request_id); + auto id_user = utils::ConvertPgResultToOptionalItem( + id_user_result); + if (!id_user) + { + return std::nullopt; + } + auto create_teacher_result = + utils::PgSafeExecute(transaction, sql::qCreateTeacher, teacher_info); + if (!create_teacher_result) + { + return std::nullopt; + } + auto created_teacher_id = utils::ConvertPgResultToItem( + create_teacher_result.value()); + utils::PgExecute(transaction, sql::qDropRequestById, request_id); + return Link(id_user.value(), created_teacher_id, transaction); +} + +std::vector Controller::GetAllRequests( + timetable_vsu_backend::utils::SharedTransaction transaction) const +{ + utils::FillSharedTransaction(transaction, pg_cluster_); + auto pg_result = utils::PgExecute(transaction, sql::qGetAllRequests); + return utils::ConvertPgResultToArray(pg_result); +} + +std::optional Controller::DropRequest( + const boost::uuids::uuid& request_id, + timetable_vsu_backend::utils::SharedTransaction transaction) const +{ + utils::FillSharedTransaction(transaction, pg_cluster_); + auto pg_result = + utils::PgExecute(transaction, sql::qDropRequestById, request_id); + return utils::ConvertPgResultToOptionalItem(pg_result); +} + } // namespace // timetable_vsu_backend::components::controllers::postgres::teacher diff --git a/src/components/controllers/postgres/teacher/controller.hpp b/src/components/controllers/postgres/teacher/controller.hpp index dcd79caa..179f7051 100644 --- a/src/components/controllers/postgres/teacher/controller.hpp +++ b/src/components/controllers/postgres/teacher/controller.hpp @@ -5,8 +5,10 @@ #include #include +#include "models/request_privileges/type.hpp" #include "models/teacher/type.hpp" #include "models/teacher_filter/type.hpp" +#include "models/teacher_info/type.hpp" #include "utils/shared_transaction.hpp" namespace timetable_vsu_backend::components::controllers::postgres::teacher @@ -16,12 +18,45 @@ class Controller final : public userver::components::LoggableComponentBase public: using userver::components::LoggableComponentBase::LoggableComponentBase; static constexpr inline std::string_view kName = "teacher_controller"; + Controller(const userver::components::ComponentConfig& config, const userver::components::ComponentContext& context); + + public: + std::optional DropRequest( + const boost::uuids::uuid& request_id, + timetable_vsu_backend::utils::SharedTransaction transaction = + nullptr) const; + std::vector GetAllRequests( + timetable_vsu_backend::utils::SharedTransaction transaction = + nullptr) const; + std::optional ApproveAndLink( + const boost::uuids::uuid& request_id, + const boost::uuids::uuid& teacher_id, + timetable_vsu_backend::utils::SharedTransaction transaction = + nullptr) const; + + std::optional ApproveAndCreateAccount( + const boost::uuids::uuid& request_id, + const models::TeacherInfo& teacher_info, + timetable_vsu_backend::utils::SharedTransaction transaction = + nullptr) const; + + std::optional Link( + const boost::uuids::uuid& user_id, const boost::uuids::uuid& teacher_id, + timetable_vsu_backend::utils::SharedTransaction transaction = + nullptr) const; + std::vector GetByFilter( std::optional& filter, timetable_vsu_backend::utils::SharedTransaction transaction = nullptr) const; + + std::optional CreateTeacher( + const models::TeacherInfo& teacher_info, + timetable_vsu_backend::utils::SharedTransaction transaction = + nullptr) const; + timetable_vsu_backend::utils::SharedTransaction CreateTransaction(); protected: diff --git a/src/components/controllers/postgres/teacher/fwd.cpp b/src/components/controllers/postgres/teacher/fwd.cpp index fc9840bd..2a231c4e 100644 --- a/src/components/controllers/postgres/teacher/fwd.cpp +++ b/src/components/controllers/postgres/teacher/fwd.cpp @@ -4,10 +4,11 @@ #include "controller.hpp" -namespace timetable_vsu_backend::components::controllers::postgres +namespace timetable_vsu_backend::components::controllers::postgres::teacher { -void AppendTeacherController(userver::components::ComponentList& component_list) +void Append(userver::components::ComponentList& component_list) { - component_list.Append(); + component_list.Append(); } -} // namespace timetable_vsu_backend::components::controllers::postgres +} // namespace + // timetable_vsu_backend::components::controllers::postgres::teacher diff --git a/src/components/controllers/postgres/teacher/fwd.hpp b/src/components/controllers/postgres/teacher/fwd.hpp index c284f55b..beb25640 100644 --- a/src/components/controllers/postgres/teacher/fwd.hpp +++ b/src/components/controllers/postgres/teacher/fwd.hpp @@ -6,7 +6,7 @@ namespace timetable_vsu_backend::components::controllers::postgres namespace teacher { class Controller; -} -void AppendTeacherController( - userver::components::ComponentList& component_list); +void Append(userver::components::ComponentList& component_list); +} // namespace teacher + } // namespace timetable_vsu_backend::components::controllers::postgres diff --git a/src/components/controllers/postgres/teacher/sql_queries.hpp b/src/components/controllers/postgres/teacher/sql_queries.hpp index 9eb4cb48..d20abeee 100644 --- a/src/components/controllers/postgres/teacher/sql_queries.hpp +++ b/src/components/controllers/postgres/teacher/sql_queries.hpp @@ -34,5 +34,26 @@ const userver::storages::postgres::Query qGetTeachersByFilter(R"( ($1.faculty_ids IS null OR faculty_id::text ILIKE ANY($1.faculty_ids)) and ($1.faculty_names IS null OR faculty_name ILIKE ANY($1.faculty_names)) ; + )"), + qCreateTeacher(R"( + INSERT INTO timetable_vsu.teacher(fio, bio, id_department) VALUES($1.fio, $1.bio, $1.id_department) + RETURNING id + ; + )"), + qGetUserIdFromRequest(R"( + SELECT id_user FROM timetable_vsu.teacher_requests WHERE id = $1 + )"), + qCreateLink(R"( + INSERT INTO timetable_vsu.teacher_link(id_user, id_teacher) VALUES($1, $2) + ON CONFLICT DO NOTHING + RETURNING id + )"), + qGetAllRequests(R"( + SELECT id, id_user, description FROM timetable_vsu.teacher_requests + )"), + qDropRequestById(R"( + DELETE FROM timetable_vsu.teacher_requests + WHERE id = $1 + RETURNING id )"); } diff --git a/src/components/controllers/postgres/token/fwd.cpp b/src/components/controllers/postgres/token/fwd.cpp index 9a7f2493..1cd2856b 100644 --- a/src/components/controllers/postgres/token/fwd.cpp +++ b/src/components/controllers/postgres/token/fwd.cpp @@ -4,10 +4,10 @@ #include "controller.hpp" -namespace timetable_vsu_backend::components::controllers::postgres +namespace timetable_vsu_backend::components::controllers::postgres::token { -void AppendTokenController(userver::components::ComponentList& component_list) +void Append(userver::components::ComponentList& component_list) { - component_list.Append(); + component_list.Append(); } -} // namespace timetable_vsu_backend::components::controllers::postgres +} // namespace timetable_vsu_backend::components::controllers::postgres::token diff --git a/src/components/controllers/postgres/token/fwd.hpp b/src/components/controllers/postgres/token/fwd.hpp index 5a222d14..44475546 100644 --- a/src/components/controllers/postgres/token/fwd.hpp +++ b/src/components/controllers/postgres/token/fwd.hpp @@ -5,6 +5,6 @@ namespace timetable_vsu_backend::components::controllers::postgres namespace token { class Controller; -} -void AppendTokenController(userver::components::ComponentList& component_list); +void Append(userver::components::ComponentList& component_list); +} // namespace token } // namespace timetable_vsu_backend::components::controllers::postgres diff --git a/src/components/controllers/postgres/user/fwd.cpp b/src/components/controllers/postgres/user/fwd.cpp index 99d58d27..d523988c 100644 --- a/src/components/controllers/postgres/user/fwd.cpp +++ b/src/components/controllers/postgres/user/fwd.cpp @@ -4,10 +4,10 @@ #include "controller.hpp" -namespace timetable_vsu_backend::components::controllers::postgres +namespace timetable_vsu_backend::components::controllers::postgres::user { -void AppendUserController(userver::components::ComponentList& component_list) +void Append(userver::components::ComponentList& component_list) { - component_list.Append(); + component_list.Append(); } -} // namespace timetable_vsu_backend::components::controllers::postgres +} // namespace timetable_vsu_backend::components::controllers::postgres::user diff --git a/src/components/controllers/postgres/user/fwd.hpp b/src/components/controllers/postgres/user/fwd.hpp index 74c832e7..09c3c0d7 100644 --- a/src/components/controllers/postgres/user/fwd.hpp +++ b/src/components/controllers/postgres/user/fwd.hpp @@ -5,7 +5,7 @@ namespace timetable_vsu_backend::components::controllers::postgres namespace user { class Controller; -} +void Append(userver::components::ComponentList& component_list); +} // namespace user -void AppendUserController(userver::components::ComponentList& component_list); } // namespace timetable_vsu_backend::components::controllers::postgres diff --git a/src/models/faculty/fwd.hpp b/src/models/faculty/fwd.hpp new file mode 100644 index 00000000..1cd026e1 --- /dev/null +++ b/src/models/faculty/fwd.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace timetable_vsu_backend::models +{ +struct Faculty; +} diff --git a/src/models/faculty/postgre.hpp b/src/models/faculty/postgre.hpp new file mode 100644 index 00000000..7fbbd4d5 --- /dev/null +++ b/src/models/faculty/postgre.hpp @@ -0,0 +1,20 @@ +#include + +#include "models/education_type/postgre.hpp" +#include "models/faculty/type.hpp" +#include "utils/convert/drop_properties_ref.hpp" +namespace timetable_vsu_backend::models +{ +using TupleFaculty = + timetable_vsu_backend::utils::convert::drop_properties_to_ref_const_t< + Faculty>; +} // namespace timetable_vsu_backend::models + +namespace userver::storages::postgres::io +{ +template <> +struct CppToUserPg +{ + static constexpr DBTypeName postgres_name = "timetable_vsu.faculty_tuple"; +}; +} // namespace userver::storages::postgres::io diff --git a/src/models/faculty/type.hpp b/src/models/faculty/type.hpp new file mode 100644 index 00000000..393df93b --- /dev/null +++ b/src/models/faculty/type.hpp @@ -0,0 +1,25 @@ +#pragma once +#include +#include +#include + +#include "models/day/type.hpp" +#include "models/education_type/type.hpp" +#include "models/lesson_type/type.hpp" +#include "models/lesson_week_type/type.hpp" +#include "models/subgroup/type.hpp" +#include "models/substring/type.hpp" +#include "models/timestring/type.hpp" +#include "utils/convert/additional_properties.hpp" + +namespace timetable_vsu_backend::models +{ +namespace convert = utils::convert; +struct Faculty +{ + convert::Property id; + convert::Property name; + static constexpr utils::convert::PolicyFields kPolicyFields = + utils::convert::PolicyFields::ConvertAll; +}; +} // namespace timetable_vsu_backend::models diff --git a/src/models/faculty_filter/fwd.hpp b/src/models/faculty_filter/fwd.hpp new file mode 100644 index 00000000..552ff2c7 --- /dev/null +++ b/src/models/faculty_filter/fwd.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace timetable_vsu_backend::models +{ +struct FacultyFilter; +} diff --git a/src/models/faculty_filter/postgre.hpp b/src/models/faculty_filter/postgre.hpp new file mode 100644 index 00000000..606f39e0 --- /dev/null +++ b/src/models/faculty_filter/postgre.hpp @@ -0,0 +1,20 @@ +#include + +#include "models/education_type/postgre.hpp" +#include "models/faculty_filter/type.hpp" +#include "utils/convert/drop_properties_ref.hpp" +namespace timetable_vsu_backend::models +{ +using TupleFacultyFilter = + timetable_vsu_backend::utils::convert::drop_properties_to_ref_const_t< + FacultyFilter>; +} // namespace timetable_vsu_backend::models + +namespace userver::storages::postgres::io +{ +template <> +struct CppToUserPg +{ + static constexpr DBTypeName postgres_name = "timetable_vsu.faculty_filter"; +}; +} // namespace userver::storages::postgres::io diff --git a/src/models/faculty_filter/type.hpp b/src/models/faculty_filter/type.hpp new file mode 100644 index 00000000..c6ebdbc9 --- /dev/null +++ b/src/models/faculty_filter/type.hpp @@ -0,0 +1,25 @@ +#pragma once +#include +#include +#include + +#include "models/day/type.hpp" +#include "models/education_type/type.hpp" +#include "models/lesson_type/type.hpp" +#include "models/lesson_week_type/type.hpp" +#include "models/subgroup/type.hpp" +#include "models/substring/type.hpp" +#include "models/timestring/type.hpp" +#include "utils/convert/additional_properties.hpp" + +namespace timetable_vsu_backend::models +{ +namespace convert = utils::convert; +struct FacultyFilter +{ + convert::OptionalArrayProperty ids; + convert::OptionalArrayProperty names; + static constexpr utils::convert::PolicyFields kPolicyFields = + utils::convert::PolicyFields::ConvertAll; +}; +} // namespace timetable_vsu_backend::models diff --git a/src/models/group_stage/fwd.hpp b/src/models/group_stage/fwd.hpp new file mode 100644 index 00000000..e3801fa7 --- /dev/null +++ b/src/models/group_stage/fwd.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace timetable_vsu_backend::models +{ +struct GroupStage; +} diff --git a/src/models/group_stage/postgre.hpp b/src/models/group_stage/postgre.hpp new file mode 100644 index 00000000..31e60456 --- /dev/null +++ b/src/models/group_stage/postgre.hpp @@ -0,0 +1,21 @@ +#include + +#include "models/education_type/postgre.hpp" +#include "models/group_stage/type.hpp" +#include "utils/convert/drop_properties_ref.hpp" +namespace timetable_vsu_backend::models +{ +using TupleGroupStage = + timetable_vsu_backend::utils::convert::drop_properties_to_ref_const_t< + GroupStage>; +} // namespace timetable_vsu_backend::models + +namespace userver::storages::postgres::io +{ +template <> +struct CppToUserPg +{ + static constexpr DBTypeName postgres_name = + "timetable_vsu.group_stage_tuple"; +}; +} // namespace userver::storages::postgres::io diff --git a/src/models/group_stage/type.hpp b/src/models/group_stage/type.hpp new file mode 100644 index 00000000..c508aaa9 --- /dev/null +++ b/src/models/group_stage/type.hpp @@ -0,0 +1,34 @@ +#pragma once +#include +#include +#include +#include + +#include "models/day/type.hpp" +#include "models/education_type/type.hpp" +#include "models/lesson_type/type.hpp" +#include "models/lesson_week_type/type.hpp" +#include "models/subgroup/type.hpp" +#include "models/substring/type.hpp" +#include "models/timestring/type.hpp" +#include "utils/convert/additional_properties.hpp" +#include "utils/convert/base.hpp" + +namespace timetable_vsu_backend::models +{ +namespace convert = utils::convert; +struct GroupStage +{ + convert::Property group_stage_id; + convert::Property group_stage_course; + convert::Property group_stage_begin; + convert::Property group_stage_end; + convert::Property group_id; + convert::Property group_name; + convert::Property group_type; + convert::Property faculty_id; + convert::Property faculty_name; + static constexpr utils::convert::PolicyFields kPolicyFields = + utils::convert::PolicyFields::ConvertAll; +}; +} // namespace timetable_vsu_backend::models diff --git a/src/models/group_stage_filter/fwd.hpp b/src/models/group_stage_filter/fwd.hpp new file mode 100644 index 00000000..cbaf2290 --- /dev/null +++ b/src/models/group_stage_filter/fwd.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace timetable_vsu_backend::models +{ +struct GroupStageFilter; +} diff --git a/src/models/group_stage_filter/postgre.hpp b/src/models/group_stage_filter/postgre.hpp new file mode 100644 index 00000000..2672ea16 --- /dev/null +++ b/src/models/group_stage_filter/postgre.hpp @@ -0,0 +1,21 @@ +#include + +#include "models/education_type/postgre.hpp" +#include "models/group_stage_filter/type.hpp" +#include "utils/convert/drop_properties_ref.hpp" +namespace timetable_vsu_backend::models +{ +using TupleGroupStageFilter = + timetable_vsu_backend::utils::convert::drop_properties_to_ref_const_t< + GroupStageFilter>; +} // namespace timetable_vsu_backend::models + +namespace userver::storages::postgres::io +{ +template <> +struct CppToUserPg +{ + static constexpr DBTypeName postgres_name = + "timetable_vsu.group_stage_filter"; +}; +} // namespace userver::storages::postgres::io diff --git a/src/models/group_stage_filter/type.hpp b/src/models/group_stage_filter/type.hpp new file mode 100644 index 00000000..8dca42a1 --- /dev/null +++ b/src/models/group_stage_filter/type.hpp @@ -0,0 +1,36 @@ +#pragma once +#include +#include +#include +#include + +#include "models/day/type.hpp" +#include "models/education_type/type.hpp" +#include "models/lesson_type/type.hpp" +#include "models/lesson_week_type/type.hpp" +#include "models/subgroup/type.hpp" +#include "models/substring/type.hpp" +#include "models/timestring/type.hpp" +#include "utils/convert/additional_properties.hpp" + +namespace timetable_vsu_backend::models +{ +namespace convert = utils::convert; +struct GroupStageFilter +{ + convert::OptionalArrayProperty + group_stage_ids; + convert::OptionalArrayProperty + group_stage_courses; + convert::OptionalProperty + group_stage_begin; + convert::OptionalProperty group_stage_end; + convert::OptionalArrayProperty group_ids; + convert::OptionalArrayProperty group_names; + convert::OptionalArrayProperty group_types; + convert::OptionalArrayProperty faculty_ids; + convert::OptionalArrayProperty faculty_names; + static constexpr utils::convert::PolicyFields kPolicyFields = + utils::convert::PolicyFields::ConvertAll; +}; +} // namespace timetable_vsu_backend::models diff --git a/src/models/request_privileges/fwd.hpp b/src/models/request_privileges/fwd.hpp new file mode 100644 index 00000000..47c7c3c0 --- /dev/null +++ b/src/models/request_privileges/fwd.hpp @@ -0,0 +1,5 @@ +#pragma once +namespace timetable_vsu_backend::models +{ +struct RequestPrivileges; +} diff --git a/src/models/request_privileges/type.hpp b/src/models/request_privileges/type.hpp new file mode 100644 index 00000000..abb4f6fb --- /dev/null +++ b/src/models/request_privileges/type.hpp @@ -0,0 +1,15 @@ +#pragma once +#include + +#include "utils/convert/base.hpp" +namespace timetable_vsu_backend::models +{ +struct RequestPrivileges +{ + utils::convert::Property request_id; + utils::convert::Property user_id; + utils::convert::Property description; + static constexpr utils::convert::PolicyFields kPolicyFields = + utils::convert::PolicyFields::ConvertAll; +}; +} // namespace timetable_vsu_backend::models diff --git a/src/models/teacher_info/parse.hpp b/src/models/teacher_info/parse.hpp new file mode 100644 index 00000000..37de745d --- /dev/null +++ b/src/models/teacher_info/parse.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "models/user_type/parse.hpp" diff --git a/src/models/teacher_info/postgre.hpp b/src/models/teacher_info/postgre.hpp new file mode 100644 index 00000000..5b3f8c21 --- /dev/null +++ b/src/models/teacher_info/postgre.hpp @@ -0,0 +1,22 @@ +#pragma once +#include +#include + +#include "models/teacher_info/type.hpp" +#include "utils/convert/drop_properties_ref.hpp" +namespace timetable_vsu_backend::models +{ +using ConstTupleTeacherInfo = + timetable_vsu_backend::utils::convert::drop_properties_to_ref_const_t< + TeacherInfo>; + +} // namespace timetable_vsu_backend::models + +namespace userver::storages::postgres::io +{ +template <> +struct CppToUserPg +{ + static constexpr DBTypeName postgres_name = "timetable_vsu.teacher_info"; +}; +} // namespace userver::storages::postgres::io diff --git a/src/models/teacher_info/serialize.hpp b/src/models/teacher_info/serialize.hpp new file mode 100644 index 00000000..c4cb4166 --- /dev/null +++ b/src/models/teacher_info/serialize.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "utils/convert/json_serialize.hpp" diff --git a/src/models/teacher_info/type.hpp b/src/models/teacher_info/type.hpp new file mode 100644 index 00000000..067b2efc --- /dev/null +++ b/src/models/teacher_info/type.hpp @@ -0,0 +1,19 @@ +#pragma once +#include +#include + +#include "models/user_type/type.hpp" +#include "utils/convert/base.hpp" + +namespace timetable_vsu_backend::models +{ +namespace convert = utils::convert; +struct TeacherInfo +{ + convert::Property fio; + convert::Property bio; + convert::Property department_id; + static constexpr convert::PolicyFields kPolicyFields = + convert::PolicyFields::ConvertAll; +}; +} // namespace timetable_vsu_backend::models diff --git a/src/utils/common_errors.hpp b/src/utils/common_errors.hpp new file mode 100644 index 00000000..130238bb --- /dev/null +++ b/src/utils/common_errors.hpp @@ -0,0 +1,25 @@ +#pragma once +#include "http/ErrorV1.hpp" + +//Для большинства ошибок данного этого формата будет за глаза +namespace timetable_vsu_backend::utils::common_errors +{ +using Response400 = + http::ErrorV1; + +using Response401 = + http::ErrorV1; + +using Response403 = + http::ErrorV1; + +struct Response500 +{ + static constexpr convert::TypeOfBody kTypeOfBody = + convert::TypeOfBody::Empty; + static constexpr convert::PolicyFields kPolicyFields = + convert::PolicyFields::ConvertAll; + static constexpr userver::server::http::HttpStatus kStatusCode = + userver::server::http::HttpStatus::kInternalServerError; +}; +} // namespace timetable_vsu_backend::utils::common_errors diff --git a/src/utils/convert/detail/parse/converter_http_request.hpp b/src/utils/convert/detail/parse/converter_http_request.hpp index f5c64061..adbc05de 100644 --- a/src/utils/convert/detail/parse/converter_http_request.hpp +++ b/src/utils/convert/detail/parse/converter_http_request.hpp @@ -59,6 +59,7 @@ struct ConverterHttpRequest static_assert(flag, "Found property from body, but body marked empty"); }; + bad(); } //парсим поле из json тела template @@ -93,9 +94,9 @@ struct ConverterHttpRequest field = body[kName].template As(); } //парсим поле из query - template + template static void ParseField(const userver::server::http::HttpRequest& value, - const userver::formats::json::Value&, Field& field) + Body&, Field& field) { static constexpr std::string_view kName = Field::kName; using FieldValue = typename Field::value_type; @@ -121,9 +122,9 @@ struct ConverterHttpRequest } } //парсим поле из cookie - template + template static void ParseField(const userver::server::http::HttpRequest& value, - const userver::formats::json::Value&, Field& field) + const Body&, Field& field) { static constexpr std::string_view kName = Field::kName; using FieldValue = typename Field::value_type; @@ -149,9 +150,9 @@ struct ConverterHttpRequest } } //парсим поле из header - template + template static void ParseField(const userver::server::http::HttpRequest& value, - const userver::formats::json::Value&, Field& field) + const Body&, Field& field) { static constexpr std::string_view kName = Field::kName; using FieldValue = typename Field::value_type; diff --git a/src/utils/perform_common_errors.cpp b/src/utils/perform_common_errors.cpp new file mode 100644 index 00000000..1a04e833 --- /dev/null +++ b/src/utils/perform_common_errors.cpp @@ -0,0 +1,33 @@ +#include "perform_common_errors.hpp" + +namespace timetable_vsu_backend::utils::common_errors +{ +Response400 PerformLoginTaken() +{ + Response400 resp; + resp.description = "Account can't created: login is already taken"; + resp.machine_id = "LOGIN_TAKEN"; + return resp; +} +Response401 PerformInvalidToken() +{ + Response401 resp; + resp.description = "Account not founded: token invalid"; + resp.machine_id = "INVALID_TOKEN"; + return resp; +} +Response403 PerformForbidden() +{ + Response403 resp; + resp.description = "Not enough permissions to do so"; + resp.machine_id = "NOT_ENOUGH_PERMISSIONS"; + return resp; +} +Response400 PerformInvalidData(std::string_view message) +{ + Response400 resp; + resp.description = message; + resp.machine_id = "INVALID_DATA"; + return resp; +} +} // namespace timetable_vsu_backend::utils::common_errors diff --git a/src/utils/perform_common_errors.hpp b/src/utils/perform_common_errors.hpp new file mode 100644 index 00000000..dd1da084 --- /dev/null +++ b/src/utils/perform_common_errors.hpp @@ -0,0 +1,12 @@ +#pragma once +#include "common_errors.hpp" +namespace timetable_vsu_backend::utils::common_errors +{ +[[nodiscard]] Response400 PerformLoginTaken(); + +[[nodiscard]] Response401 PerformInvalidToken(); + +[[nodiscard]] Response403 PerformForbidden(); + +[[nodiscard]] Response400 PerformInvalidData(std::string_view message); +} // namespace timetable_vsu_backend::utils::common_errors diff --git a/src/utils/postgres_helper.hpp b/src/utils/postgres_helper.hpp index 05b9fc1b..dd577eb4 100644 --- a/src/utils/postgres_helper.hpp +++ b/src/utils/postgres_helper.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #include #include @@ -6,6 +7,7 @@ #include #include "convert/base.hpp" +#include "userver/logging/log.hpp" #include "userver/utils/meta.hpp" #include "utils/convert/drop_properties_ref.hpp" #include "utils/shared_transaction.hpp" @@ -84,6 +86,17 @@ std::optional ConvertPgResultToOptionalItem( return pg_result.AsSingleRow(); } +template +std::optional ConvertPgResultToOptionalItem( + const std::optional& pg_result) +{ + if (!pg_result) + { + return std::nullopt; + } + return ConvertPgResultToOptionalItem(pg_result.value()); +} + namespace details { //Небольшой хелпер, чтобы обобщить обработку рефлективных типов и нерефлективных @@ -113,4 +126,26 @@ userver::storages::postgres::ResultSet PgExecute( return transaction->transaction_.Execute(query, details::HelpForwardArg(args)...); } + +//обертка для повседневного использования магических структур +//так как было решено во всех контроллерах использовать shared transaction, то +//этого интерфейса достаточно +//Ловит все исключения, если было брошено исключение, то вернет std::nullopt +template +std::optional PgSafeExecute( + const timetable_vsu_backend::utils::SharedTransaction& transaction, + const userver::storages::postgres::Query& query, const Args&... args) +{ + try + { + return transaction->transaction_.Execute( + query, details::HelpForwardArg(args)...); + } + catch (std::exception& exc) + { + LOG_ERROR() << fmt::format( + "Throwed exception while executing query, message: {}", exc.what()); + return std::nullopt; + } +} } // namespace timetable_vsu_backend::utils diff --git a/src/views/admin/create/Responses.hpp b/src/views/admin/create/Responses.hpp index 3756b0bd..bbf6d94e 100644 --- a/src/views/admin/create/Responses.hpp +++ b/src/views/admin/create/Responses.hpp @@ -11,7 +11,7 @@ #include "utils/convert/base.hpp" #include "utils/convert/http_response_serialize.hpp" #include "utils/convert/json_parse.hpp" - +#include "utils/perform_common_errors.hpp" namespace timetable_vsu_backend::views::admin::create { using namespace utils::convert; @@ -25,20 +25,12 @@ struct Response200 userver::server::http::HttpStatus::kOk; }; -using Response400 = - http::ErrorV1; +using Response400 = utils::common_errors::Response400; -using Response401 = - http::ErrorV1; +using Response401 = utils::common_errors::Response401; -using Response403 = - http::ErrorV1; +using Response403 = utils::common_errors::Response403; + +using Response500 = utils::common_errors::Response500; -struct Response500 -{ - static constexpr TypeOfBody kTypeOfBody = TypeOfBody::Empty; - static constexpr PolicyFields kPolicyFields = PolicyFields::ConvertAll; - static constexpr userver::server::http::HttpStatus kStatusCode = - userver::server::http::HttpStatus::kInternalServerError; -}; } // namespace timetable_vsu_backend::views::admin::create diff --git a/src/views/admin/create/view.cpp b/src/views/admin/create/view.cpp index de6b5357..32b88c3c 100644 --- a/src/views/admin/create/view.cpp +++ b/src/views/admin/create/view.cpp @@ -28,28 +28,6 @@ class Handler final : public http::HandlerParsed { - static Response400 PerformLoginTaken() - { - Response400 resp; - resp.description = "Account can't created: login is already taken"; - resp.machine_id = "LOGIN_TAKEN"; - return resp; - } - static Response401 PerformInvalidToken() - { - Response401 resp; - resp.description = "Account not founded: token invalid"; - resp.machine_id = "INVALID_TOKEN"; - return resp; - } - static Response403 PerformForbidden() - { - Response403 resp; - resp.description = "Not enough permissions to do so"; - resp.machine_id = "NOT_ENOUGH_PERMISSIONS"; - return resp; - } - public: [[maybe_unused]] static constexpr std::string_view kName = "handler-admin-create"; @@ -66,16 +44,16 @@ class Handler final auto user = user_controller.GetByToken(request.token()); if (!user) { - return PerformInvalidToken(); + return utils::common_errors::PerformInvalidToken(); } if (user->type() != models::UserType::kRoot) { - return PerformForbidden(); + return utils::common_errors::PerformForbidden(); } auto admin = admin_controller.CreateAdmin(request.credentials()); if (!admin) { - return PerformLoginTaken(); + return utils::common_errors::PerformLoginTaken(); } Response200 resp; resp.created_account() = std::move(admin.value()); diff --git a/src/views/admin/list/Responses.hpp b/src/views/admin/list/Responses.hpp index 6d0471e8..6c3f4f8c 100644 --- a/src/views/admin/list/Responses.hpp +++ b/src/views/admin/list/Responses.hpp @@ -12,6 +12,7 @@ #include "utils/convert/base.hpp" #include "utils/convert/http_response_serialize.hpp" #include "utils/convert/json_parse.hpp" +#include "utils/perform_common_errors.hpp" namespace timetable_vsu_backend::views::admin::list { @@ -25,20 +26,11 @@ struct Response200 userver::server::http::HttpStatus::kOk; }; -using Response400 = - http::ErrorV1; +using Response400 = utils::common_errors::Response400; -using Response401 = - http::ErrorV1; +using Response401 = utils::common_errors::Response401; -using Response403 = - http::ErrorV1; +using Response403 = utils::common_errors::Response403; -struct Response500 -{ - static constexpr TypeOfBody kTypeOfBody = TypeOfBody::Empty; - static constexpr PolicyFields kPolicyFields = PolicyFields::ConvertAll; - static constexpr userver::server::http::HttpStatus kStatusCode = - userver::server::http::HttpStatus::kInternalServerError; -}; +using Response500 = utils::common_errors::Response500; } // namespace timetable_vsu_backend::views::admin::list diff --git a/src/views/admin/list/view.cpp b/src/views/admin/list/view.cpp index c3ee6656..58bd5c0f 100644 --- a/src/views/admin/list/view.cpp +++ b/src/views/admin/list/view.cpp @@ -30,28 +30,6 @@ class Handler final : public http::HandlerParsed { - static Response400 PerformLoginTaken() - { - Response400 resp; - resp.description = "Account can't created: login is already taken"; - resp.machine_id = "LOGIN_TAKEN"; - return resp; - } - static Response401 PerformInvalidToken() - { - Response401 resp; - resp.description = "Account not founded: token invalid"; - resp.machine_id = "INVALID_TOKEN"; - return resp; - } - static Response403 PerformForbidden() - { - Response403 resp; - resp.description = "Not enough permissions to do so"; - resp.machine_id = "NOT_ENOUGH_PERMISSIONS"; - return resp; - } - public: [[maybe_unused]] static constexpr std::string_view kName = "handler-admin-list"; @@ -68,11 +46,11 @@ class Handler final auto user = user_controller.GetByToken(request.token()); if (!user) { - return PerformInvalidToken(); + return utils::common_errors::PerformInvalidToken(); } if (user->type() != models::UserType::kRoot) { - return PerformForbidden(); + return utils::common_errors::PerformForbidden(); } auto admins = admin_controller.GetByFilter(request.filter()); Response200 resp; diff --git a/src/views/faculty/list/Request.hpp b/src/views/faculty/list/Request.hpp new file mode 100644 index 00000000..fd2b2307 --- /dev/null +++ b/src/views/faculty/list/Request.hpp @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include + +#include "models/faculty_filter/type.hpp" +#include "utils/convert/base.hpp" +#include "utils/convert/http_request_parse.hpp" +#include "utils/convert/json_parse.hpp" +#include "utils/parse/uuid/string.hpp" +namespace timetable_vsu_backend::views::faculty::list +{ +using namespace utils::convert; +struct Request +{ + OptionalProperty filter; + static constexpr auto kPolicyFields = PolicyFields::ConvertAll; + static constexpr TypeOfBody kTypeOfBody = + TypeOfBody::Json; //открываем возможность использовать структуру, как + //запрос +}; +} // namespace timetable_vsu_backend::views::faculty::list diff --git a/src/views/faculty/list/Responses.hpp b/src/views/faculty/list/Responses.hpp new file mode 100644 index 00000000..7e126d1a --- /dev/null +++ b/src/views/faculty/list/Responses.hpp @@ -0,0 +1,29 @@ +#pragma once +#include +#include +#include + +#include "http/ErrorV1.hpp" +#include "models/admin_account/type.hpp" +#include "models/faculty/type.hpp" +#include "models/user/type.hpp" +#include "models/user_type/serialize.hpp" +#include "models/user_type/type.hpp" +#include "utils/convert/additional_properties.hpp" +#include "utils/convert/base.hpp" +#include "utils/convert/http_response_serialize.hpp" +#include "utils/convert/json_parse.hpp" + +namespace timetable_vsu_backend::views::faculty::list +{ +using namespace utils::convert; +struct Response200 +{ + ArrayProperty faculties; + static constexpr TypeOfBody kTypeOfBody = TypeOfBody::Json; + static constexpr PolicyFields kPolicyFields = PolicyFields::ConvertAll; + static constexpr userver::server::http::HttpStatus kStatusCode = + userver::server::http::HttpStatus::kOk; +}; + +} // namespace timetable_vsu_backend::views::faculty::list diff --git a/src/views/faculty/list/view.cpp b/src/views/faculty/list/view.cpp new file mode 100644 index 00000000..86af0e99 --- /dev/null +++ b/src/views/faculty/list/view.cpp @@ -0,0 +1,55 @@ +#include "view.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Request.hpp" +#include "Responses.hpp" +#include "components/controllers/postgres/faculty/controller.hpp" +#include "http/handler_parsed.hpp" +#include "models/auth_token/serialize.hpp" +#include "models/user/serialize.hpp" +#include "models/user_type/serialize.hpp" +#include "utils/parse/uuid/string.hpp" +namespace timetable_vsu_backend::views::faculty::list +{ +namespace +{ +namespace pg = components::controllers::postgres; +class Handler final : public http::HandlerParsed +{ + public: + [[maybe_unused]] static constexpr std::string_view kName = + "handler-faculty-list"; + Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : HandlerParsed(config, context), + faculty_controller(context.FindComponent()) + { + } + + Response Handle(Request&& request) const override + { + auto faculties = faculty_controller.GetByFilter(request.filter()); + Response200 resp; + resp.faculties() = std::move(faculties); + return resp; + } + + private: + const pg::faculty::Controller& faculty_controller; +}; +} // namespace + +void Append(userver::components::ComponentList& component_list) +{ + component_list.Append(); +} + +} // namespace timetable_vsu_backend::views::faculty::list diff --git a/src/views/faculty/list/view.hpp b/src/views/faculty/list/view.hpp new file mode 100644 index 00000000..60e9fa06 --- /dev/null +++ b/src/views/faculty/list/view.hpp @@ -0,0 +1,7 @@ +#pragma once +#include "utils/component_list_fwd.hpp" +namespace timetable_vsu_backend::views::faculty::list +{ +void Append(userver::components::ComponentList& component_list); + +} diff --git a/src/views/group-stage/list/Request.hpp b/src/views/group-stage/list/Request.hpp new file mode 100644 index 00000000..61f594f0 --- /dev/null +++ b/src/views/group-stage/list/Request.hpp @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include + +#include "models/group_stage_filter/type.hpp" +#include "utils/convert/base.hpp" +#include "utils/convert/http_request_parse.hpp" +#include "utils/convert/json_parse.hpp" +#include "utils/parse/uuid/string.hpp" +namespace timetable_vsu_backend::views::group::stage::list +{ +using namespace utils::convert; +struct Request +{ + OptionalProperty filter; + static constexpr auto kPolicyFields = PolicyFields::ConvertAll; + static constexpr TypeOfBody kTypeOfBody = + TypeOfBody::Json; //открываем возможность использовать структуру, как + //запрос +}; +} // namespace timetable_vsu_backend::views::group::stage::list diff --git a/src/views/group-stage/list/Responses.hpp b/src/views/group-stage/list/Responses.hpp new file mode 100644 index 00000000..a34f7610 --- /dev/null +++ b/src/views/group-stage/list/Responses.hpp @@ -0,0 +1,30 @@ +#pragma once +#include +#include +#include + +#include "http/ErrorV1.hpp" +#include "models/admin_account/type.hpp" +#include "models/faculty/type.hpp" +#include "models/group_stage/type.hpp" +#include "models/user/type.hpp" +#include "models/user_type/serialize.hpp" +#include "models/user_type/type.hpp" +#include "utils/convert/additional_properties.hpp" +#include "utils/convert/base.hpp" +#include "utils/convert/http_response_serialize.hpp" +#include "utils/convert/json_parse.hpp" + +namespace timetable_vsu_backend::views::group::stage::list +{ +using namespace utils::convert; +struct Response200 +{ + ArrayProperty group_stages; + static constexpr TypeOfBody kTypeOfBody = TypeOfBody::Json; + static constexpr PolicyFields kPolicyFields = PolicyFields::ConvertAll; + static constexpr userver::server::http::HttpStatus kStatusCode = + userver::server::http::HttpStatus::kOk; +}; + +} // namespace timetable_vsu_backend::views::group::stage::list diff --git a/src/views/group-stage/list/view.cpp b/src/views/group-stage/list/view.cpp new file mode 100644 index 00000000..14a897e8 --- /dev/null +++ b/src/views/group-stage/list/view.cpp @@ -0,0 +1,59 @@ +#include "view.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Request.hpp" +#include "Responses.hpp" +#include "components/controllers/postgres/faculty/controller.hpp" +#include "components/controllers/postgres/group_stage/controller.hpp" +#include "http/handler_parsed.hpp" +#include "models/auth_token/serialize.hpp" +#include "models/education_type/all.hpp" +#include "models/user/serialize.hpp" +#include "models/user_type/serialize.hpp" +#include "utils/parse/uuid/string.hpp" +namespace timetable_vsu_backend::views::group::stage::list +{ +namespace +{ +namespace pg = components::controllers::postgres; +class Handler final : public http::HandlerParsed +{ + public: + [[maybe_unused]] static constexpr std::string_view kName = + "handler-group-stage-list"; + Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : HandlerParsed(config, context), + group_stage_controller( + context.FindComponent()) + { + } + + Response Handle(Request&& request) const override + { + auto group_stages = + group_stage_controller.GetByFilter(request.filter()); + Response200 resp; + resp.group_stages() = std::move(group_stages); + return resp; + } + + private: + const pg::group_stage::Controller& group_stage_controller; +}; +} // namespace + +void Append(userver::components::ComponentList& component_list) +{ + component_list.Append(); +} + +} // namespace timetable_vsu_backend::views::group::stage::list diff --git a/src/views/group-stage/list/view.hpp b/src/views/group-stage/list/view.hpp new file mode 100644 index 00000000..d71d5063 --- /dev/null +++ b/src/views/group-stage/list/view.hpp @@ -0,0 +1,7 @@ +#pragma once +#include "utils/component_list_fwd.hpp" +namespace timetable_vsu_backend::views::group::stage::list +{ +void Append(userver::components::ComponentList& component_list); + +} diff --git a/src/views/teacher/create/Request.hpp b/src/views/teacher/create/Request.hpp new file mode 100644 index 00000000..feaaab30 --- /dev/null +++ b/src/views/teacher/create/Request.hpp @@ -0,0 +1,25 @@ +#pragma once +#include +#include +#include + +#include "models/auth_token/type.hpp" +#include "models/teacher_info/type.hpp" +#include "utils/convert/additional_properties.hpp" +#include "utils/convert/base.hpp" +#include "utils/convert/http_request_parse.hpp" +#include "utils/convert/json_parse.hpp" +#include "utils/parse/uuid/string.hpp" +namespace timetable_vsu_backend::views::teacher::create +{ +using namespace utils::convert; +struct Request +{ + Property teacher_info; + HeaderProperty token; + static constexpr auto kPolicyFields = PolicyFields::ConvertAll; + static constexpr TypeOfBody kTypeOfBody = + TypeOfBody::Json; //открываем возможность использовать структуру, как + //запрос +}; +} // namespace timetable_vsu_backend::views::teacher::create diff --git a/src/views/teacher/create/Responses.hpp b/src/views/teacher/create/Responses.hpp new file mode 100644 index 00000000..eacb02d3 --- /dev/null +++ b/src/views/teacher/create/Responses.hpp @@ -0,0 +1,34 @@ +#pragma once +#include +#include +#include + +#include "http/ErrorV1.hpp" +#include "models/admin_account/type.hpp" +#include "models/teacher/type.hpp" +#include "models/user/type.hpp" +#include "models/user_type/serialize.hpp" +#include "models/user_type/type.hpp" +#include "utils/convert/additional_properties.hpp" +#include "utils/convert/base.hpp" +#include "utils/convert/http_response_serialize.hpp" +#include "utils/convert/json_parse.hpp" +#include "utils/perform_common_errors.hpp" + +namespace timetable_vsu_backend::views::teacher::create +{ +using namespace utils::convert; +struct Response200 +{ + Property id_created_teacher; + static constexpr TypeOfBody kTypeOfBody = TypeOfBody::Json; + static constexpr PolicyFields kPolicyFields = PolicyFields::ConvertAll; + static constexpr userver::server::http::HttpStatus kStatusCode = + userver::server::http::HttpStatus::kOk; +}; + +using Response400 = utils::common_errors::Response400; +using Response401 = utils::common_errors::Response401; +using Response403 = utils::common_errors::Response403; + +} // namespace timetable_vsu_backend::views::teacher::create diff --git a/src/views/teacher/create/view.cpp b/src/views/teacher/create/view.cpp new file mode 100644 index 00000000..77877259 --- /dev/null +++ b/src/views/teacher/create/view.cpp @@ -0,0 +1,78 @@ +#include "view.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Request.hpp" +#include "Responses.hpp" +#include "components/controllers/postgres/teacher/controller.hpp" +#include "components/controllers/postgres/user/controller.hpp" +#include "http/handler_parsed.hpp" +#include "models/auth_token/serialize.hpp" +#include "models/user/serialize.hpp" +#include "models/user_type/serialize.hpp" +#include "models/user_type/type.hpp" +#include "utils/parse/uuid/string.hpp" +namespace timetable_vsu_backend::views::teacher::create +{ +namespace +{ +namespace pg = components::controllers::postgres; +class Handler final + : public http::HandlerParsed +{ + public: + [[maybe_unused]] static constexpr std::string_view kName = + "handler-teacher-create"; + Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : HandlerParsed(config, context), + teacher_controller(context.FindComponent()), + user_controller(context.FindComponent()) + { + } + + Response Handle(Request&& request) const override + { + auto user = user_controller.GetByToken(request.token()); + if (!user) + { + return utils::common_errors::PerformInvalidToken(); + } + if (user->type() == models::UserType::kUser || + user->type() == models::UserType::kTeacher) + { + return utils::common_errors::PerformForbidden(); + } + + auto teacher_id = + teacher_controller.CreateTeacher(request.teacher_info()); + + if (!teacher_id) + { + return utils::common_errors::PerformInvalidData( + "Can't create teacher: department_id is incorrect"); + } + + return Response200{.id_created_teacher = {teacher_id.value()}}; + } + + private: + const pg::teacher::Controller& teacher_controller; + const pg::user::Controller& user_controller; +}; +} // namespace + +void Append(userver::components::ComponentList& component_list) +{ + component_list.Append(); +} + +} // namespace timetable_vsu_backend::views::teacher::create diff --git a/src/views/teacher/create/view.hpp b/src/views/teacher/create/view.hpp new file mode 100644 index 00000000..4d754c4e --- /dev/null +++ b/src/views/teacher/create/view.hpp @@ -0,0 +1,7 @@ +#pragma once +#include "utils/component_list_fwd.hpp" +namespace timetable_vsu_backend::views::teacher::create +{ +void Append(userver::components::ComponentList& component_list); + +} diff --git a/src/views/teacher/request/approve/link/Request.hpp b/src/views/teacher/request/approve/link/Request.hpp new file mode 100644 index 00000000..410d55d6 --- /dev/null +++ b/src/views/teacher/request/approve/link/Request.hpp @@ -0,0 +1,23 @@ +#pragma once +#include +#include +#include + +#include "utils/convert/base.hpp" +#include "utils/convert/http_request_parse.hpp" +#include "utils/convert/json_parse.hpp" +#include "utils/parse/uuid/string.hpp" +namespace timetable_vsu_backend::views::teacher::requests::approve::link +{ +using namespace utils::convert; +struct Request +{ + HeaderProperty token; + Property teacher_id; + Property request_id; + static constexpr auto kPolicyFields = PolicyFields::ConvertAll; + static constexpr TypeOfBody kTypeOfBody = + TypeOfBody::Json; //открываем возможность использовать структуру, как + //запрос +}; +} // namespace timetable_vsu_backend::views::teacher::requests::approve::link diff --git a/src/views/teacher/request/approve/link/Responses.hpp b/src/views/teacher/request/approve/link/Responses.hpp new file mode 100644 index 00000000..d1ee8692 --- /dev/null +++ b/src/views/teacher/request/approve/link/Responses.hpp @@ -0,0 +1,37 @@ +#pragma once +#include +#include +#include + +#include "http/ErrorV1.hpp" +#include "models/admin_account/type.hpp" +#include "models/request_privileges/type.hpp" +#include "models/teacher/type.hpp" +#include "models/user/type.hpp" +#include "models/user_type/serialize.hpp" +#include "models/user_type/type.hpp" +#include "utils/common_errors.hpp" +#include "utils/convert/additional_properties.hpp" +#include "utils/convert/base.hpp" +#include "utils/convert/http_response_serialize.hpp" +#include "utils/convert/json_parse.hpp" + +namespace timetable_vsu_backend::views::teacher::requests::approve::link +{ +using namespace utils::convert; +struct Response200 +{ + Property link_id; + static constexpr TypeOfBody kTypeOfBody = TypeOfBody::Json; + static constexpr PolicyFields kPolicyFields = PolicyFields::ConvertAll; + static constexpr userver::server::http::HttpStatus kStatusCode = + userver::server::http::HttpStatus::kOk; +}; + +using Response400 = utils::common_errors::Response400; + +using Response401 = utils::common_errors::Response401; + +using Response403 = utils::common_errors::Response403; + +} // namespace timetable_vsu_backend::views::teacher::requests::approve::link diff --git a/src/views/teacher/request/approve/link/view.cpp b/src/views/teacher/request/approve/link/view.cpp new file mode 100644 index 00000000..010551dc --- /dev/null +++ b/src/views/teacher/request/approve/link/view.cpp @@ -0,0 +1,78 @@ +#include "view.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Request.hpp" +#include "Responses.hpp" +#include "components/controllers/postgres/teacher/controller.hpp" +#include "components/controllers/postgres/user/controller.hpp" +#include "http/handler_parsed.hpp" +#include "models/auth_token/serialize.hpp" +#include "models/user/serialize.hpp" +#include "models/user_type/serialize.hpp" +#include "models/user_type/type.hpp" +#include "userver/logging/log.hpp" +#include "utils/parse/uuid/string.hpp" +#include "utils/perform_common_errors.hpp" +namespace timetable_vsu_backend::views::teacher::requests::approve::link +{ +namespace +{ +namespace pg = components::controllers::postgres; +class Handler final + : public http::HandlerParsed +{ + public: + [[maybe_unused]] static constexpr std::string_view kName = + "handler-teacher-requests-approve-link"; + Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : HandlerParsed(config, context), + teacher_controller(context.FindComponent()), + user_controller(context.FindComponent()) + { + } + + Response Handle(Request&& request) const override + { + auto user = user_controller.GetByToken(request.token()); + if (!user) + { + return utils::common_errors::PerformInvalidToken(); + } + if (user->type() != models::UserType::kAdmin && + user->type() != models::UserType::kRoot) + { + return utils::common_errors::PerformForbidden(); + } + auto link_id = teacher_controller.ApproveAndLink(request.request_id(), + request.teacher_id()); + if (!link_id) + { + return utils::common_errors::PerformInvalidData( + "Request_id or teacher_id are incorrect"); + } + + return Response200{*link_id}; + } + + private: + const pg::teacher::Controller& teacher_controller; + const pg::user::Controller& user_controller; +}; +} // namespace + +void Append(userver::components::ComponentList& component_list) +{ + component_list.Append(); +} + +} // namespace timetable_vsu_backend::views::teacher::requests::approve::link diff --git a/src/views/teacher/request/approve/link/view.hpp b/src/views/teacher/request/approve/link/view.hpp new file mode 100644 index 00000000..68aa1995 --- /dev/null +++ b/src/views/teacher/request/approve/link/view.hpp @@ -0,0 +1,7 @@ +#pragma once +#include "utils/component_list_fwd.hpp" +namespace timetable_vsu_backend::views::teacher::requests::approve::link +{ +void Append(userver::components::ComponentList& component_list); + +} diff --git a/src/views/teacher/request/approve/new/Request.hpp b/src/views/teacher/request/approve/new/Request.hpp new file mode 100644 index 00000000..13e921e6 --- /dev/null +++ b/src/views/teacher/request/approve/new/Request.hpp @@ -0,0 +1,24 @@ +#pragma once +#include +#include +#include + +#include "models/teacher_info/type.hpp" +#include "utils/convert/base.hpp" +#include "utils/convert/http_request_parse.hpp" +#include "utils/convert/json_parse.hpp" +#include "utils/parse/uuid/string.hpp" +namespace timetable_vsu_backend::views::teacher::requests::approve::new_ +{ +using namespace utils::convert; +struct Request +{ + HeaderProperty token; + Property request_id; + Property teacher_info; + static constexpr auto kPolicyFields = PolicyFields::ConvertAll; + static constexpr TypeOfBody kTypeOfBody = + TypeOfBody::Json; //открываем возможность использовать структуру, + //как запрос +}; +} // namespace timetable_vsu_backend::views::teacher::requests::approve::new_ diff --git a/src/views/teacher/request/approve/new/Responses.hpp b/src/views/teacher/request/approve/new/Responses.hpp new file mode 100644 index 00000000..b4e477d5 --- /dev/null +++ b/src/views/teacher/request/approve/new/Responses.hpp @@ -0,0 +1,37 @@ +#pragma once +#include +#include +#include + +#include "http/ErrorV1.hpp" +#include "models/admin_account/type.hpp" +#include "models/request_privileges/type.hpp" +#include "models/teacher/type.hpp" +#include "models/user/type.hpp" +#include "models/user_type/serialize.hpp" +#include "models/user_type/type.hpp" +#include "utils/common_errors.hpp" +#include "utils/convert/additional_properties.hpp" +#include "utils/convert/base.hpp" +#include "utils/convert/http_response_serialize.hpp" +#include "utils/convert/json_parse.hpp" + +namespace timetable_vsu_backend::views::teacher::requests::approve::new_ +{ +using namespace utils::convert; +struct Response200 +{ + Property link_id; + static constexpr TypeOfBody kTypeOfBody = TypeOfBody::Json; + static constexpr PolicyFields kPolicyFields = PolicyFields::ConvertAll; + static constexpr userver::server::http::HttpStatus kStatusCode = + userver::server::http::HttpStatus::kOk; +}; + +using Response400 = utils::common_errors::Response400; + +using Response401 = utils::common_errors::Response401; + +using Response403 = utils::common_errors::Response403; + +} // namespace timetable_vsu_backend::views::teacher::requests::approve::new_ diff --git a/src/views/teacher/request/approve/new/view.cpp b/src/views/teacher/request/approve/new/view.cpp new file mode 100644 index 00000000..0277f34f --- /dev/null +++ b/src/views/teacher/request/approve/new/view.cpp @@ -0,0 +1,78 @@ +#include "view.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Request.hpp" +#include "Responses.hpp" +#include "components/controllers/postgres/teacher/controller.hpp" +#include "components/controllers/postgres/user/controller.hpp" +#include "http/handler_parsed.hpp" +#include "models/auth_token/serialize.hpp" +#include "models/user/serialize.hpp" +#include "models/user_type/serialize.hpp" +#include "models/user_type/type.hpp" +#include "userver/logging/log.hpp" +#include "utils/parse/uuid/string.hpp" +#include "utils/perform_common_errors.hpp" +namespace timetable_vsu_backend::views::teacher::requests::approve::new_ +{ +namespace +{ +namespace pg = components::controllers::postgres; +class Handler final + : public http::HandlerParsed +{ + public: + [[maybe_unused]] static constexpr std::string_view kName = + "handler-teacher-requests-approve-new"; + Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : HandlerParsed(config, context), + teacher_controller(context.FindComponent()), + user_controller(context.FindComponent()) + { + } + + Response Handle(Request&& request) const override + { + auto user = user_controller.GetByToken(request.token()); + if (!user) + { + return utils::common_errors::PerformInvalidToken(); + } + if (user->type() != models::UserType::kAdmin && + user->type() != models::UserType::kRoot) + { + return utils::common_errors::PerformForbidden(); + } + auto link_id = teacher_controller.ApproveAndCreateAccount( + request.request_id(), request.teacher_info()); + if (!link_id) + { + return utils::common_errors::PerformInvalidData( + "Request_id or department_id are incorrect"); + } + + return Response200{*link_id}; + } + + private: + const pg::teacher::Controller& teacher_controller; + const pg::user::Controller& user_controller; +}; +} // namespace + +void Append(userver::components::ComponentList& component_list) +{ + component_list.Append(); +} + +} // namespace timetable_vsu_backend::views::teacher::requests::approve::new_ diff --git a/src/views/teacher/request/approve/new/view.hpp b/src/views/teacher/request/approve/new/view.hpp new file mode 100644 index 00000000..9ca25bab --- /dev/null +++ b/src/views/teacher/request/approve/new/view.hpp @@ -0,0 +1,7 @@ +#pragma once +#include "utils/component_list_fwd.hpp" +namespace timetable_vsu_backend::views::teacher::requests::approve::new_ +{ +void Append(userver::components::ComponentList& component_list); + +} diff --git a/src/views/teacher/request/list/Request.hpp b/src/views/teacher/request/list/Request.hpp new file mode 100644 index 00000000..24df5b98 --- /dev/null +++ b/src/views/teacher/request/list/Request.hpp @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include + +#include "models/teacher_filter/type.hpp" +#include "utils/convert/base.hpp" +#include "utils/convert/http_request_parse.hpp" +#include "utils/convert/json_parse.hpp" +#include "utils/parse/uuid/string.hpp" +namespace timetable_vsu_backend::views::teacher::requests::list +{ +using namespace utils::convert; +struct Request +{ + HeaderProperty token; + static constexpr auto kPolicyFields = PolicyFields::ConvertAll; + static constexpr TypeOfBody kTypeOfBody = + TypeOfBody::Empty; //открываем возможность использовать структуру, как + //запрос +}; +} // namespace timetable_vsu_backend::views::teacher::requests::list diff --git a/src/views/teacher/request/list/Responses.hpp b/src/views/teacher/request/list/Responses.hpp new file mode 100644 index 00000000..a38cacdc --- /dev/null +++ b/src/views/teacher/request/list/Responses.hpp @@ -0,0 +1,35 @@ +#pragma once +#include +#include +#include + +#include "http/ErrorV1.hpp" +#include "models/admin_account/type.hpp" +#include "models/request_privileges/type.hpp" +#include "models/teacher/type.hpp" +#include "models/user/type.hpp" +#include "models/user_type/serialize.hpp" +#include "models/user_type/type.hpp" +#include "utils/common_errors.hpp" +#include "utils/convert/additional_properties.hpp" +#include "utils/convert/base.hpp" +#include "utils/convert/http_response_serialize.hpp" +#include "utils/convert/json_parse.hpp" + +namespace timetable_vsu_backend::views::teacher::requests::list +{ +using namespace utils::convert; +struct Response200 +{ + ArrayProperty requests; + static constexpr TypeOfBody kTypeOfBody = TypeOfBody::Json; + static constexpr PolicyFields kPolicyFields = PolicyFields::ConvertAll; + static constexpr userver::server::http::HttpStatus kStatusCode = + userver::server::http::HttpStatus::kOk; +}; + +using Response401 = utils::common_errors::Response401; + +using Response403 = utils::common_errors::Response403; + +} // namespace timetable_vsu_backend::views::teacher::requests::list diff --git a/src/views/teacher/request/list/view.cpp b/src/views/teacher/request/list/view.cpp new file mode 100644 index 00000000..f2abcba4 --- /dev/null +++ b/src/views/teacher/request/list/view.cpp @@ -0,0 +1,72 @@ +#include "view.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Request.hpp" +#include "Responses.hpp" +#include "components/controllers/postgres/teacher/controller.hpp" +#include "components/controllers/postgres/user/controller.hpp" +#include "http/handler_parsed.hpp" +#include "models/auth_token/serialize.hpp" +#include "models/user/serialize.hpp" +#include "models/user_type/serialize.hpp" +#include "models/user_type/type.hpp" +#include "userver/logging/log.hpp" +#include "utils/parse/uuid/string.hpp" +#include "utils/perform_common_errors.hpp" +namespace timetable_vsu_backend::views::teacher::requests::list +{ +namespace +{ +namespace pg = components::controllers::postgres; +class Handler final + : public http::HandlerParsed +{ + public: + [[maybe_unused]] static constexpr std::string_view kName = + "handler-teacher-requests-list"; + Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : HandlerParsed(config, context), + teacher_controller(context.FindComponent()), + user_controller(context.FindComponent()) + { + } + + Response Handle(Request&& request) const override + { + auto user = user_controller.GetByToken(request.token()); + if (!user) + { + return utils::common_errors::PerformInvalidToken(); + } + if (user->type() != models::UserType::kAdmin && + user->type() != models::UserType::kRoot) + { + return utils::common_errors::PerformForbidden(); + } + auto requests = teacher_controller.GetAllRequests(); + Response200 resp; + resp.requests() = std::move(requests); + return resp; + } + + private: + const pg::teacher::Controller& teacher_controller; + const pg::user::Controller& user_controller; +}; +} // namespace + +void Append(userver::components::ComponentList& component_list) +{ + component_list.Append(); +} + +} // namespace timetable_vsu_backend::views::teacher::requests::list diff --git a/src/views/teacher/request/list/view.hpp b/src/views/teacher/request/list/view.hpp new file mode 100644 index 00000000..2e162c71 --- /dev/null +++ b/src/views/teacher/request/list/view.hpp @@ -0,0 +1,7 @@ +#pragma once +#include "utils/component_list_fwd.hpp" +namespace timetable_vsu_backend::views::teacher::requests::list +{ +void Append(userver::components::ComponentList& component_list); + +} diff --git a/tests/faculty/list/data_faculty.py b/tests/faculty/list/data_faculty.py new file mode 100644 index 00000000..1349ec47 --- /dev/null +++ b/tests/faculty/list/data_faculty.py @@ -0,0 +1,27 @@ +K_FACULTY = { + 'id': 'bbc6312c-f25e-4db3-b2a0-3f5dc6717a8d', + 'name': 'Faculty of Mathematics and Mechanics' +} + +K_IDS_FIELDS = [ + ('ids', ['bbc6312c'], True), + ('ids', ['bbbbb'], False), + ('ids', ['bbbbb', 'bbc6312c'], True), +] + +K_IDS_IDS = [ + 'ids_true', 'ids_false', 'ids_many' +] + +K_NAMES_FIELDS = [ + ('names', ['Math'], True), + ('names', ['Russian'], False), + ('names', ['Russian', 'Math'], True), +] + +K_NAMES_IDS = [ + 'names_true', 'names_false', 'names_many' +] + +K_FIELDS = K_IDS_FIELDS + K_NAMES_FIELDS +K_IDS = K_IDS_IDS + K_NAMES_IDS diff --git a/tests/faculty/list/test_faculty_list.py b/tests/faculty/list/test_faculty_list.py new file mode 100644 index 00000000..e7977a98 --- /dev/null +++ b/tests/faculty/list/test_faculty_list.py @@ -0,0 +1,30 @@ +import pytest +from data_faculty import K_IDS +from data_faculty import K_FIELDS +from data_faculty import K_FACULTY + + +def _perform_filter(field, value): + return { + field: value + } + + +@pytest.mark.pgsql('db_1', files=['initial_data_timetable1.sql']) +@pytest.mark.parametrize( + 'field, value, found', + K_FIELDS, + ids=K_IDS +) +async def test_faculty_list(service_client, field, value, found): + response = await service_client.post('/faculty/list', json={ + "filter": _perform_filter(field, value) + }) + assert response.status_code == 200 + assert 'faculties' in response.json() + if found: + assert len(response.json()['faculties']) == 1 + assert response.json()['faculties'] == [K_FACULTY] + else: + assert len(response.json()['faculties']) == 0 + assert response.json()['faculties'] == [] diff --git a/tests/teacher/conftest.py b/tests/teacher/conftest.py new file mode 100644 index 00000000..606b2059 --- /dev/null +++ b/tests/teacher/conftest.py @@ -0,0 +1,56 @@ +import pytest + +K_GET_ALL_TEACHERS = """ +SELECT id, fio, bio, id_department FROM timetable_vsu."teacher" +WHERE id = '{}' +""" + +K_GET_ALL_TEACHER_LINKS = """ +SELECT id, id_user, id_teacher FROM timetable_vsu."teacher_link" +WHERE id = '{}' +""" + + +@pytest.fixture(name='vsu_timetable_db') +def mock_vsu_timetable_db(pgsql): + class Teacher: + def __init__(self, teacher_id, fio, bio, department_id): + self.id = teacher_id + self.fio = fio + self.bio = bio + self.department_id = department_id + + class TeacherLink: + def __init__(self, link_id, teacher_id, user_id): + self.id = link_id + self.teacher_id = teacher_id + self.user_id = user_id + + class Context: + def __init__(self, pgsql): + self.pgsql = pgsql + + def get_teacher_by_id(self, teacher_id): + db = self.pgsql['db_1'] + cursor = db.cursor() + cursor.execute(K_GET_ALL_TEACHERS.format(teacher_id)) + elems = cursor.fetchall() + result = [] + for elem in elems: + teacher_id, fio, bio, department_id = elem + result.append(Teacher(teacher_id, fio, bio, department_id)) + return result + + def get_link_by_id(self, out_link_id): + db = self.pgsql['db_1'] + cursor = db.cursor() + cursor.execute(K_GET_ALL_TEACHER_LINKS.format(out_link_id)) + elems = cursor.fetchall() + result = [] + for elem in elems: + link_id, link_id_user, link_id_teacher = elem + result.append(TeacherLink( + link_id, link_id_teacher, link_id_user)) + return result + + return Context(pgsql) diff --git a/tests/teacher/create/test_teacher_create.py b/tests/teacher/create/test_teacher_create.py new file mode 100644 index 00000000..a3c758e7 --- /dev/null +++ b/tests/teacher/create/test_teacher_create.py @@ -0,0 +1,100 @@ +import pytest + + +def _assert_teachers(vsu_timetable_db, teacher_id, bio, fio, department_id): + teachers = vsu_timetable_db.get_teacher_by_id(teacher_id) + assert len(teachers) == 1 + teacher = teachers[0] + assert teacher.id == teacher_id + assert teacher.bio == bio + assert teacher.fio == fio + assert teacher.department_id == department_id + + +@pytest.mark.pgsql('db_1', files=['initial_data_timetable1.sql', + 'initial_data_auth_admin.sql', + 'initial_data_auth_admin_token.sql']) +async def test_teacher_create_one_ok(service_client, vsu_timetable_db): + + response = await service_client.post('/teacher/create', json={ + "teacher_info": { + "fio": "test_fio", + "bio": "test_bio", + "department_id": '1f93ceb4-d931-4b66-a0e5-7323d6b60f3b' + } + }, + headers={ + 'token': '333111c7-9654-4814-b36b-7d39c1ddded2' + }) + assert response.status_code == 200 + assert 'id_created_teacher' in response.json() + id_created_teacher = response.json()['id_created_teacher'] + _assert_teachers(vsu_timetable_db, id_created_teacher, 'test_bio', + 'test_fio', '1f93ceb4-d931-4b66-a0e5-7323d6b60f3b') + + +@pytest.mark.pgsql('db_1', files=['initial_data_auth_admin.sql', + 'initial_data_auth_admin_token.sql']) +async def test_teacher_create_one_bad_data(service_client): + + response = await service_client.post('/teacher/create', json={ + "teacher_info": { + "fio": "test_fio", + "bio": "test_bio", + "department_id": '1f93ceb4-d931-4b66-a0e5-7323d6b60f3b' + } + }, + headers={ + 'token': '333111c7-9654-4814-b36b-7d39c1ddded2' + }) + assert response.status_code == 400 + assert response.json()['machine_id'] == 'INVALID_DATA' + + +@pytest.mark.pgsql('db_1', files=['initial_data_auth_admin.sql', + 'initial_data_auth_admin_token.sql']) +async def test_teacher_create_one_bad_token(service_client): + response = await service_client.post('/teacher/create', json={ + "teacher_info": { + "fio": "test_fio", + "bio": "test_bio", + "department_id": '1f93ceb4-d931-4b66-a0e5-7323d6b60f3b' + } + }, + headers={ + 'token': '333333c7-9654-4814-b36b-7d39c1ddded2' + }) + assert response.status_code == 401 + assert response.json()['machine_id'] == 'INVALID_TOKEN' + + +@pytest.mark.pgsql('db_1', + files=[ + 'initial_data_auth_user.sql', + 'initial_data_auth_user_token.sql', + 'initial_data_auth_admin.sql', + 'initial_data_auth_admin_token.sql', + 'initial_data_auth_teacher.sql', + 'initial_data_auth_teacher_token.sql', + ]) +@pytest.mark.parametrize( + 'token', + [ + ('111111c7-9654-4814-b36b-7d39c1ddded2'), + ('222111c7-9654-4814-b36b-7d39c1ddded2'), + ], +) +async def test_teacher_create_forbiden(service_client, token): + + response = await service_client.post('/teacher/create', json={ + "teacher_info": { + "fio": "test_fio", + "bio": "test_bio", + "department_id": '1f93ceb4-d931-4b66-a0e5-7323d6b60f3b' + } + }, + headers={ + 'token': token + }) + assert response.status_code == 403 + assert response.json()['machine_id'] == 'NOT_ENOUGH_PERMISSIONS' diff --git a/tests/teacher/request/approve/link/static/initial_data_teacher_request.sql b/tests/teacher/request/approve/link/static/initial_data_teacher_request.sql new file mode 100644 index 00000000..7cbe75ff --- /dev/null +++ b/tests/teacher/request/approve/link/static/initial_data_teacher_request.sql @@ -0,0 +1,14 @@ +INSERT INTO timetable_vsu.user(login, password, id) +VALUES('some_request_user', 'request_user_password', '000000c7-9999-4814-b36b-7d39c1ddded2'); + +INSERT INTO timetable_vsu.teacher_requests(id, id_user, description) +VALUES('000000c7-1111-4814-b36b-7d39c1ddded2','000000c7-9999-4814-b36b-7d39c1ddded2', 'some_description'); + +INSERT INTO timetable_vsu.faculty (id, name) +VALUES ('bbc6312c-f25e-4db3-b2a0-3f5dc6717a8d', 'Faculty of Mathematics and Mechanics'); + +INSERT INTO timetable_vsu.department (id, name, id_faculty) +VALUES ('1f93ceb4-d931-4b66-a0e5-7323d6b60f3b', 'Department of Applied Mathematics', 'bbc6312c-f25e-4db3-b2a0-3f5dc6717a8d'); + +INSERT INTO timetable_vsu.teacher (id, fio, bio, id_department) +VALUES ('22111667-9654-4814-b36b-7d39c1ddded2', 'John Doe', 'Professor of Mathematics', '1f93ceb4-d931-4b66-a0e5-7323d6b60f3b'); diff --git a/tests/teacher/request/approve/link/test_teacher_request_approve_link.py b/tests/teacher/request/approve/link/test_teacher_request_approve_link.py new file mode 100644 index 00000000..69fd3f44 --- /dev/null +++ b/tests/teacher/request/approve/link/test_teacher_request_approve_link.py @@ -0,0 +1,81 @@ +import pytest + + +def _assert_link_db(vsu_timetable_db, link_id, teacher_id, user_id): + links = vsu_timetable_db.get_link_by_id(link_id) + assert len(links) == 1 + link = links[0] + assert link.id == link_id + assert link.teacher_id == teacher_id + assert link.user_id == user_id + + +@pytest.mark.pgsql('db_1', + files=[ + 'initial_data_teacher_request.sql', + 'initial_data_auth_admin.sql', + 'initial_data_auth_admin_token.sql']) +async def test_teacher_request_approve_link_ok(service_client, + vsu_timetable_db): + token = '333111c7-9654-4814-b36b-7d39c1ddded2' + request_id = '000000c7-1111-4814-b36b-7d39c1ddded2' + teacher_id = '22111667-9654-4814-b36b-7d39c1ddded2' + user_id = '000000c7-9999-4814-b36b-7d39c1ddded2' + response = await service_client.post('/teacher/requests/approve/link', + headers={ + 'token': token + }, json={ + 'request_id': request_id, + 'teacher_id': teacher_id + }) + assert response.status_code == 200 + link_id = response.json()['link_id'] + assert link_id + _assert_link_db(vsu_timetable_db, link_id, teacher_id, user_id) + + +@pytest.mark.pgsql('db_1', + files=[ + 'initial_data_teacher_request.sql']) +async def test_teacher_request_approve_link_bad_token(service_client): + token = '333111c7-9654-4814-b36b-7d39c1ddded2' + request_id = '000000c7-1111-4814-b36b-7d39c1ddded2' + teacher_id = '22111667-9654-4814-b36b-7d39c1ddded2' + response = await service_client.post('/teacher/requests/approve/link', + headers={ + 'token': token + }, json={ + 'request_id': request_id, + 'teacher_id': teacher_id + }) + assert response.status_code == 401 + assert response.json()['machine_id'] == 'INVALID_TOKEN' + + +@pytest.mark.pgsql('db_1', + files=[ + 'initial_data_teacher_request.sql', + 'initial_data_auth_user.sql', + 'initial_data_auth_user_token.sql', + 'initial_data_auth_teacher.sql', + 'initial_data_auth_teacher_token.sql', + ]) +@pytest.mark.parametrize( + 'token', + [ + ('111111c7-9654-4814-b36b-7d39c1ddded2'), + ('222111c7-9654-4814-b36b-7d39c1ddded2'), + ], +) +async def test_teacher_request_approve_link_forbiden(service_client, token): + request_id = '000000c7-1111-4814-b36b-7d39c1ddded2' + teacher_id = '22111667-9654-4814-b36b-7d39c1ddded2' + response = await service_client.post('/teacher/requests/approve/link', + headers={ + 'token': token + }, json={ + 'request_id': request_id, + 'teacher_id': teacher_id + }) + assert response.status_code == 403 + assert response.json()['machine_id'] == 'NOT_ENOUGH_PERMISSIONS' diff --git a/tests/teacher/request/approve/new/static/initial_data_teacher_request.sql b/tests/teacher/request/approve/new/static/initial_data_teacher_request.sql new file mode 100644 index 00000000..2d271cf3 --- /dev/null +++ b/tests/teacher/request/approve/new/static/initial_data_teacher_request.sql @@ -0,0 +1,11 @@ +INSERT INTO timetable_vsu.user(login, password, id) +VALUES('some_request_user', 'request_user_password', '000000c7-9999-4814-b36b-7d39c1ddded2'); + +INSERT INTO timetable_vsu.teacher_requests(id, id_user, description) +VALUES('000000c7-1111-4814-b36b-7d39c1ddded2','000000c7-9999-4814-b36b-7d39c1ddded2', 'some_description'); + +INSERT INTO timetable_vsu.faculty (id, name) +VALUES ('bbc6312c-f25e-4db3-b2a0-3f5dc6717a8d', 'Faculty of Mathematics and Mechanics'); + +INSERT INTO timetable_vsu.department (id, name, id_faculty) +VALUES ('1f93ceb4-d931-4b66-a0e5-7323d6b60f3b', 'Department of Applied Mathematics', 'bbc6312c-f25e-4db3-b2a0-3f5dc6717a8d'); diff --git a/tests/teacher/request/approve/new/test_teacher_request_approve_new.py b/tests/teacher/request/approve/new/test_teacher_request_approve_new.py new file mode 100644 index 00000000..b56d9b26 --- /dev/null +++ b/tests/teacher/request/approve/new/test_teacher_request_approve_new.py @@ -0,0 +1,96 @@ +import pytest + + +def _assert_link_db(vsu_timetable_db, link_id, user_id): + links = vsu_timetable_db.get_link_by_id(link_id) + assert len(links) == 1 + link = links[0] + assert link.id == link_id + assert link.user_id == user_id + + +async def _send_request(service_client, + token, request_id, + teacher_bio, + teacher_fio, + department_id): + response = await service_client.post('/teacher/requests/approve/new', + headers={ + 'token': token + }, json={ + 'request_id': request_id, + 'teacher_info': { + 'bio': teacher_bio, + 'fio': teacher_fio, + 'department_id': department_id + } + }) + return response + + +@pytest.mark.pgsql('db_1', + files=[ + 'initial_data_teacher_request.sql', + 'initial_data_auth_admin.sql', + 'initial_data_auth_admin_token.sql']) +async def test_teacher_request_approve_new_ok(service_client, + vsu_timetable_db): + token = '333111c7-9654-4814-b36b-7d39c1ddded2' + request_id = '000000c7-1111-4814-b36b-7d39c1ddded2' + teacher_bio = 'test_bio' + teacher_fio = 'test_fio' + department_id = '1f93ceb4-d931-4b66-a0e5-7323d6b60f3b' + user_id = '000000c7-9999-4814-b36b-7d39c1ddded2' + response = await _send_request(service_client, + token, + request_id, + teacher_bio, + teacher_fio, + department_id) + assert response.status_code == 200 + link_id = response.json()['link_id'] + assert link_id + _assert_link_db(vsu_timetable_db, link_id, user_id) + + +@pytest.mark.pgsql('db_1', + files=[ + 'initial_data_teacher_request.sql']) +async def test_teacher_request_approve_new_bad_token(service_client): + token = '333111c7-9654-4814-b36b-7d39c1ddded2' + request_id = '000000c7-1111-4814-b36b-7d39c1ddded2' + teacher_bio = 'test_bio' + teacher_fio = 'test_fio' + department_id = '1f93ceb4-d931-4b66-a0e5-7323d6b60f3b' + response = await _send_request(service_client, token, + request_id, teacher_bio, + teacher_fio, department_id) + assert response.status_code == 401 + assert response.json()['machine_id'] == 'INVALID_TOKEN' + + +@pytest.mark.pgsql('db_1', + files=[ + 'initial_data_teacher_request.sql', + 'initial_data_auth_user.sql', + 'initial_data_auth_user_token.sql', + 'initial_data_auth_teacher.sql', + 'initial_data_auth_teacher_token.sql', + ]) +@pytest.mark.parametrize( + 'token', + [ + ('111111c7-9654-4814-b36b-7d39c1ddded2'), + ('222111c7-9654-4814-b36b-7d39c1ddded2'), + ], +) +async def test_teacher_request_approve_new_forbiden(service_client, token): + request_id = '000000c7-1111-4814-b36b-7d39c1ddded2' + teacher_bio = 'test_bio' + teacher_fio = 'test_fio' + department_id = '1f93ceb4-d931-4b66-a0e5-7323d6b60f3b' + response = await _send_request(service_client, token, + request_id, teacher_bio, + teacher_fio, department_id) + assert response.status_code == 403 + assert response.json()['machine_id'] == 'NOT_ENOUGH_PERMISSIONS' diff --git a/tests/teacher/request/list/static/initial_data_teacher_request.sql b/tests/teacher/request/list/static/initial_data_teacher_request.sql new file mode 100644 index 00000000..ef0adcec --- /dev/null +++ b/tests/teacher/request/list/static/initial_data_teacher_request.sql @@ -0,0 +1,5 @@ +INSERT INTO timetable_vsu.user(login, password, id) +VALUES('some_user', 'user_password', '111111c7-9999-4814-b36b-7d39c1ddded2'); + +INSERT INTO timetable_vsu.teacher_requests(id, id_user, description) +VALUES('111111c7-0000-4814-b36b-7d39c1ddded2','111111c7-9999-4814-b36b-7d39c1ddded2', 'some_description'); diff --git a/tests/teacher/request/list/test_teacher_request_list.py b/tests/teacher/request/list/test_teacher_request_list.py new file mode 100644 index 00000000..66988d19 --- /dev/null +++ b/tests/teacher/request/list/test_teacher_request_list.py @@ -0,0 +1,49 @@ +import pytest + + +@pytest.mark.pgsql('db_1', + files=[ + 'initial_data_teacher_request.sql', + 'initial_data_auth_admin.sql', + 'initial_data_auth_admin_token.sql']) +async def test_teacher_request_list_successful(service_client): + response = await service_client.post('/teacher/requests/list', headers={ + 'token': '333111c7-9654-4814-b36b-7d39c1ddded2' + }) + assert response.status_code == 200 + assert len(response.json()['requests']) == 1 + assert response.json()['requests'][0] == { + 'request_id': '111111c7-0000-4814-b36b-7d39c1ddded2', + 'user_id': '111111c7-9999-4814-b36b-7d39c1ddded2', + 'description': 'some_description' + } + + +async def test_teacher_request_list_bad_token(service_client): + response = await service_client.post('/teacher/requests/list', headers={ + 'token': '333111c7-9654-4814-b36b-7d39c1ddded2' + }) + assert response.status_code == 401 + assert response.json()['machine_id'] == 'INVALID_TOKEN' + + +@pytest.mark.pgsql('db_1', + files=[ + 'initial_data_auth_user.sql', + 'initial_data_auth_user_token.sql', + 'initial_data_auth_teacher.sql', + 'initial_data_auth_teacher_token.sql', + ]) +@pytest.mark.parametrize( + 'token', + [ + ('111111c7-9654-4814-b36b-7d39c1ddded2'), + ('222111c7-9654-4814-b36b-7d39c1ddded2'), + ], +) +async def test_teacher_request_list_forbiden(service_client, token): + response = await service_client.post('/teacher/requests/list', headers={ + 'token': token + }) + assert response.status_code == 403 + assert response.json()['machine_id'] == 'NOT_ENOUGH_PERMISSIONS' diff --git a/tests/timetable/get/test_timetable_get.py b/tests/timetable/get/test_timetable_get.py index 59f49a16..7abc5802 100644 --- a/tests/timetable/get/test_timetable_get.py +++ b/tests/timetable/get/test_timetable_get.py @@ -28,7 +28,6 @@ def _perform_filter_like(field, value): ids=K_IDS ) async def test_timetable_get_one_lesson(service_client, field, value, found): - response = await service_client.post('/timetable/get', json={ "filter": _perform_filter(field, value) }) diff --git a/united_api.yaml b/united_api.yaml index 95adf068..4f006569 100644 --- a/united_api.yaml +++ b/united_api.yaml @@ -134,6 +134,16 @@ components: - first - second type: string + TypesTeacherInfo: + properties: + bio: + description: биография + type: string + department_id: + $ref: '#/components/schemas/TypesId' + fio: + description: ФИО + type: string TypesTimestamp: example: 2023-04-01T05:30:00+0000 type: string @@ -206,6 +216,10 @@ components: $ref: '#/components/schemas/TypesUserCredentialV1' required: - user_credential + ViewsTeacherCreateRequest: + properties: + credentials: + $ref: '#/components/schemas/TypesTeacherInfo' ViewsTimetableGetRequest: properties: begin: @@ -334,7 +348,7 @@ paths: $ref: '#/components/schemas/TypesErrorV1' description: Нет прав на подобные изменения tags: - - admins + - root /admin/list: post: description: Получить список администраторов @@ -372,7 +386,7 @@ paths: $ref: '#/components/schemas/TypesErrorV1' description: Нет прав на подобные изменения tags: - - admins + - root /login: post: requestBody: @@ -421,6 +435,42 @@ paths: description: Логин уже занят или пароль не удолетворяет требованиям tags: - users + /teacher/create: + post: + description: Создать нового преподавателя + parameters: + - in: header + name: authToken + required: true + schema: + $ref: '#/components/schemas/TypesAuthTokenV1' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ViewsTeacherCreateRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesAdminAccount' + description: Преподаватель успешно создан + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Отсутствует или истекший токен + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Нет прав на подобные изменения + tags: + - admins /timetable/get: post: requestBody: @@ -441,6 +491,8 @@ paths: tags: - users tags: +- description: Доступно суперпользователю + name: root - description: Доступно администраторам сервиса name: admins - description: Доступны для преподавателей, которые ведут соответствующую группу и