Рефакторинг админских обработчиков - пагинация, сортировка, фильтрация. Часть 1

This commit is contained in:
2026-05-26 13:04:31 +03:00
parent 01dbc6d6cb
commit ed5b275efb
24 changed files with 1009 additions and 1126 deletions
@@ -31,10 +31,8 @@ init(Req, _Opts) ->
%%% Swagger metadata
-spec trails() -> [map()].
trails() ->
[
% GET list
#{
path => <<"/v1/admin/banned-words">>,
[ % GET list
#{ path => <<"/v1/admin/banned-words">>,
method => <<"GET">>,
description => <<"List all banned words (admin)">>,
tags => [<<"Banned Words">>],
@@ -53,8 +51,7 @@ trails() ->
}
},
% POST add
#{
path => <<"/v1/admin/banned-words">>,
#{ path => <<"/v1/admin/banned-words">>,
method => <<"POST">>,
description => <<"Add a new banned word">>,
tags => [<<"Banned Words">>],
@@ -72,8 +69,7 @@ trails() ->
}
},
% PUT update
#{
path => <<"/v1/admin/banned-words/{word}">>,
#{ path => <<"/v1/admin/banned-words/{word}">>,
method => <<"PUT">>,
description => <<"Update an existing banned word">>,
tags => [<<"Banned Words">>],
@@ -95,8 +91,7 @@ trails() ->
}
},
% DELETE by word
#{
path => <<"/v1/admin/banned-words/{word}">>,
#{ path => <<"/v1/admin/banned-words/{word}">>,
method => <<"DELETE">>,
description => <<"Remove a banned word">>,
tags => [<<"Banned Words">>],
@@ -109,8 +104,7 @@ trails() ->
}
},
% POST batch
#{
path => <<"/v1/admin/banned-words/batch">>,
#{ path => <<"/v1/admin/banned-words/batch">>,
method => <<"POST">>,
description => <<"Batch add banned words (only new words are added)">>,
tags => [<<"Banned Words">>],
@@ -167,7 +161,7 @@ add_word(Req) ->
#{<<"word">> := Word} ->
case core_banned_words:add_banned_word(Word, AdminId) of
{ok, _} ->
log_admin_action(AdminId, <<"add">>, <<"banned_word">>, Word, Req2),
admin_utils:log_admin_action(AdminId, <<"add">>, <<"banned_word">>, Word, Req2),
handler_utils:send_json(Req2, 201, #{status => <<"added">>});
{error, already_exists} ->
handler_utils:send_error(Req2, 409, <<"Word already exists">>);
@@ -191,7 +185,7 @@ update_word(Req) ->
#{<<"word">> := NewWord} ->
case core_banned_words:update_banned_word(OldWord, NewWord) of
{ok, _Updated} ->
log_admin_action(AdminId, <<"update">>, <<"banned_word">>,
admin_utils:log_admin_action(AdminId, <<"update">>, <<"banned_word">>,
#{old_word => OldWord, new_word => NewWord}, Req2),
handler_utils:send_json(Req2, 200, #{status => <<"updated">>});
{error, not_found} ->
@@ -215,7 +209,7 @@ delete_word(Req) ->
Word = cowboy_req:binding(word, Req1),
case core_banned_words:remove_banned_word(Word) of
{ok, _} ->
log_admin_action(AdminId, <<"delete">>, <<"banned_word">>, Word, Req1),
admin_utils:log_admin_action(AdminId, <<"delete">>, <<"banned_word">>, Word, Req1),
handler_utils:send_json(Req1, 200, #{status => <<"deleted">>});
{error, not_found} ->
handler_utils:send_error(Req1, 404, <<"Word not found">>);
@@ -246,7 +240,7 @@ batch_add_words(Req) ->
),
Added = length([R || R <- Results, maps:get(status, R) =:= <<"added">>]),
Skipped = length([R || R <- Results, maps:get(status, R) =:= <<"skipped">>]),
log_admin_action(AdminId, <<"batch_add">>, <<"banned_words">>,
admin_utils:log_admin_action(AdminId, <<"batch_add">>, <<"banned_words">>,
#{count => length(Words), added => Added, skipped => Skipped}, Req2),
handler_utils:send_json(Req2, 200, #{
results => Results,
@@ -266,31 +260,11 @@ batch_add_words(Req) ->
%%% Вспомогательные функции
%%%===================================================================
log_admin_action(AdminId, Action, EntityType, EntityId, Req) ->
case core_admin:get_by_id(AdminId) of
{ok, Admin} ->
Email = Admin#admin.email,
Role = atom_to_binary(Admin#admin.role, utf8),
Ip = ip_to_binary(cowboy_req:peer(Req)),
core_admin_audit:log(AdminId, Email, Role, Action, EntityType, EntityId, Ip),
ok;
_ -> ok
end.
ip_to_binary({A, B, C, D}) ->
list_to_binary(io_lib:format("~B.~B.~B.~B", [A, B, C, D]));
ip_to_binary(_) ->
<<"unknown">>.
datetime_to_iso8601(undefined) -> undefined;
datetime_to_iso8601({{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])).
%% @private Преобразование записи banned_word в JSON-совместимую карту.
word_to_map(W) ->
#{
id => W#banned_word.id,
word => W#banned_word.word,
added_by => W#banned_word.added_by,
added_at => datetime_to_iso8601(W#banned_word.added_at)
added_at => handler_utils:datetime_to_iso8601(W#banned_word.added_at)
}.