181 lines
6.4 KiB
Erlang
181 lines
6.4 KiB
Erlang
-module(handler_event_by_id).
|
|
-include("records.hrl").
|
|
|
|
-export([init/2]).
|
|
|
|
init(Req, Opts) ->
|
|
handle(Req, Opts).
|
|
|
|
handle(Req, _Opts) ->
|
|
case cowboy_req:method(Req) of
|
|
<<"GET">> -> get_event(Req);
|
|
<<"PUT">> -> update_event(Req);
|
|
<<"DELETE">> -> delete_event(Req);
|
|
_ -> send_error(Req, 405, <<"Method not allowed">>)
|
|
end.
|
|
|
|
%% GET /v1/events/:id - получение события
|
|
get_event(Req) ->
|
|
case handler_auth:authenticate(Req) of
|
|
{ok, UserId, Req1} ->
|
|
EventId = cowboy_req:binding(id, Req1),
|
|
case logic_event:get_event(UserId, EventId) of
|
|
{ok, Event} ->
|
|
Response = event_to_json(Event),
|
|
send_json(Req1, 200, Response);
|
|
{error, access_denied} ->
|
|
send_error(Req1, 403, <<"Access denied">>);
|
|
{error, not_found} ->
|
|
send_error(Req1, 404, <<"Event not found">>);
|
|
{error, _} ->
|
|
send_error(Req1, 500, <<"Internal server error">>)
|
|
end;
|
|
{error, Code, Message, Req1} ->
|
|
send_error(Req1, Code, Message)
|
|
end.
|
|
|
|
%% PUT /v1/events/:id - обновление события
|
|
update_event(Req) ->
|
|
case handler_auth:authenticate(Req) of
|
|
{ok, UserId, Req1} ->
|
|
EventId = cowboy_req:binding(id, Req1),
|
|
{ok, Body, Req2} = cowboy_req:read_body(Req1),
|
|
try jsx:decode(Body, [return_maps]) of
|
|
UpdatesMap when is_map(UpdatesMap) ->
|
|
Updates = maps:to_list(UpdatesMap),
|
|
UpdatesWithTypes = convert_fields(Updates),
|
|
case logic_event:update_event(UserId, EventId, UpdatesWithTypes) of
|
|
{ok, Event} ->
|
|
Response = event_to_json(Event),
|
|
send_json(Req2, 200, Response);
|
|
{error, access_denied} ->
|
|
send_error(Req2, 403, <<"Access denied">>);
|
|
{error, not_found} ->
|
|
send_error(Req2, 404, <<"Event not found">>);
|
|
{error, event_in_past} ->
|
|
send_error(Req2, 400, <<"Event cannot be in the past">>);
|
|
{error, _} ->
|
|
send_error(Req2, 500, <<"Internal server error">>)
|
|
end;
|
|
_ ->
|
|
send_error(Req2, 400, <<"Invalid JSON">>)
|
|
catch
|
|
_:_ ->
|
|
send_error(Req2, 400, <<"Invalid JSON format">>)
|
|
end;
|
|
{error, Code, Message, Req1} ->
|
|
send_error(Req1, Code, Message)
|
|
end.
|
|
|
|
%% DELETE /v1/events/:id - удаление события
|
|
delete_event(Req) ->
|
|
case handler_auth:authenticate(Req) of
|
|
{ok, UserId, Req1} ->
|
|
EventId = cowboy_req:binding(id, Req1),
|
|
case logic_event:delete_event(UserId, EventId) of
|
|
{ok, _} ->
|
|
send_json(Req1, 200, #{status => <<"deleted">>});
|
|
{error, access_denied} ->
|
|
send_error(Req1, 403, <<"Access denied">>);
|
|
{error, not_found} ->
|
|
send_error(Req1, 404, <<"Event not found">>);
|
|
{error, _} ->
|
|
send_error(Req1, 500, <<"Internal server error">>)
|
|
end;
|
|
{error, Code, Message, Req1} ->
|
|
send_error(Req1, Code, Message)
|
|
end.
|
|
|
|
%% Вспомогательные функции
|
|
convert_fields(Updates) ->
|
|
lists:map(fun
|
|
({start_time, Value}) when is_binary(Value) ->
|
|
case parse_datetime(Value) of
|
|
{ok, DateTime} -> {start_time, DateTime};
|
|
_ -> {start_time, Value}
|
|
end;
|
|
({location, Value}) when is_map(Value) ->
|
|
case Value of
|
|
#{<<"lat">> := Lat, <<"lon">> := Lon} ->
|
|
Address = maps:get(<<"address">>, Value, <<"">>),
|
|
{location, #location{address = Address, lat = Lat, lon = Lon}};
|
|
_ -> {location, undefined}
|
|
end;
|
|
({tags, Value}) when is_list(Value) ->
|
|
{tags, Value};
|
|
(Other) -> Other
|
|
end, Updates).
|
|
|
|
parse_datetime(Str) ->
|
|
try
|
|
[DateStr, TimeStr] = string:split(Str, "T"),
|
|
TimeStrNoZ = string:trim(TimeStr, trailing, "Z"),
|
|
|
|
[YearStr, MonthStr, DayStr] = string:split(DateStr, "-", all),
|
|
[HourStr, MinuteStr, SecondStr] = string:split(TimeStrNoZ, ":", all),
|
|
|
|
Year = binary_to_integer(YearStr),
|
|
Month = binary_to_integer(MonthStr),
|
|
Day = binary_to_integer(DayStr),
|
|
Hour = binary_to_integer(HourStr),
|
|
Minute = binary_to_integer(MinuteStr),
|
|
Second = binary_to_integer(SecondStr),
|
|
|
|
{ok, {{Year, Month, Day}, {Hour, Minute, Second}}}
|
|
catch
|
|
_:_ -> {error, invalid_format}
|
|
end.
|
|
|
|
event_to_json(Event) ->
|
|
LocationJson = case Event#event.location of
|
|
undefined -> null;
|
|
#location{address = Addr, lat = Lat, lon = Lon} ->
|
|
#{address => Addr, lat => Lat, lon => Lon}
|
|
end,
|
|
|
|
RecurrenceJson = case Event#event.recurrence_rule of
|
|
undefined -> null;
|
|
Rule ->
|
|
Decoded = jsx:decode(Rule, [return_maps]),
|
|
case Decoded of
|
|
Map when is_map(Map) -> Map;
|
|
{ok, Map} -> Map
|
|
end
|
|
end,
|
|
|
|
#{
|
|
id => Event#event.id,
|
|
calendar_id => Event#event.calendar_id,
|
|
title => Event#event.title,
|
|
description => Event#event.description,
|
|
event_type => Event#event.event_type,
|
|
start_time => datetime_to_iso8601(Event#event.start_time),
|
|
duration => Event#event.duration,
|
|
recurrence => RecurrenceJson,
|
|
master_id => Event#event.master_id,
|
|
is_instance => Event#event.is_instance,
|
|
specialist_id => Event#event.specialist_id,
|
|
location => LocationJson,
|
|
tags => Event#event.tags,
|
|
capacity => Event#event.capacity,
|
|
online_link => Event#event.online_link,
|
|
status => Event#event.status,
|
|
rating_avg => Event#event.rating_avg,
|
|
rating_count => Event#event.rating_count,
|
|
created_at => datetime_to_iso8601(Event#event.created_at),
|
|
updated_at => datetime_to_iso8601(Event#event.updated_at)
|
|
}.
|
|
|
|
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])).
|
|
|
|
send_json(Req, Status, Data) ->
|
|
Body = jsx:encode(Data),
|
|
cowboy_req:reply(Status, #{<<"content-type">> => <<"application/json">>}, Body, Req),
|
|
{ok, Body, []}.
|
|
|
|
send_error(Req, Status, Message) ->
|
|
Body = jsx:encode(#{error => Message}),
|
|
cowboy_req:reply(Status, #{<<"content-type">> => <<"application/json">>}, Body, Req),
|
|
{ok, Body, []}. |