asset_host_core 2.0.0.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.markdown +138 -0
  3. data/Rakefile +11 -0
  4. data/app/assets/images/asset_host_core/alert-overlay.png +0 -0
  5. data/app/assets/images/asset_host_core/arrow-left.gif +0 -0
  6. data/app/assets/images/asset_host_core/arrow-right.gif +0 -0
  7. data/app/assets/images/asset_host_core/fallback-img-rect.png +0 -0
  8. data/app/assets/images/asset_host_core/videoplayer-play.png +0 -0
  9. data/app/assets/images/asset_host_core/x.png +0 -0
  10. data/app/assets/javascripts/asset_host_core/admin/assets.js.coffee +221 -0
  11. data/app/assets/javascripts/asset_host_core/application.js +20 -0
  12. data/app/assets/javascripts/asset_host_core/assetadmin.js.coffee +56 -0
  13. data/app/assets/javascripts/asset_host_core/assethost.js.coffee.erb +17 -0
  14. data/app/assets/javascripts/asset_host_core/browserui.js.coffee +139 -0
  15. data/app/assets/javascripts/asset_host_core/chooserui.js.coffee +381 -0
  16. data/app/assets/javascripts/asset_host_core/client.js.coffee +29 -0
  17. data/app/assets/javascripts/asset_host_core/clients/BrightcoveVideo.js.coffee +64 -0
  18. data/app/assets/javascripts/asset_host_core/clients/templates/brightcove_embed.jst.eco +18 -0
  19. data/app/assets/javascripts/asset_host_core/clients/templates/vimeo_embed.jst.eco +1 -0
  20. data/app/assets/javascripts/asset_host_core/clients/templates/youtube_embed.jst.eco +1 -0
  21. data/app/assets/javascripts/asset_host_core/clients/vimeo_video.js.coffee +21 -0
  22. data/app/assets/javascripts/asset_host_core/clients/youtube_video.js.coffee +21 -0
  23. data/app/assets/javascripts/asset_host_core/cmsplugin.js.coffee +235 -0
  24. data/app/assets/javascripts/asset_host_core/models.js.coffee +586 -0
  25. data/app/assets/javascripts/asset_host_core/railsCMS.js.coffee +141 -0
  26. data/app/assets/javascripts/asset_host_core/slideshow.js.coffee +428 -0
  27. data/app/assets/javascripts/asset_host_core/templates/after_upload_button.jst.eco +3 -0
  28. data/app/assets/javascripts/asset_host_core/templates/asset_drop_asset.jst.eco +4 -0
  29. data/app/assets/javascripts/asset_host_core/templates/asset_modal.jst.eco +13 -0
  30. data/app/assets/javascripts/asset_host_core/templates/asset_preview.jst.eco +35 -0
  31. data/app/assets/javascripts/asset_host_core/templates/asset_search.jst.eco +2 -0
  32. data/app/assets/javascripts/asset_host_core/templates/browser_asset.jst.eco +1 -0
  33. data/app/assets/javascripts/asset_host_core/templates/browser_asset_tip.jst.eco +3 -0
  34. data/app/assets/javascripts/asset_host_core/templates/edit_modal.jst.eco +40 -0
  35. data/app/assets/javascripts/asset_host_core/templates/import_help.jst.eco +59 -0
  36. data/app/assets/javascripts/asset_host_core/templates/pagination_link.jst.eco +1 -0
  37. data/app/assets/javascripts/asset_host_core/templates/pagination_links.jst.eco +13 -0
  38. data/app/assets/javascripts/asset_host_core/templates/queued_file.jst.eco +11 -0
  39. data/app/assets/javascripts/asset_host_core/templates/save_and_close_view.jst.eco +4 -0
  40. data/app/assets/javascripts/asset_host_core/templates/upload_all_button.jst.eco +4 -0
  41. data/app/assets/javascripts/asset_host_core/templates/url_input.jst.eco +8 -0
  42. data/app/assets/stylesheets/asset_host_core/application.css.scss +384 -0
  43. data/app/assets/stylesheets/asset_host_core/jquery-ui.css +105 -0
  44. data/app/assets/stylesheets/asset_host_core/public.css.scss +204 -0
  45. data/app/assets/stylesheets/asset_host_core/slidetest.css.scss +93 -0
  46. data/app/controllers/asset_host_core/admin/api_users_controller.rb +72 -0
  47. data/app/controllers/asset_host_core/admin/assets_controller.rb +140 -0
  48. data/app/controllers/asset_host_core/admin/base_controller.rb +36 -0
  49. data/app/controllers/asset_host_core/admin/home_controller.rb +13 -0
  50. data/app/controllers/asset_host_core/admin/outputs_controller.rb +55 -0
  51. data/app/controllers/asset_host_core/api/assets_controller.rb +110 -0
  52. data/app/controllers/asset_host_core/api/base_controller.rb +43 -0
  53. data/app/controllers/asset_host_core/api/outputs_controller.rb +33 -0
  54. data/app/controllers/asset_host_core/application_controller.rb +43 -0
  55. data/app/controllers/asset_host_core/public_controller.rb +104 -0
  56. data/app/models/asset_host_core/api_user.rb +44 -0
  57. data/app/models/asset_host_core/api_user_permission.rb +6 -0
  58. data/app/models/asset_host_core/asset.rb +265 -0
  59. data/app/models/asset_host_core/asset_output.rb +69 -0
  60. data/app/models/asset_host_core/brightcove_video.rb +20 -0
  61. data/app/models/asset_host_core/output.rb +52 -0
  62. data/app/models/asset_host_core/permission.rb +19 -0
  63. data/app/models/asset_host_core/video.rb +8 -0
  64. data/app/models/asset_host_core/vimeo_video.rb +17 -0
  65. data/app/models/asset_host_core/youtube_video.rb +17 -0
  66. data/app/views/asset_host_core/admin/api_users/_form_fields.html.erb +5 -0
  67. data/app/views/asset_host_core/admin/api_users/edit.html.erb +26 -0
  68. data/app/views/asset_host_core/admin/api_users/index.html.erb +31 -0
  69. data/app/views/asset_host_core/admin/api_users/new.html.erb +17 -0
  70. data/app/views/asset_host_core/admin/api_users/show.html.erb +23 -0
  71. data/app/views/asset_host_core/admin/assets/index.html.erb +19 -0
  72. data/app/views/asset_host_core/admin/assets/metadata.html.erb +24 -0
  73. data/app/views/asset_host_core/admin/assets/show.html.erb +86 -0
  74. data/app/views/asset_host_core/admin/home/chooser.html.erb +49 -0
  75. data/app/views/asset_host_core/admin/outputs/_form_fields.html.erb +5 -0
  76. data/app/views/asset_host_core/admin/outputs/edit.html.erb +26 -0
  77. data/app/views/asset_host_core/admin/outputs/index.html.erb +27 -0
  78. data/app/views/asset_host_core/admin/outputs/new.html.erb +13 -0
  79. data/app/views/asset_host_core/admin/outputs/show.html.erb +17 -0
  80. data/app/views/asset_host_core/shared/_footerjs.html.erb +3 -0
  81. data/app/views/asset_host_core/shared/_navbar.html.erb +28 -0
  82. data/app/views/kaminari/_first_page.html.erb +3 -0
  83. data/app/views/kaminari/_gap.html.erb +3 -0
  84. data/app/views/kaminari/_last_page.html.erb +3 -0
  85. data/app/views/kaminari/_next_page.html.erb +3 -0
  86. data/app/views/kaminari/_page.html.erb +3 -0
  87. data/app/views/kaminari/_paginator.html.erb +17 -0
  88. data/app/views/kaminari/_prev_page.html.erb +3 -0
  89. data/app/views/layouts/asset_host_core/application.html.erb +54 -0
  90. data/app/views/layouts/asset_host_core/full_width.html.erb +32 -0
  91. data/app/views/layouts/asset_host_core/minimal.html.erb +45 -0
  92. data/config/initializers/simple_form.rb +142 -0
  93. data/config/initializers/simple_form_bootstrap.rb +45 -0
  94. data/config/locales/simple_form.en.yml +26 -0
  95. data/config/routes.rb +49 -0
  96. data/lib/asset_host_core.rb +38 -0
  97. data/lib/asset_host_core/config.rb +39 -0
  98. data/lib/asset_host_core/engine.rb +94 -0
  99. data/lib/asset_host_core/loaders.rb +34 -0
  100. data/lib/asset_host_core/loaders/asset_host.rb +30 -0
  101. data/lib/asset_host_core/loaders/base.rb +22 -0
  102. data/lib/asset_host_core/loaders/brightcove.rb +67 -0
  103. data/lib/asset_host_core/loaders/flickr.rb +114 -0
  104. data/lib/asset_host_core/loaders/url.rb +59 -0
  105. data/lib/asset_host_core/loaders/vimeo.rb +76 -0
  106. data/lib/asset_host_core/loaders/youtube.rb +90 -0
  107. data/lib/asset_host_core/model_methods.rb +61 -0
  108. data/lib/asset_host_core/paperclip.rb +4 -0
  109. data/lib/asset_host_core/paperclip/asset_thumbnail.rb +92 -0
  110. data/lib/asset_host_core/paperclip/attachment.rb +206 -0
  111. data/lib/asset_host_core/paperclip/trimmer.rb +33 -0
  112. data/lib/asset_host_core/resque_job.rb +13 -0
  113. data/lib/asset_host_core/version.rb +3 -0
  114. data/lib/tasks/asset_host_core_tasks.rake +4 -0
  115. data/spec/controllers/admin/api_users_controller_spec.rb +21 -0
  116. data/spec/controllers/admin/assets_controller_spec.rb +59 -0
  117. data/spec/controllers/admin/home_controller_spec.rb +4 -0
  118. data/spec/controllers/admin/outputs_controller_spec.rb +4 -0
  119. data/spec/controllers/api/assets_controller_spec.rb +133 -0
  120. data/spec/controllers/api/outputs_controller_spec.rb +51 -0
  121. data/spec/controllers/public_controller_spec.rb +4 -0
  122. data/spec/factories.rb +39 -0
  123. data/spec/features/api_users_spec.rb +78 -0
  124. data/spec/fixtures/api/brightcove/video.json +137 -0
  125. data/spec/fixtures/api/flickr/photos_getInfo.json +78 -0
  126. data/spec/fixtures/api/flickr/photos_getSizes.json +82 -0
  127. data/spec/fixtures/api/flickr/photos_licenses_getInfo.json +52 -0
  128. data/spec/fixtures/api/vimeo/video.json +28 -0
  129. data/spec/fixtures/api/youtube/discovery.json +5190 -0
  130. data/spec/fixtures/api/youtube/video.json +44 -0
  131. data/spec/fixtures/images/chipmunk.jpg +0 -0
  132. data/spec/fixtures/images/dude.jpg +0 -0
  133. data/spec/fixtures/images/ernie.jpg +0 -0
  134. data/spec/fixtures/images/fry.png +0 -0
  135. data/spec/fixtures/images/hat.jpg +0 -0
  136. data/spec/fixtures/images/spongebob.png +0 -0
  137. data/spec/fixtures/images/stars.jpg +0 -0
  138. data/spec/internal/app/controllers/application_controller.rb +16 -0
  139. data/spec/internal/app/controllers/sessions_controller.rb +24 -0
  140. data/spec/internal/app/models/user.rb +10 -0
  141. data/spec/internal/app/views/sessions/new.html.erb +14 -0
  142. data/spec/internal/config/database.yml +3 -0
  143. data/spec/internal/config/initializers/assethost_config.rb +57 -0
  144. data/spec/internal/config/routes.rb +7 -0
  145. data/spec/internal/db/combustion_test.sqlite +0 -0
  146. data/spec/internal/db/schema.rb +106 -0
  147. data/spec/internal/log/test.log +14769 -0
  148. data/spec/internal/public/favicon.ico +0 -0
  149. data/spec/internal/public/images/1_27f7745237849975ca90591c1fba5934_original. +0 -0
  150. data/spec/internal/public/images/1_7d33319deca787d5bb3f62ff06563ad2_original. +0 -0
  151. data/spec/internal/public/images/1_b6d48c8b1286104ce76649731e09645f_original. +0 -0
  152. data/spec/internal/public/images/1_b6d48c8b1286104ce76649731e09645f_original.jpg +0 -0
  153. data/spec/internal/public/images/1_b6d48c8b1286104ce76649731e09645f_original.txt +0 -0
  154. data/spec/internal/public/images/1_e179cbd27e07cb55042d0db36cdac095_original. +0 -0
  155. data/spec/internal/public/images/1_e669edd3dfd74be66fc38416e82e3a37_original. +0 -0
  156. data/spec/lib/asset_host_core/loaders/asset_host_spec.rb +33 -0
  157. data/spec/lib/asset_host_core/loaders/brightcove_spec.rb +51 -0
  158. data/spec/lib/asset_host_core/loaders/flickr_spec.rb +72 -0
  159. data/spec/lib/asset_host_core/loaders/url_spec.rb +42 -0
  160. data/spec/lib/asset_host_core/loaders/vimeo_spec.rb +51 -0
  161. data/spec/lib/asset_host_core/loaders/youtube_spec.rb +73 -0
  162. data/spec/lib/asset_host_core/loaders_spec.rb +4 -0
  163. data/spec/lib/asset_host_core/model_methods_spec.rb +4 -0
  164. data/spec/lib/asset_host_core/paperclip/asset_thumbnail_spec.rb +4 -0
  165. data/spec/lib/asset_host_core/paperclip/attachment_spec.rb +4 -0
  166. data/spec/lib/asset_host_core/resque_job_spec.rb +4 -0
  167. data/spec/lib/asset_host_core_spec.rb +4 -0
  168. data/spec/models/api_user_spec.rb +58 -0
  169. data/spec/models/asset_output_spec.rb +4 -0
  170. data/spec/models/asset_spec.rb +4 -0
  171. data/spec/models/output_spec.rb +4 -0
  172. data/spec/models/permission_spec.rb +4 -0
  173. data/spec/spec_helper.rb +30 -0
  174. data/spec/support/fixture_loader.rb +9 -0
  175. data/spec/support/param_helper.rb +14 -0
  176. data/spec/support/permission_matcher.rb +17 -0
  177. data/vendor/assets/images/jquery-ui/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  178. data/vendor/assets/images/jquery-ui/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  179. data/vendor/assets/images/jquery-ui/ui-bg_flat_10_000000_40x100.png +0 -0
  180. data/vendor/assets/images/jquery-ui/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  181. data/vendor/assets/images/jquery-ui/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  182. data/vendor/assets/images/jquery-ui/ui-bg_glass_65_ffffff_1x400.png +0 -0
  183. data/vendor/assets/images/jquery-ui/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  184. data/vendor/assets/images/jquery-ui/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  185. data/vendor/assets/images/jquery-ui/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  186. data/vendor/assets/images/jquery-ui/ui-icons_222222_256x240.png +0 -0
  187. data/vendor/assets/images/jquery-ui/ui-icons_228ef1_256x240.png +0 -0
  188. data/vendor/assets/images/jquery-ui/ui-icons_ef8c08_256x240.png +0 -0
  189. data/vendor/assets/images/jquery-ui/ui-icons_ffd27a_256x240.png +0 -0
  190. data/vendor/assets/images/jquery-ui/ui-icons_ffffff_256x240.png +0 -0
  191. data/vendor/assets/javascripts/backbone.js +1158 -0
  192. data/vendor/assets/javascripts/backbone.modelbinding.js +475 -0
  193. data/vendor/assets/javascripts/exif.js +695 -0
  194. data/vendor/assets/javascripts/jquery-ui.js +5614 -0
  195. data/vendor/assets/javascripts/simplemodal.js +698 -0
  196. data/vendor/assets/javascripts/spin.jquery.js +81 -0
  197. data/vendor/assets/javascripts/spin.min.js +1 -0
  198. data/vendor/assets/javascripts/underscore.min.js +1 -0
  199. metadata +658 -0
