summaryrefslogtreecommitdiff
path: root/app/models/account.rb
blob: a85e56c649b078cd19b9ea57e36215f56feff825 (plain)
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