feat(geo): Photon proxy, address-only location, nearby search. Refs EventHub/EventHubBack#77
This commit is contained in:
@@ -32,7 +32,7 @@ trails() ->
|
||||
#{name => <<"limit">>, in => <<"query">>, schema => #{type => integer}, description => <<"Maximum results per page">>},
|
||||
#{name => <<"offset">>, in => <<"query">>, schema => #{type => integer}, description => <<"Offset for pagination">>},
|
||||
#{name => <<"tags">>, in => <<"query">>, schema => #{type => string}, description => <<"Comma-separated tags">>},
|
||||
#{name => <<"sort">>, in => <<"query">>, schema => #{type => string, enum => [<<"start_time">>, <<"created_at">>, <<"title">>]}, description => <<"Field to sort by">>},
|
||||
#{name => <<"sort">>, in => <<"query">>, schema => #{type => string, enum => [<<"start_time">>, <<"created_at">>, <<"title">>, <<"distance">>]}, description => <<"Field to sort by">>},
|
||||
#{name => <<"order">>, in => <<"query">>, schema => #{type => string, enum => [<<"asc">>, <<"desc">>]}, description => <<"Sort order">>},
|
||||
#{name => <<"lat">>, in => <<"query">>, schema => #{type => number, format => float}, description => <<"Latitude for geo search">>},
|
||||
#{name => <<"lon">>, in => <<"query">>, schema => #{type => number, format => float}, description => <<"Longitude for geo search">>},
|
||||
@@ -79,18 +79,22 @@ search(Req) ->
|
||||
Qs = cowboy_req:parse_qs(Req1),
|
||||
Type = proplists:get_value(<<"type">>, Qs, undefined),
|
||||
Query = proplists:get_value(<<"q">>, Qs, undefined),
|
||||
Params = parse_params(Qs),
|
||||
case logic_search:search(Type, Query, UserId, Params) of
|
||||
{ok, Total, Results} ->
|
||||
Response = #{
|
||||
total => Total,
|
||||
limit => maps:get(limit, Params, 20),
|
||||
offset => maps:get(offset, Params, 0),
|
||||
results => Results
|
||||
},
|
||||
handler_utils:send_json(Req1, 200, Response);
|
||||
{error, _} ->
|
||||
handler_utils:send_error(Req1, 500, <<"Search failed">>)
|
||||
case parse_params(Qs) of
|
||||
{error, invalid_radius} ->
|
||||
handler_utils:send_error(Req1, 400, <<"invalid_radius">>);
|
||||
Params ->
|
||||
case logic_search:search(Type, Query, UserId, Params) of
|
||||
{ok, Total, Results} ->
|
||||
Response = #{
|
||||
total => Total,
|
||||
limit => maps:get(limit, Params, 20),
|
||||
offset => maps:get(offset, Params, 0),
|
||||
results => Results
|
||||
},
|
||||
handler_utils:send_json(Req1, 200, Response);
|
||||
{error, _} ->
|
||||
handler_utils:send_error(Req1, 500, <<"Search failed">>)
|
||||
end
|
||||
end;
|
||||
{error, Code, Message, Req1} ->
|
||||
handler_utils:send_error(Req1, Code, Message)
|
||||
@@ -103,7 +107,8 @@ search(Req) ->
|
||||
%% @private Собирает карту параметров для поискового движка.
|
||||
%% Не кладёт sort/tags/geo/даты, если их нет в QS — иначе
|
||||
%% logic_search:is_discovery_request/2 никогда не сработает (Back#50).
|
||||
-spec parse_params(cowboy_req:qs()) -> map().
|
||||
%% radius без ключа при lat/lon — без отсечения (GEO.md).
|
||||
-spec parse_params(cowboy_req:qs()) -> map() | {error, invalid_radius}.
|
||||
parse_params(Qs) ->
|
||||
Params0 = #{
|
||||
limit => parse_int_param(Qs, <<"limit">>, 20),
|
||||
@@ -125,12 +130,22 @@ parse_params(Qs) ->
|
||||
end,
|
||||
Params1#{sort => Sort, order => Order}
|
||||
end,
|
||||
Params3 = case {parse_float_param(Qs, <<"lat">>), parse_float_param(Qs, <<"lon">>)} of
|
||||
{{ok, Lat}, {ok, Lon}} ->
|
||||
Radius = parse_int_param(Qs, <<"radius">>, 10),
|
||||
Params2#{lat => Lat, lon => Lon, radius => Radius};
|
||||
_ -> Params2
|
||||
end,
|
||||
case {parse_float_param(Qs, <<"lat">>), parse_float_param(Qs, <<"lon">>)} of
|
||||
{{ok, Lat}, {ok, Lon}} ->
|
||||
case parse_optional_radius(Qs) of
|
||||
{error, invalid_radius} = E -> E;
|
||||
Radius ->
|
||||
Params3 = case Radius of
|
||||
undefined -> Params2#{lat => Lat, lon => Lon};
|
||||
R -> Params2#{lat => Lat, lon => Lon, radius => R}
|
||||
end,
|
||||
with_dates(Qs, Params3)
|
||||
end;
|
||||
_ ->
|
||||
with_dates(Qs, Params2)
|
||||
end.
|
||||
|
||||
with_dates(Qs, Params3) ->
|
||||
case {parse_datetime_param(Qs, <<"from">>), parse_datetime_param(Qs, <<"to">>)} of
|
||||
{{ok, From}, {ok, To}} -> Params3#{from => From, to => To};
|
||||
{{ok, From}, error} -> Params3#{from => From};
|
||||
@@ -138,6 +153,18 @@ parse_params(Qs) ->
|
||||
_ -> Params3
|
||||
end.
|
||||
|
||||
parse_optional_radius(Qs) ->
|
||||
case proplists:get_value(<<"radius">>, Qs) of
|
||||
undefined -> undefined;
|
||||
<<>> -> undefined;
|
||||
Val ->
|
||||
N = handler_utils:parse_int_qs(Val, 0),
|
||||
case N >= 1 andalso N =< 100 of
|
||||
true -> N;
|
||||
false -> {error, invalid_radius}
|
||||
end
|
||||
end.
|
||||
|
||||
-spec parse_int_param(cowboy_req:qs(), binary(), integer()) -> integer().
|
||||
parse_int_param(Qs, Key, Default) ->
|
||||
handler_utils:parse_int_qs(proplists:get_value(Key, Qs), Default).
|
||||
@@ -146,7 +173,18 @@ parse_int_param(Qs, Key, Default) ->
|
||||
parse_float_param(Qs, Key) ->
|
||||
case proplists:get_value(Key, Qs) of
|
||||
undefined -> error;
|
||||
Val -> {ok, binary_to_float(Val)}
|
||||
<<>> -> error;
|
||||
Val ->
|
||||
try binary_to_float(Val) of
|
||||
F -> {ok, F}
|
||||
catch
|
||||
_:_ ->
|
||||
try binary_to_integer(Val) of
|
||||
I -> {ok, float(I)}
|
||||
catch
|
||||
_:_ -> error
|
||||
end
|
||||
end
|
||||
end.
|
||||
|
||||
-spec parse_datetime_param(cowboy_req:qs(), binary()) -> {ok, calendar:datetime()} | error.
|
||||
|
||||
Reference in New Issue
Block a user