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
122
123
124
125
126
127
128
129
130
131
|
#
# The Account model takes care of the lifecycle of a user.
# It composes a User record and it's identity records.
# It also allows for other engines to hook into the lifecycle by
# monkeypatching the create, update and destroy methods.
# There's an ActiveSupport load_hook at the end of this file to
# make this more easy.
#
class Account
attr_reader :user
def initialize(user = nil)
@user = user
end
# Returns the user record so it can be used in views.
def self.create(attrs)
identity = nil
user = nil
user = User.new(attrs)
user.save
if !user.is_tmp? && user.persisted?
identity = user.identity
identity.user_id = user.id
identity.save
identity.errors.each do |attr, msg|
user.errors.add(attr, msg)
end
if APP_CONFIG[:invite_required]
user_invite_code = InviteCode.find_by_invite_code user.invite_code
user_invite_code.invite_count += 1
user_invite_code.save
end
end
rescue StandardError => ex
user.errors.add(:base, ex.to_s) if user
ensure
if creation_problem?(user, identity)
user.destroy if user && user.persisted?
identity.destroy if identity && identity.persisted?
end
return user
end
def update(attrs)
if attrs[:password_verifier].present?
update_login(attrs[:login])
@user.update_attributes attrs.slice(:password_verifier, :password_salt)
end
# TODO: move into identity controller
key = update_pgp_key(attrs[:public_key])
@user.errors.set :public_key, key.errors.full_messages
@user.save && save_identities
@user.refresh_identity
end
def destroy(destroy_identity=false)
return unless @user
if !@user.is_tmp?
if destroy_identity == false
@user.identities.each do |id|
id.orphan!
end
else
@user.identities.each do |id|
id.destroy
end
end
end
@user.destroy
end
# when a user is disable, all their data and associations remain
# in place, but the user should not be able to send email or
# create new authentication certificates.
def disable
if @user && !@user.is_tmp?
@user.enabled = false
@user.save
@user.identities.each do |id|
id.disable!
end
end
end
def enable
@user.enabled = true
@user.save
@user.identities.each do |id|
id.enable!
end
end
protected
def update_login(login)
return unless login.present?
@old_identity = Identity.for(@user)
@user.login = login
@new_identity = Identity.for(@user) # based on the new login
@old_identity.destination = @user.email_address # alias old -> new
end
def update_pgp_key(key)
PgpKey.new(key).tap do |key|
if key.present? && key.valid?
@new_identity ||= Identity.for(@user)
@new_identity.set_key(:pgp, key)
end
end
end
def save_identities
@new_identity.try(:save) && @old_identity.try(:save)
end
def self.creation_problem?(user, identity)
return true if user.nil? || !user.persisted? || user.errors.any?
if !user.is_tmp?
return true if identity.nil? || !identity.persisted? || identity.errors.any?
end
return false
end
# You can hook into the account lifecycle from different engines using
# ActiveSupport.on_load(:account) do ...
ActiveSupport.run_load_hooks(:account, self)
end
|