effective_assets 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +228 -0
  3. data/Rakefile +23 -0
  4. data/app/assets/images/effective_assets/icon_close.png +0 -0
  5. data/app/assets/images/effective_assets/s3_down_button.gif +0 -0
  6. data/app/assets/images/effective_assets/s3_over_button.gif +0 -0
  7. data/app/assets/images/effective_assets/s3_up_button.gif +0 -0
  8. data/app/assets/images/effective_assets/s3_upload.swf +0 -0
  9. data/app/assets/images/effective_assets/spinner.gif +0 -0
  10. data/app/assets/images/mime-types/excel.jpg +0 -0
  11. data/app/assets/images/mime-types/file.png +0 -0
  12. data/app/assets/images/mime-types/mp3.png +0 -0
  13. data/app/assets/images/mime-types/pdf.png +0 -0
  14. data/app/assets/images/mime-types/video.png +0 -0
  15. data/app/assets/images/mime-types/word.jpg +0 -0
  16. data/app/assets/images/mime-types/zip.png +0 -0
  17. data/app/assets/javascripts/effective_assets.js +1 -0
  18. data/app/assets/javascripts/effective_assets/asset_box_input.js.coffee +71 -0
  19. data/app/assets/javascripts/effective_assets/asset_box_uploader.js +122 -0
  20. data/app/assets/javascripts/effective_assets/asset_box_uploader_customization.js +166 -0
  21. data/app/assets/javascripts/effective_assets/jquery_ui_sortable.js +2106 -0
  22. data/app/assets/stylesheets/effective_assets.css.scss +1 -0
  23. data/app/assets/stylesheets/effective_assets/_asset_box_input.scss +206 -0
  24. data/app/controllers/effective/attachments_controller.rb +14 -0
  25. data/app/controllers/effective/s3_uploads_controller.rb +98 -0
  26. data/app/helpers/effective_assets_helper.rb +55 -0
  27. data/app/models/concerns/acts_as_asset_box.rb +97 -0
  28. data/app/models/effective/asset.rb +224 -0
  29. data/app/models/effective/attachment.rb +25 -0
  30. data/app/models/effective/delayed_job.rb +99 -0
  31. data/app/models/inputs/asset_box_input.rb +87 -0
  32. data/app/models/validators/asset_box_length_validator.rb +11 -0
  33. data/app/models/validators/asset_box_presence_validator.rb +6 -0
  34. data/app/uploaders/asset_uploader.rb +26 -0
  35. data/app/uploaders/effective_assets_uploader.rb +63 -0
  36. data/app/views/active_admin/effective_assets/_edit.html.haml +35 -0
  37. data/app/views/active_admin/effective_assets/_form.html.haml +4 -0
  38. data/app/views/active_admin/effective_assets/_new.html.haml +3 -0
  39. data/app/views/asset_box_input/_attachment_fields.html.haml +14 -0
  40. data/app/views/asset_box_input/_uploader.html.haml +119 -0
  41. data/app/views/assets/_video.html.erb +4 -0
  42. data/config/routes.rb +6 -0
  43. data/db/migrate/01_create_effective_assets.rb.erb +42 -0
  44. data/lib/effective_assets.rb +31 -0
  45. data/lib/effective_assets/engine.rb +38 -0
  46. data/lib/effective_assets/version.rb +3 -0
  47. data/lib/generators/effective_assets/install_generator.rb +41 -0
  48. data/lib/generators/templates/README +1 -0
  49. data/lib/generators/templates/asset_uploader.rb +25 -0
  50. data/lib/generators/templates/effective_assets.rb +19 -0
  51. data/lib/tasks/effective_assets_tasks.rake +4 -0
  52. data/spec/dummy/README.rdoc +261 -0
  53. data/spec/dummy/Rakefile +7 -0
  54. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  55. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  56. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  57. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  58. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  59. data/spec/dummy/config.ru +4 -0
  60. data/spec/dummy/config/application.rb +65 -0
  61. data/spec/dummy/config/boot.rb +10 -0
  62. data/spec/dummy/config/database.yml +25 -0
  63. data/spec/dummy/config/environment.rb +5 -0
  64. data/spec/dummy/config/environments/development.rb +37 -0
  65. data/spec/dummy/config/environments/production.rb +67 -0
  66. data/spec/dummy/config/environments/test.rb +37 -0
  67. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  68. data/spec/dummy/config/initializers/inflections.rb +15 -0
  69. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  70. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  71. data/spec/dummy/config/initializers/session_store.rb +8 -0
  72. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  73. data/spec/dummy/config/locales/en.yml +5 -0
  74. data/spec/dummy/config/routes.rb +58 -0
  75. data/spec/dummy/db/development.sqlite3 +0 -0
  76. data/spec/dummy/db/schema.rb +16 -0
  77. data/spec/dummy/db/test.sqlite3 +0 -0
  78. data/spec/dummy/log/development.log +71 -0
  79. data/spec/dummy/log/test.log +33 -0
  80. data/spec/dummy/public/404.html +26 -0
  81. data/spec/dummy/public/422.html +26 -0
  82. data/spec/dummy/public/500.html +25 -0
  83. data/spec/dummy/public/favicon.ico +0 -0
  84. data/spec/dummy/script/rails +6 -0
  85. data/spec/dummy/spec_link +3 -0
  86. data/spec/models/asset_spec.rb +46 -0
  87. data/spec/spec_helper.rb +34 -0
  88. data/spec/support/factories.rb +28 -0
  89. metadata +431 -0
