censor_bear 0.1.14 → 0.1.15
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.
- checksums.yaml +4 -4
- data/README.md +19 -1
- data/app/controllers/censor_bear/mod_logs_controller.rb +21 -21
- data/app/models/censor_bear/mod_log.rb +39 -16
- data/app/views/censor_bear/mod_logs/_mod_log.html.haml +42 -37
- data/app/views/censor_bear/mod_logs/index.html.haml +12 -2
- data/config/locales/censor_bear.yml +4 -0
- data/config/routes.rb +4 -3
- data/db/migrate/20211209113710_add_aasm_state_to_censor_bear_mod_logs.rb +5 -0
- data/lib/censor_bear/version.rb +1 -1
- data/lib/censor_bear.rb +1 -0
- metadata +16 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 775cd9c238b951f9b9d5ce8564ae76e3e4b5d38fb3e9b71dc599d6a75bc04f5e
|
4
|
+
data.tar.gz: f8daa1001d2682697143aec92e6098d1e291d3c4d8cb7c9d28f60455fee7e6b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3bd8ea39fb05994a01083fdaf574501657bf085238a1c9a24b883bddadf374a8a441f910a95594f7a42081d981a2800b9b2b02c9b3cc578e200536faa52ed4b8
|
7
|
+
data.tar.gz: 6ee79015b14bf37b4f070e041c91738d906bb3d1f8c39b215a94ccf6fbe89ccc0816a9d919e1436ee3689b3bb62bd9be2df1a025afbe1090e09ee9bf0be1022d
|
data/README.md
CHANGED
@@ -50,10 +50,12 @@ rails censor_bear:install:migrations
|
|
50
50
|
|
51
51
|
## 🦆 Methods
|
52
52
|
```ruby
|
53
|
-
|
53
|
+
censor_remove # 删除内容
|
54
|
+
censor_cancel # 撤销删除
|
54
55
|
censor_approve # 通过审核
|
55
56
|
censor_show_path # 详情路由
|
56
57
|
censor_ban_user # 封禁用户
|
58
|
+
|
57
59
|
```
|
58
60
|
|
59
61
|
## Exceptions
|
@@ -63,6 +65,22 @@ censor_ban_user # 封禁用户
|
|
63
65
|
class NotPassedException < StandardError; end
|
64
66
|
```
|
65
67
|
|
68
|
+
## 初始化配置
|
69
|
+
详细配置项可在`lib/censor_bear/configuration.rb`中查看。
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
CensorBear.configure do |config|
|
73
|
+
config.user_class = 'User'
|
74
|
+
config.user_name_method = 'nickname'
|
75
|
+
|
76
|
+
config.aliyun_green_access_key_id = 'access key id'
|
77
|
+
config.aliyun_green_access_key_secret = 'access key secret'
|
78
|
+
config.aliyun_green_enable_internal = false
|
79
|
+
|
80
|
+
config.main_app_root_path_method = 'root_path'
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
66
84
|
## 注意事项
|
67
85
|
1. 为 MOD 时,表示需要人工审核,需要被审查对象(UGC内容)支持`is_approved`字段(默认为`true`),此时内容自己能看到,别人暂时看不到,需审核通过后可见。
|
68
86
|
2. 被审查对象可以通过软删实现,隐藏(目的是防止错判,撤销),删除的内容对自己和别人都是不可见的。
|
@@ -1,28 +1,23 @@
|
|
1
|
-
require_dependency
|
1
|
+
require_dependency 'censor_bear/application_controller'
|
2
2
|
|
3
3
|
module CensorBear
|
4
4
|
class ModLogsController < ApplicationController
|
5
|
-
before_action :set_mod_log, only: %i[show edit update destroy
|
5
|
+
before_action :set_mod_log, only: %i[show edit update destroy suspend ban pass undo reject]
|
6
6
|
|
7
|
-
# GET /mod_logs
|
8
7
|
def index
|
9
8
|
load_mod_logs
|
10
9
|
end
|
11
10
|
|
12
|
-
# GET /mod_logs/1
|
13
11
|
def show
|
14
12
|
end
|
15
13
|
|
16
|
-
# GET /mod_logs/new
|
17
14
|
def new
|
18
15
|
@mod_log = ModLog.new
|
19
16
|
end
|
20
17
|
|
21
|
-
# GET /mod_logs/1/edit
|
22
18
|
def edit
|
23
19
|
end
|
24
20
|
|
25
|
-
# POST /mod_logs
|
26
21
|
def create
|
27
22
|
@mod_log = ModLog.new(mod_log_params)
|
28
23
|
|
@@ -33,7 +28,6 @@ module CensorBear
|
|
33
28
|
end
|
34
29
|
end
|
35
30
|
|
36
|
-
# PATCH/PUT /mod_logs/1
|
37
31
|
def update
|
38
32
|
if @mod_log.update(mod_log_params)
|
39
33
|
redirect_to @mod_log, notice: 'Mod log was successfully updated.'
|
@@ -42,7 +36,6 @@ module CensorBear
|
|
42
36
|
end
|
43
37
|
end
|
44
38
|
|
45
|
-
# DELETE /mod_logs/1
|
46
39
|
def destroy
|
47
40
|
@mod_log.destroy
|
48
41
|
|
@@ -53,23 +46,29 @@ module CensorBear
|
|
53
46
|
end
|
54
47
|
|
55
48
|
|
56
|
-
def
|
49
|
+
def suspend
|
57
50
|
@mod_log.suspend!
|
58
51
|
|
59
52
|
redirect_to mod_logs_url, notice: 'Mod log was successfully ignored.'
|
60
53
|
end
|
61
54
|
|
62
|
-
def
|
63
|
-
|
64
|
-
@mod_log.delete(params[:reason])
|
55
|
+
def pass
|
56
|
+
@mod_log.approve
|
65
57
|
|
66
|
-
redirect_to mod_logs_url, notice: 'Mod log was successfully
|
58
|
+
redirect_to mod_logs_url, notice: 'Mod log was successfully ignored.'
|
67
59
|
end
|
68
60
|
|
69
|
-
def
|
70
|
-
|
61
|
+
def undo
|
62
|
+
# TODO: 判断状态,确定是撤销通过呢还是撤销删除
|
63
|
+
@mod_log.cancel
|
64
|
+
|
65
|
+
redirect_to mod_logs_url, notice: 'Mod log was successfully ignored.'
|
66
|
+
end
|
67
|
+
|
68
|
+
def reject
|
69
|
+
@mod_log.remove(params[:reason])
|
71
70
|
|
72
|
-
redirect_to mod_logs_url, notice: 'Mod log was successfully
|
71
|
+
redirect_to mod_logs_url, notice: 'Mod log was successfully ignored.'
|
73
72
|
end
|
74
73
|
|
75
74
|
def ban
|
@@ -80,8 +79,11 @@ module CensorBear
|
|
80
79
|
|
81
80
|
def load_mod_logs
|
82
81
|
builder ||= mod_log_scope.includes(:record)
|
83
|
-
builder = builder.where(
|
84
|
-
|
82
|
+
builder = builder.where('content ilike ?', "%#{params[:q]}%") if params[:q].present?
|
83
|
+
if params[:filter] != 'all'
|
84
|
+
builder = builder.pending
|
85
|
+
builder = builder.unscope(where: :aasm_state).where(aasm_state: params[:state]) if params[:state].present?
|
86
|
+
end
|
85
87
|
builder = builder.order(id: :desc)
|
86
88
|
|
87
89
|
@pagy, @mod_logs = pagy(builder)
|
@@ -89,7 +91,6 @@ module CensorBear
|
|
89
91
|
|
90
92
|
private
|
91
93
|
|
92
|
-
# Use callbacks to share common setup or constraints between actions.
|
93
94
|
def set_mod_log
|
94
95
|
@mod_log = ModLog.find(params[:id] || params[:mod_log_id])
|
95
96
|
end
|
@@ -98,7 +99,6 @@ module CensorBear
|
|
98
99
|
ModLog
|
99
100
|
end
|
100
101
|
|
101
|
-
# Only allow a list of trusted parameters through.
|
102
102
|
def mod_log_params
|
103
103
|
params.require(:mod_log).permit(:record_id, :record_type, :mod_words, :user_id, :reason)
|
104
104
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module CensorBear
|
2
2
|
class ModLog < ApplicationRecord
|
3
|
-
|
3
|
+
include AASM
|
4
|
+
|
5
|
+
REASONS = %w(无 广告/SPAM 恶意灌水 违规内容 文不对题 重复发布 其它).freeze
|
4
6
|
belongs_to :record, polymorphic: true, required: false
|
5
7
|
|
6
8
|
def record_path
|
@@ -9,14 +11,14 @@ module CensorBear
|
|
9
11
|
record.censor_show_path
|
10
12
|
end
|
11
13
|
|
12
|
-
def
|
14
|
+
def remove(reason)
|
13
15
|
return if record.blank?
|
14
16
|
return if record.discarded?
|
15
17
|
# ugc内容需要开软删,便于撤销&查看统计,可以定时删除统计并删除软删内容,类似回收站机制
|
16
|
-
raise NoMethodError
|
18
|
+
raise NoMethodError, 'undefined censor_remove for record' unless record.respond_to?(:censor_remove)
|
17
19
|
|
18
|
-
ret = record.
|
19
|
-
|
20
|
+
ret = record.censor_remove
|
21
|
+
reject!(reason) if ret
|
20
22
|
end
|
21
23
|
|
22
24
|
def approve
|
@@ -24,7 +26,15 @@ module CensorBear
|
|
24
26
|
raise NoMethodError unless record.respond_to?(:censor_approve)
|
25
27
|
|
26
28
|
ret = record.censor_approve
|
27
|
-
|
29
|
+
pass! if ret
|
30
|
+
end
|
31
|
+
|
32
|
+
def cancel
|
33
|
+
return if record.blank?
|
34
|
+
raise NoMethodError unless record.respond_to?(:censor_cancel)
|
35
|
+
|
36
|
+
ret = record.censor_cancel
|
37
|
+
undo! if ret
|
28
38
|
end
|
29
39
|
|
30
40
|
def ban_user
|
@@ -32,23 +42,36 @@ module CensorBear
|
|
32
42
|
raise NoMethodError unless record.respond_to?(:censor_ban_user)
|
33
43
|
|
34
44
|
ret = record.censor_ban_user
|
35
|
-
|
45
|
+
reject!('已被封禁该用户') if ret
|
36
46
|
end
|
37
47
|
|
38
|
-
|
39
|
-
|
40
|
-
|
48
|
+
aasm do
|
49
|
+
state :pending, initial: true
|
50
|
+
state :rejected, :passed, :suspended
|
51
|
+
|
52
|
+
event :reject do
|
53
|
+
transitions from: %i[pending suspended], to: :rejected, after: Proc.new {|*args| set_reason(*args) }
|
54
|
+
end
|
55
|
+
|
56
|
+
event :pass do
|
57
|
+
transitions from: %i[pending suspended], to: :passed
|
58
|
+
end
|
59
|
+
|
60
|
+
event :suspend do
|
61
|
+
transitions from: :pending, to: :suspended, after: :unset_reason
|
62
|
+
end
|
41
63
|
|
42
|
-
|
43
|
-
|
64
|
+
event :undo do
|
65
|
+
transitions from: %i[passed rejected], to: :pending, after: :unset_reason
|
66
|
+
end
|
44
67
|
end
|
45
68
|
|
46
|
-
def
|
47
|
-
update_columns(
|
69
|
+
def unset_reason
|
70
|
+
update_columns(reason: nil)
|
48
71
|
end
|
49
72
|
|
50
|
-
def
|
51
|
-
update_columns(
|
73
|
+
def set_reason(reason)
|
74
|
+
update_columns(reason: reason)
|
52
75
|
end
|
53
76
|
end
|
54
77
|
end
|
@@ -2,44 +2,49 @@
|
|
2
2
|
%div{class: "flex flex-col"}
|
3
3
|
%div{class: "border rounded-md mb-2 p-2 flex flex-col space-y-1"}
|
4
4
|
%div{class: "flex justify-between"}
|
5
|
-
%div{class: ""}
|
5
|
+
%div{class: "text-sm"}
|
6
6
|
= link_to mod_log.record_path, data: { turbo: false }, target: "_blank" do
|
7
|
-
%span{class: "
|
8
|
-
-
|
9
|
-
|
10
|
-
%span{class: "text-sm bg-red-100 text-red-600 py-1 px-2 rounded-lg"}=t("censor_log.label.#{label}")
|
11
|
-
- unless mod_log.mod_words.blank?
|
12
|
-
- mod_log.mod_words.each do |word|
|
13
|
-
%span{class: "text-sm bg-yellow-100 text-yellow-600 py-1 px-2 rounded-lg"}="##{word}"
|
14
|
-
%span{class: "text-sm bg-gray-100 text-gray-600 py-1 px-2 rounded-lg"}= mod_log.created_at
|
15
|
-
%div{class: "flex space-x-2 items-center"}
|
7
|
+
%span{class: "bg-indigo-100 text-indigo-600 py-1 px-2 rounded-lg"}="#{mod_log.record_type.upcase}##{mod_log.record_id}"
|
8
|
+
%span{class: "bg-yellow-100 text-yellow-600 rounded-md p-1"}=t("censor_log.aasm_state.#{mod_log.aasm_state}")
|
9
|
+
%div{class: "flex space-x-2 items-center text-sm"}
|
16
10
|
- if mod_log.reason
|
17
11
|
%span{class: "bg-red-100 text-red-600 p-1 rounded-lg"}
|
18
12
|
= mod_log.reason
|
19
|
-
%span{class: "bg-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
%
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
13
|
+
%span{class: "bg-gray-100 text-gray-600 py-1 px-2 rounded-lg"}= mod_log.created_at
|
14
|
+
- if current_user.admin?
|
15
|
+
= button_to '删除', mod_log, method: :delete, data: { confirm: 'Are you sure?'}, class: "bg-red-600 text-white rounded-md px-2 py-0.5 cursor-pointer"
|
16
|
+
%div{class: "flex justify-between items-center py-2 w-full"}
|
17
|
+
%div{class: "flex flex-col rounded-lg bg-gray-50 p-3 text-sm space-y-4 w-full"}
|
18
|
+
-unless mod_log.record
|
19
|
+
%h3{class: "text-2xl text-red-600"} 对应条目已被永久删除,当前审核请求已无效,请删除
|
20
|
+
- else
|
21
|
+
%div
|
22
|
+
%span{class: "border border-pink-600 text-pink-600 rounded-lg text-xs p-0.5"}=mod_log.record.is_private ? "隐私" : "公开"
|
23
|
+
%span{class: "border border-blue-600 text-blue-600 rounded-lg text-xs p-0.5"}=mod_log.record.is_approved ? "审核通过" : "审核中..."
|
24
|
+
- if mod_log.record.discarded?
|
25
|
+
%div{class: "text-gray-900 leading-relaxed"}
|
26
|
+
%del= mod_log.record.content
|
27
|
+
- else
|
28
|
+
%div{class: "text-gray-900 leading-relaxed"}= mod_log.record.content
|
29
|
+
%div
|
30
|
+
- mod_log.record.pictures.each do |pic|
|
31
|
+
= image_tag pic.full_url, class: "w-16 rounded-md"
|
32
|
+
%div
|
33
|
+
- unless mod_log.labels.blank?
|
34
|
+
- mod_log.labels.each do |label|
|
35
|
+
%span{class: "text-xs bg-gray-200 text-gray-600 py-0.5 px-1 rounded-lg"}=t("censor_log.label.#{label}")
|
36
|
+
- unless mod_log.mod_words.blank?
|
37
|
+
- mod_log.mod_words.each do |word|
|
38
|
+
%span{class: "text-sm bg-gray-100 text-gray-600 py-0.5 px-1 rounded-lg"}="##{word}"
|
39
|
+
%div{class: "flex space-x-2 items-center justify-end"}
|
40
|
+
- if mod_log.may_suspend?
|
41
|
+
= link_to "忽略", mod_log_suspend_path(mod_log), class: "text-yellow-600 cursor-pointer"
|
42
|
+
- if mod_log.may_pass?
|
43
|
+
= link_to "通过", mod_log_pass_path(mod_log), class: "text-green-600 cursor-pointer"
|
44
|
+
- if mod_log.may_undo?
|
45
|
+
= link_to "撤销", mod_log_undo_path(mod_log), class: "text-red-600 cursor-pointer"
|
46
|
+
- if mod_log.may_reject?
|
47
|
+
= form_with(url: mod_log_reject_path(mod_log), method: :get, class: "space-x-1 flex items-center") do |f|
|
48
|
+
= f.submit "拒绝", class: "text-red-600 bg-transparent cursor-pointer"
|
49
|
+
= f.text_field :reason, value: mod_log.reason, placeholder: "不通过原因", class: "border rounded-md m py-0.5 px-1 text-sm"
|
50
|
+
|
@@ -6,8 +6,18 @@
|
|
6
6
|
= f.text_field :q, value: params[:q], placeholder: "关键词", class: "border rounded-md m py-0.5 px-1"
|
7
7
|
= f.submit "检索", class: "rounded-md px-2 py-1 text-sm bg-black text-white cursor-pointer"
|
8
8
|
= link_to "重置", mod_logs_path, class: "text-sm"
|
9
|
-
|
10
|
-
|
9
|
+
%div{class: "flex items-center space-x-2"}
|
10
|
+
%div{class: "text-sm text-gray-600"}="共 #{@pagy.count} 条"
|
11
|
+
%div{class: "bg-gray-200 rounded-full px-3 py-1 text-xs #{params[:filter] == "all" ? 'font-bold' : ''}"}
|
12
|
+
= link_to "全部", request.params.merge(filter: "all", state: "")
|
13
|
+
%div{class: "bg-gray-200 rounded-full px-3 py-1 text-xs #{params[:state].blank? && params[:filter].blank? ? 'font-bold' : ''}"}
|
14
|
+
= link_to "待处理", request.params.merge(state: "", filter: "")
|
15
|
+
%div{class: "bg-gray-200 rounded-full px-3 py-1 text-xs #{params[:state] == 'rejected' ? 'font-bold' : ''}"}
|
16
|
+
= link_to "被驳回", request.params.merge(state: "rejected", filter: "")
|
17
|
+
%div{class: "bg-gray-200 rounded-full px-3 py-1 text-xs #{params[:state] == 'passed' ? 'font-bold' : ''}"}
|
18
|
+
= link_to "通过", request.params.merge(state: "passed", filter: "")
|
19
|
+
%div{class: "bg-gray-200 rounded-full px-3 py-1 text-xs #{params[:state] == 'suspended' ? 'font-bold' : ''}"}
|
20
|
+
= link_to "暂缓处理", request.params.merge(state: "suspended", filter: "")
|
11
21
|
%div
|
12
22
|
- if @mod_logs.blank?
|
13
23
|
%div{class: "flex justify-center text-gray-500 p-8 border rounded-md"} 空空如也
|
data/config/routes.rb
CHANGED
data/lib/censor_bear/version.rb
CHANGED
data/lib/censor_bear.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: censor_bear
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 42up
|
@@ -30,6 +30,20 @@ dependencies:
|
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 6.0.4.1
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: aasm
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
33
47
|
- !ruby/object:Gem::Dependency
|
34
48
|
name: aliyun_green
|
35
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -169,6 +183,7 @@ files:
|
|
169
183
|
- db/migrate/20211206092626_add_ip_to_censor_bear_logs.rb
|
170
184
|
- db/migrate/20211208041114_add_labels_to_censor_bear_logs.rb
|
171
185
|
- db/migrate/20211209093050_add_response_to_censor_bear_logs.rb
|
186
|
+
- db/migrate/20211209113710_add_aasm_state_to_censor_bear_mod_logs.rb
|
172
187
|
- lib/censor_bear.rb
|
173
188
|
- lib/censor_bear/censor.rb
|
174
189
|
- lib/censor_bear/configuration.rb
|