-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathplugin.rb
242 lines (198 loc) · 9.17 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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# name: discourse-private-replies
# about: Communiteq private replies plugin
# version: 1.4.3
# authors: Communiteq
# url: https://www.communiteq.com/discoursehosting/kb/discourse-private-replies-plugin
# meta_topic_id: 146712
enabled_site_setting :private_replies_enabled
register_svg_icon "user-secret" if respond_to?(:register_svg_icon)
load File.expand_path('../lib/discourse_private_replies/engine.rb', __FILE__)
module ::DiscoursePrivateReplies
def DiscoursePrivateReplies.can_see_all_posts?(user, topic)
return false if user.nil? || user.anonymous? # anonymous users don't have the id method
return true if topic && user.id == topic.user.id
min_trust_level = SiteSetting.private_replies_min_trust_level_to_see_all
if (min_trust_level >= 0) && (min_trust_level < 5)
return true if user.has_trust_level?(TrustLevel[min_trust_level])
end
return true if (SiteSetting.private_replies_groups_can_see_all.split('|').map(&:to_i) & user.groups.pluck(:id)).count > 0
if SiteSetting.private_replies_topic_starter_primary_group_can_see_all && topic
groupids = Group.find(topic.user.primary_group_id).users.pluck(:id) if topic.user && !topic.user.anonymous?
return true if groupids.include? user.id
end
false
end
def DiscoursePrivateReplies.can_see_post_if_author_among(user, topic)
userids = []
Group.where("id in (?)", SiteSetting.private_replies_see_all_from_groups.split('|')).each do |g|
userids += g.users.pluck(:id)
end
userids = userids + [ topic.user.id ] if topic
userids = userids + [ user.id ] if user && !user.anonymous? # anonymous users don't have the id method
return userids.uniq
end
end
after_initialize do
# hide posts from the /raw/tid/pid route
module ::PostGuardian
alias_method :org_can_see_post?, :can_see_post?
def can_see_post?(post)
return true if is_admin?
allowed = org_can_see_post?(post)
return false unless allowed
if SiteSetting.private_replies_enabled && post.topic.custom_fields.keys.include?('private_replies') && post.topic.custom_fields['private_replies']
return true if DiscoursePrivateReplies.can_see_all_posts?(@user, post.topic)
userids = DiscoursePrivateReplies.can_see_post_if_author_among(@user, post.topic)
return false unless userids.include? post.user.id
end
true
end
end
# hide posts from the regular topic stream
module PatchTopicView
def participants
result = super
if SiteSetting.private_replies_enabled && @topic.custom_fields.keys.include?('private_replies') && @topic.custom_fields['private_replies']
if !@user || !DiscoursePrivateReplies.can_see_all_posts?(@user, @topic)
userids = DiscoursePrivateReplies.can_see_post_if_author_among(@user, @topic)
result.select! { |key, _| userids.include?(key) }
end
end
result
end
# hide posts at the lowest level
def unfiltered_posts
result = super
if SiteSetting.private_replies_enabled && @topic.custom_fields.keys.include?('private_replies') && @topic.custom_fields['private_replies']
if !@user || !DiscoursePrivateReplies.can_see_all_posts?(@user, @topic)
userids = DiscoursePrivateReplies.can_see_post_if_author_among(@user, @topic)
result = result.where('(posts.post_number = 1 OR posts.user_id IN (?))', userids)
end
end
result
end
# filter posts_by_ids does not seem to use unfiltered_posts ?! WHY...
# so we need to filter that separately
def filter_posts_by_ids(post_ids)
@posts = super(post_ids)
if SiteSetting.private_replies_enabled && @topic.custom_fields.keys.include?('private_replies') && @topic.custom_fields['private_replies']
if !@user || !DiscoursePrivateReplies.can_see_all_posts?(@user, @topic)
userids = DiscoursePrivateReplies.can_see_post_if_author_among(@user, @topic)
@posts = @posts.where('(posts.post_number = 1 OR posts.user_id IN (?))', userids)
end
end
@posts
end
end
module PatchTopicViewDetailsSerializer
def last_poster
if SiteSetting.private_replies_enabled && object.topic.custom_fields.keys.include?('private_replies') && object.topic.custom_fields['private_replies']
if !scope.user || !DiscoursePrivateReplies.can_see_all_posts?(scope.user, object.topic)
userids = DiscoursePrivateReplies.can_see_post_if_author_among(scope.user, object.topic)
return object.topic.user unless !userids.include? object.topic.last_poster
end
end
object.topic.last_poster
end
end
module PatchTopicPostersSummary
def initialize(topic, options = {})
super
if SiteSetting.private_replies_enabled && @topic.custom_fields.keys.include?('private_replies') && @topic.custom_fields['private_replies']
@filter_userids = DiscoursePrivateReplies.can_see_post_if_author_among(@user, @topic)
else
@filter_userids = nil
end
end
def summary
result = super
if @filter_userids
result.select! { |v| @filter_userids.include?(v.user.id) }
end
result
end
end
# hide posts from search results
module PatchSearch
def execute(readonly_mode: @readonly_mode)
super
if SiteSetting.private_replies_enabled && !DiscoursePrivateReplies.can_see_all_posts?(@guardian.user, nil)
userids = DiscoursePrivateReplies.can_see_post_if_author_among(@guardian.user, nil)
protected_topics = TopicCustomField.where(:name => 'private_replies').where(:value => true).pluck(:topic_id)
@results.posts.delete_if do |post|
next false unless protected_topics.include? post.topic_id # leave unprotected topics alone
next false if userids.include? post.user_id # show staff and own posts
next false if post.user_id == post.topic.user_id # show topic starter posts
true
end
end
@results
end
end
# hide posts from user profile -> activity
class ::UserAction
module PrivateRepliesApplyCommonFilters
def apply_common_filters(builder, user_id, guardian, ignore_private_messages=false)
if SiteSetting.private_replies_enabled && !DiscoursePrivateReplies.can_see_all_posts?(guardian.user, nil)
userids = DiscoursePrivateReplies.can_see_post_if_author_among(guardian.user, nil)
userid_list = userids.join(',')
protected_topic_list = TopicCustomField.where(:name => 'private_replies').where(:value => true).pluck(:topic_id).join(',')
if !protected_topic_list.empty?
builder.where("( (a.target_topic_id not in (#{protected_topic_list})) OR (a.acting_user_id = t.user_id) OR (a.acting_user_id in (#{userid_list})) )")
end
end
super(builder, user_id, guardian, ignore_private_messages)
end
end
singleton_class.prepend PrivateRepliesApplyCommonFilters
end
# hide posts from digest and mlm-summary
class ::Topic
class << self
alias_method :original_for_digest_private_replies, :for_digest
# either the topic is unprotected, or it is the first post number, or it is the user's own topic, or the users posts can be seen
# @TODO this does not implement private_replies_topic_starter_primary_group_can_see_all
def for_digest(user, since, opts = nil)
topics = original_for_digest_private_replies(user, since, opts)
# check if we are actually joining on posts, we are for MLM summary but we are not for digest
if SiteSetting.private_replies_enabled && !DiscoursePrivateReplies.can_see_all_posts?(user, nil) && topics.to_sql.include?('INNER JOIN "posts"')
userid_list = DiscoursePrivateReplies.can_see_post_if_author_among(user, nil).join(',')
protected_topic_list = TopicCustomField.where(:name => 'private_replies').where(:value => true).pluck(:topic_id).join(',')
topics = topics.where("(topics.id NOT IN (#{protected_topic_list}) OR posts.post_number = 1 OR topics.user_id = #{user.id} OR posts.user_id IN (#{userid_list}))")
end
topics
end
end
end
class ::TopicView
prepend PatchTopicView
end
class ::TopicPostersSummary
prepend PatchTopicPostersSummary
end
class ::TopicViewDetailsSerializer
prepend PatchTopicViewDetailsSerializer
end
class ::Search
prepend PatchSearch
end
Topic.register_custom_field_type('private_replies', :boolean)
add_to_serializer :topic_view, :private_replies do
object.topic.custom_fields['private_replies']
end
Discourse::Application.routes.append do
mount ::DiscoursePrivateReplies::Engine, at: "/private_replies"
end
DiscourseEvent.on(:topic_created) do |topic|
if SiteSetting.private_replies_enabled
if (SiteSetting.private_replies_on_selected_categories_only == false) || (topic&.category&.custom_fields&.dig('private_replies_enabled'))
if topic&.category&.custom_fields&.dig('private_replies_default_enabled')
topic.custom_fields['private_replies'] = true
topic.save_custom_fields
end
end
end
end
Site.preloaded_category_custom_fields << 'private_replies_default_enabled'
Site.preloaded_category_custom_fields << 'private_replies_enabled'
end