Stage 5
This commit is contained in:
@@ -82,4 +82,6 @@ set_field(tags, Value, C) -> C#calendar{tags = Value};
|
||||
set_field(type, Value, C) -> C#calendar{type = Value};
|
||||
set_field(confirmation, Value, C) -> C#calendar{confirmation = Value};
|
||||
set_field(status, Value, C) -> C#calendar{status = Value};
|
||||
set_field(rating_avg, Value, C) -> C#calendar{rating_avg = Value};
|
||||
set_field(rating_count, Value, C) -> C#calendar{rating_count = Value};
|
||||
set_field(_, _, C) -> C.
|
||||
@@ -187,4 +187,6 @@ set_field(tags, Value, E) -> E#event{tags = Value};
|
||||
set_field(capacity, Value, E) -> E#event{capacity = Value};
|
||||
set_field(online_link, Value, E) -> E#event{online_link = Value};
|
||||
set_field(status, Value, E) -> E#event{status = Value};
|
||||
set_field(rating_avg, Value, E) -> E#event{rating_avg = Value};
|
||||
set_field(rating_count, Value, E) -> E#event{rating_count = Value};
|
||||
set_field(_, _, E) -> E.
|
||||
@@ -0,0 +1,129 @@
|
||||
-module(core_review).
|
||||
-include("records.hrl").
|
||||
|
||||
-export([create/5, get_by_id/1, list_by_target/2, list_by_user/1,
|
||||
update/2, delete/1, hide/1, unhide/1]).
|
||||
-export([get_average_rating/2, has_user_reviewed/3]).
|
||||
-export([generate_id/0]).
|
||||
|
||||
%% Создание отзыва
|
||||
create(UserId, TargetType, TargetId, Rating, Comment) ->
|
||||
Id = generate_id(),
|
||||
Review = #review{
|
||||
id = Id,
|
||||
user_id = UserId,
|
||||
target_type = TargetType,
|
||||
target_id = TargetId,
|
||||
rating = Rating,
|
||||
comment = Comment,
|
||||
status = visible,
|
||||
created_at = calendar:universal_time(),
|
||||
updated_at = calendar:universal_time()
|
||||
},
|
||||
|
||||
F = fun() ->
|
||||
mnesia:write(Review),
|
||||
{ok, Review}
|
||||
end,
|
||||
|
||||
case mnesia:transaction(F) of
|
||||
{atomic, Result} -> Result;
|
||||
{aborted, Reason} -> {error, Reason}
|
||||
end.
|
||||
|
||||
%% Получение отзыва по ID
|
||||
get_by_id(Id) ->
|
||||
case mnesia:dirty_read(review, Id) of
|
||||
[] -> {error, not_found};
|
||||
[Review] -> {ok, Review}
|
||||
end.
|
||||
|
||||
%% Список отзывов для цели (событие или календарь)
|
||||
list_by_target(TargetType, TargetId) ->
|
||||
Match = #review{target_type = TargetType, target_id = TargetId, status = visible, _ = '_'},
|
||||
Reviews = mnesia:dirty_match_object(Match),
|
||||
{ok, lists:sort(fun(A, B) -> A#review.created_at >= B#review.created_at end, Reviews)}.
|
||||
|
||||
%% Список отзывов пользователя
|
||||
list_by_user(UserId) ->
|
||||
Match = #review{user_id = UserId, _ = '_'},
|
||||
Reviews = mnesia:dirty_match_object(Match),
|
||||
{ok, Reviews}.
|
||||
|
||||
%% Обновление отзыва
|
||||
update(Id, Updates) ->
|
||||
F = fun() ->
|
||||
case mnesia:read(review, Id) of
|
||||
[] ->
|
||||
{error, not_found};
|
||||
[Review] ->
|
||||
UpdatedReview = apply_updates(Review, Updates),
|
||||
mnesia:write(UpdatedReview),
|
||||
{ok, UpdatedReview}
|
||||
end
|
||||
end,
|
||||
|
||||
case mnesia:transaction(F) of
|
||||
{atomic, Result} -> Result;
|
||||
{aborted, Reason} -> {error, Reason}
|
||||
end.
|
||||
|
||||
%% Удаление отзыва (hard delete)
|
||||
delete(Id) ->
|
||||
F = fun() ->
|
||||
case mnesia:read(review, Id) of
|
||||
[] ->
|
||||
{error, not_found};
|
||||
[Review] ->
|
||||
mnesia:delete_object(Review),
|
||||
{ok, deleted}
|
||||
end
|
||||
end,
|
||||
|
||||
case mnesia:transaction(F) of
|
||||
{atomic, Result} -> Result;
|
||||
{aborted, Reason} -> {error, Reason}
|
||||
end.
|
||||
|
||||
%% Скрытие отзыва (модерация)
|
||||
hide(Id) ->
|
||||
update(Id, [{status, hidden}]).
|
||||
|
||||
%% Раскрытие отзыва
|
||||
unhide(Id) ->
|
||||
update(Id, [{status, visible}]).
|
||||
|
||||
%% Получение среднего рейтинга цели
|
||||
get_average_rating(TargetType, TargetId) ->
|
||||
Match = #review{target_type = TargetType, target_id = TargetId, status = visible, _ = '_'},
|
||||
Reviews = mnesia:dirty_match_object(Match),
|
||||
|
||||
case length(Reviews) of
|
||||
0 -> {0.0, 0};
|
||||
Count ->
|
||||
Total = lists:sum([R#review.rating || R <- Reviews]),
|
||||
{Total / Count, Count}
|
||||
end.
|
||||
|
||||
%% Проверка, оставлял ли пользователь отзыв
|
||||
has_user_reviewed(UserId, TargetType, TargetId) ->
|
||||
Match = #review{user_id = UserId, target_type = TargetType, target_id = TargetId, _ = '_'},
|
||||
case mnesia:dirty_match_object(Match) of
|
||||
[] -> false;
|
||||
_ -> true
|
||||
end.
|
||||
|
||||
%% Внутренние функции
|
||||
generate_id() ->
|
||||
base64:encode(crypto:strong_rand_bytes(16), #{mode => urlsafe, padding => false}).
|
||||
|
||||
apply_updates(Review, Updates) ->
|
||||
Updated = lists:foldl(fun({Field, Value}, R) ->
|
||||
set_field(Field, Value, R)
|
||||
end, Review, Updates),
|
||||
Updated#review{updated_at = calendar:universal_time()}.
|
||||
|
||||
set_field(rating, Value, R) when Value >= 1, Value =< 5 -> R#review{rating = Value};
|
||||
set_field(comment, Value, R) -> R#review{comment = Value};
|
||||
set_field(status, Value, R) when Value =:= visible; Value =:= hidden -> R#review{status = Value};
|
||||
set_field(_, _, R) -> R.
|
||||
Reference in New Issue
Block a user