-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathplugin.rb
198 lines (165 loc) · 7.44 KB
/
plugin.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# frozen_string_literal: true
# name: discourse-akismet
# about: Fights spam with Akismet, an algorithm used by millions of sites to combat spam automatically.
# meta_topic_id: 109337
# version: 0.1.0
# authors: Michael Verdi, Robin Ward
# url: https://github.com/discourse/discourse-akismet
enabled_site_setting :akismet_enabled
require_relative "lib/discourse_akismet/anti_spam_service.rb"
require_relative "lib/discourse_akismet/bouncer.rb"
require_relative "lib/discourse_akismet/engine.rb"
require_relative "lib/discourse_akismet/post_voting_comments_bouncer.rb"
require_relative "lib/discourse_akismet/posts_bouncer.rb"
require_relative "lib/discourse_akismet/users_bouncer.rb"
require_relative "lib/akismet.rb"
require_relative "lib/netease.rb"
register_asset "stylesheets/akismet.scss"
after_initialize do
require_relative "jobs/regular/check_akismet_post.rb"
require_relative "jobs/regular/check_akismet_post_voting_comment.rb"
require_relative "jobs/regular/check_akismet_user.rb"
require_relative "jobs/regular/confirm_akismet_flagged_posts.rb"
require_relative "jobs/regular/update_akismet_status.rb"
require_relative "jobs/scheduled/check_for_spam_post_voting_comments.rb"
require_relative "jobs/scheduled/check_for_spam_posts.rb"
require_relative "jobs/scheduled/check_for_spam_users.rb"
require_relative "jobs/scheduled/clean_old_akismet_custom_fields.rb"
require_relative "lib/user_destroyer_extension.rb"
require_relative "models/reviewable_akismet_post_voting_comment.rb"
require_relative "models/reviewable_akismet_post.rb"
require_relative "models/reviewable_akismet_user.rb"
if Rails.env.local? &&
DiscoursePluginRegistry.respond_to?(:discourse_dev_populate_reviewable_types)
require_relative "lib/discourse_dev/reviewable_akismet_post.rb"
require_relative "lib/discourse_dev/reviewable_akismet_user.rb"
end
require_relative "serializers/reviewable_akismet_post_voting_comment_serializer.rb"
require_relative "serializers/reviewable_akismet_post_serializer.rb"
require_relative "serializers/reviewable_akismet_user_serializer.rb"
register_reviewable_type ReviewableAkismetPost
register_reviewable_type ReviewableAkismetUser
register_reviewable_type ReviewableAkismetPostVotingComment
# TODO(roman): Remove else branch after 3.0 release.
if respond_to?(:register_user_destroyer_on_content_deletion_callback)
register_user_destroyer_on_content_deletion_callback(
Proc.new do |user, guardian, opts|
if opts[:delete_as_spammer]
ReviewableFlaggedPost
.where(target_created_by: user)
.find_each do |reviewable|
# The overriden `agree_with_flags` handles this reviewables, this
# method just ensures that feedback is submitted.
if target = Post.with_deleted.find_by(id: reviewable.target_id)
DiscourseAkismet::PostsBouncer.new.submit_feedback(target, "spam")
end
end
ReviewableAkismetPost
.where(target_created_by: user)
.find_each do |reviewable|
# Ensure that reviewable was not handled already
#
# Performing `delete_user` action sends feedback to Akismet, destroys
# the user and then updates reviewable status. This method is called
# before reviewable status is updated which means that the same action
# will be called twice.
if UserHistory.where(
custom_type: "confirmed_spam_deleted",
post_id: reviewable.target_id,
).exists?
next
end
# Confirming an Akismet reviewable automatically sends feedback
if reviewable.actions_for(guardian).has?(:confirm_spam)
reviewable.perform(guardian.user, :confirm_spam)
end
end
elsif opts[:delete_posts]
ReviewableAkismetPost.where(target_created_by: user).destroy_all
end
end,
)
else
reloadable_patch { UserDestroyer.prepend(DiscourseAkismet::UserDestroyerExtension) }
end
TopicView.add_post_custom_fields_allowlister do |user|
user&.staff? ? [DiscourseAkismet::Bouncer::AKISMET_STATE] : []
end
add_model_callback(UserProfile, :before_save) do
if (bio_raw_changed? && bio_raw.present?) || (website_changed? && website.present?)
DiscourseAkismet::UsersBouncer.new.enqueue_for_check(user)
end
end
add_to_serializer(:post, :akismet_state, include_condition: -> { scope.is_staff? }) do
post_custom_fields[DiscourseAkismet::Bouncer::AKISMET_STATE]
end
on(:post_created) do |post, params|
DiscourseAkismet::PostsBouncer
.new
.check(post) { |bouncer| bouncer.store_additional_information(post, params) }
end
on(:post_edited) do |post, _, revisor|
next unless revisor.reviewable_content_changed?
editor = post.last_editor
next if editor.is_system_user? || !editor.regular?
DiscourseAkismet::PostsBouncer.new.check(post)
end
on(:post_recovered) do |post, _, _|
# Ensure that posts that were deleted and thus skipped are eventually
# checked.
if post.custom_fields[DiscourseAkismet::Bouncer::AKISMET_STATE] !=
DiscourseAkismet::Bouncer::SKIPPED_STATE
next
end
DiscourseAkismet::PostsBouncer.new.check(post)
end
on(:post_voting_comment_created) do |comment, params|
DiscourseAkismet::PostVotingCommentsBouncer
.new
.check(comment) { |bouncer| bouncer.store_additional_information(comment, params) }
end
on(:post_voting_comment_edited) do |comment, user, revisor|
old_comment = PostVotingComment.find(comment.id)
next if comment.raw == old_comment.raw
editor = comment.last_editor
next if editor.is_system_user? || !editor.regular?
DiscourseAkismet::PostVotingCommentsBouncer.new.check(comment)
end
# If a user is anonymized, support anonymizing their IPs
on(:user_anonymized) do |args|
user = args[:user]
opts = args[:opts]
if user && opts && opts.has_key?(:anonymize_ip)
anonymize_posts = <<~SQL
UPDATE post_custom_fields AS pcf
SET value = :new_ip
FROM posts AS p
WHERE name = 'AKISMET_IP_ADDRESS'
AND p.id = pcf.post_id
AND p.user_id = :user_id
SQL
args = { user_id: user.id, new_ip: opts[:anonymize_ip] }
DB.exec anonymize_posts, args
if defined?(SiteSetting.post_voting_enabled) && SiteSetting.post_voting_enabled?
anonymize_post_voting_comments = <<~SQL
UPDATE post_voting_comment_custom_fields AS pvccf
SET value = :new_ip
FROM post_voting_comments AS pvc
WHERE name = 'AKISMET_IP_ADDRESS'
AND pvc.id = pvccf.post_voting_comment_id
AND pvc.user_id = :user_id
SQL
DB.exec anonymize_post_voting_comments, args
end
end
end
staff_actions = %i[confirmed_spam confirmed_ham ignored confirmed_spam_deleted]
extend_list_method(UserHistory, :staff_actions, staff_actions)
add_reviewable_score_link(:akismet_spam_post, "plugin:discourse-akismet")
add_reviewable_score_link(:akismet_spam_user, "plugin:discourse-akismet")
if Rails.env.local? &&
DiscoursePluginRegistry.respond_to?(:discourse_dev_populate_reviewable_types)
DiscoursePluginRegistry.discourse_dev_populate_reviewable_types.add DiscourseDev::ReviewableAkismetPost
DiscoursePluginRegistry.discourse_dev_populate_reviewable_types.add DiscourseDev::ReviewableAkismetUser
end
end