censor_bear 0.1.4 → 0.1.8
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 +1 -1
- data/app/controllers/censor_bear/logs_controller.rb +28 -11
- data/app/controllers/censor_bear/mod_logs_controller.rb +30 -10
- data/app/models/censor_bear/log.rb +1 -0
- data/app/views/censor_bear/logs/_log.html.haml +37 -0
- data/app/views/censor_bear/logs/destroy.turbo_stream.haml +1 -0
- data/app/views/censor_bear/logs/index.html.haml +18 -0
- data/app/views/censor_bear/mod_logs/_mod_log.html.haml +45 -0
- data/app/views/censor_bear/mod_logs/destroy.turbo_stream.haml +1 -0
- data/app/views/censor_bear/mod_logs/index.html.haml +18 -0
- data/app/views/censor_bear/stop_words/_stop_word.html.haml +1 -1
- data/config/locales/censor_bear.yml +23 -1
- data/db/migrate/20211206092626_add_ip_to_censor_bear_logs.rb +6 -0
- data/db/migrate/20211208041114_add_labels_to_censor_bear_logs.rb +6 -0
- data/lib/censor_bear/censor.rb +99 -14
- data/lib/censor_bear/configuration.rb +4 -0
- data/lib/censor_bear/engine.rb +8 -0
- data/lib/censor_bear/version.rb +1 -1
- data/lib/censor_bear.rb +19 -5
- metadata +34 -14
- data/app/views/censor_bear/logs/index.html.erb +0 -37
- data/app/views/censor_bear/mod_logs/index.html.erb +0 -44
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4a5519d5695908f0b7d3316070221bb2350da7d5869d7c6f8f202d1cb5d3a903
|
|
4
|
+
data.tar.gz: aa507b18784d4472427dad1c694f1cf1a552b957c54ef89d66fd1e57faa73403
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b1b68d93591c793a14c52d19c8fdbadf601adb5c2c24ce7575f3da001bf8922e6ee074e2ee5f3873005fdb8c620dfc50f5d6527f9b646573d190f8823470a592
|
|
7
|
+
data.tar.gz: 5763a681a0dc9c7dcb813ccf6b8f997e8df5ea782fc64c928d6dd04d870ef5c46a5e662ad4de0e2b9f4b4da341b6f11be4fd7044c6c04afe1f69d0e542384e29
|
data/README.md
CHANGED
|
@@ -2,11 +2,11 @@ require_dependency "censor_bear/application_controller"
|
|
|
2
2
|
|
|
3
3
|
module CensorBear
|
|
4
4
|
class LogsController < ApplicationController
|
|
5
|
-
before_action :set_log, only: [
|
|
5
|
+
before_action :set_log, only: %i[show edit update destroy]
|
|
6
6
|
|
|
7
7
|
# GET /logs
|
|
8
8
|
def index
|
|
9
|
-
|
|
9
|
+
load_logs
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
# GET /logs/1
|
|
@@ -45,18 +45,35 @@ module CensorBear
|
|
|
45
45
|
# DELETE /logs/1
|
|
46
46
|
def destroy
|
|
47
47
|
@log.destroy
|
|
48
|
-
|
|
48
|
+
|
|
49
|
+
respond_to do |format|
|
|
50
|
+
format.turbo_stream
|
|
51
|
+
format.html { redirect_to logs_url, notice: 'Log was successfully destroyed.' }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def load_logs
|
|
56
|
+
builder ||= log_scope
|
|
57
|
+
builder = builder.where("original_content ilike ?", "%#{params[:q]}%") if params[:q].present?
|
|
58
|
+
builder = builder.order(id: :desc)
|
|
59
|
+
|
|
60
|
+
@pagy, @logs = pagy(builder)
|
|
49
61
|
end
|
|
50
62
|
|
|
51
63
|
private
|
|
52
|
-
# Use callbacks to share common setup or constraints between actions.
|
|
53
|
-
def set_log
|
|
54
|
-
@log = Log.find(params[:id])
|
|
55
|
-
end
|
|
56
64
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
# Use callbacks to share common setup or constraints between actions.
|
|
66
|
+
def set_log
|
|
67
|
+
@log = Log.find(params[:id])
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def log_scope
|
|
71
|
+
Log
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Only allow a list of trusted parameters through.
|
|
75
|
+
def log_params
|
|
76
|
+
params.require(:log).permit(:original_content, :action, :filtered_content, :mod_words)
|
|
77
|
+
end
|
|
61
78
|
end
|
|
62
79
|
end
|
|
@@ -2,10 +2,11 @@ require_dependency "censor_bear/application_controller"
|
|
|
2
2
|
|
|
3
3
|
module CensorBear
|
|
4
4
|
class ModLogsController < ApplicationController
|
|
5
|
-
before_action :set_mod_log, only: [
|
|
5
|
+
before_action :set_mod_log, only: %i[show edit update destroy ignore approve ban delete]
|
|
6
6
|
|
|
7
7
|
# GET /mod_logs
|
|
8
8
|
def index
|
|
9
|
+
load_mod_logs
|
|
9
10
|
@mod_logs = ModLog.pending.all
|
|
10
11
|
end
|
|
11
12
|
|
|
@@ -45,9 +46,14 @@ module CensorBear
|
|
|
45
46
|
# DELETE /mod_logs/1
|
|
46
47
|
def destroy
|
|
47
48
|
@mod_log.destroy
|
|
48
|
-
|
|
49
|
+
|
|
50
|
+
respond_to do |format|
|
|
51
|
+
format.turbo_stream
|
|
52
|
+
format.html { redirect_to mod_logs_url, notice: 'Mod log was successfully destroyed.' }
|
|
53
|
+
end
|
|
49
54
|
end
|
|
50
55
|
|
|
56
|
+
|
|
51
57
|
def ignore
|
|
52
58
|
@mod_log.suspend!
|
|
53
59
|
|
|
@@ -73,15 +79,29 @@ module CensorBear
|
|
|
73
79
|
redirect_to mod_logs_url, notice: 'successfully baned.'
|
|
74
80
|
end
|
|
75
81
|
|
|
82
|
+
def load_mod_logs
|
|
83
|
+
builder ||= mod_log_scope
|
|
84
|
+
builder = builder.where("content ilike ?", "%#{params[:q]}%") if params[:q].present?
|
|
85
|
+
|
|
86
|
+
builder = builder.order(id: :desc)
|
|
87
|
+
|
|
88
|
+
@pagy, @logs = pagy(builder)
|
|
89
|
+
end
|
|
90
|
+
|
|
76
91
|
private
|
|
77
|
-
# Use callbacks to share common setup or constraints between actions.
|
|
78
|
-
def set_mod_log
|
|
79
|
-
@mod_log = ModLog.find(params[:id] || params[:mod_log_id])
|
|
80
|
-
end
|
|
81
92
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
93
|
+
# Use callbacks to share common setup or constraints between actions.
|
|
94
|
+
def set_mod_log
|
|
95
|
+
@mod_log = ModLog.find(params[:id] || params[:mod_log_id])
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def mod_log_scope
|
|
99
|
+
ModLog
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Only allow a list of trusted parameters through.
|
|
103
|
+
def mod_log_params
|
|
104
|
+
params.require(:mod_log).permit(:record_id, :record_type, :mod_words, :user_id, :reason)
|
|
105
|
+
end
|
|
86
106
|
end
|
|
87
107
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
= turbo_frame_tag dom_id(log) do
|
|
2
|
+
%div{class: "flex flex-col"}
|
|
3
|
+
%div{class: "border rounded-md mb-2 p-2 flex flex-col space-y-1"}
|
|
4
|
+
%div{class: "flex justify-between"}
|
|
5
|
+
%div{class: ""}
|
|
6
|
+
- unless log.scenario.blank?
|
|
7
|
+
%span{class: "text-sm bg-blue-100 text-blue-600 py-1 px-2 rounded-lg"}= log.scenario.upcase
|
|
8
|
+
- unless log.stage.blank?
|
|
9
|
+
%span{class: "text-sm bg-pink-100 text-pink-600 py-1 px-2 rounded-lg"}=t("censor_log.stage.#{log.stage}")
|
|
10
|
+
- unless log.action.blank?
|
|
11
|
+
%span{class: "text-sm bg-yellow-100 text-yellow-600 py-1 px-2 rounded-lg"}=t("censor_log.action.#{log.action.downcase}")
|
|
12
|
+
- unless log.user_id.blank?
|
|
13
|
+
%span{class: "text-sm bg-gray-100 text-gray-600 py-1 px-2 rounded-lg font-bold"}="##{log.user_id}"
|
|
14
|
+
- unless log.ip.blank?
|
|
15
|
+
%span{class: "text-sm bg-gray-100 text-gray-600 py-1 px-2 rounded-lg"}=log.ip
|
|
16
|
+
- unless log.labels.blank?
|
|
17
|
+
- log.labels.each do |label|
|
|
18
|
+
%span{class: "text-sm bg-red-100 text-red-600 py-1 px-2 rounded-lg"}=t("censor_log.label.#{label}")
|
|
19
|
+
|
|
20
|
+
%span{class: "text-sm bg-gray-100 text-gray-600 py-1 px-2 rounded-lg"}= log.created_at
|
|
21
|
+
%div{class: "flex space-x-2 items-center"}
|
|
22
|
+
%span
|
|
23
|
+
= link_to '详情', log
|
|
24
|
+
%span
|
|
25
|
+
= button_to '删除', log, method: :delete, data: { confirm: 'Are you sure?' }, class: "text-red-600 rounded-md px-2 py-0.5"
|
|
26
|
+
%div{class: "flex justify-between items-center"}
|
|
27
|
+
%div{class: "flex flex-col"}
|
|
28
|
+
%div{class: ""}
|
|
29
|
+
%div= log.original_content
|
|
30
|
+
- if log.filtered_content
|
|
31
|
+
%div{class: "border-t"}
|
|
32
|
+
%div= log.filtered_content
|
|
33
|
+
%div{class: "text-yellow-500 font-meidum text-xl"}
|
|
34
|
+
- log.mod_words.each do |word|
|
|
35
|
+
%span [
|
|
36
|
+
%span= link_to word, stop_words_path(q: word)
|
|
37
|
+
%span ]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
= turbo_stream.remove(@log)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
%div{class: "flex flex-col space-y-2 justify-center"}
|
|
2
|
+
%div{class: "flex justify-between"}
|
|
3
|
+
%div
|
|
4
|
+
= form_with(url: mod_logs_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.submit "检索", class: "rounded-md px-2 py-1 text-sm bg-black text-white cursor-pointer"
|
|
8
|
+
= link_to "重置", mod_logs_path, class: "text-sm"
|
|
9
|
+
|
|
10
|
+
%div="共 #{@pagy.count} 条"
|
|
11
|
+
%div
|
|
12
|
+
- if @logs.blank?
|
|
13
|
+
%div{class: "flex justify-center text-gray-500 p-8 border rounded-md"} 空空如也
|
|
14
|
+
- else
|
|
15
|
+
- @logs.each do |log|
|
|
16
|
+
= render log
|
|
17
|
+
%div{class: "flex justify-center"}
|
|
18
|
+
= raw pagy_nav(@pagy)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
= turbo_frame_tag dom_id(mod_log) do
|
|
2
|
+
%div{class: "flex flex-col"}
|
|
3
|
+
%div{class: "border rounded-md mb-2 p-2 flex flex-col space-y-1"}
|
|
4
|
+
%div{class: "flex justify-between"}
|
|
5
|
+
%div{class: ""}
|
|
6
|
+
= link_to mod_log.record_path do
|
|
7
|
+
%span{class: "text-sm bg-indigo-100 text-indigo-600 py-1 px-2 rounded-lg"}="#{mod_log.record_type.upcase}##{mod_log.record_id}"
|
|
8
|
+
- unless mod_log.labels.blank?
|
|
9
|
+
- mod_log.labels.each do |label|
|
|
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"}
|
|
16
|
+
- if mod_log.reason
|
|
17
|
+
%span{class: "bg-red-100 text-red-600 p-1 rounded-lg"}
|
|
18
|
+
= mod_log.reason
|
|
19
|
+
%span{class: "bg-green-100 text-green-600 rounded-md p-1"}
|
|
20
|
+
- if mod_log.status == 0
|
|
21
|
+
= "待审"
|
|
22
|
+
- if mod_log.status == 1
|
|
23
|
+
= "已处理"
|
|
24
|
+
- if mod_log.status == 2
|
|
25
|
+
= "暂缓"
|
|
26
|
+
%span
|
|
27
|
+
= link_to "详情", mod_log
|
|
28
|
+
%span
|
|
29
|
+
= button_to '删除', mod_log, method: :delete, data: { confirm: 'Are you sure?'}, class: "text-red-600 rounded-md px-2 py-0.5"
|
|
30
|
+
%div{class: "flex justify-between items-center"}
|
|
31
|
+
%div{class: "flex flex-col"}
|
|
32
|
+
%div{class: "text-sm border rounded-lg border-black p-2"}
|
|
33
|
+
%div= mod_log.content
|
|
34
|
+
%div
|
|
35
|
+
%div{class: "flex space-x-2"}
|
|
36
|
+
%span{class: "text-yellow-600"}
|
|
37
|
+
= link_to "忽略", mod_log_ignore_path(mod_log)
|
|
38
|
+
%span{class: "text-green-600"}
|
|
39
|
+
= link_to "通过", mod_log_approve_path(mod_log)
|
|
40
|
+
%div
|
|
41
|
+
= form_with(url: mod_log_delete_path(mod_log), method: :get, class: "space-x-1 flex items-center") do |f|
|
|
42
|
+
= f.submit "删除", class: "rounded-md px-2 py-1 text-sm bg-red-600 text-white cursor-pointer"
|
|
43
|
+
= f.text_field :reason, value: mod_log.reason, placeholder: "不通过原因", class: "border rounded-md m py-0.5 px-1"
|
|
44
|
+
-#%span{class: "text-red-600 font-bold"}
|
|
45
|
+
-# = link_to "封禁用户!", mod_log_ban_path(mod_log)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
= turbo_stream.remove(@mod_log)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
%div{class: "flex flex-col space-y-2 justify-center"}
|
|
2
|
+
%div{class: "flex justify-between"}
|
|
3
|
+
%div
|
|
4
|
+
= form_with(url: logs_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.submit "检索", class: "rounded-md px-2 py-1 text-sm bg-black text-white cursor-pointer"
|
|
8
|
+
= link_to "重置", logs_path, class: "text-sm"
|
|
9
|
+
|
|
10
|
+
%div="共 #{@pagy.count} 条"
|
|
11
|
+
%div
|
|
12
|
+
- if @logs.blank?
|
|
13
|
+
%div{class: "flex justify-center text-gray-500 p-8 border rounded-md"} 空空如也
|
|
14
|
+
- else
|
|
15
|
+
- @logs.each do |log|
|
|
16
|
+
= render log
|
|
17
|
+
%div{class: "flex justify-center"}
|
|
18
|
+
= raw pagy_nav(@pagy)
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
%div{class: "text-center"}=I18n.t("censor_log.action.#{stop_word.dialog}")
|
|
25
25
|
%div{class: "text-gray-500 text-xs text-center"} 私信处理
|
|
26
26
|
%div{class: "flex flex-col justify-center border rounded-md p-1"}
|
|
27
|
-
%div{class: "text-center"}=stop_word.replacement
|
|
27
|
+
%div{class: "text-center"}=stop_word.replacement || "**"
|
|
28
28
|
%div{class: "text-gray-500 text-xs text-center"} 过滤词替换
|
|
29
29
|
%div{class: "flex justify-end space-x-2 text-sm text-blue-600"}
|
|
30
30
|
%span
|
|
@@ -4,4 +4,26 @@ en:
|
|
|
4
4
|
mod: 审核
|
|
5
5
|
banned: 禁用
|
|
6
6
|
ignore: 忽略
|
|
7
|
-
replace: 替换
|
|
7
|
+
replace: 替换
|
|
8
|
+
block: 禁用
|
|
9
|
+
pass: 忽略
|
|
10
|
+
review: 审核
|
|
11
|
+
stage:
|
|
12
|
+
aliyun_check: "阿里云检查"
|
|
13
|
+
tencent_check: "腾讯云检查"
|
|
14
|
+
local_check: "本地检查"
|
|
15
|
+
qq_regex: "QQ正则检查"
|
|
16
|
+
wechat_regex: "微信正则检查"
|
|
17
|
+
label:
|
|
18
|
+
normal: 正常文本
|
|
19
|
+
spam: 含垃圾信息
|
|
20
|
+
ad: 广告
|
|
21
|
+
politics: 涉政
|
|
22
|
+
terrorism: 暴恐
|
|
23
|
+
abuse: 辱骂
|
|
24
|
+
porn: 色情
|
|
25
|
+
flood: 灌水
|
|
26
|
+
contraband: 违禁
|
|
27
|
+
meaningless: 无意义
|
|
28
|
+
harmful: 不良场景
|
|
29
|
+
customized: 自定义
|
data/lib/censor_bear/censor.rb
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
module CensorBear
|
|
2
2
|
class Result
|
|
3
|
-
attr_accessor :is_mod, :mod_words, :content
|
|
3
|
+
attr_accessor :is_mod, :mod_words, :content, :labels
|
|
4
4
|
|
|
5
|
-
def initialize(content, is_mod = false, mod_words = [])
|
|
5
|
+
def initialize(content, is_mod = false, mod_words = [], labels = [])
|
|
6
6
|
@is_mod = is_mod
|
|
7
7
|
@mod_words = mod_words
|
|
8
|
+
@labels = labels
|
|
8
9
|
@content = content || ''
|
|
9
10
|
end
|
|
10
11
|
end
|
|
@@ -13,33 +14,57 @@ module CensorBear
|
|
|
13
14
|
QQ_REG = /(?:[加茄qQ企鹅号码\s]{1,}|[群号]{1,}|[叩叩]{1,}|[抠抠]{1,}|[扣扣]{1,})(?:[\u4e00-\u9eff]*)(?:[:,:]?)([\d\s]{6,})/
|
|
14
15
|
WX_REG = /(?:[加+微++➕薇?vV威卫星♥❤姓xX信]{2,}|weixin|weix)(?:[,❤️.\s]?)(?:[\u4e00-\u9eff]?)(?:[:,:]?)([\w\s]{6,})/
|
|
15
16
|
|
|
16
|
-
def initialize(content, type = 'ugc')
|
|
17
|
+
def initialize(content, type = 'ugc', options = {})
|
|
17
18
|
@is_mod = false
|
|
18
19
|
@mod_words = []
|
|
20
|
+
@labels = []
|
|
19
21
|
@content = content
|
|
20
22
|
@type = type.to_s
|
|
23
|
+
@options = options
|
|
24
|
+
@ip = options[:ip] || nil
|
|
25
|
+
@user_id = options[:user_id] || nil
|
|
21
26
|
end
|
|
22
27
|
|
|
23
28
|
def check_text
|
|
24
29
|
return Result.new(@content) if @content.blank?
|
|
25
30
|
return Result.new(@content) unless CensorBear::StopWord::FIELDS.include?(@type)
|
|
26
31
|
|
|
32
|
+
# 正则过滤
|
|
27
33
|
if @content.match(QQ_REG)
|
|
28
|
-
CensorBear.info(@content, @type, 'BANNED', 'qq_regex')
|
|
34
|
+
CensorBear.info(@content, @type, 'BANNED', 'qq_regex', ip: @ip, user_id: @user_id)
|
|
29
35
|
raise NotPassedException
|
|
30
36
|
end
|
|
31
37
|
|
|
32
38
|
if @content.match(WX_REG)
|
|
33
|
-
CensorBear.info(@content, @type, 'BANNED', 'wx_regex')
|
|
39
|
+
CensorBear.info(@content, @type, 'BANNED', 'wx_regex', ip: @ip, user_id: @user_id)
|
|
34
40
|
raise NotPassedException
|
|
35
41
|
end
|
|
36
42
|
|
|
43
|
+
# 本地自定义词库粗查
|
|
37
44
|
local_check
|
|
45
|
+
# 第三方云端复查
|
|
46
|
+
aliyun_check unless @is_mod
|
|
38
47
|
|
|
39
48
|
# 用户相关类型直接禁止创建
|
|
40
49
|
raise NotPassedException if @is_mod && %w[username signature dialog nickname].include?(@type)
|
|
41
50
|
|
|
42
|
-
Result.new(@content, @is_mod, @mod_words.uniq)
|
|
51
|
+
Result.new(@content, @is_mod, @mod_words.uniq, @labels.uniq)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# default type = :ugc
|
|
55
|
+
def check_search
|
|
56
|
+
flag = false
|
|
57
|
+
stop_words = CensorBear::StopWord.where("#{@type} != 'IGNORE'")
|
|
58
|
+
stop_words.each do |word|
|
|
59
|
+
finder = Regexp.new(Regexp.escape(word.key))
|
|
60
|
+
action = word.send(@type.to_sym).upcase
|
|
61
|
+
if finder.match(@content)
|
|
62
|
+
flag = true
|
|
63
|
+
CensorBear.info(@content, @type, action, 'check_search', mod_words: [word.key], ip: @ip, user_id: @user_id)
|
|
64
|
+
break
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
flag
|
|
43
68
|
end
|
|
44
69
|
|
|
45
70
|
def local_check
|
|
@@ -49,41 +74,101 @@ module CensorBear
|
|
|
49
74
|
finder = Regexp.new(Regexp.escape(word.key))
|
|
50
75
|
action = word.send(@type.to_sym).upcase
|
|
51
76
|
next unless finder.match(@content)
|
|
77
|
+
|
|
52
78
|
@mod_words.push(word.key)
|
|
53
79
|
case action
|
|
54
80
|
when 'REPLACE'
|
|
55
|
-
|
|
81
|
+
replacement = word.replacement.blank? ? '**' : word.replacement
|
|
82
|
+
@content = @content.gsub(finder, replacement)
|
|
56
83
|
CensorBear.info(
|
|
57
84
|
original_content, @type, action, 'local_check',
|
|
58
85
|
filtered_content: @content,
|
|
59
|
-
mod_words: [word.key]
|
|
86
|
+
mod_words: [word.key],
|
|
87
|
+
ip: @ip, user_id: @user_id
|
|
60
88
|
)
|
|
61
89
|
when 'MOD'
|
|
62
90
|
@is_mod = true
|
|
63
91
|
CensorBear.info(
|
|
64
92
|
original_content, @type, action, 'local_check',
|
|
65
93
|
filtered_content: nil,
|
|
66
|
-
mod_words: [word.key]
|
|
94
|
+
mod_words: [word.key],
|
|
95
|
+
ip: @ip, user_id: @user_id
|
|
67
96
|
)
|
|
68
97
|
when 'BANNED'
|
|
69
|
-
@is_mod = true
|
|
70
98
|
# 禁止的直接抛出异常
|
|
71
99
|
CensorBear.info(
|
|
72
100
|
original_content, @type, action, 'local_check',
|
|
73
101
|
filtered_content: nil,
|
|
74
|
-
mod_words: [word.key]
|
|
102
|
+
mod_words: [word.key],
|
|
103
|
+
ip: @ip, user_id: @user_id
|
|
75
104
|
)
|
|
76
105
|
raise NotPassedException
|
|
77
106
|
end
|
|
78
107
|
end
|
|
79
108
|
end
|
|
80
109
|
|
|
81
|
-
def
|
|
110
|
+
def aliyun_check
|
|
111
|
+
response = AliyunGreen::Text.scan(@content)
|
|
112
|
+
d = response['data'].first
|
|
113
|
+
r = d['results'].first
|
|
114
|
+
action = r['suggestion']
|
|
115
|
+
rate = r['rate']
|
|
116
|
+
@mod_words = concat_words(r['details'])
|
|
117
|
+
@labels = concat_labels(r['details'])
|
|
118
|
+
if action == 'block' && rate >= 70 && %w[politics terrorism abuse].include?(r['label'])
|
|
119
|
+
CensorBear.info(
|
|
120
|
+
d['content'], @type, action, 'aliyun_check',
|
|
121
|
+
filtered_content: d['filteredContent'],
|
|
122
|
+
mod_words: @mod_words,
|
|
123
|
+
labels: @labels,
|
|
124
|
+
ip: @ip, user_id: @user_id
|
|
125
|
+
)
|
|
126
|
+
raise NotPassedException
|
|
127
|
+
elsif action == 'block'
|
|
128
|
+
@is_mod = true
|
|
129
|
+
CensorBear.info(
|
|
130
|
+
d['content'], @type, action, 'aliyun_check',
|
|
131
|
+
filtered_content: d['filteredContent'],
|
|
132
|
+
mod_words: @mod_words,
|
|
133
|
+
labels: @labels,
|
|
134
|
+
ip: @ip, user_id: @user_id
|
|
135
|
+
)
|
|
136
|
+
elsif action == 'review'
|
|
137
|
+
@is_mod = true
|
|
138
|
+
CensorBear.info(
|
|
139
|
+
d['content'], @type, action, 'aliyun_check',
|
|
140
|
+
filtered_content: d['filteredContent'],
|
|
141
|
+
mod_words: @mod_words,
|
|
142
|
+
labels: @labels,
|
|
143
|
+
ip: @ip, user_id: @user_id
|
|
144
|
+
)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
82
147
|
|
|
83
148
|
private
|
|
84
149
|
|
|
85
|
-
def
|
|
150
|
+
def concat_labels(data)
|
|
151
|
+
labels = []
|
|
152
|
+
data.map do |d|
|
|
153
|
+
next if d['label'].blank?
|
|
154
|
+
|
|
155
|
+
labels.push(d['label'])
|
|
156
|
+
end
|
|
157
|
+
labels
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def concat_words(data)
|
|
161
|
+
words = []
|
|
162
|
+
data.each do |d|
|
|
163
|
+
next if d['contexts'].blank?
|
|
164
|
+
|
|
165
|
+
d['contexts'].each do |c|
|
|
166
|
+
words.push(c['context'])
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
words
|
|
170
|
+
end
|
|
86
171
|
|
|
87
|
-
def
|
|
172
|
+
def tencent_check; end
|
|
88
173
|
end
|
|
89
174
|
end
|
|
@@ -13,5 +13,9 @@ module CensorBear
|
|
|
13
13
|
attr_accessor :import_file_path
|
|
14
14
|
attr_accessor :format_from_file_path
|
|
15
15
|
attr_accessor :format_dest_file_path
|
|
16
|
+
|
|
17
|
+
attr_accessor :aliyun_green_access_key_id
|
|
18
|
+
attr_accessor :aliyun_green_access_key_secret
|
|
19
|
+
attr_accessor :aliyun_green_enable_internal
|
|
16
20
|
end
|
|
17
21
|
end
|
data/lib/censor_bear/engine.rb
CHANGED
|
@@ -7,5 +7,13 @@ module CensorBear
|
|
|
7
7
|
initializer "censor_bear.assets.precompile" do |app|
|
|
8
8
|
app.config.assets.precompile += %w( censor_bear/application.css )
|
|
9
9
|
end
|
|
10
|
+
|
|
11
|
+
config.after_initialize do
|
|
12
|
+
AliyunGreen.configure do |config|
|
|
13
|
+
config.access_key_id = CensorBear.config.aliyun_green_access_key_id
|
|
14
|
+
config.access_key_secret = CensorBear.config.aliyun_green_access_key_secret
|
|
15
|
+
config.enable_internal = CensorBear.config.aliyun_green_enable_internal
|
|
16
|
+
end
|
|
17
|
+
end
|
|
10
18
|
end
|
|
11
19
|
end
|
data/lib/censor_bear/version.rb
CHANGED
data/lib/censor_bear.rb
CHANGED
|
@@ -5,6 +5,7 @@ require 'censor_bear/configuration'
|
|
|
5
5
|
|
|
6
6
|
require 'hamlit'
|
|
7
7
|
require 'pagy'
|
|
8
|
+
require 'aliyun_green'
|
|
8
9
|
|
|
9
10
|
module CensorBear
|
|
10
11
|
class NotPassedException < StandardError; end
|
|
@@ -20,6 +21,9 @@ module CensorBear
|
|
|
20
21
|
@config.import_file_path = "#{Rails.root}/tmp/dest_sensitives.txt"
|
|
21
22
|
@config.format_from_file_path = "#{Rails.root}/tmp/from_sensitives.txt"
|
|
22
23
|
@config.format_dest_file_path = "#{Rails.root}/tmp/dest_sensitives.txt"
|
|
24
|
+
@config.aliyun_green_access_key_id = ''
|
|
25
|
+
@config.aliyun_green_access_key_secret = ''
|
|
26
|
+
@config.aliyun_green_enable_internal = false
|
|
23
27
|
@config
|
|
24
28
|
end
|
|
25
29
|
|
|
@@ -27,13 +31,20 @@ module CensorBear
|
|
|
27
31
|
yield(config)
|
|
28
32
|
end
|
|
29
33
|
|
|
30
|
-
def check_text(content, type = 'ugc')
|
|
31
|
-
Censor.new(content, type).check_text
|
|
34
|
+
def check_text(content, type = 'ugc', options = {})
|
|
35
|
+
Censor.new(content, type, options).check_text
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def check_search(content, options = {})
|
|
39
|
+
Censor.new(content, 'ugc', options).check_search
|
|
32
40
|
end
|
|
33
41
|
|
|
34
42
|
def info(content, scenario, action, stage, options = {})
|
|
35
|
-
filtered_content = options[
|
|
36
|
-
mod_words = options[
|
|
43
|
+
filtered_content = options[:filtered_content] || nil
|
|
44
|
+
mod_words = options[:mod_words] || []
|
|
45
|
+
labels = options[:labels] || []
|
|
46
|
+
ip = options[:ip] || nil
|
|
47
|
+
user_id = options[:user_id] || nil
|
|
37
48
|
|
|
38
49
|
CensorBear::Log.create(
|
|
39
50
|
original_content: content,
|
|
@@ -41,7 +52,10 @@ module CensorBear
|
|
|
41
52
|
action: action,
|
|
42
53
|
stage: stage,
|
|
43
54
|
filtered_content: filtered_content,
|
|
44
|
-
mod_words: mod_words
|
|
55
|
+
mod_words: mod_words,
|
|
56
|
+
labels: labels,
|
|
57
|
+
ip: ip,
|
|
58
|
+
user_id: user_id,
|
|
45
59
|
)
|
|
46
60
|
end
|
|
47
61
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
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.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- 42up
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-12-
|
|
11
|
+
date: 2021-12-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -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: aliyun_green
|
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: 0.1.1
|
|
40
|
+
type: :runtime
|
|
41
|
+
prerelease: false
|
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 0.1.1
|
|
33
47
|
- !ruby/object:Gem::Dependency
|
|
34
48
|
name: hamlit
|
|
35
49
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -59,33 +73,33 @@ dependencies:
|
|
|
59
73
|
- !ruby/object:Gem::Version
|
|
60
74
|
version: '2.0'
|
|
61
75
|
- !ruby/object:Gem::Dependency
|
|
62
|
-
name:
|
|
76
|
+
name: pagy
|
|
63
77
|
requirement: !ruby/object:Gem::Requirement
|
|
64
78
|
requirements:
|
|
65
|
-
- - "
|
|
79
|
+
- - "~>"
|
|
66
80
|
- !ruby/object:Gem::Version
|
|
67
|
-
version: '
|
|
81
|
+
version: '5.6'
|
|
68
82
|
type: :runtime
|
|
69
83
|
prerelease: false
|
|
70
84
|
version_requirements: !ruby/object:Gem::Requirement
|
|
71
85
|
requirements:
|
|
72
|
-
- - "
|
|
86
|
+
- - "~>"
|
|
73
87
|
- !ruby/object:Gem::Version
|
|
74
|
-
version: '
|
|
88
|
+
version: '5.6'
|
|
75
89
|
- !ruby/object:Gem::Dependency
|
|
76
|
-
name:
|
|
90
|
+
name: turbo-rails
|
|
77
91
|
requirement: !ruby/object:Gem::Requirement
|
|
78
92
|
requirements:
|
|
79
|
-
- - "
|
|
93
|
+
- - ">="
|
|
80
94
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: '
|
|
95
|
+
version: '0'
|
|
82
96
|
type: :runtime
|
|
83
97
|
prerelease: false
|
|
84
98
|
version_requirements: !ruby/object:Gem::Requirement
|
|
85
99
|
requirements:
|
|
86
|
-
- - "
|
|
100
|
+
- - ">="
|
|
87
101
|
- !ruby/object:Gem::Version
|
|
88
|
-
version: '
|
|
102
|
+
version: '0'
|
|
89
103
|
description: Description of CensorBear.
|
|
90
104
|
email:
|
|
91
105
|
- foobar@v2up.com
|
|
@@ -118,13 +132,17 @@ files:
|
|
|
118
132
|
- app/models/censor_bear/mod_log.rb
|
|
119
133
|
- app/models/censor_bear/stop_word.rb
|
|
120
134
|
- app/views/censor_bear/logs/_form.html.erb
|
|
135
|
+
- app/views/censor_bear/logs/_log.html.haml
|
|
136
|
+
- app/views/censor_bear/logs/destroy.turbo_stream.haml
|
|
121
137
|
- app/views/censor_bear/logs/edit.html.erb
|
|
122
|
-
- app/views/censor_bear/logs/index.html.
|
|
138
|
+
- app/views/censor_bear/logs/index.html.haml
|
|
123
139
|
- app/views/censor_bear/logs/new.html.erb
|
|
124
140
|
- app/views/censor_bear/logs/show.html.erb
|
|
125
141
|
- app/views/censor_bear/mod_logs/_form.html.erb
|
|
142
|
+
- app/views/censor_bear/mod_logs/_mod_log.html.haml
|
|
143
|
+
- app/views/censor_bear/mod_logs/destroy.turbo_stream.haml
|
|
126
144
|
- app/views/censor_bear/mod_logs/edit.html.erb
|
|
127
|
-
- app/views/censor_bear/mod_logs/index.html.
|
|
145
|
+
- app/views/censor_bear/mod_logs/index.html.haml
|
|
128
146
|
- app/views/censor_bear/mod_logs/new.html.erb
|
|
129
147
|
- app/views/censor_bear/mod_logs/show.html.erb
|
|
130
148
|
- app/views/censor_bear/stop_words/_form.html.haml
|
|
@@ -142,6 +160,8 @@ files:
|
|
|
142
160
|
- db/migrate/20211126133758_create_censor_bear_stop_words.rb
|
|
143
161
|
- db/migrate/20211129093508_create_censor_bear_logs.rb
|
|
144
162
|
- db/migrate/20211129110218_create_censor_bear_mod_logs.rb
|
|
163
|
+
- db/migrate/20211206092626_add_ip_to_censor_bear_logs.rb
|
|
164
|
+
- db/migrate/20211208041114_add_labels_to_censor_bear_logs.rb
|
|
145
165
|
- lib/censor_bear.rb
|
|
146
166
|
- lib/censor_bear/censor.rb
|
|
147
167
|
- lib/censor_bear/configuration.rb
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
<p id="notice"><%= notice %></p>
|
|
2
|
-
|
|
3
|
-
<h1>Logs</h1>
|
|
4
|
-
|
|
5
|
-
<table>
|
|
6
|
-
<thead>
|
|
7
|
-
<tr>
|
|
8
|
-
<th>Orginal content</th>
|
|
9
|
-
<th>Action</th>
|
|
10
|
-
<th>Filtered content</th>
|
|
11
|
-
<th>Mod words</th>
|
|
12
|
-
<th colspan="3"></th>
|
|
13
|
-
</tr>
|
|
14
|
-
</thead>
|
|
15
|
-
|
|
16
|
-
<tbody>
|
|
17
|
-
<% @logs.each do |log| %>
|
|
18
|
-
<tr>
|
|
19
|
-
<td><%= log.original_content %></td>
|
|
20
|
-
<td><%= log.scenario %></td>
|
|
21
|
-
<td><%= log.stage %></td>
|
|
22
|
-
<td><%= log.action %></td>
|
|
23
|
-
<td><%= log.filtered_content %></td>
|
|
24
|
-
<td><%= log.mod_words %></td>
|
|
25
|
-
<td><%= link_to 'Show', log %></td>
|
|
26
|
-
<td><%= link_to 'Edit', edit_log_path(log) %></td>
|
|
27
|
-
<td><%= link_to 'Destroy', log, method: :delete, data: { confirm: 'Are you sure?' } %></td>
|
|
28
|
-
</tr>
|
|
29
|
-
<% end %>
|
|
30
|
-
</tbody>
|
|
31
|
-
</table>
|
|
32
|
-
|
|
33
|
-
<br>
|
|
34
|
-
|
|
35
|
-
<%= link_to 'New Log', new_log_path %>
|
|
36
|
-
|
|
37
|
-
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
<p id="notice"><%= notice %></p>
|
|
2
|
-
|
|
3
|
-
<h1>Mod Logs</h1>
|
|
4
|
-
|
|
5
|
-
<table>
|
|
6
|
-
<thead>
|
|
7
|
-
<tr>
|
|
8
|
-
<th>Record</th>
|
|
9
|
-
<th>Record type</th>
|
|
10
|
-
<th>Mod words</th>
|
|
11
|
-
<th>User</th>
|
|
12
|
-
<th colspan="3"></th>
|
|
13
|
-
</tr>
|
|
14
|
-
</thead>
|
|
15
|
-
|
|
16
|
-
<tbody>
|
|
17
|
-
<% @mod_logs.each do |mod_log| %>
|
|
18
|
-
<tr>
|
|
19
|
-
<td><%= mod_log.record_id %></td>
|
|
20
|
-
<td><%= mod_log.record_type %></td>
|
|
21
|
-
<td><%= mod_log.mod_words %></td>
|
|
22
|
-
<td><%= mod_log.user_id %></td>
|
|
23
|
-
<td><%= link_to 'Show', mod_log %></td>
|
|
24
|
-
<td><%= link_to 'Show', mod_log %></td>
|
|
25
|
-
<td><%= link_to 'Edit', edit_mod_log_path(mod_log) %></td>
|
|
26
|
-
<td><%= link_to 'Destroy', mod_log, method: :delete, data: { confirm: 'Are you sure?' } %></td>
|
|
27
|
-
<td><%= link_to "查看详情", mod_log.record_path %></td>
|
|
28
|
-
<td><%= link_to "忽略内容", mod_log_ignore_path(mod_log) %></td>
|
|
29
|
-
<td><%= link_to "通过内容", mod_log_approve_path(mod_log) %></td>
|
|
30
|
-
<td><%= link_to "封禁用户", mod_log_ban_path(mod_log) %></td>
|
|
31
|
-
<td>
|
|
32
|
-
<%= form_with(url: mod_log_delete_path(mod_log), method: :get, class: "flex items-center") do |f| %>
|
|
33
|
-
<%= f.text_field :reason, value: mod_log.reason, placeholder: "原因", class: "border rounded-md m py-0.5 px-1" %>
|
|
34
|
-
<td><%= f.submit "删除内容", class: "rounded-md px-2 py-1 text-sm bg-black text-white cursor-pointer" %></td>
|
|
35
|
-
<% end %>
|
|
36
|
-
</td>
|
|
37
|
-
</tr>
|
|
38
|
-
<% end %>
|
|
39
|
-
</tbody>
|
|
40
|
-
</table>
|
|
41
|
-
|
|
42
|
-
<br>
|
|
43
|
-
|
|
44
|
-
<%= link_to 'New Mod Log', new_mod_log_path %>
|