-module(handler_reviews). -include("records.hrl"). -export([init/2]). init(Req, Opts) -> handle(Req, Opts). handle(Req, _Opts) -> case cowboy_req:method(Req) of <<"POST">> -> create_review(Req); <<"GET">> -> list_reviews(Req); _ -> send_error(Req, 405, <<"Method not allowed">>) end. %% POST /v1/reviews - создание отзыва create_review(Req) -> case handler_auth:authenticate(Req) of {ok, UserId, Req1} -> {ok, Body, Req2} = cowboy_req:read_body(Req1), try jsx:decode(Body, [return_maps]) of Decoded when is_map(Decoded) -> case Decoded of #{<<"target_type">> := TargetTypeBin, <<"target_id">> := TargetId, <<"rating">> := Rating, <<"comment">> := Comment} -> TargetType = parse_target_type(TargetTypeBin), case logic_review:create_review(UserId, TargetType, TargetId, Rating, Comment) of {ok, Review} -> Response = review_to_json(Review), send_json(Req2, 201, Response); {error, already_reviewed} -> send_error(Req2, 409, <<"Already reviewed">>); {error, cannot_review} -> send_error(Req2, 403, <<"Cannot review this target">>); {error, target_not_found} -> send_error(Req2, 404, <<"Target not found">>); {error, _} -> send_error(Req2, 500, <<"Internal server error">>) end; _ -> send_error(Req2, 400, <<"Missing required fields">>) 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. %% GET /v1/reviews - список отзывов для цели list_reviews(Req) -> case handler_auth:authenticate(Req) of {ok, UserId, Req1} -> Qs = cowboy_req:parse_qs(Req1), case {proplists:get_value(<<"target_type">>, Qs), proplists:get_value(<<"target_id">>, Qs)} of {undefined, _} -> send_error(Req1, 400, <<"Missing target_type">>); {_, undefined} -> send_error(Req1, 400, <<"Missing target_id">>); {TargetTypeBin, TargetId} -> TargetType = parse_target_type(TargetTypeBin), case logic_review:list_reviews(UserId, TargetType, TargetId) of {ok, Reviews} -> Response = [review_to_json(R) || R <- Reviews], send_json(Req1, 200, Response); {error, _} -> send_error(Req1, 500, <<"Internal server error">>) end end; {error, Code, Message, Req1} -> send_error(Req1, Code, Message) end. %% Вспомогательные функции parse_target_type(<<"event">>) -> event; parse_target_type(<<"calendar">>) -> calendar; parse_target_type(_) -> undefined. review_to_json(Review) -> #{ id => Review#review.id, user_id => Review#review.user_id, target_type => Review#review.target_type, target_id => Review#review.target_id, rating => Review#review.rating, comment => Review#review.comment, status => Review#review.status, created_at => datetime_to_iso8601(Review#review.created_at), updated_at => datetime_to_iso8601(Review#review.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, []}.