Class: User

Inherits:
ApplicationRecord show all
Defined in:
app/models/user.rb

Overview

User model. Each instance of this class represents a single user that can log in to the application (or at least that has passed through the signup process but has not yet confirmed his email).

This class has been created by installing the Devise gem and running the following commands:

rails generate devise:install
rails generate devise User

The Devise gem manages authentication in this application. To learn more about Devise visit: github.com/plataformatec/devise

Beyond the attributes added to this class by Devise for authentication, Feedbunch establishes relationships between the User model and the following models:

  • FeedSubscription: Each user can be subscribed to many feeds, but a single subscription belongs to a single user (one-to-many relationship).

  • Feed, through the FeedSubscription model: This enables us to retrieve the feeds a user is subscribed to.

  • Folder: Each user can have many folders and each folder belongs to a single user (one-to-many relationship).

  • Entry, through the Feed model: This enables us to retrieve all entries for all feeds a user is subscribed to.

  • EntryState: This enables us to retrieve the state (read or unread) of all entries for all feeds a user is subscribed to.

  • OpmlImportJobState: This indicates whether the user has ever started an OPML import, and in this case it gives information about the import

process (whether it's still running or not, number of feeds processed, etc).

  • OpmlExportJobState: This indicates whether the user has ever started an OPML export, and in this case it gives information about the import

process state.

  • RefreshFeedJobState: Each instance of this class associated with a user represents an ocurrence of the user requesting

a refresh of a feed. The state attribute of the instance indicates if the refresh is running, successfully finished, or finished with an error.

  • SubscribeJobState: Each instance of this class associated with a user represents an ocurrence of the user trying

to subscribe to a feed. The state attribute of the instance indicates if the subscription is running, successfully finished or finished with an error.

Also, the User model has the following attributes:

  • admin: Boolean that indicates whether the user is an administrator. This attribute is used to restrict access to certain

functionality, like ActiveAdmin and Sidekiq administration.

  • free: Boolean that indicates if the user has been granted free access to the app (if true) or if he's a paying user (if false).

Note that regular users have this attribute set to false, even during any unpaid trial period. Only users who are never required to pay anything have this attribute set to true.

  • name: text with the username, to be displayed in the app. Usernames are unique. Defaults to the value of the “email” attribute.

  • locale: locale (en, es etc) in which the user wants to see the application. By default “en”.

  • timezone: name of the timezone (Europe/Madrid, UTC etc) to which the user wants to see times localized. By default “UTC”.

  • quick_reading: boolean indicating whether the user has enabled Quick Reading mode (in which entries are marked as read

as soon as they are scrolled by) or not. False by default.

  • open_all_entries: boolean indicating whether the user wants to see all entries open by default when they are loaded.

False by default.

  • show_main_tour: boolean indicating whether the main app tour should be shown when the user enters the application. True

by default

  • show_mobile_tour: boolean indicating whether the mobile app tour should be shown when the user enters the application.

True by default.

  • show_feed_tour: boolean indicating whether the feed tour should be shown. True by default.

  • show_entry_tour: boolean indicating whether the entry tour should be shown. True by default.

  • show_kb_shortcuts_tour: boolean indicating whether the keyboard shortcuts tour should be shown. True by default.

  • subscriptions_updated_at: datetime when subscriptions were updated for the last time. Events that

update this attribute are:

- subscribing to a new feed
- unsubscribing from a feed
- changing the unread entries count for a feed
- changing a feed title
- changing a feed URL
- moving a feed into or out of a folder
  • folders_updated_at: datetime when folders were updated for the last time. Events that

update this attribute are:

- creating a folder
- destroying a folder
  • refresh_feed_jobs_updated_at: datetime when refresh feed jobs for this user were updated for the last time.

Events that update this attribute are:

- creating a refresh feed job state
- destroying a refresh feed job state
- updating a refresh feed job state
  • subscribe_jobs_updated_at: datetime when subscribe feed jobs for this user were updated for the last time.

Events that update this attribute are:

- creating a subscribe feed job state
- destroying a subscribe feed job state
- updating a subscribe feed job state
  • config_updated_at: datetime when the config for this user was last updated. This attribute is

updated every time one of these attributes is changed:

- quick_reading
- open_all_entries
- show_main_tour
- show_mobile_tour
- show_feed_tour
- show_entry_tour
- show_kb_shortcuts_tour
- kb_shortcuts_enabled
  • user_data_updated_at: datetime when user data for this user was last updated. This attribute is

updated every time one of these happens:

- user subscribes to a new feed
- user unsubscribes from a feed
  • first_confirmation_reminder_sent, first_confirmation_reminder_sent: booleans that indicates if the first and second

confirmation reminder emails have been sent to a user. This happens when a user signs up but never clicks on the link in the confirmation email. Each of the two confirmation reminders will be sent just once.

  • kb_shortcuts_enabled: boolean that indicates if keyboard shortcuts are enabled for a user. True by default.

When a user is subscribed to a feed (this is, when a feed is added to the user.feeds array), EntryState instances are saved to mark all its entries as unread for this user.

Conversely when a user unsubscribes from a feed (this is, when a feed is removed from the user.feeds array), all EntryState instances for its entries and for this user are deleted; the app does not store read/unread state for entries that belong to feeds to which the user is not subscribed.

It is not mandatory that a user be suscribed to any feeds (in fact when a user first signs up he won't have any suscriptions).

Instance Method Summary collapse

Instance Method Details

#change_entries_state(entry, state, whole_feed: false, whole_folder: false, all_entries: false) ⇒ Object

Change the read/unread state of entries for this user. See EntryStateManager#change_entries_state


254
255
256
# File 'app/models/user.rb', line 254

def change_entries_state(entry, state, whole_feed: false, whole_folder: false, all_entries: false)
  EntryStateManager.change_entries_state entry, state, self, whole_feed: whole_feed, whole_folder: whole_folder, all_entries: all_entries
end

#delete_profileObject

Immediately lock the user account so that it cannot log in. Enqueue a job to destroy the user. Exception: if the user being deleted is the demo user, this method does nothing. The demo user cannot be deleted.


303
304
305
306
307
308
309
310
311
# File 'app/models/user.rb', line 303

def delete_profile
  if Feedbunch::Application.config.demo_enabled
    demo_email = Feedbunch::Application.config.demo_email
    return nil if self.email == demo_email
  end

  self.lock_access! send_instructions: false
  DestroyUserWorker.perform_async self.id
end

#enqueue_subscribe_job(url) ⇒ Object

Enqueue a job to subscribe to a feed. See URLSubscriber#enqueue_subscribe_job


233
234
235
# File 'app/models/user.rb', line 233

def enqueue_subscribe_job(url)
  URLSubscriber.enqueue_subscribe_job url, self
end

#enqueue_unsubscribe_job(feed) ⇒ Object

Enqueue a job to unsubscribe from a feed. See URLSubscriber#enqueue_unsubscribe_job


247
248
249
# File 'app/models/user.rb', line 247

def enqueue_unsubscribe_job(feed)
  SubscriptionsManager.enqueue_unsubscribe_job feed, self
end

#export_subscriptionsObject

Export an OPML file with the user's subscriptions. See OPMLExporter#enqueue_export_job


270
271
272
# File 'app/models/user.rb', line 270

def export_subscriptions
  OPMLExporter.enqueue_export_job self
end

#feed_entries(feed, include_read: false, page: nil) ⇒ Object

Retrieve entries from a feed. See EntriesPagination#feed_entries


176
177
178
# File 'app/models/user.rb', line 176

def feed_entries(feed, include_read: false, page: nil)
  EntriesPagination.feed_entries feed, self, include_read: include_read, page: page
end

#feed_unread_count(feed) ⇒ Object

Retrieve the number of unread entries in a feed for this user. See SubscriptionsManager#unread_feed_entries_count


191
192
193
# File 'app/models/user.rb', line 191

def feed_unread_count(feed)
  SubscriptionsManager.feed_unread_count feed, self
end

#find_refresh_feed_job_state(job_id) ⇒ Object

Find a refresh_feed_job_state belonging to the user


212
213
214
# File 'app/models/user.rb', line 212

def find_refresh_feed_job_state(job_id)
  return self.refresh_feed_job_states.find job_id
end

#find_subscribe_job_state(job_id) ⇒ Object

Find a subscribe_job_state belonging to the user


226
227
228
# File 'app/models/user.rb', line 226

def find_subscribe_job_state(job_id)
  return self.subscribe_job_states.find job_id
end

#folder_entries(folder, include_read: false, page: nil) ⇒ Object

Retrieve unread entries from a folder. See EntriesPagination#folder_entries


183
184
185
# File 'app/models/user.rb', line 183

def folder_entries(folder, include_read: false, page: nil)
  EntriesPagination.folder_entries folder, self, include_read: include_read, page: page
end

#folder_feeds(folder, include_read: false) ⇒ Object

Retrieves feeds subscribed by the user. See FolderManager#folder_feeds.


169
170
171
# File 'app/models/user.rb', line 169

def folder_feeds(folder, include_read: false)
  FolderManager.folder_feeds folder, self, include_read: include_read
end

#get_opml_exportObject

Get a previously exported OPML file. See OPMLExporter.get_export


278
279
280
# File 'app/models/user.rb', line 278

def get_opml_export
  OPMLExporter.get_export self
end

#import_subscriptions(file) ⇒ Object

Import an OPML (optionally zipped) with subscription data, and subscribe the user to the feeds in it. See OPMLImporter#enqueue_import_job


262
263
264
# File 'app/models/user.rb', line 262

def import_subscriptions(file)
  OPMLImporter.enqueue_import_job file, self
end

#move_feed_to_folder(feed, folder: nil, folder_title: nil) ⇒ Object

Move a feed to a folder. See FolderManager#move_feed_to_folder


198
199
200
# File 'app/models/user.rb', line 198

def move_feed_to_folder(feed, folder: nil, folder_title: nil)
  FolderManager.move_feed_to_folder feed, self, folder: folder, folder_title: folder_title
end

#refresh_feed(feed) ⇒ Object

Refresh a single feed. See FeedRefreshManager#refresh


205
206
207
# File 'app/models/user.rb', line 205

def refresh_feed(feed)
  FeedRefreshManager.refresh feed, self
end

#set_opml_export_job_state_visible(visible) ⇒ Object

Change the visibility of the alert related to the OPML export state. Receives a boolean argument and sets the alert to visible (if true) or hidden (if false).


294
295
296
# File 'app/models/user.rb', line 294

def set_opml_export_job_state_visible(visible)
  self.opml_export_job_state.update show_alert: visible
end

#set_opml_import_job_state_visible(visible) ⇒ Object

Change the visibility of the alert related to the OPML import state. Receives a boolean argument and sets the alert to visible (if true) or hidden (if false).


286
287
288
# File 'app/models/user.rb', line 286

def set_opml_import_job_state_visible(visible)
  self.opml_import_job_state.update show_alert: visible
end

#subscribe(url) ⇒ Object

Subscribe to a feed. See URLSubscriber#subscribe


219
220
221
# File 'app/models/user.rb', line 219

def subscribe(url)
  subscribed_feed = URLSubscriber.subscribe url, self
end

#subscribed_feeds(include_read: false, page: nil) ⇒ Object

Retrieves feeds subscribed by the user. See FeedsPagination#subscribed_feeds.


162
163
164
# File 'app/models/user.rb', line 162

def subscribed_feeds(include_read: false, page: nil)
  FeedsPagination.subscribed_feeds self, include_read: include_read, page: page
end

#unsubscribe(feed) ⇒ Object

Unsubscribe from a feed. See FeedUnsubscriber#unsubscribe


240
241
242
# File 'app/models/user.rb', line 240

def unsubscribe(feed)
  SubscriptionsManager.remove_subscription feed, self
end

#update_config(show_main_tour: nil, show_mobile_tour: nil, show_feed_tour: nil, show_entry_tour: nil, show_kb_shortcuts_tour: nil) ⇒ Object

Update the user configuration. Receives as optional named arguments the supported config values that can be set:

  • show_main_tour (boolean): whether to show the main application tour

  • show_mobile_tour (boolean): whether to show the mobile application tour

  • show_feed_tour (boolean): whether to show the feed application tour

  • show_entry_tour (boolean): whether to show the entry application tour

  • show_kb_shortcuts_tour (boolean): whether to show the keyboard shortcuts application tour


322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/user.rb', line 322

def update_config(show_main_tour: nil, show_mobile_tour: nil, show_feed_tour: nil, show_entry_tour: nil,
                  show_kb_shortcuts_tour: nil)
  new_config = {}
  new_config[:show_main_tour] = show_main_tour if !show_main_tour.nil?
  new_config[:show_mobile_tour] = show_mobile_tour if !show_mobile_tour.nil?
  new_config[:show_feed_tour] = show_feed_tour if !show_feed_tour.nil?
  new_config[:show_entry_tour] = show_entry_tour if !show_entry_tour.nil?
  new_config[:show_kb_shortcuts_tour] = show_kb_shortcuts_tour if !show_kb_shortcuts_tour.nil?
  Rails.logger.info "Updating user #{self.id} - #{self.email} with show_main_tour #{show_main_tour}, " +
                        "show_mobile_tour #{show_mobile_tour}, show_feed_tour #{show_feed_tour}, " +
                        "show_entry_tour #{show_entry_tour}, show_kb_shortcuts_tour #{show_kb_shortcuts_tour}"
  self.update new_config if new_config.length > 0
end