docbrown/app/models/user_subscription.rb
Alex 9ee024f9d0
UserSubscription backend refactor (#9060)
* Refactor controller validations to model

* Update specs and move current email validation back

* Refactor #subscribed

* Cleanup UserSubscriptions::Create service

* Refactor service

* Move source inside of call for clarity

* Specs for UserSubscription::Create

* Cleanup spec

* Fix Article spec

* Updated for subscriber_email

* Add comment for explicitness of subscriber_email

* Fix reference in comment...oops!

* I know what I'm doing...sometimes...maybe

* Rename CachChecker - Subscription to IsSubscribed

* Use include vs eq in specs for error messages

* attr_accessor --> attr_reader

* Don't explicitly set nil

* Rename Create service to CreateFromService

* Use errors_as_sentence

* Rename service to CreateFromControllerParams

* Assign Struct to a new constant
2020-07-02 12:08:37 -04:00

83 lines
2.7 KiB
Ruby

# This model handles a user (subscriber) subscribing to another user (author).
# We also record the source of the subscription (Article, Comment, etc.) via a
# polymorphic association (user_subscription_source/able).
class UserSubscription < ApplicationRecord
ALLOWED_TYPES = %w[Article].freeze
counter_culture :subscriber, column_name: "subscribed_to_user_subscriptions_count"
belongs_to :author, class_name: "User", inverse_of: :source_authored_user_subscriptions
belongs_to :subscriber, class_name: "User", inverse_of: :subscribed_to_user_subscriptions
belongs_to :user_subscription_sourceable, polymorphic: true
validates :author_id, presence: true
validates :subscriber_email, presence: true
validates :subscriber_id, presence: true, uniqueness: { scope: %i[subscriber_email user_subscription_sourceable_type user_subscription_sourceable_id] }
validates :user_subscription_sourceable_id, presence: true
validates :user_subscription_sourceable_type, presence: true, inclusion: { in: ALLOWED_TYPES }
validate :tag_enabled
validate :non_apple_auth_subscriber
validate :active_user_subscription_source
def self.build(source:, subscriber:)
new(build_attributes(source, subscriber))
end
def self.make(source:, subscriber:)
create(build_attributes(source, subscriber))
end
def self.build_attributes(source, subscriber)
{
user_subscription_sourceable: source,
author_id: source&.user_id,
subscriber_id: subscriber&.id,
subscriber_email: subscriber&.email
}
end
private
def tag_enabled
return unless user_subscription_sourceable
liquid_tags =
case user_subscription_sourceable_type
when "Article"
user_subscription_sourceable.liquid_tags_used(:body)
else
user_subscription_sourceable.liquid_tags_used
end
return if liquid_tags.include?(UserSubscriptionTag)
errors.add(:base, "User subscriptions are not enabled for the source.")
end
def non_apple_auth_subscriber
return unless subscriber_email&.end_with?("@privaterelay.appleid.com")
errors.add(:subscriber_email, "Can't subscribe with an Apple private relay. Please update email.")
end
def active_user_subscription_source
return unless user_subscription_sourceable
source_active =
# Don't create new user subscriptions for inactive sources
# (i.e. unpublished Articles, deleted Comments, etc.)
case user_subscription_sourceable_type
when "Article"
user_subscription_sourceable.published?
when "Comment"
!user_subscription_sourceable.deleted?
else
false
end
return if source_active
errors.add(:base, "Source not found.")
end
end