user.rb 11 KB

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