user.rb 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  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. include User::SearchIndex
  30. before_create :check_name, :check_email, :check_login, :check_password
  31. before_update :check_password, :check_email, :check_login
  32. after_create :avatar_check
  33. after_update :avatar_check
  34. after_destroy :avatar_destroy
  35. notify_clients_support
  36. has_and_belongs_to_many :groups, after_add: :cache_update, after_remove: :cache_update
  37. has_and_belongs_to_many :roles, after_add: :cache_update, after_remove: :cache_update
  38. has_and_belongs_to_many :organizations, after_add: :cache_update, after_remove: :cache_update
  39. has_many :tokens, after_add: :cache_update, after_remove: :cache_update
  40. has_many :authorizations, after_add: :cache_update, after_remove: :cache_update
  41. belongs_to :organization, class_name: 'Organization'
  42. store :preferences
  43. activity_stream_support(
  44. role: Z_ROLENAME_ADMIN,
  45. ignore_attributes: {
  46. last_login: true,
  47. image: true,
  48. image_source: true,
  49. }
  50. )
  51. history_support(
  52. ignore_attributes: {
  53. password: true,
  54. image: true,
  55. image_source: true,
  56. }
  57. )
  58. search_index_support(
  59. ignore_attributes: {
  60. password: true,
  61. image: true,
  62. image_source: true,
  63. source: true,
  64. login_failed: true,
  65. preferences: true,
  66. }
  67. )
  68. =begin
  69. fullname of user
  70. user = User.find(123)
  71. result = user.fulename
  72. returns
  73. result = "Bob Smith"
  74. =end
  75. def fullname
  76. fullname = ''
  77. if firstname && !firstname.empty?
  78. fullname = fullname + firstname
  79. end
  80. if lastname && !lastname.empty?
  81. if fullname != ''
  82. fullname = fullname + ' '
  83. end
  84. fullname = fullname + lastname
  85. end
  86. if fullname == '' && email
  87. fullname = email
  88. end
  89. fullname
  90. end
  91. =begin
  92. check if user is in role
  93. user = User.find(123)
  94. result = user.role?('Customer')
  95. returns
  96. result = true|false
  97. =end
  98. def role?( role_name )
  99. result = false
  100. roles.each { |role|
  101. next if role.name != role_name
  102. result = true
  103. break
  104. }
  105. result
  106. end
  107. =begin
  108. get users activity stream
  109. user = User.find(123)
  110. result = user.activity_stream( 20 )
  111. returns
  112. result = [
  113. {
  114. :id => 2,
  115. :o_id => 2,
  116. :created_by_id => 3,
  117. :created_at => '2013-09-28 00:57:21',
  118. :object => "User",
  119. :type => "created",
  120. },
  121. {
  122. :id => 2,
  123. :o_id => 2,
  124. :created_by_id => 3,
  125. :created_at => '2013-09-28 00:59:21',
  126. :object => "User",
  127. :type => "updated",
  128. },
  129. ]
  130. =end
  131. def activity_stream( limit, fulldata = false )
  132. activity_stream = ActivityStream.list( self, limit )
  133. return activity_stream if !fulldata
  134. # get related objects
  135. assets = ApplicationModel.assets_of_object_list(activity_stream)
  136. {
  137. activity_stream: activity_stream,
  138. assets: assets,
  139. }
  140. end
  141. =begin
  142. authenticate user
  143. result = User.authenticate(username, password)
  144. returns
  145. result = user_model # user model if authentication was successfully
  146. =end
  147. def self.authenticate( username, password )
  148. # do not authenticate with nothing
  149. return if !username || username == ''
  150. return if !password || password == ''
  151. # try to find user based on login
  152. user = User.find_by( login: username.downcase, active: true )
  153. # try second lookup with email
  154. if !user
  155. user = User.find_by( email: username.downcase, active: true )
  156. end
  157. # check failed logins
  158. max_login_failed = Setting.get('password_max_login_failed').to_i || 10
  159. if user && user.login_failed > max_login_failed
  160. logger.info "Max login faild reached for user #{user.login}."
  161. return false
  162. end
  163. user_auth = Auth.check( username, password, user )
  164. # set login failed +1
  165. if !user_auth && user
  166. sleep 1
  167. user.login_failed = user.login_failed + 1
  168. user.save
  169. end
  170. # auth ok
  171. user_auth
  172. end
  173. =begin
  174. authenticate user agains sso
  175. result = User.sso(sso_params)
  176. returns
  177. result = user_model # user model if authentication was successfully
  178. =end
  179. def self.sso(params)
  180. # try to login against configure auth backends
  181. user_auth = Sso.check( params )
  182. return if !user_auth
  183. user_auth
  184. end
  185. =begin
  186. create user from from omni auth hash
  187. result = User.create_from_hash!(hash)
  188. returns
  189. result = user_model # user model if create was successfully
  190. =end
  191. def self.create_from_hash!(hash)
  192. url = ''
  193. if hash['info']['urls']
  194. url = hash['info']['urls']['Website'] || hash['info']['urls']['Twitter'] || ''
  195. end
  196. roles = Role.where( name: 'Customer' )
  197. create(
  198. login: hash['info']['nickname'] || hash['uid'],
  199. firstname: hash['info']['name'],
  200. email: hash['info']['email'],
  201. image: hash['info']['image'],
  202. # :url => url.to_s,
  203. note: hash['info']['description'],
  204. source: hash['provider'],
  205. roles: roles,
  206. updated_by_id: 1,
  207. created_by_id: 1,
  208. )
  209. end
  210. =begin
  211. send reset password email with token to user
  212. result = User.password_reset_send(username)
  213. returns
  214. result = token
  215. =end
  216. def self.password_reset_send(username)
  217. return if !username || username == ''
  218. # try to find user based on login
  219. user = User.find_by( login: username.downcase, active: true )
  220. # try second lookup with email
  221. if !user
  222. user = User.find_by( email: username.downcase, active: true )
  223. end
  224. # check if email address exists
  225. return if !user
  226. return if !user.email
  227. # generate token
  228. token = Token.create( action: 'PasswordReset', user_id: user.id )
  229. # send mail
  230. data = {}
  231. data[:subject] = 'Reset your #{config.product_name} password'
  232. data[:body] = 'Forgot your password?
  233. We received a request to reset the password for your #{config.product_name} account (#{user.login}).
  234. If you want to reset your password, click on the link below (or copy and paste the URL into your browser):
  235. #{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}
  236. This link takes you to a page where you can change your password.
  237. If you don\'t want to reset your password, please ignore this message. Your password will not be reset.
  238. Your #{config.product_name} Team'
  239. # prepare subject & body
  240. [:subject, :body].each { |key|
  241. data[key.to_sym] = NotificationFactory.build(
  242. locale: user.preferences[:locale],
  243. string: data[key.to_sym],
  244. objects: {
  245. token: token,
  246. user: user,
  247. }
  248. )
  249. }
  250. # send notification
  251. NotificationFactory.send(
  252. recipient: user,
  253. subject: data[:subject],
  254. body: data[:body]
  255. )
  256. token
  257. end
  258. =begin
  259. check reset password token
  260. result = User.password_reset_check(token)
  261. returns
  262. result = user_model # user_model if token was verified
  263. =end
  264. def self.password_reset_check(token)
  265. user = Token.check( action: 'PasswordReset', name: token )
  266. # reset login failed if token is valid
  267. if user
  268. user.login_failed = 0
  269. user.save
  270. end
  271. user
  272. end
  273. =begin
  274. reset reset password with token and set new password
  275. result = User.password_reset_via_token(token,password)
  276. returns
  277. result = user_model # user_model if token was verified
  278. =end
  279. def self.password_reset_via_token(token, password)
  280. # check token
  281. user = Token.check( action: 'PasswordReset', name: token )
  282. return if !user
  283. # reset password
  284. user.update_attributes( password: password )
  285. # delete token
  286. Token.find_by( action: 'PasswordReset', name: token ).destroy
  287. user
  288. end
  289. =begin
  290. update last login date and reset login_failed (is automatically done by auth and sso backend)
  291. user = User.find(123)
  292. result = user.update_last_login
  293. returns
  294. result = new_user_model
  295. =end
  296. def update_last_login
  297. self.last_login = Time.zone.now
  298. # reset login failed
  299. self.login_failed = 0
  300. # set updated by user
  301. self.updated_by_id = id
  302. save
  303. end
  304. private
  305. def check_name
  306. if ( firstname && !firstname.empty? ) && ( !lastname || lastname.empty? )
  307. # Lastname, Firstname
  308. scan = firstname.scan(/, /)
  309. if scan[0]
  310. name = firstname.split(', ', 2)
  311. if !name[0].nil?
  312. self.lastname = name[0]
  313. end
  314. if !name[1].nil?
  315. self.firstname = name[1]
  316. end
  317. return
  318. end
  319. # Firstname Lastname
  320. name = firstname.split(' ', 2)
  321. if !name[0].nil?
  322. self.firstname = name[0]
  323. end
  324. if !name[1].nil?
  325. self.lastname = name[1]
  326. end
  327. return
  328. # -no name- firstname.lastname@example.com
  329. elsif ( !firstname || firstname.empty? ) && ( !lastname || lastname.empty? ) && ( email && !email.empty? )
  330. scan = email.scan(/^(.+?)\.(.+?)\@.+?$/)
  331. if scan[0]
  332. if !scan[0][0].nil?
  333. self.firstname = scan[0][0].capitalize
  334. end
  335. if !scan[0][1].nil?
  336. self.lastname = scan[0][1].capitalize
  337. end
  338. end
  339. end
  340. end
  341. def check_email
  342. return if !email
  343. self.email = email.downcase
  344. end
  345. def check_login
  346. # use email as login if not given
  347. if !login && email
  348. self.login = email
  349. end
  350. # if email has changed, login is old email, change also login
  351. if changes && changes['email']
  352. if changes['email'][0] == login
  353. self.login = email
  354. end
  355. end
  356. # check if login already exists
  357. return if !login
  358. self.login = login.downcase
  359. check = true
  360. while check
  361. exists = User.find_by( login: login )
  362. if exists && exists.id != id
  363. self.login = login + rand(999).to_s
  364. else
  365. check = false
  366. end
  367. end
  368. end
  369. def avatar_check
  370. return if !email
  371. return if email.empty?
  372. # save/update avatar
  373. avatar = Avatar.auto_detection(
  374. object: 'User',
  375. o_id: id,
  376. url: email,
  377. source: 'app',
  378. updated_by_id: updated_by_id,
  379. created_by_id: updated_by_id,
  380. )
  381. # update user link
  382. return if !avatar
  383. update_column( :image, avatar.store_hash )
  384. cache_delete
  385. end
  386. def avatar_destroy
  387. Avatar.remove( 'User', id )
  388. end
  389. def check_password
  390. # set old password again if not given
  391. if password == '' || !password
  392. # get current record
  393. if id
  394. #current = User.find(self.id)
  395. #self.password = current.password
  396. self.password = password_was
  397. end
  398. end
  399. # crypt password if not already crypted
  400. return if !password
  401. return if password =~ /^\{sha2\}/
  402. crypted = Digest::SHA2.hexdigest( password )
  403. self.password = "{sha2}#{crypted}"
  404. end
  405. end