discourse/app/services/post_action_notifier.rb
Martin Brennan eeaecd4fd2
FEATURE: Category setting to allow unlimited first post edits by the owner of the topic (#12690)
This PR adds a new category setting which is a column in the `categories` table, `allow_unlimited_owner_edits_on_first_post`.

What this does is:

* Inside the `can_edit_post?` method of `PostGuardian`, if the current user editing a post is the owner of the post, it is the first post, and the topic's category has `allow_unlimited_owner_edits_on_first_post`, then we bypass the check for `LimitedEdit#edit_time_limit_expired?` on that post.
* Also, similar to wiki topics, in `PostActionNotifier#after_create_post_revision` we send a notification to all users watching a topic when the OP is edited in a topic with the category setting `allow_unlimited_owner_edits_on_first_post` enabled.

This is useful for forums where there is a Marketplace or similar category, where topics are created and then updated indefinitely by the OP rather than the OP making new topics or additional replies. In a way this acts similar to a wiki that only one person can edit.
2021-04-14 15:54:09 +10:00

161 lines
4.2 KiB
Ruby

# frozen_string_literal: true
class PostActionNotifier
def self.disable
@disabled = true
end
def self.enable
@disabled = false
end
# For testing purposes
def self.reset!
@custom_post_revision_notifier_recipients = nil
end
def self.alerter
@alerter ||= PostAlerter.new
end
def self.refresh_like_notification(post, read)
return unless post && post.user_id && post.topic
usernames = post.post_actions.where(post_action_type_id: PostActionType.types[:like])
.joins(:user)
.order('post_actions.created_at desc')
.where('post_actions.created_at > ?', 1.day.ago)
.pluck(:username)
if usernames.length > 0
data = {
topic_title: post.topic.title,
username: usernames[0],
display_username: usernames[0],
username2: usernames[1],
count: usernames.length
}
Notification.create(
notification_type: Notification.types[:liked],
topic_id: post.topic_id,
post_number: post.post_number,
user_id: post.user_id,
read: read,
data: data.to_json
)
end
end
def self.post_action_deleted(post_action)
return if @disabled
# We only care about deleting post actions for now
return if post_action.deleted_at.blank?
if post_action.post_action_type_id == PostActionType.types[:like] && post_action.post
read = true
Notification.where(
topic_id: post_action.post.topic_id,
user_id: post_action.post.user_id,
post_number: post_action.post.post_number,
notification_type: Notification.types[:liked]
).each do |notification|
read = false unless notification.read
notification.destroy
end
refresh_like_notification(post_action.post, read)
else
# not using destroy_all cause we want stuff to trigger
Notification.where(post_action_id: post_action.id).each(&:destroy)
end
end
def self.post_action_created(post_action)
return if @disabled
# We only notify on likes for now
return unless post_action.is_like?
post = post_action.post
return if post_action.user.blank? || post.blank?
alerter.create_notification(
post.user,
Notification.types[:liked],
post,
display_username: post_action.user.username,
post_action_id: post_action.id,
user_id: post_action.user_id
)
end
def self.after_create_post_revision(post_revision)
return if @disabled
post = post_revision.post
return unless post
return if post_revision.user.blank?
return if post.topic.blank?
return if post.topic.private_message?
return if SiteSetting.disable_system_edit_notifications && post_revision.user_id == Discourse::SYSTEM_USER_ID
user_ids = []
if post_revision.user_id != post.user_id
user_ids << post.user_id
end
# Notify all users watching the topic when the OP of a wiki topic is edited
# or if the topic category allows unlimited owner edits on the OP.
if post.is_first_post? &&
(post.wiki? || post.topic.category_allows_unlimited_owner_edits_on_first_post?)
user_ids.concat(
TopicUser.watching(post.topic_id)
.where.not(user_id: post_revision.user_id)
.where(topic: post.topic)
.pluck(:user_id)
)
end
custom_post_revision_notifier_recipients.each do |block|
user_ids.concat(Array(block.call(post_revision)))
end
if user_ids.present?
DB.after_commit do
Jobs.enqueue(:notify_post_revision,
user_ids: user_ids,
post_revision_id: post_revision.id
)
end
end
end
def self.after_post_unhide(post, flaggers)
return if @disabled || post.last_editor.blank? || flaggers.blank?
flaggers.each do |flagger|
alerter.create_notification(
flagger,
Notification.types[:edited],
post,
display_username: post.last_editor.username,
acting_user_id: post.last_editor.id
)
end
end
def self.custom_post_revision_notifier_recipients
@custom_post_revision_notifier_recipients ||= Set.new
end
def self.add_post_revision_notifier_recipients(&block)
custom_post_revision_notifier_recipients << block
end
end