Пагинация, фильтры и сортировки Часть 1 #20
This commit is contained in:
@@ -113,12 +113,14 @@ convert_field({<<"location">>, Val}) -> {location, Val};
|
||||
convert_field({<<"tags">>, Val}) -> {tags, Val};
|
||||
convert_field({<<"capacity">>, Val}) -> {capacity, Val};
|
||||
convert_field({<<"online_link">>, Val}) -> {online_link, Val};
|
||||
convert_field({<<"status">>, Val}) -> {status, Val};
|
||||
convert_field({<<"status">>, Val}) ->
|
||||
try binary_to_existing_atom(Val, utf8) of
|
||||
Atom -> {status, Atom}
|
||||
catch
|
||||
error:badarg -> {status, Val} % fallback, но лучше залогировать
|
||||
end;
|
||||
convert_field(Other) -> Other.
|
||||
|
||||
%% event_to_json, datetime_to_iso8601, parse_datetime, parse_datetime_binary
|
||||
%% берутся те же, что и в admin_handler_events.erl (можно вынести в общий модуль,
|
||||
%% но для простоты дублируем).
|
||||
event_to_json(Event) ->
|
||||
LocationJson = case Event#event.location of
|
||||
undefined -> null;
|
||||
|
||||
@@ -6,37 +6,51 @@
|
||||
|
||||
init(Req, _Opts) ->
|
||||
case cowboy_req:method(Req) of
|
||||
<<"GET">> ->
|
||||
list_all_events(Req);
|
||||
_ ->
|
||||
send_error(Req, 405, <<"Method not allowed">>)
|
||||
<<"GET">> -> list_all_events(Req);
|
||||
_ -> send_error(Req, 405, <<"Method not allowed">>)
|
||||
end.
|
||||
|
||||
%% GET /v1/admin/events
|
||||
list_all_events(Req) ->
|
||||
case auth_admin(Req) of
|
||||
{ok, _AdminId, Req1} ->
|
||||
Filters = parse_filters(Req1),
|
||||
{ok, Events} = logic_event:list_all_events(Filters),
|
||||
Params = parse_admin_event_search(Req1),
|
||||
{ok, Total, Events} = logic_event:search_events(Params),
|
||||
Json = [event_to_json(E) || E <- Events],
|
||||
send_json(Req1, 200, Json);
|
||||
Limit = maps:get(limit, Params, 50),
|
||||
Offset = maps:get(offset, Params, 0),
|
||||
RangeEnd = min(Offset + Limit - 1, Total - 1),
|
||||
Headers = #{
|
||||
<<"content-type">> => <<"application/json">>,
|
||||
<<"content-range">> => iolist_to_binary(
|
||||
io_lib:format("items ~B-~B/~B", [Offset, RangeEnd, Total])),
|
||||
<<"x-total-count">> => integer_to_binary(Total),
|
||||
<<"access-control-expose-headers">> => <<"Content-Range, X-Total-Count">>
|
||||
},
|
||||
Body = jsx:encode(Json),
|
||||
cowboy_req:reply(200, Headers, Body, Req1),
|
||||
{ok, Body, []};
|
||||
{error, Code, Msg, Req1} ->
|
||||
send_error(Req1, Code, Msg)
|
||||
end.
|
||||
|
||||
%% --- Вспомогательные функции ---
|
||||
|
||||
parse_filters(Req) ->
|
||||
parse_admin_event_search(Req) ->
|
||||
Qs = cowboy_req:parse_qs(Req),
|
||||
lists:filtermap(
|
||||
fun
|
||||
({<<"from">>, Val}) -> {true, {from, parse_datetime_binary(Val)}};
|
||||
({<<"to">>, Val}) -> {true, {to, parse_datetime_binary(Val)}};
|
||||
(_) -> false
|
||||
end,
|
||||
Qs
|
||||
).
|
||||
#{
|
||||
from => parse_datetime_qs(proplists:get_value(<<"from">>, Qs)),
|
||||
to => parse_datetime_qs(proplists:get_value(<<"to">>, Qs)),
|
||||
status => proplists:get_value(<<"status">>, Qs, undefined),
|
||||
calendar_id => proplists:get_value(<<"calendar_id">>, Qs, undefined),
|
||||
title => proplists:get_value(<<"title">>, Qs, undefined),
|
||||
q => proplists:get_value(<<"q">>, Qs, undefined),
|
||||
limit => parse_int_qs(proplists:get_value(<<"limit">>, Qs), 50),
|
||||
offset => parse_int_qs(proplists:get_value(<<"offset">>, Qs), 0),
|
||||
sort => proplists:get_value(<<"sort">>, Qs, <<"created_at">>),
|
||||
order => proplists:get_value(<<"order">>, Qs, <<"desc">>)
|
||||
}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Вспомогательные функции
|
||||
%%--------------------------------------------------------------------
|
||||
auth_admin(Req) ->
|
||||
case handler_auth:authenticate(Req) of
|
||||
{ok, AdminId, Req1} ->
|
||||
@@ -48,7 +62,14 @@ auth_admin(Req) ->
|
||||
{error, Code, Msg, Req1}
|
||||
end.
|
||||
|
||||
%% Сериализация события (полностью скопирована из handler_event_by_id.erl)
|
||||
parse_int_qs(undefined, Default) -> Default;
|
||||
parse_int_qs(Bin, Default) ->
|
||||
try binary_to_integer(Bin) catch _:_ -> Default end.
|
||||
|
||||
parse_datetime_qs(undefined) -> undefined;
|
||||
parse_datetime_qs(Bin) ->
|
||||
case parse_datetime(Bin) of {ok, Dt} -> Dt; _ -> undefined end.
|
||||
|
||||
event_to_json(Event) ->
|
||||
LocationJson = case Event#event.location of
|
||||
undefined -> null;
|
||||
@@ -97,12 +118,6 @@ datetime_to_iso8601({{Year, Month, Day}, {Hour, Minute, Second}}) ->
|
||||
datetime_to_iso8601(undefined) ->
|
||||
undefined.
|
||||
|
||||
parse_datetime_binary(Str) ->
|
||||
case parse_datetime(Str) of
|
||||
{ok, Dt} -> Dt;
|
||||
_ -> undefined
|
||||
end.
|
||||
|
||||
parse_datetime(Str) ->
|
||||
try
|
||||
[DateStr, TimeStr] = string:split(Str, "T"),
|
||||
@@ -119,12 +134,6 @@ parse_datetime(Str) ->
|
||||
catch _:_ -> {error, invalid_format}
|
||||
end.
|
||||
|
||||
send_json(Req, Status, Data) ->
|
||||
Body = jsx:encode(Data),
|
||||
Headers = #{<<"content-type">> => <<"application/json">>},
|
||||
cowboy_req:reply(Status, Headers, Body, Req),
|
||||
{ok, Body, []}.
|
||||
|
||||
send_error(Req, Status, Message) ->
|
||||
Body = jsx:encode(#{error => Message}),
|
||||
cowboy_req:reply(Status, #{<<"content-type">> => <<"application/json">>}, Body, Req),
|
||||
|
||||
Reference in New Issue
Block a user