Рефакторинг обработчиков. Часть 3 #21
This commit is contained in:
@@ -1,277 +1,302 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @doc Централизованный модуль для запуска API-тестов.
|
||||
%%% Предоставляет функции для выполнения HTTP-запросов
|
||||
%%% к административному и клиентскому API с автоматическим
|
||||
%%% логированием, проверкой статусов и конфигурацией
|
||||
%%% через стандартные переменные окружения.
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(api_test_runner).
|
||||
-export([run_all/0, run/1]).
|
||||
-export([http_post/2, http_post/3, http_get/1, http_get/2, http_put/3, http_delete/2]).
|
||||
-export([extract_json/2, extract_json/3, assert_status/2]).
|
||||
-export([unique_email/1, register_and_login/2, create_calendar/2, create_event/3]).
|
||||
-export([get_admin_token/0, get_admin_id/0, get_user_token/0, get_user_id/0, get_admin_url/0, get_base_url/0, get_admin_ws_url/0, get_base_ws_url/0, login_admin/2, login_custom_admin/2]).
|
||||
-export([wait_for_server/0]).
|
||||
-export([format_datetime/1]).
|
||||
|
||||
-define(BASE_URL, base_url()).
|
||||
-define(ADMIN_URL, admin_base_url()).
|
||||
-export([
|
||||
get_admin_url/0,
|
||||
get_base_url/0,
|
||||
get_base_ws_url/0,
|
||||
get_admin_ws_url/0,
|
||||
get_admin_token/0,
|
||||
get_superadmin_token/0,
|
||||
get_moderator_token/0,
|
||||
get_support_token/0,
|
||||
get_user_token/0,
|
||||
unique_email/1,
|
||||
future_date/0,
|
||||
register_and_login/2,
|
||||
create_calendar/2,
|
||||
create_event/3
|
||||
]).
|
||||
-export([
|
||||
admin_request/3,
|
||||
admin_request/4,
|
||||
client_request/3,
|
||||
client_request/4
|
||||
]).
|
||||
-export([
|
||||
admin_get/2,
|
||||
admin_post/3,
|
||||
admin_put/3,
|
||||
admin_delete/2,
|
||||
client_get/2,
|
||||
client_post/3,
|
||||
client_put/3,
|
||||
client_delete/2,
|
||||
admin_patch/3]).
|
||||
|
||||
%% Учётные данные по умолчанию (используются в локальном режиме, если словарь пуст)
|
||||
-define(FALLBACK_ADMIN_EMAIL, <<"admin@eventhub.local">>).
|
||||
-define(FALLBACK_ADMIN_PASSWORD, <<"123456">>).
|
||||
-define(USER_EMAIL, <<"global_user@test.com">>).
|
||||
-define(USER_PASSWORD, <<"user123">>).
|
||||
%%%===================================================================
|
||||
%%% Конфигурация окружения (CT_MODE, ...)
|
||||
%%%===================================================================
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Выбор базовых URL в зависимости от режима запуска
|
||||
%% ------------------------------------------------------------------
|
||||
base_url() ->
|
||||
case os:getenv("CT_MODE", "local") of
|
||||
-spec ct_mode() -> string().
|
||||
ct_mode() ->
|
||||
os:getenv("CT_MODE", "local").
|
||||
|
||||
-spec get_base_url() -> string().
|
||||
get_base_url() ->
|
||||
case ct_mode() of
|
||||
"remote" -> os:getenv("API_HOST", "http://localhost:8080");
|
||||
_ -> "http://localhost:8080"
|
||||
end.
|
||||
|
||||
base_ws_url() ->
|
||||
case os:getenv("CT_MODE", "local") of
|
||||
"remote" -> os:getenv("WS_HOST", "ws://localhost:8081");
|
||||
_ -> "ws://localhost:8081"
|
||||
end.
|
||||
|
||||
admin_base_url() ->
|
||||
case os:getenv("CT_MODE", "local") of
|
||||
-spec get_admin_url() -> string().
|
||||
get_admin_url() ->
|
||||
case ct_mode() of
|
||||
"remote" -> os:getenv("ADMIN_API_HOST", "http://localhost:8445");
|
||||
_ -> "http://localhost:8445"
|
||||
end.
|
||||
|
||||
admin_ws_url() ->
|
||||
case os:getenv("CT_MODE", "local") of
|
||||
-spec get_base_ws_url() -> string().
|
||||
get_base_ws_url() ->
|
||||
case ct_mode() of
|
||||
"remote" -> os:getenv("WS_HOST", "ws://localhost:8081");
|
||||
_ -> "ws://localhost:8081"
|
||||
end.
|
||||
|
||||
-spec get_admin_ws_url() -> string().
|
||||
get_admin_ws_url() ->
|
||||
case ct_mode() of
|
||||
"remote" -> os:getenv("ADMIN_WS_HOST", "ws://localhost:8446");
|
||||
_ -> "ws://localhost:8446"
|
||||
end.
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Инициализация глобальных тестовых пользователей
|
||||
%% ------------------------------------------------------------------
|
||||
init_global_urls() ->
|
||||
put(admin_url, admin_base_url()),
|
||||
put(admin_ws_url, admin_ws_url()),
|
||||
put(base_url, base_url()),
|
||||
put(base_ws_url, base_ws_url()).
|
||||
%%%===================================================================
|
||||
%%% Учётные данные администраторов (из переменных окружения)
|
||||
%%%===================================================================
|
||||
|
||||
init_global_users() ->
|
||||
case get(admin_token) of
|
||||
undefined ->
|
||||
ct:pal("~n=== Initializing global test users ===~n"),
|
||||
-spec admin_super_email() -> binary().
|
||||
admin_super_email() ->
|
||||
list_to_binary(os:getenv("ADMIN_SUPER_EMAIL", "superadmin@eventhub.local")).
|
||||
|
||||
%% 1. Администратор
|
||||
AdminEmail = get(admin_super_email),
|
||||
AdminPassword = get(admin_super_password),
|
||||
AdminToken =
|
||||
if
|
||||
AdminEmail =/= undefined, AdminPassword =/= undefined ->
|
||||
%% Учётные данные переданы из api_SUITE (remote‑режим) – просто логинимся
|
||||
login_admin(AdminEmail, AdminPassword);
|
||||
true ->
|
||||
%% Локальный режим: админы уже есть, логинимся под суперадмином
|
||||
login_admin(?FALLBACK_ADMIN_EMAIL, ?FALLBACK_ADMIN_PASSWORD)
|
||||
end,
|
||||
-spec admin_super_password() -> binary().
|
||||
admin_super_password() ->
|
||||
list_to_binary(os:getenv("ADMIN_SUPER_PASSWORD", "123456")).
|
||||
|
||||
%% Получаем ID администратора через /v1/admin/me
|
||||
MeUrl = ?ADMIN_URL ++ "/v1/admin/me",
|
||||
{ok, {{_, 200, _}, _, MeBody}} = httpc:request(get,
|
||||
{MeUrl, [{"Authorization", "Bearer " ++ binary_to_list(AdminToken)}]}, ssl_opts(), []),
|
||||
#{<<"id">> := AdminId} = jsx:decode(list_to_binary(MeBody), [return_maps]),
|
||||
-spec admin_email() -> binary().
|
||||
admin_email() ->
|
||||
list_to_binary(os:getenv("ADMIN_EMAIL", "admin@eventhub.local")).
|
||||
|
||||
put(admin_token, AdminToken),
|
||||
put(admin_id, AdminId),
|
||||
-spec admin_password() -> binary().
|
||||
admin_password() ->
|
||||
list_to_binary(os:getenv("ADMIN_PASSWORD", "123456")).
|
||||
|
||||
%% 2. Обычный пользователь
|
||||
UserToken = register_and_login(?USER_EMAIL, ?USER_PASSWORD),
|
||||
{ok, {{_, 200, _}, _, UserMeBody}} = http_get("/v1/user/me", UserToken),
|
||||
#{<<"id">> := UserId} = jsx:decode(list_to_binary(UserMeBody), [return_maps]),
|
||||
-spec admin_moder_email() -> binary().
|
||||
admin_moder_email() ->
|
||||
list_to_binary(os:getenv("ADMIN_MODER_EMAIL", "moderator@eventhub.local")).
|
||||
|
||||
put(user_token, UserToken),
|
||||
put(user_id, UserId),
|
||||
-spec admin_moder_password() -> binary().
|
||||
admin_moder_password() ->
|
||||
list_to_binary(os:getenv("ADMIN_MODER_PASSWORD", "123456")).
|
||||
|
||||
ct:pal("Admin ID: ~s, User ID: ~s~n", [AdminId, UserId]),
|
||||
ct:pal("=== Global users initialized ===~n~n"),
|
||||
ok;
|
||||
-spec admin_support_email() -> binary().
|
||||
admin_support_email() ->
|
||||
list_to_binary(os:getenv("ADMIN_SUPPORT_EMAIL", "support@eventhub.local")).
|
||||
|
||||
-spec admin_support_password() -> binary().
|
||||
admin_support_password() ->
|
||||
list_to_binary(os:getenv("ADMIN_SUPPORT_PASSWORD", "123456")).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Получение токенов (с кешированием в persistent_term)
|
||||
%%%===================================================================
|
||||
|
||||
-spec get_admin_token() -> binary().
|
||||
get_admin_token() ->
|
||||
get_or_login(admin, admin_email(), admin_password()).
|
||||
|
||||
-spec get_superadmin_token() -> binary().
|
||||
get_superadmin_token() ->
|
||||
get_or_login(superadmin, admin_super_email(), admin_super_password()).
|
||||
|
||||
-spec get_moderator_token() -> binary().
|
||||
get_moderator_token() ->
|
||||
get_or_login(moderator, admin_moder_email(), admin_moder_password()).
|
||||
|
||||
-spec get_support_token() -> binary().
|
||||
get_support_token() ->
|
||||
get_or_login(support, admin_support_email(), admin_support_password()).
|
||||
|
||||
-spec get_or_login(atom(), binary(), binary()) -> binary().
|
||||
get_or_login(Role, Email, Password) ->
|
||||
Key = {?MODULE, admin_token, Role},
|
||||
case persistent_term:get(Key, undefined) of
|
||||
Token when is_binary(Token) -> Token;
|
||||
_ ->
|
||||
ct:pal("Global users already initialized.~n"),
|
||||
ok
|
||||
Token = login_admin(Email, Password),
|
||||
persistent_term:put(Key, Token),
|
||||
timer:apply_after(5 * 60 * 1000, fun() -> persistent_term:erase(Key) end),
|
||||
Token
|
||||
end.
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Вход администратора (используется, когда учётки уже известны)
|
||||
%% ------------------------------------------------------------------
|
||||
login_admin(Email, Password) ->
|
||||
ct:pal("Admin url: ~s~n", [?ADMIN_URL]),
|
||||
ct:pal("Admin: ~s, password: ~s~n", [Email, Password]),
|
||||
LoginBody = jsx:encode(#{<<"email">> => Email, <<"password">> => Password}),
|
||||
ct:pal("url: ~s, body: ~s~n", [?ADMIN_URL ++ "/v1/admin/login", LoginBody]),
|
||||
{ok, {{_, _, _}, _, LoginResp}} = httpc:request(post,
|
||||
{?ADMIN_URL ++ "/v1/admin/login", [], "application/json", LoginBody}, ssl_opts(), []),
|
||||
ct:pal("LoginResp: ~s~n", [LoginResp]),
|
||||
#{<<"token">> := Token} = jsx:decode(list_to_binary(LoginResp), [return_maps]),
|
||||
%% @doc Возвращает JWT-токен обычного пользователя.
|
||||
%% При каждом вызове создаёт нового уникального пользователя,
|
||||
%% чтобы избежать конфликтов состояния в тестах.
|
||||
-spec get_user_token() -> binary().
|
||||
get_user_token() ->
|
||||
Email = unique_email(<<"testuser">>),
|
||||
register_and_login(Email, <<"testpass">>).
|
||||
|
||||
%%%===================================================================
|
||||
%%% HTTP-клиент (логирование, заголовки)
|
||||
%%%===================================================================
|
||||
|
||||
-spec admin_request(atom(), binary(), binary()) -> {ok, integer(), proplists:proplist(), binary()} | {error, term()}.
|
||||
admin_request(Method, Path, Token) ->
|
||||
admin_request(Method, Path, Token, <<>>).
|
||||
|
||||
-spec admin_request(atom(), binary(), binary(), binary()) -> {ok, integer(), proplists:proplist(), binary()} | {error, term()}.
|
||||
admin_request(Method, Path, Token, Body) ->
|
||||
request(get_admin_url(), Method, Path, Token, Body, "ADMIN").
|
||||
|
||||
-spec client_request(atom(), binary(), binary()) -> {ok, integer(), proplists:proplist(), binary()} | {error, term()}.
|
||||
client_request(Method, Path, Token) ->
|
||||
client_request(Method, Path, Token, <<>>).
|
||||
|
||||
-spec client_request(atom(), binary(), binary(), binary()) -> {ok, integer(), proplists:proplist(), binary()} | {error, term()}.
|
||||
client_request(Method, Path, Token, Body) ->
|
||||
request(get_base_url(), Method, Path, Token, Body, "CLIENT").
|
||||
|
||||
%%%===================================================================
|
||||
%%% Внутренняя реализация HTTP-запроса
|
||||
%%%===================================================================
|
||||
|
||||
-spec request(string(), atom(), binary(), binary(), binary(), string()) -> {ok, integer(), proplists:proplist(), binary()} | {error, term()}.
|
||||
request(BaseUrl, Method, Path, Token, Body, Prefix) ->
|
||||
URL = BaseUrl ++ binary_to_list(Path),
|
||||
Headers0 = [],
|
||||
Headers = case Token of
|
||||
<<>> -> Headers0; % пустой токен – не добавляем Authorization
|
||||
_ -> [{"Authorization", "Bearer " ++ binary_to_list(Token)}]
|
||||
end,
|
||||
ct:pal("~s REQUEST: ~s ~s", [Prefix, Method, URL]),
|
||||
RequestArg = case Method of
|
||||
get -> {URL, Headers};
|
||||
delete -> {URL, Headers};
|
||||
_ -> {URL, Headers, "application/json", Body}
|
||||
end,
|
||||
Response = httpc:request(Method, RequestArg, [], []),
|
||||
case Response of
|
||||
{ok, {{_, Status, _}, RespHeaders, RespBody}} ->
|
||||
ct:pal("~s RESPONSE: ~p ~s", [Prefix, Status, RespBody]),
|
||||
{ok, Status, RespHeaders, RespBody};
|
||||
_ ->
|
||||
ct:pal("~s REQUEST ERROR: ~p", [Prefix, Response]),
|
||||
{error, Response}
|
||||
end.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Высокоуровневые обёртки (GET/POST/PUT/DELETE)
|
||||
%%%===================================================================
|
||||
|
||||
-spec admin_get(binary(), binary()) -> jsx:json_term().
|
||||
admin_get(Path, Token) ->
|
||||
{ok, 200, _, Body} = admin_request(get, Path, Token),
|
||||
jsx:decode(list_to_binary(Body), [return_maps]).
|
||||
|
||||
-spec admin_post(binary(), binary(), map()) -> jsx:json_term().
|
||||
admin_post(Path, Token, BodyMap) ->
|
||||
Body = jsx:encode(BodyMap),
|
||||
{ok, 201, _, RespBody} = admin_request(post, Path, Token, Body),
|
||||
jsx:decode(list_to_binary(RespBody), [return_maps]).
|
||||
|
||||
-spec admin_put(binary(), binary(), map()) -> jsx:json_term().
|
||||
admin_put(Path, Token, BodyMap) ->
|
||||
Body = jsx:encode(BodyMap),
|
||||
{ok, 200, _, RespBody} = admin_request(put, Path, Token, Body),
|
||||
jsx:decode(list_to_binary(RespBody), [return_maps]).
|
||||
|
||||
%% В api_test_runner.erl добавить в блок высокоуровневых обёрток:
|
||||
-spec admin_patch(binary(), binary(), [map()]) -> jsx:json_term().
|
||||
admin_patch(Path, Token, BodyList) ->
|
||||
Body = jsx:encode(BodyList),
|
||||
{ok, 200, _, RespBody} = admin_request(patch, Path, Token, Body),
|
||||
jsx:decode(list_to_binary(RespBody), [return_maps]).
|
||||
|
||||
-spec admin_delete(binary(), binary()) -> jsx:json_term().
|
||||
admin_delete(Path, Token) ->
|
||||
{ok, 200, _, Body} = admin_request(delete, Path, Token),
|
||||
jsx:decode(list_to_binary(Body), [return_maps]).
|
||||
|
||||
-spec client_get(binary(), binary()) -> jsx:json_term().
|
||||
client_get(Path, Token) ->
|
||||
{ok, 200, _, Body} = client_request(get, Path, Token),
|
||||
jsx:decode(list_to_binary(Body), [return_maps]).
|
||||
|
||||
-spec client_post(binary(), binary(), map()) -> jsx:json_term().
|
||||
client_post(Path, Token, BodyMap) ->
|
||||
Body = jsx:encode(BodyMap),
|
||||
{ok, 201, _, RespBody} = client_request(post, Path, Token, Body),
|
||||
jsx:decode(list_to_binary(RespBody), [return_maps]).
|
||||
|
||||
-spec client_put(binary(), binary(), map()) -> jsx:json_term().
|
||||
client_put(Path, Token, BodyMap) ->
|
||||
Body = jsx:encode(BodyMap),
|
||||
{ok, 200, _, RespBody} = client_request(put, Path, Token, Body),
|
||||
jsx:decode(list_to_binary(RespBody), [return_maps]).
|
||||
|
||||
-spec client_delete(binary(), binary()) -> jsx:json_term().
|
||||
client_delete(Path, Token) ->
|
||||
{ok, 200, _, Body} = client_request(delete, Path, Token),
|
||||
jsx:decode(list_to_binary(Body), [return_maps]).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Фикстуры (создание тестовых данных)
|
||||
%%%===================================================================
|
||||
|
||||
-spec unique_email(binary()) -> binary().
|
||||
unique_email(Prefix) ->
|
||||
Unique = integer_to_binary(erlang:system_time()),
|
||||
<<Prefix/binary, "_", Unique/binary, "@test.local">>.
|
||||
|
||||
-spec future_date() -> calendar:datetime().
|
||||
future_date() ->
|
||||
Seconds = calendar:datetime_to_gregorian_seconds(calendar:universal_time()) + 86400,
|
||||
calendar:gregorian_seconds_to_datetime(Seconds).
|
||||
|
||||
-spec register_and_login(binary(), binary()) -> binary().
|
||||
register_and_login(Email, Password) ->
|
||||
Resp = client_request(post, <<"/v1/register">>, <<>>,
|
||||
jsx:encode(#{email => Email, password => Password})),
|
||||
{ok, 201, _, Body} = Resp,
|
||||
#{<<"token">> := Token} = jsx:decode(list_to_binary(Body), [return_maps]),
|
||||
Token.
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Остальные функции (без изменений, только используют ?BASE_URL / ?ADMIN_URL)
|
||||
%% ------------------------------------------------------------------
|
||||
get_admin_url() ->
|
||||
init_global_urls(),
|
||||
get(admin_url).
|
||||
|
||||
get_admin_ws_url() ->
|
||||
init_global_urls(),
|
||||
get(admin_ws_url).
|
||||
|
||||
get_base_url() ->
|
||||
init_global_urls(),
|
||||
get(base_url).
|
||||
|
||||
get_base_ws_url() ->
|
||||
init_global_urls(),
|
||||
get(base_ws_url).
|
||||
|
||||
get_admin_token() ->
|
||||
init_global_users(),
|
||||
get(admin_token).
|
||||
|
||||
get_admin_id() ->
|
||||
init_global_users(),
|
||||
get(admin_id).
|
||||
|
||||
get_user_token() ->
|
||||
init_global_users(),
|
||||
get(user_token).
|
||||
|
||||
get_user_id() ->
|
||||
init_global_users(),
|
||||
get(user_id).
|
||||
|
||||
run_all() ->
|
||||
inets:start(),
|
||||
ssl:start(),
|
||||
|
||||
case wait_for_server() of
|
||||
ok -> ok;
|
||||
{error, _} -> ct:pal("❌ Server is not running!~n"), exit(server_not_running)
|
||||
end,
|
||||
|
||||
init_global_users(),
|
||||
|
||||
ct:pal("Starting API tests...~n"),
|
||||
Modules = [
|
||||
api_auth_tests,
|
||||
api_calendar_tests,
|
||||
api_event_tests,
|
||||
api_booking_tests,
|
||||
api_search_tests,
|
||||
api_reviews_tests,
|
||||
api_moderation_tests,
|
||||
api_tickets_tests,
|
||||
api_subscription_tests,
|
||||
api_admin_tests
|
||||
],
|
||||
lists:foreach(fun(M) -> M:test() end, Modules).
|
||||
|
||||
run(Module) ->
|
||||
inets:start(),
|
||||
ssl:start(),
|
||||
init_global_users(),
|
||||
Module:test().
|
||||
|
||||
%% ── HTTP‑запросы ─────────────────────────────────────────
|
||||
ssl_opts() ->
|
||||
[{ssl, [{verify, verify_none}]}].
|
||||
|
||||
http_post(Url, Body) -> http_post(Url, Body, undefined).
|
||||
http_post(Url, Body, Token) ->
|
||||
Headers = case Token of
|
||||
undefined -> [{"Content-Type", "application/json"}];
|
||||
_ -> [{"Content-Type", "application/json"}, {"Authorization", "Bearer " ++ binary_to_list(Token)}]
|
||||
end,
|
||||
httpc:request(post, {?BASE_URL ++ Url, Headers, "application/json", jsx:encode(Body)}, ssl_opts(), []).
|
||||
|
||||
http_get(Url) -> http_get(Url, undefined).
|
||||
http_get(Url, Token) ->
|
||||
Headers = case Token of
|
||||
undefined -> [];
|
||||
_ -> [{"Authorization", "Bearer " ++ binary_to_list(Token)}]
|
||||
end,
|
||||
httpc:request(get, {?BASE_URL ++ Url, Headers}, ssl_opts(), []).
|
||||
|
||||
http_put(Url, Body, Token) ->
|
||||
Headers = [{"Content-Type", "application/json"}, {"Authorization", "Bearer " ++ binary_to_list(Token)}],
|
||||
httpc:request(put, {?BASE_URL ++ Url, Headers, "application/json", jsx:encode(Body)}, ssl_opts(), []).
|
||||
|
||||
http_delete(Url, Token) ->
|
||||
Headers = [{"Authorization", "Bearer " ++ binary_to_list(Token)}],
|
||||
httpc:request(delete, {?BASE_URL ++ Url, Headers}, ssl_opts(), []).
|
||||
|
||||
%% ── Вспомогательные функции ──────────────────────────────
|
||||
extract_json({ok, {{_, 200, _}, _, Body}}, Field) ->
|
||||
Map = jsx:decode(list_to_binary(Body), [return_maps]),
|
||||
maps:get(Field, Map);
|
||||
extract_json({ok, {{_, 201, _}, _, Body}}, Field) ->
|
||||
Map = jsx:decode(list_to_binary(Body), [return_maps]),
|
||||
maps:get(Field, Map);
|
||||
extract_json(Response, _Field) ->
|
||||
error({unexpected_response, Response}).
|
||||
|
||||
extract_json(Response, Field, ExpectedStatus) ->
|
||||
case Response of
|
||||
{ok, {{_, ExpectedStatus, _}, _, Body}} ->
|
||||
Map = jsx:decode(list_to_binary(Body), [return_maps]),
|
||||
maps:get(Field, Map);
|
||||
_ ->
|
||||
error({unexpected_response, Response})
|
||||
end.
|
||||
|
||||
assert_status(Status, {ok, {{_, Status, _}, _, _}}) -> ok;
|
||||
assert_status(Expected, {ok, {{_, Got, _}, _, _}}) ->
|
||||
error({expected_status, Expected, got, Got}).
|
||||
|
||||
unique_email(Prefix) ->
|
||||
list_to_binary([Prefix, "_", integer_to_binary(os:system_time(millisecond)), "@test.com"]).
|
||||
|
||||
register_and_login(Email, Password) ->
|
||||
RegBody = #{email => Email, password => Password},
|
||||
case http_post("/v1/register", RegBody) of
|
||||
{ok, {{_, 201, _}, _, RegResp}} ->
|
||||
Map = jsx:decode(list_to_binary(RegResp), [return_maps]),
|
||||
maps:get(<<"token">>, Map);
|
||||
{ok, {{_, 409, _}, _, _}} ->
|
||||
LoginBody = #{email => Email, password => Password},
|
||||
{ok, {{_, 200, _}, _, LoginResp}} = http_post("/v1/login", LoginBody),
|
||||
Map = jsx:decode(list_to_binary(LoginResp), [return_maps]),
|
||||
maps:get(<<"token">>, Map)
|
||||
end.
|
||||
|
||||
login_custom_admin(Email, Password) ->
|
||||
%% LoginBody = #{email => Email, password => Password},
|
||||
LoginBody = jsx:encode(#{<<"email">> => Email, <<"password">> => Password}),
|
||||
{ok, {{_, _, _}, _, LoginResp}} = httpc:request(post,
|
||||
{?ADMIN_URL ++ "/v1/admin/login", [], "application/json", LoginBody}, ssl_opts(), []),
|
||||
Map = jsx:decode(list_to_binary(LoginResp), [return_maps]),
|
||||
maps:get(<<"token">>, Map).
|
||||
|
||||
-spec create_calendar(binary(), map()) -> binary().
|
||||
create_calendar(Token, Params) ->
|
||||
Response = http_post("/v1/calendars", Params, Token),
|
||||
ct:pal(" create_calendar Response: ~p~n", [Response]),
|
||||
Id = extract_json(Response, <<"id">>),
|
||||
Id.
|
||||
#{<<"id">> := CalId} = client_post(<<"/v1/calendars">>, Token, Params),
|
||||
CalId.
|
||||
|
||||
-spec create_event(binary(), binary(), map()) -> binary().
|
||||
create_event(Token, CalId, Params) ->
|
||||
Url = "/v1/calendars/" ++ binary_to_list(CalId) ++ "/events",
|
||||
Id = extract_json(http_post(Url, Params, Token), <<"id">>),
|
||||
Id.
|
||||
Path = <<"/v1/calendars/", CalId/binary, "/events">>,
|
||||
#{<<"id">> := EventId} = client_post(Path, Token, Params),
|
||||
EventId.
|
||||
|
||||
wait_for_server() -> wait_for_server(30).
|
||||
wait_for_server(0) -> {error, timeout};
|
||||
wait_for_server(Attempts) ->
|
||||
case httpc:request(get, {?BASE_URL ++ "/health", []}, ssl_opts(), [{timeout, 1000}]) of
|
||||
{ok, {{_, 200, _}, _, _}} -> ok;
|
||||
_ -> timer:sleep(1000), wait_for_server(Attempts - 1)
|
||||
end.
|
||||
%%%===================================================================
|
||||
%%% Внутренние функции
|
||||
%%%===================================================================
|
||||
|
||||
format_datetime({{Year, Month, Day}, {Hour, Minute, Second}}) ->
|
||||
iolist_to_binary(
|
||||
io_lib:format("~4..0B-~2..0B-~2..0BT~2..0B:~2..0B:~2..0BZ",
|
||||
[Year, Month, Day, Hour, Minute, Second])
|
||||
).
|
||||
-spec login_admin(binary(), binary()) -> binary().
|
||||
login_admin(Email, Password) ->
|
||||
BodyMap = #{<<"email">> => Email, <<"password">> => Password},
|
||||
Body = jsx:encode(BodyMap),
|
||||
{ok, 200, _, RespBody} = admin_request(post, <<"/v1/admin/login">>, <<>>, Body),
|
||||
#{<<"token">> := Token} = jsx:decode(list_to_binary(RespBody), [return_maps]),
|
||||
Token.
|
||||
Reference in New Issue
Block a user