%%%------------------------------------------------------------------- %%% @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").