beetle_reporter 0.1.0 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +70 -16
  4. data/Rakefile +5 -9
  5. data/app/assets/config/beetle_reporter_manifest.js +1 -0
  6. data/app/assets/stylesheets/beetle_reporter/application.css +15 -0
  7. data/app/assets/stylesheets/beetle_reporter/home.css +4 -0
  8. data/app/assets/stylesheets/beetle_reporter/reports.css +4 -0
  9. data/app/assets/stylesheets/beetle_reporter/tailwind.min.css +1 -0
  10. data/app/assets/stylesheets/scaffold.css +80 -0
  11. data/app/controllers/beetle_reporter/application_controller.rb +11 -0
  12. data/app/controllers/beetle_reporter/home_controller.rb +8 -0
  13. data/app/controllers/beetle_reporter/reports_controller.rb +166 -0
  14. data/app/helpers/beetle_reporter/application_helper.rb +9 -0
  15. data/app/helpers/beetle_reporter/home_helper.rb +4 -0
  16. data/app/helpers/beetle_reporter/reports_helper.rb +4 -0
  17. data/app/jobs/beetle_reporter/application_job.rb +4 -0
  18. data/app/mailers/beetle_reporter/application_mailer.rb +6 -0
  19. data/app/models/beetle_reporter/application_record.rb +5 -0
  20. data/app/models/beetle_reporter/report.rb +123 -0
  21. data/app/views/beetle_reporter/home/index.html.haml +4 -0
  22. data/app/views/beetle_reporter/reports/_form.html.haml +14 -0
  23. data/app/views/beetle_reporter/reports/_report.html.haml +55 -0
  24. data/app/views/beetle_reporter/reports/destroy.turbo_stream.haml +1 -0
  25. data/app/views/beetle_reporter/reports/edit.html.haml +6 -0
  26. data/app/views/beetle_reporter/reports/index.html.haml +38 -0
  27. data/app/views/beetle_reporter/reports/new.html.haml +5 -0
  28. data/app/views/beetle_reporter/reports/show.html.haml +1 -0
  29. data/app/views/layouts/beetle_reporter/application.html.haml +22 -0
  30. data/config/locales/beetle_reporter.yml +18 -0
  31. data/config/routes.rb +13 -0
  32. data/db/migrate/20211216073022_create_beetle_reporter_reports.rb +20 -0
  33. data/lib/beetle_reporter/configuration.rb +9 -0
  34. data/lib/beetle_reporter/engine.rb +9 -0
  35. data/lib/beetle_reporter/version.rb +1 -3
  36. data/lib/beetle_reporter.rb +46 -4
  37. data/lib/tasks/beetle_reporter_tasks.rake +4 -0
  38. metadata +137 -15
  39. data/.rspec +0 -3
  40. data/.rubocop.yml +0 -13
  41. data/CHANGELOG.md +0 -5
  42. data/Gemfile +0 -12
  43. data/LICENSE.txt +0 -21
  44. data/beetle_reporter.gemspec +0 -39
  45. data/bin/console +0 -15
  46. data/bin/setup +0 -8
