Добавить автомодерацию: политики, порог жалоб, settings/hits API и тесты.
Refs EventHub/EventHubBack#37 Refs EventHub/EventHubBack#38 Refs EventHub/EventHubBack#39 Refs EventHub/EventHubBack#40
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @doc User-facing automod API: content reject + report threshold + review reports.
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(user_automod_tests).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
-export([test/0]).
|
||||
|
||||
-spec test() -> ok.
|
||||
test() ->
|
||||
ct:pal("=== User Automod Tests ==="),
|
||||
Admin = api_test_runner:get_admin_token(),
|
||||
Unique = integer_to_binary(erlang:system_time()),
|
||||
BadWord = <<"uam_bad_", Unique/binary>>,
|
||||
_ = api_test_runner:admin_post(<<"/v1/admin/banned-words">>, Admin, #{<<"word">> => BadWord}),
|
||||
|
||||
test_reject_event_create(Admin, BadWord),
|
||||
test_reject_calendar_create(Admin, BadWord),
|
||||
test_report_threshold_freezes_event(Admin),
|
||||
test_report_on_review(Admin),
|
||||
test_dismissed_reports_do_not_freeze(Admin),
|
||||
|
||||
%% restore defaults
|
||||
_ = api_test_runner:admin_put(<<"/v1/admin/automod/settings">>, Admin, #{
|
||||
<<"keyword_action">> => <<"flag">>,
|
||||
<<"match_mode">> => <<"word_boundary">>,
|
||||
<<"report_threshold">> => 3
|
||||
}),
|
||||
ct:pal("=== All user automod tests passed ==="),
|
||||
ok.
|
||||
|
||||
test_reject_event_create(Admin, BadWord) ->
|
||||
ct:pal(" TEST: reject policy returns 400 on event create"),
|
||||
_ = api_test_runner:admin_put(<<"/v1/admin/automod/settings">>, Admin, #{
|
||||
<<"keyword_action">> => <<"reject">>
|
||||
}),
|
||||
User = api_test_runner:get_user_token(),
|
||||
CalId = api_test_runner:create_calendar(User, #{title => <<"CleanCal">>}),
|
||||
{ok, Status, _, Body} = api_test_runner:client_request(post,
|
||||
<<"/v1/calendars/", CalId/binary, "/events">>, User,
|
||||
jsx:encode(#{
|
||||
title => <<"Has ", BadWord/binary>>,
|
||||
start_time => api_test_runner:future_date_iso8601(),
|
||||
duration => 30
|
||||
})),
|
||||
?assertEqual(400, Status),
|
||||
?assert(binary:match(list_to_binary(Body), <<"banned">>) =/= nomatch),
|
||||
ct:pal(" OK").
|
||||
|
||||
test_reject_calendar_create(Admin, BadWord) ->
|
||||
ct:pal(" TEST: reject policy returns 400 on calendar create"),
|
||||
_ = api_test_runner:admin_put(<<"/v1/admin/automod/settings">>, Admin, #{
|
||||
<<"keyword_action">> => <<"reject">>
|
||||
}),
|
||||
User = api_test_runner:get_user_token(),
|
||||
{ok, Status, _, _} = api_test_runner:client_request(post, <<"/v1/calendars">>, User,
|
||||
jsx:encode(#{title => <<"Cal ", BadWord/binary>>, description => <<"x">>})),
|
||||
?assertEqual(400, Status),
|
||||
ct:pal(" OK").
|
||||
|
||||
test_report_threshold_freezes_event(Admin) ->
|
||||
ct:pal(" TEST: 3 pending reports freeze event"),
|
||||
_ = api_test_runner:admin_put(<<"/v1/admin/automod/settings">>, Admin, #{
|
||||
<<"keyword_action">> => <<"flag">>,
|
||||
<<"report_threshold">> => 3
|
||||
}),
|
||||
Owner = api_test_runner:get_user_token(),
|
||||
CalId = api_test_runner:create_calendar(Owner, #{title => <<"RepThrCal">>}),
|
||||
#{<<"id">> := EventId} = api_test_runner:client_post(
|
||||
<<"/v1/calendars/", CalId/binary, "/events">>, Owner,
|
||||
#{title => <<"Clean event">>,
|
||||
start_time => api_test_runner:future_date_iso8601(),
|
||||
duration => 60}),
|
||||
lists:foreach(fun(_) ->
|
||||
Tok = api_test_runner:get_user_token(),
|
||||
{ok, 201, _, _} = api_test_runner:client_request(post, <<"/v1/reports">>, Tok,
|
||||
jsx:encode(#{
|
||||
target_type => <<"event">>,
|
||||
target_id => EventId,
|
||||
reason => <<"spam">>
|
||||
}))
|
||||
end, [1, 2, 3]),
|
||||
Ev = api_test_runner:admin_get(<<"/v1/admin/events/", EventId/binary>>, Admin),
|
||||
?assertEqual(<<"frozen">>, maps:get(<<"status">>, Ev)),
|
||||
Hits = api_test_runner:admin_get(<<"/v1/admin/automod/hits?trigger=report_threshold">>, Admin),
|
||||
?assert(lists:any(fun(H) -> maps:get(<<"entity_id">>, H) =:= EventId end, Hits)),
|
||||
ct:pal(" OK").
|
||||
|
||||
test_report_on_review(Admin) ->
|
||||
ct:pal(" TEST: report on review + threshold hides"),
|
||||
_ = api_test_runner:admin_put(<<"/v1/admin/automod/settings">>, Admin, #{
|
||||
<<"report_threshold">> => 3
|
||||
}),
|
||||
Owner = api_test_runner:get_user_token(),
|
||||
CalId = api_test_runner:create_calendar(Owner, #{title => <<"RevRepCal">>}),
|
||||
Reviewer = api_test_runner:get_user_token(),
|
||||
{ok, 201, _, RevBody} = api_test_runner:client_request(post, <<"/v1/reviews">>, Reviewer,
|
||||
jsx:encode(#{
|
||||
target_type => <<"calendar">>,
|
||||
target_id => CalId,
|
||||
rating => 2,
|
||||
comment => <<"meh">>
|
||||
})),
|
||||
#{<<"id">> := ReviewId} = jsx:decode(list_to_binary(RevBody), [return_maps]),
|
||||
lists:foreach(fun(_) ->
|
||||
Tok = api_test_runner:get_user_token(),
|
||||
{ok, 201, _, _} = api_test_runner:client_request(post, <<"/v1/reports">>, Tok,
|
||||
jsx:encode(#{
|
||||
target_type => <<"review">>,
|
||||
target_id => ReviewId,
|
||||
reason => <<"abuse">>
|
||||
}))
|
||||
end, [1, 2, 3]),
|
||||
Rev = api_test_runner:admin_get(<<"/v1/admin/reviews/", ReviewId/binary>>, Admin),
|
||||
?assertEqual(<<"hidden">>, maps:get(<<"status">>, Rev)),
|
||||
ct:pal(" OK").
|
||||
|
||||
test_dismissed_reports_do_not_freeze(Admin) ->
|
||||
ct:pal(" TEST: dismissed reports do not freeze"),
|
||||
_ = api_test_runner:admin_put(<<"/v1/admin/automod/settings">>, Admin, #{
|
||||
<<"report_threshold">> => 3
|
||||
}),
|
||||
Owner = api_test_runner:get_user_token(),
|
||||
CalId = api_test_runner:create_calendar(Owner, #{title => <<"DismissCal">>}),
|
||||
#{<<"id">> := EventId} = api_test_runner:client_post(
|
||||
<<"/v1/calendars/", CalId/binary, "/events">>, Owner,
|
||||
#{title => <<"Still clean">>,
|
||||
start_time => api_test_runner:future_date_iso8601(),
|
||||
duration => 60}),
|
||||
ReportIds = lists:map(fun(_) ->
|
||||
Tok = api_test_runner:get_user_token(),
|
||||
{ok, 201, _, B} = api_test_runner:client_request(post, <<"/v1/reports">>, Tok,
|
||||
jsx:encode(#{
|
||||
target_type => <<"event">>,
|
||||
target_id => EventId,
|
||||
reason => <<"noise">>
|
||||
})),
|
||||
maps:get(<<"id">>, jsx:decode(list_to_binary(B), [return_maps]))
|
||||
end, [1, 2]),
|
||||
lists:foreach(fun(Rid) ->
|
||||
_ = api_test_runner:admin_put(<<"/v1/admin/reports/", Rid/binary>>, Admin,
|
||||
#{<<"status">> => <<"dismissed">>})
|
||||
end, ReportIds),
|
||||
Tok3 = api_test_runner:get_user_token(),
|
||||
{ok, 201, _, _} = api_test_runner:client_request(post, <<"/v1/reports">>, Tok3,
|
||||
jsx:encode(#{
|
||||
target_type => <<"event">>,
|
||||
target_id => EventId,
|
||||
reason => <<"one pending">>
|
||||
})),
|
||||
Ev = api_test_runner:admin_get(<<"/v1/admin/events/", EventId/binary>>, Admin),
|
||||
?assertEqual(<<"active">>, maps:get(<<"status">>, Ev)),
|
||||
ct:pal(" OK").
|
||||
Reference in New Issue
Block a user