From 2b91e4a3e04f80f833457721d712c44947c7ad67 Mon Sep 17 00:00:00 2001 From: sabudilovskiy Date: Sun, 9 Apr 2023 18:54:07 +0300 Subject: [PATCH] Docs: update merge script + added to git unite_api.yaml Docs: update merge script + added to git unite_api.yaml Login: fix errors responses --- .gen/objs.txt | 4 + .github/workflows/ci.yml | 1 + Makefile | 2 +- api/api.yaml | 7 +- api/types/Day.yaml | 14 +- api/types/LessonV1.yaml | 6 +- api/types/Subgroup.yaml | 10 +- api/types/TypeOfLesson.yaml | 6 + api/types/TypeOfWeek.yaml | 10 +- api/types/UserTypeV1.yaml | 2 +- api/views/login/view.yaml | 4 +- postgresql/data/initial_data_auth.sql | 2 +- scripts/merge_yaml.py | 88 +++- src/http/ErrorV1.hpp | 17 + src/http/handler_parsed.hpp | 2 +- src/models/lesson/type.hpp | 15 + src/models/user_type/serialize.cpp | 26 + src/models/user_type/serialize.hpp | 11 + src/views/login/Responses.hpp | 12 +- src/views/login/view.cpp | 11 +- tests/login/test_login_basic.py | 68 +-- united_api.yaml | 719 ++++++++++++++++++++++++++ 22 files changed, 943 insertions(+), 94 deletions(-) create mode 100644 api/types/TypeOfLesson.yaml create mode 100644 src/http/ErrorV1.hpp create mode 100644 src/models/lesson/type.hpp create mode 100644 src/models/user_type/serialize.cpp create mode 100644 src/models/user_type/serialize.hpp create mode 100644 united_api.yaml diff --git a/.gen/objs.txt b/.gen/objs.txt index c95778e0..276370c6 100644 --- a/.gen/objs.txt +++ b/.gen/objs.txt @@ -24,15 +24,19 @@ src/utils/convert/base.hpp src/utils/constexpr_string.hpp src/utils/component_list_fwd.hpp src/models/user_type/type.hpp +src/models/user_type/serialize.hpp +src/models/user_type/serialize.cpp src/models/user_type/postgre.hpp 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/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 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c2c131a7..e65fe6e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,6 +52,7 @@ jobs: - name: Gen list of source and check diffs with commit run: | make gen + make unite-api make check-git-status - name: Reuse ccache directory uses: actions/cache@v2 diff --git a/Makefile b/Makefile index df7733e6..1fca6855 100644 --- a/Makefile +++ b/Makefile @@ -123,7 +123,7 @@ gen: .PHONY: unite-api unite-api: - @python3 srcipts/merge_yaml.py api/api.yaml merged_api.yaml + @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-% diff --git a/api/api.yaml b/api/api.yaml index cfa919cb..416d948e 100644 --- a/api/api.yaml +++ b/api/api.yaml @@ -45,9 +45,4 @@ paths: /admin/teacher/link: $ref: views/admin/teacher/link/view.yaml /admin/teacher/unlink: - $ref: views/admin/teacher/unlink/view.yaml -components: - schemas: - AuthTokenV1: - $ref: types/AuthTokenV1.yaml - + $ref: views/admin/teacher/unlink/view.yaml \ No newline at end of file diff --git a/api/types/Day.yaml b/api/types/Day.yaml index 81f14d89..cfecdb49 100644 --- a/api/types/Day.yaml +++ b/api/types/Day.yaml @@ -1,8 +1,8 @@ -type: integer +type: string enum: - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 \ No newline at end of file + - Monday + - Tuesday + - Wednesday + - Thursday + - Friday + - Saturday \ No newline at end of file diff --git a/api/types/LessonV1.yaml b/api/types/LessonV1.yaml index 87a5b3c8..4e29f1a6 100644 --- a/api/types/LessonV1.yaml +++ b/api/types/LessonV1.yaml @@ -24,7 +24,9 @@ properties: $ref: './TypeOfWeek.yaml' subgroup: $ref: './Subgroup.yaml' - start: + begin: $ref: './Timestamp.yaml' end: - $ref: './Timestamp.yaml' \ No newline at end of file + $ref: './Timestamp.yaml' + type_lesson: + $ref: './TypeOfLesson.yaml' \ No newline at end of file diff --git a/api/types/Subgroup.yaml b/api/types/Subgroup.yaml index e3f497bf..3beec741 100644 --- a/api/types/Subgroup.yaml +++ b/api/types/Subgroup.yaml @@ -1,6 +1,6 @@ -description: 'Тип подгруппы: 0 - для обеих, 1 - только для левой, 2 - только для правой' -type: integer +description: 'Тип подгруппы: All - для обеих' +type: string enum: - - 0 - - 1 - - 2 \ No newline at end of file + - All + - First + - Second \ No newline at end of file diff --git a/api/types/TypeOfLesson.yaml b/api/types/TypeOfLesson.yaml new file mode 100644 index 00000000..b3bae18d --- /dev/null +++ b/api/types/TypeOfLesson.yaml @@ -0,0 +1,6 @@ +description: 'Тип пары' +type: string +enum: + - Labaratory + - Lection + - Practice \ No newline at end of file diff --git a/api/types/TypeOfWeek.yaml b/api/types/TypeOfWeek.yaml index bbdd8c2b..9e03accb 100644 --- a/api/types/TypeOfWeek.yaml +++ b/api/types/TypeOfWeek.yaml @@ -1,6 +1,6 @@ -description: 'Тип недели: 0 - всегда, 1 - только по числителю, 2 - только по знаменателю' -type: integer +description: 'Тип недели: All - всегда, Even - только по числителю, Odd - только по знаменателю' +type: string enum: - - 0 - - 1 - - 2 \ No newline at end of file + - All + - Even + - Odd \ No newline at end of file diff --git a/api/types/UserTypeV1.yaml b/api/types/UserTypeV1.yaml index 8c13a3eb..529bf5bc 100644 --- a/api/types/UserTypeV1.yaml +++ b/api/types/UserTypeV1.yaml @@ -1,6 +1,6 @@ type: string enum: - - 'student' + - 'user' - 'teacher' - 'admin' - 'root' #may be unused \ No newline at end of file diff --git a/api/views/login/view.yaml b/api/views/login/view.yaml index 45e78e73..b504861d 100644 --- a/api/views/login/view.yaml +++ b/api/views/login/view.yaml @@ -14,7 +14,9 @@ post: application/json: schema: $ref : './ResponseV1.yaml' - '404': + '400': + description: Не переданы необходимые параметры + '401': description: Имя пользователя или пароль не верны content: application/json: diff --git a/postgresql/data/initial_data_auth.sql b/postgresql/data/initial_data_auth.sql index b60cc114..fe5ff088 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('test_user', 'password123', 'user'); \ No newline at end of file +VALUES('some_nickname', 'some_password', 'user'); \ No newline at end of file diff --git a/scripts/merge_yaml.py b/scripts/merge_yaml.py index 82f51a5c..f29044f5 100644 --- a/scripts/merge_yaml.py +++ b/scripts/merge_yaml.py @@ -26,11 +26,16 @@ def resolve_refs(content, base_path, resolved_files): resolve_refs(item, base_path, resolved_files) return content + +def is_ref_to_schemas(v): + return v.startswith('#/components/schemas') + + def have_refs(yaml): if isinstance(yaml, dict): for k, v in yaml.items(): if k == '$ref': - return True + return not is_ref_to_schemas(v) elif have_refs(v): return True elif isinstance(yaml, list): @@ -39,7 +44,35 @@ def have_refs(yaml): return True return False -def replace_ref(yaml, dir_path, ref_path, ref_src): + +def get_ref_name(base_path, path_to_file): + relative_path = os.path.relpath(path_to_file, base_path) + relative_path = relative_path.replace("\\", "/") + + if relative_path.startswith("./"): + relative_path = relative_path[2:] + + if relative_path.endswith("."): + relative_path = relative_path[:-1] + + file_extension = os.path.splitext(relative_path)[-1] + if file_extension: + relative_path = relative_path[:-len(file_extension)] + + result = "" + relative_path = relative_path.replace('-', '/') + relative_path = relative_path.replace('_', '/') + for word in relative_path.split('/'): + temp = word[0].upper() + word[1:] + result += temp + + return result + +def get_ref_name_path(base_path, path_to_file): + result = '#/components/schemas/' + get_ref_name(base_path, path_to_file) + return result + +def replace_ref(yaml, dir_path, ref_path, ref_name): if isinstance(yaml, dict): for k, v in yaml.items(): if isinstance(v, dict): @@ -47,34 +80,60 @@ def replace_ref(yaml, dir_path, ref_path, ref_src): if isinstance(v['$ref'], str): check_path = os.path.abspath(os.path.join(dir_path, v['$ref'])) if check_path == ref_path: - yaml[k] = ref_src + yaml[k] = {'$ref': ref_name} else: - replace_ref(v, dir_path, ref_path, ref_src) + replace_ref(v, dir_path, ref_path, ref_name) elif isinstance(v, list): for count, item in enumerate(v): if isinstance(item, dict) and len(item) == 1 and '$ref' in item.keys(): - v[count] = ref_src + check_path = os.path.abspath(os.path.join(dir_path, item['$ref'])) + if check_path == ref_path: + v[count] = {'$ref': ref_name} else: - replace_ref(v[count], dir_path, ref_path, ref_src) + replace_ref(v[count], dir_path, ref_path, ref_name) elif isinstance(yaml, list): for count, item in enumerate(yaml): if isinstance(item, dict) and len(item) == 1 and '$ref' in item.keys(): - yaml[count] = ref_src + yaml[count] = {'$ref': ref_name} else: - replace_ref(yaml[count], dir_path, ref_path, ref_src) - + replace_ref(yaml[count], dir_path, ref_path, ref_name) -def create_final_content(refs): +def create_final_content(refs, base_path): + components_schemas = {} while len(refs) > 1: old_refs = refs.copy() for replacer_filepath, replacer_data in old_refs.items(): if not have_refs(replacer_data): + ref_name_path = get_ref_name_path(base_path, replacer_filepath) + ref_name = get_ref_name(base_path, replacer_filepath) for filepath, data in refs.items(): - replace_ref(data, os.path.dirname(filepath), replacer_filepath, replacer_data) + replace_ref(data, os.path.dirname(filepath), replacer_filepath, ref_name_path) if len(refs) > 1: + components_schemas[ref_name] = replacer_data refs.pop(replacer_filepath) - return list(refs.values())[0] + result = list(refs.values())[0] + result.setdefault('components', {}) + result['components'].setdefault('schemas', components_schemas) + return result + +def remove_schema_prefix(s): + prefix = "#/components/schemas/" + if s.startswith(prefix): + s = s[len(prefix):] + return s + +def fix_views(yaml): + newyaml = yaml + for k, v in yaml['paths'].items(): + if isinstance(v, dict): + if len(v) == 1 and '$ref' in v.keys(): + name_schema = remove_schema_prefix(v['$ref']) + newyaml['paths'][k] = yaml['components']['schemas'][name_schema] + del newyaml['components']['schemas'][name_schema] + else: + newyaml[k] = v + return newyaml def main(): if len(sys.argv) < 3: @@ -91,9 +150,10 @@ def main(): # Step 3: Create final_content yaml.Dumper.ignore_aliases = lambda *args: True - final_content = create_final_content(refs) + final_content = create_final_content(refs, os.path.dirname(input_path)) + fixed = fix_views(final_content) with open(output_path, 'w', encoding='utf-8') as result_f: - yaml.dump(final_content, result_f, allow_unicode=True) + yaml.dump(fixed, result_f, allow_unicode=True) if __name__ == '__main__': diff --git a/src/http/ErrorV1.hpp b/src/http/ErrorV1.hpp new file mode 100644 index 00000000..d73246a0 --- /dev/null +++ b/src/http/ErrorV1.hpp @@ -0,0 +1,17 @@ +#pragma once +#include "../utils/convert/base.hpp" +#include "userver/server/http/http_status.hpp" + +namespace timetable_vsu_backend::http { +namespace convert = timetable_vsu_backend::utils::convert; +template +struct ErrorV1 { + static constexpr convert::TypeOfBody kTypeOfBody = + convert::TypeOfBody::Json; + static constexpr convert::PolicyFields kPolicyFields = + convert::PolicyFields::ConvertAll; + static constexpr userver::server::http::HttpStatus kStatusCode = code; + convert::Property description; + convert::Property machine_id; +}; +} // namespace timetable_vsu_backend::http \ No newline at end of file diff --git a/src/http/handler_parsed.hpp b/src/http/handler_parsed.hpp index 14309e1a..bea91421 100644 --- a/src/http/handler_parsed.hpp +++ b/src/http/handler_parsed.hpp @@ -8,10 +8,10 @@ #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" -#include "utils/convert/http_response_base.hpp" namespace timetable_vsu_backend::http { template diff --git a/src/models/lesson/type.hpp b/src/models/lesson/type.hpp new file mode 100644 index 00000000..f2f8ee57 --- /dev/null +++ b/src/models/lesson/type.hpp @@ -0,0 +1,15 @@ +#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/user_type/serialize.cpp b/src/models/user_type/serialize.cpp new file mode 100644 index 00000000..947e4088 --- /dev/null +++ b/src/models/user_type/serialize.cpp @@ -0,0 +1,26 @@ +#include "serialize.hpp" + +#include "userver/formats/json/value_builder.hpp" + +namespace timetable_vsu_backend::models { +std::string Serialize(const UserType& value, + userver::formats::serialize::To) { + switch (value) { + case UserType::kUser: + return "user"; + case UserType::kAdmin: + return "admin"; + case UserType::kRoot: + return "root"; + case UserType::kTeacher: + return "teacher"; + } +} +userver::formats::json::Value Serialize( + const UserType& 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 \ No newline at end of file diff --git a/src/models/user_type/serialize.hpp b/src/models/user_type/serialize.hpp new file mode 100644 index 00000000..661673cd --- /dev/null +++ b/src/models/user_type/serialize.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "type.hpp" +#include "userver/formats/json/value.hpp" + +namespace timetable_vsu_backend::models { +userver::formats::json::Value Serialize( + const UserType& value, + 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 diff --git a/src/views/login/Responses.hpp b/src/views/login/Responses.hpp index 4a928fcd..9aa3af54 100644 --- a/src/views/login/Responses.hpp +++ b/src/views/login/Responses.hpp @@ -2,6 +2,9 @@ #include #include +#include "http/ErrorV1.hpp" +#include "models/user_type/serialize.hpp" +#include "models/user_type/type.hpp" #include "utils/convert/base.hpp" #include "utils/convert/http_response_serialize.hpp" #include "utils/convert/json_parse.hpp" @@ -10,17 +13,14 @@ namespace timetable_vsu_backend::views::login { using namespace utils::convert; struct Response200 { Property id; + Property user_type; static constexpr TypeOfBody kTypeOfBody = TypeOfBody::Json; static constexpr PolicyFields kPolicyFields = PolicyFields::ConvertAll; static constexpr userver::server::http::HttpStatus kStatusCode = userver::server::http::HttpStatus::kOk; }; -struct Response401 { - static constexpr TypeOfBody kTypeOfBody = TypeOfBody::Empty; - static constexpr PolicyFields kPolicyFields = PolicyFields::ConvertAll; - static constexpr userver::server::http::HttpStatus kStatusCode = - userver::server::http::HttpStatus::kUnauthorized; -}; +using Response401 = + http::ErrorV1; struct Response500 { static constexpr TypeOfBody kTypeOfBody = TypeOfBody::Empty; static constexpr PolicyFields kPolicyFields = PolicyFields::ConvertAll; diff --git a/src/views/login/view.cpp b/src/views/login/view.cpp index aac576cb..1d4baaf7 100644 --- a/src/views/login/view.cpp +++ b/src/views/login/view.cpp @@ -20,6 +20,13 @@ namespace { class LoginHandler final : public http::HandlerParsed { + static Response401 PerformInvalidCredentials() { + Response401 resp; + resp.description = "Account not founded: login or password invalid"; + resp.machine_id = "INVALID_CREDENTIALS"; + return resp; + } + public: static constexpr std::string_view kName = "handler-login"; LoginHandler(const userver::components::ComponentConfig& config, @@ -33,7 +40,7 @@ class LoginHandler final Response Handle(Request&& request) const override { auto user = user_controller.GetByLogin(request.login()); if (!user || user->password != request.password()) { - return Response401{}; + return PerformInvalidCredentials(); } auto id = token_controller.CreateNew( user->id, userver::utils::datetime::Now() + std::chrono::hours(24)); @@ -43,7 +50,7 @@ class LoginHandler final boost::uuids::to_string(user->id.GetUnderlying())); return Response500{}; } - return Response200{*id}; + return Response200{{*id}, {user->user_type}}; } private: diff --git a/tests/login/test_login_basic.py b/tests/login/test_login_basic.py index 73ac4f54..2153c446 100644 --- a/tests/login/test_login_basic.py +++ b/tests/login/test_login_basic.py @@ -4,59 +4,43 @@ @pytest.mark.pgsql('db_1', files=['initial_data_auth.sql']) -async def test_login_endpoint(service_client): - response = await service_client.post( - '/login', - json={'login': 'test_user', 'password': 'password123'} - ) - assert response.status == 200 +async def test_login_successful(service_client): + credentials = {'login': 'some_nickname', 'password': 'some_password'} + response = await service_client.post('/login', json=credentials) + + assert response.status_code == 200 assert 'token' in response.json() - assert isinstance(response.json()['token'], str) + assert 'user_type' in response.json() + assert response.json()['user_type'] == 'user' @pytest.mark.pgsql('db_1', files=['initial_data_auth.sql']) -async def test_login_endpoint_success(service_client): - response = await service_client.post( - '/login', - json={'login': 'test_user', 'password': 'password123'} - ) - assert response.status == 200 - assert 'token' in response.json() - assert isinstance(response.json()['token'], str) +async def test_login_missing_credentials(service_client): + response = await service_client.post('/login', json={}) + assert response.status_code == 400 @pytest.mark.pgsql('db_1', files=['initial_data_auth.sql']) -async def test_login_endpoint_success(service_client): - response = await service_client.post( - '/login', - json={'login': 'test_user', 'password': 'password123'} - ) - assert response.status == 200 - assert 'token' in response.json() - assert isinstance(response.json()['token'], str) +async def test_login_invalid_credentials(service_client): + credentials = {'login': 'invalid_nickname', 'password': 'invalid_password'} + response = await service_client.post('/login', json=credentials) + assert response.status_code == 401 + assert 'description' in response.json() + assert 'machine_id' in response.json() -@pytest.mark.pgsql('db_1', files=['initial_data_auth.sql']) -async def test_login_endpoint_wrong_password(service_client): - response = await service_client.post( - '/login', - json={'login': 'test_user', 'password': 'wrong_password'} - ) - assert response.status == 401 +@pytest.mark.pgsql('db_1', files=['initial_data_auth.sql']) +async def test_login_missing_login(service_client): + credentials = {'password': 'some_password'} + response = await service_client.post('/login', json=credentials) -async def test_login_endpoint_missing_username(service_client): - response = await service_client.post( - '/login', - json={'password': 'password123'} - ) - assert response.status == 400 + assert response.status_code == 400 @pytest.mark.pgsql('db_1', files=['initial_data_auth.sql']) -async def test_login_endpoint_missing_password(service_client): - response = await service_client.post( - '/login', - json={'login': 'test_user'} - ) - assert response.status == 400 +async def test_login_missing_password(service_client): + credentials = {'login': 'some_nickname'} + response = await service_client.post('/login', json=credentials) + + assert response.status_code == 400 diff --git a/united_api.yaml b/united_api.yaml new file mode 100644 index 00000000..9ce06c9c --- /dev/null +++ b/united_api.yaml @@ -0,0 +1,719 @@ +components: + schemas: + TypesAuthTokenV1: + allOf: + - $ref: '#/components/schemas/TypesId' + description: Используется для аунтефикации пользователя. Передаем строго через + куки + TypesDay: + enum: + - Monday + - Tuesday + - Wednesday + - Thursday + - Friday + - Saturday + type: string + TypesEducationType: + enum: + - undergraduate + - magistracy + - magistracy + - specialty + type: string + TypesErrorV1: + properties: + description: + example: Password must have at least 10 symbols + type: string + machine_id: + example: SMALL_PASSWORD + type: string + TypesGroupV1: + properties: + course: + type: integer + name: + type: string + type: + $ref: '#/components/schemas/TypesEducationType' + TypesId: + description: UUID v4 + example: 6173575e-e86c-4c55-b43d-aa3ca6242181 + type: string + TypesLessonV1: + properties: + begin: + $ref: '#/components/schemas/TypesTimestamp' + end: + $ref: '#/components/schemas/TypesTimestamp' + group: + $ref: '#/components/schemas/TypesGroupV1' + group_id: + $ref: '#/components/schemas/TypesId' + room_id: + $ref: '#/components/schemas/TypesId' + room_name: + description: Номер аудитории + example: 405П + type: string + subgroup: + $ref: '#/components/schemas/TypesSubgroup' + subject_id: + $ref: '#/components/schemas/TypesId' + subject_name: + example: Дифференциальные уравнения + type: string + teacher_fio: + example: Иванов Иван Иванович + type: string + teacher_id: + example: some_id + type: string + type_lesson: + $ref: '#/components/schemas/TypesTypeOfLesson' + week: + $ref: '#/components/schemas/TypesTypeOfWeek' + TypesNumberLesson: + enum: + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + type: integer + TypesSubgroup: + description: 'Тип подгруппы: All - для обеих' + enum: + - All + - First + - Second + type: string + TypesTimestamp: + example: 2010-02-10-08.15.000Z + type: string + TypesTypeOfLesson: + description: Тип пары + enum: + - Labaratory + - Lection + - Practice + type: string + TypesTypeOfWeek: + description: 'Тип недели: All - всегда, Even - только по числителю, Odd - только + по знаменателю' + enum: + - All + - Even + - Odd + type: string + TypesUserCredentialV1: + properties: + login: + example: some_nickname + type: string + password: + example: some_password + type: string + required: + - login + - password + TypesUserTypeV1: + enum: + - user + - teacher + - admin + - root + type: string + ViewsAdminGroupAddRequest: + properties: + group_course: + example: 3 + type: integer + group_name: + example: '62' + type: string + group_type: + $ref: '#/components/schemas/TypesEducationType' + ViewsAdminGroupLessonAddRequest: + properties: + group_id: + $ref: '#/components/schemas/TypesId' + subject_id: + $ref: '#/components/schemas/TypesId' + ViewsAdminGroupLessonRemoveRequest: + properties: + group_id: + $ref: '#/components/schemas/TypesId' + subject_id: + $ref: '#/components/schemas/TypesId' + ViewsAdminGroupRemoveRequest: + properties: + group_id: + $ref: '#/components/schemas/TypesId' + ViewsAdminGroupTeacherAddRequest: + properties: + group_id: + $ref: '#/components/schemas/TypesId' + subject_id: + $ref: '#/components/schemas/TypesId' + teacher_id: + $ref: '#/components/schemas/TypesId' + ViewsAdminGroupTeacherRemoveRequest: + properties: + group_id: + $ref: '#/components/schemas/TypesId' + subject_id: + $ref: '#/components/schemas/TypesId' + teacher_id: + $ref: '#/components/schemas/TypesId' + ViewsAdminTeacherLinkRequest: + properties: + teacher_id: + $ref: '#/components/schemas/TypesId' + user_id: + $ref: '#/components/schemas/TypesId' + ViewsAdminTeacherUnlinkRequest: + properties: + teacher_id: + $ref: '#/components/schemas/TypesId' + user_id: + $ref: '#/components/schemas/TypesId' + ViewsGetTimetableRequest: + properties: + 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 + subgroup: + $ref: '#/components/schemas/TypesSubgroup' + subject_name: + type: string + teacher_fio: + type: string + teacher_id: + type: string + week: + $ref: '#/components/schemas/TypesTypeOfWeek' + ViewsLessonAddRequest: + properties: + end: + $ref: '#/components/schemas/TypesTimestamp' + number_lesson: + $ref: '#/components/schemas/TypesNumberLesson' + room_id: + $ref: '#/components/schemas/TypesId' + start: + $ref: '#/components/schemas/TypesTimestamp' + subject_id: + $ref: '#/components/schemas/TypesId' + ViewsLessonMoveRequest: + properties: + end: + $ref: '#/components/schemas/TypesTimestamp' + lesson_old_id: + $ref: '#/components/schemas/TypesId' + number_lesson: + $ref: '#/components/schemas/TypesNumberLesson' + room_id: + $ref: '#/components/schemas/TypesId' + start: + $ref: '#/components/schemas/TypesTimestamp' + subject_id: + $ref: '#/components/schemas/TypesId' + ViewsLessonRemoveRequest: + properties: + end: + $ref: '#/components/schemas/TypesTimestamp' + lesson_id: + $ref: '#/components/schemas/TypesId' + start: + $ref: '#/components/schemas/TypesTimestamp' + ViewsLoginResponseV1: + properties: + token: + $ref: '#/components/schemas/TypesAuthTokenV1' + user_type: + $ref: '#/components/schemas/TypesUserTypeV1' + ViewsRegisterRequestV1: + properties: + user_credential: + $ref: '#/components/schemas/TypesUserCredentialV1' + user_type: + $ref: '#/components/schemas/TypesUserTypeV1' +info: + description: This is a simple timetable API + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + title: Simple Timetable API + version: 1.0.0 +openapi: 3.0.0 +paths: + /admin/group/add: + post: + description: Создать группу + parameters: + - in: cookie + name: authToken + required: true + schema: + $ref: '#/components/schemas/TypesAuthTokenV1' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ViewsAdminGroupAddRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesGroupV1' + description: Группа успешно создана + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Отсутствует или истекший токен + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Нет прав на подобные изменения + tags: + - admins + /admin/group/lesson/add: + post: + description: Добавить пару группе + parameters: + - in: cookie + name: authToken + required: true + schema: + $ref: '#/components/schemas/TypesAuthTokenV1' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ViewsAdminGroupLessonAddRequest' + required: true + responses: + '200': + description: Предмет успешно добавлен в группу + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Отсутствует или истекший токен + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Нет прав на подобные изменения + tags: + - admins + /admin/group/lesson/remove: + post: + description: Убрать пару у группы + parameters: + - in: cookie + name: authToken + required: true + schema: + $ref: '#/components/schemas/TypesAuthTokenV1' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ViewsAdminGroupLessonRemoveRequest' + required: true + responses: + '200': + description: Предмет успешно удален из группы + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Отсутствует или истекший токен + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Нет прав на подобные изменения + tags: + - admins + /admin/group/remove: + post: + description: Удалить группу + parameters: + - in: cookie + name: authToken + required: true + schema: + $ref: '#/components/schemas/TypesAuthTokenV1' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ViewsAdminGroupRemoveRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesGroupV1' + description: Группа успешно удалена + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Отсутствует или истекший токен + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Нет прав на подобные изменения + tags: + - admins + /admin/group/teacher/add: + post: + description: Добавить преподавателя группе + parameters: + - in: cookie + name: authToken + required: true + schema: + $ref: '#/components/schemas/TypesAuthTokenV1' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ViewsAdminGroupTeacherAddRequest' + required: true + responses: + '200': + description: Преподаватель успешно добавлен в группу + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Отсутствует или истекший токен + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Нет прав на подобные изменения + tags: + - admins + /admin/group/teacher/remove: + post: + description: Убрать преподавателя из группы + parameters: + - in: cookie + name: authToken + required: true + schema: + $ref: '#/components/schemas/TypesAuthTokenV1' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ViewsAdminGroupTeacherRemoveRequest' + required: true + responses: + '200': + description: Преподаватель успешно удален из группы + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Отсутствует или истекший токен + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Нет прав на подобные изменения + tags: + - admins + /admin/teacher/link: + post: + description: Связать преподавателя с его аккаунтом + parameters: + - in: cookie + name: authToken + required: true + schema: + $ref: '#/components/schemas/TypesAuthTokenV1' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ViewsAdminTeacherLinkRequest' + required: true + responses: + '200': + description: Преподаватель успешно удален из группы + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Отсутствует или истекший токен + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Нет прав на подобные изменения + tags: + - admins + /admin/teacher/unlink: + post: + description: Отвязать аккаунт у преподавателя + parameters: + - in: cookie + name: authToken + required: true + schema: + $ref: '#/components/schemas/TypesAuthTokenV1' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ViewsAdminTeacherUnlinkRequest' + required: true + responses: + '200': + description: Аккаунт успешно отвязан от преподавателя + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Отсутствует или истекший токен + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Нет прав на подобные изменения + tags: + - admins + /get-timetable: + post: + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ViewsGetTimetableRequest' + required: true + responses: + '200': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/TypesLessonV1' + type: array + description: Найденные пары + tags: + - users + /lesson/add: + post: + parameters: + - in: cookie + name: authToken + required: true + schema: + $ref: '#/components/schemas/TypesAuthTokenV1' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ViewsLessonAddRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesLessonV1' + description: Пара успешно создана + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Отсутствует или истекший токен + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Нет прав на подобные изменения + tags: + - teachers + /lesson/move: + post: + parameters: + - in: cookie + name: authToken + required: true + schema: + $ref: '#/components/schemas/TypesAuthTokenV1' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ViewsLessonMoveRequest' + required: true + responses: + '200': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/TypesLessonV1' + type: array + description: Пара успешно перемещена + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Отсутствует или истекший токен + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Нет прав на подобные изменения + tags: + - teachers + /lesson/remove: + post: + parameters: + - in: cookie + name: authToken + required: true + schema: + $ref: '#/components/schemas/TypesAuthTokenV1' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ViewsLessonRemoveRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesLessonV1' + description: Пара успешно отменена + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Отсутствует или истекший токен + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Нет прав на подобные изменения + tags: + - teachers + /login: + post: + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TypesUserCredentialV1' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ViewsLoginResponseV1' + description: Авторизация прозошла успешно + '400': + description: Не переданы необходимые параметры + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Имя пользователя или пароль не верны + tags: + - users + /register: + post: + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ViewsRegisterRequestV1' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesAuthTokenV1' + description: Создан новый пользователь + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesErrorV1' + description: Логин уже занят или пароль не удолетворяет требованиям + tags: + - users +servers: +- description: SwaggerHub API Auto Mocking + url: https://virtserver.swaggerhub.com/SABUDILOVSKIY_1/CourseWork/1.0.0 +tags: +- description: Доступно администраторам сервиса + name: admins +- description: Доступны для преподавателей, которые ведут соответствующую группу и + соответствующий предмет + name: teachers +- description: Доступно всем + name: users