user.rb 12 KB

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