docbrown/app/services/articles/updater.rb
Joshua Wehner 375cbfe946
Refresh audience segment for 'active' user (#19470)
* Refresh an individual user's segmentation

* Refresh segment if creating a published article

* Quick refactor

* Refresh segment if update publishing

* Quick refactor

* Refresh segment if update user settings

* Refresh segments after user update + role change

* Using latest_article_updated_at

* Sidekiq uses JSON for arguments, needs basic types

* Fix test issues with last_updated_at and sidekiq params

* Tests update continues

* Consolidate dependencies

* Method names acknowledging manual exclusive

* Fix test name copypasta

* Rubocop

* Try to clarify Creator#series

* Try to avoid naming predicate

* Remove erroneously included helper
2023-05-19 14:16:07 +02:00

88 lines
2.9 KiB
Ruby

module Articles
class Updater
Result = Struct.new(:success, :article, keyword_init: true)
def self.call(...)
new(...).call
end
def initialize(user, article, article_params)
@user = user
@article = article
@article_params = normalize_params(article_params)
end
def call
user.rate_limiter.check_limit!(:article_update)
success = article.update(article_params)
if success
user.rate_limiter.track_limit_by_action(:article_update)
remove_all_notifications if became_unpublished?
send_to_mentioned_users_and_followers if remains_published?
refresh_auto_audience_segments if became_published?
end
Result.new(success: success, article: article.decorate)
end
private
attr_reader :user, :article, :article_params
def normalize_params(original_params)
article_params = original_params.dup
# updated edited time only if already published and not edited by an admin
update_edited_at = article.user == user && article.published
# remove published_at values received from a user if an articles was published before (has past published_at)
# published_at will remain as it was in this case
article_params.delete :published_at if article.published_at && !article.scheduled?
# NOTE: It's surprising that this is article.user and not @user
Articles::Attributes.new(article_params, article.user)
.for_update(update_edited_at: update_edited_at)
end
def refresh_auto_audience_segments
user.refresh_auto_audience_segments
end
def became_published?
article.published? && !article.published_previously_was
end
def remains_published?
article.published && article.saved_change_to_published.blank?
end
def became_unpublished?
article.saved_changes["published"] == [true, false]
end
# If the article has already been published and is only being updated, then we need to create
# mentions and send notifications to mentioned users inline via the Mentions::CreateAll service.
def send_to_mentioned_users_and_followers
Mentions::CreateAll.call(article)
end
# Remove any associated notifications if Article is unpublished
def remove_all_notifications
Notification.remove_all_by_action_without_delay(notifiable_ids: article.id, notifiable_type: "Article",
action: "Published")
ContextNotification.delete_by(context_id: article.id, context_type: "Article",
action: "Published")
if article.comments.exists?
Notification.remove_all(notifiable_ids: article.comments.ids,
notifiable_type: "Comment")
end
return unless article.mentions.exists?
Notification.remove_all(notifiable_ids: article.mentions.ids,
notifiable_type: "Mention")
end
end
end