<%= link_to_user forum_post.creator %> @@ -32,6 +37,9 @@
-
<%= render "forum_post_votes/list", votes: forum_post.votes, forum_post: forum_post %>
diff --git a/app/views/forum_posts/_listing.html.erb b/app/views/forum_posts/_listing.html.erb
index 0612f2522..5bea63030 100644
--- a/app/views/forum_posts/_listing.html.erb
+++ b/app/views/forum_posts/_listing.html.erb
@@ -1,9 +1,18 @@
<%- # forum_post %>
<%- # original_forum_post_id %>
<%- # dtext_data %>
+<%- # moderation_reports %>
+ <% if moderation_reports.present? %>
+
diff --git a/app/views/forum_topics/show.html.erb b/app/views/forum_topics/show.html.erb
index c8d64d5dc..5bab6d482 100644
--- a/app/views/forum_topics/show.html.erb
+++ b/app/views/forum_topics/show.html.erb
@@ -20,7 +20,7 @@
+
+ This topic has forum posts reported for moderation! (<%= pluralize(moderation_reports.length, "report") %>)
+
+
+ <% end %>
+
<% forum_posts.each do |forum_post| %>
- <%= render "forum_posts/forum_post", forum_post: forum_post, original_forum_post_id: original_forum_post_id, dtext_data: dtext_data %>
+ <%= render "forum_posts/forum_post", forum_post: forum_post, original_forum_post_id: original_forum_post_id, dtext_data: dtext_data, moderation_reports: moderation_reports %>
<% end %>
+
diff --git a/app/views/moderation_reports/create.js.erb b/app/views/moderation_reports/create.js.erb
new file mode 100644
index 000000000..755f3d075
--- /dev/null
+++ b/app/views/moderation_reports/create.js.erb
@@ -0,0 +1 @@
+Danbooru.notice("Report submitted.");
\ No newline at end of file
diff --git a/app/views/moderation_reports/index.html.erb b/app/views/moderation_reports/index.html.erb
new file mode 100644
index 000000000..93507dbd1
--- /dev/null
+++ b/app/views/moderation_reports/index.html.erb
@@ -0,0 +1,27 @@
+
+ <%= format_text(WikiPage.titled(Danbooru.config.report_notice_wiki_page).first.try(&:body)) %>
+
+
+ <%# XXX dtext_field expects there to be a `moderation_report` instance variable. %>
+ <% @moderation_report = moderation_report %>
+ <%= edit_form_for(@moderation_report, format: :js, remote: true) do |f| %>
+ <%= f.hidden_field :model_type %>
+ <%= f.hidden_field :model_id %>
+ <%= dtext_field "moderation_report", "reason", preview_id: "dtext-preview-for-moderation-report", type: "string" %>
+ <%= dtext_preview_button "moderation_report", "reason", preview_id: "dtext-preview-for-moderation-report" %>
+ <% end %>
+
+
diff --git a/app/views/moderation_reports/new.html.erb b/app/views/moderation_reports/new.html.erb
new file mode 100644
index 000000000..70ebcbda7
--- /dev/null
+++ b/app/views/moderation_reports/new.html.erb
@@ -0,0 +1,5 @@
+
+
by <%= link_to_user report.creator %> + <% end %> + <% end %> + + <%= numbered_paginator(@moderation_reports) %> +
+Moderation reports
+ <%= table_for @moderation_reports, width: "100%" do |t| %> + <% t.column "Reported", width: "10%" do |report| %> + <% if report.model_type == "User" %> + <%= link_to_user report.model %> + <% elsif report.model_type == "Comment" %> + <%= link_to "comment ##{report.model_id}", comment_path(report.model_id) %> + <% elsif report.model_type == "ForumPost" %> + <%= link_to "forum ##{report.model_id}", forum_post_path(report.model_id) %> + <% end %> + <% end %> + <% t.column "Reason" do |report| %> + + <%= format_text report.reason, inline: true %> + + <% end %> + <% t.column "Creator", width: "10%" do |report| %> + <%= compact_time report.created_at %> +by <%= link_to_user report.creator %> + <% end %> + <% end %> + + <%= numbered_paginator(@moderation_reports) %> +
+
diff --git a/app/views/moderation_reports/new.js.erb b/app/views/moderation_reports/new.js.erb
new file mode 100644
index 000000000..8f83b844a
--- /dev/null
+++ b/app/views/moderation_reports/new.js.erb
@@ -0,0 +1 @@
+Danbooru.Utility.dialog("Send report", "<%= j render "moderation_reports/new", moderation_report: @moderation_report %>");
diff --git a/app/views/static/site_map.html.erb b/app/views/static/site_map.html.erb
index 8951e50ce..32a695924 100644
--- a/app/views/static/site_map.html.erb
+++ b/app/views/static/site_map.html.erb
@@ -155,6 +155,7 @@
<% end %>
<% if CurrentUser.is_moderator? %>
+
+ <%= render "moderation_reports/new", moderation_report: @moderation_report %>
+
+<%= link_to_user @user %>
+ <% if @user.viewable_moderation_reports.present? %> +
+
+ This user has been reported for moderation! (<%= pluralize(@user.viewable_moderation_reports.length, "report") %>)
+
+
+ <% end %>
+
<%= render "statistics", presenter: @user.presenter, user: @user %>
<%= render "posts/partials/common/inline_blacklist" %>
diff --git a/config/danbooru_default_config.rb b/config/danbooru_default_config.rb
index 409d9f35f..42b134975 100644
--- a/config/danbooru_default_config.rb
+++ b/config/danbooru_default_config.rb
@@ -305,6 +305,10 @@ module Danbooru
"help:appeal_notice"
end
+ def report_notice_wiki_page
+ "help:report_notice"
+ end
+
def replacement_notice_wiki_page
"help:replacement_notice"
end
diff --git a/config/routes.rb b/config/routes.rb
index a0e692beb..f7a750ca3 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -160,6 +160,7 @@ Rails.application.routes.draw do
end
end
resources :mod_actions
+ resources :moderation_reports, only: [:new, :create, :index]
resources :news_updates
resources :notes do
collection do
diff --git a/db/migrate/20200117220602_create_moderation_reports.rb b/db/migrate/20200117220602_create_moderation_reports.rb
new file mode 100644
index 000000000..38f83f26e
--- /dev/null
+++ b/db/migrate/20200117220602_create_moderation_reports.rb
@@ -0,0 +1,12 @@
+class CreateModerationReports < ActiveRecord::Migration[6.0]
+ def change
+ create_table :moderation_reports do |t|
+ t.timestamps
+ t.references :model, polymorphic: true, null: false
+ t.integer :creator_id, null: false
+ t.text :reason, null: false
+ end
+
+ add_index :moderation_reports, :creator_id
+ end
+end
diff --git a/db/structure.sql b/db/structure.sql
index 5f00617b0..b545e73e6 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -2408,6 +2408,40 @@ CREATE SEQUENCE public.mod_actions_id_seq
ALTER SEQUENCE public.mod_actions_id_seq OWNED BY public.mod_actions.id;
+--
+-- Name: moderation_reports; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.moderation_reports (
+ id bigint NOT NULL,
+ created_at timestamp(6) without time zone NOT NULL,
+ updated_at timestamp(6) without time zone NOT NULL,
+ model_type character varying NOT NULL,
+ model_id bigint NOT NULL,
+ creator_id integer NOT NULL,
+ reason text NOT NULL
+);
+
+
+--
+-- Name: moderation_reports_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE public.moderation_reports_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+--
+-- Name: moderation_reports_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE public.moderation_reports_id_seq OWNED BY public.moderation_reports.id;
+
+
--
-- Name: news_updates; Type: TABLE; Schema: public; Owner: -
--
@@ -4080,6 +4114,13 @@ ALTER TABLE ONLY public.ip_bans ALTER COLUMN id SET DEFAULT nextval('public.ip_b
ALTER TABLE ONLY public.mod_actions ALTER COLUMN id SET DEFAULT nextval('public.mod_actions_id_seq'::regclass);
+--
+-- Name: moderation_reports id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.moderation_reports ALTER COLUMN id SET DEFAULT nextval('public.moderation_reports_id_seq'::regclass);
+
+
--
-- Name: news_updates id; Type: DEFAULT; Schema: public; Owner: -
--
@@ -4440,6 +4481,14 @@ ALTER TABLE ONLY public.mod_actions
ADD CONSTRAINT mod_actions_pkey PRIMARY KEY (id);
+--
+-- Name: moderation_reports moderation_reports_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.moderation_reports
+ ADD CONSTRAINT moderation_reports_pkey PRIMARY KEY (id);
+
+
--
-- Name: news_updates news_updates_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -6514,6 +6563,20 @@ CREATE INDEX index_mod_actions_on_created_at ON public.mod_actions USING btree (
CREATE INDEX index_mod_actions_on_creator_id ON public.mod_actions USING btree (creator_id);
+--
+-- Name: index_moderation_reports_on_creator_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX index_moderation_reports_on_creator_id ON public.moderation_reports USING btree (creator_id);
+
+
+--
+-- Name: index_moderation_reports_on_model_type_and_model_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX index_moderation_reports_on_model_type_and_model_id ON public.moderation_reports USING btree (model_type, model_id);
+
+
--
-- Name: index_news_updates_on_created_at; Type: INDEX; Schema: public; Owner: -
--
@@ -7415,6 +7478,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20191223032633'),
('20200114204550'),
('20200115010442'),
+('20200117220602'),
('20200118015014');
diff --git a/test/factories/moderation_report.rb b/test/factories/moderation_report.rb
new file mode 100644
index 000000000..55cdbaa78
--- /dev/null
+++ b/test/factories/moderation_report.rb
@@ -0,0 +1,5 @@
+FactoryBot.define do
+ factory(:moderation_report) do
+ reason {"xxx"}
+ end
+end
diff --git a/test/functional/moderation_reports_controller_test.rb b/test/functional/moderation_reports_controller_test.rb
new file mode 100644
index 000000000..3d18bc445
--- /dev/null
+++ b/test/functional/moderation_reports_controller_test.rb
@@ -0,0 +1,66 @@
+require 'test_helper'
+
+class ModerationReportsControllerTest < ActionDispatch::IntegrationTest
+ context "The moderation reports controller" do
+ setup do
+ travel_to(2.weeks.ago) do
+ @user = create(:user)
+ @builder = create(:builder_user)
+ @mod = create(:moderator_user)
+ end
+
+ @user.as_current do
+ @comment = create(:comment)
+ end
+ end
+
+ context "new action" do
+ should "render the access denied page" do
+ get_auth new_moderation_report_path, @user
+ assert_response 403
+ assert_select "h1", /Access Denied/
+ end
+
+ should "render" do
+ get_auth new_moderation_report_path, @mod, params: {:moderation_report => {:model_id => @comment.id, :model_type => "Comment"}}
+ assert_response :success
+ end
+ end
+
+ context "index action" do
+ setup do
+ @builder.as_current do
+ create(:moderation_report, model: @comment)
+ end
+ end
+
+ should "render the access denied page" do
+ get_auth moderation_reports_path, @builder
+ assert_response 403
+ assert_select "h1", /Access Denied/
+ end
+
+ should "render" do
+ get_auth moderation_reports_path, @mod
+ assert_response :success
+ end
+
+ context "with search parameters" do
+ should "render" do
+ get_auth moderation_reports_path, @mod, params: {:search => {:model_id => @comment.id}}
+ assert_response :success
+ end
+ end
+
+ context "create action" do
+ should "create a new moderation report" do
+ assert_difference("ModerationReport.count", 1) do
+ assert_difference("ModerationReport.count") do
+ post_auth moderation_reports_path, @builder, params: {:format => "js", :moderation_report => {:model_id => @comment.id, :model_type => "Comment", :reason => "xxx"}}
+ end
+ end
+ end
+ end
+ end
+ end
+end