module Users class ChangePassword Result = Struct.new(:ok?, :error, keyword_init: true) def self.call(user:, current_password:, password:, password_confirmation:) new( user: user, current_password: current_password, password: password, password_confirmation: password_confirmation ).call end def initialize(user:, current_password:, password:, password_confirmation:) @user = user @current_password = current_password.to_s @password = password.to_s @password_confirmation = password_confirmation.to_s end def call unless @user.authenticate(@current_password) return Result.new(ok?: false, error: :current_incorrect) end if @password != @password_confirmation return Result.new(ok?: false, error: :mismatch) end if (code = PasswordComplexity.violation(@password)) return Result.new(ok?: false, error: code == :blank ? :too_short : code) end unless @user.update(password: @password) complexity_error = @user.errors.details[:password]&.any? { |d| d[:error] == :complexity } return Result.new(ok?: false, error: complexity_error ? :too_weak : :too_short) end @user.clear_password_reset! Result.new(ok?: true) end end end