@@ -0,0 +1,104 @@
1
+ module AssetHostCore
2
+ class PublicController < AssetHostCore::ApplicationController
3
+
4
+ def home
5
+ render text: "", status: :ok, layout: false
6
+ end
7
+
8
+ #----------
9
+
10
+ # Given a fingerprint, id and style, determine whether the size has been cut.
11
+ # If so, redirect to the image file. If not, fire off a render process for
12
+ # the style.
13
+ def image
14
+ # if we have a cache key with aprint and style, assume we're good
15
+ # to just return that value
16
+ if img = Rails.cache.read("img:#{params[:id]}:#{params[:aprint]}:#{params[:style]}")
17
+ _send_file(img) and return
18
+ end
19
+
20
+ asset = Asset.find_by_id(params[:id])
21
+
22
+ if !asset
23
+ render_not_found and return
24
+ end
25
+
26
+ # Special case for "original"
27
+ # This isn't a "style", just someone has requested
28
+ # the raw image file.
29
+ if params[:aprint] == "original"
30
+ _send_file(asset.image.path) and return
31
+ end
32
+
33
+
34
+ # valid style?
35
+ output = Output.find_by_code(params[:style])
36
+
37
+ if !output
38
+ render_not_found and return
39
+ end
40
+
41
+ # do the fingerprints match? If not, redirect them to the correct URL
42
+ if asset.image_fingerprint && params[:aprint] != asset.image_fingerprint
43
+ redirect_to image_path(
44
+ :aprint => asset.image_fingerprint,
45
+ :id => asset.id,
46
+ :style => params[:style]
47
+ ), status: :moved_permanently and return
48
+ end
49
+
50
+ # do we have a rendered output for this style?
51
+ asset_outputs = asset.outputs.where(output_id: output.id)
52
+
53
+ if asset_outputs.present?
54
+ if asset_outputs.first.fingerprint.present?
55
+ # Yes, return the image
56
+ # the file may still not have been written yet. loop a try to return it
57
+
58
+ 5.times do
59
+ if asset.image.exists? output.code_sym
60
+ # got it. cache and return
61
+
62
+ path = asset.image.path(output.code)
63
+ Rails.cache.write("img:#{asset.id}:#{asset.image_fingerprint}:#{output.code}",path)
64
+
65
+ _send_file(path) and return
66
+ end
67
+
68
+ # nope... sleep!
69
+ sleep 0.5
70
+ end
71
+
72
+ # crap. totally failed.
73
+ redirect_to asset.image.url(output.code) and return
74
+ else
75
+
76
+ # we're in the middle of rendering
77
+ # sleep for 500ms to try and let the render complete, then try again
78
+ sleep 0.5
79
+ redirect_to asset.image.url(output.code) and return
80
+ end
81
+
82
+ else
83
+ # No, fire a render for the style
84
+
85
+ # create an AssetOutput with no fingerprint
86
+ asset.outputs.create(output_id: output.id, image_fingerprint: asset.image_fingerprint)
87
+
88
+ # and fire the queue
89
+ asset.image.enqueue_styles(output.code)
90
+
91
+ # now, sleep for 500ms to try and let the render complete, then try again
92
+ sleep 0.5
93
+ redirect_to asset.image.url(output.code) and return
94
+ end
95
+ end
96
+
97
+
98
+ private
99
+
100
+ def _send_file(file)
101
+ send_file file, type: "image/jpeg", disposition: 'inline'
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,44 @@
1
+ require 'securerandom'
2
+
3
+ module AssetHostCore
4
+ class ApiUser < ActiveRecord::Base
5
+ has_many :api_user_permissions
6
+ has_many :permissions, through: :api_user_permissions
7
+
8
+ validates_uniqueness_of :auth_token
9
+ validates :name, :email, presence: true
10
+
11
+ before_create :generate_auth_token, if: -> {
12
+ self.auth_token.blank?
13
+ }
14
+
15
+ attr_accessible :name, :email, :is_active, :permission_ids
16
+
17
+ class << self
18
+ def authenticate(auth_token)
19
+ if user = self.where(is_active: true, auth_token: auth_token).first
20
+ user.update_column(:last_authenticated, Time.now)
21
+ user
22
+ else
23
+ false
24
+ end
25
+ end
26
+ end
27
+
28
+
29
+ def may?(ability, resource)
30
+ !!self.permissions.find do |p|
31
+ p.resource == resource.to_s && p.ability == ability.to_s
32
+ end
33
+ end
34
+
35
+
36
+ def generate_auth_token
37
+ self.auth_token = SecureRandom.urlsafe_base64
38
+ end
39
+
40
+ def generate_auth_token!
41
+ generate_auth_token and save
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,6 @@
1
+ module AssetHostCore
2
+ class ApiUserPermission < ActiveRecord::Base
3
+ belongs_to :api_user
4
+ belongs_to :permission
5
+ end
6
+ end
@@ -0,0 +1,265 @@
1
+ module AssetHostCore
2
+ class Asset < ActiveRecord::Base
3
+ @queue = :paperclip
4
+
5
+ VIA_UNKNOWN = 0
6
+ VIA_FLICKR = 1
7
+ VIA_LOCAL = 2
8
+ VIA_UPLOAD = 3
9
+
10
+ GRAVITY_OPTIONS = [
11
+ [ "Center (default)", "Center" ],
12
+ [ "Top", "North" ],
13
+ [ "Bottom", "South" ],
14
+ [ "Left", "West" ],
15
+ [ "Right", "East" ],
16
+ [ "Top Left", "NorthWest" ],
17
+ [ "Top Right", "NorthEast" ],
18
+ [ "Bottom Left", "SouthWest" ],
19
+ [ "Bottom Right", "SouthEast" ]
20
+ ]
21
+
22
+
23
+ define_index do
24
+ indexes title
25
+ indexes caption
26
+ indexes notes
27
+ indexes owner
28
+ has created_at
29
+ has updated_at
30
+ where "is_hidden = 0"
31
+ end
32
+
33
+
34
+ scope :visible, -> { where(is_hidden: false) }
35
+
36
+ has_many :outputs, :class_name => "AssetOutput", :order => "created_at desc", :dependent => :destroy
37
+ belongs_to :native, :polymorphic => true
38
+
39
+ has_attached_file :image, Rails.application.config.assethost.paperclip_options.merge({
40
+ :styles => proc { Output.paperclip_sizes },
41
+ :processors => [:asset_thumbnail],
42
+ :interpolator => self
43
+ })
44
+
45
+ treat_as_image_asset :image
46
+
47
+ before_create :sync_exif_data
48
+
49
+ after_commit :publish_asset_update, :if => :persisted?
50
+ after_commit :publish_asset_delete, :on => :destroy
51
+
52
+
53
+ attr_accessible :title,
54
+ :caption,
55
+ :owner,
56
+ :url,
57
+ :notes,
58
+ :creator_id,
59
+ :image,
60
+ :image_taken,
61
+ :native,
62
+ :image_gravity
63
+
64
+
65
+ #----------
66
+
67
+ def size(code)
68
+ @_sizes ||= {}
69
+ @_sizes[ code ] ||= AssetSize.new(self, Output.where(code: code).first)
70
+ end
71
+
72
+ #----------
73
+
74
+ def as_json(options={})
75
+ {
76
+ :id => self.id,
77
+ :title => self.title,
78
+ :caption => self.caption,
79
+ :owner => self.owner,
80
+ :size => [self.image_width, self.image_height].join('x'),
81
+ :tags => self.image.tags,
82
+ :notes => self.notes,
83
+ :created_at => self.created_at,
84
+ :taken_at => self.image_taken || self.created_at,
85
+ :native => self.native.try(:as_json),
86
+ :image_file_size => self.image_file_size,
87
+
88
+ :url => "http://#{Rails.application.config.assethost.server}#{AssetHostCore::Engine.mounted_path}/api/assets/#{self.id}/",
89
+ :sizes => Output.paperclip_sizes.inject({}) { |h, (s,_)| h[s] = { width: self.image.width(s), height: self.image.height(s) }; h },
90
+ :urls => Output.paperclip_sizes.inject({}) { |h, (s,_)| h[s] = self.image.url(s); h }
91
+ }
92
+ end
93
+
94
+ alias :json :as_json
95
+
96
+ #----------
97
+
98
+ def tag(style)
99
+ self.image.tag(style)
100
+ end
101
+
102
+ #----------
103
+
104
+ def isPortrait?
105
+ self.image_width < self.image_height
106
+ end
107
+
108
+ #----------
109
+
110
+ def url_domain
111
+ return nil if !self.url
112
+
113
+ domain = URI.parse(self.url).host
114
+ domain == 'www.flickr.com' ? 'Flickr' : domain
115
+ end
116
+
117
+ #----------
118
+
119
+ def output_by_style(style)
120
+ @s_outputs ||= self.outputs.inject({}) { |h,o| h[o.output.code] = o; h }
121
+ @s_outputs[style.to_s] || false
122
+ end
123
+
124
+ def rendered_outputs
125
+ @rendered ||= Output.paperclip_sizes.collect do |s|
126
+ ["#{s[0]} (#{self.image.width(s[0])}x#{self.image.height(s[0])})",s[0]]
127
+ end
128
+ end
129
+
130
+ #----------
131
+
132
+ def self.interpolate(pattern, attachment, style)
133
+ # we support:
134
+ # global:
135
+ # :rails_root -- Rails.root
136
+ #
137
+ # style-based:
138
+ # :style -- output code
139
+ # :extension -- extension for Output
140
+ #
141
+ # asset-based:
142
+ # :id -- asset id
143
+ # :fingerprint -- image fingerprint
144
+ #
145
+ # output-based:
146
+ # :sprint -- AssetOutput fingerprint
147
+ #
148
+ # first see what we've been passed as a style. could be string, symbol,
149
+ # Output or AssetOutput
150
+
151
+ asset = attachment.instance
152
+ result = pattern.clone
153
+
154
+ if style.respond_to?(:to_sym) && style.to_sym == :original
155
+ # special case...
156
+
157
+ elsif style.is_a? AssetOutput
158
+ ao = style
159
+ output = ao.output
160
+
161
+ elsif style.is_a? Output
162
+ output = style
163
+ ao = attachment.instance.outputs.where(output_id: output.id).first
164
+ return nil if !ao
165
+
166
+ else
167
+ output = Output.where(code: style).first
168
+ return nil if !output
169
+
170
+ ao = attachment.instance.outputs.where(output_id: output.id).first
171
+ end
172
+
173
+
174
+ # global rules
175
+ result.gsub!(":rails_root", Rails.root.to_s)
176
+
177
+ if asset
178
+ # asset-based rules
179
+ result.gsub!(":id", asset.id.to_s)
180
+ result.gsub!(":fingerprint", asset.image_fingerprint.to_s)
181
+ else
182
+ if pattern =~ /:(?:id|fingerprint)/
183
+ return false
184
+ end
185
+ end
186
+
187
+ if style.respond_to?(:to_sym) && style.to_sym == :original
188
+ # hardcoded handling for the original file
189
+ result.gsub!(":style", "original")
190
+ result.gsub!(":extension", File.extname(attachment.original_filename).gsub(/^\.+/, ""))
191
+ result.gsub!(":sprint","original")
192
+ else
193
+ if output
194
+ # style-based rules
195
+ result.gsub!(":style", output.code.to_s)
196
+ result.gsub!(":extension", output.extension)
197
+ else
198
+ if pattern =~ /:(?:style|extension)/
199
+ return false
200
+ end
201
+ end
202
+
203
+
204
+ if ao && ao.fingerprint
205
+ # output-based rules
206
+ result.gsub!(":sprint", ao.fingerprint)
207
+ else
208
+ result.gsub!(":sprint", "NOT_YET_RENDERED")
209
+ end
210
+ end
211
+
212
+ result
213
+ end
214
+
215
+ #----------
216
+ # syncs the exif to the corresponding Asset attributes
217
+ # We don't want to override anything that was set explicitly.
218
+ def sync_exif_data
219
+ self.title = self.image_title if self.title.blank?
220
+ self.caption = self.image_description if self.caption.blank?
221
+ self.owner = self.image_copyright if self.owner.blank?
222
+ end
223
+
224
+ #----------
225
+
226
+ def method_missing(method, *args)
227
+ if output = Output.where(code: method.to_s).first
228
+ self.size(output.code)
229
+ else
230
+ super
231
+ end
232
+ end
233
+
234
+
235
+ #----------
236
+
237
+ private
238
+
239
+ def publish_asset_update
240
+ AssetHostCore::Engine.redis_publish(action: "UPDATE", id: self.id)
241
+ true
242
+ end
243
+
244
+ def publish_asset_delete
245
+ AssetHostCore::Engine.redis_publish(action: "DELETE", id: self.id)
246
+ true
247
+ end
248
+ end
249
+
250
+ #----------
251
+
252
+ class AssetSize
253
+ attr_accessor :width, :height, :tag, :url, :asset, :output
254
+
255
+ def initialize(asset,output)
256
+ @asset = asset
257
+ @output = output
258
+
259
+ @width = @asset.image.width(output.code_sym)
260
+ @height = @asset.image.height(output.code_sym)
261
+ @url = @asset.image.url(output.code_sym)
262
+ @tag = @asset.image.tag(output.code_sym)
263
+ end
264
+ end
265
+ end
@@ -0,0 +1,69 @@
1
+ module AssetHostCore
2
+ class AssetOutput < ActiveRecord::Base
3
+ belongs_to :asset
4
+ belongs_to :output
5
+
6
+ before_save :delete_cache_and_img, if: -> { self.fingerprint_changed? || self.image_fingerprint_changed? }
7
+ before_destroy :delete_cache_and_img_and_fingerprint
8
+
9
+ after_commit :cache_img_path, if: -> { self.image_fingerprint.present? && self.fingerprint.present? }
10
+
11
+ scope :rendered, -> { where("fingerprint != ''") }
12
+
13
+
14
+ #----------
15
+
16
+ protected
17
+
18
+ # on save, check whether we should be creating or deleting caches
19
+ def delete_cache_and_img
20
+ # -- out with the old -- #
21
+
22
+ finger = self.fingerprint_changed? ? self.fingerprint_was : self.fingerprint
23
+ imgfinger = self.image_fingerprint_changed? ? self.image_fingerprint_was : self.image_fingerprint
24
+
25
+ if finger && imgfinger
26
+ # -- delete our old cache -- #
27
+ resp = Rails.cache.delete("img:"+[self.asset.id,imgfinger,self.output.code].join(":"))
28
+
29
+ # -- delete our AssetOutput -- #
30
+ path = self.asset.image.path(self)
31
+
32
+ if path
33
+ # this path could have our current values in it. make sure we've
34
+ # got old fingerprints
35
+ path = path.gsub(self.asset.image_fingerprint,imgfinger).gsub(self.fingerprint,finger)
36
+
37
+ self.asset.image.delete_path(path)
38
+ end
39
+ end
40
+
41
+ true
42
+ end
43
+
44
+ #----------
45
+
46
+ # on destroy, we need to do the normal save deletes and also delete our fingerprint
47
+ def delete_cache_and_img_and_fingerprint
48
+ self.delete_cache_and_img
49
+
50
+ # why do we bother clearing our fingerprint if the AssetOutput itself
51
+ # is about to get deleted? If we don't, the after_commit handler will
52
+ # rewrite the same cache we just deleted.
53
+ self.fingerprint = ''
54
+ end
55
+
56
+ #----------
57
+
58
+ def cache_img_path
59
+ # -- in with the new -- #
60
+ path = self.asset.image.path(self)
61
+
62
+ if path && File.exists?(path)
63
+ Rails.cache.write("img:"+[self.asset.id,self.image_fingerprint,self.output.code].join(":"),path)
64
+ end
65
+
66
+ true
67
+ end
68
+ end
69
+ end