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.
- data/MIT-LICENSE +20 -0
- data/README.markdown +138 -0
- data/Rakefile +11 -0
- data/app/assets/images/asset_host_core/alert-overlay.png +0 -0
- data/app/assets/images/asset_host_core/arrow-left.gif +0 -0
- data/app/assets/images/asset_host_core/arrow-right.gif +0 -0
- data/app/assets/images/asset_host_core/fallback-img-rect.png +0 -0
- data/app/assets/images/asset_host_core/videoplayer-play.png +0 -0
- data/app/assets/images/asset_host_core/x.png +0 -0
- data/app/assets/javascripts/asset_host_core/admin/assets.js.coffee +221 -0
- data/app/assets/javascripts/asset_host_core/application.js +20 -0
- data/app/assets/javascripts/asset_host_core/assetadmin.js.coffee +56 -0
- data/app/assets/javascripts/asset_host_core/assethost.js.coffee.erb +17 -0
- data/app/assets/javascripts/asset_host_core/browserui.js.coffee +139 -0
- data/app/assets/javascripts/asset_host_core/chooserui.js.coffee +381 -0
- data/app/assets/javascripts/asset_host_core/client.js.coffee +29 -0
- data/app/assets/javascripts/asset_host_core/clients/BrightcoveVideo.js.coffee +64 -0
- data/app/assets/javascripts/asset_host_core/clients/templates/brightcove_embed.jst.eco +18 -0
- data/app/assets/javascripts/asset_host_core/clients/templates/vimeo_embed.jst.eco +1 -0
- data/app/assets/javascripts/asset_host_core/clients/templates/youtube_embed.jst.eco +1 -0
- data/app/assets/javascripts/asset_host_core/clients/vimeo_video.js.coffee +21 -0
- data/app/assets/javascripts/asset_host_core/clients/youtube_video.js.coffee +21 -0
- data/app/assets/javascripts/asset_host_core/cmsplugin.js.coffee +235 -0
- data/app/assets/javascripts/asset_host_core/models.js.coffee +586 -0
- data/app/assets/javascripts/asset_host_core/railsCMS.js.coffee +141 -0
- data/app/assets/javascripts/asset_host_core/slideshow.js.coffee +428 -0
- data/app/assets/javascripts/asset_host_core/templates/after_upload_button.jst.eco +3 -0
- data/app/assets/javascripts/asset_host_core/templates/asset_drop_asset.jst.eco +4 -0
- data/app/assets/javascripts/asset_host_core/templates/asset_modal.jst.eco +13 -0
- data/app/assets/javascripts/asset_host_core/templates/asset_preview.jst.eco +35 -0
- data/app/assets/javascripts/asset_host_core/templates/asset_search.jst.eco +2 -0
- data/app/assets/javascripts/asset_host_core/templates/browser_asset.jst.eco +1 -0
- data/app/assets/javascripts/asset_host_core/templates/browser_asset_tip.jst.eco +3 -0
- data/app/assets/javascripts/asset_host_core/templates/edit_modal.jst.eco +40 -0
- data/app/assets/javascripts/asset_host_core/templates/import_help.jst.eco +59 -0
- data/app/assets/javascripts/asset_host_core/templates/pagination_link.jst.eco +1 -0
- data/app/assets/javascripts/asset_host_core/templates/pagination_links.jst.eco +13 -0
- data/app/assets/javascripts/asset_host_core/templates/queued_file.jst.eco +11 -0
- data/app/assets/javascripts/asset_host_core/templates/save_and_close_view.jst.eco +4 -0
- data/app/assets/javascripts/asset_host_core/templates/upload_all_button.jst.eco +4 -0
- data/app/assets/javascripts/asset_host_core/templates/url_input.jst.eco +8 -0
- data/app/assets/stylesheets/asset_host_core/application.css.scss +384 -0
- data/app/assets/stylesheets/asset_host_core/jquery-ui.css +105 -0
- data/app/assets/stylesheets/asset_host_core/public.css.scss +204 -0
- data/app/assets/stylesheets/asset_host_core/slidetest.css.scss +93 -0
- data/app/controllers/asset_host_core/admin/api_users_controller.rb +72 -0
- data/app/controllers/asset_host_core/admin/assets_controller.rb +140 -0
- data/app/controllers/asset_host_core/admin/base_controller.rb +36 -0
- data/app/controllers/asset_host_core/admin/home_controller.rb +13 -0
- data/app/controllers/asset_host_core/admin/outputs_controller.rb +55 -0
- data/app/controllers/asset_host_core/api/assets_controller.rb +110 -0
- data/app/controllers/asset_host_core/api/base_controller.rb +43 -0
- data/app/controllers/asset_host_core/api/outputs_controller.rb +33 -0
- data/app/controllers/asset_host_core/application_controller.rb +43 -0
- data/app/controllers/asset_host_core/public_controller.rb +104 -0
- data/app/models/asset_host_core/api_user.rb +44 -0
- data/app/models/asset_host_core/api_user_permission.rb +6 -0
- data/app/models/asset_host_core/asset.rb +265 -0
- data/app/models/asset_host_core/asset_output.rb +69 -0
- data/app/models/asset_host_core/brightcove_video.rb +20 -0
- data/app/models/asset_host_core/output.rb +52 -0
- data/app/models/asset_host_core/permission.rb +19 -0
- data/app/models/asset_host_core/video.rb +8 -0
- data/app/models/asset_host_core/vimeo_video.rb +17 -0
- data/app/models/asset_host_core/youtube_video.rb +17 -0
- data/app/views/asset_host_core/admin/api_users/_form_fields.html.erb +5 -0
- data/app/views/asset_host_core/admin/api_users/edit.html.erb +26 -0
- data/app/views/asset_host_core/admin/api_users/index.html.erb +31 -0
- data/app/views/asset_host_core/admin/api_users/new.html.erb +17 -0
- data/app/views/asset_host_core/admin/api_users/show.html.erb +23 -0
- data/app/views/asset_host_core/admin/assets/index.html.erb +19 -0
- data/app/views/asset_host_core/admin/assets/metadata.html.erb +24 -0
- data/app/views/asset_host_core/admin/assets/show.html.erb +86 -0
- data/app/views/asset_host_core/admin/home/chooser.html.erb +49 -0
- data/app/views/asset_host_core/admin/outputs/_form_fields.html.erb +5 -0
- data/app/views/asset_host_core/admin/outputs/edit.html.erb +26 -0
- data/app/views/asset_host_core/admin/outputs/index.html.erb +27 -0
- data/app/views/asset_host_core/admin/outputs/new.html.erb +13 -0
- data/app/views/asset_host_core/admin/outputs/show.html.erb +17 -0
- data/app/views/asset_host_core/shared/_footerjs.html.erb +3 -0
- data/app/views/asset_host_core/shared/_navbar.html.erb +28 -0
- data/app/views/kaminari/_first_page.html.erb +3 -0
- data/app/views/kaminari/_gap.html.erb +3 -0
- data/app/views/kaminari/_last_page.html.erb +3 -0
- data/app/views/kaminari/_next_page.html.erb +3 -0
- data/app/views/kaminari/_page.html.erb +3 -0
- data/app/views/kaminari/_paginator.html.erb +17 -0
- data/app/views/kaminari/_prev_page.html.erb +3 -0
- data/app/views/layouts/asset_host_core/application.html.erb +54 -0
- data/app/views/layouts/asset_host_core/full_width.html.erb +32 -0
- data/app/views/layouts/asset_host_core/minimal.html.erb +45 -0
- data/config/initializers/simple_form.rb +142 -0
- data/config/initializers/simple_form_bootstrap.rb +45 -0
- data/config/locales/simple_form.en.yml +26 -0
- data/config/routes.rb +49 -0
- data/lib/asset_host_core.rb +38 -0
- data/lib/asset_host_core/config.rb +39 -0
- data/lib/asset_host_core/engine.rb +94 -0
- data/lib/asset_host_core/loaders.rb +34 -0
- data/lib/asset_host_core/loaders/asset_host.rb +30 -0
- data/lib/asset_host_core/loaders/base.rb +22 -0
- data/lib/asset_host_core/loaders/brightcove.rb +67 -0
- data/lib/asset_host_core/loaders/flickr.rb +114 -0
- data/lib/asset_host_core/loaders/url.rb +59 -0
- data/lib/asset_host_core/loaders/vimeo.rb +76 -0
- data/lib/asset_host_core/loaders/youtube.rb +90 -0
- data/lib/asset_host_core/model_methods.rb +61 -0
- data/lib/asset_host_core/paperclip.rb +4 -0
- data/lib/asset_host_core/paperclip/asset_thumbnail.rb +92 -0
- data/lib/asset_host_core/paperclip/attachment.rb +206 -0
- data/lib/asset_host_core/paperclip/trimmer.rb +33 -0
- data/lib/asset_host_core/resque_job.rb +13 -0
- data/lib/asset_host_core/version.rb +3 -0
- data/lib/tasks/asset_host_core_tasks.rake +4 -0
- data/spec/controllers/admin/api_users_controller_spec.rb +21 -0
- data/spec/controllers/admin/assets_controller_spec.rb +59 -0
- data/spec/controllers/admin/home_controller_spec.rb +4 -0
- data/spec/controllers/admin/outputs_controller_spec.rb +4 -0
- data/spec/controllers/api/assets_controller_spec.rb +133 -0
- data/spec/controllers/api/outputs_controller_spec.rb +51 -0
- data/spec/controllers/public_controller_spec.rb +4 -0
- data/spec/factories.rb +39 -0
- data/spec/features/api_users_spec.rb +78 -0
- data/spec/fixtures/api/brightcove/video.json +137 -0
- data/spec/fixtures/api/flickr/photos_getInfo.json +78 -0
- data/spec/fixtures/api/flickr/photos_getSizes.json +82 -0
- data/spec/fixtures/api/flickr/photos_licenses_getInfo.json +52 -0
- data/spec/fixtures/api/vimeo/video.json +28 -0
- data/spec/fixtures/api/youtube/discovery.json +5190 -0
- data/spec/fixtures/api/youtube/video.json +44 -0
- data/spec/fixtures/images/chipmunk.jpg +0 -0
- data/spec/fixtures/images/dude.jpg +0 -0
- data/spec/fixtures/images/ernie.jpg +0 -0
- data/spec/fixtures/images/fry.png +0 -0
- data/spec/fixtures/images/hat.jpg +0 -0
- data/spec/fixtures/images/spongebob.png +0 -0
- data/spec/fixtures/images/stars.jpg +0 -0
- data/spec/internal/app/controllers/application_controller.rb +16 -0
- data/spec/internal/app/controllers/sessions_controller.rb +24 -0
- data/spec/internal/app/models/user.rb +10 -0
- data/spec/internal/app/views/sessions/new.html.erb +14 -0
- data/spec/internal/config/database.yml +3 -0
- data/spec/internal/config/initializers/assethost_config.rb +57 -0
- data/spec/internal/config/routes.rb +7 -0
- data/spec/internal/db/combustion_test.sqlite +0 -0
- data/spec/internal/db/schema.rb +106 -0
- data/spec/internal/log/test.log +14769 -0
- data/spec/internal/public/favicon.ico +0 -0
- data/spec/internal/public/images/1_27f7745237849975ca90591c1fba5934_original. +0 -0
- data/spec/internal/public/images/1_7d33319deca787d5bb3f62ff06563ad2_original. +0 -0
- data/spec/internal/public/images/1_b6d48c8b1286104ce76649731e09645f_original. +0 -0
- data/spec/internal/public/images/1_b6d48c8b1286104ce76649731e09645f_original.jpg +0 -0
- data/spec/internal/public/images/1_b6d48c8b1286104ce76649731e09645f_original.txt +0 -0
- data/spec/internal/public/images/1_e179cbd27e07cb55042d0db36cdac095_original. +0 -0
- data/spec/internal/public/images/1_e669edd3dfd74be66fc38416e82e3a37_original. +0 -0
- data/spec/lib/asset_host_core/loaders/asset_host_spec.rb +33 -0
- data/spec/lib/asset_host_core/loaders/brightcove_spec.rb +51 -0
- data/spec/lib/asset_host_core/loaders/flickr_spec.rb +72 -0
- data/spec/lib/asset_host_core/loaders/url_spec.rb +42 -0
- data/spec/lib/asset_host_core/loaders/vimeo_spec.rb +51 -0
- data/spec/lib/asset_host_core/loaders/youtube_spec.rb +73 -0
- data/spec/lib/asset_host_core/loaders_spec.rb +4 -0
- data/spec/lib/asset_host_core/model_methods_spec.rb +4 -0
- data/spec/lib/asset_host_core/paperclip/asset_thumbnail_spec.rb +4 -0
- data/spec/lib/asset_host_core/paperclip/attachment_spec.rb +4 -0
- data/spec/lib/asset_host_core/resque_job_spec.rb +4 -0
- data/spec/lib/asset_host_core_spec.rb +4 -0
- data/spec/models/api_user_spec.rb +58 -0
- data/spec/models/asset_output_spec.rb +4 -0
- data/spec/models/asset_spec.rb +4 -0
- data/spec/models/output_spec.rb +4 -0
- data/spec/models/permission_spec.rb +4 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/support/fixture_loader.rb +9 -0
- data/spec/support/param_helper.rb +14 -0
- data/spec/support/permission_matcher.rb +17 -0
- data/vendor/assets/images/jquery-ui/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_flat_10_000000_40x100.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-icons_222222_256x240.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-icons_228ef1_256x240.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-icons_ef8c08_256x240.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-icons_ffd27a_256x240.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-icons_ffffff_256x240.png +0 -0
- data/vendor/assets/javascripts/backbone.js +1158 -0
- data/vendor/assets/javascripts/backbone.modelbinding.js +475 -0
- data/vendor/assets/javascripts/exif.js +695 -0
- data/vendor/assets/javascripts/jquery-ui.js +5614 -0
- data/vendor/assets/javascripts/simplemodal.js +698 -0
- data/vendor/assets/javascripts/spin.jquery.js +81 -0
- data/vendor/assets/javascripts/spin.min.js +1 -0
- data/vendor/assets/javascripts/underscore.min.js +1 -0
- 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,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
|