155 lines
5.1 KiB
Erlang
155 lines
5.1 KiB
Erlang
-module(logic_ticket).
|
|
-include("records.hrl").
|
|
|
|
-export([report_error/3,
|
|
get_ticket/2,
|
|
list_tickets/1,
|
|
list_tickets_by_status/2,
|
|
update_status/3,
|
|
assign_ticket/3,
|
|
resolve_ticket/3,
|
|
close_ticket/2,
|
|
get_statistics/1]).
|
|
-export([delete_ticket/2]).
|
|
-export([get_user_ticket/2]).
|
|
|
|
%% Зарегистрировать ошибку (создать или обновить тикет)
|
|
report_error(ErrorMessage, Stacktrace, Context) ->
|
|
Existing = [T || T <- core_ticket:list_all(), T#ticket.error_message =:= ErrorMessage],
|
|
case Existing of
|
|
[Ticket] ->
|
|
% Увеличить счётчик и обновить last_seen
|
|
Updated = Ticket#ticket{
|
|
count = Ticket#ticket.count + 1,
|
|
last_seen = calendar:universal_time()
|
|
},
|
|
mnesia:dirty_write(Updated),
|
|
{ok, Updated};
|
|
[] ->
|
|
ReporterId = maps:get(<<"reporter_id">>, Context,
|
|
maps:get(reporter_id, Context, <<"anonymous">>)),
|
|
Data = #{
|
|
<<"reporter_id">> => ReporterId,
|
|
<<"error_message">> => ErrorMessage,
|
|
<<"stacktrace">> => Stacktrace,
|
|
<<"context">> => list_to_binary(io_lib:format("~p", [Context]))
|
|
},
|
|
case core_ticket:create_ticket(Data) of
|
|
{ok, Ticket} = Result ->
|
|
% Уведомление администраторов (заглушка)
|
|
notify_admins(Ticket),
|
|
Result;
|
|
Error -> Error
|
|
end
|
|
end.
|
|
|
|
%% Получить тикет, проверяя, что пользователь является репортером
|
|
get_user_ticket(UserId, TicketId) ->
|
|
case core_ticket:get_by_id(TicketId) of % используем базовую функцию без проверки прав
|
|
{ok, Ticket} ->
|
|
case Ticket#ticket.reporter_id =:= UserId of
|
|
true -> {ok, Ticket};
|
|
false -> {error, access_denied}
|
|
end;
|
|
Error -> Error
|
|
end.
|
|
|
|
%% Получить тикет (только для админов)
|
|
get_ticket(AdminId, TicketId) ->
|
|
case admin_utils:is_admin(AdminId) of
|
|
true -> core_ticket:get_by_id(TicketId);
|
|
false -> {error, access_denied}
|
|
end.
|
|
|
|
%% Список всех тикетов (только для админов)
|
|
list_tickets(AdminId) ->
|
|
case admin_utils:is_admin(AdminId) of
|
|
true -> core_ticket:list_all();
|
|
false -> {error, access_denied}
|
|
end.
|
|
|
|
%% Список тикетов по статусу (только для админов)
|
|
list_tickets_by_status(AdminId, Status) ->
|
|
case admin_utils:is_admin(AdminId) of
|
|
true ->
|
|
All = core_ticket:list_all(),
|
|
[T || T <- All, T#ticket.status =:= Status];
|
|
false -> {error, access_denied}
|
|
end.
|
|
|
|
%% Обновить статус тикета
|
|
update_status(AdminId, TicketId, closed) ->
|
|
close_ticket(AdminId, TicketId);
|
|
update_status(AdminId, TicketId, Status) ->
|
|
case admin_utils:is_admin(AdminId) of
|
|
true -> core_ticket:update_ticket(TicketId, #{<<"status">> => Status});
|
|
false -> {error, access_denied}
|
|
end.
|
|
|
|
%% Назначить тикет администратору
|
|
assign_ticket(AdminId, TicketId, AssignToId) ->
|
|
case admin_utils:is_admin(AdminId) of
|
|
true -> core_ticket:update_ticket(TicketId, #{<<"assigned_to">> => AssignToId});
|
|
false -> {error, access_denied}
|
|
end.
|
|
|
|
%% Отметить тикет как решённый с примечанием
|
|
resolve_ticket(AdminId, TicketId, ResolutionNote) ->
|
|
case admin_utils:is_admin(AdminId) of
|
|
true ->
|
|
core_ticket:update_ticket(TicketId, #{
|
|
<<"status">> => <<"resolved">>,
|
|
<<"resolution_note">> => ResolutionNote,
|
|
<<"closed_at">> => calendar:universal_time()
|
|
});
|
|
false -> {error, access_denied}
|
|
end.
|
|
|
|
%% Закрыть тикет
|
|
close_ticket(AdminId, TicketId) ->
|
|
case admin_utils:is_admin(AdminId) of
|
|
true -> core_ticket:close(TicketId, AdminId);
|
|
false -> {error, access_denied}
|
|
end.
|
|
|
|
%% Удалить тикет (только для админов)
|
|
delete_ticket(AdminId, TicketId) ->
|
|
case admin_utils:is_admin(AdminId) of
|
|
true -> core_ticket:delete_ticket(TicketId);
|
|
false -> {error, access_denied}
|
|
end.
|
|
|
|
%% Получить статистику по тикетам
|
|
get_statistics(AdminId) ->
|
|
case admin_utils:is_admin(AdminId) of
|
|
true ->
|
|
All = core_ticket:list_all(),
|
|
Open = count_by_status(All, open),
|
|
InProgress = count_by_status(All, in_progress),
|
|
Resolved = count_by_status(All, resolved),
|
|
Closed = count_by_status(All, closed),
|
|
TotalErrors = lists:sum([T#ticket.count || T <- All]),
|
|
#{
|
|
total_tickets => length(All),
|
|
open => Open,
|
|
in_progress => InProgress,
|
|
resolved => Resolved,
|
|
closed => Closed,
|
|
total_errors => TotalErrors
|
|
};
|
|
false -> {error, access_denied}
|
|
end.
|
|
|
|
count_by_status(Tickets, Status) ->
|
|
length([T || T <- Tickets, normalize_status(T#ticket.status) =:= Status]).
|
|
|
|
normalize_status(Status) when is_atom(Status) -> Status;
|
|
normalize_status(Status) when is_binary(Status) ->
|
|
try binary_to_existing_atom(Status, utf8)
|
|
catch error:badarg -> Status
|
|
end.
|
|
|
|
%% ============ Вспомогательные функции ============
|
|
|
|
notify_admins(_Ticket) ->
|
|
ok. |