Добавить авто-регистрацию тикетов (hash/dedupe/500/WS). Refs EventHub/EventHubBack#35
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
%%% GET – получить список тикетов.
|
||||
%%% Администраторы видят все тикеты,
|
||||
%%% обычные пользователи – только свои.
|
||||
%%% POST – создать новый тикет об ошибке.
|
||||
%%% POST – создать/дедуплицировать тикет об ошибке через logic_ticket:report_error.
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(handler_tickets).
|
||||
@@ -47,7 +47,7 @@ trails() ->
|
||||
#{ % POST create
|
||||
path => <<"/v1/tickets">>,
|
||||
method => <<"POST">>,
|
||||
description => <<"Create a new ticket (bug report)">>,
|
||||
description => <<"Create or bump a ticket (bug report / frontend error)">>,
|
||||
tags => [<<"Tickets">>],
|
||||
requestBody => #{
|
||||
required => true,
|
||||
@@ -57,14 +57,16 @@ trails() ->
|
||||
properties => #{
|
||||
error_message => #{type => string},
|
||||
stacktrace => #{type => string},
|
||||
context => #{type => string}
|
||||
context => #{type => object},
|
||||
source => #{type => string, enum => [<<"frontend">>, <<"manual">>]}
|
||||
}
|
||||
}}}
|
||||
},
|
||||
responses => #{
|
||||
201 => #{description => <<"Ticket created">>},
|
||||
201 => #{description => <<"Ticket created or updated">>},
|
||||
400 => #{description => <<"Missing required fields or invalid JSON">>},
|
||||
401 => #{description => <<"Unauthorized">>}
|
||||
401 => #{description => <<"Unauthorized">>},
|
||||
429 => #{description => <<"Rate limited">>}
|
||||
}
|
||||
}
|
||||
].
|
||||
@@ -84,7 +86,8 @@ ticket_schema() ->
|
||||
last_seen => #{type => string, format => <<"date-time">>},
|
||||
status => #{type => string, enum => [<<"open">>, <<"in_progress">>, <<"resolved">>, <<"closed">>]},
|
||||
assigned_to => #{type => string, nullable => true},
|
||||
resolution_note => #{type => string, nullable => true}
|
||||
resolution_note => #{type => string, nullable => true},
|
||||
source => #{type => string, enum => [<<"backend">>, <<"frontend">>, <<"manual">>]}
|
||||
}
|
||||
}.
|
||||
|
||||
@@ -118,21 +121,23 @@ list_tickets(Req) ->
|
||||
handler_utils:send_error(Req1, Code, Message)
|
||||
end.
|
||||
|
||||
%% @doc POST /v1/tickets — создание тикета.
|
||||
%% @doc POST /v1/tickets — создание/дедуп тикета.
|
||||
-spec create_ticket(cowboy_req:req()) -> {ok, binary(), cowboy_req:req()}.
|
||||
create_ticket(Req) ->
|
||||
case handler_utils:auth_user(Req) of
|
||||
{ok, UserId, Req1} ->
|
||||
{ok, Body, Req2} = cowboy_req:read_body(Req1),
|
||||
try jsx:decode(Body, [return_maps]) of
|
||||
#{<<"error_message">> := _} = Data ->
|
||||
TicketData = maps:merge(
|
||||
#{<<"reporter_id">> => UserId, <<"status">> => <<"open">>},
|
||||
Data
|
||||
),
|
||||
case core_ticket:create_ticket(TicketData) of
|
||||
#{<<"error_message">> := ErrorMessage} = Data ->
|
||||
Stacktrace = maps:get(<<"stacktrace">>, Data, <<>>),
|
||||
Source = resolve_source(Data, Stacktrace),
|
||||
Context0 = maps:get(<<"context">>, Data, #{}),
|
||||
Context = merge_context(Context0, UserId),
|
||||
case logic_ticket:report_error(Source, ErrorMessage, Stacktrace, Context) of
|
||||
{ok, Ticket} ->
|
||||
handler_utils:send_json(Req2, 201, handler_utils:ticket_to_json(Ticket));
|
||||
{error, rate_limited} ->
|
||||
handler_utils:send_error(Req2, 429, <<"Too many new tickets">>);
|
||||
{error, Reason} ->
|
||||
handler_utils:send_error(Req2, 500, Reason)
|
||||
end;
|
||||
@@ -143,4 +148,19 @@ create_ticket(Req) ->
|
||||
end;
|
||||
{error, Code, Message, Req1} ->
|
||||
handler_utils:send_error(Req1, Code, Message)
|
||||
end.
|
||||
end.
|
||||
|
||||
resolve_source(#{<<"source">> := <<"frontend">>}, _) -> frontend;
|
||||
resolve_source(#{<<"source">> := <<"manual">>}, _) -> manual;
|
||||
resolve_source(#{<<"source">> := <<"backend">>}, _) -> backend;
|
||||
resolve_source(_, Stacktrace) when is_binary(Stacktrace), Stacktrace =/= <<>> ->
|
||||
frontend;
|
||||
resolve_source(_, _) ->
|
||||
manual.
|
||||
|
||||
merge_context(Ctx, UserId) when is_map(Ctx) ->
|
||||
Ctx#{<<"reporter_id">> => UserId};
|
||||
merge_context(Ctx, UserId) when is_binary(Ctx) ->
|
||||
#{<<"reporter_id">> => UserId, <<"raw">> => Ctx};
|
||||
merge_context(_, UserId) ->
|
||||
#{<<"reporter_id">> => UserId}.
|
||||
|
||||
Reference in New Issue
Block a user