@@ -0,0 +1 @@
1
+ @import "effective_assets/asset_box_input";
@@ -0,0 +1,206 @@
1
+ @mixin clearfix {
2
+ display: block;
3
+ &:after { content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden; }
4
+ }
5
+
6
+ @mixin border-radius ($radius) {
7
+ position: relative;
8
+ -webkit-border-radius: $radius;
9
+ -moz-border-radius: $radius;
10
+ -ms-border-radius: $radius;
11
+ -o-border-radius: $radius;
12
+ border-radius: $radius;
13
+ }
14
+
15
+ .asset_box_uploader {
16
+ width: 800px;
17
+ margin: 0px auto;
18
+ text-align: left;
19
+
20
+ .file_lists {
21
+ border: 1px solid #B7B9BB;
22
+ height: 300px;
23
+ margin-bottom: 10px;
24
+ overflow-y: scroll;
25
+ }
26
+
27
+ .file_list {
28
+ border-width: 0 0 1px 0;
29
+ list-style-type: none;
30
+ padding: 0;
31
+ margin: 0;
32
+
33
+ li {
34
+ border: 1px solid #B7B9BB;
35
+ height: 60px;
36
+ line-height: 45px;
37
+ position: relative;
38
+ padding: 0 0 25px 0;
39
+ }
40
+
41
+ .progress {
42
+ display: block;
43
+ height: 85px;
44
+ text-align: right;
45
+ background: #EFEFEF;
46
+ background: -webkit-gradient(linear, left top, left bottom, from(#EFEFEF), to(#DFE1E2));
47
+ background: -moz-linear-gradient(-90deg, #EFEFEF, #DFE1E2);
48
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#efefef, endColorstr=#dfe1e2);
49
+ -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#efefef, endColorstr=#dfe1e2);
50
+
51
+ .amount {
52
+ position: absolute;
53
+ right: 10px;
54
+ top: 15px;
55
+ color: #666;
56
+ text-shadow: 1px 1px #fff;
57
+ }
58
+ }
59
+
60
+ .file_name {
61
+ display: block;
62
+ position: absolute;
63
+ font-weight: bold;
64
+ margin: 0 0 15px 10px;
65
+ }
66
+
67
+ .file_size {
68
+ display: block;
69
+ position: absolute;
70
+ right: 10px;
71
+ bottom: 0;
72
+ line-height: 2;
73
+ color: #AEAEAE;
74
+ }
75
+
76
+ .properties {
77
+ position: absolute;
78
+ left: 10px;
79
+ bottom: 10px;
80
+ display: block;
81
+
82
+ label {
83
+ float: left !important;
84
+ line-height: 2 !important;
85
+ margin-right: 4px !important;
86
+ }
87
+
88
+ input[type="text"] {
89
+ float: left !important;
90
+ margin-right: 30px !important;
91
+ width: 130px !important;
92
+ }
93
+ }
94
+ }
95
+
96
+ .file_todo_list {
97
+ .progress { display: none; }
98
+ }
99
+
100
+ .file_done_list {
101
+ .progress { width: 100%; }
102
+ }
103
+
104
+ .overall {
105
+ border: 1px solid #B7B9BB;
106
+ height: 35px;
107
+ line-height: 35px;
108
+ position: relative;
109
+ font-size: 130%;
110
+ margin-bottom: 10px;
111
+
112
+ .progress {
113
+ display: block;
114
+ height: 35px;
115
+ background: #6A7176;
116
+ background: -webkit-gradient(linear, left top, left bottom, from(#6A7176), to(#4D5256));
117
+ background: -moz-linear-gradient(-90deg, #6A7176, #4D5256);
118
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6a7176, endColorstr=#4d5256);
119
+ -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6a7176, endColorstr=#4d5256);
120
+
121
+ .amount {
122
+ padding-right: 0px;
123
+ color: #eaeaea;
124
+ text-shadow: 1px 1px #333;
125
+ position: absolute;
126
+ right: 10px;
127
+ }
128
+ }
129
+
130
+ .status {
131
+ text-align: center;
132
+ display: block;
133
+ width: 100%;
134
+ font-weight: bold;
135
+ color: #aaa;
136
+ position: absolute;
137
+ }
138
+
139
+ }
140
+
141
+ .progress {
142
+ display: block;
143
+ position: absolute;
144
+ text-align: right;
145
+ }
146
+
147
+ input[type="submit"] {
148
+ margin-left: 0 !important;
149
+
150
+ &.StopButton, &.ResetButton {
151
+ float: right;
152
+ margin-left: 10px !important;
153
+ }
154
+ }
155
+
156
+ label {
157
+ float: none;
158
+ width: auto !important;
159
+ text-align: left;
160
+ margin: 0 !important;
161
+ }
162
+ }
163
+
164
+ .asset-box-attachment {
165
+ position: relative;
166
+ width: 128px;
167
+ float: left;
168
+ margin-right: 20px;
169
+ height: 190px;
170
+
171
+ p.title {
172
+ font-size: 14px;
173
+ color: #818181;
174
+ padding: 10px;
175
+ margin: 0;
176
+ }
177
+ }
178
+
179
+ .asset-box-spinner {
180
+ height: 128px;
181
+ width: 128px;
182
+ background: rgba(255,255,255,0.8) image-url('effective_assets/spinner.gif') no-repeat center center;
183
+ display: block;
184
+ margin-bottom: 6px;
185
+ }
186
+
187
+ .attachments {
188
+ @include clearfix;
189
+ }
190
+
191
+ .file_to_upload .delete, .asset-box-remove {
192
+ @include border-radius(3px);
193
+ display: block;
194
+ position: absolute;
195
+ background: rgba(255,255,255,0.8) image-url('effective_assets/icon_close.png') no-repeat center center;
196
+ text-indent: -99999px !important;
197
+ height: 20px;
198
+ width: 20px;
199
+ right: 10px;
200
+ top: 10px;
201
+ cursor: pointer;
202
+ }
203
+
204
+ .assets {
205
+ clear: both;
206
+ }
@@ -0,0 +1,14 @@
1
+ module Effective
2
+ class AttachmentsController < ApplicationController
3
+ skip_authorize_resource if defined?(CanCan)
4
+ respond_to :json
5
+
6
+ def show
7
+ @asset = Asset.find(params[:id]) # This should actually search Assets
8
+
9
+ EffectiveAssets.authorized?(self, :read, @asset)
10
+
11
+ respond_with @asset
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,98 @@
1
+ require 's3_swf_upload'
2
+ require 'base64'
3
+
4
+ module Effective
5
+ class S3UploadsController < ApplicationController
6
+ skip_authorize_resource if defined?(CanCan)
7
+
8
+ respond_to :js, :xml
9
+
10
+ include S3SwfUpload::Signature
11
+
12
+ def index
13
+ # This is actually a 'new' action. Not an index. The s3 flash uploader is hardcoded to check this url as an xml request
14
+
15
+ EffectiveAssets.authorized?(self, :create, Effective::Asset)
16
+
17
+ bucket = EffectiveAssets.aws_bucket
18
+ access_key_id = EffectiveAssets.aws_access_key_id
19
+ acl = EffectiveAssets.aws_acl
20
+ secret_key = EffectiveAssets.aws_secret_access_key
21
+ key = params[:key]
22
+ content_type = params[:content_type]
23
+ https = 'false'
24
+ error_message = ''
25
+ expiration_date = 1.hours.from_now.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z')
26
+
27
+ policy = Base64.encode64(
28
+ "{
29
+ 'expiration': '#{expiration_date}',
30
+ 'conditions': [
31
+ {'bucket': '#{bucket}'},
32
+ {'key': '#{key}'},
33
+ {'acl': '#{acl}'},
34
+ {'Content-Type': '#{content_type}'},
35
+ {'Content-Disposition': 'attachment'},
36
+ ['starts-with', '$Filename', ''],
37
+ ['eq', '$success_action_status', '201']
38
+ ]
39
+ }").gsub(/\n|\r/, '')
40
+
41
+ signature = b64_hmac_sha1(secret_key, policy)
42
+
43
+ respond_to do |format|
44
+ format.xml {
45
+ render :xml => {
46
+ :policy => policy,
47
+ :signature => signature,
48
+ :bucket => bucket,
49
+ :accesskeyid => access_key_id,
50
+ :acl => acl,
51
+ :expirationdate => expiration_date,
52
+ :https => https,
53
+ :errorMessage => error_message.to_s,
54
+ }.to_xml
55
+ }
56
+ end
57
+ end
58
+
59
+ def create
60
+ EffectiveAssets.authorized?(self, :create, Effective::Asset)
61
+
62
+ # If we're passed Asset information, then create an Asset
63
+ if params[:file_path].present?
64
+ asset = Asset.create_from_s3_uploader(params[:file_path],
65
+ {
66
+ :title => params[:title],
67
+ :description => params[:description],
68
+ :tags => params[:tags],
69
+ :content_type => params[:content_type],
70
+ :data_size => params[:file_size],
71
+ :user_id => current_user.try(:id)
72
+ }
73
+ )
74
+ else
75
+ asset = (Asset.find(params[:asset_id].to_i) rescue false)
76
+ end
77
+
78
+ unless asset
79
+ render :text => '', :status => :unprocessable_entity
80
+ return
81
+ end
82
+
83
+ # If the attachment information is present, then our input needs some attachment HTML
84
+ if params.key?(:attachable_type)
85
+ attachment = Attachment.new
86
+ attachment.attachable_type = params[:attachable_type].try(:classify)
87
+ attachment.attachable_id = params[:attachable_id].try(:to_i) if params[:attachable_id].present? # attachable_id can be nil if we're on a New action
88
+ attachment.asset_id = asset.try(:id)
89
+ attachment.box = params[:box]
90
+ attachment.position = 0
91
+
92
+ render :partial => 'asset_box_input/attachment_fields', :locals => {:attachment => attachment}, :status => 200, :content_type => 'text/html'
93
+ else
94
+ render :text => '', :status => 200
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,55 @@
1
+ module EffectiveAssetsHelper
2
+ # Generates an image tag based on the particular asset
3
+ def effective_asset_image_tag(asset, version = nil, options = {})
4
+ if asset.image? == false
5
+ opts = {}
6
+ elsif version.present? and asset.versions_info[version].present?
7
+ opts = { :height => asset.versions_info[version][:height], :width => asset.versions_info[version][:width] }
8
+ elsif version.present? and asset.data.respond_to?(:versions_info) and asset.data.versions_info[version].present?
9
+ opts = { :height => asset.data.versions_info[version][:height], :width => asset.data.versions_info[version][:width] }
10
+ elsif asset.height.present? and asset.width.present?
11
+ opts = { :height => asset.height, :width => asset.width }
12
+ else
13
+ opts = {}
14
+ end
15
+
16
+ opts = opts.merge({:alt => asset.description || asset.title || asset.file_name}).merge(options)
17
+ image_tag(_effective_asset_image_url(asset, version), opts).gsub('"', "'").html_safe # we need all ' quotes or it breaks Insert as functionality
18
+ end
19
+
20
+ def effective_asset_link_to(asset, version = nil, options = {})
21
+ link_title = asset.title || asset.file_name || asset.description || "Asset ##{asset.id}"
22
+
23
+ link_to(link_title, asset.url).gsub('"', "'").html_safe # we need all ' quotes or it breaks Insert as functionality
24
+ end
25
+
26
+ def effective_asset_video_tag(asset)
27
+ render(:partial => 'assets/video', :locals => { :asset => asset }).gsub('"', "'").html_safe # we need all ' quotes or it breaks Insert as functionality
28
+ end
29
+
30
+ def _effective_asset_image_url(asset, version = nil)
31
+ return '/assets/mime-types/file.png' if !asset.content_type.present? or asset.content_type == 'unknown'
32
+
33
+ if asset.icon?
34
+ asset.url
35
+ elsif asset.image?
36
+ (version == nil or asset.still_processing?) ? asset.url : asset.url.insert(asset.url.rindex('/')+1, "#{version.to_s}_")
37
+ elsif asset.audio?
38
+ '/assets/mime-types/mp3.png'
39
+ elsif asset.video?
40
+ '/assets/mime-types/video.png'
41
+ elsif asset.content_type.include? 'msword'
42
+ '/assets/mime-types/word.jpg'
43
+ elsif asset.content_type.include? 'excel'
44
+ '/assets/mime-types/excel.jpg'
45
+ elsif asset.content_type.include? 'application/pdf'
46
+ '/assets/mime-types/pdf.png'
47
+ elsif asset.content_type.include? 'application/zip'
48
+ '/assets/mime-types/zip.png'
49
+ else
50
+ '/assets/mime-types/file.png'
51
+ end
52
+ end
53
+
54
+
55
+ end
@@ -0,0 +1,97 @@
1
+ # ActsAsAssetBox
2
+ #
3
+ # Returns a set of assets or one asset as defined by the provided 'boxes' (a box is just a category) array
4
+ # Works with Formtastic::Inputs::asset_box_input
5
+ #
6
+ # Define your model with 'acts_as_asset_box' if you just need one box of assets
7
+ # You will then be able to call @my_resource.assets and @my_resource.asset
8
+ #
9
+ # or
10
+ #
11
+ # acts_as_asset_box :fav_icon, :pictures, :logos
12
+ #
13
+ # or (if you want validations)
14
+ #
15
+ # acts_as_asset_box :fav_icon => true, :pictures => false, :videos => 2, :images => 5..10
16
+ #
17
+ # Define your model with 'acts_as_asset_box :fav_icon, :pictures, :logos' for 3 different boxes of assets.
18
+ # This creates three methods, @my_resource.fav_icon, @my_resource.pictures, @my_resource.logos
19
+ #
20
+ # If you define a singular name, like :fav_icon, then calling @my_resource.fav_icon will return the 1 asset from the fav_icon box
21
+ # If you define a plural name, like :pictures, then calling @my_resource.pictures will return all assets in the pictures box
22
+ #
23
+ # This works with the lib/acts_as_asset_box_input.rb for editting boxes of assets
24
+ #
25
+
26
+ module ActsAsAssetBox
27
+ extend ActiveSupport::Concern
28
+
29
+ module ActiveRecord
30
+ def acts_as_asset_box(*options)
31
+ @acts_as_asset_box_opts = options || []
32
+ include ::ActsAsAssetBox
33
+ end
34
+ end
35
+
36
+ included do
37
+ has_many :attachments, :as => :attachable, :class_name => "Effective::Attachment", :dependent => :delete_all
38
+ has_many :assets, :through => :attachments, :class_name => "Effective::Asset"
39
+
40
+ #attr_accessible :attachments_attributes
41
+ accepts_nested_attributes_for :attachments, :reject_if => :all_blank, :allow_destroy => true
42
+
43
+ # Setup validations
44
+ boxes = @acts_as_asset_box_opts.try(:flatten) || []
45
+ if boxes.first.kind_of?(Hash) # We were passed some validation requirements
46
+ boxes = boxes.first
47
+
48
+ @@acts_as_asset_box_boxes = boxes.keys
49
+
50
+ boxes.each do |box, validation|
51
+ if validation == true
52
+ validates box, :asset_box_presence => true
53
+ elsif validation.kind_of?(Integer) or validation.kind_of?(Range)
54
+ validates box, :asset_box_length => validation
55
+ end
56
+ end
57
+ else
58
+ @@acts_as_asset_box_boxes = boxes
59
+ end
60
+
61
+ class_eval do
62
+ def attachments_attributes=(atts)
63
+ current_box = ''; position = 0
64
+
65
+ atts.each do |k, v|
66
+ (current_box = v['box'] and position = 0) if v['box'] != current_box
67
+ atts[k]['position'] = (position += 1) if atts[k]['_destroy'] != '1'
68
+ end
69
+
70
+ assign_nested_attributes_for_collection_association(:attachments, atts, {})
71
+ end
72
+ end
73
+ end
74
+
75
+ module ClassMethods
76
+ end
77
+
78
+ def assets(box = nil)
79
+ box = (box.present? ? box.to_s : 'assets')
80
+
81
+ if box == box.pluralize
82
+ attachments.select { |attachment| attachment.box == box }.map { |attachment| attachment.asset }
83
+ else
84
+ attachments.to_a.find { |attachment| attachment.box == box.pluralize }.try(:asset)
85
+ end
86
+ end
87
+
88
+ def asset
89
+ assets(:asset)
90
+ end
91
+
92
+ # This handles all the boxes type function calls
93
+ def method_missing(method_name, *args, &block)
94
+ (@@acts_as_asset_box_boxes || []).include?(method_name.to_sym) ? assets(method_name) : super
95
+ end
96
+ end
97
+