From d2463b8d6200d628452bde882feb9958f2641c31 Mon Sep 17 00:00:00 2001 From: sabudilovskiy Date: Wed, 3 May 2023 14:25:53 +0300 Subject: [PATCH] Fix api (#9) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1) Убраны команды для Docker из readme, так как docker более не поддерживается 2) Добавлены команды для make, позволяющие удобнее работать с тестами, форматированием и запуском 3) сервиса 3) Реализована и покрыта тестами ручка /get-timetable 4) Реализован конвертер структур, использующие Property в кортежи ссылок, поддерживает массивы и опциональные параметры, благодаря этому можно теперь пихать структурки в постгрес и наоборот 5) Добавлено форматирование EOL в конце файлов 6) Наведен порядок в схемах постгреса(используется порядковое нумерование для избежания неоднозначностей) --- .clang-format | 3 +- .gen/objs.txt | 85 ++++- .gen/unittest.txt | 2 + .github/workflows/ci.yml | 8 +- .github/workflows/delete_old_runs.yml | 2 +- .gitignore | 3 +- .vscode/settings.json | 2 + Makefile | 94 +++-- README.md | 17 +- api/api.yaml | 2 +- api/types/AuthTokenV1.yaml | 2 +- api/types/Day.yaml | 12 +- api/types/EducationType.yaml | 4 +- api/types/ErrorV1.yaml | 2 +- api/types/FacultyV1.yaml | 2 +- api/types/GroupV1.yaml | 2 +- api/types/Id.yaml | 2 +- api/types/LessonV1.yaml | 67 +++- api/types/NumberLesson.yaml | 2 +- api/types/Subgroup.yaml | 6 +- api/types/TeacherV1.yaml | 2 +- api/types/Timestamp.yaml | 2 +- api/types/TypeOfLesson.yaml | 6 +- api/types/TypeOfWeek.yaml | 6 +- api/types/UserCredentialV1.yaml | 2 +- api/types/UserTypeV1.yaml | 2 +- api/views/admin/group/add/Request.yaml | 2 +- api/views/admin/group/add/view.yaml | 2 +- api/views/admin/group/lesson/add/Request.yaml | 2 +- api/views/admin/group/lesson/add/view.yaml | 2 +- .../admin/group/lesson/remove/Request.yaml | 2 +- api/views/admin/group/lesson/remove/view.yaml | 2 +- api/views/admin/group/remove/Request.yaml | 2 +- api/views/admin/group/remove/view.yaml | 2 +- .../admin/group/teacher/add/Request.yaml | 2 +- api/views/admin/group/teacher/add/view.yaml | 2 +- .../admin/group/teacher/remove/Request.yaml | 2 +- .../admin/group/teacher/remove/view.yaml | 2 +- api/views/admin/teacher/link/Request.yaml | 2 +- api/views/admin/teacher/link/view.yaml | 2 +- api/views/admin/teacher/unlink/Request.yaml | 2 +- api/views/admin/teacher/unlink/view.yaml | 2 +- api/views/get-timetable/Request.yaml | 96 +++-- api/views/get-timetable/view.yaml | 2 +- api/views/lesson/add/Request.yaml | 2 +- api/views/lesson/add/view.yaml | 2 +- api/views/lesson/move/Request.yaml | 2 +- api/views/lesson/move/view.yaml | 2 +- api/views/lesson/remove/Request.yaml | 2 +- api/views/lesson/remove/view.yaml | 2 +- api/views/login/ResponseV1.yaml | 2 +- api/views/login/view.yaml | 2 +- api/views/register/RequestV1.yaml | 2 +- api/views/register/view.yaml | 2 +- configs/config_dev.yaml | 9 - configs/config_vars.docker.yaml | 2 +- configs/config_vars.yaml | 2 +- configs/dynamic_config_fallback.json | 2 +- configs/static_config.yaml.in | 6 +- configs_testing/config_vars_testing.yaml | 2 +- dependencies/python.md | 2 +- docker-compose.yml | 2 +- postgresql/data/initial_data_auth.sql | 4 +- postgresql/data/initial_data_hello.sql | 2 +- postgresql/data/initial_data_timetable1.sql | 37 ++ postgresql/data/initial_data_timetable2.sql | 37 ++ postgresql/data/timetable_random.sql | 47 +++ postgresql/schemas/db_1/000_init.sql | 257 +++++++++++++ .../schemas/db_1/{hello.sql => 001_hello.sql} | 6 +- .../schemas/db_1/002_add_lesson_filter.sql | 31 ++ postgresql/schemas/db_1/auth.sql | 22 -- redocly.yaml | 2 +- service/main.cpp | 38 +- .../postgres/lesson/controller.cpp | 143 ++++++++ .../postgres/lesson/controller.hpp | 28 ++ .../controllers/postgres/lesson/fwd.cpp | 12 + .../controllers/postgres/lesson/fwd.hpp | 8 + .../token/controller.cpp} | 26 +- .../token/controller.hpp} | 7 +- .../controllers/postgres/token/fwd.cpp | 11 + .../token/fwd.hpp} | 4 +- .../user/controller.cpp} | 20 +- .../user/controller.hpp} | 6 +- .../controllers/postgres/user/fwd.cpp | 11 + .../user/fwd.hpp} | 4 +- .../controllers/token_controller_fwd.cpp | 10 - .../controllers/user_controller_fwd.cpp | 9 - src/helpers/lesson_converter.hpp | 33 ++ src/http/ErrorV1.hpp | 5 +- src/http/handler_parsed.hpp | 24 +- src/http/legacy_handler_parsed.hpp | 9 +- src/models/auth_token/serialize.hpp | 8 +- src/models/auth_token/type.hpp | 2 +- src/models/day/all.hpp | 4 + src/models/day/parse.cpp | 38 ++ src/models/day/parse.hpp | 12 + src/models/day/postgre.hpp | 25 ++ src/models/day/serialize.cpp | 30 ++ src/models/day/serialize.hpp | 12 + src/models/day/type.hpp | 12 + src/models/education_type/all.hpp | 4 + src/models/education_type/parse.cpp | 35 ++ src/models/education_type/parse.hpp | 13 + src/models/education_type/postgre.hpp | 23 ++ src/models/education_type/serialize.cpp | 26 ++ src/models/education_type/serialize.hpp | 12 + src/models/education_type/type.hpp | 10 + src/models/lesson/type.hpp | 15 - src/models/lesson_filter/fwd.hpp | 5 + src/models/lesson_filter/postgre.hpp | 17 + src/models/lesson_filter/type.hpp | 49 +++ src/models/lesson_type/all.hpp | 4 + src/models/lesson_type/parse.cpp | 34 ++ src/models/lesson_type/parse.hpp | 12 + src/models/lesson_type/postgre.hpp | 22 ++ src/models/lesson_type/serialize.cpp | 24 ++ src/models/lesson_type/serialize.hpp | 12 + src/models/lesson_type/type.hpp | 5 + src/models/lesson_v1/parse.hpp | 8 + src/models/lesson_v1/postgre.hpp | 9 + src/models/lesson_v1/serialize.hpp | 8 + src/models/lesson_v1/type.hpp | 44 +++ src/models/lesson_week_type/all.hpp | 4 + src/models/lesson_week_type/parse.cpp | 33 ++ src/models/lesson_week_type/parse.hpp | 13 + src/models/lesson_week_type/postgre.hpp | 22 ++ src/models/lesson_week_type/serialize.cpp | 24 ++ src/models/lesson_week_type/serialize.hpp | 12 + src/models/lesson_week_type/type.hpp | 5 + src/models/lesson_with_details/parse.hpp | 8 + src/models/lesson_with_details/postgre.hpp | 8 + src/models/lesson_with_details/serialize.hpp | 8 + src/models/lesson_with_details/type.hpp | 41 +++ src/models/subgroup/all.hpp | 4 + src/models/subgroup/parse.cpp | 32 ++ src/models/subgroup/parse.hpp | 12 + src/models/subgroup/postgre.hpp | 22 ++ src/models/subgroup/serialize.cpp | 24 ++ src/models/subgroup/serialize.hpp | 12 + src/models/subgroup/type.hpp | 5 + src/models/timestring/all.hpp | 4 + src/models/timestring/fwd.hpp | 4 + src/models/timestring/parse.cpp | 26 ++ src/models/timestring/parse.hpp | 13 + src/models/timestring/postgre.hpp | 12 + src/models/timestring/serialize.cpp | 18 + src/models/timestring/serialize.hpp | 12 + src/models/timestring/type.hpp | 8 + src/models/user/postgre.hpp | 4 +- src/models/user/type.hpp | 5 +- src/models/user_type/parse.cpp | 2 +- src/models/user_type/parse.hpp | 4 +- src/models/user_type/postgre.hpp | 4 +- src/models/user_type/serialize.cpp | 4 +- src/models/user_type/serialize.hpp | 5 +- src/utils/component_list_fwd.hpp | 2 +- src/utils/constexpr_string.hpp | 2 +- src/utils/convert/additional_properties.hpp | 88 +++++ src/utils/convert/base.hpp | 10 +- .../drop_properties/const_dropper_to_ref.hpp | 134 +++++++ .../drop_properties/mut_dropper_to_ref.hpp | 134 +++++++ .../detail/parse/converter_http_request.hpp | 35 +- .../convert/detail/parse/converter_json.hpp | 18 +- .../serialize/converter_http_response.hpp | 6 +- .../detail/serialize/converter_json.hpp | 4 +- src/utils/convert/drop_properties_ref.hpp | 76 ++++ src/utils/convert/http_request_parse.hpp | 4 +- src/utils/convert/http_response_base.hpp | 2 +- src/utils/convert/http_response_serialize.hpp | 4 +- src/utils/convert/json_parse.hpp | 6 +- src/utils/convert/json_serialize.hpp | 4 +- src/utils/json_type.cpp | 5 +- src/utils/json_type.hpp | 5 +- src/utils/type_holder.hpp | 5 + src/views/get-timetable/Request.hpp | 20 + src/views/get-timetable/Responses.hpp | 32 ++ src/views/get-timetable/view.cpp | 72 ++++ src/views/get-timetable/view.hpp | 7 + src/views/hello/view.cpp | 2 +- src/views/hello/view.hpp | 2 +- src/views/login/Request.hpp | 6 +- src/views/login/Responses.hpp | 2 +- src/views/login/view.cpp | 39 +- src/views/register/Request.cpp | 11 +- src/views/register/Request.hpp | 2 +- src/views/register/view.cpp | 39 +- tests/__init__.py | 2 + tests/conftest.py | 17 +- tests/get-timetable/get_timetable_data.py | 345 ++++++++++++++++++ .../get-timetable/test_get_timetable_basic.py | 33 ++ tests/pytest.ini | 2 +- tests/requirements.txt | 2 +- united_api.yaml | 167 ++++++--- utests/convert_test.cpp | 11 +- utests/dropper.cpp | 101 +++++ utests/dropper_additional.cpp | 49 +++ 196 files changed, 3382 insertions(+), 442 deletions(-) create mode 100644 .vscode/settings.json delete mode 100644 configs/config_dev.yaml create mode 100644 postgresql/data/initial_data_timetable1.sql create mode 100644 postgresql/data/initial_data_timetable2.sql create mode 100644 postgresql/data/timetable_random.sql create mode 100755 postgresql/schemas/db_1/000_init.sql rename postgresql/schemas/db_1/{hello.sql => 001_hello.sql} (90%) create mode 100644 postgresql/schemas/db_1/002_add_lesson_filter.sql delete mode 100755 postgresql/schemas/db_1/auth.sql create mode 100644 src/components/controllers/postgres/lesson/controller.cpp create mode 100644 src/components/controllers/postgres/lesson/controller.hpp create mode 100644 src/components/controllers/postgres/lesson/fwd.cpp create mode 100644 src/components/controllers/postgres/lesson/fwd.hpp rename src/components/controllers/{token_controller.cpp => postgres/token/controller.cpp} (72%) rename src/components/controllers/{token_controller.hpp => postgres/token/controller.hpp} (78%) create mode 100644 src/components/controllers/postgres/token/fwd.cpp rename src/components/controllers/{token_controller_fwd.hpp => postgres/token/fwd.hpp} (52%) rename src/components/controllers/{user_controller.cpp => postgres/user/controller.cpp} (72%) rename src/components/controllers/{user_controller.hpp => postgres/user/controller.hpp} (76%) create mode 100644 src/components/controllers/postgres/user/fwd.cpp rename src/components/controllers/{user_controller_fwd.hpp => postgres/user/fwd.hpp} (52%) delete mode 100644 src/components/controllers/token_controller_fwd.cpp delete mode 100644 src/components/controllers/user_controller_fwd.cpp create mode 100644 src/helpers/lesson_converter.hpp create mode 100644 src/models/day/all.hpp create mode 100644 src/models/day/parse.cpp create mode 100644 src/models/day/parse.hpp create mode 100644 src/models/day/postgre.hpp create mode 100644 src/models/day/serialize.cpp create mode 100644 src/models/day/serialize.hpp create mode 100644 src/models/day/type.hpp create mode 100644 src/models/education_type/all.hpp create mode 100644 src/models/education_type/parse.cpp create mode 100644 src/models/education_type/parse.hpp create mode 100644 src/models/education_type/postgre.hpp create mode 100644 src/models/education_type/serialize.cpp create mode 100644 src/models/education_type/serialize.hpp create mode 100644 src/models/education_type/type.hpp delete mode 100644 src/models/lesson/type.hpp create mode 100644 src/models/lesson_filter/fwd.hpp create mode 100644 src/models/lesson_filter/postgre.hpp create mode 100644 src/models/lesson_filter/type.hpp create mode 100644 src/models/lesson_type/all.hpp create mode 100644 src/models/lesson_type/parse.cpp create mode 100644 src/models/lesson_type/parse.hpp create mode 100644 src/models/lesson_type/postgre.hpp create mode 100644 src/models/lesson_type/serialize.cpp create mode 100644 src/models/lesson_type/serialize.hpp create mode 100644 src/models/lesson_type/type.hpp create mode 100644 src/models/lesson_v1/parse.hpp create mode 100644 src/models/lesson_v1/postgre.hpp create mode 100644 src/models/lesson_v1/serialize.hpp create mode 100644 src/models/lesson_v1/type.hpp create mode 100644 src/models/lesson_week_type/all.hpp create mode 100644 src/models/lesson_week_type/parse.cpp create mode 100644 src/models/lesson_week_type/parse.hpp create mode 100644 src/models/lesson_week_type/postgre.hpp create mode 100644 src/models/lesson_week_type/serialize.cpp create mode 100644 src/models/lesson_week_type/serialize.hpp create mode 100644 src/models/lesson_week_type/type.hpp create mode 100644 src/models/lesson_with_details/parse.hpp create mode 100644 src/models/lesson_with_details/postgre.hpp create mode 100644 src/models/lesson_with_details/serialize.hpp create mode 100644 src/models/lesson_with_details/type.hpp create mode 100644 src/models/subgroup/all.hpp create mode 100644 src/models/subgroup/parse.cpp create mode 100644 src/models/subgroup/parse.hpp create mode 100644 src/models/subgroup/postgre.hpp create mode 100644 src/models/subgroup/serialize.cpp create mode 100644 src/models/subgroup/serialize.hpp create mode 100644 src/models/subgroup/type.hpp create mode 100644 src/models/timestring/all.hpp create mode 100644 src/models/timestring/fwd.hpp create mode 100644 src/models/timestring/parse.cpp create mode 100644 src/models/timestring/parse.hpp create mode 100644 src/models/timestring/postgre.hpp create mode 100644 src/models/timestring/serialize.cpp create mode 100644 src/models/timestring/serialize.hpp create mode 100644 src/models/timestring/type.hpp create mode 100644 src/utils/convert/additional_properties.hpp create mode 100644 src/utils/convert/detail/drop_properties/const_dropper_to_ref.hpp create mode 100644 src/utils/convert/detail/drop_properties/mut_dropper_to_ref.hpp create mode 100644 src/utils/convert/drop_properties_ref.hpp create mode 100644 src/utils/type_holder.hpp create mode 100644 src/views/get-timetable/Request.hpp create mode 100644 src/views/get-timetable/Responses.hpp create mode 100644 src/views/get-timetable/view.cpp create mode 100644 src/views/get-timetable/view.hpp create mode 100644 tests/get-timetable/get_timetable_data.py create mode 100644 tests/get-timetable/test_get_timetable_basic.py create mode 100644 utests/dropper.cpp create mode 100644 utests/dropper_additional.cpp diff --git a/.clang-format b/.clang-format index ba25f56b..e9e7cd76 100644 --- a/.clang-format +++ b/.clang-format @@ -12,4 +12,5 @@ ColumnLimit: 80 PointerAlignment: Left SpaceAfterCStyleCast: true DerivePointerAlignment: false -AlignTrailingComments: true \ No newline at end of file +AlignTrailingComments: true +SortIncludes: true diff --git a/.gen/objs.txt b/.gen/objs.txt index 276370c6..99ebfb11 100644 --- a/.gen/objs.txt +++ b/.gen/objs.txt @@ -8,6 +8,11 @@ src/views/login/Responses.hpp src/views/login/Request.hpp src/views/hello/view.hpp src/views/hello/view.cpp +src/views/get-timetable/view.hpp +src/views/get-timetable/view.cpp +src/views/get-timetable/Responses.hpp +src/views/get-timetable/Request.hpp +src/utils/type_holder.hpp src/utils/meta.hpp src/utils/json_type.hpp src/utils/json_type.cpp @@ -16,11 +21,15 @@ src/utils/convert/json_parse.hpp src/utils/convert/http_response_serialize.hpp src/utils/convert/http_response_base.hpp src/utils/convert/http_request_parse.hpp +src/utils/convert/drop_properties_ref.hpp src/utils/convert/detail/serialize/converter_json.hpp src/utils/convert/detail/serialize/converter_http_response.hpp src/utils/convert/detail/parse/converter_json.hpp src/utils/convert/detail/parse/converter_http_request.hpp +src/utils/convert/detail/drop_properties/mut_dropper_to_ref.hpp +src/utils/convert/detail/drop_properties/const_dropper_to_ref.hpp src/utils/convert/base.hpp +src/utils/convert/additional_properties.hpp src/utils/constexpr_string.hpp src/utils/component_list_fwd.hpp src/models/user_type/type.hpp @@ -31,17 +40,75 @@ src/models/user_type/parse.hpp src/models/user_type/parse.cpp src/models/user/type.hpp src/models/user/postgre.hpp -src/models/lesson/type.hpp +src/models/timestring/type.hpp +src/models/timestring/serialize.hpp +src/models/timestring/serialize.cpp +src/models/timestring/postgre.hpp +src/models/timestring/parse.hpp +src/models/timestring/parse.cpp +src/models/timestring/fwd.hpp +src/models/timestring/all.hpp +src/models/subgroup/type.hpp +src/models/subgroup/serialize.hpp +src/models/subgroup/serialize.cpp +src/models/subgroup/postgre.hpp +src/models/subgroup/parse.hpp +src/models/subgroup/parse.cpp +src/models/subgroup/all.hpp +src/models/lesson_with_details/type.hpp +src/models/lesson_with_details/serialize.hpp +src/models/lesson_with_details/postgre.hpp +src/models/lesson_with_details/parse.hpp +src/models/lesson_week_type/type.hpp +src/models/lesson_week_type/serialize.hpp +src/models/lesson_week_type/serialize.cpp +src/models/lesson_week_type/postgre.hpp +src/models/lesson_week_type/parse.hpp +src/models/lesson_week_type/parse.cpp +src/models/lesson_week_type/all.hpp +src/models/lesson_v1/type.hpp +src/models/lesson_v1/serialize.hpp +src/models/lesson_v1/postgre.hpp +src/models/lesson_v1/parse.hpp +src/models/lesson_type/type.hpp +src/models/lesson_type/serialize.hpp +src/models/lesson_type/serialize.cpp +src/models/lesson_type/postgre.hpp +src/models/lesson_type/parse.hpp +src/models/lesson_type/parse.cpp +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/education_type/type.hpp +src/models/education_type/serialize.hpp +src/models/education_type/serialize.cpp +src/models/education_type/postgre.hpp +src/models/education_type/parse.hpp +src/models/education_type/parse.cpp +src/models/education_type/all.hpp +src/models/day/type.hpp +src/models/day/serialize.hpp +src/models/day/serialize.cpp +src/models/day/postgre.hpp +src/models/day/parse.hpp +src/models/day/parse.cpp +src/models/day/all.hpp src/models/auth_token/type.hpp src/models/auth_token/serialize.hpp src/http/legacy_handler_parsed.hpp src/http/handler_parsed.hpp src/http/ErrorV1.hpp -src/components/controllers/user_controller_fwd.hpp -src/components/controllers/user_controller_fwd.cpp -src/components/controllers/user_controller.hpp -src/components/controllers/user_controller.cpp -src/components/controllers/token_controller_fwd.hpp -src/components/controllers/token_controller_fwd.cpp -src/components/controllers/token_controller.hpp -src/components/controllers/token_controller.cpp +src/helpers/lesson_converter.hpp +src/components/controllers/postgres/user/fwd.hpp +src/components/controllers/postgres/user/fwd.cpp +src/components/controllers/postgres/user/controller.hpp +src/components/controllers/postgres/user/controller.cpp +src/components/controllers/postgres/token/fwd.hpp +src/components/controllers/postgres/token/fwd.cpp +src/components/controllers/postgres/token/controller.hpp +src/components/controllers/postgres/token/controller.cpp +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 diff --git a/.gen/unittest.txt b/.gen/unittest.txt index cf65d423..bb090e37 100644 --- a/.gen/unittest.txt +++ b/.gen/unittest.txt @@ -1,2 +1,4 @@ utests/hello_test.cpp +utests/dropper_additional.cpp +utests/dropper.cpp utests/convert_test.cpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e65fe6e1..025177d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,20 +76,20 @@ jobs: if: matrix.make == 'test-release' run: | make dist-clean - make install PREFIX=`pwd`/local_installation/ + sudo make install-release - name: Test run after install if: matrix.make == 'test-release' run: | - ./local_installation/bin/timetable_vsu_backend --config=./local_installation/etc/timetable_vsu_backend/static_config.yaml & + make run-release & - name: Check work run service if: matrix.make == 'test-release' run: | - ps aux | grep timetable_vsu_backend | grep config && curl http://localhost:8080/ping -v + ps aux | grep timetable_vsu_backend_release && curl http://localhost:8080/ping -v - name: Stop all if: matrix.make == 'test-release' run: | - killall timetable_vsu_backend + killall timetable_vsu_backend_release diff --git a/.github/workflows/delete_old_runs.yml b/.github/workflows/delete_old_runs.yml index 24a8bcea..f195073b 100644 --- a/.github/workflows/delete_old_runs.yml +++ b/.github/workflows/delete_old_runs.yml @@ -54,4 +54,4 @@ jobs: delete_workflow_pattern: ${{ github.event.inputs.delete_workflow_pattern }} delete_workflow_by_state_pattern: ${{ github.event.inputs.delete_workflow_by_state_pattern }} delete_run_by_conclusion_pattern: ${{ github.event.inputs.delete_run_by_conclusion_pattern }} - dry_run: ${{ github.event.inputs.dry_run }} \ No newline at end of file + dry_run: ${{ github.event.inputs.dry_run }} diff --git a/.gitignore b/.gitignore index 8b6438cb..97aa15a2 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ cmake-build-* Testing/ configs/static_config.yaml Makefile.local -merged_api.yaml \ No newline at end of file +merged_api.yaml +tests/results diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..7a73a41b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/Makefile b/Makefile index 1fca6855..2bc0a4e4 100644 --- a/Makefile +++ b/Makefile @@ -34,24 +34,45 @@ cmake-debug cmake-release: cmake-%: build_%/Makefile build-debug build-release: build-%: cmake-% @cmake --build build_$* -j $(NPROCS) --target timetable_vsu_backend -# Test +# Test All .PHONY: test-debug test-release test-debug test-release: test-%: build-% + @rm -rf tests/results @cmake --build build_$* -j $(NPROCS) --target timetable_vsu_backend_unittest @cmake --build build_$* -j $(NPROCS) --target timetable_vsu_backend_benchmark @cd build_$* && ((test -t 1 && GTEST_COLOR=1 PYTEST_ADDOPTS="--color=yes" ctest -V) || ctest -V) @pep8 tests +#run only testsuite tests +#use make testsuite-debug F="some regex" if you want filter tests by regex +.PHONY: testsuite-debug testsuite-release +testsuite-debug testsuite-release: testsuite-%: build-% + @rm -rf tests/results + @cd build_$* && ((test -t 1 && GTEST_COLOR=1 PYTEST_ADDOPTS="--color=yes -k $(F)" ctest -V -R "testsuite")) + # Start the service (via testsuite service runner) .PHONY: service-start-debug service-start-release service-start-debug service-start-release: service-start-%: build-% @cd ./build_$* && $(MAKE) start-timetable_vsu_backend +.PHONY: add-eol +add-eol: + @find $(P) -type f | while read file; do \ + if ! tail -c1 "$$file" | grep -q "^$$"; then \ + # echo "Adding EOL to $$file"; \ + echo >> "$$file"; \ + fi \ + done + # Cleanup data .PHONY: clean-debug clean-release clean-debug clean-release: clean-%: cd build_$* && $(MAKE) clean +.PHONY: check-pep8 +check-pep8: + @pep8 tests + .PHONY: dist-clean dist-clean: @rm -rf build_* @@ -64,9 +85,18 @@ dist-clean: install-debug install-release: install-%: build-% @cd build_$* && \ cmake --install . -v --component timetable_vsu_backend + mv /usr/local/bin/timetable_vsu_backend /usr/local/bin/timetable_vsu_backend_$* + +.PHONY: nothing-debug nothing-release +nothing-debug nothing-release: + +.PHONY: run-debug run-release +run-debug run-release: run-%: nothing-% + @/usr/local/bin/timetable_vsu_backend_$* --config /usr/local/etc/timetable_vsu_backend/static_config.yaml -.PHONY: install -install: install-release +.PHONY: install-run-debug install-run-release +install-run-debug install-run-release: install-run-%: install-% + $(MAKE) run-$* .PHONY: format-cpp format-cpp: @@ -74,15 +104,28 @@ format-cpp: @find service -name '*pp' -type f | xargs $(CLANG_FORMAT) -i @find src -name '*pp' -type f | xargs $(CLANG_FORMAT) -i @find utests -name '*pp' -type f | xargs $(CLANG_FORMAT) -i + $(MAKE) add-eol P=benchs + $(MAKE) add-eol P=service + $(MAKE) add-eol P=src + $(MAKE) add-eol P=utests # Format the sources .PHONY: format-all format-all: format-cpp @find tests -name '*.py' -type f | xargs autopep8 -i + $(MAKE) add-eol P=tests + $(MAKE) add-eol P=scripts + $(MAKE) add-eol P=postgresql + $(MAKE) add-eol P=configs_testing + $(MAKE) add-eol P=configs + $(MAKE) add-eol P=CMakeLists.txt + $(MAKE) add-eol P=redocly.yaml + $(MAKE) add-eol P=united_api.yaml # Check format the sources .PHONY: check-format check-format: check-format-cpp + $(MAKE) check-pep8 .PHONY: check-git-status check-git-status: @@ -120,30 +163,31 @@ gen: @find utests -name '*pp' > .gen/unittest.txt @LC_COLLATE=C sort .gen/unittest.txt -r -o .gen/unittest.txt + $(MAKE) add-eol P=.gen .PHONY: unite-api unite-api: @python3 scripts/merge_yaml.py api/api.yaml united_api.yaml -# Internal hidden targets that are used only in docker environment ---in-docker-start-debug --in-docker-start-release: --in-docker-start-%: install-% - @sed -i 's/config_vars.yaml/config_vars.docker.yaml/g' /home/user/.local/etc/timetable_vsu_backend/static_config.yaml - @psql 'postgresql://user:password@service-postgres:5432/timetable_vsu_backend_db-1' -f ./postgresql/data/initial_data.sql - @/home/user/.local/bin/timetable_vsu_backend \ - --config /home/user/.local/etc/timetable_vsu_backend/static_config.yaml - -# Build and run service in docker environment -.PHONY: docker-start-service-debug docker-start-service-release -docker-start-service-debug docker-start-service-release: docker-start-service-%: - @docker-compose run -p 8080:8080 --rm timetable_vsu_backend-container $(MAKE) -- --in-docker-start-$* - -# Start targets makefile in docker environment -.PHONY: docker-cmake-debug docker-build-debug docker-test-debug docker-clean-debug docker-install-debug docker-cmake-release docker-build-release docker-test-release docker-clean-release docker-install-release -docker-cmake-debug docker-build-debug docker-test-debug docker-clean-debug docker-install-debug docker-cmake-release docker-build-release docker-test-release docker-clean-release docker-install-release: docker-%: - docker-compose run --rm timetable_vsu_backend-container $(MAKE) $* - -# Stop docker container and remove PG data -.PHONY: docker-clean-data -docker-clean-data: - @docker-compose down -v - @rm -rf ./.pgdata \ No newline at end of file +# # Internal hidden targets that are used only in docker environment +# --in-docker-start-debug --in-docker-start-release: --in-docker-start-%: install-% +# @sed -i 's/config_vars.yaml/config_vars.docker.yaml/g' /home/user/.local/etc/timetable_vsu_backend/static_config.yaml +# @psql 'postgresql://user:password@service-postgres:5432/timetable_vsu_backend_db-1' -f ./postgresql/data/initial_data.sql +# @/home/user/.local/bin/timetable_vsu_backend \ +# --config /home/user/.local/etc/timetable_vsu_backend/static_config.yaml + +# # Build and run service in docker environment +# .PHONY: docker-start-service-debug docker-start-service-release +# docker-start-service-debug docker-start-service-release: docker-start-service-%: +# @docker-compose run -p 8080:8080 --rm timetable_vsu_backend-container $(MAKE) -- --in-docker-start-$* + +# # Start targets makefile in docker environment +# .PHONY: docker-cmake-debug docker-build-debug docker-test-debug docker-clean-debug docker-install-debug docker-cmake-release docker-build-release docker-test-release docker-clean-release docker-install-release +# docker-cmake-debug docker-build-debug docker-test-debug docker-clean-debug docker-install-debug docker-cmake-release docker-build-release docker-test-release docker-clean-release docker-install-release: docker-%: +# docker-compose run --rm timetable_vsu_backend-container $(MAKE) $* + +# # Stop docker container and remove PG data +# .PHONY: docker-clean-data +# docker-clean-data: +# @docker-compose down -v +# @rm -rf ./.pgdata diff --git a/README.md b/README.md index 17bf46f4..ca776394 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,12 @@ Makefile contains typicaly useful targets for development: * `make test-release` - does a `make build-release` and runs all the tests on the result * `make service-start-debug` - builds the service in debug mode and starts it * `make service-start-release` - builds the service in release mode and starts it +* `make install-debug` - builds the service in debug mode and install it +* `make install-release` - builds the service in release mode and install it +* `make run-debug` - runs installed debug service +* `make run-release` - runs installed release service +* `make install-run-debug` - builds the service in debug mode install and run it +* `make install-run-release` - builds the service in release mode install and run it * `make` or `make all` - builds and runs all the tests in release and debug modes * `make format-all` - autoformat all the C++ and Python sources * `make format-cpp` - autoformat all the C++ sources @@ -27,17 +33,14 @@ Makefile contains typicaly useful targets for development: * `make dist-clean` - clean all, including the CMake cached configurations * `make install` - does a `make build-release` and run install in directory set in environment `PREFIX` * `make install-debug` - does a `make build-debug` and runs install in directory set in environment `PREFIX` -* `make docker-COMMAND` - run `make COMMAND` in docker environment -* `make docker-build-debug` - debug build of the service with all the assertions and sanitizers enabled in docker environment -* `make docker-test-debug` - does a `make build-debug` and runs all the tests on the result in docker environment -* `make docker-start-service-release` - does a `make install-release` and runs service in docker environment -* `make docker-start-service-debug` - does a `make install-debug` and runs service in docker environment -* `make docker-clean-data` - stop docker containers * `make gen` - regenerate source lists for CMake in .gen * `make check-format-cpp` - сheck formatting in C++ sources, if something is not formatted, an error will be returned +* `make check-pep8` - сheck formatting in Python sources, if something is not formatted, an error will be returned * `make check-format-all` - сheck formatting in all sources, if something is not formatted, an error will be returned * `make unite-api` - create united api file(merged_api.yaml) * `make check-git-status` - сheck if there are changes in files +* `make testsuite-debug F='somestring'` - does a `make build-debug` and runs all the python tests on the result which are filtred by 'somestring' +* `make testsuite-release F='somestring'` - does a `make build-debug` and runs all the python tests on the result which are filtred by 'somestring' Edit `Makefile.local` to change the default configuration and build options. @@ -49,4 +52,4 @@ Use `ln -s build_debug/compile_commands.json compile_commands.json` ## License The original template is distributed under the [Apache-2.0 License](https://github.com/userver-framework/userver/blob/develop/LICENSE) -and [CLA](https://github.com/userver-framework/userver/blob/develop/CONTRIBUTING.md). \ No newline at end of file +and [CLA](https://github.com/userver-framework/userver/blob/develop/CONTRIBUTING.md). diff --git a/api/api.yaml b/api/api.yaml index 416d948e..b7ec7f6d 100644 --- a/api/api.yaml +++ b/api/api.yaml @@ -45,4 +45,4 @@ paths: /admin/teacher/link: $ref: views/admin/teacher/link/view.yaml /admin/teacher/unlink: - $ref: views/admin/teacher/unlink/view.yaml \ No newline at end of file + $ref: views/admin/teacher/unlink/view.yaml diff --git a/api/types/AuthTokenV1.yaml b/api/types/AuthTokenV1.yaml index 7d04e8ab..90dc94da 100644 --- a/api/types/AuthTokenV1.yaml +++ b/api/types/AuthTokenV1.yaml @@ -1,3 +1,3 @@ description: 'Используется для аунтефикации пользователя. Передаем строго через куки' allOf: - - $ref: './Id.yaml' \ No newline at end of file + - $ref: './Id.yaml' diff --git a/api/types/Day.yaml b/api/types/Day.yaml index cfecdb49..3a0f33c2 100644 --- a/api/types/Day.yaml +++ b/api/types/Day.yaml @@ -1,8 +1,8 @@ type: string enum: - - Monday - - Tuesday - - Wednesday - - Thursday - - Friday - - Saturday \ No newline at end of file + - monday + - tuesday + - wednesday + - thursday + - friday + - saturday diff --git a/api/types/EducationType.yaml b/api/types/EducationType.yaml index cfa90aa3..423d8452 100644 --- a/api/types/EducationType.yaml +++ b/api/types/EducationType.yaml @@ -2,5 +2,5 @@ type: string enum: - 'undergraduate' - 'magistracy' - - 'magistracy' - - 'specialty' \ No newline at end of file + - 'postgraduate' + - 'specialty' diff --git a/api/types/ErrorV1.yaml b/api/types/ErrorV1.yaml index 6d0fc3ef..3e15fec3 100644 --- a/api/types/ErrorV1.yaml +++ b/api/types/ErrorV1.yaml @@ -4,4 +4,4 @@ properties: example: 'SMALL_PASSWORD' description: type: string - example: 'Password must have at least 10 symbols' \ No newline at end of file + example: 'Password must have at least 10 symbols' diff --git a/api/types/FacultyV1.yaml b/api/types/FacultyV1.yaml index 38008c70..f100eb0f 100644 --- a/api/types/FacultyV1.yaml +++ b/api/types/FacultyV1.yaml @@ -7,4 +7,4 @@ properties: example: 'Медведев' dean_id: type: string - example: '132131' \ No newline at end of file + example: '132131' diff --git a/api/types/GroupV1.yaml b/api/types/GroupV1.yaml index 4233fc10..87ed4880 100644 --- a/api/types/GroupV1.yaml +++ b/api/types/GroupV1.yaml @@ -4,4 +4,4 @@ properties: course: type: integer type: - $ref: './EducationType.yaml' \ No newline at end of file + $ref: './EducationType.yaml' diff --git a/api/types/Id.yaml b/api/types/Id.yaml index 1cdbefeb..35c78b81 100644 --- a/api/types/Id.yaml +++ b/api/types/Id.yaml @@ -1,3 +1,3 @@ description: 'UUID v4' type: string -example: '6173575e-e86c-4c55-b43d-aa3ca6242181' \ No newline at end of file +example: '6173575e-e86c-4c55-b43d-aa3ca6242181' diff --git a/api/types/LessonV1.yaml b/api/types/LessonV1.yaml index 4e29f1a6..95991bbd 100644 --- a/api/types/LessonV1.yaml +++ b/api/types/LessonV1.yaml @@ -1,4 +1,49 @@ properties: + id: + $ref: './Id.yaml' + begin: + $ref: './Timestamp.yaml' + end: + $ref: './Timestamp.yaml' + number: + $ref: './NumberLesson.yaml' + type: + $ref: './TypeOfLesson.yaml' + week_type: + $ref: './TypeOfWeek.yaml' + subgroup: + $ref: './Subgroup.yaml' + subject_id: + $ref: './Id.yaml' + day: + $ref: './Day.yaml' + subject_name: + type: string + example: 'Дифференциальные уравнения' + group_id: + $ref: './Id.yaml' + group_course: + type: integer + minimum: 1 + maximum: 6 + group_name: + type: string + description: 'Название группы' + example: 'ФИИТ' + group_type: + $ref: './EducationType.yaml' + faculty_id: + $ref: './Id.yaml' + faculty_name: + type: string + example: 'ПММ' + description: 'Название факультета' + department_id: + $ref: './Id.yaml' + department_name: + type: string + example: 'ПММ' + description: 'Название факультета' room_id: $ref: './Id.yaml' room_name: @@ -8,25 +53,9 @@ properties: teacher_id: type: string example: 'some_id' + teacher_bio: + type: string + example: 'Нереально работаю в ВГУ' teacher_fio: type: string example: 'Иванов Иван Иванович' - subject_id: - $ref: './Id.yaml' - subject_name: - type: string - example: 'Дифференциальные уравнения' - group: - $ref: './GroupV1.yaml' - group_id: - $ref: './Id.yaml' - week: - $ref: './TypeOfWeek.yaml' - subgroup: - $ref: './Subgroup.yaml' - begin: - $ref: './Timestamp.yaml' - end: - $ref: './Timestamp.yaml' - type_lesson: - $ref: './TypeOfLesson.yaml' \ No newline at end of file diff --git a/api/types/NumberLesson.yaml b/api/types/NumberLesson.yaml index c8e3c692..b1258d10 100644 --- a/api/types/NumberLesson.yaml +++ b/api/types/NumberLesson.yaml @@ -6,4 +6,4 @@ enum: - 4 - 5 - 6 - - 7 \ No newline at end of file + - 7 diff --git a/api/types/Subgroup.yaml b/api/types/Subgroup.yaml index 3beec741..f65b4cef 100644 --- a/api/types/Subgroup.yaml +++ b/api/types/Subgroup.yaml @@ -1,6 +1,6 @@ description: 'Тип подгруппы: All - для обеих' type: string enum: - - All - - First - - Second \ No newline at end of file + - all + - first + - second diff --git a/api/types/TeacherV1.yaml b/api/types/TeacherV1.yaml index 9b1d414f..66a6bd26 100644 --- a/api/types/TeacherV1.yaml +++ b/api/types/TeacherV1.yaml @@ -14,4 +14,4 @@ properties: $ref: './types/Id.yaml' bio: type: string - example: 'Работаю 100500 лет, люблю ВГУ' \ No newline at end of file + example: 'Работаю 100500 лет, люблю ВГУ' diff --git a/api/types/Timestamp.yaml b/api/types/Timestamp.yaml index 3fdc7c89..329078e2 100644 --- a/api/types/Timestamp.yaml +++ b/api/types/Timestamp.yaml @@ -1,2 +1,2 @@ type: string -example: '2010-02-10-08.15.000Z' \ No newline at end of file +example: '2023-04-01T05:30:00+0000' diff --git a/api/types/TypeOfLesson.yaml b/api/types/TypeOfLesson.yaml index b3bae18d..aa252d0c 100644 --- a/api/types/TypeOfLesson.yaml +++ b/api/types/TypeOfLesson.yaml @@ -1,6 +1,6 @@ description: 'Тип пары' type: string enum: - - Labaratory - - Lection - - Practice \ No newline at end of file + - labaratory + - lection + - practice diff --git a/api/types/TypeOfWeek.yaml b/api/types/TypeOfWeek.yaml index 9e03accb..2c7a7335 100644 --- a/api/types/TypeOfWeek.yaml +++ b/api/types/TypeOfWeek.yaml @@ -1,6 +1,6 @@ description: 'Тип недели: All - всегда, Even - только по числителю, Odd - только по знаменателю' type: string enum: - - All - - Even - - Odd \ No newline at end of file + - all + - even + - odd diff --git a/api/types/UserCredentialV1.yaml b/api/types/UserCredentialV1.yaml index 5230ab81..d32236fa 100644 --- a/api/types/UserCredentialV1.yaml +++ b/api/types/UserCredentialV1.yaml @@ -7,4 +7,4 @@ properties: example: 'some_password' required: - login - - password \ No newline at end of file + - password diff --git a/api/types/UserTypeV1.yaml b/api/types/UserTypeV1.yaml index 529bf5bc..02d6a3f6 100644 --- a/api/types/UserTypeV1.yaml +++ b/api/types/UserTypeV1.yaml @@ -3,4 +3,4 @@ enum: - 'user' - 'teacher' - 'admin' - - 'root' #may be unused \ No newline at end of file + - 'root' #may be unused diff --git a/api/views/admin/group/add/Request.yaml b/api/views/admin/group/add/Request.yaml index b93e42aa..a18813c7 100644 --- a/api/views/admin/group/add/Request.yaml +++ b/api/views/admin/group/add/Request.yaml @@ -6,4 +6,4 @@ properties: type: integer example: 3 group_type: - $ref: '../../../../types/EducationType.yaml' \ No newline at end of file + $ref: '../../../../types/EducationType.yaml' diff --git a/api/views/admin/group/add/view.yaml b/api/views/admin/group/add/view.yaml index b57c792b..d16018cb 100644 --- a/api/views/admin/group/add/view.yaml +++ b/api/views/admin/group/add/view.yaml @@ -32,4 +32,4 @@ post: content: application/json: schema: - $ref: '../../../../types/ErrorV1.yaml' \ No newline at end of file + $ref: '../../../../types/ErrorV1.yaml' diff --git a/api/views/admin/group/lesson/add/Request.yaml b/api/views/admin/group/lesson/add/Request.yaml index dcf9d344..17703dbf 100644 --- a/api/views/admin/group/lesson/add/Request.yaml +++ b/api/views/admin/group/lesson/add/Request.yaml @@ -2,4 +2,4 @@ properties: group_id: $ref: '../../../../../types/Id.yaml' subject_id: - $ref: '../../../../../types/Id.yaml' \ No newline at end of file + $ref: '../../../../../types/Id.yaml' diff --git a/api/views/admin/group/lesson/add/view.yaml b/api/views/admin/group/lesson/add/view.yaml index 282103af..ef269c81 100644 --- a/api/views/admin/group/lesson/add/view.yaml +++ b/api/views/admin/group/lesson/add/view.yaml @@ -28,4 +28,4 @@ post: content: application/json: schema: - $ref: '../../../../../types/ErrorV1.yaml' \ No newline at end of file + $ref: '../../../../../types/ErrorV1.yaml' diff --git a/api/views/admin/group/lesson/remove/Request.yaml b/api/views/admin/group/lesson/remove/Request.yaml index dcf9d344..17703dbf 100644 --- a/api/views/admin/group/lesson/remove/Request.yaml +++ b/api/views/admin/group/lesson/remove/Request.yaml @@ -2,4 +2,4 @@ properties: group_id: $ref: '../../../../../types/Id.yaml' subject_id: - $ref: '../../../../../types/Id.yaml' \ No newline at end of file + $ref: '../../../../../types/Id.yaml' diff --git a/api/views/admin/group/lesson/remove/view.yaml b/api/views/admin/group/lesson/remove/view.yaml index 1202ba99..24b6f428 100644 --- a/api/views/admin/group/lesson/remove/view.yaml +++ b/api/views/admin/group/lesson/remove/view.yaml @@ -28,4 +28,4 @@ post: content: application/json: schema: - $ref: '../../../../../types/ErrorV1.yaml' \ No newline at end of file + $ref: '../../../../../types/ErrorV1.yaml' diff --git a/api/views/admin/group/remove/Request.yaml b/api/views/admin/group/remove/Request.yaml index a1dafbda..2e15e36a 100644 --- a/api/views/admin/group/remove/Request.yaml +++ b/api/views/admin/group/remove/Request.yaml @@ -1,3 +1,3 @@ properties: group_id: - $ref: '../../../../types/Id.yaml' \ No newline at end of file + $ref: '../../../../types/Id.yaml' diff --git a/api/views/admin/group/remove/view.yaml b/api/views/admin/group/remove/view.yaml index 6a8ff730..c5548388 100644 --- a/api/views/admin/group/remove/view.yaml +++ b/api/views/admin/group/remove/view.yaml @@ -32,4 +32,4 @@ post: content: application/json: schema: - $ref: '../../../../types/ErrorV1.yaml' \ No newline at end of file + $ref: '../../../../types/ErrorV1.yaml' diff --git a/api/views/admin/group/teacher/add/Request.yaml b/api/views/admin/group/teacher/add/Request.yaml index c1c1c37d..cb81e572 100644 --- a/api/views/admin/group/teacher/add/Request.yaml +++ b/api/views/admin/group/teacher/add/Request.yaml @@ -4,4 +4,4 @@ properties: subject_id: $ref: '../../../../../types/Id.yaml' teacher_id: - $ref: '../../../../../types/Id.yaml' \ No newline at end of file + $ref: '../../../../../types/Id.yaml' diff --git a/api/views/admin/group/teacher/add/view.yaml b/api/views/admin/group/teacher/add/view.yaml index dc2a7ff2..a242606a 100644 --- a/api/views/admin/group/teacher/add/view.yaml +++ b/api/views/admin/group/teacher/add/view.yaml @@ -28,4 +28,4 @@ post: content: application/json: schema: - $ref: '../../../../../types/ErrorV1.yaml' \ No newline at end of file + $ref: '../../../../../types/ErrorV1.yaml' diff --git a/api/views/admin/group/teacher/remove/Request.yaml b/api/views/admin/group/teacher/remove/Request.yaml index c1c1c37d..cb81e572 100644 --- a/api/views/admin/group/teacher/remove/Request.yaml +++ b/api/views/admin/group/teacher/remove/Request.yaml @@ -4,4 +4,4 @@ properties: subject_id: $ref: '../../../../../types/Id.yaml' teacher_id: - $ref: '../../../../../types/Id.yaml' \ No newline at end of file + $ref: '../../../../../types/Id.yaml' diff --git a/api/views/admin/group/teacher/remove/view.yaml b/api/views/admin/group/teacher/remove/view.yaml index c7a073e6..319aa578 100644 --- a/api/views/admin/group/teacher/remove/view.yaml +++ b/api/views/admin/group/teacher/remove/view.yaml @@ -28,4 +28,4 @@ post: content: application/json: schema: - $ref: '../../../../../types/ErrorV1.yaml' \ No newline at end of file + $ref: '../../../../../types/ErrorV1.yaml' diff --git a/api/views/admin/teacher/link/Request.yaml b/api/views/admin/teacher/link/Request.yaml index 786ff93b..099e45da 100644 --- a/api/views/admin/teacher/link/Request.yaml +++ b/api/views/admin/teacher/link/Request.yaml @@ -2,4 +2,4 @@ properties: user_id: $ref: '../../../../types/Id.yaml' teacher_id: - $ref: '../../../../types/Id.yaml' \ No newline at end of file + $ref: '../../../../types/Id.yaml' diff --git a/api/views/admin/teacher/link/view.yaml b/api/views/admin/teacher/link/view.yaml index 06a57890..ec05784b 100644 --- a/api/views/admin/teacher/link/view.yaml +++ b/api/views/admin/teacher/link/view.yaml @@ -28,4 +28,4 @@ post: content: application/json: schema: - $ref: '../../../../types/ErrorV1.yaml' \ No newline at end of file + $ref: '../../../../types/ErrorV1.yaml' diff --git a/api/views/admin/teacher/unlink/Request.yaml b/api/views/admin/teacher/unlink/Request.yaml index 786ff93b..099e45da 100644 --- a/api/views/admin/teacher/unlink/Request.yaml +++ b/api/views/admin/teacher/unlink/Request.yaml @@ -2,4 +2,4 @@ properties: user_id: $ref: '../../../../types/Id.yaml' teacher_id: - $ref: '../../../../types/Id.yaml' \ No newline at end of file + $ref: '../../../../types/Id.yaml' diff --git a/api/views/admin/teacher/unlink/view.yaml b/api/views/admin/teacher/unlink/view.yaml index ec03c6fa..d498333b 100644 --- a/api/views/admin/teacher/unlink/view.yaml +++ b/api/views/admin/teacher/unlink/view.yaml @@ -28,4 +28,4 @@ post: content: application/json: schema: - $ref: '../../../../types/ErrorV1.yaml' \ No newline at end of file + $ref: '../../../../types/ErrorV1.yaml' diff --git a/api/views/get-timetable/Request.yaml b/api/views/get-timetable/Request.yaml index 93d5c25d..71592aa2 100644 --- a/api/views/get-timetable/Request.yaml +++ b/api/views/get-timetable/Request.yaml @@ -1,31 +1,83 @@ properties: - teacher_id: - type: string - teacher_fio: - type: string - subject_name: - type: string - room_name: - type: string + lesson_ids: + type: array + items: + $ref: '../../types/Id.yaml' + begin: + $ref: '../../types/Timestamp.yaml' + end: + ref: '../../types/Timestamp.yaml' days: type: array items: $ref: '../../types/Day.yaml' + department_ids: + type: array + items: + $ref: '../../types/Id.yaml' + department_names: + type: array + items: + type: string + faculty_ids: + type: array + items: + $ref: '../../types/Id.yaml' + faculty_names: + type: array + items: + type: string + group_ids: + type: array + items: + $ref: '../../types/Id.yaml' + group_names: + type: array + items: + type: string + group_courses: + type: array + items: + type: integer + group_types: + type: array + items: + type: '../../types/EducationType.yaml' + room_ids: + type: array + items: + $ref: '../../types/Id.yaml' + room_names: + type: array + items: + type: string subgroup: $ref: '../../types/Subgroup.yaml' + subject_ids: + type: array + items: + $ref: '../../types/Id.yaml' + subject_names: + type: array + items: + type: string + teacher_ids: + type: array + items: + $ref: '../../types/Id.yaml' + teacher_fios: + type: array + items: + type: string + teacher_bios: + type: array + items: + type: string week: $ref: '../../types/TypeOfWeek.yaml' - faculty_name: - type: string - faculty_id: - type: string - department_name: - type: string - department_id: - type: string - group_id: - type: string - group_name: - type: string - group_course: - type: string \ No newline at end of file + lesson_type: + $ref: '../../types/TypeOfLesson.yaml' + numbers: + type: array + items: + type: integer diff --git a/api/views/get-timetable/view.yaml b/api/views/get-timetable/view.yaml index 09270a19..f7143a96 100644 --- a/api/views/get-timetable/view.yaml +++ b/api/views/get-timetable/view.yaml @@ -15,4 +15,4 @@ post: schema: type: array items: - $ref: '../../types/LessonV1.yaml' \ No newline at end of file + $ref: '../../types/LessonV1.yaml' diff --git a/api/views/lesson/add/Request.yaml b/api/views/lesson/add/Request.yaml index 9ee2cf4f..be43ebab 100644 --- a/api/views/lesson/add/Request.yaml +++ b/api/views/lesson/add/Request.yaml @@ -8,4 +8,4 @@ properties: start: $ref: '../../../types/Timestamp.yaml' end: - $ref: '../../../types/Timestamp.yaml' \ No newline at end of file + $ref: '../../../types/Timestamp.yaml' diff --git a/api/views/lesson/add/view.yaml b/api/views/lesson/add/view.yaml index c468efe0..0afeee5c 100644 --- a/api/views/lesson/add/view.yaml +++ b/api/views/lesson/add/view.yaml @@ -31,4 +31,4 @@ post: content: application/json: schema: - $ref: '../../../types/ErrorV1.yaml' \ No newline at end of file + $ref: '../../../types/ErrorV1.yaml' diff --git a/api/views/lesson/move/Request.yaml b/api/views/lesson/move/Request.yaml index c2ba3c8d..bbe7a185 100644 --- a/api/views/lesson/move/Request.yaml +++ b/api/views/lesson/move/Request.yaml @@ -10,4 +10,4 @@ properties: start: $ref: '../../../types/Timestamp.yaml' end: - $ref: '../../../types/Timestamp.yaml' \ No newline at end of file + $ref: '../../../types/Timestamp.yaml' diff --git a/api/views/lesson/move/view.yaml b/api/views/lesson/move/view.yaml index b81cd172..036d67bc 100644 --- a/api/views/lesson/move/view.yaml +++ b/api/views/lesson/move/view.yaml @@ -33,4 +33,4 @@ post: content: application/json: schema: - $ref: '../../../types/ErrorV1.yaml' \ No newline at end of file + $ref: '../../../types/ErrorV1.yaml' diff --git a/api/views/lesson/remove/Request.yaml b/api/views/lesson/remove/Request.yaml index 4ee5eab5..47be4bf1 100644 --- a/api/views/lesson/remove/Request.yaml +++ b/api/views/lesson/remove/Request.yaml @@ -4,4 +4,4 @@ properties: start: $ref: '../../../types/Timestamp.yaml' end: - $ref: '../../../types/Timestamp.yaml' \ No newline at end of file + $ref: '../../../types/Timestamp.yaml' diff --git a/api/views/lesson/remove/view.yaml b/api/views/lesson/remove/view.yaml index e50e114f..018b9091 100644 --- a/api/views/lesson/remove/view.yaml +++ b/api/views/lesson/remove/view.yaml @@ -31,4 +31,4 @@ post: content: application/json: schema: - $ref: '../../../types/ErrorV1.yaml' \ No newline at end of file + $ref: '../../../types/ErrorV1.yaml' diff --git a/api/views/login/ResponseV1.yaml b/api/views/login/ResponseV1.yaml index cf3ba770..e90284a2 100644 --- a/api/views/login/ResponseV1.yaml +++ b/api/views/login/ResponseV1.yaml @@ -2,4 +2,4 @@ properties: token: $ref: '../../types/AuthTokenV1.yaml' user_type: - $ref: ../../types/UserTypeV1.yaml \ No newline at end of file + $ref: ../../types/UserTypeV1.yaml diff --git a/api/views/login/view.yaml b/api/views/login/view.yaml index b504861d..e6dc1a28 100644 --- a/api/views/login/view.yaml +++ b/api/views/login/view.yaml @@ -21,4 +21,4 @@ post: content: application/json: schema: - $ref : '../../types/ErrorV1.yaml' \ No newline at end of file + $ref : '../../types/ErrorV1.yaml' diff --git a/api/views/register/RequestV1.yaml b/api/views/register/RequestV1.yaml index ab0a68e5..d905e885 100644 --- a/api/views/register/RequestV1.yaml +++ b/api/views/register/RequestV1.yaml @@ -2,4 +2,4 @@ properties: user_credential: $ref: '../../types/UserCredentialV1.yaml' user_type: - $ref: '../../types/UserTypeV1.yaml' \ No newline at end of file + $ref: '../../types/UserTypeV1.yaml' diff --git a/api/views/register/view.yaml b/api/views/register/view.yaml index 664d273f..8060f0f9 100644 --- a/api/views/register/view.yaml +++ b/api/views/register/view.yaml @@ -19,4 +19,4 @@ post: content: application/json: schema: - $ref : '../../types/ErrorV1.yaml' \ No newline at end of file + $ref : '../../types/ErrorV1.yaml' diff --git a/configs/config_dev.yaml b/configs/config_dev.yaml deleted file mode 100644 index 5ea8d2d9..00000000 --- a/configs/config_dev.yaml +++ /dev/null @@ -1,9 +0,0 @@ -worker-threads: 4 -worker-fs-threads: 2 -logger-level: debug - -is_testing: false - -server-port: 8080 - -dbconnection: 'postgresql://timetable_vsu_backend_user:password@localhost:5432/timetable_vsu_backend_db_1' \ No newline at end of file diff --git a/configs/config_vars.docker.yaml b/configs/config_vars.docker.yaml index bb93e69e..b565aa3c 100644 --- a/configs/config_vars.docker.yaml +++ b/configs/config_vars.docker.yaml @@ -6,4 +6,4 @@ is_testing: false server-port: 8080 -dbconnection: 'postgresql://user:password@service-postgres:5432/timetable_vsu_backend_db_1' \ No newline at end of file +dbconnection: 'postgresql://user:password@service-postgres:5432/timetable_vsu_backend_db_1' diff --git a/configs/config_vars.yaml b/configs/config_vars.yaml index 5ea8d2d9..6e9e1f9a 100644 --- a/configs/config_vars.yaml +++ b/configs/config_vars.yaml @@ -6,4 +6,4 @@ is_testing: false server-port: 8080 -dbconnection: 'postgresql://timetable_vsu_backend_user:password@localhost:5432/timetable_vsu_backend_db_1' \ No newline at end of file +dbconnection: 'postgresql://timetable_vsu_backend_user:password@localhost:5432/timetable_vsu_backend_db_1' diff --git a/configs/dynamic_config_fallback.json b/configs/dynamic_config_fallback.json index 07d7288a..f91a591a 100644 --- a/configs/dynamic_config_fallback.json +++ b/configs/dynamic_config_fallback.json @@ -61,4 +61,4 @@ "max_statement_metrics": 5 } } -} \ No newline at end of file +} diff --git a/configs/static_config.yaml.in b/configs/static_config.yaml.in index dfd3adc6..e7988b8c 100644 --- a/configs/static_config.yaml.in +++ b/configs/static_config.yaml.in @@ -61,6 +61,10 @@ components_manager: path: /register method: POST task_processor: main-task-processor + handler-get-timetable: + path: /get-timetable + method: GET,POST + task_processor: main-task-processor postgres-db-1: dbconnection: $dbconnection blocking_task_processor: fs-task-processor @@ -68,7 +72,7 @@ components_manager: sync-start: true user_controller: {} token_controller: {} - + lesson_details_controller : {} handler-ping: path: /ping method: GET diff --git a/configs_testing/config_vars_testing.yaml b/configs_testing/config_vars_testing.yaml index c580077d..cbdf8fb9 100644 --- a/configs_testing/config_vars_testing.yaml +++ b/configs_testing/config_vars_testing.yaml @@ -7,4 +7,4 @@ is_testing: true server-port: 8080 # timetable_vsu_backend_db_1 is the service name + _ + filename of the db_1.sql -dbconnection: 'postgresql://testsuite:password@localhost:15433/timetable_vsu_backend_db_1' \ No newline at end of file +dbconnection: 'postgresql://testsuite:password@localhost:15433/timetable_vsu_backend_db_1' diff --git a/dependencies/python.md b/dependencies/python.md index ddb37e19..658130bb 100644 --- a/dependencies/python.md +++ b/dependencies/python.md @@ -1 +1 @@ -psycopg2 \ No newline at end of file +psycopg2 diff --git a/docker-compose.yml b/docker-compose.yml index 53092599..b492f439 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,4 +50,4 @@ services: networks: postgres: - driver: bridge \ No newline at end of file + driver: bridge diff --git a/postgresql/data/initial_data_auth.sql b/postgresql/data/initial_data_auth.sql index fe5ff088..becb87a0 100644 --- a/postgresql/data/initial_data_auth.sql +++ b/postgresql/data/initial_data_auth.sql @@ -1,2 +1,2 @@ -INSERT INTO vsu_timetable.user(login, password, user_type) -VALUES('some_nickname', 'some_password', 'user'); \ No newline at end of file +INSERT INTO vsu_timetable.user(login, password) +VALUES('some_nickname', 'some_password'); diff --git a/postgresql/data/initial_data_hello.sql b/postgresql/data/initial_data_hello.sql index 8f5ad4de..77296cb4 100644 --- a/postgresql/data/initial_data_hello.sql +++ b/postgresql/data/initial_data_hello.sql @@ -1,4 +1,4 @@ INSERT INTO hello_schema.users(name, count) VALUES ('user-from-initial_data.sql', 42) ON CONFLICT (name) -DO NOTHING; \ No newline at end of file +DO NOTHING; diff --git a/postgresql/data/initial_data_timetable1.sql b/postgresql/data/initial_data_timetable1.sql new file mode 100644 index 00000000..c7367bdd --- /dev/null +++ b/postgresql/data/initial_data_timetable1.sql @@ -0,0 +1,37 @@ +-- Insert test data into the faculty table +INSERT INTO vsu_timetable.faculty (id, name) +VALUES ('bbc6312c-f25e-4db3-b2a0-3f5dc6717a8d', 'Faculty of Mathematics and Mechanics'); + +-- Insert test data into the department table +INSERT INTO vsu_timetable.department (id, name, id_faculty) +VALUES ('1f93ceb4-d931-4b66-a0e5-7323d6b60f3b', 'Department of Applied Mathematics', 'bbc6312c-f25e-4db3-b2a0-3f5dc6717a8d'); + +-- Insert test data into the teacher table +INSERT INTO vsu_timetable.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 vsu_timetable.group (id, name, type) +VALUES ('c1fb3eac-de6d-44ef-bf35-18bebe832e1d', 'MM-21', 'magistracy'); + +-- Insert test data into the group_stage table +INSERT INTO vsu_timetable.group_stage (id, begin, "end", course, id_group) +VALUES ('4148147a-740b-48f9-aba1-47eb17432855', '2023-09-01 00:00:00', '2024-06-30 00:00:00', 1, 'c1fb3eac-de6d-44ef-bf35-18bebe832e1d'); + +-- Insert test data into the room table +INSERT INTO vsu_timetable.room (id, name) +VALUES ('f245127f-a730-4d13-a15d-7648deb1d4d2', '101'); + +-- Insert test data into the subject table +INSERT INTO vsu_timetable.subject (id, name) +VALUES ('053222c5-315a-4301-abfe-586d2409fcd3', 'Mathematics'); + +-- Insert test data into the shedule table +INSERT INTO vsu_timetable.shedule (id, id_teacher, id_subject, id_group_stage) +VALUES ('ab5f0559-d2ee-4030-919e-5962f1ff2235', '241416c7-9654-4814-b36b-7d39c1ddded2', '053222c5-315a-4301-abfe-586d2409fcd3', '4148147a-740b-48f9-aba1-47eb17432855'); + +-- Insert test data into the lesson table +INSERT INTO vsu_timetable.lesson (id, begin, "end", number_lesson, type_lesson, type_week, subgroup, day, id_room, id_shedule) +VALUES ('3d04fc36-ab71-42db-9e38-efd792afa7ba', '2023-04-01 08:30:00', '2023-05-01 10:05:00', 1, 'lection', 'all', 'all', 'monday', +'f245127f-a730-4d13-a15d-7648deb1d4d2', +'ab5f0559-d2ee-4030-919e-5962f1ff2235'); diff --git a/postgresql/data/initial_data_timetable2.sql b/postgresql/data/initial_data_timetable2.sql new file mode 100644 index 00000000..6d7e239b --- /dev/null +++ b/postgresql/data/initial_data_timetable2.sql @@ -0,0 +1,37 @@ +-- Insert test data into the faculty table +INSERT INTO vsu_timetable.faculty (id, name) +VALUES ('af8f26b8-afc7-483d-b6cc-ffaec29d4bc7', 'ПММ'); + +-- Insert test data into the department table +INSERT INTO vsu_timetable.department (id, name, id_faculty) +VALUES ('3ec37598-6c49-4a02-8134-d9dbffafa8c4', 'МОЭВМ', 'af8f26b8-afc7-483d-b6cc-ffaec29d4bc7'); + +-- Insert test data into the teacher table +INSERT INTO vsu_timetable.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 vsu_timetable.group (id, name, type) +VALUES ('c8a34f05-f081-4d78-b971-30d562fd9f1c', '62', 'undergraduate'); + +-- Insert test data into the group_stage table +INSERT INTO vsu_timetable.group_stage (id, begin, "end", course, id_group) +VALUES ('4f9c8f36-c007-4d1a-9255-4a4ce8d45a96', '2023-09-01 00:00:00', '2024-06-30 00:00:00', 1, 'c8a34f05-f081-4d78-b971-30d562fd9f1c'); + +-- Insert test data into the room table +INSERT INTO vsu_timetable.room (id, name) +VALUES ('b5a90d34-307f-4ab1-9caf-8b6749189de8', '101'); + +-- Insert test data into the subject table +INSERT INTO vsu_timetable.subject (id, name) +VALUES ('6990a617-405e-492a-990f-621ab0411623', 'Mathematics'); + +-- Insert test data into the shedule table +INSERT INTO vsu_timetable.shedule (id, id_teacher, id_subject, id_group_stage) +VALUES ('75021a69-9ceb-4eec-8151-34f93c0af429', 'dc5bad6f-fcf6-4869-b0e5-5c36aed85cc1', '6990a617-405e-492a-990f-621ab0411623', '4f9c8f36-c007-4d1a-9255-4a4ce8d45a96'); + +-- Insert test data into the lesson table +INSERT INTO vsu_timetable.lesson (id, begin, "end", number_lesson, type_lesson, type_week, subgroup, day, id_room, id_shedule) +VALUES ('6e3092e3-ac10-47a8-b52b-a15682ecc40c', '2021-09-01 08:30:00', '2021-10-01 10:05:00', 1, 'practice', 'even', 'first', 'monday', +'b5a90d34-307f-4ab1-9caf-8b6749189de8', +'75021a69-9ceb-4eec-8151-34f93c0af429'); diff --git a/postgresql/data/timetable_random.sql b/postgresql/data/timetable_random.sql new file mode 100644 index 00000000..bc6b743b --- /dev/null +++ b/postgresql/data/timetable_random.sql @@ -0,0 +1,47 @@ +-- Insert test data into the user table +INSERT INTO vsu_timetable.user (login, password) +VALUES ('user1', 'password1'); + +-- Insert test data into the token table +INSERT INTO vsu_timetable.token (expire_time, id_user) +VALUES ('2023-04-18 12:00:00', (SELECT id FROM vsu_timetable.user ORDER BY random() LIMIT 1)); + +-- Insert test data into the admin table +INSERT INTO vsu_timetable.admin (id_user) +VALUES ((SELECT id FROM vsu_timetable.user ORDER BY random() LIMIT 1)); + +-- Insert test data into the faculty table +INSERT INTO vsu_timetable.faculty (name) +VALUES ('Faculty of Mathematics and Mechanics'); + +-- Insert test data into the department table +INSERT INTO vsu_timetable.department (name, id_faculty) +VALUES ('Department of Applied Mathematics', (SELECT id FROM vsu_timetable.faculty ORDER BY random() LIMIT 1)); + +-- Insert test data into the teacher table +INSERT INTO vsu_timetable.teacher (fio, bio, id_department) +VALUES ('John Doe', 'Professor of Mathematics', (SELECT id FROM vsu_timetable.department ORDER BY random() LIMIT 1)); + +-- Insert test data into the group table +INSERT INTO vsu_timetable."group" (name, type) +VALUES ('MM-21', 'magistracy'); + +-- Insert test data into the group_stage table +INSERT INTO vsu_timetable.group_stage (begin, "end", course, id_group) +VALUES ('2023-09-01 00:00:00', '2024-06-30 00:00:00', 1, (SELECT id FROM vsu_timetable."group" ORDER BY random() LIMIT 1)); + +-- Insert test data into the room table +INSERT INTO vsu_timetable.room (name) +VALUES ('Room 101'); + +-- Insert test data into the subject table +INSERT INTO vsu_timetable.subject (name) +VALUES ('Mathematics'); + +-- Insert test data into the shedule table +INSERT INTO vsu_timetable.shedule (id_teacher, id_subject, id_group_stage) +VALUES ((SELECT id FROM vsu_timetable.teacher ORDER BY random() LIMIT 1), (SELECT id FROM vsu_timetable.subject ORDER BY random() LIMIT 1), (SELECT id FROM vsu_timetable.group_stage ORDER BY random() LIMIT 1)); + +-- Insert test data into the lesson table +INSERT INTO vsu_timetable.lesson (begin, "end", number_lesson, type_lesson, type_week, subgroup, day, id_room, id_shedule) +VALUES ('2023-09-01 08:30:00', '2023-09-01 10:05:00', 1, 'lection', 'all', 'all', 'monday', (SELECT id FROM vsu_timetable.room ORDER BY random() LIMIT 1), (SELECT id FROM vsu_timetable.shedule ORDER BY random() LIMIT 1)); diff --git a/postgresql/schemas/db_1/000_init.sql b/postgresql/schemas/db_1/000_init.sql new file mode 100755 index 00000000..b0d49e7a --- /dev/null +++ b/postgresql/schemas/db_1/000_init.sql @@ -0,0 +1,257 @@ +BEGIN; + +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; +DROP SCHEMA IF EXISTS vsu_timetable CASCADE; + +CREATE SCHEMA vsu_timetable; + + +DROP TABLE IF EXISTS vsu_timetable."user" CASCADE; +CREATE TABLE vsu_timetable."user" ( + id uuid NOT NULL DEFAULT uuid_generate_v4(), + login text, + password text, + CONSTRAINT user_pk PRIMARY KEY (id) +); + +DROP TABLE IF EXISTS vsu_timetable.token CASCADE; +CREATE TABLE vsu_timetable.token ( + id uuid NOT NULL DEFAULT uuid_generate_v4(), + expire_time timestamptz, + id_user uuid NOT NULL, + CONSTRAINT token_pk PRIMARY KEY (id) +); + + +ALTER TABLE vsu_timetable.token DROP CONSTRAINT IF EXISTS user_fk CASCADE; +ALTER TABLE vsu_timetable.token ADD CONSTRAINT user_fk FOREIGN KEY (id_user) REFERENCES vsu_timetable."user" (id) MATCH FULL ON DELETE RESTRICT ON UPDATE CASCADE; + + +DROP TABLE IF EXISTS vsu_timetable.admin CASCADE; +CREATE TABLE vsu_timetable.admin ( + id uuid NOT NULL DEFAULT uuid_generate_v4(), + id_user uuid NOT NULL, + CONSTRAINT admin_pk PRIMARY KEY (id) +); +ALTER TABLE vsu_timetable.admin DROP CONSTRAINT IF EXISTS user_fk CASCADE; +ALTER TABLE vsu_timetable.admin ADD CONSTRAINT user_fk FOREIGN KEY (id_user) REFERENCES vsu_timetable."user" (id) MATCH FULL ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE vsu_timetable.admin DROP CONSTRAINT IF EXISTS admin_user_unique CASCADE; +ALTER TABLE vsu_timetable.admin ADD CONSTRAINT admin_user_unique UNIQUE(id_user); + + +DROP TABLE IF EXISTS vsu_timetable.faculty CASCADE; +CREATE TABLE vsu_timetable.faculty ( + id uuid NOT NULL DEFAULT uuid_generate_v4(), + name text, + CONSTRAINT faculty_pk PRIMARY KEY (id) +); + + + +DROP TABLE IF EXISTS vsu_timetable.department CASCADE; +CREATE TABLE vsu_timetable.department ( + id uuid NOT NULL DEFAULT uuid_generate_v4(), + name text, + id_faculty uuid, + CONSTRAINT department_pk PRIMARY KEY (id) +); + + + +ALTER TABLE vsu_timetable.department DROP CONSTRAINT IF EXISTS faculty_fk CASCADE; +ALTER TABLE vsu_timetable.department ADD CONSTRAINT faculty_fk FOREIGN KEY (id_faculty) +REFERENCES vsu_timetable.faculty (id) MATCH FULL +ON DELETE SET NULL ON UPDATE CASCADE; + + + +CREATE TABLE vsu_timetable.teacher ( + id uuid NOT NULL DEFAULT uuid_generate_v4(), + fio text, + bio text, + id_department uuid, + CONSTRAINT teacher_pk PRIMARY KEY (id) +); + + + +ALTER TABLE vsu_timetable.teacher DROP CONSTRAINT IF EXISTS department_fk CASCADE; +ALTER TABLE vsu_timetable.teacher ADD CONSTRAINT department_fk FOREIGN KEY (id_department) +REFERENCES vsu_timetable.department (id) MATCH FULL +ON DELETE SET NULL ON UPDATE CASCADE; + + + +DROP TYPE IF EXISTS vsu_timetable.grouptype CASCADE; +CREATE TYPE vsu_timetable.grouptype AS +ENUM ('undergraduate','magistracy','postgraduate','specialty'); + + + +DROP TABLE IF EXISTS vsu_timetable."group" CASCADE; +CREATE TABLE vsu_timetable."group" ( + id uuid NOT NULL DEFAULT uuid_generate_v4(), + name text, + type vsu_timetable.grouptype, + CONSTRAINT group_pk PRIMARY KEY (id) +); + + + +DROP TABLE IF EXISTS vsu_timetable.group_stage CASCADE; +CREATE TABLE vsu_timetable.group_stage ( + id uuid NOT NULL DEFAULT uuid_generate_v4(), + begin timestamptz, + "end" timestamptz, + course smallint, + id_group uuid, + CONSTRAINT group_stage_pk PRIMARY KEY (id) +); + + + +ALTER TABLE vsu_timetable.group_stage DROP CONSTRAINT IF EXISTS group_fk CASCADE; +ALTER TABLE vsu_timetable.group_stage ADD CONSTRAINT group_fk FOREIGN KEY (id_group) +REFERENCES vsu_timetable."group" (id) MATCH FULL +ON DELETE SET NULL ON UPDATE CASCADE; + + + +DROP TABLE IF EXISTS vsu_timetable.room CASCADE; +CREATE TABLE vsu_timetable.room ( + id uuid NOT NULL DEFAULT uuid_generate_v4(), + name text, + CONSTRAINT room_pk PRIMARY KEY (id) +); + + + +DROP TYPE IF EXISTS vsu_timetable.type_lesson CASCADE; +CREATE TYPE vsu_timetable.type_lesson AS +ENUM ('labaratory','lection','practice'); + + + +DROP TYPE IF EXISTS vsu_timetable.type_of_week CASCADE; +CREATE TYPE vsu_timetable.type_of_week AS +ENUM ('all','even','odd'); + + + + +DROP TYPE IF EXISTS vsu_timetable.subgroup CASCADE; +CREATE TYPE vsu_timetable.subgroup AS +ENUM ('all','first','second'); + +DROP TYPE IF EXISTS vsu_timetable.day CASCADE; +CREATE TYPE vsu_timetable.day AS +ENUM ('monday','tuesday','wednesday','thursday', 'friday', 'saturday'); + + + +DROP TABLE IF EXISTS vsu_timetable.lesson CASCADE; +CREATE TABLE vsu_timetable.lesson ( + id uuid NOT NULL DEFAULT uuid_generate_v4(), + begin timestamptz, + "end" timestamptz, + number_lesson smallint, + type_lesson vsu_timetable.type_lesson, + type_week vsu_timetable.type_of_week, + subgroup vsu_timetable.subgroup, + day vsu_timetable.day, + id_room uuid, + id_shedule uuid, + CONSTRAINT lesson_pk PRIMARY KEY (id) +); + + + + +DROP TABLE IF EXISTS vsu_timetable.subject CASCADE; +CREATE TABLE vsu_timetable.subject ( + id uuid NOT NULL DEFAULT uuid_generate_v4(), + name text, + CONSTRAINT subject_pk PRIMARY KEY (id) +); + + + + +ALTER TABLE vsu_timetable.lesson DROP CONSTRAINT IF EXISTS room_fk CASCADE; +ALTER TABLE vsu_timetable.lesson ADD CONSTRAINT room_fk FOREIGN KEY (id_room) +REFERENCES vsu_timetable.room (id) MATCH FULL +ON DELETE SET NULL ON UPDATE CASCADE; + + + +DROP TABLE IF EXISTS vsu_timetable.shedule CASCADE; +CREATE TABLE vsu_timetable.shedule ( + id uuid NOT NULL DEFAULT uuid_generate_v4(), + id_teacher uuid, + id_subject uuid, + id_group_stage uuid, + CONSTRAINT shedule_pk PRIMARY KEY (id) +); + + + + +ALTER TABLE vsu_timetable.shedule DROP CONSTRAINT IF EXISTS teacher_fk CASCADE; +ALTER TABLE vsu_timetable.shedule ADD CONSTRAINT teacher_fk FOREIGN KEY (id_teacher) +REFERENCES vsu_timetable.teacher (id) MATCH FULL +ON DELETE SET NULL ON UPDATE CASCADE; + + + +ALTER TABLE vsu_timetable.shedule DROP CONSTRAINT IF EXISTS subject_fk CASCADE; +ALTER TABLE vsu_timetable.shedule ADD CONSTRAINT subject_fk FOREIGN KEY (id_subject) +REFERENCES vsu_timetable.subject (id) MATCH FULL +ON DELETE SET NULL ON UPDATE CASCADE; + + + +ALTER TABLE vsu_timetable.shedule DROP CONSTRAINT IF EXISTS group_stage_fk CASCADE; +ALTER TABLE vsu_timetable.shedule ADD CONSTRAINT group_stage_fk FOREIGN KEY (id_group_stage) +REFERENCES vsu_timetable.group_stage (id) MATCH FULL +ON DELETE SET NULL ON UPDATE CASCADE; + + + +ALTER TABLE vsu_timetable.lesson DROP CONSTRAINT IF EXISTS shedule_fk CASCADE; +ALTER TABLE vsu_timetable.lesson ADD CONSTRAINT shedule_fk FOREIGN KEY (id_shedule) +REFERENCES vsu_timetable.shedule (id) MATCH FULL +ON DELETE SET NULL ON UPDATE CASCADE; + + + +DROP TABLE IF EXISTS vsu_timetable.teacher_link CASCADE; +CREATE TABLE vsu_timetable.teacher_link ( + id uuid NOT NULL DEFAULT uuid_generate_v4(), + id_user uuid, + id_teacher uuid NOT NULL, + CONSTRAINT teacher_link_pk PRIMARY KEY (id) +); + + + + +ALTER TABLE vsu_timetable.teacher_link DROP CONSTRAINT IF EXISTS user_fk CASCADE; +ALTER TABLE vsu_timetable.teacher_link ADD CONSTRAINT user_fk FOREIGN KEY (id_user) +REFERENCES vsu_timetable."user" (id) MATCH FULL +ON DELETE SET NULL ON UPDATE CASCADE; + + +ALTER TABLE vsu_timetable.teacher_link DROP CONSTRAINT IF EXISTS teacher_fk CASCADE; +ALTER TABLE vsu_timetable.teacher_link ADD CONSTRAINT teacher_fk FOREIGN KEY (id_teacher) +REFERENCES vsu_timetable.teacher (id) MATCH FULL +ON DELETE SET NULL ON UPDATE CASCADE; + + +ALTER TABLE vsu_timetable.teacher_link DROP CONSTRAINT IF EXISTS teacher_link_user_unique CASCADE; +ALTER TABLE vsu_timetable.teacher_link ADD CONSTRAINT teacher_link_user_unique UNIQUE (id_user); + + +ALTER TABLE vsu_timetable.teacher_link DROP CONSTRAINT IF EXISTS teacher_unique CASCADE; +ALTER TABLE vsu_timetable.teacher_link ADD CONSTRAINT teacher_unique UNIQUE (id_teacher); + +COMMIT; diff --git a/postgresql/schemas/db_1/hello.sql b/postgresql/schemas/db_1/001_hello.sql similarity index 90% rename from postgresql/schemas/db_1/hello.sql rename to postgresql/schemas/db_1/001_hello.sql index 539abc9a..2a3a604c 100644 --- a/postgresql/schemas/db_1/hello.sql +++ b/postgresql/schemas/db_1/001_hello.sql @@ -1,3 +1,5 @@ +BEGIN; + DROP SCHEMA IF EXISTS hello_schema CASCADE; CREATE SCHEMA IF NOT EXISTS hello_schema; @@ -5,4 +7,6 @@ CREATE SCHEMA IF NOT EXISTS hello_schema; CREATE TABLE IF NOT EXISTS hello_schema.users ( name TEXT PRIMARY KEY, count INTEGER DEFAULT(1) -); \ No newline at end of file +); + +COMMIT; diff --git a/postgresql/schemas/db_1/002_add_lesson_filter.sql b/postgresql/schemas/db_1/002_add_lesson_filter.sql new file mode 100644 index 00000000..790e91f5 --- /dev/null +++ b/postgresql/schemas/db_1/002_add_lesson_filter.sql @@ -0,0 +1,31 @@ +BEGIN; + +DROP TYPE IF EXISTS vsu_timetable.lesson_filter; +CREATE TYPE vsu_timetable.lesson_filter AS +( + lesson_ids uuid[], + begin timestamptz, + "end" timestamptz, + days vsu_timetable.day[], + department_ids uuid[], + department_names text[], + faculty_ids uuid[], + faculty_names text[], + group_ids uuid[], + group_names text[], + group_courses SMALLINT[], + group_types vsu_timetable.grouptype[], + room_ids uuid[], + room_names text[], + subgroup vsu_timetable.subgroup, + subject_ids uuid[], + subject_names text[], + teacher_ids uuid[], + teacher_fios text[], + teacher_bios text[], + week vsu_timetable.type_of_week, + lesson_type vsu_timetable.type_lesson, + numbers SMALLINT[] +); + +COMMIT; diff --git a/postgresql/schemas/db_1/auth.sql b/postgresql/schemas/db_1/auth.sql deleted file mode 100755 index ba5466f6..00000000 --- a/postgresql/schemas/db_1/auth.sql +++ /dev/null @@ -1,22 +0,0 @@ -CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; - -CREATE SCHEMA IF NOT EXISTS vsu_timetable; - -DROP TABLE IF EXISTS vsu_timetable.user CASCADE; - -CREATE TYPE vsu_timetable.usertype as enum ( - 'user', 'admin', 'root', 'teacher' -); - -CREATE TABLE IF NOT EXISTS vsu_timetable.user ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - login TEXT UNIQUE NOT NULL, - password TEXT NOT NULL, - user_type vsu_timetable.usertype NOT NULL -); - -CREATE TABLE IF NOT EXISTS vsu_timetable.token ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - user_id uuid NOT NULL references vsu_timetable."user"(id), - expire_time timestamp with time zone NOT NULL -); \ No newline at end of file diff --git a/redocly.yaml b/redocly.yaml index 98645f32..17ba87c8 100644 --- a/redocly.yaml +++ b/redocly.yaml @@ -19,4 +19,4 @@ theme: openapi: generateCodeSamples: languages: - - lang: curl \ No newline at end of file + - lang: curl diff --git a/service/main.cpp b/service/main.cpp index 4f7a8697..dbb469b3 100644 --- a/service/main.cpp +++ b/service/main.cpp @@ -4,17 +4,19 @@ #include #include #include +#include +#include #include #include +#include #include #include #include -#include "components/controllers/token_controller_fwd.hpp" -#include "components/controllers/user_controller_fwd.hpp" -#include "userver/formats/json/value.hpp" -#include "userver/logging/log.hpp" -#include "userver/storages/postgres/component.hpp" +#include "components/controllers/postgres/lesson/fwd.hpp" +#include "components/controllers/postgres/token/fwd.hpp" +#include "components/controllers/postgres/user/fwd.hpp" +#include "views/get-timetable/view.hpp" #include "views/hello/view.hpp" #include "views/login/view.hpp" #include "views/register/view.hpp" @@ -51,22 +53,19 @@ void LogFile(std::string_view path) { } else if (file.eof()) { LOG_ERROR() << fmt::format("{} is empty", path); } - while (std::getline(file, temp)) { - LOG_ERROR() << temp; - } + // while (std::getline(file, temp)) { + // LOG_ERROR() << temp; + // } file.close(); } int main(int argc, char* argv[]) { // LogAllFiles(fs::current_path()); // LogAllFiles("/home/user/.local/etc/timetable_vsu_backend/"); - // LogCommands(argc, argv); - // //кто это? - // LogFile("/usr/local/etc/timetable_vsu_backend/config_dev.yaml"); - // LogFile("/home/user/.local/etc/timetable_vsu_backend/config_vars_docker.yaml"); + LogCommands(argc, argv); + LogFile("/usr/local/etc/timetable_vsu_backend/config_dev.yaml"); // LogFile("config_vars.docker.yaml"); - using namespace timetable_vsu_backend::components; - using namespace timetable_vsu_backend::views; + using namespace timetable_vsu_backend; auto component_list = userver::components::MinimalServerComponentList() .Append() @@ -76,9 +75,12 @@ int main(int argc, char* argv[]) { .Append("postgres-db-1") .Append(); service_template::AppendHello(component_list); - timetable_vsu_backend::views::login::Append(component_list); - timetable_vsu_backend::views::register_::Append(component_list); - AppendUserController(component_list); - AppendTokenController(component_list); + views::login::Append(component_list); + views::register_::Append(component_list); + views::get_timetable::Append(component_list); + components::controllers::postgres::AppendUserController(component_list); + components::controllers::postgres::AppendTokenController(component_list); + components::controllers::postgres::AppendLessonDetailsController( + component_list); return userver::utils::DaemonMain(argc, argv, component_list); } diff --git a/src/components/controllers/postgres/lesson/controller.cpp b/src/components/controllers/postgres/lesson/controller.cpp new file mode 100644 index 00000000..142defc4 --- /dev/null +++ b/src/components/controllers/postgres/lesson/controller.cpp @@ -0,0 +1,143 @@ +#include "controller.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "models/lesson_filter/postgre.hpp" +#include "models/lesson_v1/postgre.hpp" +#include "models/lesson_v1/type.hpp" +#include "models/lesson_with_details/postgre.hpp" +#include "models/subgroup/serialize.hpp" +#include "utils/convert/drop_properties_ref.hpp" + +namespace timetable_vsu_backend::components::controllers::postgres { +namespace { +const userver::storages::postgres::Query qGetLessonsByFilter(R"( + WITH lesson_info as (SELECT + l.id AS lesson_id, + l.begin AS lesson_begin, + l.end AS lesson_end, + l.number_lesson AS lesson_number, + l.type_lesson AS lesson_type, + l.type_week AS lesson_week_type, + l.subgroup AS lesson_subgroup, + l.day AS lesson_day, + r.id AS room_id, + r.name AS room_name, + s.id AS subject_id, + s.name AS subject_name, + gs.id AS group_stage_id, + gs.begin AS group_stage_begin, + gs.end AS group_stage_end, + gs.course AS group_stage_course, + 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, + d.id AS department_id, + d.name AS department_name, + t.id AS teacher_id, + t.fio AS teacher_fio, + t.bio AS teacher_bio + FROM vsu_timetable.lesson AS l + LEFT JOIN vsu_timetable.room AS r ON l.id_room = r.id + LEFT JOIN vsu_timetable.shedule AS sh ON l.id_shedule = sh.id + LEFT JOIN vsu_timetable.subject AS s ON sh.id_subject = s.id + LEFT JOIN vsu_timetable.group_stage AS gs ON sh.id_group_stage = gs.id + LEFT JOIN vsu_timetable.group AS g ON gs.id_group = g.id + LEFT JOIN vsu_timetable.teacher AS t ON sh.id_teacher = t.id + LEFT JOIN vsu_timetable.department AS d ON t.id_department = d.id + LEFT JOIN vsu_timetable.faculty AS f ON d.id_faculty = f.id + ) + SELECT + lesson_id, + lesson_begin, + lesson_end, + lesson_number, + lesson_type, + lesson_week_type, + lesson_subgroup, + lesson_day, + room_id, + room_name, + subject_id, + subject_name, + group_stage_id AS group_id, + group_stage_course AS group_course, + group_name, + group_type, + faculty_id, + faculty_name, + department_id, + department_name, + teacher_id, + teacher_fio, + teacher_bio + FROM lesson_info + WHERE + ($1.lesson_ids IS null OR lesson_id = ANY($1.lesson_ids)) and + ($1.begin IS null OR $1.begin <= lesson_end) and + ($1."end" IS null OR $1."end" >= lesson_begin) and + ($1.days IS null OR lesson_day = ANY($1.days)) and + ($1.department_ids IS null OR department_id = ANY($1.department_ids)) and + ($1.department_names IS null OR department_name = ANY($1.department_names)) and + ($1.faculty_ids IS null OR faculty_id = ANY($1.faculty_ids)) and + ($1.faculty_names IS null OR faculty_name = ANY($1.faculty_names)) and + ($1.group_ids IS null OR group_stage_id = ANY($1.group_ids)) and + ($1.group_names IS null OR group_name = ANY($1.group_names)) and + ($1.group_courses is null OR group_stage_course = ANY($1.group_courses)) and + ($1.group_types is null OR group_type = ANY($1.group_types)) and + ($1.room_ids IS null OR room_id = ANY($1.room_ids)) and + ($1.room_names IS null OR room_name = ANY($1.room_names)) and + ($1.subject_names IS null OR subject_name = ANY($1.subject_names)) and + ($1.subject_ids IS null OR subject_id = ANY($1.subject_ids)) and + ($1.teacher_fios IS null OR teacher_fio = ANY($1.teacher_fios)) and + ($1.teacher_bios IS null OR teacher_bio = ANY($1.teacher_bios)) and + ($1.teacher_ids IS null OR teacher_id = ANY($1.teacher_ids)) and + ($1.subgroup IS null OR lesson_subgroup = $1.subgroup) and + ($1.week IS null OR lesson_week_type = $1.week) and + ($1.lesson_type is null OR lesson_type = $1.lesson_type) and + ($1.numbers is null OR lesson_number = ANY($1.numbers)) + ; + )"); +} + +std::vector LessonDetailsController::Search( + const std::optional& filter) const { + std::optional filter_tuple = + convert::DropPropertiesToConstRefs(filter); + auto result = pg_cluster_->Execute( + userver::storages::postgres::ClusterHostType::kMaster, + qGetLessonsByFilter, filter_tuple); + std::vector lessons; + lessons.reserve(result.Size()); + auto it = result.begin(); + for (auto& row : result) { + auto& lesson = lessons.emplace_back(); + auto tuple = convert::DropPropertiesToMutRefs(lesson); + row.To(tuple, userver::storages::postgres::kRowTag); + } + return lessons; +} +LessonDetailsController::LessonDetailsController( + const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : LoggableComponentBase(config, context), + pg_cluster_( + context.FindComponent("postgres-db-1") + .GetCluster()) { +} +} // namespace timetable_vsu_backend::components::controllers::postgres diff --git a/src/components/controllers/postgres/lesson/controller.hpp b/src/components/controllers/postgres/lesson/controller.hpp new file mode 100644 index 00000000..61943a88 --- /dev/null +++ b/src/components/controllers/postgres/lesson/controller.hpp @@ -0,0 +1,28 @@ +#pragma once +#include +#include +#include +#include +#include + +#include "models/lesson_filter/fwd.hpp" +#include "models/lesson_v1/type.hpp" +#include "models/lesson_with_details/type.hpp" + +namespace timetable_vsu_backend::components::controllers::postgres { +class LessonDetailsController final + : public userver::components::LoggableComponentBase { + public: + using userver::components::LoggableComponentBase::LoggableComponentBase; + static constexpr inline std::string_view kName = + "lesson_details_controller"; + std::vector Search( + const std::optional& filter) const; + LessonDetailsController( + const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context); + + protected: + userver::storages::postgres::ClusterPtr pg_cluster_; +}; +} // namespace timetable_vsu_backend::components::controllers::postgres diff --git a/src/components/controllers/postgres/lesson/fwd.cpp b/src/components/controllers/postgres/lesson/fwd.cpp new file mode 100644 index 00000000..ee4d4289 --- /dev/null +++ b/src/components/controllers/postgres/lesson/fwd.cpp @@ -0,0 +1,12 @@ +#include "fwd.hpp" + +#include + +#include "controller.hpp" + +namespace timetable_vsu_backend::components::controllers::postgres { +void AppendLessonDetailsController( + userver::components::ComponentList& component_list) { + component_list.Append(); +} +} // namespace timetable_vsu_backend::components::controllers::postgres diff --git a/src/components/controllers/postgres/lesson/fwd.hpp b/src/components/controllers/postgres/lesson/fwd.hpp new file mode 100644 index 00000000..99e01bfd --- /dev/null +++ b/src/components/controllers/postgres/lesson/fwd.hpp @@ -0,0 +1,8 @@ +#pragma once +#include "utils/component_list_fwd.hpp" + +namespace timetable_vsu_backend::components::controllers::postgres { +class LessonDetailsController; +void AppendLessonDetailsController( + userver::components::ComponentList& component_list); +} // namespace timetable_vsu_backend::components::controllers::postgres diff --git a/src/components/controllers/token_controller.cpp b/src/components/controllers/postgres/token/controller.cpp similarity index 72% rename from src/components/controllers/token_controller.cpp rename to src/components/controllers/postgres/token/controller.cpp index f98985c6..9a99ac3d 100644 --- a/src/components/controllers/token_controller.cpp +++ b/src/components/controllers/postgres/token/controller.cpp @@ -1,4 +1,4 @@ -#include "token_controller.hpp" +#include "controller.hpp" #include @@ -6,29 +6,29 @@ #include #include #include +#include +#include #include +#include +#include +#include +#include #include "models/user/postgre.hpp" #include "models/user_type/postgre.hpp" -#include "userver/components/component_context.hpp" -#include "userver/logging/log.hpp" -#include "userver/storages/postgres/cluster_types.hpp" -#include "userver/storages/postgres/component.hpp" -#include "userver/storages/postgres/query.hpp" -#include "userver/utils/datetime.hpp" namespace { const userver::storages::postgres::Query qGetUserByTokenId(R"( - WITH found_token AS (select user_id + WITH found_token AS (select id_user from vsu_timetable.token WHERE id = $1 AND expire_time > $2) - SELECT id, login, password, user_type from vsu_timetable."user" LEFT OUTER JOIN found_token ON user_id = "user".id + SELECT id, login, password, user_type from vsu_timetable."user" LEFT OUTER JOIN found_token ON id_user = "user".id )"), qAddToken(R"( - insert into vsu_timetable."token" (user_id, expire_time) values ($1, $2) RETURNING id + insert into vsu_timetable."token" (id_user, expire_time) values ($1, $2) RETURNING id )"); } -namespace timetable_vsu_backend::components { +namespace timetable_vsu_backend::components::controllers::postgres { TokenController::TokenController( const userver::components::ComponentConfig& config, const userver::components::ComponentContext& context) @@ -52,7 +52,7 @@ std::optional TokenController::GetById( std::optional TokenController::CreateNew( const models::User::Id& id, const std::chrono::system_clock::time_point& time) const { - LOG_DEBUG() << fmt::format("Try to create new token, user_id: {}", + LOG_DEBUG() << fmt::format("Try to create new token, id_user: {}", boost::uuids::to_string(id.GetUnderlying())); auto result = pg_cluster_->Execute( userver::storages::postgres::ClusterHostType::kMaster, qAddToken, id, @@ -62,4 +62,4 @@ std::optional TokenController::CreateNew( } return result.AsSingleRow(); } -} // namespace timetable_vsu_backend::components \ No newline at end of file +} // namespace timetable_vsu_backend::components::controllers::postgres diff --git a/src/components/controllers/token_controller.hpp b/src/components/controllers/postgres/token/controller.hpp similarity index 78% rename from src/components/controllers/token_controller.hpp rename to src/components/controllers/postgres/token/controller.hpp index 624e481e..5233705f 100644 --- a/src/components/controllers/token_controller.hpp +++ b/src/components/controllers/postgres/token/controller.hpp @@ -6,9 +6,10 @@ #include "models/user/type.hpp" -namespace timetable_vsu_backend::components { +namespace timetable_vsu_backend::components::controllers::postgres { -class TokenController : public userver::components::LoggableComponentBase { +class TokenController final + : public userver::components::LoggableComponentBase { public: using userver::components::LoggableComponentBase::LoggableComponentBase; static constexpr inline std::string_view kName = "token_controller"; @@ -22,4 +23,4 @@ class TokenController : public userver::components::LoggableComponentBase { protected: userver::storages::postgres::ClusterPtr pg_cluster_; }; -} // namespace timetable_vsu_backend::components \ No newline at end of file +} // namespace timetable_vsu_backend::components::controllers::postgres diff --git a/src/components/controllers/postgres/token/fwd.cpp b/src/components/controllers/postgres/token/fwd.cpp new file mode 100644 index 00000000..79061967 --- /dev/null +++ b/src/components/controllers/postgres/token/fwd.cpp @@ -0,0 +1,11 @@ +#include "fwd.hpp" + +#include + +#include "controller.hpp" + +namespace timetable_vsu_backend::components::controllers::postgres { +void AppendTokenController(userver::components::ComponentList& component_list) { + component_list.Append(); +} +} // namespace timetable_vsu_backend::components::controllers::postgres diff --git a/src/components/controllers/token_controller_fwd.hpp b/src/components/controllers/postgres/token/fwd.hpp similarity index 52% rename from src/components/controllers/token_controller_fwd.hpp rename to src/components/controllers/postgres/token/fwd.hpp index 529335e7..b83628bd 100644 --- a/src/components/controllers/token_controller_fwd.hpp +++ b/src/components/controllers/postgres/token/fwd.hpp @@ -1,6 +1,6 @@ #pragma once #include "utils/component_list_fwd.hpp" -namespace timetable_vsu_backend::components { +namespace timetable_vsu_backend::components::controllers::postgres { class TokenController; void AppendTokenController(userver::components::ComponentList& component_list); -} // namespace timetable_vsu_backend::components \ No newline at end of file +} // namespace timetable_vsu_backend::components::controllers::postgres diff --git a/src/components/controllers/user_controller.cpp b/src/components/controllers/postgres/user/controller.cpp similarity index 72% rename from src/components/controllers/user_controller.cpp rename to src/components/controllers/postgres/user/controller.cpp index c43d027b..5b290de6 100644 --- a/src/components/controllers/user_controller.cpp +++ b/src/components/controllers/postgres/user/controller.cpp @@ -1,30 +1,30 @@ -#include "user_controller.hpp" +#include "controller.hpp" #include #include #include #include +#include +#include #include +#include +#include +#include #include "models/user/postgre.hpp" #include "models/user_type/postgre.hpp" -#include "userver/components/component_context.hpp" -#include "userver/logging/log.hpp" -#include "userver/storages/postgres/cluster_types.hpp" -#include "userver/storages/postgres/component.hpp" -#include "userver/storages/postgres/query.hpp" namespace { const userver::storages::postgres::Query qGetUserByLogin(R"( select * from vsu_timetable."user" WHERE login = $1 )"), qAddUser(R"( - insert into vsu_timetable."user"(login, password, user_type) values ($1, $2, $3) ON CONFLICT DO NOTHING + insert into vsu_timetable."user"(login, password) values ($1, $2) ON CONFLICT DO NOTHING RETURNING id )"); } -namespace timetable_vsu_backend::components { +namespace timetable_vsu_backend::components::controllers::postgres { UserController::UserController( const userver::components::ComponentConfig& config, const userver::components::ComponentContext& context) @@ -49,10 +49,10 @@ std::optional UserController::TryToAdd( const models::User& user) const { auto result = pg_cluster_->Execute( userver::storages::postgres::ClusterHostType::kMaster, qAddUser, - user.login, user.password, user.user_type); + user.login, user.password); if (result.IsEmpty()) { return {}; } return result.AsSingleRow(); } -} // namespace timetable_vsu_backend::components \ No newline at end of file +} // namespace timetable_vsu_backend::components::controllers::postgres diff --git a/src/components/controllers/user_controller.hpp b/src/components/controllers/postgres/user/controller.hpp similarity index 76% rename from src/components/controllers/user_controller.hpp rename to src/components/controllers/postgres/user/controller.hpp index 603e375a..e30b9ed8 100644 --- a/src/components/controllers/user_controller.hpp +++ b/src/components/controllers/postgres/user/controller.hpp @@ -5,9 +5,9 @@ #include "models/user/type.hpp" -namespace timetable_vsu_backend::components { +namespace timetable_vsu_backend::components::controllers::postgres { -class UserController : public userver::components::LoggableComponentBase { +class UserController final : public userver::components::LoggableComponentBase { public: using userver::components::LoggableComponentBase::LoggableComponentBase; static constexpr inline std::string_view kName = "user_controller"; @@ -19,4 +19,4 @@ class UserController : public userver::components::LoggableComponentBase { protected: userver::storages::postgres::ClusterPtr pg_cluster_; }; -} // namespace timetable_vsu_backend::components \ No newline at end of file +} // 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 new file mode 100644 index 00000000..691ff5c7 --- /dev/null +++ b/src/components/controllers/postgres/user/fwd.cpp @@ -0,0 +1,11 @@ +#include "fwd.hpp" + +#include + +#include "controller.hpp" + +namespace timetable_vsu_backend::components::controllers::postgres { +void AppendUserController(userver::components::ComponentList& component_list) { + component_list.Append(); +} +} // namespace timetable_vsu_backend::components::controllers::postgres diff --git a/src/components/controllers/user_controller_fwd.hpp b/src/components/controllers/postgres/user/fwd.hpp similarity index 52% rename from src/components/controllers/user_controller_fwd.hpp rename to src/components/controllers/postgres/user/fwd.hpp index d85175a5..1eb34ddb 100644 --- a/src/components/controllers/user_controller_fwd.hpp +++ b/src/components/controllers/postgres/user/fwd.hpp @@ -1,6 +1,6 @@ #pragma once #include "utils/component_list_fwd.hpp" -namespace timetable_vsu_backend::components { +namespace timetable_vsu_backend::components::controllers::postgres { class UserController; void AppendUserController(userver::components::ComponentList& component_list); -} // namespace timetable_vsu_backend::components \ No newline at end of file +} // namespace timetable_vsu_backend::components::controllers::postgres diff --git a/src/components/controllers/token_controller_fwd.cpp b/src/components/controllers/token_controller_fwd.cpp deleted file mode 100644 index 4ab1fbe8..00000000 --- a/src/components/controllers/token_controller_fwd.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "token_controller_fwd.hpp" - -#include "token_controller.hpp" -#include "userver/components/component_list.hpp" - -namespace timetable_vsu_backend::components { -void AppendTokenController(userver::components::ComponentList& component_list) { - component_list.Append(); -} -} // namespace timetable_vsu_backend::components \ No newline at end of file diff --git a/src/components/controllers/user_controller_fwd.cpp b/src/components/controllers/user_controller_fwd.cpp deleted file mode 100644 index c74e6bea..00000000 --- a/src/components/controllers/user_controller_fwd.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "token_controller_fwd.hpp" -#include "user_controller.hpp" -#include "userver/components/component_list.hpp" - -namespace timetable_vsu_backend::components { -void AppendUserController(userver::components::ComponentList& component_list) { - component_list.Append(); -} -} // namespace timetable_vsu_backend::components \ No newline at end of file diff --git a/src/helpers/lesson_converter.hpp b/src/helpers/lesson_converter.hpp new file mode 100644 index 00000000..554238b5 --- /dev/null +++ b/src/helpers/lesson_converter.hpp @@ -0,0 +1,33 @@ +#pragma once +#include "models/lesson_type/type.hpp" +#include "models/lesson_v1/type.hpp" +#include "models/lesson_with_details/type.hpp" + +namespace timetable_vsu_backend::helpers { +inline models::LessonV1 ConvertLesson(models::LessonWithDetails&& lesson) { + return models::LessonV1{ + .lesson_id = {lesson.lesson_id}, + .lesson_begin = {lesson.lesson_begin}, + .lesson_end = {lesson.lesson_end}, + .lesson_number = {lesson.lesson_number}, + .lesson_type = {lesson.lesson_type}, + .lesson_week_type = {lesson.lesson_week_type}, + .lesson_subgroup = {lesson.lesson_subgroup}, + .lesson_day = {lesson.lesson_day}, + .room_id = {lesson.room_id}, + .room_name = {std::move(lesson.room_name)}, + .subject_id = {lesson.subject_id}, + .subject_name = {std::move(lesson.subject_name)}, + .group_id = {lesson.group_id}, + .group_stage_course = {lesson.group_stage_course}, + .group_name = {std::move(lesson.group_name)}, + .group_type = {lesson.group_type}, + .faculty_id = {lesson.faculty_id}, + .faculty_name = {std::move(lesson.faculty_name)}, + .department_id = {lesson.department_id}, + .department_name = {std::move(lesson.department_name)}, + .teacher_id = {lesson.teacher_id}, + .teacher_fio = {std::move(lesson.teacher_fio)}, + .teacher_bio = {std::move(lesson.teacher_bio)}}; +} +} // namespace timetable_vsu_backend::helpers diff --git a/src/http/ErrorV1.hpp b/src/http/ErrorV1.hpp index d73246a0..1265b8e4 100644 --- a/src/http/ErrorV1.hpp +++ b/src/http/ErrorV1.hpp @@ -1,6 +1,7 @@ #pragma once +#include + #include "../utils/convert/base.hpp" -#include "userver/server/http/http_status.hpp" namespace timetable_vsu_backend::http { namespace convert = timetable_vsu_backend::utils::convert; @@ -14,4 +15,4 @@ struct ErrorV1 { convert::Property description; convert::Property machine_id; }; -} // namespace timetable_vsu_backend::http \ No newline at end of file +} // namespace timetable_vsu_backend::http diff --git a/src/http/handler_parsed.hpp b/src/http/handler_parsed.hpp index bea91421..1447c421 100644 --- a/src/http/handler_parsed.hpp +++ b/src/http/handler_parsed.hpp @@ -4,14 +4,14 @@ #include #include +#include +#include #include #include +#include #include #include "../utils/convert/http_response_base.hpp" -#include "userver/formats/json/value.hpp" -#include "userver/formats/json/value_builder.hpp" -#include "userver/server/http/http_status.hpp" namespace timetable_vsu_backend::http { template @@ -24,21 +24,27 @@ class HandlerParsed : public userver::server::handlers::HttpHandlerBase { : HttpHandlerBase(config, context) { } virtual Response Handle(Request&& request) const = 0; + + private: static std::optional ParseUserRequest( const userver::server::http::HttpRequest& raw_request) { std::optional request; try { + static_assert(userver::formats::common::impl::kHasParse< + userver::server::http::HttpRequest, Request>, + "Request should be able to parse from " + "userver::server::http::HttpRequest"); request = Parse(raw_request, userver::formats::parse::To{}); return request; } catch (std::exception& exc) { LOG_DEBUG() << fmt::format( "Can't parse user request, return 400. Error: {}", exc.what()); - return std::nullopt; + request = std::nullopt; } + return request; } - private: using HttpStatus = userver::server::http::HttpStatus; template @@ -53,7 +59,8 @@ class HandlerParsed : public userver::server::handlers::HttpHandlerBase { } std::string HandleRequestThrow( const userver::server::http::HttpRequest& raw_request, - userver::server::request::RequestContext& /*context*/) const override { + userver::server::request::RequestContext& /*context*/) + const override final { auto& http_response = raw_request.GetHttpResponse(); auto request = ParseUserRequest(raw_request); if (!request) { @@ -61,7 +68,8 @@ class HandlerParsed : public userver::server::handlers::HttpHandlerBase { return {}; } try { - auto response = Handle(std::move(*request)); + Request&& parsed_request = std::move(*request); + auto response = Handle(std::move(parsed_request)); auto visiter = [&raw_request](auto& value) { return SerializeResponse(value, raw_request); }; @@ -74,4 +82,4 @@ class HandlerParsed : public userver::server::handlers::HttpHandlerBase { } } }; -} // namespace timetable_vsu_backend::http \ No newline at end of file +} // namespace timetable_vsu_backend::http diff --git a/src/http/legacy_handler_parsed.hpp b/src/http/legacy_handler_parsed.hpp index e6e0bd20..0990dc7b 100644 --- a/src/http/legacy_handler_parsed.hpp +++ b/src/http/legacy_handler_parsed.hpp @@ -4,12 +4,11 @@ #include #include +#include +#include #include #include - -#include "userver/formats/json/value.hpp" -#include "userver/formats/json/value_builder.hpp" -#include "userver/server/http/http_status.hpp" +#include namespace timetable_vsu_backend::http { template @@ -60,4 +59,4 @@ class LegacyHandlerParsed : public userver::server::handlers::HttpHandlerBase { } } }; -} // namespace timetable_vsu_backend::http \ No newline at end of file +} // namespace timetable_vsu_backend::http diff --git a/src/models/auth_token/serialize.hpp b/src/models/auth_token/serialize.hpp index 7a47931a..25dd53fe 100644 --- a/src/models/auth_token/serialize.hpp +++ b/src/models/auth_token/serialize.hpp @@ -3,11 +3,11 @@ #include #include +#include +#include +#include #include "type.hpp" -#include "userver/formats/json/value.hpp" -#include "userver/formats/json/value_builder.hpp" -#include "userver/logging/log.hpp" namespace timetable_vsu_backend::models { inline userver::formats::json::Value Serialize( @@ -17,4 +17,4 @@ inline userver::formats::json::Value Serialize( json["token"] = boost::uuids::to_string(token.id); return json.ExtractValue(); } -} // namespace timetable_vsu_backend::models \ No newline at end of file +} // namespace timetable_vsu_backend::models diff --git a/src/models/auth_token/type.hpp b/src/models/auth_token/type.hpp index 315fd2a2..ac54a5b5 100644 --- a/src/models/auth_token/type.hpp +++ b/src/models/auth_token/type.hpp @@ -5,4 +5,4 @@ namespace timetable_vsu_backend::models { struct AuthToken { boost::uuids::uuid id; }; -} // namespace timetable_vsu_backend::models \ No newline at end of file +} // namespace timetable_vsu_backend::models diff --git a/src/models/day/all.hpp b/src/models/day/all.hpp new file mode 100644 index 00000000..79e8d9dd --- /dev/null +++ b/src/models/day/all.hpp @@ -0,0 +1,4 @@ +#pragma once +#include "models/day/parse.hpp" +#include "models/day/postgre.hpp" +#include "models/day/serialize.hpp" diff --git a/src/models/day/parse.cpp b/src/models/day/parse.cpp new file mode 100644 index 00000000..0048b575 --- /dev/null +++ b/src/models/day/parse.cpp @@ -0,0 +1,38 @@ +#include "parse.hpp" + +#include + +#include +#include + +#include "type.hpp" +#include "utils/json_type.hpp" + +namespace timetable_vsu_backend::models { +Day Parse(std::string_view str, userver::formats::parse::To) { + if (str == "monday") { + return Day::kMonday; + } else if (str == "tuesday") { + return Day::kTuesday; + } else if (str == "thursday") { + return Day::kThursday; + } else if (str == "wednesday") { + return Day::kWednesday; + } else if (str == "saturday") { + return Day::kSaturday; + } else if (str == "friday") { + return Day::kFriday; + } else + throw std::runtime_error( + fmt::format("Fail parse Day, get unexpected value: {}", str)); +} +Day Parse(const userver::formats::json::Value& value, + userver::formats::parse::To) { + if (!value.IsString()) { + throw std::runtime_error(fmt::format( + "Expected string type, but got: {}", utils::GetType(value))); + } + auto raw_value = value.As(); + return Parse(raw_value, userver::formats::parse::To{}); +} +} // namespace timetable_vsu_backend::models diff --git a/src/models/day/parse.hpp b/src/models/day/parse.hpp new file mode 100644 index 00000000..46cb9fdf --- /dev/null +++ b/src/models/day/parse.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include +#include + +#include "type.hpp" + +namespace timetable_vsu_backend::models { +Day Parse(std::string_view str, userver::formats::parse::To); +Day Parse(const userver::formats::json::Value& value, + userver::formats::parse::To); +} // namespace timetable_vsu_backend::models diff --git a/src/models/day/postgre.hpp b/src/models/day/postgre.hpp new file mode 100644 index 00000000..b9be4ee4 --- /dev/null +++ b/src/models/day/postgre.hpp @@ -0,0 +1,25 @@ +#pragma once +#include +#include +#include + +#include "type.hpp" + +namespace userver::storages::postgres::io { +using timetable_vsu_backend::models::Day; +template <> +struct CppToUserPg : EnumMappingBase { + static constexpr userver::storages::postgres::DBTypeName postgres_name = + "vsu_timetable.day"; + static constexpr userver::utils::TrivialBiMap enumerators = + [](auto selector) { + return selector() + .Case("monday", Day::kMonday) + .Case("tuesday", Day::kTuesday) + .Case("wednesday", Day::kWednesday) + .Case("thursday", Day::kThursday) + .Case("friday", Day::kFriday) + .Case("saturday", Day::kSaturday); + }; +}; +} // namespace userver::storages::postgres::io diff --git a/src/models/day/serialize.cpp b/src/models/day/serialize.cpp new file mode 100644 index 00000000..f750a6f0 --- /dev/null +++ b/src/models/day/serialize.cpp @@ -0,0 +1,30 @@ +#include "serialize.hpp" + +#include + +namespace timetable_vsu_backend::models { +std::string Serialize(const Day& value, + userver::formats::serialize::To) { + switch (value) { + case Day::kMonday: + return "monday"; + case Day::kTuesday: + return "tuesday"; + case Day::kWednesday: + return "wednesday"; + case Day::kThursday: + return "thursday"; + case Day::kFriday: + return "friday"; + case Day::kSaturday: + return "saturday"; + } +} +userver::formats::json::Value Serialize( + const Day& value, + userver::formats::serialize::To) { + std::string str = + Serialize(value, userver::formats::serialize::To{}); + return userver::formats::json::ValueBuilder(str).ExtractValue(); +} +} // namespace timetable_vsu_backend::models diff --git a/src/models/day/serialize.hpp b/src/models/day/serialize.hpp new file mode 100644 index 00000000..50efe278 --- /dev/null +++ b/src/models/day/serialize.hpp @@ -0,0 +1,12 @@ +#pragma once +#include + +#include "type.hpp" + +namespace timetable_vsu_backend::models { +userver::formats::json::Value Serialize( + const Day& value, + userver::formats::serialize::To); +std::string Serialize(const Day& value, + userver::formats::serialize::To); +} // namespace timetable_vsu_backend::models diff --git a/src/models/day/type.hpp b/src/models/day/type.hpp new file mode 100644 index 00000000..24963d76 --- /dev/null +++ b/src/models/day/type.hpp @@ -0,0 +1,12 @@ +#pragma once + +namespace timetable_vsu_backend::models { +enum struct Day { + kMonday, + kTuesday, + kWednesday, + kThursday, + kFriday, + kSaturday +}; +} diff --git a/src/models/education_type/all.hpp b/src/models/education_type/all.hpp new file mode 100644 index 00000000..70d37443 --- /dev/null +++ b/src/models/education_type/all.hpp @@ -0,0 +1,4 @@ +#pragma once +#include "models/education_type/parse.hpp" +#include "models/education_type/postgre.hpp" +#include "models/education_type/serialize.hpp" diff --git a/src/models/education_type/parse.cpp b/src/models/education_type/parse.cpp new file mode 100644 index 00000000..cc77cd9e --- /dev/null +++ b/src/models/education_type/parse.cpp @@ -0,0 +1,35 @@ +#include "parse.hpp" + +#include + +#include +#include + +#include "type.hpp" +#include "utils/json_type.hpp" + +namespace timetable_vsu_backend::models { +EducationType Parse(std::string_view str, + userver::formats::parse::To) { + if (str == "magistracy") { + return EducationType::kMagistracy; + } else if (str == "postgraduate") { + return EducationType::kPostgraduate; + } else if (str == "specialty") { + return EducationType::kSpecialty; + } else if (str == "undergraduate") { + return EducationType::kUndergraduate; + } else + throw std::runtime_error(fmt::format( + "Fail parse EducationType, get unexpected value: {}", str)); +} +EducationType Parse(const userver::formats::json::Value& value, + userver::formats::parse::To) { + if (!value.IsString()) { + throw std::runtime_error(fmt::format( + "Expected string type, but got: {}", utils::GetType(value))); + } + auto raw_value = value.As(); + return Parse(raw_value, userver::formats::parse::To{}); +} +} // namespace timetable_vsu_backend::models diff --git a/src/models/education_type/parse.hpp b/src/models/education_type/parse.hpp new file mode 100644 index 00000000..1895e7d3 --- /dev/null +++ b/src/models/education_type/parse.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include +#include + +#include "type.hpp" + +namespace timetable_vsu_backend::models { +EducationType Parse(std::string_view str, + userver::formats::parse::To); +EducationType Parse(const userver::formats::json::Value& value, + userver::formats::parse::To); +} // namespace timetable_vsu_backend::models diff --git a/src/models/education_type/postgre.hpp b/src/models/education_type/postgre.hpp new file mode 100644 index 00000000..6b8d0356 --- /dev/null +++ b/src/models/education_type/postgre.hpp @@ -0,0 +1,23 @@ +#pragma once +#include +#include +#include + +#include "type.hpp" + +namespace userver::storages::postgres::io { +using timetable_vsu_backend::models::EducationType; +template <> +struct CppToUserPg : EnumMappingBase { + static constexpr userver::storages::postgres::DBTypeName postgres_name = + "vsu_timetable.grouptype"; + static constexpr userver::utils::TrivialBiMap enumerators = + [](auto selector) { + return selector() + .Case("magistracy", EducationType::kMagistracy) + .Case("postgraduate", EducationType::kPostgraduate) + .Case("undergraduate", EducationType::kUndergraduate) + .Case("specialty", EducationType::kSpecialty); + }; +}; +} // namespace userver::storages::postgres::io diff --git a/src/models/education_type/serialize.cpp b/src/models/education_type/serialize.cpp new file mode 100644 index 00000000..76a119b0 --- /dev/null +++ b/src/models/education_type/serialize.cpp @@ -0,0 +1,26 @@ +#include "serialize.hpp" + +#include + +namespace timetable_vsu_backend::models { +std::string Serialize(const EducationType& value, + userver::formats::serialize::To) { + switch (value) { + case EducationType::kMagistracy: + return "magistracy"; + case EducationType::kPostgraduate: + return "postgraduate"; + case EducationType::kUndergraduate: + return "undergraduate"; + case EducationType::kSpecialty: + return "specialty"; + } +} +userver::formats::json::Value Serialize( + const EducationType& value, + userver::formats::serialize::To) { + std::string str = + Serialize(value, userver::formats::serialize::To{}); + return userver::formats::json::ValueBuilder(str).ExtractValue(); +} +} // namespace timetable_vsu_backend::models diff --git a/src/models/education_type/serialize.hpp b/src/models/education_type/serialize.hpp new file mode 100644 index 00000000..bc087643 --- /dev/null +++ b/src/models/education_type/serialize.hpp @@ -0,0 +1,12 @@ +#pragma once +#include + +#include "type.hpp" + +namespace timetable_vsu_backend::models { +userver::formats::json::Value Serialize( + const EducationType& value, + userver::formats::serialize::To); +std::string Serialize(const EducationType& value, + userver::formats::serialize::To); +} // namespace timetable_vsu_backend::models diff --git a/src/models/education_type/type.hpp b/src/models/education_type/type.hpp new file mode 100644 index 00000000..3ed6d3fa --- /dev/null +++ b/src/models/education_type/type.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace timetable_vsu_backend::models { +enum struct EducationType { + kUndergraduate, + kMagistracy, + kPostgraduate, + kSpecialty +}; +} diff --git a/src/models/lesson/type.hpp b/src/models/lesson/type.hpp deleted file mode 100644 index f2f8ee57..00000000 --- a/src/models/lesson/type.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include - -#include "utils/convert/base.hpp" - -namespace convert = timetable_vsu_backend::utils::convert; - -struct LessonV1 { - convert::Property room_id; - convert::Property room_name; - convert::Property teacher_id; - convert::Property teacher_fio; - convert::Property subject_id; - convert::Property subject_name; -}; \ No newline at end of file diff --git a/src/models/lesson_filter/fwd.hpp b/src/models/lesson_filter/fwd.hpp new file mode 100644 index 00000000..b7b8e922 --- /dev/null +++ b/src/models/lesson_filter/fwd.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace timetable_vsu_backend::models { +struct LessonFilter; +} diff --git a/src/models/lesson_filter/postgre.hpp b/src/models/lesson_filter/postgre.hpp new file mode 100644 index 00000000..fe240133 --- /dev/null +++ b/src/models/lesson_filter/postgre.hpp @@ -0,0 +1,17 @@ +#include + +#include "models/education_type/postgre.hpp" +#include "models/lesson_filter/type.hpp" +#include "utils/convert/drop_properties_ref.hpp" +namespace timetable_vsu_backend::models { +using TupleLessonFilter = + timetable_vsu_backend::utils::convert::drop_properties_to_ref_const_t< + LessonFilter>; +} +namespace userver::storages::postgres::io { + +template <> +struct CppToUserPg { + static constexpr DBTypeName postgres_name = "vsu_timetable.lesson_filter"; +}; +} // namespace userver::storages::postgres::io diff --git a/src/models/lesson_filter/type.hpp b/src/models/lesson_filter/type.hpp new file mode 100644 index 00000000..fb6f1aa2 --- /dev/null +++ b/src/models/lesson_filter/type.hpp @@ -0,0 +1,49 @@ +#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/timestring/type.hpp" +#include "utils/convert/additional_properties.hpp" + +namespace timetable_vsu_backend::models { +namespace convert = utils::convert; +struct LessonFilter { + convert::OptionalArrayProperty lesson_ids; + convert::OptionalProperty begin; + convert::OptionalProperty end; + convert::OptionalArrayProperty days; + convert::OptionalArrayProperty + department_ids; + convert::OptionalArrayProperty + department_names; + convert::OptionalArrayProperty + faculty_ids; + convert::OptionalArrayProperty faculty_names; + convert::OptionalArrayProperty group_ids; + convert::OptionalArrayProperty group_names; + convert::OptionalArrayProperty group_courses; + convert::OptionalArrayProperty + group_types; + convert::OptionalArrayProperty room_ids; + convert::OptionalArrayProperty room_names; + convert::OptionalProperty subgroup; + convert::OptionalArrayProperty + subject_ids; + convert::OptionalArrayProperty subject_names; + convert::OptionalArrayProperty + teacher_ids; + convert::OptionalArrayProperty teacher_fios; + convert::OptionalArrayProperty teacher_bios; + convert::OptionalProperty week; + convert::OptionalProperty type; + convert::OptionalArrayProperty numbers; + static constexpr utils::convert::PolicyFields kPolicyFields = + utils::convert::PolicyFields::ConvertAll; +}; +} // namespace timetable_vsu_backend::models diff --git a/src/models/lesson_type/all.hpp b/src/models/lesson_type/all.hpp new file mode 100644 index 00000000..382480ec --- /dev/null +++ b/src/models/lesson_type/all.hpp @@ -0,0 +1,4 @@ +#pragma once +#include "models/lesson_type/parse.hpp" +#include "models/lesson_type/postgre.hpp" +#include "models/lesson_type/serialize.hpp" diff --git a/src/models/lesson_type/parse.cpp b/src/models/lesson_type/parse.cpp new file mode 100644 index 00000000..d7f49f0d --- /dev/null +++ b/src/models/lesson_type/parse.cpp @@ -0,0 +1,34 @@ +#include "parse.hpp" + +#include + +#include +#include + +#include "type.hpp" +#include "utils/json_type.hpp" + +namespace timetable_vsu_backend::models { +LessonType Parse(std::string_view str, + userver::formats::parse::To) { + if (str == "labaratory") { + return LessonType::kLabaratory; + } else if (str == "lection") { + return LessonType::kLection; + } else if (str == "practice") { + return LessonType::kPractice; + } else + throw std::runtime_error(fmt::format( + "Fail parse LessonType, get unexpected value: {}", str)); +} +LessonType Parse(const userver::formats::json::Value& value, + userver::formats::parse::To) { + if (!value.IsString()) { + throw std::runtime_error(fmt::format( + "Expected string type, but got: {}", utils::GetType(value))); + } + auto raw_value = value.As(); + return Parse(std::string_view{raw_value}, + userver::formats::parse::To{}); +} +} // namespace timetable_vsu_backend::models diff --git a/src/models/lesson_type/parse.hpp b/src/models/lesson_type/parse.hpp new file mode 100644 index 00000000..e569df19 --- /dev/null +++ b/src/models/lesson_type/parse.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include +#include + +#include "type.hpp" + +namespace timetable_vsu_backend::models { +LessonType Parse(std::string_view str, userver::formats::parse::To); +LessonType Parse(const userver::formats::json::Value& value, + userver::formats::parse::To); +} // namespace timetable_vsu_backend::models diff --git a/src/models/lesson_type/postgre.hpp b/src/models/lesson_type/postgre.hpp new file mode 100644 index 00000000..e70d1b92 --- /dev/null +++ b/src/models/lesson_type/postgre.hpp @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include + +#include "type.hpp" + +namespace userver::storages::postgres::io { +using timetable_vsu_backend::models::LessonType; +template <> +struct CppToUserPg : EnumMappingBase { + static constexpr userver::storages::postgres::DBTypeName postgres_name = + "vsu_timetable.type_lesson"; + static constexpr userver::utils::TrivialBiMap enumerators = + [](auto selector) { + return selector() + .Case("labaratory", LessonType::kLabaratory) + .Case("lection", LessonType::kLection) + .Case("practice", LessonType::kPractice); + }; +}; +} // namespace userver::storages::postgres::io diff --git a/src/models/lesson_type/serialize.cpp b/src/models/lesson_type/serialize.cpp new file mode 100644 index 00000000..b40d508b --- /dev/null +++ b/src/models/lesson_type/serialize.cpp @@ -0,0 +1,24 @@ +#include "serialize.hpp" + +#include + +namespace timetable_vsu_backend::models { +std::string Serialize(const LessonType& value, + userver::formats::serialize::To) { + switch (value) { + case LessonType::kLabaratory: + return "labaratory"; + case LessonType::kLection: + return "lection"; + case LessonType::kPractice: + return "practice"; + } +} +userver::formats::json::Value Serialize( + const LessonType& value, + userver::formats::serialize::To) { + std::string str = + Serialize(value, userver::formats::serialize::To{}); + return userver::formats::json::ValueBuilder(str).ExtractValue(); +} +} // namespace timetable_vsu_backend::models diff --git a/src/models/lesson_type/serialize.hpp b/src/models/lesson_type/serialize.hpp new file mode 100644 index 00000000..b8525801 --- /dev/null +++ b/src/models/lesson_type/serialize.hpp @@ -0,0 +1,12 @@ +#pragma once +#include + +#include "type.hpp" + +namespace timetable_vsu_backend::models { +userver::formats::json::Value Serialize( + const LessonType& value, + userver::formats::serialize::To); +std::string Serialize(const LessonType& value, + userver::formats::serialize::To); +} // namespace timetable_vsu_backend::models diff --git a/src/models/lesson_type/type.hpp b/src/models/lesson_type/type.hpp new file mode 100644 index 00000000..3c18811e --- /dev/null +++ b/src/models/lesson_type/type.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace timetable_vsu_backend::models { +enum struct LessonType { kLabaratory, kLection, kPractice }; +} diff --git a/src/models/lesson_v1/parse.hpp b/src/models/lesson_v1/parse.hpp new file mode 100644 index 00000000..9b53ac07 --- /dev/null +++ b/src/models/lesson_v1/parse.hpp @@ -0,0 +1,8 @@ +#pragma once +#include "models/day/parse.hpp" +#include "models/education_type/parse.hpp" +#include "models/lesson_type/parse.hpp" +#include "models/lesson_week_type/parse.hpp" +#include "models/subgroup/parse.hpp" +#include "models/timestring/parse.hpp" +#include "type.hpp" diff --git a/src/models/lesson_v1/postgre.hpp b/src/models/lesson_v1/postgre.hpp new file mode 100644 index 00000000..e7b788f3 --- /dev/null +++ b/src/models/lesson_v1/postgre.hpp @@ -0,0 +1,9 @@ +#include + +#include "models/lesson_v1/type.hpp" +#include "utils/convert/drop_properties_ref.hpp" +namespace timetable_vsu_backend::models { +using TupleLessonV1 = + timetable_vsu_backend::utils::convert::drop_properties_to_ref_mut_t< + LessonV1>; +} diff --git a/src/models/lesson_v1/serialize.hpp b/src/models/lesson_v1/serialize.hpp new file mode 100644 index 00000000..019fa27d --- /dev/null +++ b/src/models/lesson_v1/serialize.hpp @@ -0,0 +1,8 @@ +#pragma once +#include "models/day/serialize.hpp" +#include "models/education_type/serialize.hpp" +#include "models/lesson_type/serialize.hpp" +#include "models/lesson_week_type/serialize.hpp" +#include "models/subgroup/serialize.hpp" +#include "models/timestring/serialize.hpp" +#include "type.hpp" diff --git a/src/models/lesson_v1/type.hpp b/src/models/lesson_v1/type.hpp new file mode 100644 index 00000000..e052dee9 --- /dev/null +++ b/src/models/lesson_v1/type.hpp @@ -0,0 +1,44 @@ +#pragma once +#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/timestring/type.hpp" +#include "utils/convert/base.hpp" + +namespace convert = timetable_vsu_backend::utils::convert; + +namespace timetable_vsu_backend::models { +//Пара со всей дополнительной информацией +struct LessonV1 { + convert::Property lesson_id; + convert::Property lesson_begin; + convert::Property lesson_end; + convert::Property lesson_number; + convert::Property lesson_type; + convert::Property lesson_week_type; + convert::Property lesson_subgroup; + convert::Property lesson_day; + convert::Property room_id; + convert::Property room_name; + convert::Property subject_id; + convert::Property subject_name; + convert::Property group_id; + convert::Property group_stage_course; + convert::Property group_name; + convert::Property group_type; + convert::Property faculty_id; + convert::Property faculty_name; + convert::Property department_id; + convert::Property department_name; + convert::Property teacher_id; + convert::Property teacher_fio; + convert::Property teacher_bio; + static constexpr utils::convert::PolicyFields kPolicyFields = + utils::convert::PolicyFields::ConvertAll; +}; +} // namespace timetable_vsu_backend::models diff --git a/src/models/lesson_week_type/all.hpp b/src/models/lesson_week_type/all.hpp new file mode 100644 index 00000000..f7060391 --- /dev/null +++ b/src/models/lesson_week_type/all.hpp @@ -0,0 +1,4 @@ +#pragma once +#include "models/lesson_week_type/parse.hpp" +#include "models/lesson_week_type/postgre.hpp" +#include "models/lesson_week_type/serialize.hpp" diff --git a/src/models/lesson_week_type/parse.cpp b/src/models/lesson_week_type/parse.cpp new file mode 100644 index 00000000..c6327034 --- /dev/null +++ b/src/models/lesson_week_type/parse.cpp @@ -0,0 +1,33 @@ +#include "parse.hpp" + +#include + +#include +#include + +#include "type.hpp" +#include "utils/json_type.hpp" + +namespace timetable_vsu_backend::models { +LessonWeekType Parse(std::string_view str, + userver::formats::parse::To) { + if (str == "all") { + return LessonWeekType::kAll; + } else if (str == "even") { + return LessonWeekType::kEven; + } else if (str == "odd") { + return LessonWeekType::kOdd; + } else + throw std::runtime_error(fmt::format( + "Fail parse LessonWeekType, get unexpected value: {}", str)); +} +LessonWeekType Parse(const userver::formats::json::Value& value, + userver::formats::parse::To) { + if (!value.IsString()) { + throw std::runtime_error(fmt::format( + "Expected string type, but got: {}", utils::GetType(value))); + } + auto raw_value = value.As(); + return Parse(raw_value, userver::formats::parse::To{}); +} +} // namespace timetable_vsu_backend::models diff --git a/src/models/lesson_week_type/parse.hpp b/src/models/lesson_week_type/parse.hpp new file mode 100644 index 00000000..c63efbb7 --- /dev/null +++ b/src/models/lesson_week_type/parse.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include +#include + +#include "type.hpp" + +namespace timetable_vsu_backend::models { +LessonWeekType Parse(std::string_view str, + userver::formats::parse::To); +LessonWeekType Parse(const userver::formats::json::Value& value, + userver::formats::parse::To); +} // namespace timetable_vsu_backend::models diff --git a/src/models/lesson_week_type/postgre.hpp b/src/models/lesson_week_type/postgre.hpp new file mode 100644 index 00000000..e9a0a8d2 --- /dev/null +++ b/src/models/lesson_week_type/postgre.hpp @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include + +#include "type.hpp" + +namespace userver::storages::postgres::io { +using timetable_vsu_backend::models::LessonWeekType; +template <> +struct CppToUserPg : EnumMappingBase { + static constexpr userver::storages::postgres::DBTypeName postgres_name = + "vsu_timetable.type_of_week"; + static constexpr userver::utils::TrivialBiMap enumerators = + [](auto selector) { + return selector() + .Case("all", LessonWeekType::kAll) + .Case("even", LessonWeekType::kEven) + .Case("odd", LessonWeekType::kOdd); + }; +}; +} // namespace userver::storages::postgres::io diff --git a/src/models/lesson_week_type/serialize.cpp b/src/models/lesson_week_type/serialize.cpp new file mode 100644 index 00000000..865653f5 --- /dev/null +++ b/src/models/lesson_week_type/serialize.cpp @@ -0,0 +1,24 @@ +#include "serialize.hpp" + +#include + +namespace timetable_vsu_backend::models { +std::string Serialize(const LessonWeekType& value, + userver::formats::serialize::To) { + switch (value) { + case LessonWeekType::kAll: + return "all"; + case LessonWeekType::kEven: + return "even"; + case LessonWeekType::kOdd: + return "odd"; + } +} +userver::formats::json::Value Serialize( + const LessonWeekType& value, + userver::formats::serialize::To) { + std::string str = + Serialize(value, userver::formats::serialize::To{}); + return userver::formats::json::ValueBuilder(str).ExtractValue(); +} +} // namespace timetable_vsu_backend::models diff --git a/src/models/lesson_week_type/serialize.hpp b/src/models/lesson_week_type/serialize.hpp new file mode 100644 index 00000000..c4cca84a --- /dev/null +++ b/src/models/lesson_week_type/serialize.hpp @@ -0,0 +1,12 @@ +#pragma once +#include + +#include "type.hpp" + +namespace timetable_vsu_backend::models { +userver::formats::json::Value Serialize( + const LessonWeekType& value, + userver::formats::serialize::To); +std::string Serialize(const LessonWeekType& value, + userver::formats::serialize::To); +} // namespace timetable_vsu_backend::models diff --git a/src/models/lesson_week_type/type.hpp b/src/models/lesson_week_type/type.hpp new file mode 100644 index 00000000..7d971fbb --- /dev/null +++ b/src/models/lesson_week_type/type.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace timetable_vsu_backend::models { +enum struct LessonWeekType { kAll, kEven, kOdd }; +} diff --git a/src/models/lesson_with_details/parse.hpp b/src/models/lesson_with_details/parse.hpp new file mode 100644 index 00000000..9b53ac07 --- /dev/null +++ b/src/models/lesson_with_details/parse.hpp @@ -0,0 +1,8 @@ +#pragma once +#include "models/day/parse.hpp" +#include "models/education_type/parse.hpp" +#include "models/lesson_type/parse.hpp" +#include "models/lesson_week_type/parse.hpp" +#include "models/subgroup/parse.hpp" +#include "models/timestring/parse.hpp" +#include "type.hpp" diff --git a/src/models/lesson_with_details/postgre.hpp b/src/models/lesson_with_details/postgre.hpp new file mode 100644 index 00000000..cf03db26 --- /dev/null +++ b/src/models/lesson_with_details/postgre.hpp @@ -0,0 +1,8 @@ +#pragma once +#include "models/day/postgre.hpp" +#include "models/education_type/postgre.hpp" +#include "models/lesson_type/postgre.hpp" +#include "models/lesson_week_type/postgre.hpp" +#include "models/subgroup/postgre.hpp" +#include "models/timestring/postgre.hpp" +#include "type.hpp" diff --git a/src/models/lesson_with_details/serialize.hpp b/src/models/lesson_with_details/serialize.hpp new file mode 100644 index 00000000..019fa27d --- /dev/null +++ b/src/models/lesson_with_details/serialize.hpp @@ -0,0 +1,8 @@ +#pragma once +#include "models/day/serialize.hpp" +#include "models/education_type/serialize.hpp" +#include "models/lesson_type/serialize.hpp" +#include "models/lesson_week_type/serialize.hpp" +#include "models/subgroup/serialize.hpp" +#include "models/timestring/serialize.hpp" +#include "type.hpp" diff --git a/src/models/lesson_with_details/type.hpp b/src/models/lesson_with_details/type.hpp new file mode 100644 index 00000000..3bb3c7f3 --- /dev/null +++ b/src/models/lesson_with_details/type.hpp @@ -0,0 +1,41 @@ +#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/timestring/type.hpp" + +namespace timetable_vsu_backend::models { +// postgres type +struct LessonWithDetails { + boost::uuids::uuid lesson_id; + TimeString lesson_begin; + TimeString lesson_end; + short lesson_number; + LessonType lesson_type; + LessonWeekType lesson_week_type; + Subgroup lesson_subgroup; + Day lesson_day; + boost::uuids::uuid room_id; + std::string room_name; + boost::uuids::uuid subject_id; + std::string subject_name; + boost::uuids::uuid group_id; + short group_stage_course; + std::string group_name; + EducationType group_type; + boost::uuids::uuid faculty_id; + std::string faculty_name; + boost::uuids::uuid department_id; + std::string department_name; + boost::uuids::uuid teacher_id; + std::string teacher_fio; + std::string teacher_bio; +}; + +} // namespace timetable_vsu_backend::models diff --git a/src/models/subgroup/all.hpp b/src/models/subgroup/all.hpp new file mode 100644 index 00000000..a6cfacf2 --- /dev/null +++ b/src/models/subgroup/all.hpp @@ -0,0 +1,4 @@ +#pragma once +#include "models/subgroup/parse.hpp" +#include "models/subgroup/postgre.hpp" +#include "models/subgroup/serialize.hpp" diff --git a/src/models/subgroup/parse.cpp b/src/models/subgroup/parse.cpp new file mode 100644 index 00000000..14f7d8b1 --- /dev/null +++ b/src/models/subgroup/parse.cpp @@ -0,0 +1,32 @@ +#include "parse.hpp" + +#include + +#include +#include + +#include "type.hpp" +#include "utils/json_type.hpp" + +namespace timetable_vsu_backend::models { +Subgroup Parse(std::string_view str, userver::formats::parse::To) { + if (str == "all") { + return Subgroup::kAll; + } else if (str == "first") { + return Subgroup::kFirst; + } else if (str == "second") { + return Subgroup::kSecond; + } else + throw std::runtime_error( + fmt::format("Fail parse Subgroup, get unexpected value: {}", str)); +} +Subgroup Parse(const userver::formats::json::Value& value, + userver::formats::parse::To) { + if (!value.IsString()) { + throw std::runtime_error(fmt::format( + "Expected string type, but got: {}", utils::GetType(value))); + } + auto raw_value = value.As(); + return Parse(raw_value, userver::formats::parse::To{}); +} +} // namespace timetable_vsu_backend::models diff --git a/src/models/subgroup/parse.hpp b/src/models/subgroup/parse.hpp new file mode 100644 index 00000000..effdf729 --- /dev/null +++ b/src/models/subgroup/parse.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include +#include + +#include "type.hpp" + +namespace timetable_vsu_backend::models { +Subgroup Parse(std::string_view str, userver::formats::parse::To); +Subgroup Parse(const userver::formats::json::Value& value, + userver::formats::parse::To); +} // namespace timetable_vsu_backend::models diff --git a/src/models/subgroup/postgre.hpp b/src/models/subgroup/postgre.hpp new file mode 100644 index 00000000..ff27c143 --- /dev/null +++ b/src/models/subgroup/postgre.hpp @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include + +#include "type.hpp" + +namespace userver::storages::postgres::io { +using timetable_vsu_backend::models::Subgroup; +template <> +struct CppToUserPg : EnumMappingBase { + static constexpr userver::storages::postgres::DBTypeName postgres_name = + "vsu_timetable.subgroup"; + static constexpr userver::utils::TrivialBiMap enumerators = + [](auto selector) { + return selector() + .Case("all", Subgroup::kAll) + .Case("first", Subgroup::kFirst) + .Case("second", Subgroup::kSecond); + }; +}; +} // namespace userver::storages::postgres::io diff --git a/src/models/subgroup/serialize.cpp b/src/models/subgroup/serialize.cpp new file mode 100644 index 00000000..a83ba485 --- /dev/null +++ b/src/models/subgroup/serialize.cpp @@ -0,0 +1,24 @@ +#include "serialize.hpp" + +#include + +namespace timetable_vsu_backend::models { +std::string Serialize(const Subgroup& value, + userver::formats::serialize::To) { + switch (value) { + case Subgroup::kAll: + return "all"; + case Subgroup::kFirst: + return "first"; + case Subgroup::kSecond: + return "second"; + } +} +userver::formats::json::Value Serialize( + const Subgroup& value, + userver::formats::serialize::To) { + std::string str = + Serialize(value, userver::formats::serialize::To{}); + return userver::formats::json::ValueBuilder(str).ExtractValue(); +} +} // namespace timetable_vsu_backend::models diff --git a/src/models/subgroup/serialize.hpp b/src/models/subgroup/serialize.hpp new file mode 100644 index 00000000..d7d23893 --- /dev/null +++ b/src/models/subgroup/serialize.hpp @@ -0,0 +1,12 @@ +#pragma once +#include + +#include "type.hpp" + +namespace timetable_vsu_backend::models { +userver::formats::json::Value Serialize( + const Subgroup& value, + userver::formats::serialize::To); +std::string Serialize(const Subgroup& value, + userver::formats::serialize::To); +} // namespace timetable_vsu_backend::models diff --git a/src/models/subgroup/type.hpp b/src/models/subgroup/type.hpp new file mode 100644 index 00000000..0f7dc379 --- /dev/null +++ b/src/models/subgroup/type.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace timetable_vsu_backend::models { +enum struct Subgroup { kAll, kFirst, kSecond }; +} diff --git a/src/models/timestring/all.hpp b/src/models/timestring/all.hpp new file mode 100644 index 00000000..b7ef3910 --- /dev/null +++ b/src/models/timestring/all.hpp @@ -0,0 +1,4 @@ +#pragma once +#include "models/timestring/parse.hpp" +#include "models/timestring/postgre.hpp" +#include "models/timestring/serialize.hpp" diff --git a/src/models/timestring/fwd.hpp b/src/models/timestring/fwd.hpp new file mode 100644 index 00000000..0703ea2d --- /dev/null +++ b/src/models/timestring/fwd.hpp @@ -0,0 +1,4 @@ +#pragma once +namespace timetable_vsu_backend::models { +struct TimeString; +} diff --git a/src/models/timestring/parse.cpp b/src/models/timestring/parse.cpp new file mode 100644 index 00000000..8ade93f8 --- /dev/null +++ b/src/models/timestring/parse.cpp @@ -0,0 +1,26 @@ +#include "parse.hpp" + +#include + +#include +#include + +#include "type.hpp" +#include "utils/json_type.hpp" + +namespace timetable_vsu_backend::models { +TimeString Parse(const std::string& str, + userver::formats::parse::To) { + auto value = userver::utils::datetime::GuessStringtime(str, "UTC"); + return TimeString{value}; +} +TimeString Parse(const userver::formats::json::Value& value, + userver::formats::parse::To) { + if (!value.IsString()) { + throw std::runtime_error(fmt::format( + "Expected string type, but got: {}", utils::GetType(value))); + } + auto raw_value = value.As(); + return Parse(raw_value, userver::formats::parse::To{}); +} +} // namespace timetable_vsu_backend::models diff --git a/src/models/timestring/parse.hpp b/src/models/timestring/parse.hpp new file mode 100644 index 00000000..caea51b6 --- /dev/null +++ b/src/models/timestring/parse.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include +#include + +#include "type.hpp" + +namespace timetable_vsu_backend::models { +TimeString Parse(const std::string& str, + userver::formats::parse::To); +TimeString Parse(const userver::formats::json::Value& value, + userver::formats::parse::To); +} // namespace timetable_vsu_backend::models diff --git a/src/models/timestring/postgre.hpp b/src/models/timestring/postgre.hpp new file mode 100644 index 00000000..36adbe63 --- /dev/null +++ b/src/models/timestring/postgre.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include + +#include "type.hpp" + +namespace userver::storages::postgres::io { +using timetable_vsu_backend::models::TimeString; +template <> +struct CppToSystemPg : PredefinedOid { +}; +} // namespace userver::storages::postgres::io diff --git a/src/models/timestring/serialize.cpp b/src/models/timestring/serialize.cpp new file mode 100644 index 00000000..25ca2339 --- /dev/null +++ b/src/models/timestring/serialize.cpp @@ -0,0 +1,18 @@ +#include "serialize.hpp" + +#include +#include + +namespace timetable_vsu_backend::models { +std::string Serialize(const TimeString& value, + userver::formats::serialize::To) { + return userver::utils::datetime::Timestring(value.GetUnderlying()); +} +userver::formats::json::Value Serialize( + const TimeString& value, + userver::formats::serialize::To) { + std::string str = + Serialize(value, userver::formats::serialize::To{}); + return userver::formats::json::ValueBuilder(str).ExtractValue(); +} +} // namespace timetable_vsu_backend::models diff --git a/src/models/timestring/serialize.hpp b/src/models/timestring/serialize.hpp new file mode 100644 index 00000000..03285b54 --- /dev/null +++ b/src/models/timestring/serialize.hpp @@ -0,0 +1,12 @@ +#pragma once +#include + +#include "type.hpp" + +namespace timetable_vsu_backend::models { +userver::formats::json::Value Serialize( + const TimeString& value, + userver::formats::serialize::To); +std::string Serialize(const TimeString& value, + userver::formats::serialize::To); +} // namespace timetable_vsu_backend::models diff --git a/src/models/timestring/type.hpp b/src/models/timestring/type.hpp new file mode 100644 index 00000000..ecee3cda --- /dev/null +++ b/src/models/timestring/type.hpp @@ -0,0 +1,8 @@ +#pragma once +#include +#include +namespace timetable_vsu_backend::models { +using TimeString = + userver::utils::StrongTypedef; +} diff --git a/src/models/user/postgre.hpp b/src/models/user/postgre.hpp index 34286e48..9491c70d 100644 --- a/src/models/user/postgre.hpp +++ b/src/models/user/postgre.hpp @@ -1,9 +1,9 @@ #pragma once #include #include +#include #include "type.hpp" -#include "userver/utils/trivial_map.hpp" namespace userver::storages::postgres::io { // This specialization MUST go to the header together with the mapped type @@ -13,4 +13,4 @@ struct CppToUserPg { static constexpr userver::storages::postgres::DBTypeName postgres_name = "uuid"; }; -} // namespace userver::storages::postgres::io \ No newline at end of file +} // namespace userver::storages::postgres::io diff --git a/src/models/user/type.hpp b/src/models/user/type.hpp index 15565b8d..b2462c46 100644 --- a/src/models/user/type.hpp +++ b/src/models/user/type.hpp @@ -2,14 +2,11 @@ #include #include -#include "models/user_type/type.hpp" - namespace timetable_vsu_backend::models { struct User { using Id = userver::utils::StrongTypedef; Id id; std::string login; std::string password; - UserType user_type; }; -} // namespace timetable_vsu_backend::models \ No newline at end of file +} // namespace timetable_vsu_backend::models diff --git a/src/models/user_type/parse.cpp b/src/models/user_type/parse.cpp index b09d242a..305faa26 100644 --- a/src/models/user_type/parse.cpp +++ b/src/models/user_type/parse.cpp @@ -32,4 +32,4 @@ UserType Parse(const userver::formats::json::Value& value, return Parse(std::string_view{raw_value}, userver::formats::parse::To{}); } -} // namespace timetable_vsu_backend::models \ No newline at end of file +} // namespace timetable_vsu_backend::models diff --git a/src/models/user_type/parse.hpp b/src/models/user_type/parse.hpp index 459b762d..13ce01c3 100644 --- a/src/models/user_type/parse.hpp +++ b/src/models/user_type/parse.hpp @@ -1,12 +1,12 @@ #pragma once #include +#include #include #include "type.hpp" -#include "userver/formats/json/value.hpp" namespace timetable_vsu_backend::models { UserType Parse(std::string_view str, userver::formats::parse::To); UserType Parse(const userver::formats::json::Value& value, userver::formats::parse::To); -} // namespace timetable_vsu_backend::models \ No newline at end of file +} // namespace timetable_vsu_backend::models diff --git a/src/models/user_type/postgre.hpp b/src/models/user_type/postgre.hpp index 70f28f5c..991edd99 100644 --- a/src/models/user_type/postgre.hpp +++ b/src/models/user_type/postgre.hpp @@ -1,9 +1,9 @@ #pragma once #include #include +#include #include "type.hpp" -#include "userver/utils/trivial_map.hpp" namespace userver::storages::postgres::io { using timetable_vsu_backend::models::UserType; @@ -20,4 +20,4 @@ struct CppToUserPg : EnumMappingBase { .Case("teacher", UserType::kTeacher); }; }; -} // namespace userver::storages::postgres::io \ No newline at end of file +} // namespace userver::storages::postgres::io diff --git a/src/models/user_type/serialize.cpp b/src/models/user_type/serialize.cpp index 947e4088..15667144 100644 --- a/src/models/user_type/serialize.cpp +++ b/src/models/user_type/serialize.cpp @@ -1,6 +1,6 @@ #include "serialize.hpp" -#include "userver/formats/json/value_builder.hpp" +#include namespace timetable_vsu_backend::models { std::string Serialize(const UserType& value, @@ -23,4 +23,4 @@ userver::formats::json::Value Serialize( Serialize(value, userver::formats::serialize::To{}); return userver::formats::json::ValueBuilder(str).ExtractValue(); } -} // namespace timetable_vsu_backend::models \ No newline at end of file +} // namespace timetable_vsu_backend::models diff --git a/src/models/user_type/serialize.hpp b/src/models/user_type/serialize.hpp index 661673cd..9cc00559 100644 --- a/src/models/user_type/serialize.hpp +++ b/src/models/user_type/serialize.hpp @@ -1,6 +1,7 @@ #pragma once +#include + #include "type.hpp" -#include "userver/formats/json/value.hpp" namespace timetable_vsu_backend::models { userver::formats::json::Value Serialize( @@ -8,4 +9,4 @@ userver::formats::json::Value Serialize( userver::formats::serialize::To); std::string Serialize(const UserType& value, userver::formats::serialize::To); -} // namespace timetable_vsu_backend::models \ No newline at end of file +} // namespace timetable_vsu_backend::models diff --git a/src/utils/component_list_fwd.hpp b/src/utils/component_list_fwd.hpp index d89a12bf..6f669f0c 100644 --- a/src/utils/component_list_fwd.hpp +++ b/src/utils/component_list_fwd.hpp @@ -1,4 +1,4 @@ #pragma once namespace userver::components { class ComponentList; -} \ No newline at end of file +} diff --git a/src/utils/constexpr_string.hpp b/src/utils/constexpr_string.hpp index b3127c8e..c275a8a7 100644 --- a/src/utils/constexpr_string.hpp +++ b/src/utils/constexpr_string.hpp @@ -37,4 +37,4 @@ struct ConstexprString { return string == lhs; } }; -} // namespace timetable_vsu_backend::utils \ No newline at end of file +} // namespace timetable_vsu_backend::utils diff --git a/src/utils/convert/additional_properties.hpp b/src/utils/convert/additional_properties.hpp new file mode 100644 index 00000000..c0851c11 --- /dev/null +++ b/src/utils/convert/additional_properties.hpp @@ -0,0 +1,88 @@ +#pragma once +#include "base.hpp" + +namespace std { +template +class optional; +} + +namespace timetable_vsu_backend::utils::convert { + +template +using OptionalProperty = + BaseProperty, name, RequestParse::Unspecified>; + +template +concept IsArray = requires { + typename U::value_type; + requires std::is_same_v, U>; +}; + +template +concept IsOptionalProperty = requires { + requires std::is_class_v; + typename T::value_type; + typename T::value_type::value_type; + requires std::is_same_v< + OptionalProperty, T>; + requires !IsArray; +}; + +//Оригинальный тип, спрятанный под OptionalProperty +template +using optional_property_t = typename T::value_type::value_type; + +template +using ArrayProperty = + BaseProperty, name, RequestParse::Unspecified>; + +//Оригинальный тип, спрятанный под ArrayProperty +template +concept IsArrayProperty = requires { + requires std::is_class_v; + typename T::value_type; + typename T::value_type::value_type; + requires std::is_same_v< + ArrayProperty, T>; +}; + +template +using array_property_t = typename T::value_type::value_type; + +template +using OptionalArrayProperty = BaseProperty>, name, + RequestParse::Unspecified>; + +template +concept IsOptionalArrayProperty = requires { + requires std::is_class_v; + typename T::value_type; + typename T::value_type::value_type; + typename T::value_type::value_type::value_type; + requires std::is_same_v< + OptionalArrayProperty, + T>; +}; + +//Оригинальный тип, спрятанный под OptionalArrayProperty +template +using optional_array_property_t = + typename T::value_type::value_type::value_type; + +//концепт проверяет, является ли свойство структурным, то есть несёт в себе +//структуру, которую так же необходимо разложить +template +concept IsStructuralProperty = requires { + requires IsAnyProperty; + requires IsConvertAll; +}; + +//данный концепт является костылём, он определяет, что поле является "обычным" +//свойством, то есть не требует дополнительных действий +template +concept IsUsualProperty = + IsAnyProperty && !IsOptionalProperty && !IsOptionalArrayProperty && + !IsArrayProperty && !IsStructuralProperty; + +} // namespace timetable_vsu_backend::utils::convert diff --git a/src/utils/convert/base.hpp b/src/utils/convert/base.hpp index da87ed3a..9df92776 100644 --- a/src/utils/convert/base.hpp +++ b/src/utils/convert/base.hpp @@ -10,9 +10,13 @@ namespace timetable_vsu_backend::utils::convert { //В данный момент поддерживаются только конвертация всех полей enum struct PolicyFields { ConvertAll }; -//тип тела в запросе. Empty body = body игнорируеттся -enum struct TypeOfBody { Empty, Json }; +//тип тела в запросе +enum struct TypeOfBody { + Empty, // Empty body = body игнорируеттся + Json +}; +//указание откуда следует парсить в http запросе enum struct RequestParse { Unspecified, //данное поле в запросах будет парсится из body Query, @@ -84,4 +88,4 @@ template concept IsConvertAll = requires { requires T::kPolicyFields == PolicyFields::ConvertAll; }; -} // namespace timetable_vsu_backend::utils::convert \ No newline at end of file +} // namespace timetable_vsu_backend::utils::convert diff --git a/src/utils/convert/detail/drop_properties/const_dropper_to_ref.hpp b/src/utils/convert/detail/drop_properties/const_dropper_to_ref.hpp new file mode 100644 index 00000000..ce57dd69 --- /dev/null +++ b/src/utils/convert/detail/drop_properties/const_dropper_to_ref.hpp @@ -0,0 +1,134 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../base.hpp" +#include "utils/convert/additional_properties.hpp" +#include "utils/type_holder.hpp" +namespace timetable_vsu_backend::utils::convert::detail::drop_properties { +template +struct ConstDropperToRef final { + static auto Do(const T& t) { + auto tuple = GetTuple(t); + return HandleTuple(tuple, IndexSequence{}); + } + static auto ResultType() { + return type_holder()))>{}; + } + + // protected: + using ValueType = T; + //кортеж ссылок на изначальную структуру + using TupleType = + decltype(boost::pfr::structure_tie(std::declval())); + //количество полей + static constexpr std::size_t size = std::tuple_size::value; + //последовательность индексов для обхода полей + using IndexSequence = std::make_index_sequence; + //создаем кортеж ссылок на изначальную структуру + static TupleType GetTuple(const ValueType& v) { + return boost::pfr::structure_tie(v); + } + //если это usual propery, то через () получаем ссылку на изначальный объект + //под + template + static decltype(auto) HandleMember(const Member& member) { + return member(); + } + + template + static decltype(auto) HandleMember(const Member& member) { + using NestedType = optional_property_t; + //если вложенный тип структурный, то нужна дополнительная магия + if constexpr (IsConvertAll) { + //подсматривает результирующий тип + using ResultTypeHelper = + decltype(ConstDropperToRef::ResultType()); + using ResultType = typename ResultTypeHelper::value_type; + std::optional result = std::nullopt; + if (member().has_value()) { + result = ConstDropperToRef::Do(member().value()); + } + return result; + } else { + return member(); + } + } + + template + static decltype(auto) HandleMember(const Member& member) { + using NestedType = array_property_t; + auto& value = member(); + //если вложенный тип структурный, то нужна дополнительная магия + if constexpr (IsConvertAll) { + //подсматривает результирующий тип + using ResultTypeHelper = + decltype(ConstDropperToRef::ResultType()); + using ResultType = typename ResultTypeHelper::value_type; + std::vector result; + result.reserve(value.size()); + for (auto& elem : value) { + result.emplace_back(ConstDropperToRef::Do(elem)); + } + return result; + } else { + return member(); + } + } + + template + static decltype(auto) HandleMember(const Member& member) { + using NestedType = optional_array_property_t; + auto& value = member(); + //если вложенный тип структурный, то нужна дополнительная магия + if constexpr (IsConvertAll) { + //подсматривает результирующий тип + using ResultTypeHelper = + decltype(ConstDropperToRef::ResultType()); + using ResultType = typename ResultTypeHelper::value_type; + std::optional> result = std::nullopt; + if (value.has_value()) { + result = std::vector{}; + result->reserve(value->size()); + for (auto& elem : *value) { + result.emplace_back( + ConstDropperToRef::Do(elem)); + } + } + return result; + } else { + return member(); + } + } + + //если это структурное свойство, то раскладываем его + template + static decltype(auto) HandleMember(const Member& member) { + using RawType = typename Member::value_type; + return ConstDropperToRef::Do(member()); + } + template + static decltype(auto) HelpHandleMember(Tuple& tuple) { + return HandleMember(std::get(tuple)); + } + template + static auto ConstructResult(Type&&... values) { + return std::tuple(std::forward(values)...); + } + template + static decltype(auto) HandleTuple(Tuple& tuple, + std::index_sequence) { + return ConstructResult(HelpHandleMember(tuple)...); + } +}; +} // namespace timetable_vsu_backend::utils::convert::detail::drop_properties diff --git a/src/utils/convert/detail/drop_properties/mut_dropper_to_ref.hpp b/src/utils/convert/detail/drop_properties/mut_dropper_to_ref.hpp new file mode 100644 index 00000000..80f1c9ba --- /dev/null +++ b/src/utils/convert/detail/drop_properties/mut_dropper_to_ref.hpp @@ -0,0 +1,134 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../base.hpp" +#include "utils/convert/additional_properties.hpp" +#include "utils/type_holder.hpp" +namespace timetable_vsu_backend::utils::convert::detail::drop_properties { + +template +struct MutDropperToRef final { + static auto Do(T& t) { + auto tuple = GetTuple(t); + return HandleTuple(tuple, IndexSequence{}); + } + static auto ResultType() { + return type_holder()))>{}; + } + + // protected: + using ValueType = T; + //кортеж ссылок на изначальную структуру + using TupleType = + decltype(boost::pfr::structure_tie(std::declval())); + //количество полей + static constexpr std::size_t size = std::tuple_size::value; + //последовательность индексов для обхода полей + using IndexSequence = std::make_index_sequence; + //создаем кортеж ссылок на изначальную структуру + static TupleType GetTuple(ValueType& v) { + return boost::pfr::structure_tie(v); + } + //если это usual propery, то через () получаем ссылку на изначальный объект + //под + template + static decltype(auto) HandleMember(Member& member) { + return member(); + } + + template + static decltype(auto) HandleMember(Member& member) { + using NestedType = optional_property_t; + //если вложенный тип структурный, то нужна дополнительная магия + if constexpr (IsConvertAll) { + //подсматривает результирующий тип + using ResultTypeHelper = + decltype(MutDropperToRef::ResultType()); + using ResultType = typename ResultTypeHelper::value_type; + std::optional result = std::nullopt; + if (member().has_value()) { + result = MutDropperToRef::Do(member().value()); + } + return result; + } else { + return member(); + } + } + + template + static decltype(auto) HandleMember(Member& member) { + using NestedType = array_property_t; + auto& value = member(); + //если вложенный тип структурный, то нужна дополнительная магия + if constexpr (IsConvertAll) { + //подсматривает результирующий тип + using ResultTypeHelper = + decltype(MutDropperToRef::ResultType()); + using ResultType = typename ResultTypeHelper::value_type; + std::vector result; + result.reserve(value.size()); + for (auto& elem : value) { + result.emplace_back(MutDropperToRef::Do(elem)); + } + return result; + } else { + return member(); + } + } + + template + static decltype(auto) HandleMember(Member& member) { + using NestedType = optional_array_property_t; + auto& value = member(); + //если вложенный тип структурный, то нужна дополнительная магия + if constexpr (IsConvertAll) { + //подсматривает результирующий тип + using ResultTypeHelper = + decltype(MutDropperToRef::ResultType()); + using ResultType = typename ResultTypeHelper::value_type; + std::optional> result = std::nullopt; + if (value.has_value()) { + result = std::vector{}; + result->reserve(value->size()); + for (auto& elem : *value) { + result.emplace_back(MutDropperToRef::Do(elem)); + } + } + return result; + } else { + return member(); + } + } + + //если это структурное свойство, то раскладываем его + template + static decltype(auto) HandleMember(Member& member) { + using RawType = typename Member::value_type; + return MutDropperToRef::Do(member()); + } + + template + static decltype(auto) HelpHandleMember(Tuple& tuple) { + return HandleMember(std::get(tuple)); + } + template + static auto ConstructResult(Type&&... values) { + return std::tuple(std::forward(values)...); + } + template + static decltype(auto) HandleTuple(Tuple& tuple, + std::index_sequence) { + return ConstructResult(HelpHandleMember(tuple)...); + } +}; +} // namespace timetable_vsu_backend::utils::convert::detail::drop_properties diff --git a/src/utils/convert/detail/parse/converter_http_request.hpp b/src/utils/convert/detail/parse/converter_http_request.hpp index f6c2dc99..19ed3a9c 100644 --- a/src/utils/convert/detail/parse/converter_http_request.hpp +++ b/src/utils/convert/detail/parse/converter_http_request.hpp @@ -1,10 +1,16 @@ #pragma once +#include + #include +#include +#include #include +#include +#include +#include +#include -#include "userver/formats/json/value.hpp" -#include "userver/server/http/http_request.hpp" -#include "utils/convert/base.hpp" +#include "../../base.hpp" namespace timetable_vsu_backend::utils::convert::detail::parse { template @@ -49,7 +55,23 @@ struct ConverterHttpRequest { const userver::formats::json::Value& body, Field& field) { static constexpr std::string_view kName = Field::kName; - field = body[kName].template As(); + using FieldValue = typename Field::value_type; + if (body.IsNull()) { + throw std::runtime_error(fmt::format( + "Unexpected null json get while parsing field: {}", kName)); + } else if (body.IsMissing()) { + throw std::runtime_error(fmt::format( + "Unexpected missing json get while parsing field: {}", kName)); + } + if (!body.HasMember(kName)) { + if constexpr (userver::meta::kIsOptional) { + field = std::nullopt; + } else { + throw std::runtime_error( + fmt::format("Missing field: {}", kName)); + } + } + field = body[kName].template As(); } //парсим поле из query template @@ -100,7 +122,8 @@ struct ConverterHttpRequest { template static auto GetBody(const userver::server::http::HttpRequest& value) { if constexpr (type_of_body == TypeOfBody::Json) { - return userver::formats::json::FromString(value.RequestBody()); + auto json = userver::formats::json::FromString(value.RequestBody()); + return json; } else { return EmptyBody{}; } @@ -114,4 +137,4 @@ struct ConverterHttpRequest { (ParseField(value, body, std::get(tuple)), ...); } }; -} // namespace timetable_vsu_backend::utils::convert::detail::parse \ No newline at end of file +} // namespace timetable_vsu_backend::utils::convert::detail::parse diff --git a/src/utils/convert/detail/parse/converter_json.hpp b/src/utils/convert/detail/parse/converter_json.hpp index 5f25fe54..130c208b 100644 --- a/src/utils/convert/detail/parse/converter_json.hpp +++ b/src/utils/convert/detail/parse/converter_json.hpp @@ -30,6 +30,22 @@ struct ConverterJson { static void ParseField(const userver::formats::json::Value& value, Field& field) { static constexpr std::string_view kName = Field::kName; + using FieldValue = typename Field::value_type; + if (value.IsNull()) { + throw std::runtime_error(fmt::format( + "Unexpected null json get while parsing field: {}", kName)); + } else if (value.IsMissing()) { + throw std::runtime_error(fmt::format( + "Unexpected missing json get while parsing field: {}", kName)); + } + if (!value.HasMember(kName)) { + if constexpr (userver::meta::kIsOptional) { + field = std::nullopt; + } else { + throw std::runtime_error( + fmt::format("Missing field: {}", kName)); + } + } field = value[kName].template As(); } //проверяем, что каждое поле кортежа является Property @@ -46,4 +62,4 @@ struct ConverterJson { (ParseField(value, std::get(tuple)), ...); } }; -} // namespace timetable_vsu_backend::utils::convert::detail::parse \ No newline at end of file +} // namespace timetable_vsu_backend::utils::convert::detail::parse diff --git a/src/utils/convert/detail/serialize/converter_http_response.hpp b/src/utils/convert/detail/serialize/converter_http_response.hpp index 915aa2ac..544b1f45 100644 --- a/src/utils/convert/detail/serialize/converter_http_response.hpp +++ b/src/utils/convert/detail/serialize/converter_http_response.hpp @@ -1,9 +1,9 @@ #pragma once #include #include +#include +#include -#include "userver/formats/json/value_builder.hpp" -#include "userver/server/http/http_response.hpp" #include "utils/convert/base.hpp" #include "utils/convert/http_response_base.hpp" @@ -126,4 +126,4 @@ struct ConverterHttpResponse { (SerializeField(response, body, std::get(tuple)), ...); } }; -} // namespace timetable_vsu_backend::utils::convert::detail::serialize \ No newline at end of file +} // namespace timetable_vsu_backend::utils::convert::detail::serialize diff --git a/src/utils/convert/detail/serialize/converter_json.hpp b/src/utils/convert/detail/serialize/converter_json.hpp index 01f616b0..5439e70c 100644 --- a/src/utils/convert/detail/serialize/converter_json.hpp +++ b/src/utils/convert/detail/serialize/converter_json.hpp @@ -1,7 +1,7 @@ #pragma once #include +#include -#include "userver/formats/json/value_builder.hpp" #include "utils/convert/base.hpp" namespace timetable_vsu_backend::utils::convert::detail::serialize { @@ -49,4 +49,4 @@ struct ConverterJson { (SerializeField(value, std::get(tuple)), ...); } }; -} // namespace timetable_vsu_backend::utils::convert::detail::serialize \ No newline at end of file +} // namespace timetable_vsu_backend::utils::convert::detail::serialize diff --git a/src/utils/convert/drop_properties_ref.hpp b/src/utils/convert/drop_properties_ref.hpp new file mode 100644 index 00000000..3cec4e11 --- /dev/null +++ b/src/utils/convert/drop_properties_ref.hpp @@ -0,0 +1,76 @@ +#pragma once +#include +#include +#include + +#include "base.hpp" +#include "detail/drop_properties/const_dropper_to_ref.hpp" +#include "detail/drop_properties/mut_dropper_to_ref.hpp" +namespace timetable_vsu_backend::utils::convert { +//данный концепт лишь активирует перегрузки, но не проверяет все требования для +//типа +template +concept DroppableToTupleRef = IsConvertAll; + +template +concept OptionalDroppableToTupleRef = requires { + typename T::value_type; + requires std::same_as, T>; + requires IsConvertAll; +}; + +//возвращает кортеж константных ссылок на поля структуры, где будут изначальные +//поля +template +auto DropPropertiesToMutRefs(T& t) { + return detail::drop_properties::MutDropperToRef::Do(t); +} + +//возвращает кортеж ссылок на поля структуры, где будут изначальные поля +template +auto DropPropertiesToMutRefs(T& t) { + using ValueType = typename std::remove_cvref_t::value_type; + using ResultTypeHelper = decltype( + detail::drop_properties::MutDropperToRef::ResultType()); + using ResultType = typename ResultTypeHelper::value_type; + std::optional result = std::nullopt; + if (t) { + result.emplace( + detail::drop_properties::MutDropperToRef::Do(*t)); + } + return result; +} + +//возвращает кортеж ссылок на поля структуры, где будут изначальные поля +template +auto DropPropertiesToConstRefs(T& t) { + return detail::drop_properties::ConstDropperToRef::Do(t); +} + +//возвращает кортеж ссылок на поля структуры, где будут изначальные поля +template +auto DropPropertiesToConstRefs(const T& t) { + using ValueType = typename std::remove_cvref_t::value_type; + using ResultTypeHelper = decltype( + detail::drop_properties::ConstDropperToRef::ResultType()); + using ResultType = typename ResultTypeHelper::value_type; + std::optional result = std::nullopt; + if (t.has_value()) { + result.emplace( + detail::drop_properties::ConstDropperToRef::Do( + t.value())); + } + return result; +} + +template +using drop_properties_to_ref_const_t = + decltype(timetable_vsu_backend::utils::convert::DropPropertiesToConstRefs( + std::declval())); + +template +using drop_properties_to_ref_mut_t = + decltype(timetable_vsu_backend::utils::convert::DropPropertiesToMutRefs( + std::declval())); + +} // namespace timetable_vsu_backend::utils::convert diff --git a/src/utils/convert/http_request_parse.hpp b/src/utils/convert/http_request_parse.hpp index fe61a091..7f9185a5 100644 --- a/src/utils/convert/http_request_parse.hpp +++ b/src/utils/convert/http_request_parse.hpp @@ -2,7 +2,7 @@ #include "detail/parse/converter_http_request.hpp" namespace timetable_vsu_backend::utils::convert { -//данынй концепт лишь активирует перегрузки, но не проверяет все требования для +//данный концепт лишь активирует перегрузки, но не проверяет все требования для //типа template concept HttpRequestParsable = IsConvertAll&& HasTypeOfBody; @@ -18,4 +18,4 @@ T Parse(const userver::server::http::HttpRequest& value, T>::Parse(t, value); return t; } -} // namespace userver::formats::parse \ No newline at end of file +} // namespace userver::formats::parse diff --git a/src/utils/convert/http_response_base.hpp b/src/utils/convert/http_response_base.hpp index e55e8306..4afb58b3 100644 --- a/src/utils/convert/http_response_base.hpp +++ b/src/utils/convert/http_response_base.hpp @@ -24,4 +24,4 @@ concept HasStatusCode = requires { ->std::convertible_to; requires IsConstexpr; }; -} // namespace timetable_vsu_backend::utils::convert \ No newline at end of file +} // namespace timetable_vsu_backend::utils::convert diff --git a/src/utils/convert/http_response_serialize.hpp b/src/utils/convert/http_response_serialize.hpp index 57410b94..70fd9625 100644 --- a/src/utils/convert/http_response_serialize.hpp +++ b/src/utils/convert/http_response_serialize.hpp @@ -2,7 +2,7 @@ #include "detail/serialize/converter_http_response.hpp" namespace timetable_vsu_backend::utils::convert { -//данынй концепт лишь активирует перегрузки, но не проверяет все требования для +//данный концепт лишь активирует перегрузки, но не проверяет все требования для //типа template concept HttpResponseSeriazable = @@ -12,4 +12,4 @@ template void Serialize(const T& t, HttpResponse& response) { detail::serialize::ConverterHttpResponse::Serialize(t, response); } -} // namespace timetable_vsu_backend::utils::convert \ No newline at end of file +} // namespace timetable_vsu_backend::utils::convert diff --git a/src/utils/convert/json_parse.hpp b/src/utils/convert/json_parse.hpp index 15e47891..2c0603fb 100644 --- a/src/utils/convert/json_parse.hpp +++ b/src/utils/convert/json_parse.hpp @@ -1,8 +1,10 @@ #pragma once #include "detail/parse/converter_json.hpp" +#include "userver/compiler/demangle.hpp" +#include "userver/logging/log.hpp" namespace timetable_vsu_backend::utils::convert { -//данынй концепт лишь активирует перегрузки, но не проверяет все требования для +//данный концепт лишь активирует перегрузки, но не проверяет все требования для //типа template concept JsonParsable = IsConvertAll; @@ -23,4 +25,4 @@ T Parse(const json::Value& value, To) { return t; } -} // namespace userver::formats::parse \ No newline at end of file +} // namespace userver::formats::parse diff --git a/src/utils/convert/json_serialize.hpp b/src/utils/convert/json_serialize.hpp index f8746d96..3ccd58ae 100644 --- a/src/utils/convert/json_serialize.hpp +++ b/src/utils/convert/json_serialize.hpp @@ -2,7 +2,7 @@ #include "detail/serialize/converter_json.hpp" namespace timetable_vsu_backend::utils::convert { -//данынй концепт лишь активирует перегрузки, но не проверяет все требования для +//данный концепт лишь активирует перегрузки, но не проверяет все требования для //типа template concept JsonSeriazable = IsConvertAll; @@ -22,4 +22,4 @@ json::Value Serialize(const T& t, To) { T>::Serialize(t, json); return json.ExtractValue(); } -} // namespace userver::formats::serialize \ No newline at end of file +} // namespace userver::formats::serialize diff --git a/src/utils/json_type.cpp b/src/utils/json_type.cpp index 767bfa9a..13fdcbde 100644 --- a/src/utils/json_type.cpp +++ b/src/utils/json_type.cpp @@ -1,8 +1,7 @@ #include "json_type.hpp" #include - -#include "userver/formats/json/impl/types.hpp" +#include namespace timetable_vsu_backend::utils { std::string_view GetType(const userver::formats::json::Value& value) { @@ -27,4 +26,4 @@ std::string_view GetType(const userver::formats::json::Value& value) { } else return "Unknown"; } -} // namespace timetable_vsu_backend::utils \ No newline at end of file +} // namespace timetable_vsu_backend::utils diff --git a/src/utils/json_type.hpp b/src/utils/json_type.hpp index f052409d..a13a2da2 100644 --- a/src/utils/json_type.hpp +++ b/src/utils/json_type.hpp @@ -1,9 +1,8 @@ #include #pragma once +#include #include -#include "userver/formats/json/value.hpp" - namespace timetable_vsu_backend::utils { std::string_view GetType(const userver::formats::json::Value& value); -} \ No newline at end of file +} diff --git a/src/utils/type_holder.hpp b/src/utils/type_holder.hpp new file mode 100644 index 00000000..29d63d22 --- /dev/null +++ b/src/utils/type_holder.hpp @@ -0,0 +1,5 @@ +#pragma once +template +struct type_holder { + using value_type = Type; +}; diff --git a/src/views/get-timetable/Request.hpp b/src/views/get-timetable/Request.hpp new file mode 100644 index 00000000..5b860119 --- /dev/null +++ b/src/views/get-timetable/Request.hpp @@ -0,0 +1,20 @@ +#pragma once +#include +#include +#include +#include + +#include "models/lesson_filter/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" + +namespace timetable_vsu_backend::views::get_timetable { +using namespace utils::convert; +struct Request { + OptionalProperty filter; + static constexpr TypeOfBody kTypeOfBody = TypeOfBody::Json; + static constexpr PolicyFields kPolicyFields = PolicyFields::ConvertAll; +}; +} // namespace timetable_vsu_backend::views::get_timetable diff --git a/src/views/get-timetable/Responses.hpp b/src/views/get-timetable/Responses.hpp new file mode 100644 index 00000000..c0a03fc4 --- /dev/null +++ b/src/views/get-timetable/Responses.hpp @@ -0,0 +1,32 @@ +#pragma once +#include +#include +#include + +#include "http/ErrorV1.hpp" +#include "models/lesson_v1/type.hpp" +#include "models/user_type/serialize.hpp" +#include "models/user_type/type.hpp" +#include "userver/formats/json/value.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/convert/json_serialize.hpp" + +namespace timetable_vsu_backend::views::get_timetable { +using namespace utils::convert; +struct Response200 { + ArrayProperty lessons; + static constexpr TypeOfBody kTypeOfBody = TypeOfBody::Json; + static constexpr PolicyFields kPolicyFields = PolicyFields::ConvertAll; + static constexpr userver::server::http::HttpStatus kStatusCode = + userver::server::http::HttpStatus::kOk; +}; + +static_assert(userver::formats::common::impl::kHasSerialize< + userver::formats::json::Value, models::LessonV1>); +static_assert(userver::formats::common::impl::kHasSerialize< + userver::formats::json::Value, std::vector>); + +} // namespace timetable_vsu_backend::views::get_timetable diff --git a/src/views/get-timetable/view.cpp b/src/views/get-timetable/view.cpp new file mode 100644 index 00000000..38d5cd78 --- /dev/null +++ b/src/views/get-timetable/view.cpp @@ -0,0 +1,72 @@ +#include "view.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Request.hpp" +#include "Responses.hpp" +#include "components/controllers/postgres/lesson/controller.hpp" +#include "helpers/lesson_converter.hpp" +#include "http/handler_parsed.hpp" +#include "models/day/all.hpp" +#include "models/education_type/all.hpp" +#include "models/lesson_v1/parse.hpp" +#include "models/lesson_v1/serialize.hpp" +#include "models/lesson_with_details/parse.hpp" +#include "models/lesson_with_details/serialize.hpp" +#include "models/user_type/type.hpp" +#include "userver/logging/log.hpp" +#include "utils/convert/http_request_parse.hpp" +#include "utils/convert/http_response_serialize.hpp" +#include "utils/convert/json_parse.hpp" +#include "utils/convert/json_serialize.hpp" + +static_assert(userver::formats::common::impl::kHasSerialize< + userver::formats::json::Value, + timetable_vsu_backend::models::LessonType>); +namespace timetable_vsu_backend::views::get_timetable { + +namespace { + +using components::controllers::postgres::LessonDetailsController; +class Handler final : public http::HandlerParsed { + public: + static constexpr std::string_view kName = "handler-get-timetable"; + Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : HandlerParsed(config, context), + lesson_controller(context.FindComponent()) { + } + static void ValidateBeginEnd(Request& request) { + if (request.filter() and request.filter()->begin() and + request.filter()->end() && + request.filter()->begin().value() > + request.filter()->end().value()) { + std::swap(request.filter()->begin().value(), + request.filter()->end().value()); + } + } + Response Handle(Request&& request) const override { + Response200 resp; + ValidateBeginEnd(request); + resp.lessons() = lesson_controller.Search(request.filter()); + return resp; + } + + private: + const LessonDetailsController& lesson_controller; +}; +} // namespace + +void Append(userver::components::ComponentList& component_list) { + component_list.Append(); +} + +} // namespace timetable_vsu_backend::views::get_timetable diff --git a/src/views/get-timetable/view.hpp b/src/views/get-timetable/view.hpp new file mode 100644 index 00000000..ecd9a8a1 --- /dev/null +++ b/src/views/get-timetable/view.hpp @@ -0,0 +1,7 @@ +#pragma once +#include "utils/component_list_fwd.hpp" +namespace timetable_vsu_backend::views::get_timetable { + +void Append(userver::components::ComponentList& component_list); + +} diff --git a/src/views/hello/view.cpp b/src/views/hello/view.cpp index d429964b..fbfcb649 100644 --- a/src/views/hello/view.cpp +++ b/src/views/hello/view.cpp @@ -72,4 +72,4 @@ void AppendHello(userver::components::ComponentList& component_list) { component_list.Append(); } -} // namespace service_template \ No newline at end of file +} // namespace service_template diff --git a/src/views/hello/view.hpp b/src/views/hello/view.hpp index ef51c616..6e14a601 100644 --- a/src/views/hello/view.hpp +++ b/src/views/hello/view.hpp @@ -11,4 +11,4 @@ std::string SayHelloTo(std::string_view name, UserType type); void AppendHello(userver::components::ComponentList& component_list); -} // namespace service_template \ No newline at end of file +} // namespace service_template diff --git a/src/views/login/Request.hpp b/src/views/login/Request.hpp index 7793b6e0..321ddaa3 100644 --- a/src/views/login/Request.hpp +++ b/src/views/login/Request.hpp @@ -1,9 +1,9 @@ #pragma once #include +#include #include +#include -#include "userver/formats/common/meta.hpp" -#include "userver/server/http/http_request.hpp" #include "utils/convert/base.hpp" #include "utils/convert/http_request_parse.hpp" #include "utils/convert/json_parse.hpp" @@ -17,4 +17,4 @@ struct Request { static constexpr PolicyFields kPolicyFields = PolicyFields::ConvertAll; }; static_assert(HasTypeOfBody); -} // namespace timetable_vsu_backend::views::login \ No newline at end of file +} // namespace timetable_vsu_backend::views::login diff --git a/src/views/login/Responses.hpp b/src/views/login/Responses.hpp index 9aa3af54..c0e14613 100644 --- a/src/views/login/Responses.hpp +++ b/src/views/login/Responses.hpp @@ -27,4 +27,4 @@ struct Response500 { static constexpr userver::server::http::HttpStatus kStatusCode = userver::server::http::HttpStatus::kInternalServerError; }; -} // namespace timetable_vsu_backend::views::login \ No newline at end of file +} // namespace timetable_vsu_backend::views::login diff --git a/src/views/login/view.cpp b/src/views/login/view.cpp index 1d4baaf7..ff48931b 100644 --- a/src/views/login/view.cpp +++ b/src/views/login/view.cpp @@ -3,23 +3,25 @@ #include #include #include +#include +#include +#include #include "Request.hpp" -#include "components/controllers/token_controller.hpp" -#include "components/controllers/user_controller.hpp" +#include "Responses.hpp" +#include "components/controllers/postgres/token/controller.hpp" +#include "components/controllers/postgres/user/controller.hpp" #include "http/handler_parsed.hpp" #include "models/auth_token/serialize.hpp" -#include "userver/formats/parse/to.hpp" -#include "userver/storages/postgres/component.hpp" -#include "userver/utils/datetime.hpp" -#include "views/login/Responses.hpp" +#include "models/user_type/type.hpp" namespace timetable_vsu_backend::views::login { namespace { -class LoginHandler final - : public http::HandlerParsed { +using components::controllers::postgres::TokenController; +using components::controllers::postgres::UserController; +class Handler final : public http::HandlerParsed { static Response401 PerformInvalidCredentials() { Response401 resp; resp.description = "Account not founded: login or password invalid"; @@ -28,13 +30,12 @@ class LoginHandler final } public: - static constexpr std::string_view kName = "handler-login"; - LoginHandler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& context) + [[maybe_unused]] static constexpr std::string_view kName = "handler-login"; + Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) : HandlerParsed(config, context), - user_controller(context.FindComponent()), - token_controller( - context.FindComponent()) { + user_controller(context.FindComponent()), + token_controller(context.FindComponent()) { } Response Handle(Request&& request) const override { @@ -50,17 +51,17 @@ class LoginHandler final boost::uuids::to_string(user->id.GetUnderlying())); return Response500{}; } - return Response200{{*id}, {user->user_type}}; + return Response200{{*id}, {models::UserType::kUser}}; } private: - const components::UserController& user_controller; - const components::TokenController& token_controller; + const UserController& user_controller; + const TokenController& token_controller; }; } // namespace void Append(userver::components::ComponentList& component_list) { - component_list.Append(); + component_list.Append(); } } // namespace timetable_vsu_backend::views::login diff --git a/src/views/register/Request.cpp b/src/views/register/Request.cpp index ca4be265..7bec7a73 100644 --- a/src/views/register/Request.cpp +++ b/src/views/register/Request.cpp @@ -1,9 +1,10 @@ #include "Request.hpp" -#include "userver/formats/json.hpp" -#include "userver/formats/json/value_builder.hpp" -#include "userver/logging/log.hpp" -#include "userver/server/http/http_request.hpp" +#include +#include +#include +#include + #include "utils/json_type.hpp" namespace timetable_vsu_backend::views::register_ { @@ -14,4 +15,4 @@ Request Parse(const userver::server::http::HttpRequest& value, auto password = body["password"].As(); return Request{std::move(login), std::move(password)}; } -} // namespace timetable_vsu_backend::views::register_ \ No newline at end of file +} // namespace timetable_vsu_backend::views::register_ diff --git a/src/views/register/Request.hpp b/src/views/register/Request.hpp index 40364d70..bc3f5bdf 100644 --- a/src/views/register/Request.hpp +++ b/src/views/register/Request.hpp @@ -13,4 +13,4 @@ struct Request { }; Request Parse(const userver::server::http::HttpRequest& value, userver::formats::parse::To); -} // namespace timetable_vsu_backend::views::register_ \ No newline at end of file +} // namespace timetable_vsu_backend::views::register_ diff --git a/src/views/register/view.cpp b/src/views/register/view.cpp index 7ce80129..23032346 100644 --- a/src/views/register/view.cpp +++ b/src/views/register/view.cpp @@ -7,41 +7,40 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "Request.hpp" -#include "components/controllers/token_controller.hpp" -#include "components/controllers/user_controller.hpp" +#include "components/controllers/postgres/token/controller.hpp" +#include "components/controllers/postgres/user/controller.hpp" #include "http/legacy_handler_parsed.hpp" #include "models/auth_token/serialize.hpp" -#include "userver/formats/parse/to.hpp" -#include "userver/logging/log.hpp" -#include "userver/storages/postgres/component.hpp" -#include "userver/utils/boost_uuid4.hpp" -#include "userver/utils/datetime.hpp" -#include "userver/utils/uuid4.hpp" namespace timetable_vsu_backend::views::register_ { namespace { +using components::controllers::postgres::TokenController; +using components::controllers::postgres::UserController; using Response = models::AuthToken; -class RegisterHandler final - : public http::LegacyHandlerParsed { +class Handler final : public http::LegacyHandlerParsed { public: static constexpr std::string_view kName = "handler-register"; using http::LegacyHandlerParsed::LegacyHandlerParsed; - RegisterHandler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& context) + Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) : LegacyHandlerParsed(config, context), - user_controller(context.FindComponent()), - token_controller( - context.FindComponent()) { + user_controller(context.FindComponent()), + token_controller(context.FindComponent()) { } Response Handle( Request&& request, userver::server::http::HttpResponse& http_response) const override { - models::User user{models::User::Id{}, request.login, request.password, - models::UserType::kUser}; + models::User user{models::User::Id{}, request.login, request.password}; auto user_id = user_controller.TryToAdd(user); if (!user_id) { LOG_DEBUG() << fmt::format("Cannot create user, login: {}", @@ -63,13 +62,13 @@ class RegisterHandler final } private: - const components::UserController& user_controller; - const components::TokenController& token_controller; + const UserController& user_controller; + const TokenController& token_controller; }; } // namespace void Append(userver::components::ComponentList& component_list) { - component_list.Append(); + component_list.Append(); } } // namespace timetable_vsu_backend::views::register_ diff --git a/tests/__init__.py b/tests/__init__.py index e69de29b..1f143595 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -0,0 +1,2 @@ +class NothingHere: + pass diff --git a/tests/conftest.py b/tests/conftest.py index f486df66..259a0275 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,13 +1,28 @@ import pathlib - +import os +from datetime import datetime import pytest from testsuite.databases.pgsql import discover +from _pytest.assertion import truncate +truncate.DEFAULT_MAX_LINES = 9999 +truncate.DEFAULT_MAX_CHARS = 9999 pytest_plugins = ['pytest_userver.plugins.postgresql'] +@pytest.hookimpl +def pytest_runtest_setup(item): + logging_plugin = item.config.pluginmanager.get_plugin("logging-plugin") + timestamp = datetime.strftime(datetime.now(), '%Y-%m-%d_%H-%M-%S') + path = 'results' + if item.cls is not None: + path = os.path.join(path, item.cls.__name__) + logging_plugin.set_log_path(os.path.join( + path, f'{item.name}_{timestamp}.log')) + + @pytest.fixture(scope='session') def service_source_dir(): """Path to root directory service.""" diff --git a/tests/get-timetable/get_timetable_data.py b/tests/get-timetable/get_timetable_data.py new file mode 100644 index 00000000..8f422c30 --- /dev/null +++ b/tests/get-timetable/get_timetable_data.py @@ -0,0 +1,345 @@ +K_LESSON = { + "id": "3d04fc36-ab71-42db-9e38-efd792afa7ba", # + + "begin": "2023-04-01T05:30:00+0000", # + + "end": "2023-05-01T07:05:00+0000", # + + "number": 1, # + + "type": "lection", # + + "week_type": "all", # + + "subgroup": "all", # + + "day": "monday", # + + "room_id": "f245127f-a730-4d13-a15d-7648deb1d4d2", # + + "room_name": "101", # + + "subject_id": "053222c5-315a-4301-abfe-586d2409fcd3", + "subject_name": "Mathematics", # + + "group_id": "4148147a-740b-48f9-aba1-47eb17432855", # + + "group_course": 1, # + + "group_name": "MM-21", # + + "group_type": "magistracy", # + + "faculty_id": "bbc6312c-f25e-4db3-b2a0-3f5dc6717a8d", # + + "faculty_name": "Faculty of Mathematics and Mechanics", # + + "department_id": "1f93ceb4-d931-4b66-a0e5-7323d6b60f3b", # + + "department_name": "Department of Applied Mathematics", # + + "teacher_id": "241416c7-9654-4814-b36b-7d39c1ddded2", # + + "teacher_fio": "John Doe", # + + "teacher_bio": "Professor of Mathematics" # + +} + +K_FIELDS_SUBJECT_IDS = [ + ('subject_ids', ['053222c5-315a-4301-abfe-586d2409fcd3'], True), + ('subject_ids', ['22244447-9654-4814-b36b-7d39c1ddded2'], False), + ('subject_ids', ['22244447-9654-4814-b36b-7d39c1ddded2', + '053222c5-315a-4301-abfe-586d2409fcd3'], True), +] + +K_IDS_SUBJECT_IDS = [ + 'subject_ids_true', + 'subject_ids_false', + 'subject_ids_many' +] + +K_FIELDS_TEACHER_BIOS = [ + ('teacher_bios', ['Professor of Mathematics'], True), + ('teacher_bios', ['Uskova'], False), + ('teacher_bios', ['Uskova', 'Professor of Mathematics'], True) +] + +K_IDS_TEACHER_BIOS = [ + 'teacher_bios_true', + 'teacher_bios_false', + 'teacher_bios_many' +] + +K_FIELDS_GROUP_TYPES = [ + ('group_types', ['magistracy'], True), + ('group_types', ['postgraduate'], False), + ('group_types', ['postgraduate', 'magistracy'], True) +] + +K_IDS_GROUP_TYPES = [ + 'group_types_true', + 'group_types_false', + 'group_types_many' +] + +K_FIELDS_GROUP_COURSES = [ + ('group_courses', [1], True), + ('group_courses', [2], False), + ('group_courses', [2, 1], True) +] + +K_IDS_GROUP_COURSES = [ + 'group_courses_true', + 'group_courses_false', + 'group_courses_many' +] + +K_FIELDS_ROOM_IDS = [ + ('room_ids', ['f245127f-a730-4d13-a15d-7648deb1d4d2'], True), + ('room_ids', ['22244447-9654-4814-b36b-7d39c1ddded2'], False), + ('room_ids', ['22244447-9654-4814-b36b-7d39c1ddded2', + 'f245127f-a730-4d13-a15d-7648deb1d4d2'], True), +] + +K_IDS_ROOM_IDS = [ + 'room_ids_true', + 'room_ids_false', + 'room_ids_many' +] + +K_FIELDS_LESSON_IDS = [ + ('lesson_ids', ['3d04fc36-ab71-42db-9e38-efd792afa7ba'], True), + ('lesson_ids', ['22244447-9654-4814-b36b-7d39c1ddded2'], False), + ('lesson_ids', ['22244447-9654-4814-b36b-7d39c1ddded2', + '3d04fc36-ab71-42db-9e38-efd792afa7ba'], True), +] + +K_IDS_LESSON_IDS = [ + 'lesson_ids_true', + 'lesson_ids_false', + 'lesson_ids_many' +] + +K_FIELDS_NUMBERS = [ + ('numbers', [1], True), + ('numbers', [2], False), + ('numbers', [2, 1], True) +] + +K_IDS_NUMBERS = [ + 'numbers_true', + 'numbers_false', + 'numbers_many' +] + +K_FIELDS_FACULTY_NAMES = [ + ('faculty_names', ['Faculty of Mathematics and Mechanics'], True), + ('faculty_names', ['RGF'], False), + ('faculty_names', ['RGF', 'Faculty of Mathematics and Mechanics'], True) +] + +K_IDS_FACULTY_NAMES = [ + 'faculty_names_true', + 'faculty_names_false', + 'faculty_names_many' +] + +K_FIELDS_SUBJECT_NAMES = [ + ('subject_names', ['Mathematics'], True), + ('subject_names', ['Russian'], False), + ('subject_names', ['Russian', 'Mathematics'], True) +] + +K_IDS_SUBJECT_NAMES = [ + 'subject_names_true', + 'subject_names_false', + 'subject_names_many' +] + +K_FIELDS_GROUP_NAMES = [ + ('group_names', ['MM-21'], True), + ('group_names', ['62'], False), + ('group_names', ['62', 'MM-21'], True) +] + +K_IDS_GROUP_NAMES = [ + 'group_names_true', + 'group_names_false', + 'group_names_many' +] + +K_FIELDS_GROUP_IDS = [ + ('group_ids', ['4148147a-740b-48f9-aba1-47eb17432855'], True), + ('group_ids', ['22244447-9654-4814-b36b-7d39c1ddded2'], False), + ('group_ids', ['22244447-9654-4814-b36b-7d39c1ddded2', + '4148147a-740b-48f9-aba1-47eb17432855'], True), +] + +K_IDS_GROUP_IDS = [ + 'group_ids_true', + 'group_ids_false', + 'group_ids_many' +] + +K_FIELDS_TEACHER_FIOS = [ + ('teacher_fios', ['John Doe'], True), + ('teacher_fios', ['Uskova'], False), + ('teacher_fios', ['Uskova', 'John Doe'], True) +] + +K_IDS_TEACHER_FIOS = [ + 'teacher_fios_true', + 'teacher_fios_false', + 'teacher_fios_many' +] + +K_FIELDS_TEACHER_IDS = [ + ('teacher_ids', ['241416c7-9654-4814-b36b-7d39c1ddded2'], True), + ('teacher_ids', ['22244447-9654-4814-b36b-7d39c1ddded2'], False), + ('teacher_ids', ['22244447-9654-4814-b36b-7d39c1ddded2', + '241416c7-9654-4814-b36b-7d39c1ddded2'], True), +] + +K_IDS_TEACHER_IDS = [ + 'teacher_ids_true', + 'teacher_ids_false', + 'teacher_ids_many' +] + +K_FIELDS_ROOM_NAMES = [ + ('room_names', ['101'], True), + ('room_names', ['102'], False), + ('room_names', ['102', '101'], True) +] + +K_IDS_ROOM_NAMES = [ + 'room_names_true', + 'room_names_false', + 'room_names_many' +] + +K_FIELDS_FACULTY_IDS = [ + ('faculty_ids', ['bbc6312c-f25e-4db3-b2a0-3f5dc6717a8d'], True), + ('faculty_ids', ['bbcccccc-f25e-4db3-b2a0-3f5dc6717a8d'], False), + ('faculty_ids', ['bbcccccc-f25e-4db3-b2a0-3f5dc6717a8d', + 'bbc6312c-f25e-4db3-b2a0-3f5dc6717a8d'], True) +] + +K_IDS_FACULTY_IDS = [ + 'faculty_ids_true', + 'faculty_ids_false', + 'faculty_ids_many' +] + +K_FIELDS_BEGIN = [ + ('begin', '2023-04-01T05:30:00+0000', True), + ('begin', '2023-06-01T05:30:00+0000', False) +] + +K_IDS_BEGIN = [ + 'begin_true', + 'begin_false' +] + +K_FIELDS_END = [ + ('end', '2023-06-01T05:30:00+0000', True), + ('end', '2023-03-01T05:30:00+0000', False) +] + +K_IDS_END = [ + 'end_true', + 'end_false' +] + +K_FIELDS_LESSON_TYPE = [ + ('lesson_type', 'lection', True), + ('lesson_type', 'practice', False), +] + +K_IDS_LESSON_TYPE = [ + 'lesson_type_true', + 'lesson_type_false' +] + +K_FIELDS_WEEK_TYPE = [ + ('week_type', 'all', True), + ('week_type', 'odd', False), +] + +K_IDS_WEEK_TYPE = [ + 'week_type_true', + 'week_type_false' +] + +K_FIELDS_SUBGROUP = [ + ('subgroup', 'all', True), + ('subgroup', 'second', False), +] + +K_IDS_SUBGROUP = [ + 'subgroup_true', + 'subgroup_false' +] + +K_FIELDS_DAYS = [ + ('days', ['monday'], True), + ('days', ['tuesday'], False), + ('days', ['monday', 'tuesday'], True) +] + +K_IDS_DAYS = [ + 'days_true', + 'days_false', + 'days_many_true', +] + +K_FIELDS_DEPARTMENT_IDS = [ + ('department_ids', ['1f93ceb4-d931-4b66-a0e5-7323d6b60f3b'], True), + ('department_ids', ['11111111-d931-4b66-a0e5-7323d6b60f1b'], False), + ('department_ids', ['11111111-d931-4b66-a0e5-7323d6b60f1b', + '1f93ceb4-d931-4b66-a0e5-7323d6b60f3b'], True), +] + +K_IDS_DEPARTMENT_IDS = [ + 'dep_ids_true', + 'dep_ids_false', + 'dep_ids_many_true', +] + +K_FIELDS_DEPARTMENT_NAMES = [ + ('department_names', ['Department of Applied Mathematics'], True), + ('department_names', ['Another Department'], False), + ('department_names', ['Another Department', + 'Department of Applied Mathematics'], True), +] + +K_IDS_DEPARTMENT_NAMES = [ + 'dep_names_true', + 'dep_names_false', + 'dep_names_many_true', +] + +K_FIELDS = K_FIELDS_DAYS \ + + K_FIELDS_DEPARTMENT_IDS \ + + K_FIELDS_DEPARTMENT_NAMES \ + + K_FIELDS_SUBGROUP \ + + K_FIELDS_WEEK_TYPE \ + + K_FIELDS_LESSON_TYPE \ + + K_FIELDS_BEGIN \ + + K_FIELDS_END \ + + K_FIELDS_FACULTY_IDS \ + + K_FIELDS_ROOM_NAMES \ + + K_FIELDS_TEACHER_IDS \ + + K_FIELDS_TEACHER_FIOS \ + + K_FIELDS_GROUP_IDS \ + + K_FIELDS_GROUP_NAMES \ + + K_FIELDS_SUBJECT_NAMES \ + + K_FIELDS_FACULTY_NAMES \ + + K_FIELDS_NUMBERS \ + + K_FIELDS_LESSON_IDS \ + + K_FIELDS_ROOM_IDS \ + + K_FIELDS_GROUP_COURSES \ + + K_FIELDS_GROUP_TYPES \ + + K_FIELDS_SUBJECT_IDS + +K_IDS = K_IDS_DAYS \ + + K_IDS_DEPARTMENT_IDS \ + + K_IDS_DEPARTMENT_NAMES \ + + K_IDS_SUBGROUP \ + + K_IDS_WEEK_TYPE \ + + K_IDS_LESSON_TYPE \ + + K_IDS_BEGIN \ + + K_IDS_END \ + + K_IDS_FACULTY_IDS \ + + K_IDS_ROOM_NAMES \ + + K_IDS_TEACHER_IDS \ + + K_IDS_TEACHER_FIOS \ + + K_IDS_GROUP_IDS \ + + K_IDS_GROUP_NAMES \ + + K_IDS_SUBJECT_NAMES \ + + K_IDS_FACULTY_NAMES \ + + K_IDS_NUMBERS \ + + K_IDS_LESSON_IDS \ + + K_IDS_ROOM_IDS \ + + K_IDS_GROUP_COURSES \ + + K_IDS_GROUP_TYPES \ + + K_IDS_SUBJECT_IDS diff --git a/tests/get-timetable/test_get_timetable_basic.py b/tests/get-timetable/test_get_timetable_basic.py new file mode 100644 index 00000000..f6a83bb3 --- /dev/null +++ b/tests/get-timetable/test_get_timetable_basic.py @@ -0,0 +1,33 @@ +import pytest +import logging +from testsuite.databases import pgsql +from get_timetable_data import K_IDS +from get_timetable_data import K_FIELDS +from get_timetable_data import K_LESSON + + +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_get_timetable_one_lesson(service_client, field, value, found): + + response = await service_client.post('/get-timetable', json={ + "filter": _perform_filter(field, value) + }) + assert response.status_code == 200 + assert 'lessons' in response.json() + if found: + assert len(response.json()['lessons']) == 1 + assert response.json()['lessons'] == [K_LESSON] + else: + assert len(response.json()['lessons']) == 0 + assert response.json()['lessons'] == [] diff --git a/tests/pytest.ini b/tests/pytest.ini index 23260b64..c988b45e 100644 --- a/tests/pytest.ini +++ b/tests/pytest.ini @@ -1,4 +1,4 @@ [pytest] asyncio_mode = auto log_level = debug -addopts = -p no:warnings \ No newline at end of file +addopts = -p no:warnings diff --git a/tests/requirements.txt b/tests/requirements.txt index 450d540c..7cfdee5c 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,2 +1,2 @@ yandex-taxi-testsuite >= 0.1.7.2 -yandex-taxi-testsuite[postgresql-binary] >= 0.1.7.2 \ No newline at end of file +yandex-taxi-testsuite[postgresql-binary] >= 0.1.7.2 diff --git a/united_api.yaml b/united_api.yaml index 9ce06c9c..515fb5d9 100644 --- a/united_api.yaml +++ b/united_api.yaml @@ -7,18 +7,18 @@ components: куки TypesDay: enum: - - Monday - - Tuesday - - Wednesday - - Thursday - - Friday - - Saturday + - monday + - tuesday + - wednesday + - thursday + - friday + - saturday type: string TypesEducationType: enum: - undergraduate - magistracy - - magistracy + - postgraduate - specialty type: string TypesErrorV1: @@ -45,12 +45,38 @@ components: properties: begin: $ref: '#/components/schemas/TypesTimestamp' + day: + $ref: '#/components/schemas/TypesDay' + department_id: + $ref: '#/components/schemas/TypesId' + department_name: + description: Название факультета + example: ПММ + type: string end: $ref: '#/components/schemas/TypesTimestamp' - group: - $ref: '#/components/schemas/TypesGroupV1' + faculty_id: + $ref: '#/components/schemas/TypesId' + faculty_name: + description: Название факультета + example: ПММ + type: string + group_course: + maximum: 6 + minimum: 1 + type: integer group_id: $ref: '#/components/schemas/TypesId' + group_name: + description: Название группы + example: ФИИТ + type: string + group_type: + $ref: '#/components/schemas/TypesEducationType' + id: + $ref: '#/components/schemas/TypesId' + number: + $ref: '#/components/schemas/TypesNumberLesson' room_id: $ref: '#/components/schemas/TypesId' room_name: @@ -64,15 +90,18 @@ components: subject_name: example: Дифференциальные уравнения type: string + teacher_bio: + example: Нереально работаю в ВГУ + type: string teacher_fio: example: Иванов Иван Иванович type: string teacher_id: example: some_id type: string - type_lesson: + type: $ref: '#/components/schemas/TypesTypeOfLesson' - week: + week_type: $ref: '#/components/schemas/TypesTypeOfWeek' TypesNumberLesson: enum: @@ -87,27 +116,27 @@ components: TypesSubgroup: description: 'Тип подгруппы: All - для обеих' enum: - - All - - First - - Second + - all + - first + - second type: string TypesTimestamp: - example: 2010-02-10-08.15.000Z + example: 2023-04-01T05:30:00+0000 type: string TypesTypeOfLesson: description: Тип пары enum: - - Labaratory - - Lection - - Practice + - labaratory + - lection + - practice type: string TypesTypeOfWeek: description: 'Тип недели: All - всегда, Even - только по числителю, Odd - только по знаменателю' enum: - - All - - Even - - Odd + - all + - even + - odd type: string TypesUserCredentialV1: properties: @@ -183,34 +212,86 @@ components: $ref: '#/components/schemas/TypesId' ViewsGetTimetableRequest: properties: + begin: + $ref: '#/components/schemas/TypesTimestamp' days: items: $ref: '#/components/schemas/TypesDay' type: array - department_id: - type: string - department_name: - type: string - faculty_id: - type: string - faculty_name: - type: string - group_course: - type: string - group_id: - type: string - group_name: - type: string - room_name: - type: string + department_ids: + items: + $ref: '#/components/schemas/TypesId' + type: array + department_names: + items: + type: string + type: array + end: + ref: ../../types/Timestamp.yaml + faculty_ids: + items: + $ref: '#/components/schemas/TypesId' + type: array + faculty_names: + items: + type: string + type: array + group_courses: + items: + type: integer + type: array + group_ids: + items: + $ref: '#/components/schemas/TypesId' + type: array + group_names: + items: + type: string + type: array + group_types: + items: + type: ../../types/EducationType.yaml + type: array + lesson_ids: + items: + $ref: '#/components/schemas/TypesId' + type: array + lesson_type: + $ref: '#/components/schemas/TypesTypeOfLesson' + numbers: + items: + type: integer + type: array + room_ids: + items: + $ref: '#/components/schemas/TypesId' + type: array + room_names: + items: + type: string + type: array subgroup: $ref: '#/components/schemas/TypesSubgroup' - subject_name: - type: string - teacher_fio: - type: string - teacher_id: - type: string + subject_ids: + items: + $ref: '#/components/schemas/TypesId' + type: array + subject_names: + items: + type: string + type: array + teacher_bios: + items: + type: string + type: array + teacher_fios: + items: + type: string + type: array + teacher_ids: + items: + $ref: '#/components/schemas/TypesId' + type: array week: $ref: '#/components/schemas/TypesTypeOfWeek' ViewsLessonAddRequest: diff --git a/utests/convert_test.cpp b/utests/convert_test.cpp index 38dbb429..feab6bd4 100644 --- a/utests/convert_test.cpp +++ b/utests/convert_test.cpp @@ -3,13 +3,12 @@ #include #include #include +#include +#include +#include +#include #include -#include "userver/formats/common/meta.hpp" -#include "userver/formats/json/value.hpp" -#include "userver/formats/json/value_builder.hpp" -#include "userver/logging/log.hpp" -#include "userver/server/http/http_request.hpp" #include "utils/convert/base.hpp" #include "utils/convert/json_parse.hpp" #include "utils/convert/json_serialize.hpp" @@ -47,4 +46,4 @@ UTEST(TestConvert, BasicStructToJson) { userver::formats::json::ValueBuilder(test_struct).ExtractValue(); EXPECT_EQ(json["login"].As(), "some_login"); EXPECT_EQ(json["password"].As(), "some_password"); -} \ No newline at end of file +} diff --git a/utests/dropper.cpp b/utests/dropper.cpp new file mode 100644 index 00000000..247dc0f8 --- /dev/null +++ b/utests/dropper.cpp @@ -0,0 +1,101 @@ +#include +#include +#include + +#include "userver/utils/assert.hpp" +#include "utils/convert/additional_properties.hpp" +#include "utils/convert/drop_properties_ref.hpp" + +namespace magic = timetable_vsu_backend::utils::convert; +namespace { +struct TestStruct { + static constexpr auto kPolicyFields = magic::PolicyFields::ConvertAll; + magic::Property Login; + magic::Property Password; +}; + +struct TestStruct2 { + static constexpr auto kPolicyFields = magic::PolicyFields::ConvertAll; + magic::Property auth; + magic::Property description; +}; + +} // namespace + +UTEST(TestDropProperties, Recursive) { + TestStruct2 test; + test.auth().Login() = "1232"; + test.auth().Password() = "adad"; + // UASSERT_MSG(false, "Some string"); + auto tuple = magic::DropPropertiesToMutRefs(test); + static_assert( + std::same_as< + decltype(tuple), + std::tuple, std::string&>>); + static_assert(std::same_as(tuple)), + std::tuple&>); + static_assert(std::same_as(tuple)), std::string&>); + UASSERT(std::get<0>(std::get<0>(tuple)) == test.auth().Login()); + UASSERT(std::get<1>(std::get<0>(tuple)) == test.auth().Password()); + auto& left = std::get<1>(tuple); + auto& right = test.description(); + UASSERT_MSG(std::get<1>(tuple) == test.description(), + fmt::format("failed std::get<1>(tuple) == test.description(), " + "left: {}, right: {}", + left, right)); + UASSERT(&std::get<0>(std::get<0>(tuple)) == &test.auth().Login()); + UASSERT(&std::get<1>(std::get<0>(tuple)) == &test.auth().Password()); + UASSERT(&std::get<1>(tuple) == &test.description()); +} + +UTEST(TestDropProperties, Basic) { + TestStruct test; + test.Login() = "1232"; + test.Password() = "adad"; + auto tuple = magic::DropPropertiesToMutRefs(test); + static_assert(std::same_as(tuple)), std::string&>); + static_assert(std::same_as(tuple)), std::string&>); + UASSERT(std::get<0>(tuple) == test.Login()); + UASSERT(std::get<1>(tuple) == test.Password()); + UASSERT(&std::get<0>(tuple) == &test.Login()); + UASSERT(&std::get<1>(tuple) == &test.Password()); +} + +UTEST(TestDropProperties, ConstBasic) { + TestStruct test; + test.Login() = "1232"; + test.Password() = "adad"; + auto tuple = magic::DropPropertiesToConstRefs(std::as_const(test)); + static_assert( + std::same_as(tuple)), const std::string&>); + static_assert( + std::same_as(tuple)), const std::string&>); + UASSERT(std::get<0>(tuple) == test.Login()); + UASSERT(std::get<1>(tuple) == test.Password()); + UASSERT(&std::get<0>(tuple) == &test.Login()); + UASSERT(&std::get<1>(tuple) == &test.Password()); +} + +UTEST(TestDropProperties, ConstRecursive) { + TestStruct2 test; + test.auth().Login() = "1232"; + test.auth().Password() = "adad"; + auto tuple = magic::DropPropertiesToConstRefs(std::as_const(test)); + static_assert(std::same_as< + decltype(tuple), + std::tuple, + const std::string&>>); + static_assert( + std::same_as(tuple)), + std::tuple&>); + static_assert( + std::same_as(tuple)), const std::string&>); + UASSERT(std::get<0>(std::get<0>(tuple)) == test.auth().Login()); + UASSERT(std::get<1>(std::get<0>(tuple)) == test.auth().Password()); + UASSERT(test.description().empty()); + UASSERT(std::get<1>(tuple).empty()); + UASSERT(std::get<1>(tuple) == test.description()); + UASSERT(&std::get<0>(std::get<0>(tuple)) == &test.auth().Login()); + UASSERT(&std::get<1>(std::get<0>(tuple)) == &test.auth().Password()); + UASSERT(&std::get<1>(tuple) == &test.description()); +} diff --git a/utests/dropper_additional.cpp b/utests/dropper_additional.cpp new file mode 100644 index 00000000..66f23173 --- /dev/null +++ b/utests/dropper_additional.cpp @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +#include "userver/utils/assert.hpp" +#include "utils/convert/additional_properties.hpp" +#include "utils/convert/drop_properties_ref.hpp" + +using namespace timetable_vsu_backend::utils::convert; +namespace { +struct TestStruct { + static constexpr auto kPolicyFields = PolicyFields::ConvertAll; + Property login; + Property password; +}; + +struct TestStruct2 { + static constexpr auto kPolicyFields = PolicyFields::ConvertAll; + Property descriptor; + Property money; +}; + +struct TestStruct3 { + static constexpr auto kPolicyFields = PolicyFields::ConvertAll; + OptionalProperty auth; + OptionalProperty description; +}; +} // namespace + +UTEST(TestDropAdditionalProperties, Recursive) { + TestStruct3 test; + test.description() = {TestStruct2{.descriptor = {42}, .money = {43}}}; + auto tuple = DropPropertiesToMutRefs(test); + auto& [_, o2] = test; + auto& [o3, o4] = *o2(); + auto& [t1, t2] = tuple; + using Type1 = decltype(t1); + static_assert( + std::same_as>>); + using Type2 = decltype(t2); + static_assert(std::same_as>>); + UASSERT(!t1); + UASSERT(t2); + auto& [t3, t4] = *t2; + UASSERT(&t3 == &o3()); + UASSERT(&t4 == &o4()); +}