user.rb 14 KB

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