The code powering m.abunchtell.com https://m.abunchtell.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

371 lines
11 KiB

  1. # frozen_string_literal: true
  2. # == Schema Information
  3. #
  4. # Table name: users
  5. #
  6. # id :bigint(8) not null, primary key
  7. # email :string default(""), not null
  8. # created_at :datetime not null
  9. # updated_at :datetime not null
  10. # encrypted_password :string default(""), not null
  11. # reset_password_token :string
  12. # reset_password_sent_at :datetime
  13. # remember_created_at :datetime
  14. # sign_in_count :integer default(0), not null
  15. # current_sign_in_at :datetime
  16. # last_sign_in_at :datetime
  17. # current_sign_in_ip :inet
  18. # last_sign_in_ip :inet
  19. # admin :boolean default(FALSE), not null
  20. # confirmation_token :string
  21. # confirmed_at :datetime
  22. # confirmation_sent_at :datetime
  23. # unconfirmed_email :string
  24. # locale :string
  25. # encrypted_otp_secret :string
  26. # encrypted_otp_secret_iv :string
  27. # encrypted_otp_secret_salt :string
  28. # consumed_timestep :integer
  29. # otp_required_for_login :boolean default(FALSE), not null
  30. # last_emailed_at :datetime
  31. # otp_backup_codes :string is an Array
  32. # filtered_languages :string default([]), not null, is an Array
  33. # account_id :bigint(8) not null
  34. # disabled :boolean default(FALSE), not null
  35. # moderator :boolean default(FALSE), not null
  36. # invite_id :bigint(8)
  37. # remember_token :string
  38. # chosen_languages :string is an Array
  39. # created_by_application_id :bigint(8)
  40. #
  41. class User < ApplicationRecord
  42. include Settings::Extend
  43. include Omniauthable
  44. # The home and list feeds will be stored in Redis for this amount
  45. # of time, and status fan-out to followers will include only people
  46. # within this time frame. Lowering the duration may improve performance
  47. # if lots of people sign up, but not a lot of them check their feed
  48. # every day. Raising the duration reduces the amount of expensive
  49. # RegenerationWorker jobs that need to be run when those people come
  50. # to check their feed
  51. ACTIVE_DURATION = ENV.fetch('USER_ACTIVE_DAYS', 7).to_i.days
  52. devise :two_factor_authenticatable,
  53. otp_secret_encryption_key: Rails.configuration.x.otp_secret
  54. devise :two_factor_backupable,
  55. otp_number_of_backup_codes: 10
  56. devise :registerable, :recoverable, :rememberable, :trackable, :validatable,
  57. :confirmable
  58. devise :pam_authenticatable if ENV['PAM_ENABLED'] == 'true'
  59. devise :omniauthable
  60. belongs_to :account, inverse_of: :user
  61. belongs_to :invite, counter_cache: :uses, optional: true
  62. belongs_to :created_by_application, class_name: 'Doorkeeper::Application', optional: true
  63. accepts_nested_attributes_for :account
  64. has_many :applications, class_name: 'Doorkeeper::Application', as: :owner
  65. has_many :backups, inverse_of: :user
  66. validates :locale, inclusion: I18n.available_locales.map(&:to_s), if: :locale?
  67. validates_with BlacklistedEmailValidator, if: :email_changed?
  68. validates_with EmailMxValidator, if: :validate_email_dns?
  69. validates :agreement, acceptance: { allow_nil: false, accept: [true, 'true', '1'] }, on: :create
  70. scope :recent, -> { order(id: :desc) }
  71. scope :admins, -> { where(admin: true) }
  72. scope :moderators, -> { where(moderator: true) }
  73. scope :staff, -> { admins.or(moderators) }
  74. scope :confirmed, -> { where.not(confirmed_at: nil) }
  75. scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) }
  76. scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where(accounts: { suspended: false }) }
  77. scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) }
  78. before_validation :sanitize_languages
  79. # This avoids a deprecation warning from Rails 5.1
  80. # It seems possible that a future release of devise-two-factor will
  81. # handle this itself, and this can be removed from our User class.
  82. attribute :otp_secret
  83. has_many :session_activations, dependent: :destroy
  84. delegate :auto_play_gif, :default_sensitive, :unfollow_modal, :boost_modal, :delete_modal,
  85. :reduce_motion, :system_font_ui, :noindex, :theme, :display_media, :hide_network,
  86. :expand_spoilers, :default_language, :aggregate_reblogs, to: :settings, prefix: :setting, allow_nil: false
  87. attr_reader :invite_code
  88. def pam_conflict(_)
  89. # block pam login tries on traditional account
  90. nil
  91. end
  92. def pam_conflict?
  93. return false unless Devise.pam_authentication
  94. encrypted_password.present? && pam_managed_user?
  95. end
  96. def pam_get_name
  97. return account.username if account.present?
  98. super
  99. end
  100. def pam_setup(_attributes)
  101. acc = Account.new(username: pam_get_name)
  102. acc.save!(validate: false)
  103. self.email = "#{acc.username}@#{find_pam_suffix}" if email.nil? && find_pam_suffix
  104. self.confirmed_at = Time.now.utc
  105. self.admin = false
  106. self.account = acc
  107. acc.destroy! unless save
  108. end
  109. def ldap_setup(_attributes)
  110. self.confirmed_at = Time.now.utc
  111. self.admin = false
  112. save!
  113. end
  114. def confirmed?
  115. confirmed_at.present?
  116. end
  117. def staff?
  118. admin? || moderator?
  119. end
  120. def role
  121. if admin?
  122. 'admin'
  123. elsif moderator?
  124. 'moderator'
  125. else
  126. 'user'
  127. end
  128. end
  129. def role?(role)
  130. case role
  131. when 'user'
  132. true
  133. when 'moderator'
  134. staff?
  135. when 'admin'
  136. admin?
  137. else
  138. false
  139. end
  140. end
  141. def disable!
  142. update!(disabled: true,
  143. last_sign_in_at: current_sign_in_at,
  144. current_sign_in_at: nil)
  145. end
  146. def enable!
  147. update!(disabled: false)
  148. end
  149. def confirm
  150. new_user = !confirmed?
  151. super
  152. prepare_new_user! if new_user
  153. end
  154. def confirm!
  155. new_user = !confirmed?
  156. skip_confirmation!
  157. save!
  158. prepare_new_user! if new_user
  159. end
  160. def update_tracked_fields!(request)
  161. super
  162. prepare_returning_user!
  163. end
  164. def promote!
  165. if moderator?
  166. update!(moderator: false, admin: true)
  167. elsif !admin?
  168. update!(moderator: true)
  169. end
  170. end
  171. def demote!
  172. if admin?
  173. update!(admin: false, moderator: true)
  174. elsif moderator?
  175. update!(moderator: false)
  176. end
  177. end
  178. def disable_two_factor!
  179. self.otp_required_for_login = false
  180. otp_backup_codes&.clear
  181. save!
  182. end
  183. def setting_default_privacy
  184. settings.default_privacy || (account.locked? ? 'private' : 'public')
  185. end
  186. def allows_digest_emails?
  187. settings.notification_emails['digest']
  188. end
  189. def allows_report_emails?
  190. settings.notification_emails['report']
  191. end
  192. def hides_network?
  193. @hides_network ||= settings.hide_network
  194. end
  195. def aggregates_reblogs?
  196. @aggregates_reblogs ||= settings.aggregate_reblogs
  197. end
  198. def token_for_app(a)
  199. return nil if a.nil? || a.owner != self
  200. Doorkeeper::AccessToken
  201. .find_or_create_by(application_id: a.id, resource_owner_id: id) do |t|
  202. t.scopes = a.scopes
  203. t.expires_in = Doorkeeper.configuration.access_token_expires_in
  204. t.use_refresh_token = Doorkeeper.configuration.refresh_token_enabled?
  205. end
  206. end
  207. def activate_session(request)
  208. session_activations.activate(session_id: SecureRandom.hex,
  209. user_agent: request.user_agent,
  210. ip: request.remote_ip).session_id
  211. end
  212. def exclusive_session(id)
  213. session_activations.exclusive(id)
  214. end
  215. def session_active?(id)
  216. session_activations.active? id
  217. end
  218. def web_push_subscription(session)
  219. session.web_push_subscription.nil? ? nil : session.web_push_subscription
  220. end
  221. def invite_code=(code)
  222. self.invite = Invite.find_by(code: code) if code.present?
  223. @invite_code = code
  224. end
  225. def password_required?
  226. return false if Devise.pam_authentication || Devise.ldap_authentication
  227. super
  228. end
  229. def send_reset_password_instructions
  230. return false if encrypted_password.blank? && (Devise.pam_authentication || Devise.ldap_authentication)
  231. super
  232. end
  233. def reset_password!(new_password, new_password_confirmation)
  234. return false if encrypted_password.blank? && (Devise.pam_authentication || Devise.ldap_authentication)
  235. super
  236. end
  237. def self.pam_get_user(attributes = {})
  238. return nil unless attributes[:email]
  239. resource =
  240. if Devise.check_at_sign && !attributes[:email].index('@')
  241. joins(:account).find_by(accounts: { username: attributes[:email] })
  242. else
  243. find_by(email: attributes[:email])
  244. end
  245. if resource.blank?
  246. resource = new(email: attributes[:email], agreement: true)
  247. if Devise.check_at_sign && !resource[:email].index('@')
  248. resource[:email] = Rpam2.getenv(resource.find_pam_service, attributes[:email], attributes[:password], 'email', false)
  249. resource[:email] = "#{attributes[:email]}@#{resource.find_pam_suffix}" unless resource[:email]
  250. end
  251. end
  252. resource
  253. end
  254. def self.ldap_get_user(attributes = {})
  255. resource = joins(:account).find_by(accounts: { username: attributes[Devise.ldap_uid.to_sym].first })
  256. if resource.blank?
  257. resource = new(email: attributes[:mail].first, agreement: true, account_attributes: { username: attributes[Devise.ldap_uid.to_sym].first })
  258. resource.ldap_setup(attributes)
  259. end
  260. resource
  261. end
  262. def self.authenticate_with_pam(attributes = {})
  263. return nil unless Devise.pam_authentication
  264. super
  265. end
  266. def show_all_media?
  267. setting_display_media == 'show_all'
  268. end
  269. def hide_all_media?
  270. setting_display_media == 'hide_all'
  271. end
  272. protected
  273. def send_devise_notification(notification, *args)
  274. devise_mailer.send(notification, self, *args).deliver_later
  275. end
  276. private
  277. def sanitize_languages
  278. return if chosen_languages.nil?
  279. chosen_languages.reject!(&:blank?)
  280. self.chosen_languages = nil if chosen_languages.empty?
  281. end
  282. def prepare_new_user!
  283. BootstrapTimelineWorker.perform_async(account_id)
  284. ActivityTracker.increment('activity:accounts:local')
  285. UserMailer.welcome(self).deliver_later
  286. end
  287. def prepare_returning_user!
  288. ActivityTracker.record('activity:logins', id)
  289. regenerate_feed! if needs_feed_update?
  290. end
  291. def regenerate_feed!
  292. Redis.current.setnx("account:#{account_id}:regeneration", true) && Redis.current.expire("account:#{account_id}:regeneration", 1.day.seconds)
  293. RegenerationWorker.perform_async(account_id)
  294. end
  295. def needs_feed_update?
  296. last_sign_in_at < ACTIVE_DURATION.ago
  297. end
  298. def validate_email_dns?
  299. email_changed? && !(Rails.env.test? || Rails.env.development?)
  300. end
  301. end