diff --git a/subprojects/sim/include/sim/sql/fields/datetime.hh b/subprojects/sim/include/sim/sql/fields/datetime.hh index 4cc6f0d2..6b945a8f 100644 --- a/subprojects/sim/include/sim/sql/fields/datetime.hh +++ b/subprojects/sim/include/sim/sql/fields/datetime.hh @@ -1,6 +1,6 @@ #pragma once -#include "varbinary.hh" +#include "binary.hh" #include #include @@ -11,7 +11,7 @@ namespace sim::sql::fields { // Format: YYYY-mm-dd HH:MM:SS -class Datetime : public Varbinary::length("YYYY-mm-dd HH:MM:SS")> { +class Datetime : public Binary::length("YYYY-mm-dd HH:MM:SS")> { public: Datetime() noexcept = default; Datetime(const Datetime&) = default; @@ -21,14 +21,14 @@ public: ~Datetime() = default; explicit Datetime(std::string str) - : Varbinary{[&]() -> decltype(auto) { + : Binary{[&]() -> decltype(auto) { throw_assert(is_datetime(str.c_str())); return std::move(str); }()} {} Datetime& operator=(std::string str) { throw_assert(is_datetime(str.c_str())); - Varbinary::operator=(std::move(str)); + Binary::operator=(std::move(str)); return *this; } diff --git a/subprojects/sim/include/sim/sql/fields/inf_datetime.hh b/subprojects/sim/include/sim/sql/fields/inf_datetime.hh index 2490132b..8a522431 100644 --- a/subprojects/sim/include/sim/sql/fields/inf_datetime.hh +++ b/subprojects/sim/include/sim/sql/fields/inf_datetime.hh @@ -1,6 +1,6 @@ #pragma once -#include "varbinary.hh" +#include "binary.hh" #include #include @@ -11,7 +11,7 @@ namespace sim::sql::fields { // Format: YYYY-mm-dd HH:MM:SS | # | @ -class InfDatetime : public Varbinary::length("YYYY-mm-dd HH:MM:SS")> { +class InfDatetime : public Binary::length("YYYY-mm-dd HH:MM:SS")> { static constexpr const auto NEG_INF_STR = std::string_view{"#"}; static constexpr const auto INF_STR = std::string_view{"@"}; @@ -24,14 +24,22 @@ public: ~InfDatetime() = default; explicit InfDatetime(std::string str) - : Varbinary{[&]() -> decltype(auto) { - throw_assert(is_datetime(str.c_str())); + : Binary{[&]() -> decltype(auto) { + // Database stores binary as bytes padded with '\0' at the end + while (!str.empty() && str.back() == '\0') { + str.pop_back(); + } + throw_assert(str == NEG_INF_STR || str == INF_STR || is_datetime(str.c_str())); return std::move(str); }()} {} InfDatetime& operator=(std::string str) { - throw_assert(is_datetime(str.c_str())); - Varbinary::operator=(std::move(str)); + // Database stores binary as bytes padded with '\0' at the end + while (!str.empty() && str.back() == '\0') { + str.pop_back(); + } + throw_assert(str == NEG_INF_STR || str == INF_STR || is_datetime(str.c_str())); + Binary::operator=(std::move(str)); return *this; } diff --git a/subprojects/sim/src/sim/db/schema.cc b/subprojects/sim/src/sim/db/schema.cc index 4225b5a7..86086e10 100644 --- a/subprojects/sim/src/sim/db/schema.cc +++ b/subprojects/sim/src/sim/db/schema.cc @@ -164,10 +164,10 @@ const DbSchema& get_schema() { " `contest_id` bigint(20) unsigned NOT NULL," " `name` varbinary(", decltype(ContestRound::name)::max_len, ") NOT NULL," " `item` bigint(20) unsigned NOT NULL," - " `begins` binary(", decltype(ContestRound::begins)::max_len, ") NOT NULL," - " `ends` binary(", decltype(ContestRound::ends)::max_len, ") NOT NULL," - " `full_results` binary(", decltype(ContestRound::full_results)::max_len, ") NOT NULL," - " `ranking_exposure` binary(", decltype(ContestRound::ranking_exposure)::max_len, ") NOT NULL," + " `begins` binary(", decltype(ContestRound::begins)::len, ") NOT NULL," + " `ends` binary(", decltype(ContestRound::ends)::len, ") NOT NULL," + " `full_results` binary(", decltype(ContestRound::full_results)::len, ") NOT NULL," + " `ranking_exposure` binary(", decltype(ContestRound::ranking_exposure)::len, ") NOT NULL," " PRIMARY KEY (`id`)," " UNIQUE KEY `contest_id_3` (`contest_id`,`item`)," " KEY `contest_id_2` (`contest_id`,`begins`)," diff --git a/subprojects/sim/src/web_server/capabilities/contest_entry_token.cc b/subprojects/sim/src/web_server/capabilities/contest_entry_token.cc index af301741..997fbbb0 100644 --- a/subprojects/sim/src/web_server/capabilities/contest_entry_token.cc +++ b/subprojects/sim/src/web_server/capabilities/contest_entry_token.cc @@ -16,8 +16,8 @@ ContestEntryToken contest_entry_token_for( const Contest& caps_contest, std::optional contest_user_mode ) noexcept { - bool is_contest_moderator = caps_contest.node.view and - (is_admin(session) or + bool is_contest_moderator = caps_contest.node.view && + (is_admin(session) || is_one_of(contest_user_mode, ContestUser::Mode::OWNER, ContestUser::Mode::MODERATOR)); switch (token_kind) { case ContestEntryTokenKind::NORMAL: diff --git a/subprojects/sim/src/web_server/capabilities/contests.cc b/subprojects/sim/src/web_server/capabilities/contests.cc index 607c1aa8..a29362fd 100644 --- a/subprojects/sim/src/web_server/capabilities/contests.cc +++ b/subprojects/sim/src/web_server/capabilities/contests.cc @@ -10,7 +10,7 @@ Contests contests_for(const decltype(web_worker::Context::session)& session) noe .web_ui_view = true, .view_all = is_admin(session), .view_public = true, - .add_private = is_admin(session) or is_teacher(session), + .add_private = is_admin(session) || is_teacher(session), .add_public = is_admin(session), }; } diff --git a/subprojects/sim/src/web_server/capabilities/problems.cc b/subprojects/sim/src/web_server/capabilities/problems.cc index 5e8a8bfc..20a833e1 100644 --- a/subprojects/sim/src/web_server/capabilities/problems.cc +++ b/subprojects/sim/src/web_server/capabilities/problems.cc @@ -14,38 +14,39 @@ namespace web_server::capabilities { ProblemsCapabilities problems(const decltype(Context::session)& session) noexcept { return { .web_ui_view = true, - .add_problem = is_admin(session) or is_teacher(session), - .add_problem_with_type_private = is_admin(session) or is_teacher(session), - .add_problem_with_type_contest_only = is_admin(session) or is_teacher(session), - .add_problem_with_type_public = is_admin(session), + .add_problem = is_admin(session) || is_teacher(session), + .add_problem_with_visibility_private = is_admin(session) || is_teacher(session), + .add_problem_with_visibility_contest_only = is_admin(session) || is_teacher(session), + .add_problem_with_visibility_public = is_admin(session), }; } ProblemsListCapabilities list_problems(const decltype(Context::session)& session) noexcept { return { .query_all = true, - .query_with_type_public = true, - .query_with_type_contest_only = is_admin(session) or is_teacher(session) or - (session and list_user_problems(session, session->user_id).query_with_type_contest_only + .query_with_visibility_public = true, + .query_with_visibility_contest_only = is_admin(session) || is_teacher(session) || + (session && + list_user_problems(session, session->user_id).query_with_visibility_contest_only), + .query_with_visibility_private = is_admin(session) || is_teacher(session) || + (session && list_user_problems(session, session->user_id).query_with_visibility_private ), - .query_with_type_private = is_admin(session) or is_teacher(session) or - (session and list_user_problems(session, session->user_id).query_with_type_private), - .view_all_with_type_public = true, - .view_all_with_type_contest_only = is_admin(session) or is_teacher(session), - .view_all_with_type_private = is_admin(session), + .view_all_with_visibility_public = true, + .view_all_with_visibility_contest_only = is_admin(session) || is_teacher(session), + .view_all_with_visibility_private = is_admin(session), }; } ProblemsListCapabilities list_user_problems(const decltype(Context::session)& session, decltype(User::id) user_id) noexcept { return { - .query_all = is_self(session, user_id) or is_admin(session), - .query_with_type_public = is_self(session, user_id) or is_admin(session), - .query_with_type_contest_only = is_self(session, user_id) or is_admin(session), - .query_with_type_private = is_self(session, user_id) or is_admin(session), - .view_all_with_type_public = is_self(session, user_id) or is_admin(session), - .view_all_with_type_contest_only = is_self(session, user_id) or is_admin(session), - .view_all_with_type_private = is_self(session, user_id) or is_admin(session), + .query_all = is_self(session, user_id) || is_admin(session), + .query_with_visibility_public = is_self(session, user_id) || is_admin(session), + .query_with_visibility_contest_only = is_self(session, user_id) || is_admin(session), + .query_with_visibility_private = is_self(session, user_id) || is_admin(session), + .view_all_with_visibility_public = is_self(session, user_id) || is_admin(session), + .view_all_with_visibility_contest_only = is_self(session, user_id) || is_admin(session), + .view_all_with_visibility_private = is_self(session, user_id) || is_admin(session), }; } @@ -54,35 +55,35 @@ ProblemCapabilities problem( decltype(Problem::visibility) problem_visibility, decltype(Problem::owner_id) problem_owner_id ) noexcept { - bool is_owned = problem_owner_id and is_self(session, *problem_owner_id); + bool is_owned = problem_owner_id && is_self(session, *problem_owner_id); bool is_public = problem_visibility == sim::problems::Problem::Visibility::PUBLIC; bool is_contest_only = problem_visibility == sim::problems::Problem::Visibility::CONTEST_ONLY; bool view = - is_public or is_owned or is_admin(session) or (is_teacher(session) and is_contest_only); + is_public || is_owned || is_admin(session) || (is_teacher(session) && is_contest_only); return { .view = view, .view_statement = view, .view_public_tags = view, - .view_hidden_tags = view and (is_admin(session) or is_teacher(session) or is_owned), - .view_solutions = is_admin(session) or is_owned or (is_teacher(session) and is_public), - .view_simfile = is_admin(session) or is_owned or - (is_teacher(session) and (is_public or is_contest_only)), - .view_owner = is_admin(session) or is_owned or - (is_teacher(session) and (is_public or is_contest_only)), - .view_creation_time = is_admin(session) or is_owned or - (is_teacher(session) and (is_public or is_contest_only)), - .view_update_time = is_admin(session) or is_owned or - (is_teacher(session) and (is_public or is_contest_only)), - .view_final_submission_full_status = view and session, - .download = is_admin(session) or is_owned or (is_teacher(session) and is_public), - .create_submission = view and session, - .edit = is_admin(session) or is_owned, - .reupload = is_admin(session) or is_owned, - .rejudge_all_submissions = is_admin(session) or is_owned, - .reset_time_limits = is_admin(session) or is_owned, - .delete_ = is_admin(session) or is_owned, - .merge_into_another_problem = is_admin(session) or is_owned, - .merge_other_problem_into_this_problem = is_admin(session) or is_owned, + .view_hidden_tags = view && (is_admin(session) || is_teacher(session) || is_owned), + .view_solutions = is_admin(session) || is_owned || (is_teacher(session) && is_public), + .view_simfile = is_admin(session) || is_owned || + (is_teacher(session) && (is_public || is_contest_only)), + .view_owner = is_admin(session) || is_owned || + (is_teacher(session) && (is_public || is_contest_only)), + .view_creation_time = is_admin(session) || is_owned || + (is_teacher(session) && (is_public || is_contest_only)), + .view_update_time = is_admin(session) || is_owned || + (is_teacher(session) && (is_public || is_contest_only)), + .view_final_submission_full_status = view && session, + .download = is_admin(session) || is_owned || (is_teacher(session) && is_public), + .create_submission = view && session, + .edit = is_admin(session) || is_owned, + .reupload = is_admin(session) || is_owned, + .rejudge_all_submissions = is_admin(session) || is_owned, + .reset_time_limits = is_admin(session) || is_owned, + .delete_ = is_admin(session) || is_owned, + .merge_into_another_problem = is_admin(session) || is_owned, + .merge_other_problem_into_this_problem = is_admin(session) || is_owned, }; } diff --git a/subprojects/sim/src/web_server/capabilities/problems.hh b/subprojects/sim/src/web_server/capabilities/problems.hh index 31c3f46f..4723b691 100644 --- a/subprojects/sim/src/web_server/capabilities/problems.hh +++ b/subprojects/sim/src/web_server/capabilities/problems.hh @@ -10,21 +10,21 @@ namespace web_server::capabilities { struct ProblemsCapabilities { bool web_ui_view : 1; bool add_problem : 1; - bool add_problem_with_type_private : 1; - bool add_problem_with_type_contest_only : 1; - bool add_problem_with_type_public : 1; + bool add_problem_with_visibility_private : 1; + bool add_problem_with_visibility_contest_only : 1; + bool add_problem_with_visibility_public : 1; }; ProblemsCapabilities problems(const decltype(web_worker::Context::session)& session) noexcept; struct ProblemsListCapabilities { bool query_all : 1; - bool query_with_type_public : 1; - bool query_with_type_contest_only : 1; - bool query_with_type_private : 1; - bool view_all_with_type_public : 1; - bool view_all_with_type_contest_only : 1; - bool view_all_with_type_private : 1; + bool query_with_visibility_public : 1; + bool query_with_visibility_contest_only : 1; + bool query_with_visibility_private : 1; + bool view_all_with_visibility_public : 1; + bool view_all_with_visibility_contest_only : 1; + bool view_all_with_visibility_private : 1; }; ProblemsListCapabilities list_problems(const decltype(web_worker::Context::session)& session diff --git a/subprojects/sim/src/web_server/capabilities/users.cc b/subprojects/sim/src/web_server/capabilities/users.cc index 9641b94f..e017e76e 100644 --- a/subprojects/sim/src/web_server/capabilities/users.cc +++ b/subprojects/sim/src/web_server/capabilities/users.cc @@ -12,7 +12,7 @@ UsersCapabilities users(const decltype(Context::session)& session) noexcept { return { .web_ui_view = is_admin(session), .add_user = is_admin(session), - .add_admin = session and session->user_id == sim::users::SIM_ROOT_ID, + .add_admin = session && session->user_id == sim::users::SIM_ROOT_ID, .add_teacher = is_admin(session), .add_normal_user = is_admin(session), .sign_in = true, @@ -42,29 +42,28 @@ UserCapabilities user( bool is_admin_ = is_admin(session); bool is_teacher_ = is_teacher(session); bool is_self_ = is_self(session, user_id); - bool edit = is_self_ or (is_admin_ and user_id != SIM_ROOT_ID); + bool edit = is_self_ || (is_admin_ && user_id != SIM_ROOT_ID); bool make_admin = - (session and session->user_id == SIM_ROOT_ID) or (edit and user_type == User::Type::ADMIN); + (session && session->user_id == SIM_ROOT_ID) || (edit && user_type == User::Type::ADMIN); bool make_teacher = - (user_id != SIM_ROOT_ID) and (is_admin_ or (edit and user_type == User::Type::TEACHER)); - bool make_normal = (user_id != SIM_ROOT_ID) and - (is_admin_ or (is_teacher_ and is_self_) or (edit and user_type == User::Type::NORMAL)); + (user_id != SIM_ROOT_ID) && (is_admin_ || (edit && user_type == User::Type::TEACHER)); + bool make_normal = (user_id != SIM_ROOT_ID) && + (is_admin_ || (is_teacher_ && is_self_) || (edit && user_type == User::Type::NORMAL)); return { - .view = is_self_ or is_admin_, + .view = is_self_ || is_admin_, .edit = edit, - .edit_username = is_self_ or (is_admin_ and user_id != SIM_ROOT_ID), - .edit_first_name = is_self_ or (is_admin_ and user_id != SIM_ROOT_ID), - .edit_last_name = is_self_ or (is_admin_ and user_id != SIM_ROOT_ID), - .edit_email = is_self_ or (is_admin_ and user_id != SIM_ROOT_ID), - .change_password = is_self_ or (is_admin_ and user_id != SIM_ROOT_ID), - .change_password_without_old_password = - not is_self_ and is_admin_ and user_id != SIM_ROOT_ID, - .change_type = make_admin or make_teacher or make_normal, + .edit_username = is_self_ || (is_admin_ && user_id != SIM_ROOT_ID), + .edit_first_name = is_self_ || (is_admin_ && user_id != SIM_ROOT_ID), + .edit_last_name = is_self_ || (is_admin_ && user_id != SIM_ROOT_ID), + .edit_email = is_self_ || (is_admin_ && user_id != SIM_ROOT_ID), + .change_password = is_self_ || (is_admin_ && user_id != SIM_ROOT_ID), + .change_password_without_old_password = not is_self_ && is_admin_ && user_id != SIM_ROOT_ID, + .change_type = make_admin || make_teacher || make_normal, .make_admin = make_admin, .make_teacher = make_teacher, .make_normal = make_normal, - .delete_ = user_id != SIM_ROOT_ID and (is_self_ or is_admin_), - .merge_into_another_user = user_id != SIM_ROOT_ID and is_admin_, + .delete_ = user_id != SIM_ROOT_ID && (is_self_ || is_admin_), + .merge_into_another_user = user_id != SIM_ROOT_ID && is_admin_, .merge_someone_into_this_user = user_id != SIM_ROOT_ID }; } diff --git a/subprojects/sim/src/web_server/capabilities/utils.hh b/subprojects/sim/src/web_server/capabilities/utils.hh index a69e0ec5..66eeec33 100644 --- a/subprojects/sim/src/web_server/capabilities/utils.hh +++ b/subprojects/sim/src/web_server/capabilities/utils.hh @@ -7,17 +7,17 @@ namespace web_server::capabilities { constexpr bool is_admin(const decltype(web_worker::Context::session)& session) noexcept { - return session and session->user_type == sim::users::User::Type::ADMIN; + return session && session->user_type == sim::users::User::Type::ADMIN; } constexpr bool is_teacher(const decltype(web_worker::Context::session)& session) noexcept { - return session and session->user_type == sim::users::User::Type::TEACHER; + return session && session->user_type == sim::users::User::Type::TEACHER; } constexpr bool is_self( const decltype(web_worker::Context::session)& session, decltype(sim::users::User::id) user_id ) noexcept { - return session and session->user_id == user_id; + return session && session->user_id == user_id; } } // namespace web_server::capabilities diff --git a/subprojects/sim/src/web_server/problems/api.cc b/subprojects/sim/src/web_server/problems/api.cc index a49fade4..71046e80 100644 --- a/subprojects/sim/src/web_server/problems/api.cc +++ b/subprojects/sim/src/web_server/problems/api.cc @@ -236,9 +236,9 @@ constexpr bool is_query_allowed( } // NOLINTNEXTLINE(bugprone-switch-missing-default-case) switch (*problem_visibility) { - case Problem::Visibility::PUBLIC: return caps.query_with_type_public; - case Problem::Visibility::CONTEST_ONLY: return caps.query_with_type_contest_only; - case Problem::Visibility::PRIVATE: return caps.query_with_type_private; + case Problem::Visibility::PUBLIC: return caps.query_with_visibility_public; + case Problem::Visibility::CONTEST_ONLY: return caps.query_with_visibility_contest_only; + case Problem::Visibility::PRIVATE: return caps.query_with_visibility_private; } THROW("unexpected problem visibility"); } @@ -247,7 +247,7 @@ Condition<> caps_to_condition( ProblemsListCapabilities caps, optional problem_visibility ) { optional> res; - if (caps.view_all_with_type_public and + if (caps.view_all_with_visibility_public and (!problem_visibility or problem_visibility == Problem::Visibility::PUBLIC)) { res = std::move(res) || @@ -255,7 +255,7 @@ Condition<> caps_to_condition( concat_tostr("p.visibility=", enum_to_underlying_type(Problem::Visibility::PUBLIC)) )}; } - if (caps.view_all_with_type_contest_only and + if (caps.view_all_with_visibility_contest_only and (!problem_visibility or problem_visibility == Problem::Visibility::CONTEST_ONLY)) { res = std::move(res) || @@ -263,7 +263,7 @@ Condition<> caps_to_condition( "p.visibility=", enum_to_underlying_type(Problem::Visibility::CONTEST_ONLY) ))}; } - if (caps.view_all_with_type_private and + if (caps.view_all_with_visibility_private and (!problem_visibility or problem_visibility == Problem::Visibility::PRIVATE)) { res = std::move(res) || @@ -629,9 +629,9 @@ http::Response add(web_worker::Context& ctx) { VALIDATE(ctx.request.form_fields, ctx.response_400, (visibility, params::visibility, REQUIRED_ENUM_CAPS( - (PRIVATE, caps.add_problem_with_type_private) - (CONTEST_ONLY, caps.add_problem_with_type_contest_only) - (PUBLIC, caps.add_problem_with_type_public) + (PRIVATE, caps.add_problem_with_visibility_private) + (CONTEST_ONLY, caps.add_problem_with_visibility_contest_only) + (PUBLIC, caps.add_problem_with_visibility_public) )) ); diff --git a/subprojects/sim/src/web_server/static/kit/scripts.js b/subprojects/sim/src/web_server/static/kit/scripts.js index 5b40413d..3946ad3a 100644 --- a/subprojects/sim/src/web_server/static/kit/scripts.js +++ b/subprojects/sim/src/web_server/static/kit/scripts.js @@ -119,7 +119,7 @@ function url_api_problem(problem_id) { return `/api/problem/${problem_id}`; } function url_api_problem_reupload(problem_id) { return `/api/problem/${problem_id}/reupload`; } function url_api_problems() { return '/api/problems'; } function url_api_problems_add() { return '/api/problems/add'; } -function url_api_problems_with_type(problem_visibility) { return `/api/problems/visibility=/${problem_visibility}`; } +function url_api_problems_with_visibility(problem_visibility) { return `/api/problems/visibility=/${problem_visibility}`; } function url_api_sign_in() { return '/api/sign_in'; } function url_api_sign_out() { return '/api/sign_out'; } function url_api_sign_up() { return '/api/sign_up'; } @@ -130,7 +130,7 @@ function url_api_user_delete(user_id) { return `/api/user/${user_id}/delete`; } function url_api_user_edit(user_id) { return `/api/user/${user_id}/edit`; } function url_api_user_merge_into_another(user_id) { return `/api/user/${user_id}/merge_into_another`; } function url_api_user_problems(user_id) { return `/api/user/${user_id}/problems`; } -function url_api_user_problems_with_type(user_id, problem_visibility) { return `/api/user/${user_id}/problems/visibility=/${problem_visibility}`; } +function url_api_user_problems_with_visibility(user_id, problem_visibility) { return `/api/user/${user_id}/problems/visibility=/${problem_visibility}`; } function url_api_users() { return '/api/users'; } function url_api_users_add() { return '/api/users/add'; } function url_api_users_with_type(user_type) { return `/api/users/type=/${user_type}`; } @@ -1857,13 +1857,13 @@ async function add_problem() { const view = new View(url_problems_add()); const form = new Form('Add problem', url_api_problems_add()); const type_select = form.append_select('visibility', 'Visibility'); - if (global_capabilities.problems.add_problem_with_type_private) { + if (global_capabilities.problems.add_problem_with_visibility_private) { type_select.append_option('private', 'Private', {selected: true}); } - if (global_capabilities.problems.add_problem_with_type_contest_only) { + if (global_capabilities.problems.add_problem_with_visibility_contest_only) { type_select.append_option('contest_only', 'Contest only'); } - if (global_capabilities.problems.add_problem_with_type_public) { + if (global_capabilities.problems.add_problem_with_visibility_public) { type_select.append_option('public', 'Public'); } append_common_form_elems_for_add_problem_and_reupload_problem(form); @@ -2002,21 +2002,21 @@ function list_problems() { if (list_capabilities.query_all) { tabmenu.add_tab('All', retab.bind(null, url_all_func(), list_capabilities)); } - if (list_capabilities.query_with_type_public) { + if (list_capabilities.query_with_visibility_public) { tabmenu.add_tab('Public', retab.bind(null, url_by_type_func('public'), list_capabilities)); } - if (list_capabilities.query_with_type_contest_only) { + if (list_capabilities.query_with_visibility_contest_only) { tabmenu.add_tab('Contest only', retab.bind(null, url_by_type_func('contest_only'), list_capabilities)); } - if (list_capabilities.query_with_type_private) { + if (list_capabilities.query_with_visibility_private) { tabmenu.add_tab('Private', retab.bind(null, url_by_type_func('private'), list_capabilities)); } tabmenu.build_and_append_to(elem); }; const can_list_something = (list_capabilities) => { - return list_capabilities.query_all || list_capabilities.query_with_type_public || - list_capabilities.query_with_type_contest_only || list_capabilities.query_with_type_private; + return list_capabilities.query_all || list_capabilities.query_with_visibility_public || + list_capabilities.query_with_visibility_contest_only || list_capabilities.query_with_visibility_private; }; const tabmenu = new TabMenuBuilder(); @@ -2024,7 +2024,7 @@ function list_problems() { tabmenu.add_tab('All problems', retab.bind( null, url_api_problems, - url_api_problems_with_type, + url_api_problems_with_visibility, global_capabilities.problems.list_all, { show_owner_column: window.signed_user_type == 'admin' || window.signed_user_type == 'teacher', @@ -2036,7 +2036,7 @@ function list_problems() { tabmenu.add_tab('My problems', retab.bind( null, url_api_user_problems.bind(null, signed_user_id), - url_api_user_problems_with_type.bind(null, signed_user_id), + url_api_user_problems_with_visibility.bind(null, signed_user_id), global_capabilities.problems.list_my, { show_owner_column: false, diff --git a/subprojects/sim/src/web_server/ui_template.cc b/subprojects/sim/src/web_server/ui_template.cc index ae4fb730..1d850e12 100644 --- a/subprojects/sim/src/web_server/ui_template.cc +++ b/subprojects/sim/src/web_server/ui_template.cc @@ -115,15 +115,22 @@ std::string sim_template_params(const decltype(web_worker::Context::session)& se const auto caps = capabilities::problems(session); obj.prop("ui_view", caps.web_ui_view); obj.prop("add_problem", caps.add_problem); - obj.prop("add_problem_with_type_private", caps.add_problem_with_type_private); - obj.prop("add_problem_with_type_contest_only", caps.add_problem_with_type_contest_only); - obj.prop("add_problem_with_type_public", caps.add_problem_with_type_public); + obj.prop( + "add_problem_with_visibility_private", caps.add_problem_with_visibility_private + ); + obj.prop( + "add_problem_with_visibility_contest_only", + caps.add_problem_with_visibility_contest_only + ); + obj.prop("add_problem_with_visibility_public", caps.add_problem_with_visibility_public); auto fill_with_list_caps = [&](auto& obj, const capabilities::ProblemsListCapabilities caps) { obj.prop("query_all", caps.query_all); - obj.prop("query_with_type_public", caps.query_with_type_public); - obj.prop("query_with_type_contest_only", caps.query_with_type_contest_only); - obj.prop("query_with_type_private", caps.query_with_type_private); + obj.prop("query_with_visibility_public", caps.query_with_visibility_public); + obj.prop( + "query_with_visibility_contest_only", caps.query_with_visibility_contest_only + ); + obj.prop("query_with_visibility_private", caps.query_with_visibility_private); }; obj.prop_obj("list_all", [&](auto& obj) { fill_with_list_caps(obj, capabilities::list_problems(session)); diff --git a/subprojects/sim/src/web_server/web_worker/context.cc b/subprojects/sim/src/web_server/web_worker/context.cc index 01d97a4b..79484630 100644 --- a/subprojects/sim/src/web_server/web_worker/context.cc +++ b/subprojects/sim/src/web_server/web_worker/context.cc @@ -188,7 +188,7 @@ Response Context::response_403(StringView content, StringView content_type) { ); } case UT::TEACHER: - case UT::NORMAL: break; + case UT::NORMAL: return response_404(); } std::terminate(); } diff --git a/subprojects/sip/templates/sim-statement.cls b/subprojects/sip/templates/sim-statement.cls index 6a64d6bc..2e2e8646 100644 --- a/subprojects/sip/templates/sim-statement.cls +++ b/subprojects/sip/templates/sim-statement.cls @@ -115,38 +115,38 @@ \sip_statement_readcell:n { #1 } % #1 is the file to read } % appends second token list to the first token list -\cs_new_protected:Npn \sip_append_tl:NN #1 #2 +\cs_new_protected:Npn \sip_append_str:Nn #1 #2 { - \tl_map_inline:Nn #2 + \str_map_inline:Nn {#2} { - \tl_put_right:Nn #1 {##1} + % append current character do the #1 token list. \verb ensures the character will not be + % interpreted in the tabularx environment, ';' is a delimiter for \verb command to interpret the ##1 appropriately. Files may contain ';' - it works. + \tl_put_right:Nn #1 {\verb;##1;} } } -% some variables +% some local variables \tl_new:N \l__sip_statement_cell_content_tl \tl_new:N \l__sip_statement_newlines_accumulator_tl \ior_new:N \g_sip_statement_import_stream % proper implementation \cs_new_protected:Npn \sip_statement_readcell:n #1 { - % clear the variable containing the cell contents - \tl_clear:N \l__sip_statement_cell_content_tl % start reading the file \ior_open:Nn \g_sip_statement_import_stream { #1 } % at each line ... \ior_str_map_inline:Nn \g_sip_statement_import_stream { - % if the line is empty - \tl_if_eq:nnTF {##1} {\par } + % if the line is empty (this is a trick to skip trailing newlines) + \tl_if_eq:nnTF {##1} {} { % add newline to newlines accumulator \tl_put_right:Nn \l__sip_statement_newlines_accumulator_tl {\linebreak} } { % append newlines accumulator to cell_content - \sip_append_tl:NN \l__sip_statement_cell_content_tl \l__sip_statement_newlines_accumulator_tl - % add the current line to cell_content (\verb;; prevents stripping leading spaces) - \tl_put_right:Nn \l__sip_statement_cell_content_tl {\verb;;##1} + \tl_concat:NNN \l__sip_statement_cell_content_tl \l__sip_statement_cell_content_tl \l__sip_statement_newlines_accumulator_tl + % add the current line to cell_content + \sip_append_str:Nn \l__sip_statement_cell_content_tl {##1} % set the newlines accumulator to single newline \tl_set:Nn \l__sip_statement_newlines_accumulator_tl {\linebreak} }