Class: URLSubscriber

Inherits:
Object
  • Object
show all
Defined in:
lib/url_subscriber.rb

Overview

This class has methods to subscribe a user to a feed.

Class Method Summary collapse

Class Method Details

.enqueue_subscribe_job(url, user) ⇒ Object

Enqueue a job to subscribe a user to a feed. Receives as arguments the URL of the feed and the user that will be subscribed.

Returns the SubscribeJobState instance representing the current state of the job.


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
# File 'lib/url_subscriber.rb', line 16

def self.enqueue_subscribe_job(url, user)
  Rails.logger.info "User #{user.id} - #{user.email} has requested to be subscribed to feed with fetch_url #{url}"

  # Check if the feed url is blacklisted
  if FeedBlacklister.blacklisted_url? url
    Rails.logger.warn "URL #{url} is blacklisted, cannot add subscription"
    job_state = user.subscribe_job_states.create fetch_url: url, state: SubscribeJobState::ERROR
    raise BlacklistedUrlError.new
  end

  # Check if the user is already subscribed to the feed
  existing_feed = Feed.url_variants_feed url
  if existing_feed.present?
    # Check if the user is already subscribed to the feed
    if user.feeds.include? existing_feed
      Rails.logger.info "User #{user.id} (#{user.email}) is already subscribed to feed #{existing_feed.id} - #{existing_feed.fetch_url}. No action necessary."
      job_state = user.subscribe_job_states.create fetch_url: url, state: SubscribeJobState::SUCCESS,
                                                   feed_id: existing_feed.id
      return job_state
    end
  end

  job_state = user.subscribe_job_states.create fetch_url: url
  Rails.logger.info "Enqueuing subscribe_user_job_state #{job_state.id} for user #{user.id} - #{user.email}"
  SubscribeUserWorker.perform_async user.id, url, job_state.id
  return job_state
end

.subscribe(url, user) ⇒ Object

Subscribe a user to a feed. Receives as arguments the URL of the feed and the user that will be subscribed.

First it checks if the feed is already in the database. In this case:

  • If the user is already subscribed to the feed, an AlreadySubscribedError is raised.

  • Otherwise, the user is subscribed to the feed. The feed is not fetched (it is assumed its entries are

fresh enough).

If the feed is not in the database, it checks if the feed can be fetched. If so, the feed is fetched, parsed, saved in the database and the user is subscribed to it.

If parsing the fetched response fails, it checks if the URL corresponds to an HTML page with feed autodiscovery enabled. In this case the actual feed is fetched, saved in the database and the user subscribed to it.

If the end result is that the user has a new subscription, returns the feed object. If the user is already subscribed to the feed, raises an AlreadySubscribedError. If the user has not been subscribed to a new feed (i.e. because the URL is not valid), returns nil.

Note,- When searching for feeds in the database (to see if there is a feed with a matching URL, and whether the user is already subscribed to it), this method is insensitive to trailing slashes, and if no URI-scheme is present an “http://” scheme is assumed.

E.g. if the user is subscribed to a feed with url “xkcd.com/”, the following URLs would cause an AlreadySubscribedError to be raised:


75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/url_subscriber.rb', line 75

def self.subscribe(url, user)
  Rails.logger.info "Subscribing user #{user.id} - #{user.email} to feed URL #{url}"

  # Ensure the url has a schema (defaults to http:// if none is passed)
  feed_url = URLNormalizer.normalize_feed_url url

  # Try to subscribe the user to the feed assuming it's in the database
  feed = subscribe_known_feed user, feed_url

  # If the feed is not in the database, save it and fetch it for the first time.
  if feed.blank?
    feed = subscribe_new_feed user, feed_url
  end

  return feed
end