mirror of
https://github.com/mastodon/mastodon.git
synced 2025-09-06 09:51:24 +00:00
Extract User::Confirmation
concern (#35582)
This commit is contained in:
parent
15b72591d4
commit
6dc55a2f4e
22
app/models/concerns/user/confirmation.rb
Normal file
22
app/models/concerns/user/confirmation.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module User::Confirmation
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
scope :confirmed, -> { where.not(confirmed_at: nil) }
|
||||||
|
scope :unconfirmed, -> { where(confirmed_at: nil) }
|
||||||
|
|
||||||
|
def confirm
|
||||||
|
wrap_email_confirmation { super }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def confirmed?
|
||||||
|
confirmed_at.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def unconfirmed?
|
||||||
|
!confirmed?
|
||||||
|
end
|
||||||
|
end
|
|
@ -58,6 +58,7 @@ class User < ApplicationRecord
|
||||||
|
|
||||||
include LanguagesHelper
|
include LanguagesHelper
|
||||||
include Redisable
|
include Redisable
|
||||||
|
include User::Confirmation
|
||||||
include User::HasSettings
|
include User::HasSettings
|
||||||
include User::LdapAuthenticable
|
include User::LdapAuthenticable
|
||||||
include User::Omniauthable
|
include User::Omniauthable
|
||||||
|
@ -118,8 +119,6 @@ class User < ApplicationRecord
|
||||||
scope :recent, -> { order(id: :desc) }
|
scope :recent, -> { order(id: :desc) }
|
||||||
scope :pending, -> { where(approved: false) }
|
scope :pending, -> { where(approved: false) }
|
||||||
scope :approved, -> { where(approved: true) }
|
scope :approved, -> { where(approved: true) }
|
||||||
scope :confirmed, -> { where.not(confirmed_at: nil) }
|
|
||||||
scope :unconfirmed, -> { where(confirmed_at: nil) }
|
|
||||||
scope :enabled, -> { where(disabled: false) }
|
scope :enabled, -> { where(disabled: false) }
|
||||||
scope :disabled, -> { where(disabled: true) }
|
scope :disabled, -> { where(disabled: true) }
|
||||||
scope :active, -> { confirmed.signed_in_recently.account_not_suspended }
|
scope :active, -> { confirmed.signed_in_recently.account_not_suspended }
|
||||||
|
@ -184,10 +183,6 @@ class User < ApplicationRecord
|
||||||
current_sign_in_at.present? && current_sign_in_at >= ACTIVE_DURATION.ago
|
current_sign_in_at.present? && current_sign_in_at >= ACTIVE_DURATION.ago
|
||||||
end
|
end
|
||||||
|
|
||||||
def confirmed?
|
|
||||||
confirmed_at.present?
|
|
||||||
end
|
|
||||||
|
|
||||||
def invited?
|
def invited?
|
||||||
invite_id.present?
|
invite_id.present?
|
||||||
end
|
end
|
||||||
|
@ -212,12 +207,6 @@ class User < ApplicationRecord
|
||||||
account_id
|
account_id
|
||||||
end
|
end
|
||||||
|
|
||||||
def confirm
|
|
||||||
wrap_email_confirmation do
|
|
||||||
super
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Mark current email as confirmed, bypassing Devise
|
# Mark current email as confirmed, bypassing Devise
|
||||||
def mark_email_as_confirmed!
|
def mark_email_as_confirmed!
|
||||||
wrap_email_confirmation do
|
wrap_email_confirmation do
|
||||||
|
@ -264,10 +253,6 @@ class User < ApplicationRecord
|
||||||
confirmed? && approved? && !disabled? && !account.unavailable? && !account.memorial?
|
confirmed? && approved? && !disabled? && !account.unavailable? && !account.memorial?
|
||||||
end
|
end
|
||||||
|
|
||||||
def unconfirmed?
|
|
||||||
!confirmed?
|
|
||||||
end
|
|
||||||
|
|
||||||
def unconfirmed_or_pending?
|
def unconfirmed_or_pending?
|
||||||
unconfirmed? || pending?
|
unconfirmed? || pending?
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,6 +10,7 @@ RSpec.describe User do
|
||||||
let(:account) { Fabricate(:account, username: 'alice') }
|
let(:account) { Fabricate(:account, username: 'alice') }
|
||||||
|
|
||||||
it_behaves_like 'two_factor_backupable'
|
it_behaves_like 'two_factor_backupable'
|
||||||
|
it_behaves_like 'User::Confirmation'
|
||||||
|
|
||||||
describe 'otp_secret' do
|
describe 'otp_secret' do
|
||||||
it 'encrypts the saved value' do
|
it 'encrypts the saved value' do
|
||||||
|
@ -65,14 +66,6 @@ RSpec.describe User do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'confirmed' do
|
|
||||||
it 'returns an array of users who are confirmed' do
|
|
||||||
Fabricate(:user, confirmed_at: nil)
|
|
||||||
confirmed_user = Fabricate(:user, confirmed_at: Time.zone.now)
|
|
||||||
expect(described_class.confirmed).to contain_exactly(confirmed_user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'signed_in_recently' do
|
describe 'signed_in_recently' do
|
||||||
it 'returns a relation of users who have signed in during the recent period' do
|
it 'returns a relation of users who have signed in during the recent period' do
|
||||||
recent_sign_in_user = Fabricate(:user, current_sign_in_at: within_duration_window_days.ago)
|
recent_sign_in_user = Fabricate(:user, current_sign_in_at: within_duration_window_days.ago)
|
||||||
|
@ -228,79 +221,6 @@ RSpec.describe User do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#confirmed?' do
|
|
||||||
it 'returns true when a confirmed_at is set' do
|
|
||||||
user = Fabricate.build(:user, confirmed_at: Time.now.utc)
|
|
||||||
expect(user.confirmed?).to be true
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns false if a confirmed_at is nil' do
|
|
||||||
user = Fabricate.build(:user, confirmed_at: nil)
|
|
||||||
expect(user.confirmed?).to be false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#confirm' do
|
|
||||||
subject { user.confirm }
|
|
||||||
|
|
||||||
let(:new_email) { 'new-email@example.com' }
|
|
||||||
|
|
||||||
before do
|
|
||||||
allow(TriggerWebhookWorker).to receive(:perform_async)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the user is already confirmed' do
|
|
||||||
let!(:user) { Fabricate(:user, confirmed_at: Time.now.utc, approved: true, unconfirmed_email: new_email) }
|
|
||||||
|
|
||||||
it 'sets email to unconfirmed_email and does not trigger web hook' do
|
|
||||||
expect { subject }.to change { user.reload.email }.to(new_email)
|
|
||||||
|
|
||||||
expect(TriggerWebhookWorker).to_not have_received(:perform_async).with('account.approved', 'Account', user.account_id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the user is a new user' do
|
|
||||||
let(:user) { Fabricate(:user, confirmed_at: nil, unconfirmed_email: new_email) }
|
|
||||||
|
|
||||||
context 'when the user is already approved' do
|
|
||||||
before do
|
|
||||||
Setting.registrations_mode = 'approved'
|
|
||||||
user.approve!
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'sets email to unconfirmed_email and triggers `account.approved` web hook' do
|
|
||||||
expect { subject }.to change { user.reload.email }.to(new_email)
|
|
||||||
|
|
||||||
expect(TriggerWebhookWorker).to have_received(:perform_async).with('account.approved', 'Account', user.account_id).once
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the user does not require explicit approval' do
|
|
||||||
before do
|
|
||||||
Setting.registrations_mode = 'open'
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'sets email to unconfirmed_email and triggers `account.approved` web hook' do
|
|
||||||
expect { subject }.to change { user.reload.email }.to(new_email)
|
|
||||||
|
|
||||||
expect(TriggerWebhookWorker).to have_received(:perform_async).with('account.approved', 'Account', user.account_id).once
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the user requires explicit approval but is not approved' do
|
|
||||||
before do
|
|
||||||
Setting.registrations_mode = 'approved'
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'sets email to unconfirmed_email and does not trigger web hook' do
|
|
||||||
expect { subject }.to change { user.reload.email }.to(new_email)
|
|
||||||
|
|
||||||
expect(TriggerWebhookWorker).to_not have_received(:perform_async).with('account.approved', 'Account', user.account_id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#approve!' do
|
describe '#approve!' do
|
||||||
subject { user.approve! }
|
subject { user.approve! }
|
||||||
|
|
||||||
|
|
114
spec/support/examples/models/concerns/user/confirmation.rb
Normal file
114
spec/support/examples/models/concerns/user/confirmation.rb
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.shared_examples 'User::Confirmation' do
|
||||||
|
describe 'Scopes' do
|
||||||
|
let!(:unconfirmed_user) { Fabricate :user, confirmed_at: nil }
|
||||||
|
let!(:confirmed_user) { Fabricate :user, confirmed_at: Time.now.utc }
|
||||||
|
|
||||||
|
describe '.confirmed' do
|
||||||
|
it 'returns users who are confirmed' do
|
||||||
|
expect(described_class.confirmed)
|
||||||
|
.to contain_exactly(confirmed_user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '.unconfirmed' do
|
||||||
|
it 'returns users who are not confirmed' do
|
||||||
|
expect(described_class.unconfirmed)
|
||||||
|
.to contain_exactly(unconfirmed_user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#confirmed?' do
|
||||||
|
subject { Fabricate.build(:user, confirmed_at:) }
|
||||||
|
|
||||||
|
context 'when confirmed_at is set' do
|
||||||
|
let(:confirmed_at) { Time.now.utc }
|
||||||
|
|
||||||
|
it { is_expected.to be_confirmed }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when confirmed_at is not set' do
|
||||||
|
let(:confirmed_at) { nil }
|
||||||
|
|
||||||
|
it { is_expected.to_not be_confirmed }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#unconfirmed?' do
|
||||||
|
subject { Fabricate.build(:user, confirmed_at:) }
|
||||||
|
|
||||||
|
context 'when confirmed_at is set' do
|
||||||
|
let(:confirmed_at) { Time.now.utc }
|
||||||
|
|
||||||
|
it { is_expected.to_not be_unconfirmed }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when confirmed_at is not set' do
|
||||||
|
let(:confirmed_at) { nil }
|
||||||
|
|
||||||
|
it { is_expected.to be_unconfirmed }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#confirm' do
|
||||||
|
subject { user.confirm }
|
||||||
|
|
||||||
|
let(:new_email) { 'new-email@host.example' }
|
||||||
|
|
||||||
|
before { allow(TriggerWebhookWorker).to receive(:perform_async) }
|
||||||
|
|
||||||
|
context 'when the user is already confirmed' do
|
||||||
|
let!(:user) { Fabricate(:user, confirmed_at: Time.now.utc, approved: true, unconfirmed_email: new_email) }
|
||||||
|
|
||||||
|
it 'sets email to unconfirmed_email and does not trigger web hook' do
|
||||||
|
expect { subject }
|
||||||
|
.to change { user.reload.email }.to(new_email)
|
||||||
|
expect(TriggerWebhookWorker)
|
||||||
|
.to_not have_received(:perform_async).with('account.approved', 'Account', user.account_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the user is a new user' do
|
||||||
|
let(:user) { Fabricate(:user, confirmed_at: nil, unconfirmed_email: new_email) }
|
||||||
|
|
||||||
|
context 'when the user does not require explicit approval' do
|
||||||
|
before { Setting.registrations_mode = 'open' }
|
||||||
|
|
||||||
|
it 'sets email to unconfirmed_email and triggers `account.approved` web hook' do
|
||||||
|
expect { subject }
|
||||||
|
.to change { user.reload.email }.to(new_email)
|
||||||
|
expect(TriggerWebhookWorker)
|
||||||
|
.to have_received(:perform_async).with('account.approved', 'Account', user.account_id).once
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when registrations mode is approved' do
|
||||||
|
before { Setting.registrations_mode = 'approved' }
|
||||||
|
|
||||||
|
context 'when the user is already approved' do
|
||||||
|
before { user.approve! }
|
||||||
|
|
||||||
|
it 'sets email to unconfirmed_email and triggers `account.approved` web hook' do
|
||||||
|
expect { subject }
|
||||||
|
.to change { user.reload.email }.to(new_email)
|
||||||
|
expect(TriggerWebhookWorker)
|
||||||
|
.to have_received(:perform_async).with('account.approved', 'Account', user.account_id).once
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the user is not approved' do
|
||||||
|
it 'sets email to unconfirmed_email and does not trigger web hook' do
|
||||||
|
expect { subject }
|
||||||
|
.to change { user.reload.email }.to(new_email)
|
||||||
|
expect(TriggerWebhookWorker)
|
||||||
|
.to_not have_received(:perform_async).with('account.approved', 'Account', user.account_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user