avatar.rb 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
  2. class Avatar < ApplicationModel
  3. belongs_to :object_lookup, class_name: 'ObjectLookup'
  4. =begin
  5. add an avatar based on auto detection (email address)
  6. Avatar.auto_detection(
  7. :object => 'User',
  8. :o_id => user.id,
  9. :url => 'somebody@example.com',
  10. :source => 'web',
  11. :updated_by_id => 1,
  12. :created_by_id => 1,
  13. )
  14. =end
  15. def self.auto_detection(data)
  16. # return if we run import mode
  17. return if Setting.get('import_mode')
  18. return if !data[:url]
  19. return if data[:url].empty?
  20. # dry gravatar lookup
  21. hash = Digest::MD5.hexdigest(data[:url])
  22. url = "http://www.gravatar.com/avatar/#{hash}.jpg?s=160&d=404"
  23. logger.info "Avatar.auto_detection found #{data[:url]}: #{url}"
  24. Avatar.add(
  25. object: data[:object],
  26. o_id: data[:o_id],
  27. url: url,
  28. source: 'gravatar.com',
  29. deletable: false,
  30. updated_by_id: 1,
  31. created_by_id: 1,
  32. )
  33. end
  34. =begin
  35. add a avatar
  36. Avatar.add(
  37. :object => 'User',
  38. :o_id => user.id,
  39. :default => true,
  40. :full => {
  41. :content => '...',
  42. :mime_type => 'image/png',
  43. },
  44. :resize => {
  45. :content => '...',
  46. :mime_type => 'image/png',
  47. },
  48. :source => 'web',
  49. :updated_by_id => 1,
  50. :created_by_id => 1,
  51. )
  52. =end
  53. def self.add(data)
  54. # lookups
  55. if data[:object]
  56. object_id = ObjectLookup.by_name( data[:object] )
  57. end
  58. # add initial avatar
  59. add_init_avatar(object_id, data[:o_id])
  60. record = {
  61. o_id: data[:o_id],
  62. object_lookup_id: object_id,
  63. default: true,
  64. deletable: data[:deletable],
  65. initial: false,
  66. source: data[:source],
  67. source_url: data[:url],
  68. updated_by_id: data[:updated_by_id],
  69. created_by_id: data[:created_by_id],
  70. }
  71. # check if avatar with url already exists
  72. avatar_already_exists = nil
  73. if data[:source] && !data[:source].empty?
  74. avatar_already_exists = Avatar.find_by(
  75. object_lookup_id: object_id,
  76. o_id: data[:o_id],
  77. source: data[:source],
  78. )
  79. end
  80. # fetch image
  81. if data[:url] && data[:url] =~ /^http/
  82. # check if source ist already updated within last 2 minutes
  83. if avatar_already_exists
  84. if avatar_already_exists.source_url == data[:url]
  85. if avatar_already_exists.updated_at > 2.minutes.ago
  86. return
  87. end
  88. end
  89. end
  90. # twitter workaround to get bigger avatar images
  91. # see also https://dev.twitter.com/overview/general/user-profile-images-and-banners
  92. if data[:url] =~ %r{//pbs.twimg.com/}i
  93. data[:url].sub!(/normal\.png$/, 'bigger.png')
  94. end
  95. # fetch image
  96. response = UserAgent.get(
  97. data[:url],
  98. {},
  99. {
  100. open_timeout: 4,
  101. read_timeout: 6,
  102. },
  103. )
  104. if !response.success?
  105. logger.info "Can't fetch '#{data[:url]}' (maybe no avatar available), http code: #{response.code}"
  106. return
  107. end
  108. logger.info "Fetch '#{data[:url]}', http code: #{response.code}"
  109. mime_type = 'image'
  110. if data[:url] =~ /\.png/i
  111. mime_type = 'image/png'
  112. end
  113. if data[:url] =~ /\.(jpg|jpeg)/i
  114. mime_type = 'image/png'
  115. end
  116. if !data[:resize]
  117. data[:resize] = {}
  118. end
  119. data[:resize][:content] = response.body
  120. data[:resize][:mime_type] = mime_type
  121. if !data[:full]
  122. data[:full] = {}
  123. end
  124. data[:full][:content] = response.body
  125. data[:full][:mime_type] = mime_type
  126. end
  127. # check if avatar need to be updated
  128. record[:store_hash] = Digest::MD5.hexdigest( data[:resize][:content] )
  129. if avatar_already_exists
  130. return if avatar_already_exists.store_hash == record[:store_hash]
  131. end
  132. # store images
  133. object_name = "Avatar::#{data[:object]}"
  134. if data[:full]
  135. store_full = Store.add(
  136. object: "#{object_name}::Full",
  137. o_id: data[:o_id],
  138. data: data[:full][:content],
  139. filename: 'avatar_full',
  140. preferences: {
  141. 'Mime-Type' => data[:full][:mime_type]
  142. },
  143. created_by_id: data[:created_by_id],
  144. )
  145. record[:store_full_id] = store_full.id
  146. record[:store_hash] = Digest::MD5.hexdigest( data[:full][:content] )
  147. end
  148. if data[:resize]
  149. store_resize = Store.add(
  150. object: "#{object_name}::Resize",
  151. o_id: data[:o_id],
  152. data: data[:resize][:content],
  153. filename: 'avatar',
  154. preferences: {
  155. 'Mime-Type' => data[:resize][:mime_type]
  156. },
  157. created_by_id: data[:created_by_id],
  158. )
  159. record[:store_resize_id] = store_resize.id
  160. record[:store_hash] = Digest::MD5.hexdigest( data[:resize][:content] )
  161. end
  162. # update existing
  163. if avatar_already_exists
  164. avatar_already_exists.update_attributes( record )
  165. avatar = avatar_already_exists
  166. # add new one and set it as default
  167. else
  168. avatar = Avatar.create(record)
  169. set_default_items(object_id, data[:o_id], avatar.id)
  170. end
  171. avatar
  172. end
  173. =begin
  174. set avatars as default
  175. Avatar.set_default( 'User', 123, avatar_id )
  176. =end
  177. def self.set_default( object_name, o_id, avatar_id )
  178. object_id = ObjectLookup.by_name( object_name )
  179. avatar = Avatar.find_by(
  180. object_lookup_id: object_id,
  181. o_id: o_id,
  182. id: avatar_id,
  183. )
  184. avatar.default = true
  185. avatar.save!
  186. # set all other to default false
  187. set_default_items(object_id, o_id, avatar_id)
  188. avatar
  189. end
  190. =begin
  191. remove all avatars of an object
  192. Avatar.remove( 'User', 123 )
  193. =end
  194. def self.remove( object_name, o_id )
  195. object_id = ObjectLookup.by_name( object_name )
  196. Avatar.where(
  197. object_lookup_id: object_id,
  198. o_id: o_id,
  199. ).destroy_all
  200. object_name_store = "Avatar::#{object_name}"
  201. Store.remove(
  202. object: "#{object_name_store}::Full",
  203. o_id: o_id,
  204. )
  205. Store.remove(
  206. object: "#{object_name_store}::Resize",
  207. o_id: o_id,
  208. )
  209. end
  210. =begin
  211. remove one avatars of an object
  212. Avatar.remove_one( 'User', 123, avatar_id )
  213. =end
  214. def self.remove_one( object_name, o_id, avatar_id )
  215. object_id = ObjectLookup.by_name( object_name )
  216. Avatar.where(
  217. object_lookup_id: object_id,
  218. o_id: o_id,
  219. id: avatar_id,
  220. ).destroy_all
  221. end
  222. =begin
  223. return all avatars of an user
  224. avatars = Avatar.list( 'User', 123 )
  225. =end
  226. def self.list(object_name, o_id)
  227. object_id = ObjectLookup.by_name( object_name )
  228. avatars = Avatar.where(
  229. object_lookup_id: object_id,
  230. o_id: o_id,
  231. ).order( 'initial DESC, deletable ASC, created_at ASC, id DESC' )
  232. # add initial avatar
  233. add_init_avatar(object_id, o_id)
  234. avatar_list = []
  235. avatars.each do |avatar|
  236. data = avatar.attributes
  237. if avatar.store_resize_id
  238. file = Store.find(avatar.store_resize_id)
  239. data['content'] = "data:#{ file.preferences['Mime-Type'] };base64,#{ Base64.strict_encode64( file.content ) }"
  240. end
  241. avatar_list.push data
  242. end
  243. avatar_list
  244. end
  245. =begin
  246. get default avatar image of user by hash
  247. store = Avatar.get_by_hash( hash )
  248. returns:
  249. store object
  250. =end
  251. def self.get_by_hash(hash)
  252. avatar = Avatar.find_by(
  253. store_hash: hash,
  254. )
  255. return if !avatar
  256. file = Store.find(avatar.store_resize_id)
  257. end
  258. =begin
  259. get default avatar of user by user id
  260. avatar = Avatar.get_default( 'User', user_id )
  261. returns:
  262. avatar object
  263. =end
  264. def self.get_default(object_name, o_id)
  265. object_id = ObjectLookup.by_name( object_name )
  266. Avatar.find_by(
  267. object_lookup_id: object_id,
  268. o_id: o_id,
  269. default: true,
  270. )
  271. end
  272. def self.set_default_items(object_id, o_id, avatar_id)
  273. avatars = Avatar.where(
  274. object_lookup_id: object_id,
  275. o_id: o_id,
  276. ).order( 'created_at ASC, id DESC' )
  277. avatars.each do |avatar|
  278. next if avatar.id == avatar_id
  279. avatar.default = false
  280. avatar.save!
  281. end
  282. end
  283. def self.add_init_avatar(object_id, o_id)
  284. count = Avatar.where(
  285. object_lookup_id: object_id,
  286. o_id: o_id,
  287. ).count
  288. return if count > 0
  289. Avatar.create(
  290. o_id: o_id,
  291. object_lookup_id: object_id,
  292. default: true,
  293. source: 'init',
  294. initial: true,
  295. deletable: false,
  296. updated_by_id: 1,
  297. created_by_id: 1,
  298. )
  299. end
  300. end