Ролевая модель и аудит Часть 1.

This commit is contained in:
2026-04-28 19:12:02 +03:00
parent 7ea4efd7d9
commit b2cea7896d
32 changed files with 369 additions and 320 deletions
+23 -13
View File
@@ -2,7 +2,8 @@
-export([hash_password/1, verify_password/2,
generate_jwt/2, verify_jwt/1,
generate_refresh_token/1,
authenticate_user/2]).
authenticate_user/2,
authenticate_admin/2]).
-include("records.hrl").
@@ -26,18 +27,27 @@ authenticate_user(Email, Password) ->
{ok, User} ->
case verify_password(Password, User#user.password_hash) of
{ok, true} ->
{ok, user_to_map(User)};
_ ->
{error, invalid_credentials}
{ok, #{
id => User#user.id,
email => User#user.email,
role => atom_to_binary(User#user.role, utf8)
}};
_ -> {error, invalid_credentials}
end;
{error, not_found} ->
{error, invalid_credentials}
{error, not_found} -> {error, invalid_credentials}
end.
user_to_map(User) ->
#{
id => User#user.id,
email => User#user.email,
role => atom_to_binary(User#user.role, utf8),
status => atom_to_binary(User#user.status, utf8)
}.
authenticate_admin(Email, Password) ->
case core_admin:get_by_email(Email) of
{ok, Admin} ->
case verify_password(Password, Admin#admin.password_hash) of
{ok, true} ->
{ok, #{
id => Admin#admin.id,
email => Admin#admin.email,
role => atom_to_binary(Admin#admin.role, utf8)
}};
_ -> {error, invalid_credentials}
end;
{error, not_found} -> {error, invalid_credentials}
end.
+11 -17
View File
@@ -43,20 +43,20 @@ create_report(ReporterId, TargetType, TargetId, Reason) ->
end.
get_reports(AdminId) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true -> core_report:list_all();
false -> {error, access_denied}
end.
get_reports_by_target(AdminId, TargetType, TargetId) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true -> core_report:list_by_target(TargetType, TargetId);
false -> {error, access_denied}
end.
resolve_report(AdminId, ReportId, Action)
when Action =:= reviewed; Action =:= dismissed ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true ->
case core_report:get_by_id(ReportId) of
{ok, Report} ->
@@ -99,19 +99,19 @@ auto_freeze(_, _) -> ok.
%% ============ Бан-лист ===================================
add_banned_word(AdminId, Word) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true -> core_banned_words:add_banned_word(Word, AdminId);
false -> {error, access_denied}
end.
remove_banned_word(AdminId, Word) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true -> core_banned_words:remove_banned_word(Word);
false -> {error, access_denied}
end.
list_banned_words(AdminId) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true -> {ok, core_banned_words:list_banned_words()};
false -> {error, access_denied}
end.
@@ -143,7 +143,7 @@ auto_moderate(Text) ->
%% ============ Заморозка/разморозка =======================
freeze_calendar(AdminId, CalendarId) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true ->
case core_calendar:get_by_id(CalendarId) of
{ok, _Calendar} ->
@@ -154,7 +154,7 @@ freeze_calendar(AdminId, CalendarId) ->
end.
unfreeze_calendar(AdminId, CalendarId) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true ->
case core_calendar:get_by_id(CalendarId) of
{ok, _Calendar} ->
@@ -165,7 +165,7 @@ unfreeze_calendar(AdminId, CalendarId) ->
end.
freeze_event(AdminId, EventId) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true ->
case core_event:get_by_id(EventId) of
{ok, _Event} ->
@@ -176,7 +176,7 @@ freeze_event(AdminId, EventId) ->
end.
unfreeze_event(AdminId, EventId) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true ->
case core_event:get_by_id(EventId) of
{ok, _Event} ->
@@ -198,10 +198,4 @@ target_exists(calendar, CalendarId) ->
{ok, _} -> true;
_ -> false
end;
target_exists(_, _) -> false.
is_admin(UserId) ->
case core_user:get_by_id(UserId) of
{ok, User} -> User#user.role =:= admin;
_ -> false
end.
target_exists(_, _) -> false.
+4 -10
View File
@@ -36,7 +36,7 @@ create_review(UserId, TargetType, TargetId, Rating, Comment) ->
get_review(UserId, ReviewId) ->
case core_review:get_by_id(ReviewId) of
{ok, Review} ->
case is_admin(UserId) orelse Review#review.status =:= visible of
case admin_utils:is_admin(UserId) orelse Review#review.status =:= visible of
true -> {ok, Review};
false -> {error, access_denied}
end;
@@ -48,7 +48,7 @@ get_review(UserId, ReviewId) ->
list_reviews(UserId, TargetType, TargetId) ->
case core_review:list_by_target(TargetType, TargetId) of
{ok, Reviews} ->
case is_admin(UserId) of
case admin_utils:is_admin(UserId) of
true -> {ok, Reviews};
false -> {ok, [R || R <- Reviews, R#review.status =:= visible]}
end;
@@ -95,7 +95,7 @@ update_review(UserId, ReviewId, Updates) ->
delete_review(UserId, ReviewId) ->
case core_review:get_by_id(ReviewId) of
{ok, Review} ->
case Review#review.user_id =:= UserId orelse is_admin(UserId) of
case Review#review.user_id =:= UserId orelse admin_utils:is_admin(UserId) of
true ->
TargetType = Review#review.target_type,
TargetId = Review#review.target_id,
@@ -159,7 +159,7 @@ can_review(UserId, TargetType, TargetId) ->
%% Проверка, может ли пользователь модерировать отзыв (скрыть/раскрыть)
can_moderate_review(UserId, ReviewId) ->
case is_admin(UserId) of
case admin_utils:is_admin(UserId) of
true ->
true;
false ->
@@ -200,12 +200,6 @@ target_exists(calendar, CalendarId) ->
end;
target_exists(_, _) -> false.
is_admin(UserId) ->
case core_user:get_by_id(UserId) of
{ok, User} -> User#user.role =:= admin;
_ -> false
end.
update_target_rating(event, EventId) ->
{Avg, Count} = core_review:get_average_rating(event, EventId),
io:format("Updating event ~p rating: avg=~p, count=~p~n", [EventId, Avg, Count]),
+2 -8
View File
@@ -57,7 +57,7 @@ activate_subscription(UserId, Plan, PaymentInfo) ->
%% Отменить подписку
cancel_subscription(AdminId, SubscriptionId) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true ->
case core_subscription:get_by_id(SubscriptionId) of
{ok, _Subscription} ->
@@ -80,7 +80,7 @@ get_user_subscription(UserId) ->
%% Получить подписку по ID (только админ)
get_subscription(AdminId, SubscriptionId) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true -> core_subscription:get_by_id(SubscriptionId);
false -> {error, access_denied}
end.
@@ -137,12 +137,6 @@ handle_expired_subscriptions() ->
%% ============ Внутренние функции ============
is_admin(UserId) ->
case core_user:get_by_id(UserId) of
{ok, User} -> User#user.role =:= admin;
_ -> false
end.
plan_price(monthly) -> 999; % $9.99
plan_price(quarterly) -> 2499; % $24.99
plan_price(biannual) -> 4499; % $44.99
+8 -14
View File
@@ -40,21 +40,21 @@ report_error(ErrorMessage, Stacktrace, Context) ->
%% Получить тикет (только для админов)
get_ticket(AdminId, TicketId) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true -> core_ticket:get_by_id(TicketId);
false -> {error, access_denied}
end.
%% Список всех тикетов (только для админов)
list_tickets(AdminId) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true -> core_ticket:list_all();
false -> {error, access_denied}
end.
%% Список тикетов по статусу (только для админов)
list_tickets_by_status(AdminId, Status) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true ->
All = core_ticket:list_all(),
[T || T <- All, T#ticket.status =:= Status];
@@ -63,21 +63,21 @@ list_tickets_by_status(AdminId, Status) ->
%% Обновить статус тикета
update_status(AdminId, TicketId, Status) ->
case is_admin(AdminId) of
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 is_admin(AdminId) of
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 is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true ->
core_ticket:update_ticket(TicketId, #{
<<"status">> => <<"closed">>,
@@ -88,14 +88,14 @@ resolve_ticket(AdminId, TicketId, ResolutionNote) ->
%% Закрыть тикет
close_ticket(AdminId, TicketId) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true -> core_ticket:update_ticket(TicketId, #{<<"status">> => <<"closed">>});
false -> {error, access_denied}
end.
%% Получить статистику по тикетам
get_statistics(AdminId) ->
case is_admin(AdminId) of
case admin_utils:is_admin(AdminId) of
true ->
All = core_ticket:list_all(),
Open = length([T || T <- All, T#ticket.status =:= open]),
@@ -116,11 +116,5 @@ get_statistics(AdminId) ->
%% ============ Вспомогательные функции ============
is_admin(UserId) ->
case core_user:get_by_id(UserId) of
{ok, User} -> User#user.role =:= admin;
_ -> false
end.
notify_admins(_Ticket) ->
ok.