user.rb 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. # Copyright (C) 2012-2014 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 User::Permission
  26. load 'user/assets.rb'
  27. include User::Assets
  28. extend User::Search
  29. before_create :check_name, :check_email, :check_login, :check_password, :check_preferences_default
  30. before_update :check_password, :check_email, :check_login, :check_preferences_default
  31. after_create :avatar_for_email_check
  32. after_update :avatar_for_email_check
  33. after_destroy :avatar_destroy
  34. notify_clients_support
  35. has_and_belongs_to_many :groups, after_add: :cache_update, after_remove: :cache_update, class_name: 'Group'
  36. has_and_belongs_to_many :roles, after_add: [:cache_update, :check_notifications], after_remove: :cache_update, class_name: 'Role'
  37. has_and_belongs_to_many :organizations, after_add: :cache_update, after_remove: :cache_update, class_name: 'Organization'
  38. has_many :tokens, after_add: :cache_update, after_remove: :cache_update
  39. has_many :authorizations, after_add: :cache_update, after_remove: :cache_update
  40. belongs_to :organization, class_name: 'Organization'
  41. store :preferences
  42. activity_stream_support(
  43. role: Z_ROLENAME_ADMIN,
  44. ignore_attributes: {
  45. last_login: true,
  46. login_failed: true,
  47. image: true,
  48. image_source: true,
  49. preferences: true,
  50. }
  51. )
  52. history_support(
  53. ignore_attributes: {
  54. password: true,
  55. image: true,
  56. image_source: true,
  57. preferences: true,
  58. }
  59. )
  60. search_index_support(
  61. ignore_attributes: {
  62. password: true,
  63. image: true,
  64. image_source: true,
  65. source: true,
  66. login_failed: true,
  67. preferences: true,
  68. },
  69. ignore_ids: [1],
  70. )
  71. =begin
  72. fullname of user
  73. user = User.find(123)
  74. result = user.fullname
  75. returns
  76. result = "Bob Smith"
  77. =end
  78. def fullname
  79. name = ''
  80. if firstname && !firstname.empty?
  81. name = name + firstname
  82. end
  83. if lastname && !lastname.empty?
  84. if name != ''
  85. name += ' '
  86. end
  87. name += lastname
  88. end
  89. if name == '' && email
  90. name = email
  91. end
  92. name
  93. end
  94. =begin
  95. longname of user
  96. user = User.find(123)
  97. result = user.longname
  98. returns
  99. result = "Bob Smith"
  100. or with org
  101. result = "Bob Smith (Org ABC)"
  102. =end
  103. def longname
  104. name = fullname
  105. if organization_id
  106. organization = Organization.lookup(id: organization_id)
  107. if organization
  108. name += " (#{organization.name})"
  109. end
  110. end
  111. name
  112. end
  113. =begin
  114. check if user is in role
  115. user = User.find(123)
  116. result = user.role?('Customer')
  117. result = user.role?(['Agent', 'Admin'])
  118. returns
  119. result = true|false
  120. =end
  121. def role?(role_name)
  122. result = false
  123. roles.each { |role|
  124. if role_name.class == Array
  125. next if !role_name.include?(role.name)
  126. elsif role.name != role_name
  127. next
  128. end
  129. result = true
  130. break
  131. }
  132. result
  133. end
  134. =begin
  135. get users activity stream
  136. user = User.find(123)
  137. result = user.activity_stream(20)
  138. returns
  139. result = [
  140. {
  141. :id => 2,
  142. :o_id => 2,
  143. :created_by_id => 3,
  144. :created_at => '2013-09-28 00:57:21',
  145. :object => "User",
  146. :type => "created",
  147. },
  148. {
  149. :id => 2,
  150. :o_id => 2,
  151. :created_by_id => 3,
  152. :created_at => '2013-09-28 00:59:21',
  153. :object => "User",
  154. :type => "updated",
  155. },
  156. ]
  157. =end
  158. def activity_stream(limit, fulldata = false)
  159. activity_stream = ActivityStream.list(self, limit)
  160. return activity_stream if !fulldata
  161. # get related objects
  162. assets = ApplicationModel.assets_of_object_list(activity_stream)
  163. {
  164. activity_stream: activity_stream,
  165. assets: assets,
  166. }
  167. end
  168. =begin
  169. authenticate user
  170. result = User.authenticate(username, password)
  171. returns
  172. result = user_model # user model if authentication was successfully
  173. =end
  174. def self.authenticate(username, password)
  175. # do not authenticate with nothing
  176. return if !username || username == ''
  177. return if !password || password == ''
  178. # try to find user based on login
  179. user = User.find_by(login: username.downcase, active: true)
  180. # try second lookup with email
  181. if !user
  182. user = User.find_by(email: username.downcase, active: true)
  183. end
  184. # check failed logins
  185. max_login_failed = Setting.get('password_max_login_failed').to_i || 10
  186. if user && user.login_failed > max_login_failed
  187. logger.info "Max login faild reached for user #{user.login}."
  188. return false
  189. end
  190. user_auth = Auth.check(username, password, user)
  191. # set login failed +1
  192. if !user_auth && user
  193. sleep 1
  194. user.login_failed = user.login_failed + 1
  195. user.save
  196. end
  197. # auth ok
  198. user_auth
  199. end
  200. =begin
  201. authenticate user agains sso
  202. result = User.sso(sso_params)
  203. returns
  204. result = user_model # user model if authentication was successfully
  205. =end
  206. def self.sso(params)
  207. # try to login against configure auth backends
  208. user_auth = Sso.check(params)
  209. return if !user_auth
  210. user_auth
  211. end
  212. =begin
  213. create user from from omni auth hash
  214. result = User.create_from_hash!(hash)
  215. returns
  216. result = user_model # user model if create was successfully
  217. =end
  218. def self.create_from_hash!(hash)
  219. roles = Role.where(name: 'Customer')
  220. url = ''
  221. if hash['info']['urls']
  222. hash['info']['urls'].each {|_name, local_url|
  223. next if !local_url
  224. next if local_url.empty?
  225. url = local_url
  226. }
  227. end
  228. create(
  229. login: hash['info']['nickname'] || hash['uid'],
  230. firstname: hash['info']['name'],
  231. email: hash['info']['email'],
  232. image_source: hash['info']['image'],
  233. web: url,
  234. address: hash['info']['location'],
  235. note: hash['info']['description'],
  236. source: hash['provider'],
  237. roles: roles,
  238. updated_by_id: 1,
  239. created_by_id: 1,
  240. )
  241. end
  242. =begin
  243. generate new token for reset password
  244. result = User.password_reset_new_token(username)
  245. returns
  246. result = {
  247. token: token,
  248. user: user,
  249. }
  250. =end
  251. def self.password_reset_new_token(username)
  252. return if !username || username == ''
  253. # try to find user based on login
  254. user = User.find_by(login: username.downcase, active: true)
  255. # try second lookup with email
  256. if !user
  257. user = User.find_by(email: username.downcase, active: true)
  258. end
  259. # check if email address exists
  260. return if !user
  261. return if !user.email
  262. # generate token
  263. token = Token.create(action: 'PasswordReset', user_id: user.id)
  264. {
  265. token: token,
  266. user: user,
  267. }
  268. end
  269. =begin
  270. check reset password token
  271. result = User.password_reset_check(token)
  272. returns
  273. result = user_model # user_model if token was verified
  274. =end
  275. def self.password_reset_check(token)
  276. user = Token.check(action: 'PasswordReset', name: token)
  277. # reset login failed if token is valid
  278. if user
  279. user.login_failed = 0
  280. user.save
  281. end
  282. user
  283. end
  284. =begin
  285. reset password with token and set new password
  286. result = User.password_reset_via_token(token,password)
  287. returns
  288. result = user_model # user_model if token was verified
  289. =end
  290. def self.password_reset_via_token(token, password)
  291. # check token
  292. user = Token.check(action: 'PasswordReset', name: token)
  293. return if !user
  294. # reset password
  295. user.update_attributes(password: password)
  296. # delete token
  297. Token.find_by(action: 'PasswordReset', name: token).destroy
  298. user
  299. end
  300. =begin
  301. update last login date and reset login_failed (is automatically done by auth and sso backend)
  302. user = User.find(123)
  303. result = user.update_last_login
  304. returns
  305. result = new_user_model
  306. =end
  307. def update_last_login
  308. self.last_login = Time.zone.now
  309. # reset login failed
  310. self.login_failed = 0
  311. save
  312. end
  313. =begin
  314. generate new token for signup
  315. result = User.signup_new_token(user) # or email
  316. returns
  317. result = {
  318. token: token,
  319. user: user,
  320. }
  321. =end
  322. def self.signup_new_token(user)
  323. return if !user
  324. return if !user.email
  325. # generate token
  326. token = Token.create(action: 'Signup', user_id: user.id)
  327. {
  328. token: token,
  329. user: user,
  330. }
  331. end
  332. =begin
  333. verify signup with token
  334. result = User.signup_verify_via_token(token, user)
  335. returns
  336. result = user_model # user_model if token was verified
  337. =end
  338. def self.signup_verify_via_token(token, user = nil)
  339. # check token
  340. local_user = Token.check(action: 'Signup', name: token)
  341. return if !local_user
  342. # if requested user is different to current user
  343. return if user && local_user.id != user.id
  344. # set verified
  345. local_user.update_attributes(verified: true)
  346. # delete token
  347. Token.find_by(action: 'Signup', name: token).destroy
  348. local_user
  349. end
  350. =begin
  351. merge two users to one
  352. user = User.find(123)
  353. result = user.merge(user_id_of_duplicate_user)
  354. returns
  355. result = new_user_model
  356. =end
  357. def merge(user_id_of_duplicate_user)
  358. # find email addresses and move them to primary user
  359. duplicate_user = User.find(user_id_of_duplicate_user)
  360. # merge missing attibutes
  361. Models.merge('User', id, user_id_of_duplicate_user)
  362. true
  363. end
  364. =begin
  365. list of active users in role
  366. result = User.of_role('Agent', group_ids)
  367. returns
  368. result = [user1, user2]
  369. =end
  370. def self.of_role(role, group_ids = nil)
  371. roles_ids = Role.where(active: true, name: role).map(&:id)
  372. if !group_ids
  373. return User.where(active: true).joins(:users_roles).where('roles_users.role_id IN (?)', roles_ids).order('users.updated_at DESC')
  374. end
  375. User.where(active: true)
  376. .joins(:users_roles)
  377. .joins(:users_groups)
  378. .where('roles_users.role_id IN (?) AND users_groups.group_ids IN (?)', roles_ids, group_ids).order('users.updated_at DESC')
  379. end
  380. =begin
  381. update/sync default preferences of users in a dedecated role
  382. result = User.update_default_preferences('Agent')
  383. returns
  384. result = true # false
  385. =end
  386. def self.update_default_preferences(role_name)
  387. role = Role.lookup(name: role_name)
  388. User.of_role(role_name).each {|user|
  389. user.check_notifications(role)
  390. user.check_preferences_default
  391. user.save
  392. }
  393. true
  394. end
  395. def check_notifications(o)
  396. default = Rails.configuration.preferences_default_by_role
  397. return if !default
  398. default.deep_stringify_keys!
  399. return if !default[o.name]
  400. if !@preferences_default
  401. @preferences_default = {}
  402. end
  403. default[o.name].each {|key, value|
  404. next if @preferences_default[key]
  405. @preferences_default[key] = value
  406. }
  407. end
  408. def check_preferences_default
  409. return if !@preferences_default
  410. return if @preferences_default.empty?
  411. preferences_tmp = @preferences_default.merge(preferences)
  412. self.preferences = preferences_tmp
  413. end
  414. private
  415. def cache_delete
  416. super
  417. # delete asset caches
  418. key = "User::authorizations::#{id}"
  419. Cache.delete(key)
  420. key = "User::role_ids::#{id}"
  421. Cache.delete(key)
  422. key = "User::group_ids::#{id}"
  423. Cache.delete(key)
  424. key = "User::organization_ids::#{id}"
  425. Cache.delete(key)
  426. end
  427. def check_name
  428. if (firstname && !firstname.empty?) && (!lastname || lastname.empty?)
  429. # Lastname, Firstname
  430. scan = firstname.scan(/, /)
  431. if scan[0]
  432. name = firstname.split(', ', 2)
  433. if !name[0].nil?
  434. self.lastname = name[0]
  435. end
  436. if !name[1].nil?
  437. self.firstname = name[1]
  438. end
  439. return
  440. end
  441. # Firstname Lastname
  442. name = firstname.split(' ', 2)
  443. if !name[0].nil?
  444. self.firstname = name[0]
  445. end
  446. if !name[1].nil?
  447. self.lastname = name[1]
  448. end
  449. return
  450. # -no name- firstname.lastname@example.com
  451. elsif (!firstname || firstname.empty?) && (!lastname || lastname.empty?) && (email && !email.empty?)
  452. scan = email.scan(/^(.+?)\.(.+?)\@.+?$/)
  453. if scan[0]
  454. if !scan[0][0].nil?
  455. self.firstname = scan[0][0].capitalize
  456. end
  457. if !scan[0][1].nil?
  458. self.lastname = scan[0][1].capitalize
  459. end
  460. end
  461. end
  462. end
  463. def check_email
  464. return if !email
  465. self.email = email.downcase
  466. end
  467. def check_login
  468. # use email as login if not given
  469. if !login && email
  470. self.login = email
  471. end
  472. # if email has changed, login is old email, change also login
  473. if changes && changes['email']
  474. if changes['email'][0] == login
  475. self.login = email
  476. end
  477. end
  478. # check if login already exists
  479. return if !login
  480. self.login = login.downcase
  481. check = true
  482. while check
  483. exists = User.find_by(login: login)
  484. if exists && exists.id != id
  485. self.login = login + rand(999).to_s
  486. else
  487. check = false
  488. end
  489. end
  490. end
  491. def avatar_for_email_check
  492. return if !email
  493. return if email.empty?
  494. return if email !~ /@/
  495. # save/update avatar
  496. avatar = Avatar.auto_detection(
  497. object: 'User',
  498. o_id: id,
  499. url: email,
  500. source: 'app',
  501. updated_by_id: updated_by_id,
  502. created_by_id: updated_by_id,
  503. )
  504. # update user link
  505. return if !avatar
  506. update_column(:image, avatar.store_hash)
  507. cache_delete
  508. end
  509. def avatar_destroy
  510. Avatar.remove('User', id)
  511. end
  512. def check_password
  513. # set old password again if not given
  514. if password == '' || !password
  515. # get current record
  516. if id
  517. #current = User.find(self.id)
  518. #self.password = current.password
  519. self.password = password_was
  520. end
  521. end
  522. # crypt password if not already crypted
  523. return if !password
  524. return if password =~ /^\{sha2\}/
  525. crypted = Digest::SHA2.hexdigest(password)
  526. self.password = "{sha2}#{crypted}"
  527. end
  528. end