diff options
author | Thibaut Girka <thib@sitedethib.com> | 2019-03-14 17:14:05 +0100 |
---|---|---|
committer | Thibaut Girka <thib@sitedethib.com> | 2019-03-14 17:17:20 +0100 |
commit | 07eb31eeacc4e0364b839233a41fa65eb3c650ce (patch) | |
tree | 843cda5a4d9bc730aba9a13d0634fef5e2212515 /app/models | |
parent | fa75324059c7a146354470691888dc0e1de0342f (diff) | |
parent | 874bd3ac0c56e2d2901785e170b27f5cde32b33b (diff) |
Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - app/views/admin/settings/edit.html.haml: Conflict due to how the theming settings change.
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/account.rb | 2 | ||||
-rw-r--r-- | app/models/account_filter.rb | 4 | ||||
-rw-r--r-- | app/models/concerns/ldap_authenticable.rb | 25 | ||||
-rw-r--r-- | app/models/concerns/omniauthable.rb | 2 | ||||
-rw-r--r-- | app/models/concerns/pam_authenticable.rb | 68 | ||||
-rw-r--r-- | app/models/concerns/user_roles.rb | 54 | ||||
-rw-r--r-- | app/models/form/admin_settings.rb | 4 | ||||
-rw-r--r-- | app/models/user.rb | 166 |
8 files changed, 201 insertions, 124 deletions
diff --git a/app/models/account.rb b/app/models/account.rb index 0bb20b2f2..6b539f004 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -108,6 +108,8 @@ class Account < ApplicationRecord :current_sign_in_ip, :current_sign_in_at, :confirmed?, + :approved?, + :pending?, :admin?, :moderator?, :staff?, diff --git a/app/models/account_filter.rb b/app/models/account_filter.rb index b10f50db7..d2503100c 100644 --- a/app/models/account_filter.rb +++ b/app/models/account_filter.rb @@ -22,7 +22,7 @@ class AccountFilter def set_defaults! params['local'] = '1' if params['remote'].blank? - params['active'] = '1' if params['suspended'].blank? && params['silenced'].blank? + params['active'] = '1' if params['suspended'].blank? && params['silenced'].blank? && params['pending'].blank? end def scope_for(key, value) @@ -35,6 +35,8 @@ class AccountFilter Account.where(domain: value) when 'active' Account.without_suspended + when 'pending' + accounts_with_users.merge User.pending when 'silenced' Account.silenced when 'suspended' diff --git a/app/models/concerns/ldap_authenticable.rb b/app/models/concerns/ldap_authenticable.rb new file mode 100644 index 000000000..e1b5e3832 --- /dev/null +++ b/app/models/concerns/ldap_authenticable.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module LdapAuthenticable + extend ActiveSupport::Concern + + def ldap_setup(_attributes) + self.confirmed_at = Time.now.utc + self.admin = false + + save! + end + + class_methods do + def ldap_get_user(attributes = {}) + resource = joins(:account).find_by(accounts: { username: attributes[Devise.ldap_uid.to_sym].first }) + + if resource.blank? + resource = new(email: attributes[:mail].first, agreement: true, account_attributes: { username: attributes[Devise.ldap_uid.to_sym].first }) + resource.ldap_setup(attributes) + end + + resource + end + end +end diff --git a/app/models/concerns/omniauthable.rb b/app/models/concerns/omniauthable.rb index 4dd2e9383..1b28b8162 100644 --- a/app/models/concerns/omniauthable.rb +++ b/app/models/concerns/omniauthable.rb @@ -7,6 +7,8 @@ module Omniauthable TEMP_EMAIL_REGEX = /\Achange@me/ included do + devise :omniauthable + def omniauth_providers Devise.omniauth_configs.keys end diff --git a/app/models/concerns/pam_authenticable.rb b/app/models/concerns/pam_authenticable.rb new file mode 100644 index 000000000..2f651c1a3 --- /dev/null +++ b/app/models/concerns/pam_authenticable.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +module PamAuthenticable + extend ActiveSupport::Concern + + included do + devise :pam_authenticatable if ENV['PAM_ENABLED'] == 'true' + + def pam_conflict(_attributes) + # Block pam login tries on traditional account + end + + def pam_conflict? + if Devise.pam_authentication + encrypted_password.present? && pam_managed_user? + else + false + end + end + + def pam_get_name + if account.present? + account.username + else + super + end + end + + def pam_setup(_attributes) + account = Account.new(username: pam_get_name) + account.save!(validate: false) + + self.email = "#{account.username}@#{find_pam_suffix}" if email.nil? && find_pam_suffix + self.confirmed_at = Time.now.utc + self.admin = false + self.account = account + + account.destroy! unless save + end + + def self.pam_get_user(attributes = {}) + return nil unless attributes[:email] + + resource = begin + if Devise.check_at_sign && !attributes[:email].index('@') + joins(:account).find_by(accounts: { username: attributes[:email] }) + else + find_by(email: attributes[:email]) + end + end + + if resource.nil? + resource = new(email: attributes[:email], agreement: true) + + if Devise.check_at_sign && !resource[:email].index('@') + resource[:email] = Rpam2.getenv(resource.find_pam_service, attributes[:email], attributes[:password], 'email', false) + resource[:email] = "#{attributes[:email]}@#{resource.find_pam_suffix}" unless resource[:email] + end + end + + resource + end + + def self.authenticate_with_pam(attributes = {}) + super if Devise.pam_authentication + end + end +end diff --git a/app/models/concerns/user_roles.rb b/app/models/concerns/user_roles.rb new file mode 100644 index 000000000..58dffdc46 --- /dev/null +++ b/app/models/concerns/user_roles.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module UserRoles + extend ActiveSupport::Concern + + included do + scope :admins, -> { where(admin: true) } + scope :moderators, -> { where(moderator: true) } + scope :staff, -> { admins.or(moderators) } + end + + def staff? + admin? || moderator? + end + + def role + if admin? + 'admin' + elsif moderator? + 'moderator' + else + 'user' + end + end + + def role?(role) + case role + when 'user' + true + when 'moderator' + staff? + when 'admin' + admin? + else + false + end + end + + def promote! + if moderator? + update!(moderator: false, admin: true) + elsif !admin? + update!(moderator: true) + end + end + + def demote! + if admin? + update!(admin: false, moderator: true) + elsif moderator? + update!(moderator: false) + end + end +end diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb index d568200ed..929c65793 100644 --- a/app/models/form/admin_settings.rb +++ b/app/models/form/admin_settings.rb @@ -18,8 +18,8 @@ class Form::AdminSettings :site_extended_description=, :site_terms, :site_terms=, - :open_registrations, - :open_registrations=, + :registrations_mode, + :registrations_mode=, :closed_registrations_message, :closed_registrations_message=, :open_deletion, diff --git a/app/models/user.rb b/app/models/user.rb index f91ed7015..47657a670 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -37,11 +37,12 @@ # remember_token :string # chosen_languages :string is an Array # created_by_application_id :bigint(8) +# approved :boolean default(TRUE), not null # class User < ApplicationRecord include Settings::Extend - include Omniauthable + include UserRoles # The home and list feeds will be stored in Redis for this amount # of time, and status fan-out to followers will include only people @@ -61,9 +62,9 @@ class User < ApplicationRecord devise :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable - devise :pam_authenticatable if ENV['PAM_ENABLED'] == 'true' - - devise :omniauthable + include Omniauthable + include PamAuthenticable + include LdapAuthenticable belongs_to :account, inverse_of: :user belongs_to :invite, counter_cache: :uses, optional: true @@ -79,9 +80,8 @@ class User < ApplicationRecord validates :agreement, acceptance: { allow_nil: false, accept: [true, 'true', '1'] }, on: :create scope :recent, -> { order(id: :desc) } - scope :admins, -> { where(admin: true) } - scope :moderators, -> { where(moderator: true) } - scope :staff, -> { admins.or(moderators) } + scope :pending, -> { where(approved: false) } + scope :approved, -> { where(approved: true) } scope :confirmed, -> { where.not(confirmed_at: nil) } scope :enabled, -> { where(disabled: false) } scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) } @@ -90,6 +90,7 @@ class User < ApplicationRecord scope :emailable, -> { confirmed.enabled.joins(:account).merge(Account.searchable) } before_validation :sanitize_languages + before_create :set_approved # This avoids a deprecation warning from Rails 5.1 # It seems possible that a future release of devise-two-factor will @@ -104,39 +105,6 @@ class User < ApplicationRecord attr_reader :invite_code - def pam_conflict(_) - # block pam login tries on traditional account - nil - end - - def pam_conflict? - return false unless Devise.pam_authentication - encrypted_password.present? && pam_managed_user? - end - - def pam_get_name - return account.username if account.present? - super - end - - def pam_setup(_attributes) - acc = Account.new(username: pam_get_name) - acc.save!(validate: false) - - self.email = "#{acc.username}@#{find_pam_suffix}" if email.nil? && find_pam_suffix - self.confirmed_at = Time.now.utc - self.admin = false - self.account = acc - - acc.destroy! unless save - end - - def ldap_setup(_attributes) - self.confirmed_at = Time.now.utc - self.admin = false - save! - end - def confirmed? confirmed_at.present? end @@ -145,33 +113,6 @@ class User < ApplicationRecord invite_id.present? end - def staff? - admin? || moderator? - end - - def role - if admin? - 'admin' - elsif moderator? - 'moderator' - else - 'user' - end - end - - def role?(role) - case role - when 'user' - true - when 'moderator' - staff? - when 'admin' - admin? - else - false - end - end - def disable! update!(disabled: true, last_sign_in_at: current_sign_in_at, @@ -186,7 +127,12 @@ class User < ApplicationRecord new_user = !confirmed? super - prepare_new_user! if new_user + + if new_user && approved? + prepare_new_user! + elsif new_user + notify_staff_about_pending_account! + end end def confirm! @@ -194,28 +140,32 @@ class User < ApplicationRecord skip_confirmation! save! - prepare_new_user! if new_user + + prepare_new_user! if new_user && approved? end - def update_tracked_fields!(request) - super - prepare_returning_user! + def pending? + !approved? end - def promote! - if moderator? - update!(moderator: false, admin: true) - elsif !admin? - update!(moderator: true) - end + def active_for_authentication? + super && approved? end - def demote! - if admin? - update!(admin: false, moderator: true) - elsif moderator? - update!(moderator: false) - end + def inactive_message + !approved? ? :pending : super + end + + def approve! + return if approved? + + update!(approved: true) + prepare_new_user! + end + + def update_tracked_fields!(request) + super + prepare_returning_user! end def disable_two_factor! @@ -297,43 +247,6 @@ class User < ApplicationRecord super end - def self.pam_get_user(attributes = {}) - return nil unless attributes[:email] - - resource = - if Devise.check_at_sign && !attributes[:email].index('@') - joins(:account).find_by(accounts: { username: attributes[:email] }) - else - find_by(email: attributes[:email]) - end - - if resource.blank? - resource = new(email: attributes[:email], agreement: true) - - if Devise.check_at_sign && !resource[:email].index('@') - resource[:email] = Rpam2.getenv(resource.find_pam_service, attributes[:email], attributes[:password], 'email', false) - resource[:email] = "#{attributes[:email]}@#{resource.find_pam_suffix}" unless resource[:email] - end - end - resource - end - - def self.ldap_get_user(attributes = {}) - resource = joins(:account).find_by(accounts: { username: attributes[Devise.ldap_uid.to_sym].first }) - - if resource.blank? - resource = new(email: attributes[:mail].first, agreement: true, account_attributes: { username: attributes[Devise.ldap_uid.to_sym].first }) - resource.ldap_setup(attributes) - end - - resource - end - - def self.authenticate_with_pam(attributes = {}) - return nil unless Devise.pam_authentication - super - end - def show_all_media? setting_display_media == 'show_all' end @@ -350,6 +263,10 @@ class User < ApplicationRecord private + def set_approved + self.approved = Setting.registrations_mode == 'open' || invited? + end + def sanitize_languages return if chosen_languages.nil? chosen_languages.reject!(&:blank?) @@ -367,6 +284,13 @@ class User < ApplicationRecord regenerate_feed! if needs_feed_update? end + def notify_staff_about_pending_account! + User.staff.includes(:account).each do |u| + next unless u.allows_report_emails? + AdminMailer.new_pending_account(u.account, self).deliver_later + end + end + def regenerate_feed! return unless Redis.current.setnx("account:#{account_id}:regeneration", true) Redis.current.expire("account:#{account_id}:regeneration", 1.day.seconds) |