user.rb 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
  2. require 'digest/md5'
  3. # @model User
  4. #
  5. # @property id(required) [Integer] The identifier for the User.
  6. # @property login(required) [String] The login of the User used for authentication.
  7. # @property firstname [String] The firstname of the User.
  8. # @property lastname [String] The lastname of the User.
  9. # @property email [String] The email of the User.
  10. # @property image [String] The Image used as the User avatar (TODO: Image model?).
  11. # @property web [String] The website/URL of the User.
  12. # @property password [String] The password of the User.
  13. # @property phone [String] The phone number of the User.
  14. # @property fax [String] The fax number of the User.
  15. # @property mobile [String] The mobile number of the User.
  16. # @property department [String] The department the User is working at.
  17. # @property street [String] The street the User lives in.
  18. # @property zip [Integer] The zip postal code of the User city.
  19. # @property city [String] The city the User lives in.
  20. # @property country [String] The country the User lives in.
  21. # @property verified [Boolean] The flag that shows the verified state of the User.
  22. # @property active [Boolean] The flag that shows the active state of the User.
  23. # @property note [String] The note or comment stored to the User.
  24. class User < ApplicationModel
  25. include LogsActivityStream
  26. include NotifiesClients
  27. include Historisable
  28. include SearchIndexed
  29. load 'user/permission.rb'
  30. include User::Permission
  31. load 'user/assets.rb'
  32. include User::Assets
  33. extend User::Search
  34. load 'user/search_index.rb'
  35. include User::SearchIndex
  36. before_validation :check_name, :check_email, :check_login, :ensure_password
  37. before_create :check_preferences_default, :validate_roles, :domain_based_assignment, :set_locale
  38. before_update :check_preferences_default, :validate_roles, :reset_login_failed
  39. after_create :avatar_for_email_check
  40. after_update :avatar_for_email_check
  41. after_destroy :avatar_destroy
  42. has_and_belongs_to_many :groups, after_add: :cache_update, after_remove: :cache_update, class_name: 'Group'
  43. has_and_belongs_to_many :roles, after_add: [:cache_update, :check_notifications], after_remove: :cache_update, class_name: 'Role'
  44. has_and_belongs_to_many :organizations, after_add: :cache_update, after_remove: :cache_update, class_name: 'Organization'
  45. #has_many :permissions, class_name: 'Permission', through: :roles, class_name: 'Role'
  46. has_many :tokens, after_add: :cache_update, after_remove: :cache_update
  47. has_many :authorizations, after_add: :cache_update, after_remove: :cache_update
  48. belongs_to :organization, class_name: 'Organization'
  49. store :preferences
  50. activity_stream_permission 'admin.user'
  51. activity_stream_attributes_ignored :last_login,
  52. :login_failed,
  53. :image,
  54. :image_source,
  55. :preferences
  56. history_attributes_ignored :password,
  57. :last_login,
  58. :image,
  59. :image_source,
  60. :preferences
  61. search_index_attributes_ignored :password,
  62. :image,
  63. :image_source,
  64. :source,
  65. :login_failed,
  66. :preferences
  67. def ignore_search_indexing?(_action)
  68. # ignore internal user
  69. return true if id == 1
  70. false
  71. end
  72. =begin
  73. fullname of user
  74. user = User.find(123)
  75. result = user.fullname
  76. returns
  77. result = "Bob Smith"
  78. =end
  79. def fullname
  80. name = ''
  81. if firstname && !firstname.empty?
  82. name = name + firstname
  83. end
  84. if lastname && !lastname.empty?
  85. if name != ''
  86. name += ' '
  87. end
  88. name += lastname
  89. end
  90. if name == '' && email
  91. name = email
  92. end
  93. name
  94. end
  95. =begin
  96. longname of user
  97. user = User.find(123)
  98. result = user.longname
  99. returns
  100. result = "Bob Smith"
  101. or with org
  102. result = "Bob Smith (Org ABC)"
  103. =end
  104. def longname
  105. name = fullname
  106. if organization_id
  107. organization = Organization.lookup(id: organization_id)
  108. if organization
  109. name += " (#{organization.name})"
  110. end
  111. end
  112. name
  113. end
  114. =begin
  115. check if user is in role
  116. user = User.find(123)
  117. result = user.role?('Customer')
  118. result = user.role?(['Agent', 'Admin'])
  119. returns
  120. result = true|false
  121. =end
  122. def role?(role_name)
  123. roles.where(name: role_name).any?
  124. end
  125. =begin
  126. get users activity stream
  127. user = User.find(123)
  128. result = user.activity_stream(20)
  129. returns
  130. result = [
  131. {
  132. id: 2,
  133. o_id: 2,
  134. created_by_id: 3,
  135. created_at: '2013-09-28 00:57:21',
  136. object: "User",
  137. type: "created",
  138. },
  139. {
  140. id: 2,
  141. o_id: 2,
  142. created_by_id: 3,
  143. created_at: '2013-09-28 00:59:21',
  144. object: "User",
  145. type: "updated",
  146. },
  147. ]
  148. =end
  149. def activity_stream(limit, fulldata = false)
  150. activity_stream = ActivityStream.list(self, limit)
  151. return activity_stream if !fulldata
  152. # get related objects
  153. assets = ApplicationModel.assets_of_object_list(activity_stream)
  154. {
  155. activity_stream: activity_stream,
  156. assets: assets,
  157. }
  158. end
  159. =begin
  160. authenticate user
  161. result = User.authenticate(username, password)
  162. returns
  163. result = user_model # user model if authentication was successfully
  164. =end
  165. def self.authenticate(username, password)
  166. # do not authenticate with nothing
  167. return if username.blank? || password.blank?
  168. # try to find user based on login
  169. user = User.find_by(login: username.downcase, active: true)
  170. # try second lookup with email
  171. user ||= User.find_by(email: username.downcase, active: true)
  172. # check failed logins
  173. max_login_failed = Setting.get('password_max_login_failed').to_i || 10
  174. if user && user.login_failed > max_login_failed
  175. logger.info "Max login faild reached for user #{user.login}."
  176. return false
  177. end
  178. user_auth = Auth.check(username, password, user)
  179. # set login failed +1
  180. if !user_auth && user
  181. sleep 1
  182. user.login_failed += 1
  183. user.save
  184. end
  185. # auth ok
  186. user_auth
  187. end
  188. =begin
  189. authenticate user agains sso
  190. result = User.sso(sso_params)
  191. returns
  192. result = user_model # user model if authentication was successfully
  193. =end
  194. def self.sso(params)
  195. # try to login against configure auth backends
  196. user_auth = Sso.check(params)
  197. return if !user_auth
  198. user_auth
  199. end
  200. =begin
  201. create user from from omni auth hash
  202. result = User.create_from_hash!(hash)
  203. returns
  204. result = user_model # user model if create was successfully
  205. =end
  206. def self.create_from_hash!(hash)
  207. role_ids = Role.signup_role_ids
  208. url = ''
  209. if hash['info']['urls']
  210. hash['info']['urls'].each { |_name, local_url|
  211. next if !local_url
  212. next if local_url.empty?
  213. url = local_url
  214. }
  215. end
  216. create(
  217. login: hash['info']['nickname'] || hash['uid'],
  218. firstname: hash['info']['name'],
  219. email: hash['info']['email'],
  220. image_source: hash['info']['image'],
  221. web: url,
  222. address: hash['info']['location'],
  223. note: hash['info']['description'],
  224. source: hash['provider'],
  225. role_ids: role_ids,
  226. updated_by_id: 1,
  227. created_by_id: 1,
  228. )
  229. end
  230. =begin
  231. get all permissions of user
  232. user = User.find(123)
  233. user.permissions
  234. returns
  235. {
  236. 'permission.key' => true,
  237. # ...
  238. }
  239. =end
  240. def permissions
  241. list = {}
  242. Object.const_get('Permission').select('permissions.name, permissions.preferences').joins(:roles).where('roles.id IN (?) AND permissions.active = ?', role_ids, true).pluck(:name, :preferences).each { |permission|
  243. next if permission[1]['selectable'] == false
  244. list[permission[0]] = true
  245. }
  246. list
  247. end
  248. =begin
  249. true or false for permission
  250. user = User.find(123)
  251. user.permissions?('permission.key') # access to certain permission.key
  252. user.permissions?(['permission.key1', 'permission.key2']) # access to permission.key1 or permission.key2
  253. user.permissions?('permission') # access to all sub keys
  254. user.permissions?('permission.*') # access if one sub key access exists
  255. returns
  256. true|false
  257. =end
  258. def permissions?(key)
  259. keys = key
  260. names = []
  261. if key.class == String
  262. keys = [key]
  263. end
  264. keys.each { |local_key|
  265. cache_key = "User::permissions?:local_key:::#{id}"
  266. if Rails.env.production?
  267. cache = Cache.get(cache_key)
  268. return cache if cache
  269. end
  270. list = []
  271. if local_key =~ /\.\*$/
  272. local_key.sub!('.*', '.%')
  273. permissions = Object.const_get('Permission').with_parents(local_key)
  274. list = Object.const_get('Permission').select('preferences').joins(:roles).where('roles.id IN (?) AND roles.active = ? AND (permissions.name IN (?) OR permissions.name LIKE ?) AND permissions.active = ?', role_ids, true, permissions, local_key, true).pluck(:preferences)
  275. else
  276. permission = Object.const_get('Permission').lookup(name: local_key)
  277. break if permission && permission.active == false
  278. permissions = Object.const_get('Permission').with_parents(local_key)
  279. list = Object.const_get('Permission').select('preferences').joins(:roles).where('roles.id IN (?) AND roles.active = ? AND permissions.name IN (?) AND permissions.active = ?', role_ids, true, permissions, true).pluck(:preferences)
  280. end
  281. list.each { |preferences|
  282. next if preferences[:selectable] == false
  283. Cache.write(key, true, expires_in: 10.seconds)
  284. return true
  285. }
  286. }
  287. Cache.write(key, false, expires_in: 10.seconds)
  288. false
  289. end
  290. =begin
  291. returns all accessable permission ids of user
  292. user = User.find(123)
  293. user.permissions_with_child_ids
  294. returns
  295. [permission1_id, permission2_id, permission3_id]
  296. =end
  297. def permissions_with_child_ids
  298. where = ''
  299. where_bind = [true]
  300. permissions.each { |permission_name, _value|
  301. where += ' OR ' if where != ''
  302. where += 'permissions.name = ? OR permissions.name LIKE ?'
  303. where_bind.push permission_name
  304. where_bind.push "#{permission_name}.%"
  305. }
  306. return [] if where == ''
  307. Object.const_get('Permission').where("permissions.active = ? AND (#{where})", *where_bind).pluck(:id)
  308. end
  309. =begin
  310. get all users with permission
  311. users = User.with_permissions('admin.session')
  312. get all users with permission "admin.session" or "ticket.agent"
  313. users = User.with_permissions(['admin.session', 'ticket.agent'])
  314. returns
  315. [user1, user2, ...]
  316. =end
  317. def self.with_permissions(keys)
  318. if keys.class != Array
  319. keys = [keys]
  320. end
  321. total_role_ids = []
  322. permission_ids = []
  323. keys.each { |key|
  324. role_ids = []
  325. Object.const_get('Permission').with_parents(key).each { |local_key|
  326. permission = Object.const_get('Permission').lookup(name: local_key)
  327. next if !permission
  328. permission_ids.push permission.id
  329. }
  330. next if permission_ids.empty?
  331. Role.joins(:roles_permissions).joins(:permissions).where('permissions_roles.permission_id IN (?) AND roles.active = ? AND permissions.active = ?', permission_ids, true, true).uniq().pluck(:id).each { |role_id|
  332. role_ids.push role_id
  333. }
  334. total_role_ids.push role_ids
  335. }
  336. return [] if total_role_ids.empty?
  337. condition = ''
  338. total_role_ids.each { |_role_ids|
  339. if condition != ''
  340. condition += ' OR '
  341. end
  342. condition += 'roles_users.role_id IN (?)'
  343. }
  344. User.joins(:users_roles).where("(#{condition}) AND users.active = ?", *total_role_ids, true).distinct.order(:id)
  345. end
  346. =begin
  347. generate new token for reset password
  348. result = User.password_reset_new_token(username)
  349. returns
  350. result = {
  351. token: token,
  352. user: user,
  353. }
  354. =end
  355. def self.password_reset_new_token(username)
  356. return if username.blank?
  357. # try to find user based on login
  358. user = User.find_by(login: username.downcase, active: true)
  359. # try second lookup with email
  360. user ||= User.find_by(email: username.downcase, active: true)
  361. # check if email address exists
  362. return if !user
  363. return if !user.email
  364. # generate token
  365. token = Token.create(action: 'PasswordReset', user_id: user.id)
  366. {
  367. token: token,
  368. user: user,
  369. }
  370. end
  371. =begin
  372. returns the User instance for a given password token if found
  373. result = User.by_reset_token(token)
  374. returns
  375. result = user_model # user_model if token was verified
  376. =end
  377. def self.by_reset_token(token)
  378. Token.check(action: 'PasswordReset', name: token)
  379. end
  380. =begin
  381. reset password with token and set new password
  382. result = User.password_reset_via_token(token,password)
  383. returns
  384. result = user_model # user_model if token was verified
  385. =end
  386. def self.password_reset_via_token(token, password)
  387. # check token
  388. user = by_reset_token(token)
  389. return if !user
  390. # reset password
  391. user.update_attributes(password: password)
  392. # delete token
  393. Token.find_by(action: 'PasswordReset', name: token).destroy
  394. user
  395. end
  396. =begin
  397. update last login date and reset login_failed (is automatically done by auth and sso backend)
  398. user = User.find(123)
  399. result = user.update_last_login
  400. returns
  401. result = new_user_model
  402. =end
  403. def update_last_login
  404. self.last_login = Time.zone.now
  405. # reset login failed
  406. self.login_failed = 0
  407. save
  408. end
  409. =begin
  410. generate new token for signup
  411. result = User.signup_new_token(user) # or email
  412. returns
  413. result = {
  414. token: token,
  415. user: user,
  416. }
  417. =end
  418. def self.signup_new_token(user)
  419. return if !user
  420. return if !user.email
  421. # generate token
  422. token = Token.create(action: 'Signup', user_id: user.id)
  423. {
  424. token: token,
  425. user: user,
  426. }
  427. end
  428. =begin
  429. verify signup with token
  430. result = User.signup_verify_via_token(token, user)
  431. returns
  432. result = user_model # user_model if token was verified
  433. =end
  434. def self.signup_verify_via_token(token, user = nil)
  435. # check token
  436. local_user = Token.check(action: 'Signup', name: token)
  437. return if !local_user
  438. # if requested user is different to current user
  439. return if user && local_user.id != user.id
  440. # set verified
  441. local_user.update_attributes(verified: true)
  442. # delete token
  443. Token.find_by(action: 'Signup', name: token).destroy
  444. local_user
  445. end
  446. =begin
  447. merge two users to one
  448. user = User.find(123)
  449. result = user.merge(user_id_of_duplicate_user)
  450. returns
  451. result = new_user_model
  452. =end
  453. def merge(user_id_of_duplicate_user)
  454. # find email addresses and move them to primary user
  455. duplicate_user = User.find(user_id_of_duplicate_user)
  456. # merge missing attibutes
  457. Models.merge('User', id, user_id_of_duplicate_user)
  458. true
  459. end
  460. =begin
  461. list of active users in role
  462. result = User.of_role('Agent', group_ids)
  463. result = User.of_role(['Agent', 'Admin'])
  464. returns
  465. result = [user1, user2]
  466. =end
  467. def self.of_role(role, group_ids = nil)
  468. roles_ids = Role.where(active: true, name: role).map(&:id)
  469. if !group_ids
  470. return User.where(active: true).joins(:users_roles).where('roles_users.role_id IN (?)', roles_ids).order('users.updated_at DESC')
  471. end
  472. User.where(active: true)
  473. .joins(:users_roles)
  474. .joins(:users_groups)
  475. .where('roles_users.role_id IN (?) AND users_groups.group_ids IN (?)', roles_ids, group_ids).order('users.updated_at DESC')
  476. end
  477. =begin
  478. update/sync default preferences of users in a dedecated permissions
  479. result = User.update_default_preferences_by_permission('ticket.agent', force)
  480. returns
  481. result = true # false
  482. =end
  483. def self.update_default_preferences_by_permission(permission_name, force = false)
  484. permission = Object.const_get('Permission').lookup(name: permission_name)
  485. return if !permission
  486. default = Rails.configuration.preferences_default_by_permission
  487. return false if !default
  488. default.deep_stringify_keys!
  489. User.with_permissions(permission.name).each { |user|
  490. next if !default[permission.name]
  491. has_changed = false
  492. default[permission.name].each { |key, value|
  493. next if !force && user.preferences[key]
  494. has_changed = true
  495. user.preferences[key] = value
  496. }
  497. if has_changed
  498. user.save!
  499. end
  500. }
  501. true
  502. end
  503. =begin
  504. update/sync default preferences of users in a dedecated role
  505. result = User.update_default_preferences_by_role('Agent', force)
  506. returns
  507. result = true # false
  508. =end
  509. def self.update_default_preferences_by_role(role_name, force = false)
  510. role = Role.lookup(name: role_name)
  511. return if !role
  512. default = Rails.configuration.preferences_default_by_permission
  513. return false if !default
  514. default.deep_stringify_keys!
  515. role.permissions.each { |permission|
  516. User.update_default_preferences_by_permission(permission.name, force)
  517. }
  518. true
  519. end
  520. def check_notifications(o)
  521. default = Rails.configuration.preferences_default_by_permission
  522. return if !default
  523. default.deep_stringify_keys!
  524. has_changed = false
  525. o.permissions.each { |permission|
  526. next if !default[permission.name]
  527. default[permission.name].each { |key, value|
  528. next if preferences[key]
  529. preferences[key] = value
  530. has_changed = true
  531. }
  532. }
  533. return true if !has_changed
  534. if id
  535. save!
  536. return true
  537. end
  538. @preferences_default = preferences
  539. true
  540. end
  541. def check_preferences_default
  542. return if @preferences_default.blank?
  543. preferences_tmp = @preferences_default.merge(preferences)
  544. self.preferences = preferences_tmp
  545. @preferences_default = nil
  546. true
  547. end
  548. private
  549. def cache_delete
  550. super
  551. # delete asset caches
  552. key = "User::authorizations::#{id}"
  553. Cache.delete(key)
  554. # delete permission cache
  555. key = "User::permissions?:local_key:::#{id}"
  556. Cache.delete(key)
  557. end
  558. def check_name
  559. return if !firstname.empty? && !lastname.empty?
  560. if !firstname.empty? && lastname.empty?
  561. # "Lastname, Firstname"
  562. scan = firstname.scan(/, /)
  563. if scan[0]
  564. name = firstname.split(', ', 2)
  565. if !name[0].nil?
  566. self.lastname = name[0]
  567. end
  568. if !name[1].nil?
  569. self.firstname = name[1]
  570. end
  571. return
  572. end
  573. # "Firstname Lastname"
  574. name = firstname.split(' ', 2)
  575. if !name[0].nil?
  576. self.firstname = name[0]
  577. end
  578. if !name[1].nil?
  579. self.lastname = name[1]
  580. end
  581. return
  582. # -no name- "firstname.lastname@example.com"
  583. elsif firstname.empty? && lastname.empty? && !email.empty?
  584. scan = email.scan(/^(.+?)\.(.+?)\@.+?$/)
  585. if scan[0]
  586. if !scan[0][0].nil?
  587. self.firstname = scan[0][0].capitalize
  588. end
  589. if !scan[0][1].nil?
  590. self.lastname = scan[0][1].capitalize
  591. end
  592. end
  593. end
  594. end
  595. def check_email
  596. return if Setting.get('import_mode')
  597. return if email.empty?
  598. self.email = email.downcase.strip
  599. return if id == 1
  600. raise Exceptions::UnprocessableEntity, 'Invalid email' if email !~ /@/
  601. raise Exceptions::UnprocessableEntity, 'Invalid email' if email =~ /\s/
  602. end
  603. def check_login
  604. # use email as login if not given
  605. if login.empty? && !email.empty?
  606. self.login = email
  607. end
  608. # if email has changed, login is old email, change also login
  609. if changes && changes['email']
  610. if changes['email'][0] == login
  611. self.login = email
  612. end
  613. end
  614. # if no email, complain about missing login
  615. if id != 1 && login.empty? && email.empty?
  616. raise Exceptions::UnprocessableEntity, 'Attribute \'login\' required!'
  617. end
  618. # check if login already exists
  619. self.login = login.downcase.strip
  620. check = true
  621. while check
  622. exists = User.find_by(login: login)
  623. if exists && exists.id != id
  624. self.login = login + rand(999).to_s
  625. else
  626. check = false
  627. end
  628. end
  629. end
  630. def validate_roles
  631. return if !role_ids
  632. role_ids.each { |role_id|
  633. role = Role.lookup(id: role_id)
  634. raise "Unable to find role for id #{role_id}" if !role
  635. next if !role.preferences[:not]
  636. role.preferences[:not].each { |local_role_name|
  637. local_role = Role.lookup(name: local_role_name)
  638. next if !local_role
  639. raise "Role #{role.name} conflicts with #{local_role.name}" if role_ids.include?(local_role.id)
  640. }
  641. }
  642. end
  643. def domain_based_assignment
  644. return if !email
  645. return if organization_id
  646. begin
  647. domain = Mail::Address.new(email).domain
  648. return if !domain
  649. organization = Organization.find_by(domain: domain.downcase, domain_assignment: true)
  650. return if !organization
  651. self.organization_id = organization.id
  652. rescue
  653. return
  654. end
  655. end
  656. # sets locale of the user
  657. def set_locale
  658. # set the user's locale to the one of the "executing" user
  659. return if !UserInfo.current_user_id
  660. user = User.find_by( id: UserInfo.current_user_id )
  661. return if !user
  662. return if !user.preferences[:locale]
  663. preferences[:locale] = user.preferences[:locale]
  664. end
  665. def avatar_for_email_check
  666. return if email.blank?
  667. return if email !~ /@/
  668. return if !changes['email'] && updated_at > Time.zone.now - 10.days
  669. # save/update avatar
  670. avatar = Avatar.auto_detection(
  671. object: 'User',
  672. o_id: id,
  673. url: email,
  674. source: 'app',
  675. updated_by_id: updated_by_id,
  676. created_by_id: updated_by_id,
  677. )
  678. # update user link
  679. return if !avatar
  680. update_column(:image, avatar.store_hash)
  681. cache_delete
  682. end
  683. def avatar_destroy
  684. Avatar.remove('User', id)
  685. end
  686. def ensure_password
  687. return if password_empty?
  688. return if PasswordHash.crypted?(password)
  689. self.password = PasswordHash.crypt(password)
  690. end
  691. def password_empty?
  692. # set old password again if not given
  693. return if password.present?
  694. # skip if it's not desired to set a password (yet)
  695. return true if !password
  696. # get current record
  697. return if !id
  698. self.password = password_was
  699. true
  700. end
  701. # reset login_failed if password is changed
  702. def reset_login_failed
  703. return if !changes
  704. return if !changes['password']
  705. self.login_failed = 0
  706. end
  707. end