forked from discourse/discourse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
email_updater.rb
121 lines (100 loc) · 3.68 KB
/
email_updater.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
require_dependency 'email'
require_dependency 'has_errors'
require_dependency 'email_validator'
class EmailUpdater
include HasErrors
attr_reader :user
def initialize(guardian = nil, user = nil)
@guardian = guardian
@user = user
end
def self.human_attribute_name(name, options = {})
User.human_attribute_name(name, options)
end
def authorize_both?
@user.staff?
end
def change_to(email_input)
@guardian.ensure_can_edit_email!(@user)
email = Email.downcase(email_input.strip)
EmailValidator.new(attributes: :email).validate_each(self, :email, email)
if existing_user = User.find_by_email(email)
if SiteSetting.hide_email_address_taken
Jobs.enqueue(:critical_user_email, type: :account_exists, user_id: existing_user.id)
else
error_message = 'change_email.error'
error_message << '_staged' if existing_user.staged?
errors.add(:base, I18n.t(error_message))
end
end
if errors.blank? && existing_user.nil?
args = {
old_email: @user.email,
new_email: email,
}
if authorize_both?
args[:change_state] = EmailChangeRequest.states[:authorizing_old]
email_token = @user.email_tokens.create!(email: args[:old_email])
args[:old_email_token] = email_token
else
args[:change_state] = EmailChangeRequest.states[:authorizing_new]
email_token = @user.email_tokens.create!(email: args[:new_email])
args[:new_email_token] = email_token
end
@user.email_change_requests.create!(args)
if args[:change_state] == EmailChangeRequest.states[:authorizing_new]
send_email(:confirm_new_email, email_token)
elsif args[:change_state] == EmailChangeRequest.states[:authorizing_old]
send_email(:confirm_old_email, email_token)
end
end
end
def confirm(token)
confirm_result = nil
change_req = nil
User.transaction do
result = EmailToken.atomic_confirm(token)
if result[:success]
token = result[:email_token]
@user = token.user
change_req = user.email_change_requests
.where('old_email_token_id = :token_id OR new_email_token_id = :token_id', token_id: token.id)
.first
# Simple state machine
case change_req.try(:change_state)
when EmailChangeRequest.states[:authorizing_old]
new_token = user.email_tokens.create(email: change_req.new_email)
change_req.update_columns(change_state: EmailChangeRequest.states[:authorizing_new],
new_email_token_id: new_token.id)
send_email(:confirm_new_email, new_token)
confirm_result = :authorizing_new
when EmailChangeRequest.states[:authorizing_new]
change_req.update_column(:change_state, EmailChangeRequest.states[:complete])
user.primary_email.update!(email: token.email)
confirm_result = :complete
end
else
errors.add(:base, I18n.t('change_email.already_done'))
confirm_result = :error
end
end
if confirm_result == :complete && change_req.old_email_token_id.blank?
notify_old(change_req.old_email, token.email)
end
confirm_result || :error
end
protected
def notify_old(old_email, new_email)
Jobs.enqueue :critical_user_email,
to_address: old_email,
type: :notify_old_email,
user_id: @user.id
end
def send_email(type, email_token)
Jobs.enqueue :critical_user_email,
to_address: email_token.email,
type: type,
user_id: @user.id,
email_token: email_token.token
end
end