@@ -0,0 +1,80 @@
1
+ body {
2
+ background-color: #fff;
3
+ color: #333;
4
+ margin: 33px;
5
+ }
6
+
7
+ body, p, ol, ul, td {
8
+ font-family: verdana, arial, helvetica, sans-serif;
9
+ font-size: 13px;
10
+ line-height: 18px;
11
+ }
12
+
13
+ pre {
14
+ background-color: #eee;
15
+ padding: 10px;
16
+ font-size: 11px;
17
+ }
18
+
19
+ a {
20
+ color: #000;
21
+ }
22
+
23
+ a:visited {
24
+ color: #666;
25
+ }
26
+
27
+ a:hover {
28
+ color: #fff;
29
+ background-color: #000;
30
+ }
31
+
32
+ th {
33
+ padding-bottom: 5px;
34
+ }
35
+
36
+ td {
37
+ padding: 0 5px 7px;
38
+ }
39
+
40
+ div.field,
41
+ div.actions {
42
+ margin-bottom: 10px;
43
+ }
44
+
45
+ #notice {
46
+ color: green;
47
+ }
48
+
49
+ .field_with_errors {
50
+ padding: 2px;
51
+ background-color: red;
52
+ display: table;
53
+ }
54
+
55
+ #error_explanation {
56
+ width: 450px;
57
+ border: 2px solid red;
58
+ padding: 7px 7px 0;
59
+ margin-bottom: 20px;
60
+ background-color: #f0f0f0;
61
+ }
62
+
63
+ #error_explanation h2 {
64
+ text-align: left;
65
+ font-weight: bold;
66
+ padding: 5px 5px 5px 15px;
67
+ font-size: 12px;
68
+ margin: -7px -7px 0;
69
+ background-color: #c00;
70
+ color: #fff;
71
+ }
72
+
73
+ #error_explanation ul li {
74
+ font-size: 12px;
75
+ list-style: square;
76
+ }
77
+
78
+ label {
79
+ display: block;
80
+ }
@@ -0,0 +1,11 @@
1
+ module BeetleReporter
2
+ class ApplicationController < ActionController::Base
3
+ include ActionView::RecordIdentifier
4
+
5
+ include Pagy::Backend
6
+
7
+ def current_user
8
+ main_app.scope.request.env['warden']&.user
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ require_dependency "beetle_reporter/application_controller"
2
+
3
+ module BeetleReporter
4
+ class HomeController < ApplicationController
5
+ def index
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,166 @@
1
+ module BeetleReporter
2
+ class ReportsController < BeetleReporter::ApplicationController
3
+ before_action :load_report, only: %w[show edit update destroy ignore undo suspend hide remove mute forbid]
4
+
5
+ def index
6
+ # authorize Report
7
+
8
+ load_reports
9
+
10
+ # skip_policy_scope
11
+ end
12
+
13
+ def show
14
+ # authorize @report
15
+ end
16
+
17
+ def new
18
+ # authorize Report
19
+
20
+ @report = Report.new
21
+ end
22
+
23
+ def create
24
+ # authorize Report
25
+
26
+ create_params = report_params.to_hash.deep_symbolize_keys
27
+ @report = report_scope.new(create_params)
28
+ @report.user = current_user
29
+
30
+ respond_to do |format|
31
+ if @report.save
32
+ format.turbo_stream { render turbo_stream: turbo_stream.replace(dom_id(@report), partial: "report", locals: {report: @report}) }
33
+ format.html { redirect_to reports_path, notice: "report was successfully created." }
34
+ else
35
+ format.html { render :edit, status: :unprocessable_entity }
36
+ end
37
+ end
38
+ end
39
+
40
+ def edit
41
+ # authorize @report
42
+ end
43
+
44
+ def update
45
+ # authorize @report
46
+
47
+ update_params = report_params.to_hash.deep_symbolize_keys
48
+
49
+ respond_to do |format|
50
+ if @report.update(update_params)
51
+ format.turbo_stream { render turbo_stream: turbo_stream.replace(dom_id(@report), partial: "report", locals: {report: @report}) }
52
+ format.html { redirect_to reports_path, notice: "report was successfully updated." }
53
+ else
54
+ format.html { render :edit, status: :unprocessable_entity }
55
+ end
56
+ end
57
+ end
58
+
59
+ def destroy
60
+ # authorize @report
61
+
62
+ @report.discard
63
+
64
+ respond_to do |format|
65
+ format.turbo_stream
66
+ end
67
+ end
68
+
69
+ def ignore
70
+ @report.ignore!
71
+
72
+ respond_to do |format|
73
+ format.turbo_stream { render turbo_stream: turbo_stream.remove(dom_id(@report)) }
74
+ format.html { redirect_to reports_url, notice: 'report was successfully ignored.' }
75
+ end
76
+ end
77
+
78
+ def suspend
79
+ @report.suspend!
80
+
81
+ respond_to do |format|
82
+ format.turbo_stream { render turbo_stream: turbo_stream.remove(dom_id(@report)) }
83
+ format.html { redirect_to reports_url, notice: 'report was successfully suspended.' }
84
+ end
85
+ end
86
+
87
+ def hide
88
+ @report.beetle_hide(params[:reason])
89
+
90
+ respond_to do |format|
91
+ format.turbo_stream { render turbo_stream: turbo_stream.remove(dom_id(@report)) }
92
+ format.html { redirect_to reports_url, notice: 'report was successfully hidden.' }
93
+ end
94
+ end
95
+
96
+ def remove
97
+ @report.beetle_remove(params[:reason])
98
+
99
+ respond_to do |format|
100
+ format.turbo_stream { render turbo_stream: turbo_stream.remove(dom_id(@report)) }
101
+ format.html { redirect_to reports_url, notice: 'report was successfully removed.' }
102
+ end
103
+ end
104
+
105
+ def mute
106
+ # TODO: 禁言时间
107
+ @report.beetle_mute(params[:reason])
108
+
109
+ respond_to do |format|
110
+ format.turbo_stream { render turbo_stream: turbo_stream.remove(dom_id(@report)) }
111
+ format.html { redirect_to reports_url, notice: 'report was successfully muted.' }
112
+ end
113
+ end
114
+
115
+ def forbid
116
+ @report.beetle_forbid(params[:reason])
117
+
118
+ respond_to do |format|
119
+ format.turbo_stream { render turbo_stream: turbo_stream.remove(dom_id(@report)) }
120
+ format.html { redirect_to reports_url, notice: 'report was successfully forbiden.' }
121
+ end
122
+ end
123
+
124
+ def undo
125
+ @report.undo!
126
+
127
+ respond_to do |format|
128
+ format.turbo_stream { render turbo_stream: turbo_stream.remove(dom_id(@report)) }
129
+ format.html { redirect_to reports_url, notice: 'report was successfully undo.' }
130
+ end
131
+ end
132
+
133
+ private
134
+
135
+ def load_reports
136
+ builder = report_scope.includes(:record)
137
+ builder = builder.where("reason ilike ?", "%#{params[:q]}%") if params[:q].present?
138
+
139
+ if params[:filter] != 'all'
140
+ builder = builder.pending
141
+ builder = builder.unscope(where: :aasm_state).where(aasm_state: params[:state]) if params[:state].present?
142
+ end
143
+ builder = builder.where(record_type: params[:type]&.classify) if params[:type].present?
144
+
145
+ builder = builder.order(id: :desc, reported_count: :desc)
146
+ builder = builder.reorder(updated_at: :desc) if params[:order] == 'last_updated'
147
+ builder = builder.reorder(created_at: :desc) if params[:order] == 'last_created'
148
+ builder = builder.reorder(updated_at: :asc) if params[:order] == 'oldest_updated'
149
+ builder = builder.reorder(created_at: :asc) if params[:order] == 'oldest_created'
150
+
151
+ @pagy, @reports = pagy(builder)
152
+ end
153
+
154
+ def load_report
155
+ @report = report_scope.find(params[:id] || params[:report_id])
156
+ end
157
+
158
+ def report_scope
159
+ BeetleReporter::Report.kept
160
+ end
161
+
162
+ def report_params
163
+ params.require(:report).permit(:id, :record_id, :record_type, :reason, :user_id, :device_id)
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,9 @@
1
+ module BeetleReporter
2
+ module ApplicationHelper
3
+ include Pagy::Frontend
4
+
5
+ def current_user
6
+ main_app.scope.request.env['warden']&.user
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ module BeetleReporter
2
+ module HomeHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module BeetleReporter
2
+ module ReportsHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module BeetleReporter
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module BeetleReporter
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: 'from@example.com'
4
+ layout 'mailer'
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module BeetleReporter
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,123 @@
1
+ module BeetleReporter
2
+ class Report < ApplicationRecord
3
+ include AASM
4
+ include Discard::Model
5
+
6
+ REASON_TYPES = %w(垃圾广告营销 侮辱谩骂内容 淫秽色情内容 涉政敏感信息 违法有害信息 内容令人不适 内容存在错误)
7
+
8
+ belongs_to :record, polymorphic: true, required: false
9
+ belongs_to :user, class_name: BeetleReporter.config.user_class, optional: true
10
+
11
+ aasm do
12
+ state :pending, initial: true
13
+ state :ignored, :hidden, :removed, :muted, :forbiden, :suspended
14
+
15
+ event :ignore do
16
+ transitions from: :pending, to: :ignored
17
+ end
18
+
19
+ event :hide do
20
+ transitions from: %i[pending ignored], to: :hidden, after: Proc.new {|*args| set_reason(*args) }
21
+ end
22
+
23
+ event :remove do
24
+ transitions from: %i[pending ignored], to: :removed, after: Proc.new {|*args| set_reason(*args) }
25
+ end
26
+
27
+ event :mute do
28
+ transitions from: %i[pending ignored], to: :muted, after: Proc.new {|*args| set_reason(*args) }
29
+ end
30
+
31
+ event :forbid do
32
+ transitions from: %i[pending muted], to: :forbiden, after: Proc.new {|*args| set_reason(*args) }
33
+ end
34
+
35
+ event :suspend do
36
+ transitions from: :pending, to: :suspended
37
+ end
38
+
39
+ event :undo do
40
+ transitions from: %i[ignored hidden removed muted forbiden suspended], to: :pending, after: :undo_callback
41
+ end
42
+ end
43
+
44
+ def beetle_hide(reason)
45
+ return if record.blank?
46
+ raise NoMethodError unless record.respond_to?(:beetle_hide)
47
+
48
+ ret = record.beetle_hide
49
+ hide!(reason) if ret
50
+ end
51
+
52
+ def beetle_remove(reason)
53
+ return if record.blank?
54
+ raise NoMethodError unless record.respond_to?(:beetle_remove)
55
+
56
+ ret = record.beetle_remove
57
+ remove!(reason) if ret
58
+ end
59
+
60
+ def beetle_mute(reason)
61
+ return if record.blank?
62
+ return if record&.user.blank?
63
+ raise NoMethodError unless record.respond_to?(:beetle_mute)
64
+
65
+ ret = record.beetle_mute
66
+ mute!(reason) if ret
67
+ end
68
+
69
+ def beetle_mute(reason)
70
+ return if record.blank?
71
+ return if record&.user.blank?
72
+ raise NoMethodError unless record.respond_to?(:beetle_mute)
73
+
74
+ ret = record.beetle_mute
75
+ mute!(reason) if ret
76
+ end
77
+
78
+ def beetle_forbid(reason)
79
+ return if record.blank?
80
+ return if record&.user.blank?
81
+ raise NoMethodError unless record.respond_to?(:beetle_forbid)
82
+
83
+ ret = record.beetle_forbid
84
+ forbid!(reason) if ret
85
+ end
86
+
87
+ def record_path
88
+ return '#' if record.blank?
89
+
90
+ record.beetle_record_path
91
+ end
92
+
93
+ def record_partial_path
94
+ record.beetle_record_partial_path
95
+ end
96
+
97
+ def undo_callback
98
+ if hidden?
99
+ ret = record.beetle_undo_hide
100
+ update_columns(reason: nil) if ret
101
+ elsif removed?
102
+ ret = record.beetle_undo_remove
103
+ update_columns(reason: nil) if ret
104
+ elsif muted?
105
+ ret = record.beetle_undo_mute
106
+ update_columns(reason: nil) if ret
107
+ elsif forbiden?
108
+ ret = record.beetle_undo_forbid
109
+ update_columns(reason: nil) if ret
110
+ else
111
+ update_columns(reason: nil)
112
+ end
113
+ end
114
+
115
+ def set_reason(reason)
116
+ update_columns(reason: reason)
117
+ end
118
+
119
+ def self.record_type_options
120
+ select(:record_type).where.not(record_type: nil).distinct.map{|t| [t.record_type, t.record_type.downcase]}
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,4 @@
1
+ %h1{class: "text-red-400 text-xl"} Home#index
2
+ %p Find me in app/views/beetle_reporter/home/index.html.erb2
3
+
4
+ %div=link_to "举报中心", reports_path
@@ -0,0 +1,14 @@
1
+ - url = report&.id.blank? ? reports_path : report_path(report)
2
+
3
+ = form_with(model: report, id: dom_id(report), url: url, local: true ) do |form|
4
+ - if report.errors.any?
5
+ %h2= "#{pluralize(report.errors.count, "error")} prohibited this report from being saved:"
6
+ %ul
7
+ - report.errors.each do |error|
8
+ %li= error.full_message
9
+ %div{class: "space-y-2"}
10
+ %div
11
+ %div{class: "text-gray-500 text-xs"}= form.label :reason, "举报原因"
12
+ %div= form.text_field :reason, class: "border p-1 w-full rounded-md"
13
+ %div
14
+ %div= form.submit "确认", class: "px-2 py-0.5 rounded-md bg-gray-800 text-white"
@@ -0,0 +1,55 @@
1
+ = turbo_frame_tag dom_id(report) do
2
+ %div{class: "flex flex-col space-y-2 border rounded-md p-2 mt-2"}
3
+ %div{class: "flex justify-between text-xs"}
4
+ %span{class: "space-x-2"}
5
+ - unless report.record.blank?
6
+ = link_to report.record_path, data: { turbo: false }, target: "_blank" do
7
+ %span{class: "bg-indigo-100 text-indigo-600 py-1 px-2 rounded-lg"}="#{report.record_type.upcase}##{report.record_id}"
8
+ %span{class: "bg-yellow-100 text-yellow-600 rounded-md p-1"}=t("beetle_reporter.aasm_state.#{report.aasm_state}")
9
+ - unless report.reasons.blank?
10
+ - report.reasons.each do |reason|
11
+ %span{class: "border border-red-600 text-red-600 rounded-lg text-xs p-0.5"}= reason
12
+ %span{class: "flex space-x-2 items-center text-sm"}
13
+ - if report.reason
14
+ %span{class: "bg-red-100 text-red-600 p-1 rounded-lg"}= "处置原因:#{report.reason}"
15
+ %span{class: "space-x-1"}
16
+ - report.user_ids.compact.uniq.each do |uid|
17
+ = link_to main_app.send(BeetleReporter.config.main_app_user_path_method.to_sym, uid), data: {turbo: false} do
18
+ %span{class: "bg-blue-100 rounded-lg px-1 py-0.5"}= "#{uid}"
19
+ %span{class: "bg-red-600 text-white rounded-full w-5 h-5 flex justify-center items-center"}= "#{report.reported_count}"
20
+ %span{class: "bg-gray-100 text-gray-600 py-1 px-2 rounded-lg"}
21
+ = link_to report.created_at, report_path(report), data: {turbo: false}
22
+ - unless current_user&.admin?
23
+ = button_to '删除', report, method: :delete, data: { confirm: 'Are you sure?'}, class: "bg-red-600 text-white rounded-md px-2 py-0.5 cursor-pointer"
24
+ %div{class: "flex justify-between items-center py-2 w-full"}
25
+ %div{class: "flex flex-col rounded-lg bg-gray-50 p-3 text-sm space-y-4 w-full"}
26
+ - unless report.record
27
+ %h3{class: "text-2xl text-red-600 flex items-center"}
28
+ 对应条目已被永久删除,当前审核请求已无效
29
+ =button_to "点我删除", report, method: :delete, class: "ml-2 bg-yellow-500 text-white rounded-lg px-2 py-0.5 cursor-pointer"
30
+ - else
31
+ = render report.record_partial_path, record: report.record
32
+ %div{class: "flex flex-col space-y-2"}
33
+ - if report.may_ignore?
34
+ = button_to "无效举报", report_ignore_path(report), class: "text-yellow-600 cursor-pointer px-2 py-0.5 bg-gray-100 rounded-lg"
35
+ - if report.may_suspend?
36
+ = button_to "暂缓处理", report_suspend_path(report), class: "text-indigo-600 cursor-pointer px-2 py-0.5 bg-gray-100 rounded-lg"
37
+ - if report.may_undo?
38
+ = button_to "撤销", report_undo_path(report), class: "text-red-600 cursor-pointer px-2 py-0.5 bg-gray-100 rounded-lg"
39
+ - if report.may_hide?
40
+ = form_with(url: report_hide_path(report), class: "space-x-1 flex items-center") do |f|
41
+ = f.text_field :reason, value: report.reason, placeholder: "隐藏原因是什么?", class: "border rounded-md m py-0.5 px-1"
42
+ = f.submit "隐藏内容", class: "bg-red-500 text-white cursor-pointer px-2 py-0.5 bg-gray-100 rounded-lg"
43
+ - if report.may_remove?
44
+ = form_with(url: report_remove_path(report), class: "space-x-1 flex items-center") do |f|
45
+ = f.text_field :reason, value: report.reason, placeholder: "删除原因是什么?", class: "border rounded-md m py-0.5 px-1"
46
+ = f.submit "删除内容", class: "bg-red-600 text-white cursor-pointer px-2 py-0.5 bg-gray-100 rounded-lg"
47
+ - if report.may_mute?
48
+ = form_with(url: report_mute_path(report), class: "space-x-1 flex items-center") do |f|
49
+ -# = f.text_field :mute_days, value: report.mute_days, placeholder: "禁言天数", class: "border rounded-md m py-0.5 px-1"
50
+ = f.text_field :reason, value: report.reason, placeholder: "禁言原因是什么?", class: "border rounded-md m py-0.5 px-1"
51
+ = f.submit "禁言用户", class: "bg-red-700 text-white cursor-pointer px-2 py-0.5 bg-gray-100 rounded-lg"
52
+ - if report.may_forbid?
53
+ = form_with(url: report_forbid_path(report), class: "space-x-1 flex items-center") do |f|
54
+ = f.text_field :reason, value: report.reason, placeholder: "封禁原因是什么?", class: "border rounded-md m py-0.5 px-1"
55
+ = f.submit "封禁用户", class: "bg-red-800 text-white cursor-pointer px-2 py-0.5 bg-gray-100 rounded-lg"
@@ -0,0 +1 @@
1
+ = turbo_stream.remove(@report)
@@ -0,0 +1,6 @@
1
+ = turbo_frame_tag dom_id(@report) do
2
+ %div{class: "bg-gray-100 p-2 rounded-lg"}
3
+ %div{class: "flex justify-between"}
4
+ %div{class: "text-lg font-bold"} 编辑
5
+ %div= link_to '返回', reports_path, class: "text-gray-500"
6
+ = render 'form', report: @report
@@ -0,0 +1,38 @@
1
+ %div{class: "flex flex-col space-y-2 justify-center"}
2
+ %div{class: "flex justify-between"}
3
+ %div
4
+ = form_with(url: reports_path, method: :get, class: "flex items-center") do |f|
5
+ %div{class: "space-x-0.5"}
6
+ = f.text_field :q, value: params[:q], placeholder: "关键词", class: "border rounded-md m py-0.5 px-1"
7
+ = f.select :type, options_for_select(BeetleReporter::Report.record_type_options, params[:type]), {include_blank: "-- 筛选 --"}, class: "border rounded-md m py-0.5 px-1"
8
+ = f.select :order, options_for_select([%w[按最近创建 last_created], %w[按最晚创建 oldest_created]], params[:order]), {include_blank: "-- 排序 --"}, class: "border rounded-md m py-0.5 px-1"
9
+ = f.hidden_field :state, value: params[:state]
10
+ = f.hidden_field :filter, value: params[:filter]
11
+ = f.submit "检索", class: "rounded-md px-2 py-1 text-sm bg-black text-white cursor-pointer"
12
+ = link_to "重置", reports_path, class: "text-sm"
13
+ %div{class: "flex items-center space-x-2"}
14
+ %div{class: "text-sm text-gray-600"}="共 #{@pagy.count} 条"
15
+ %div{class: "bg-gray-200 rounded-full px-3 py-1 text-xs #{params[:state].blank? && params[:filter].blank? ? 'font-bold' : ''}"}
16
+ = link_to "待处理", request.params.merge(state: "", filter: "")
17
+ %div{class: "bg-gray-200 rounded-full px-3 py-1 text-xs #{params[:state] == 'ignored' ? 'font-bold' : ''}"}
18
+ = link_to "无效举报", request.params.merge(state: "ignored", filter: "")
19
+ %div{class: "bg-gray-200 rounded-full px-3 py-1 text-xs #{params[:state] == 'hidden' ? 'font-bold' : ''}"}
20
+ = link_to "已隐藏", request.params.merge(state: "hidden", filter: "")
21
+ %div{class: "bg-gray-200 rounded-full px-3 py-1 text-xs #{params[:state] == 'removed' ? 'font-bold' : ''}"}
22
+ = link_to "已删除", request.params.merge(state: "removed", filter: "")
23
+ %div{class: "bg-gray-200 rounded-full px-3 py-1 text-xs #{params[:state] == 'muted' ? 'font-bold' : ''}"}
24
+ = link_to "已禁言用户", request.params.merge(state: "muted", filter: "")
25
+ %div{class: "bg-gray-200 rounded-full px-3 py-1 text-xs #{params[:state] == 'forbiden' ? 'font-bold' : ''}"}
26
+ = link_to "已封禁用户", request.params.merge(state: "forbiden", filter: "")
27
+ %div{class: "bg-gray-200 rounded-full px-3 py-1 text-xs #{params[:state] == 'suspended' ? 'font-bold' : ''}"}
28
+ = link_to "暂缓处理", request.params.merge(state: "suspended", filter: "")
29
+ %div{class: "bg-gray-200 rounded-full px-3 py-1 text-xs #{params[:filter] == "all" ? 'font-bold' : ''}"}
30
+ = link_to "全部", request.params.merge(filter: "all", state: "")
31
+ %div
32
+ - if @reports.blank?
33
+ %div{class: "flex justify-center text-gray-500 p-8 border rounded-md"} 空空如也
34
+ - else
35
+ - @reports.each do |report|
36
+ = render report
37
+ %div{class: "flex justify-center mt-2"}
38
+ = raw pagy_nav(@pagy)
@@ -0,0 +1,5 @@
1
+ %div{class: "bg-gray-100 p-2 rounded-lg"}
2
+ %div{class: "flex justify-between"}
3
+ %div{class: "text-lg font-bold"} 添加
4
+ %div= link_to '返回', reports_path, class: "text-gray-500"
5
+ = render 'form', report: @report
@@ -0,0 +1 @@
1
+ = render @report
@@ -0,0 +1,22 @@
1
+ !!! 5
2
+ %html
3
+ %head
4
+ %title 🐞 举报中心
5
+ = csrf_meta_tags
6
+ = csp_meta_tag
7
+ = stylesheet_link_tag "beetle_reporter/application", media: "all"
8
+ = javascript_include_tag "turbo", type: "module"
9
+ = yield :head
10
+ %body{class: "flex flex-col space-y-6 p-4"}
11
+ %div{class: "flex justify-between items-center"}
12
+ %h2{class: "text-xl bg-black text-white rounded-full py-1 px-4 cursor-pointer"}
13
+ %span{class: "shadow-lg"} 🐞
14
+ %span 举报中心
15
+
16
+ %ul{class: "flex justify-end items-center space-x-2 text-blue-600"}
17
+ %li= link_to "待处理(#{BeetleReporter::Report.pending.count})", reports_path
18
+ %li= link_to "控制台", main_app.send(BeetleReporter.config.main_app_root_path_method.to_sym)
19
+ %li= current_user.email
20
+
21
+ %div
22
+ = yield
@@ -0,0 +1,18 @@
1
+ "zh-CN":
2
+ beetle_reporter:
3
+ action:
4
+ mod: 审核
5
+ banned: 禁用
6
+ ignore: 忽略
7
+ replace: 替换
8
+ block: 禁用
9
+ pass: 忽略
10
+ review: 审核
11
+ aasm_state:
12
+ pending: 待审
13
+ suspended: 暂缓处理
14
+ ignored: 无效举报
15
+ hidden: 已隐藏
16
+ removed: 已删除
17
+ muted: 已禁言用户
18
+ forbiden: 已封禁用户
data/config/routes.rb ADDED
@@ -0,0 +1,13 @@
1
+ BeetleReporter::Engine.routes.draw do
2
+ resources :reports do
3
+ post :ignore
4
+ post :undo
5
+ post :suspend
6
+ post :hide
7
+ post :remove
8
+ post :mute
9
+ post :forbid
10
+ end
11
+
12
+ root "reports#index"
13
+ end
@@ -0,0 +1,20 @@
1
+ class CreateBeetleReporterReports < ActiveRecord::Migration[6.1]
2
+ def change
3
+ create_table :beetle_reporter_reports do |t|
4
+ t.bigint :record_id
5
+ t.string :record_type
6
+ t.string :reason
7
+ t.bigint :user_id
8
+ t.bigint :user_ids, array: true, default: []
9
+ t.string :reasons, array: true, default: []
10
+ t.integer :reported_count, default: 0
11
+ t.string :device_id
12
+ t.string :aasm_state
13
+ t.string :treatment_reason
14
+ t.datetime :discarded_at
15
+
16
+ t.timestamps
17
+ end
18
+ add_index :beetle_reporter_reports, :discarded_at
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ module BeetleReporter
2
+ class Configuration
3
+ attr_accessor :user_class
4
+ attr_accessor :current_user_method
5
+ attr_accessor :user_name_method
6
+ attr_accessor :main_app_root_path_method
7
+ attr_accessor :main_app_user_path_method
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module BeetleReporter
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace BeetleReporter
4
+
5
+ initializer "beetle_reporter.assets.precompile" do |app|
6
+ app.config.assets.precompile += %w( beetle_reporter/application.css )
7
+ end
8
+ end
9
+ end