File: account_expiration.rb

package info (click to toggle)
ruby-rodauth 2.42.0-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 812 kB
  • sloc: ruby: 7,524; javascript: 100; makefile: 4
file content (128 lines) | stat: -rw-r--r-- 3,888 bytes parent folder | download | duplicates (2)
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
# frozen-string-literal: true

module Rodauth
  Feature.define(:account_expiration, :AccountExpiration) do
    error_flash "You cannot log into this account as it has expired"
    redirect
    after

    auth_value_method :account_activity_expired_column, :expired_at
    auth_value_method :account_activity_id_column, :id
    auth_value_method :account_activity_last_activity_column, :last_activity_at
    auth_value_method :account_activity_last_login_column, :last_login_at
    auth_value_method :account_activity_table, :account_activity_times
    auth_value_method :expire_account_after, 180*86400
    auth_value_method :expire_account_on_last_activity?, false

    auth_methods(
      :account_expired?,
      :account_expired_at,
      :last_account_activity_at,
      :last_account_login_at,
      :set_expired,
      :update_last_activity,
      :update_last_login
    )

    def last_account_activity_at
      get_activity_timestamp(session_value, account_activity_last_activity_column)
    end

    def last_account_login_at
      get_activity_timestamp(session_value, account_activity_last_login_column)
    end

    def account_expired_at
      get_activity_timestamp(account_id, account_activity_expired_column)
    end

    def update_last_login
      update_activity(account_id, account_activity_last_login_column, account_activity_last_activity_column)
    end

    def update_last_activity
      if session_value
        update_activity(session_value, account_activity_last_activity_column)
      end
    end

    def set_expired
      update_activity(account_id, account_activity_expired_column)
      after_account_expiration
    end

    def account_expired?
      columns = [account_activity_last_activity_column, account_activity_last_login_column, account_activity_expired_column]
      last_activity, last_login, expired = account_activity_ds(account_id).get(columns)
      return true if expired
      timestamp = convert_timestamp(expire_account_on_last_activity? ? last_activity : last_login)
      return false unless timestamp
      timestamp < Time.now - expire_account_after
    end

    def check_account_expiration
      if account_expired?
        set_expired unless account_expired_at
        set_redirect_error_flash account_expiration_error_flash
        redirect account_expiration_redirect
      end
      update_last_login
    end

    def update_session
      check_account_expiration
      super
    end

    private

    def before_reset_password
      check_account_expiration
      super if defined?(super)
    end

    def before_reset_password_request
      check_account_expiration
      super if defined?(super)
    end

    def before_unlock_account
      check_account_expiration
      super if defined?(super)
    end

    def before_unlock_account_request
      check_account_expiration
      super if defined?(super)
    end

    def after_close_account
      super if defined?(super)
      account_activity_ds(account_id).delete
    end

    def account_activity_ds(account_id)
      db[account_activity_table].
        where(account_activity_id_column=>account_id)
    end

    def get_activity_timestamp(account_id, column)
      convert_timestamp(account_activity_ds(account_id).get(column))
    end

    def update_activity(account_id, *columns)
      ds = account_activity_ds(account_id)
      hash = {}
      columns.each do |c|
        hash[c] = Sequel::CURRENT_TIMESTAMP
      end
      if ds.update(hash) == 0
        hash[account_activity_id_column] = account_id
        hash[account_activity_last_activity_column] ||= Sequel::CURRENT_TIMESTAMP
        hash[account_activity_last_login_column] ||= Sequel::CURRENT_TIMESTAMP
        # It is safe to ignore uniqueness violations here, as a concurrent insert would also use current timestamps.
        ignore_uniqueness_violation{ds.insert(hash)}
      end
    end
  end
end