Статистика для дашборда, расширенная #7
This commit is contained in:
@@ -4,20 +4,25 @@
|
||||
update_role/2, block/1, unblock/1, generate_id/0]).
|
||||
|
||||
create(Email, Password, Role) ->
|
||||
Id = generate_id(),
|
||||
{ok, Hash} = argon2:hash(Password),
|
||||
Now = calendar:universal_time(),
|
||||
Admin = #admin{
|
||||
id = Id,
|
||||
email = Email,
|
||||
password_hash = Hash,
|
||||
role = Role,
|
||||
status = active,
|
||||
created_at = Now,
|
||||
updated_at = Now
|
||||
},
|
||||
mnesia:dirty_write(Admin),
|
||||
{ok, Admin}.
|
||||
case get_by_email(Email) of
|
||||
{ok, _} ->
|
||||
{error, email_exists};
|
||||
{error, not_found} ->
|
||||
Id = generate_id(),
|
||||
{ok, Hash} = argon2:hash(Password),
|
||||
Now = calendar:universal_time(),
|
||||
Admin = #admin{
|
||||
id = Id,
|
||||
email = Email,
|
||||
password_hash = Hash,
|
||||
role = Role,
|
||||
status = active,
|
||||
created_at = Now,
|
||||
updated_at = Now
|
||||
},
|
||||
mnesia:dirty_write(Admin),
|
||||
{ok, Admin}
|
||||
end.
|
||||
|
||||
get_by_email(Email) ->
|
||||
Match = #admin{email = Email, _ = '_'},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
-module(core_admin_audit).
|
||||
-include("records.hrl").
|
||||
-export([log/7, list/0, list/1]).
|
||||
-export([count_actions_by_admin/2]).
|
||||
|
||||
log(AdminId, Email, Role, Action, EntityType, EntityId, Ip) ->
|
||||
log(AdminId, Email, Role, Action, EntityType, EntityId, Ip, undefined).
|
||||
@@ -26,15 +27,33 @@ list() ->
|
||||
|
||||
%% Фильтрация по параметрам (простая версия)
|
||||
list(Filters) ->
|
||||
All = list(),
|
||||
All = list(), % все записи
|
||||
lists:filter(fun(E) ->
|
||||
% Фильтр по admin_id
|
||||
case proplists:get_value(admin_id, Filters) of
|
||||
undefined -> true;
|
||||
Id -> E#admin_audit.admin_id =:= Id
|
||||
end andalso
|
||||
case proplists:get_value(action, Filters) of
|
||||
undefined -> true;
|
||||
Act -> E#admin_audit.action =:= Act
|
||||
end
|
||||
% можно добавить фильтр по дате и т.д.
|
||||
Id -> E#admin_audit.admin_id =:= Id
|
||||
end
|
||||
andalso
|
||||
% Фильтр по action
|
||||
case proplists:get_value(action, Filters) of
|
||||
undefined -> true;
|
||||
Act -> E#admin_audit.action =:= Act
|
||||
end
|
||||
andalso
|
||||
% Фильтр по дате с
|
||||
case proplists:get_value(date_from, Filters) of
|
||||
undefined -> true;
|
||||
From -> E#admin_audit.timestamp >= From
|
||||
end
|
||||
andalso
|
||||
% Фильтр по дате по
|
||||
case proplists:get_value(date_to, Filters) of
|
||||
undefined -> true;
|
||||
To -> E#admin_audit.timestamp =< To
|
||||
end
|
||||
end, All).
|
||||
|
||||
count_actions_by_admin(AdminId, Action) ->
|
||||
Match = #admin_audit{admin_id = AdminId, action = Action, _ = '_'},
|
||||
length(mnesia:dirty_match_object(Match)).
|
||||
@@ -4,7 +4,7 @@
|
||||
-export([create/4, create_recurring/5, get_by_id/1, list_by_calendar/1,
|
||||
update/2, delete/1, materialize_occurrence/3]).
|
||||
-export([generate_id/0]).
|
||||
-export([count_events/0]).
|
||||
-export([count_events/0, count_events_by_date/2]).
|
||||
|
||||
%% Создание одиночного события
|
||||
create(CalendarId, Title, StartTime, Duration) ->
|
||||
@@ -171,6 +171,22 @@ delete(Id) ->
|
||||
count_events() ->
|
||||
mnesia:table_info(event, size).
|
||||
|
||||
count_events_by_date(From, To) ->
|
||||
All = mnesia:dirty_match_object(#event{_ = '_'}),
|
||||
Filtered = lists:filter(fun(E) ->
|
||||
E#event.created_at >= From andalso E#event.created_at =< To
|
||||
end, All),
|
||||
Counts = lists:foldl(fun(E, Acc) ->
|
||||
Day = date_part(E#event.created_at),
|
||||
case lists:keyfind(Day, 1, Acc) of
|
||||
false -> [{Day, 1} | Acc];
|
||||
{Day, C} -> lists:keyreplace(Day, 1, Acc, {Day, C+1})
|
||||
end
|
||||
end, [], Filtered),
|
||||
lists:sort(Counts).
|
||||
|
||||
date_part({{Y,M,D}, _}) -> {Y,M,D}.
|
||||
|
||||
%% Внутренние функции
|
||||
generate_id() ->
|
||||
base64:encode(crypto:strong_rand_bytes(16), #{mode => urlsafe, padding => false}).
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
-export([update_status/3, get_count_by_target/2]).
|
||||
-export([generate_id/0]).
|
||||
-export([count_reports_by_status/1, count_reports_by_admin/2]).
|
||||
-export([count_reports_resolved_by_admin/2, avg_resolution_time/1]).
|
||||
|
||||
%% Создание жалобы
|
||||
create(ReporterId, TargetType, TargetId, Reason) ->
|
||||
@@ -92,6 +93,22 @@ count_reports_by_admin(AdminId, Status) ->
|
||||
Match = #report{resolved_by = AdminId, status = Status, _ = '_'},
|
||||
length(mnesia:dirty_match_object(Match)).
|
||||
|
||||
count_reports_resolved_by_admin(AdminId, Status) ->
|
||||
Match = #report{resolved_by = AdminId, status = Status, _ = '_'},
|
||||
length(mnesia:dirty_match_object(Match)).
|
||||
|
||||
avg_resolution_time(Status) ->
|
||||
Match = #report{status = Status, _ = '_'},
|
||||
Reports = mnesia:dirty_match_object(Match),
|
||||
Resolved = lists:filter(fun(R) -> R#report.resolved_at =/= undefined end, Reports),
|
||||
case Resolved of
|
||||
[] -> 0;
|
||||
_ ->
|
||||
TotalSeconds = lists:sum([calendar:datetime_to_gregorian_seconds(R#report.resolved_at) -
|
||||
calendar:datetime_to_gregorian_seconds(R#report.created_at) || R <- Resolved]),
|
||||
TotalSeconds / length(Resolved) / 3600.0
|
||||
end.
|
||||
|
||||
%% Внутренние функции
|
||||
generate_id() ->
|
||||
base64:encode(crypto:strong_rand_bytes(16), #{mode => urlsafe, padding => false}).
|
||||
@@ -8,6 +8,7 @@
|
||||
create_ticket/1,
|
||||
list_by_user/1]).
|
||||
-export([count_tickets_by_status/1, count_tickets_by_admin/2]).
|
||||
-export([avg_resolution_time/0]).
|
||||
|
||||
list_all() ->
|
||||
mnesia:dirty_match_object(#ticket{_ = '_'}).
|
||||
@@ -69,6 +70,27 @@ create_ticket(Data) ->
|
||||
list_by_user(UserId) ->
|
||||
mnesia:dirty_match_object(#ticket{reporter_id = UserId, _ = '_'}).
|
||||
|
||||
count_by_status(Status, Tickets) ->
|
||||
length([T || T <- Tickets, T#ticket.status =:= Status]).
|
||||
|
||||
count_tickets_by_status(Status) ->
|
||||
Match = #ticket{status = Status, _ = '_'},
|
||||
length(mnesia:dirty_match_object(Match)).
|
||||
|
||||
count_tickets_by_admin(AdminId, Status) ->
|
||||
Match = #ticket{assigned_to = AdminId, status = Status, _ = '_'},
|
||||
length(mnesia:dirty_match_object(Match)).
|
||||
|
||||
avg_resolution_time() ->
|
||||
Tickets = mnesia:dirty_match_object(#ticket{status = closed, _ = '_'}),
|
||||
case Tickets of
|
||||
[] -> 0;
|
||||
_ ->
|
||||
TotalSeconds = lists:sum([calendar:datetime_to_gregorian_seconds(T#ticket.last_seen) -
|
||||
calendar:datetime_to_gregorian_seconds(T#ticket.first_seen) || T <- Tickets]),
|
||||
TotalSeconds / length(Tickets) / 3600.0
|
||||
end.
|
||||
|
||||
%% ── внутренние ─────────────────────────────────────────
|
||||
apply_updates(Ticket, Updates) ->
|
||||
lists:foldl(fun({Key, Value}, Acc) ->
|
||||
@@ -82,14 +104,3 @@ apply_updates(Ticket, Updates) ->
|
||||
_ -> Acc
|
||||
end
|
||||
end, Ticket, maps:to_list(Updates)).
|
||||
|
||||
count_by_status(Status, Tickets) ->
|
||||
length([T || T <- Tickets, T#ticket.status =:= Status]).
|
||||
|
||||
count_tickets_by_status(Status) ->
|
||||
Match = #ticket{status = Status, _ = '_'},
|
||||
length(mnesia:dirty_match_object(Match)).
|
||||
|
||||
count_tickets_by_admin(AdminId, Status) ->
|
||||
Match = #ticket{assigned_to = AdminId, status = Status, _ = '_'},
|
||||
length(mnesia:dirty_match_object(Match)).
|
||||
@@ -6,7 +6,7 @@
|
||||
-export([generate_id/0]).
|
||||
-export([list_users/0]).
|
||||
-export([block/1, unblock/1]).
|
||||
-export([count_users/0]).
|
||||
-export([count_users/0, count_users_by_date/2]).
|
||||
|
||||
%% Создание пользователя
|
||||
create(Email, Password) ->
|
||||
@@ -126,6 +126,22 @@ unblock(Id) ->
|
||||
count_users() ->
|
||||
mnesia:table_info(user, size).
|
||||
|
||||
count_users_by_date(From, To) ->
|
||||
All = mnesia:dirty_match_object(#user{_ = '_'}),
|
||||
Filtered = lists:filter(fun(U) ->
|
||||
U#user.created_at >= From andalso U#user.created_at =< To
|
||||
end, All),
|
||||
Counts = lists:foldl(fun(U, Acc) ->
|
||||
Day = date_part(U#user.created_at),
|
||||
case lists:keyfind(Day, 1, Acc) of
|
||||
false -> [{Day, 1} | Acc];
|
||||
{Day, C} -> lists:keyreplace(Day, 1, Acc, {Day, C+1})
|
||||
end
|
||||
end, [], Filtered),
|
||||
lists:sort(Counts).
|
||||
|
||||
date_part({{Y,M,D}, _}) -> {Y,M,D}.
|
||||
|
||||
%% Внутренние функции
|
||||
generate_id() ->
|
||||
base64:encode(crypto:strong_rand_bytes(16), #{mode => urlsafe, padding => false}).
|
||||
|
||||
@@ -39,12 +39,9 @@ create_admin(Req) ->
|
||||
Role = binary_to_atom(RoleBin, utf8),
|
||||
case core_admin:create(Email, Password, Role) of
|
||||
{ok, Admin} ->
|
||||
% Заглушка отправки email
|
||||
% send_invitation_email(Email),
|
||||
core_admin_audit:log(AdminId, Admin#admin.email, Admin#admin.role,
|
||||
<<"create_admin">>, <<"admin">>, Admin,
|
||||
admin_utils:client_ip(Req)),
|
||||
send_json(Req2, 201, admin_to_json(Admin));
|
||||
{error, email_exists} ->
|
||||
send_error(Req2, 409, <<"Email already exists">>);
|
||||
{error, Reason} ->
|
||||
send_error(Req2, 500, Reason)
|
||||
end;
|
||||
|
||||
@@ -14,7 +14,14 @@ get_stats(Req) ->
|
||||
case admin_utils:is_admin(AdminId) of
|
||||
true ->
|
||||
{ok, Admin} = core_admin:get_by_id(AdminId),
|
||||
Stats = logic_stats:get_stats(Admin#admin.role, AdminId),
|
||||
Role = Admin#admin.role,
|
||||
% Извлекаем параметры from и to из запроса
|
||||
Stats = case parse_date_range(Req1) of
|
||||
{ok, From, To} ->
|
||||
logic_stats:get_stats(Role, AdminId, From, To);
|
||||
_ ->
|
||||
logic_stats:get_stats(Role, AdminId)
|
||||
end,
|
||||
send_json(Req1, 200, Stats);
|
||||
false ->
|
||||
send_error(Req1, 403, <<"Admin access required">>)
|
||||
@@ -23,6 +30,28 @@ get_stats(Req) ->
|
||||
send_error(Req1, Code, Message)
|
||||
end.
|
||||
|
||||
parse_date_range(Req) ->
|
||||
Qs = cowboy_req:parse_qs(Req),
|
||||
From = proplists:get_value(<<"from">>, Qs),
|
||||
To = proplists:get_value(<<"to">>, Qs),
|
||||
case {From, To} of
|
||||
{undefined, _} -> error;
|
||||
{_, undefined} -> error;
|
||||
{F, T} ->
|
||||
try
|
||||
FromDT = iso8601_to_datetime(F),
|
||||
ToDT = iso8601_to_datetime(T),
|
||||
{ok, FromDT, ToDT}
|
||||
catch _:_ -> error
|
||||
end
|
||||
end.
|
||||
|
||||
iso8601_to_datetime(Str) ->
|
||||
[Date, Time] = binary:split(Str, <<"T">>),
|
||||
[Y, M, D] = [binary_to_integer(X) || X <- binary:split(Date, <<"-">>, [global])],
|
||||
[H, Min, S] = [binary_to_integer(X) || X <- binary:split(Time, <<":">>, [global])],
|
||||
{{Y, M, D}, {H, Min, S}}.
|
||||
|
||||
send_json(Req, Status, Data) ->
|
||||
Body = jsx:encode(Data),
|
||||
cowboy_req:reply(Status, #{<<"content-type">> => <<"application/json">>}, Body, Req),
|
||||
|
||||
@@ -1,29 +1,82 @@
|
||||
-module(logic_stats).
|
||||
-export([get_stats/2]).
|
||||
-export([get_stats/2, get_stats/4]).
|
||||
|
||||
-include("records.hrl").
|
||||
|
||||
%% ========== Точка входа (без дат) =============================
|
||||
-spec get_stats(Role :: atom(), AdminId :: binary()) -> map().
|
||||
get_stats(superadmin, _AdminId) ->
|
||||
#{
|
||||
users => core_user:count_users(),
|
||||
calendars => core_calendar:count_calendars(),
|
||||
events => core_event:count_events(),
|
||||
bookings => core_booking:count_bookings(),
|
||||
reviews => core_review:count_reviews(),
|
||||
reports_total => core_report:count_reports_by_status(pending),
|
||||
tickets_open => core_ticket:count_tickets_by_status(open),
|
||||
subscriptions => core_subscription:count_subscription()
|
||||
};
|
||||
get_stats(moderator, AdminId) ->
|
||||
#{
|
||||
reports_reviewed => core_report:count_reports_by_admin(AdminId, reviewed),
|
||||
events_moderated => 0 % пока заглушка, можно добавить позже
|
||||
};
|
||||
get_stats(support, AdminId) ->
|
||||
#{
|
||||
tickets_assigned => core_ticket:count_tickets_by_admin(AdminId, open),
|
||||
reports_pending => core_report:count_reports_by_status(pending)
|
||||
};
|
||||
get_stats(_, _) ->
|
||||
get_stats(Role, AdminId) ->
|
||||
{{Y, _, _}, _} = calendar:universal_time(),
|
||||
From = {{Y, 1, 1}, {0, 0, 0}}, % начало текущего года
|
||||
To = calendar:universal_time(),
|
||||
get_stats(Role, AdminId, From, To).
|
||||
|
||||
%% ========== Точка входа (с фильтром по датам) =================
|
||||
-spec get_stats(Role :: atom(), AdminId :: binary(),
|
||||
From :: calendar:datetime(), To :: calendar:datetime()) -> map().
|
||||
get_stats(superadmin, _AdminId, From, To) ->
|
||||
build_superadmin_stats(From, To);
|
||||
get_stats(moderator, AdminId, From, To) ->
|
||||
build_moderator_stats(AdminId, From, To);
|
||||
get_stats(support, AdminId, From, To) ->
|
||||
build_support_stats(AdminId, From, To);
|
||||
get_stats(_, _, _, _) ->
|
||||
#{}.
|
||||
|
||||
%% ========== Суперадмин =========================================
|
||||
build_superadmin_stats(From, To) ->
|
||||
#{
|
||||
users_total => core_user:count_users(),
|
||||
events_total => core_event:count_events(),
|
||||
calendars_total => core_calendar:count_calendars(),
|
||||
reviews_total => core_review:count_reviews(),
|
||||
reports_total => core_report:count_reports_by_status(pending),
|
||||
tickets_open => core_ticket:count_tickets_by_status(open),
|
||||
tickets_total => length(core_ticket:list_all()),
|
||||
avg_ticket_resolution_h => trunc_hours(core_ticket:avg_resolution_time()),
|
||||
registrations_by_day => date_list_to_json(core_user:count_users_by_date(From, To)),
|
||||
events_by_day => date_list_to_json(core_event:count_events_by_date(From, To)),
|
||||
admin_activity => collect_admin_activity()
|
||||
}.
|
||||
|
||||
%% ========== Модератор ==========================================
|
||||
build_moderator_stats(AdminId, _From, _To) ->
|
||||
#{
|
||||
reports_reviewed => core_report:count_reports_resolved_by_admin(AdminId, reviewed),
|
||||
reports_dismissed => core_report:count_reports_resolved_by_admin(AdminId, dismissed),
|
||||
avg_report_resolution_h => trunc_hours(core_report:avg_resolution_time(reviewed)),
|
||||
events_moderated => 0 % заглушка, можно доработать
|
||||
}.
|
||||
|
||||
%% ========== Поддержка ==========================================
|
||||
build_support_stats(AdminId, _From, _To) ->
|
||||
#{
|
||||
tickets_assigned_open => core_ticket:count_tickets_by_admin(AdminId, open),
|
||||
tickets_assigned_total => core_ticket:count_tickets_by_admin(AdminId, closed) +
|
||||
core_ticket:count_tickets_by_admin(AdminId, in_progress),
|
||||
reports_pending => core_report:count_reports_by_status(pending)
|
||||
}.
|
||||
|
||||
%% ========== Вспомогательные функции ============================
|
||||
|
||||
date_list_to_json(List) ->
|
||||
[ #{<<"date">> => iso8601_date(Date), <<"count">> => Count} || {Date, Count} <- List ].
|
||||
|
||||
iso8601_date({{Y, M, D}, _}) ->
|
||||
iolist_to_binary(io_lib:format("~4..0B-~2..0B-~2..0B", [Y, M, D]));
|
||||
iso8601_date({Y, M, D}) ->
|
||||
iolist_to_binary(io_lib:format("~4..0B-~2..0B-~2..0B", [Y, M, D])).
|
||||
|
||||
trunc_hours(Value) ->
|
||||
round(Value * 10) / 10.0.
|
||||
|
||||
collect_admin_activity() ->
|
||||
Admins = core_admin:list_all(),
|
||||
lists:map(fun(A) ->
|
||||
Actions = length(core_admin_audit:list([{admin_id, A#admin.id}])),
|
||||
#{
|
||||
admin_id => A#admin.id,
|
||||
email => A#admin.email,
|
||||
actions => Actions
|
||||
}
|
||||
end, Admins).
|
||||
@@ -1,4 +1,6 @@
|
||||
-module(api_admin_tests).
|
||||
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
-export([test/0]).
|
||||
|
||||
test() ->
|
||||
@@ -25,17 +27,23 @@ test() ->
|
||||
|
||||
%% TEST 3: Admin stats (superadmin)
|
||||
io:format(" TEST 3: Admin stats (superadmin)... "),
|
||||
% Логинимся под суперадмином (данные из api_test_runner)
|
||||
LoginBody = jsx:encode(#{<<"email">> => <<"admin@eventhub.local">>, <<"password">> => <<"123456">>}),
|
||||
{ok, {{_, 200, _}, _, LoginResp}} = httpc:request(post,
|
||||
{AdminURL ++ "/v1/admin/login", [], "application/json", LoginBody}, [], []),
|
||||
#{<<"token">> := SuperToken} = jsx:decode(list_to_binary(LoginResp), [return_maps]),
|
||||
|
||||
% Запрашиваем статистику
|
||||
{ok, {{_, 200, _}, _, StatsResp}} = httpc:request(get,
|
||||
% Без дат
|
||||
{ok, {{_, 200, _}, _, StatsResp1}} = httpc:request(get,
|
||||
{AdminURL ++ "/v1/admin/stats", [{"Authorization", "Bearer " ++ binary_to_list(SuperToken)}]}, [], []),
|
||||
Stats = jsx:decode(list_to_binary(StatsResp), [return_maps]),
|
||||
io:format(" OK (keys: ~p)~n", [maps:keys(Stats)]),
|
||||
Stats1 = jsx:decode(list_to_binary(StatsResp1), [return_maps]),
|
||||
io:format(" OK (keys: ~p)~n", [maps:keys(Stats1)]),
|
||||
|
||||
% С датами
|
||||
{ok, {{_, 200, _}, _, StatsResp2}} = httpc:request(get,
|
||||
{AdminURL ++ "/v1/admin/stats?from=2026-01-01T00:00:00&to=2026-12-31T23:59:59",
|
||||
[{"Authorization", "Bearer " ++ binary_to_list(SuperToken)}]}, [], []),
|
||||
Stats2 = jsx:decode(list_to_binary(StatsResp2), [return_maps]),
|
||||
io:format(" (with dates, keys: ~p)~n", [maps:keys(Stats2)]),
|
||||
|
||||
%% TEST 4: List users
|
||||
io:format(" TEST 4: List users... "),
|
||||
|
||||
@@ -22,15 +22,17 @@ cleanup(_) ->
|
||||
admin_stats_test_() ->
|
||||
{setup, fun setup/0, fun cleanup/1, [
|
||||
{"GET /admin/stats as superadmin returns 200 with system metrics", fun test_superadmin/0},
|
||||
{"GET /admin/stats as superadmin with date filter", fun test_superadmin_dates/0},
|
||||
{"GET /admin/stats as moderator returns 200 with own metrics", fun test_moderator/0},
|
||||
{"GET /admin/stats as support returns 200 with assigned tickets", fun test_support/0},
|
||||
{"GET /admin/stats with non‑admin token returns 403", fun test_forbidden/0},
|
||||
{"POST /admin/stats returns 405", fun test_wrong_method/0}
|
||||
]}.
|
||||
|
||||
%% --- Суперадмин ---
|
||||
%% --- Суперадмин (без дат) ---
|
||||
test_superadmin() ->
|
||||
ok = meck:expect(cowboy_req, method, fun(_) -> <<"GET">> end),
|
||||
ok = meck:expect(cowboy_req, parse_qs, fun(_) -> [] end),
|
||||
ok = meck:expect(handler_auth, authenticate,
|
||||
fun(Req) -> {ok, <<"adm1">>, Req} end),
|
||||
ok = meck:expect(admin_utils, is_admin, fun(_) -> true end),
|
||||
@@ -41,9 +43,26 @@ test_superadmin() ->
|
||||
{ok, _, _} = admin_handler_stats:init(req, []),
|
||||
?assertEqual(200, erase(test_reply)).
|
||||
|
||||
%% --- Суперадмин (с датами) ---
|
||||
test_superadmin_dates() ->
|
||||
ok = meck:expect(cowboy_req, method, fun(_) -> <<"GET">> end),
|
||||
ok = meck:expect(cowboy_req, parse_qs, fun(_) ->
|
||||
[{<<"from">>, <<"2026-01-01T00:00:00">>}, {<<"to">>, <<"2026-06-01T00:00:00">>}]
|
||||
end),
|
||||
ok = meck:expect(handler_auth, authenticate,
|
||||
fun(Req) -> {ok, <<"adm1">>, Req} end),
|
||||
ok = meck:expect(admin_utils, is_admin, fun(_) -> true end),
|
||||
ok = meck:expect(core_admin, get_by_id,
|
||||
fun(<<"adm1">>) -> {ok, #admin{id = <<"adm1">>, role = superadmin}} end),
|
||||
ok = meck:expect(logic_stats, get_stats,
|
||||
fun(superadmin, _, _, _) -> #{users => 10} end),
|
||||
{ok, _, _} = admin_handler_stats:init(req, []),
|
||||
?assertEqual(200, erase(test_reply)).
|
||||
|
||||
%% --- Модератор ---
|
||||
test_moderator() ->
|
||||
ok = meck:expect(cowboy_req, method, fun(_) -> <<"GET">> end),
|
||||
ok = meck:expect(cowboy_req, parse_qs, fun(_) -> [] end),
|
||||
ok = meck:expect(handler_auth, authenticate,
|
||||
fun(Req) -> {ok, <<"mod1">>, Req} end),
|
||||
ok = meck:expect(admin_utils, is_admin, fun(_) -> true end),
|
||||
@@ -57,6 +76,7 @@ test_moderator() ->
|
||||
%% --- Поддержка ---
|
||||
test_support() ->
|
||||
ok = meck:expect(cowboy_req, method, fun(_) -> <<"GET">> end),
|
||||
ok = meck:expect(cowboy_req, parse_qs, fun(_) -> [] end),
|
||||
ok = meck:expect(handler_auth, authenticate,
|
||||
fun(Req) -> {ok, <<"sup1">>, Req} end),
|
||||
ok = meck:expect(admin_utils, is_admin, fun(_) -> true end),
|
||||
|
||||
Reference in New Issue
Block a user