Skip to content
Snippets Groups Projects
Verified Commit 61c9a4b4 authored by Björn Geuken's avatar Björn Geuken Committed by Andrej Shadura
Browse files

[api] Use ActiveModel::Dirty in user model

ActiveModel::Dirty provides a nice set of helper methods to track and
handle changes of attributes of a model.
This allows us to remove a number of custom code that previously was
taking care of this.

Cherry-picked from 7453160b
parent 6f3b0b25
Branches
No related tags found
1 merge request!21OBS SSO implementation
......@@ -20,6 +20,7 @@ class UserBasicStrategy
end
class User < ActiveRecord::Base
include ActiveModel::Dirty
include CanRenderModel
PASSWORD_HASH_TYPES = ['md5', 'md5crypt', 'sha256crypt']
......@@ -80,17 +81,12 @@ class User < ActiveRecord::Base
STATES['confirmed']
end
# When a record object is initialized, we set the state, password
# hash type, indicator whether the password has freshly been set
# (@new_password) and the login failure count to
# unconfirmed/false/0 when it has not been set yet.
# When a record object is initialized, we set the state and the login failure
# count to unconfirmed/0 when it has not been set yet.
before_validation(:on => :create) do
self.state = STATES['unconfirmed'] if self.state.nil?
self.password_hash_type = 'md5' if self.password_hash_type.to_s == ''
@new_password = false if @new_password.nil?
@new_hash_type = false if @new_hash_type.nil?
self.login_failure_count = 0 if self.login_failure_count.nil?
end
......@@ -99,40 +95,27 @@ class User < ActiveRecord::Base
self.last_logged_in_at = Time.now
end
# Override the accessor for the "password_hash_type" property so it sets
# the "@new_hash_type" private property to signal that the password's
# hash method has been changed. Changing the password hash type is only
# Overriding the default accessor to ensure ActiveModel::Dirty get's notified
# when password_hash_type changes. Changing the password hash type is only
# possible if a new password has been provided.
def password_hash_type=(value)
password_hash_type_will_change!
write_attribute(:password_hash_type, value)
@new_hash_type = true
end
# After saving, we want to set the "@new_hash_type" value set to false
# again.
after_save :set_new_hash_type_false
# Add accessors for "new_password" property. This boolean property is set
# to true when the password has been set and validation on this password is
# required.
attr_accessor :new_password
# Inform ActiveModel::Dirty that changes are persistent now
after_save :changes_applied
# Generate accessors for the password confirmation property.
attr_accessor :password_confirmation
scope :all_without_nobody, -> { where("login != ?", nobody_login) }
# Overriding the default accessor to update @new_password on setting this
# property.
# Overriding the default accessor to ensure ActiveModel::Dirty get's notified
# about changes of password attribute
def password=(value)
password_will_change!
write_attribute(:password, value)
@new_password = true
end
# Returns true if the password has been set after the User has been loaded
# from the database and false otherwise
def new_password?
@new_password
end
# Method to update the password and confirmation at the same time. Call
......@@ -147,14 +130,12 @@ class User < ActiveRecord::Base
# user.save
#
def update_password(pass)
password_will_change!
self.password_crypted = hash_string(pass).crypt('os')
self.password_confirmation = hash_string(pass)
self.password = hash_string(pass)
end
# After saving the object into the database, the password is not new any more.
after_save :set_new_password_false
# This method returns true if the user is assigned the role with one of the
# role titles given as parameters. False otherwise.
def has_role?(*role_titles)
......@@ -352,13 +333,13 @@ class User < ActiveRecord::Base
errors.add(:state, 'must be a valid new state from the current state.') unless state_transition_allowed?(@old_state, state)
# validate the password
if @new_password and not password.nil?
if password_changed? and not password.nil?
errors.add(:password, 'must match the confirmation.') unless password_confirmation == password
end
# check that the password hash type has not been set if no new password
# has been provided
return unless @new_hash_type && (!@new_password || password.nil?)
return unless password_hash_type_changed? && (!password_changed? || password_was.nil?)
errors.add(:password_hash_type, 'cannot be changed unless a new password has been provided.')
end
......@@ -393,7 +374,7 @@ class User < ActiveRecord::Base
validates :password,
format: { with: %r{\A[\w\.\- /+=!?(){}|~*]+\z},
message: 'must not contain invalid characters.',
if: Proc.new { |user| user.new_password? && !user.password.nil? } }
if: Proc.new { |user| user.password_changed? && !user.password_was.nil? } }
# We want the password to have between 6 and 64 characters.
# The length must only be checked if the password has been set and the record
......@@ -402,7 +383,7 @@ class User < ActiveRecord::Base
length: { within: 6..64,
too_long: 'must have between 6 and 64 characters.',
too_short: 'must have between 6 and 64 characters.',
if: Proc.new { |user| user.new_password? && !user.password.nil? } }
if: Proc.new { |user| user.password_changed? && !user.password_was.nil? } }
class << self
def current
......@@ -472,7 +453,7 @@ class User < ActiveRecord::Base
# After validation, the password should be encrypted
after_validation(:on => :create) do
if errors.empty? and @new_password and !password.nil?
if errors.empty? and password_changed? && !password_was.nil?
# generate a new 10-char long hash only Base64 encoded so things are compatible
self.password_salt = [Array.new(10){rand(256).chr}.join].pack('m')[0..9]
......@@ -483,14 +464,9 @@ class User < ActiveRecord::Base
# write encrypted password to object property
write_attribute(:password, hash_string(password))
# mark password as "not new" any more
@new_password = false
self.password_confirmation = nil
# mark the hash type as "not new" any more
@new_hash_type = false
else
logger.debug "Error - skipping to create user #{errors.inspect} #{@new_password.inspect} #{password.inspect}"
logger.debug "Error - skipping to create user #{errors.inspect} #{password} #{password_was}"
end
end
......@@ -1032,14 +1008,6 @@ class User < ActiveRecord::Base
private
def set_new_hash_type_false
@new_hash_type = false
end
def set_new_password_false
@new_password = false
end
def can_modify_project_internal(project, ignoreLock)
# The ordering is important because of the lock status check
return false if !ignoreLock && project.is_locked?
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment