caboose-cms 0.4.71 → 0.4.72

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MzFjYWNhODVkZjAxODY3NDM0ZTE0YzE4ZTlkYWM2NzkxYmZkNzc2Nw==
4
+ OWQ2YWNkYzI0MTBjZjI1ZmYyNDRhYTE4NGE5ODA4ZDQ0MWRiMDBlMQ==
5
5
  data.tar.gz: !binary |-
6
- MDk2YWUzODMyN2U0YWM0ZTRmMjExYzUzNDQ2MzliODYxYzc1ZjJmMw==
6
+ YWM0MWU1NTc0ZjE4NWIyNTA3NTI2ZDJlNjhlY2U3N2NjZWQ1ZmExOQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- MDM1MWZkYzI2ZDIxOTlkNTIyMWYyYTlhOTQ5MTQ1MDAwMDg0NGQ0MTEwMTQx
10
- MDBjZGI4NzA1Y2UzYjYwOGVhOTNkOWViZWY1Zjg0Yjc5YTg4ZGI2YmQ4ZDBj
11
- YjIxODNmMGVmYmQ0NmQ0Y2M3NDRlNThjZTdmMDU2MmRkNzhjNDc=
9
+ NWQyNGIzYTJhNThmYjRiM2M0ZjQ0NjA3ZDU1ZGNiOTRlNzYyYzk2YWNjYTM4
10
+ OGUxMzc2N2Q2ODVkOGViNjg0NjJkZjJmOTE5Yjk2MjJhZjQ5YjI5MTk1MDFm
11
+ ZGRkMzE4YzJjY2U1MTY2ZmVmOWM3NjRmNmMyMWQwNjdiNjMxMzI=
12
12
  data.tar.gz: !binary |-
13
- OTVhOGZjMDhkNjMxNjM1NzFlNWMzZjhhN2ZmYWYxYzU1OWNhNGY2YzkxZGFh
14
- NWNiZGUzOWM0YzFkODdhMjY0NmE0ZDhiMDcwMTYyYzlmMGZhMGY2OGZkYWMw
15
- YTY1NjFkYTJlYzJiMTI5ZWViYTQ5NWM4MGY3ZDVkMDFmNzgxYWQ=
13
+ Yzk3NjQyZTQxZTAxNTM2OTBlMTA0MGQzYjFmZmIxZDhlMDkwNzYzOWNmYTM5
14
+ MTE2OWNkNjVkOTcyYmEwYzM4MDcwNWFmMzMwNmQxZDNjNDZmYTU2ZDg3N2Fi
15
+ MjZkMDRiNWI1Njk1ODE3ZDViMjAwZDczYWZhYmM5NjE0YmYwNzQ=
@@ -0,0 +1,168 @@
1
+
2
+ var ImagesController = function(params) { this.init(params); };
3
+
4
+ ImagesController.prototype = {
5
+
6
+ cat_id: false,
7
+ cat: false,
8
+
9
+ init: function(params) {
10
+ var that = this;
11
+ for (var i in params)
12
+ this[i] = params[i];
13
+
14
+ $('#new_cat_link').click(function(e) {
15
+ e.preventDefault();
16
+ that.add_category(that.cat_id);
17
+ });
18
+
19
+ this.print_images();
20
+ },
21
+
22
+ // Gets updated image info from server and prints out categories and images.
23
+ print_images: function() {
24
+ var that = this;
25
+ $('#message').html("<p class='loading'>Refreshing images...</p>");
26
+ $.ajax({
27
+ url: '/admin/images/json',
28
+ type: 'get',
29
+ async: false,
30
+ data: { media_category_id: this.cat_id },
31
+ success: function(resp) {
32
+ that.cat = resp;
33
+ }
34
+ });
35
+ $('#message').empty();
36
+ var ul = $('#media');
37
+ if (this.cat.children.length > 0 || this.cat.images.count > 0)
38
+ {
39
+ $.each(this.cat.children, function(i, cat2) {
40
+ ul.append($('<li/>').addClass('category').attr('id', 'cat' + cat2.id)
41
+ .append($('<a/>').attr('href', '/admin/images?media_category_id=' + cat2.id)
42
+ .append($('<span/>').addClass('icon icon-folder2'))
43
+ .append($('<span/>').addClass('name').html(cat2.name))
44
+ )
45
+ );
46
+ });
47
+ $.each(this.cat.images, function(i, mi) {
48
+ ul.append($('<li/>').addClass('image').attr('id', 'image' + mi.id)
49
+ .append($('<a/>').attr('href', '/admin/images/' + mi.id)
50
+ .css('background-image', mi.tiny_url)
51
+ .append($('<span/>').addClass('name').html(mi.name))
52
+ )
53
+ );
54
+ });
55
+ }
56
+ ul.replaceWith($('<p/>').html("This category is empty."));
57
+ },
58
+
59
+ // Adds a new media category
60
+ add_category: function(parent_id, name)
61
+ {
62
+ var that = this;
63
+ if (!name)
64
+ {
65
+ var div = $('<p/>').addClass('note warning')
66
+ .append('New Category Name: ')
67
+ .append($('<input/>').attr('type', 'text').attr('id', 'new_cat_name')).append(" ")
68
+ .append($('<input/>').attr('type', 'button').val('Add').click(function() { that.add_category(parent_id, $('#new_cat_name').val()); })).append(" ")
69
+ .append($('<input/>').attr('type', 'button').val('Cancel').click(function() { $('#new_cat_message').empty(); }));
70
+ $('#new_cat_message').empty().append(div);
71
+ return;
72
+ }
73
+ $('#new_cat_message').empty().html("<p class='loading'>Adding category...</p>");
74
+ $.ajax({
75
+ url: '/admin/media-categories',
76
+ type: 'post',
77
+ data: {
78
+ parent_id: parent_id,
79
+ name: name
80
+ },
81
+ success: function(resp) {
82
+ if (resp.error) $('#new_cat_message').empty().html("<p class='note error'>" + resp.error + "</p>");
83
+ if (resp.refresh) window.location.reload(true);
84
+ }
85
+ });
86
+ },
87
+
88
+ // Lets a single image poll the server to see if it has been processed.
89
+ wait_for_image_processing: function(image_id, i)
90
+ {
91
+ if (!i) i = 1;
92
+ var is_finished = false;
93
+ $.ajax({
94
+ url: '/admin/images/' + image_id + '/finished',
95
+ type: 'get',
96
+ async: false,
97
+ success: function(resp) {
98
+ if (resp.error) alert("Error processing image: \n" + resp.error);
99
+ if (resp.is_finished)
100
+ {
101
+ is_finished = true;
102
+ $('#image' + mi.id + ' a').css('background-image', resp.tiny_url);
103
+ }
104
+ }
105
+ });
106
+ if (!is_finished)
107
+ setTimeout(function() { that.wait_for_image_processing(image_id, i+1); }, 500);
108
+ },
109
+
110
+ upload_form: function()
111
+ {
112
+ var that = this;
113
+ $('#file').fileupload({
114
+ //forceIframeTransport: true,
115
+ autoUpload: true,
116
+ //replaceFileInput: true,
117
+ //singleFileUploads: false,
118
+ add: function(e, data) {
119
+ $.ajax({
120
+ url: '/admin/images/s3',
121
+ type: 'get',
122
+ data: {
123
+ name: data.files[0].name,
124
+ media_category_id: that.cat_id
125
+ },
126
+ async: false,
127
+ success: function(resp) {
128
+ image_ids.push(resp.media_image_id);
129
+ var form = $('#new_image_form');
130
+ for (var i in resp.fields)
131
+ form.find("input[name=" + i + "]").val(resp.fields[i]);
132
+ form.attr('action', resp.url);
133
+ }
134
+ });
135
+ data.submit();
136
+ },
137
+ progressall: function (e, data) {
138
+ $('#bar').css('width', parseInt(data.loaded / data.total * 100, 10) + '%')
139
+ },
140
+ start: function (e) {
141
+ $('#file').hide();
142
+ $('#bar').css('background', 'green').css('display', 'block').css('width', '0%').html("&nbsp;");
143
+ },
144
+ done: function(e, data) {
145
+ console.log("Upload done.");
146
+ console.log(data);
147
+ setTimeout(function() {
148
+ $.each(image_ids, function(i, id) {
149
+ $.ajax({
150
+ url: '/admin/images/' + id + '/process',
151
+ type: 'get',
152
+ async: false,
153
+ success: function(resp) {}
154
+ });
155
+ });
156
+ $('#progress').empty().html("<p class='loading'>Upload complete. Processing images...</p>");
157
+ that.wait_for_image_processing(id);
158
+
159
+ }, 500);
160
+ },
161
+ fail: function(e, data) {
162
+ console.log("Upload failed.");
163
+ console.log(data);
164
+ $('#bar').css("background", "red").text("Failed");
165
+ }
166
+ });
167
+ }
168
+ };
@@ -0,0 +1,33 @@
1
+
2
+ ul.media { list-style: none; margin: 0; padding: 0; }
3
+ ul.media li { list-style: none; margin: 4px; padding: 0; float: left; }
4
+ ul.media a {
5
+ display: block;
6
+ width: 150px;
7
+ height: 150px;
8
+ overflow: hidden;
9
+ border: #666 4px solid;
10
+ background-size: contain;
11
+ background-repeat: no-repeat;
12
+ background-position: center;
13
+ background-color: #666;
14
+ position: relative;
15
+ text-align: center;
16
+ }
17
+ ul.media a:hover {
18
+ background-color: #fff69f;
19
+ border-color: #fff69f;
20
+ }
21
+ ul.media li a span { color: #fff; text-decoration: none; }
22
+ ul.media li a:hover span { background: #efefef; color: #000; }
23
+ ul.media li a span.name { display: block; background: #666; color: #fff; text-decoration: none !important; border: 0; }
24
+ ul.media li a:hover span.name { background: #fff69f; color: #000; }
25
+
26
+ ul.media li a.selected span,
27
+ ul.media li a.selected:hover span { background: #fff69f; color: #000; border: #fff69f 1px solid; }
28
+
29
+ ul.media li.category a span.icon { display: block; padding: 10px 20px; font-size: 24pt; color: #fff; }
30
+ ul.media li.category a:hover span.icon { background: #fff69f; color: #000; }
31
+
32
+ .progress { max-width: 600px; margin: 0.2em 0 0.2em 0; }
33
+ .progress .bar { height: 1.2em; padding: 0.2em; color: white; display: none; }
@@ -16,7 +16,7 @@
16
16
 
17
17
  .mb_container input.mb_dirty,
18
18
  .mb_container textarea.mb_dirty {
19
- background: #4D0101;
19
+ background: #fff799;
20
20
  }
21
21
 
22
22
  .mb_container select.mb_fake {
@@ -10,11 +10,23 @@ module Caboose
10
10
 
11
11
  # GET /admin/images
12
12
  def admin_index
13
- return if !user_is_allowed('images', 'view')
14
- @domain = Domain.where(:domain => request.host_with_port).first
15
- @media_category = @domain ? MediaCategory.top_image_category(@domain.site_id) : nil
13
+ return if !user_is_allowed('images', 'view')
14
+ render :file => 'caboose/extras/error_invalid_site' and return if @site.nil?
15
+
16
+ id = params[:media_category_id]
17
+ @media_category = id ? MediaCategory.find(id) : MediaCategory.top_image_category(@site.id)
16
18
  render :layout => 'caboose/admin'
17
19
  end
20
+
21
+ # GET /admin/images/json
22
+ def admin_json
23
+ return if !user_is_allowed('images', 'view')
24
+ render :json => false and return if @site.nil?
25
+
26
+ id = params[:media_category_id]
27
+ cat = id ? MediaCategory.find(id) : MediaCategory.top_image_category(@site.id)
28
+ render :json => cat.api_hash
29
+ end
18
30
 
19
31
  # GET /admin/images/new
20
32
  def admin_new
@@ -26,252 +38,39 @@ module Caboose
26
38
  # GET /admin/images/:id
27
39
  def admin_edit
28
40
  return unless user_is_allowed('images', 'edit')
29
- @page = Page.find(params[:id])
41
+ @media_image = MediaImage.find(params[:id])
30
42
  render :layout => 'caboose/admin'
31
43
  end
32
-
33
- # POST /admin/images
34
- def admin_add
35
- return unless user_is_allowed('images', 'add')
36
-
37
- resp = Caboose::StdClass.new({
38
- 'error' => nil,
39
- 'redirect' => nil
40
- })
41
44
 
42
- parent_id = params[:parent_id]
43
- title = params[:title]
44
-
45
- if (title.strip.length == 0)
46
- resp.error = "A page title is required."
47
- elsif (!logged_in_user.is_allowed('all', 'all') &&
48
- !Page.page_ids_with_permission(logged_in_user, 'edit' ).include?(parent_id) &&
49
- !Page.page_ids_with_permission(logged_in_user, 'approve').include?(parent_id))
50
- resp.error = "You don't have permission to add a page there."
51
- end
52
- if (!resp.error.nil?)
53
- render :json => resp
54
- return
55
- end
56
-
57
- parent = Caboose::Page.find(parent_id)
58
- page = Caboose::Page.new
59
-
60
- if parent.nil?
61
- d = Domain.where(:domain => request.host_with_port).first.site_id
62
- page.site_id = d.site_id
63
- else
64
- page.site_id = parent.site_id
65
- end
66
-
67
- page.title = title
68
- page.parent_id = parent_id
69
- page.hide = true
70
- page.content_format = Caboose::Page::CONTENT_FORMAT_HTML
71
-
72
- i = 0
73
- begin
74
- page.slug = Page.slug(page.title + (i > 0 ? " #{i}" : ""))
75
- page.uri = parent.parent_id == -1 ? page.slug : "#{parent.uri}/#{page.slug}"
76
- i = i+1
77
- end while (Page.where(:uri => page.uri).count > 0 && i < 10)
78
-
79
- page.save
80
-
81
- # Create the top level block for the page
82
- bt = BlockType.find(params[:block_type_id])
83
- Block.create(:page_id => page.id, :block_type_id => params[:block_type_id], :name => bt.name)
84
-
85
- # Set the new page's permissions
86
- viewers = Caboose::PagePermission.where({ :page_id => parent.id, :action => 'view' }).pluck(:role_id)
87
- editors = Caboose::PagePermission.where({ :page_id => parent.id, :action => 'edit' }).pluck(:role_id)
88
- Caboose::Page.update_authorized_for_action(page.id, 'view', viewers)
89
- Caboose::Page.update_authorized_for_action(page.id, 'edit', editors)
90
-
91
- # Send back the response
92
- resp.redirect = "/admin/images/#{page.id}/edit"
93
- render json: resp
94
- end
95
-
96
45
  # PUT /admin/images/:id
97
46
  def admin_update
98
47
  return unless user_is_allowed('images', 'edit')
99
48
 
100
49
  resp = StdClass.new({'attributes' => {}})
101
- page = Page.find(params[:id])
50
+ image = MediaImage.find(params[:id])
102
51
 
103
- save = true
104
- user = logged_in_user
52
+ save = true
105
53
  params.each do |name, value|
106
54
  case name
107
- when 'parent_id'
108
- value = value.to_i
109
- if page.id == value
110
- resp.error = "The page's parent cannot be itself."
111
- elsif Page.is_child(page.id, value)
112
- resp.error = "You can't set the current page's parent to be one of its child pages."
113
- elsif value != page.parent_id
114
- p = Page.find(value)
115
- if !user.is_allowed(p, 'edit')
116
- resp.error = "You don't have access to put the current page there."
117
- end
118
- end
119
- if resp.error
120
- save = false
121
- else
122
- page.parent = Page.find(value)
123
- page.save
124
- Page.update_uri(page)
125
- resp.attributes['parent_id'] = { 'text' => page.parent.title }
126
- end
127
-
128
- when 'custom_css', 'custom_js'
129
- value.strip!
130
- page[name.to_sym] = value
131
-
132
- when 'title', 'menu_title', 'hide', 'layout', 'redirect_url',
133
- 'seo_title', 'meta_description', 'fb_description', 'gp_description', 'canonical_url'
134
- page[name.to_sym] = value
135
-
136
- when 'linked_resources'
137
- result = []
138
- value.each_line do |line|
139
- line.chomp!
140
- line.strip!
141
- next if line.empty?
142
-
143
- if !(line.ends_with('.js') || line.ends_with('.css'))
144
- resp.error = "Resource '#{line}' has an unsupported file type ('#{comps.last}')."
145
- save = false
146
- end
147
-
148
- result << line
149
- end
150
- page.linked_resources = result.join("\n")
151
-
152
- when 'content_format'
153
- page.content_format = value
154
- resp.attributes['content_format'] = { 'text' => value }
155
-
156
- when 'meta_robots'
157
- if (value.include?('index') && value.include?('noindex'))
158
- resp.error = "You can't have both index and noindex"
159
- save = false
160
- elsif (value.include?('follow') && value.include?('nofollow'))
161
- resp.error = "You can't have both follow and nofollow"
162
- save = false
163
- else
164
- page.meta_robots = value.join(', ')
165
- resp.attributes['meta_robots'] = { 'text' => page.meta_robots }
166
- end
167
-
168
- when 'content'
169
- page.content = value.strip.gsub(/<meta.*?>/, '').gsub(/<link.*?>/, '').gsub(/\<\!--[\S\s]*?--\>/, '')
170
-
171
- when 'slug'
172
- page.slug = Page.slug(value.strip.length > 0 ? value : page.title)
173
- page.save
174
- Page.update_uri(page)
175
- resp.attributes['slug'] = { 'value' => page.slug }
176
- resp.attributes['uri'] = { 'value' => page.uri }
177
-
178
- when 'alias'
179
- page.alias = Page.slug(value.strip)
180
- page.save
181
- Page.update_uri(page)
182
- resp.attributes['slug'] = { 'value' => page.slug }
183
- resp.attributes['uri'] = { 'value' => page.uri }
184
-
185
- when 'custom_sort_children'
186
- if (value == 0)
187
- page.children.each do |p|
188
- p.sort_order = 1
189
- p.save
190
- end
191
- end
192
- page.custom_sort_children = value
193
-
194
- when 'viewers'
195
- Page.update_authorized_for_action(page.id, 'view', value)
196
- when 'editors'
197
- Page.update_authorized_for_action(page.id, 'edit', value)
198
- when 'approvers'
199
- Page.update_authorized_for_action(page.id, 'approve', value)
55
+ when 'name' then image.name = value
56
+ when 'description' then image.description = value
200
57
  end
201
58
  end
202
59
 
203
- resp.success = save && page.save
204
- render json: resp
60
+ resp.success = save && image.save
61
+ render :json => resp
205
62
  end
206
63
 
207
- # DELETE /admin/images/1
64
+ # DELETE /admin/images/:id
208
65
  def admin_delete
209
66
  return unless user_is_allowed('images', 'delete')
210
- p = Page.find(params[:id])
211
- p.destroy
212
-
67
+ img = MediaImage.find(params[:id])
213
68
  resp = StdClass.new({
214
- 'redirect' => '/admin/images'
69
+ 'redirect' => "/admin/images?media_category_id=#{img.media_category_id}"
215
70
  })
216
- render json: resp
71
+ img.destroy
72
+ render :json => resp
217
73
  end
218
-
219
- ## PUT /admin/images/sign-s3
220
- #def admin_sign_s3
221
- # return unless user_is_allowed('images', 'add')
222
- #
223
- # config = YAML.load(File.read(Rails.root.join('config', 'aws.yml')))[Rails.env]
224
- # access_key = config['access_key_id']
225
- # secret_key = config['secret_access_key']
226
- # bucket = config['bucket']
227
- # s3 = AWS::S3.new(
228
- # :access_key_id => access_key,
229
- # :secret_access_key => secret_key
230
- # )
231
- #
232
- # name = params[:name]
233
- # mi = MediaImage.create(
234
- # :media_category_id => params[:media_category_id],
235
- # :name => params[:name]
236
- # )
237
- # pp = s3.buckets[bucket].presigned_post(
238
- # :key => "media-images/test.jpg", #{mi.id}.#{File.extname(name)}",
239
- # :expires => DateTime.now + 10.seconds,
240
- # :success_action_status => 201,
241
- # :acl => :public_read
242
- # )
243
- #
244
- # render :json => {
245
- # 'media_image' => mi,
246
- # 'presigned_post' => {
247
- # 'url' => pp.url.to_s,
248
- # 'fields' => pp.fields
249
- # }
250
- # }
251
- #
252
- # #expires = (DateTime.now.utc + 10.seconds).to_i
253
- # #amz_headers = "x-amz-acl:public-read"
254
- # #put_request = "PUT\n\n#{mime_type}\n#{expires}\n#{amz_headers}\n/#{bucket}/media-images/#{object_name}"
255
- # #signature = CGI.escape(Base64.encode64("#{OpenSSL::HMAC.digest('sha1', secret_key, put_request)}\n"))
256
- # ##signature = base64.encodestring(hmac.new(secret_key, put_request, sha1).digest())
257
- # ##signature = urllib.quote_plus(signature.strip())
258
- # #render :json => {
259
- # # 'signed_request' => "#{url}?AWSAccessKeyId=#{access_key}&Expires=#{expires}&Signature=#{signature}",
260
- # # 'url' => url
261
- # #}
262
- #
263
- # #pp = AWS::S3::PresignedPost.new(s3.buckets[bucket],
264
- # # :key => "media-images/#{object_name}",
265
- # # :expires => DateTime.now + 10.seconds,
266
- # # :content_type => mime_type
267
- # #)
268
- # #url = "#{pp.url.to_s}#{pp.key}" #"https://#{pp.bucket.name}.s3.amazonaws.com/#{pp.key}"
269
- # #render :json => {
270
- # # 'signed_request' => "#{url}?AWSAccessKeyId=#{access_key}&Expires=#{pp.expires.to_time.to_i}&Signature=#{pp.fields[:signature]}",
271
- # # 'url' => url
272
- # #}
273
- #
274
- #end
275
74
 
276
75
  # GET /admin/images/sign-s3
277
76
  def admin_sign_s3
@@ -291,7 +90,7 @@ module Caboose
291
90
  policy = {
292
91
  "expiration" => 10.seconds.from_now.utc.xmlschema,
293
92
  "conditions" => [
294
- { "bucket" => 'cabooseit' },
93
+ { "bucket" => bucket },
295
94
  ["starts-with", "$key", key],
296
95
  { "acl" => "public-read" },
297
96
  { "success_action_status" => "200" }
@@ -324,10 +123,27 @@ module Caboose
324
123
  # GET /admin/images/:id/process
325
124
  def admin_process
326
125
  return if !user_is_allowed('images', 'edit')
327
- mi = MediaImage.find(params[:id])
126
+ mi = MediaImage.find(params[:id])
328
127
  mi.delay.process
329
128
  render :json => true
330
129
  end
130
+
131
+ ## GET /admin/images/:id/finished
132
+ def admin_process_finished
133
+ return if !user_is_allowed('images', 'edit')
134
+ mi = MediaImage.find(params[:id])
135
+ resp = StdClass.new
136
+ if mi.image_file_name && mi.image_file_name.strip.length > 0
137
+ resp.is_finished = true
138
+ resp.tiny_url = mi.image.url(:tiny)
139
+ resp.thumb_url = mi.image.url(:thumb)
140
+ resp.large_url = mi.image.url(:large)
141
+ resp.original_url = mi.image.url(:original)
142
+ else
143
+ resp.is_finished = false
144
+ end
145
+ render :json => resp
146
+ end
331
147
 
332
148
  end
333
149
  end
@@ -39,7 +39,7 @@ module Caboose
39
39
  login_user(login_resp.user, remember)
40
40
  resp.redirect = return_url
41
41
  resp.modal = false
42
- Caboose.plugin_hook('login_success')
42
+ Caboose.plugin_hook('login_success', user_id)
43
43
  end
44
44
  end
45
45
  end
@@ -2,6 +2,8 @@ module Caboose
2
2
  class LogoutController < ApplicationController
3
3
  # GET /logout
4
4
  def index
5
+ Caboose.plugin_hook('before_logout')
6
+
5
7
  logout_user
6
8
  elo = User.find(User::LOGGED_OUT_USER_ID)
7
9
  login_user(elo)
@@ -0,0 +1,56 @@
1
+
2
+ module Caboose
3
+ class MediaCategoriesController < ApplicationController
4
+
5
+ # POST /admin/media-categories
6
+ def admin_add
7
+ return unless user_is_allowed('mediacategories', 'add')
8
+
9
+ resp = Caboose::StdClass.new
10
+
11
+ cat = MediaCategory.new(
12
+ :site_id => @site.id,
13
+ :parent_id => params[:parent_id],
14
+ :name => params[:name]
15
+ )
16
+ if !cat.save
17
+ resp.error = cat.errors.first[1]
18
+ else
19
+ resp.refresh = true
20
+ end
21
+
22
+ render :json => resp
23
+ end
24
+
25
+ # PUT /admin/media-categories/:id
26
+ def admin_update
27
+ return unless user_is_allowed('mediacategories', 'edit')
28
+
29
+ resp = StdClass.new
30
+ cat = MediaCategory.find(params[:id])
31
+
32
+ save = true
33
+ params.each do |name, value|
34
+ case name
35
+ when 'name' then cat.name = value
36
+ end
37
+ end
38
+
39
+ resp.success = save && cat.save
40
+ render :json => resp
41
+ end
42
+
43
+ # DELETE /admin/media-categories/:id
44
+ def admin_delete
45
+ return unless user_is_allowed('mediacategories', 'delete')
46
+ cat = MediaCategory.find(params[:id])
47
+ cat.destroy
48
+
49
+ resp = StdClass.new({
50
+ 'redirect' => '/admin/media-categories'
51
+ })
52
+ render :json => resp
53
+ end
54
+
55
+ end
56
+ end
@@ -14,5 +14,17 @@ class Caboose::MediaCategory < ActiveRecord::Base
14
14
  def self.top_file_category(site_id)
15
15
  return self.where("parent_id is null and site_id = ? and name = ?", site_id, 'Files').first
16
16
  end
17
+
18
+ def api_hash
19
+ {
20
+ :id => self.id,
21
+ :parent_id => self.parent_id,
22
+ :site_id => self.site_id,
23
+ :name => self.name,
24
+ :children => self.children.collect { |child| child.api_hash },
25
+ :images => self.media_images.collect { |img| img.api_hash },
26
+ :files => self.media_files.collect { |file| file.api_hash }
27
+ }
28
+ end
17
29
 
18
30
  end
@@ -5,5 +5,14 @@ class Caboose::MediaFile < ActiveRecord::Base
5
5
  has_attached_file :file, :path => 'media-files/:id.:extension'
6
6
  do_not_validate_attachment_file_type :file
7
7
  attr_accessible :id, :media_category_id, :name, :description
8
+
9
+ def api_hash
10
+ {
11
+ :id => self.id,
12
+ :name => self.name,
13
+ :description => self.description,
14
+ :url => self.file.url
15
+ }
16
+ end
8
17
 
9
18
  end
@@ -1,4 +1,5 @@
1
1
  require 'uri'
2
+ require 'httparty'
2
3
 
3
4
  class Caboose::MediaImage < ActiveRecord::Base
4
5
 
@@ -16,9 +17,27 @@ class Caboose::MediaImage < ActiveRecord::Base
16
17
  attr_accessible :id, :media_category_id, :name, :description
17
18
 
18
19
  def process
19
- puts "http://#{Caboose::cdn_domain}/media-images/#{self.id}#{File.extname(self.name.downcase)}"
20
- self.image = URI.parse("http://#{Caboose::cdn_domain}/media-images/#{self.id}#{File.extname(self.name.downcase)}")
21
- self.save
20
+
21
+ config = YAML.load(File.read(Rails.root.join('config', 'aws.yml')))[Rails.env]
22
+ bucket = config['bucket']
23
+
24
+ uri = "http://#{bucket}.s3.amazonaws.com/media-images/#{self.id}#{File.extname(self.name.downcase)}"
25
+ puts "Processing #{uri}..."
26
+
27
+ self.image = URI.parse(uri)
28
+ self.save
29
+ end
30
+
31
+ def api_hash
32
+ {
33
+ :id => self.id,
34
+ :name => self.name,
35
+ :description => self.description,
36
+ :tiny_url => self.image.url(:tiny),
37
+ :thumb_url => self.image.url(:thumb),
38
+ :large_url => self.image.url(:large),
39
+ :original_url => self.image.url(:original)
40
+ }
22
41
  end
23
42
 
24
43
  end
@@ -0,0 +1,73 @@
1
+ require 'faye/websocket'
2
+
3
+ module Caboose
4
+ class MediaImageSocket
5
+
6
+ KEEPALIVE_TIME = 15 # in seconds
7
+
8
+ def initialize(app)
9
+ @app = app
10
+ @clients = {}
11
+ @image_ids = {}
12
+ end
13
+
14
+ def call(env)
15
+ if Faye::WebSocket.websocket?(env)
16
+
17
+ uri = env['REQUEST_URI']
18
+ #Caboose.log(uri)
19
+
20
+ # GET /admin/images/:id/wait
21
+ if uri =~ /\/admin\/images\/\d*\/wait/
22
+ image_id = uri.gsub('/admin/images/', '').gsub('/wait', '').to_i
23
+ #Caboose.log("Waiting on image_id #{image_id}...")
24
+ ws = Faye::WebSocket.new(env, nil, { :ping => KEEPALIVE_TIME })
25
+ ws.on :open do |event|
26
+ Caboose.log("Opening browser web socket for image #{image_id}...")
27
+ @clients[image_id] = [] if @clients[image_id].nil?
28
+ @clients[image_id] << ws
29
+ end
30
+ ws.on :message do |event|
31
+ Caboose.log("Received browser message for image #{image_id}")
32
+ @clients[image_id].each { |client| client.send(event.data) }
33
+ end
34
+ ws.on :close do |event|
35
+ Caboose.log("Closing browser web socket for image #{image_id}...")
36
+ #p [:close, ws.object_id, event.code, event.reason]
37
+ @clients.delete(ws)
38
+ ws = nil
39
+ end
40
+ ws.rack_response
41
+
42
+ # GET /admin/images/:id/finished
43
+ elsif uri =~ /\/admin\/images\/\d*\/finished/
44
+ image_id = uri.gsub('/admin/images/', '').gsub('/finished', '').to_i
45
+ ws = Faye::WebSocket.new(env, nil, { :ping => KEEPALIVE_TIME })
46
+ ws.on :open do |event|
47
+ #p [:open, ws.object_id]
48
+ Caboose.log("Opening server web socket for image #{image_id}...")
49
+ @image_ids[ws.object_id] = image_id
50
+ end
51
+ ws.on :message do |event|
52
+ #p [:message, event.data]
53
+ Caboose.log("Receieved server message for image #{image_id}")
54
+ image_id = @image_ids[ws.object_id]
55
+ @clients[image_id].each { |client| client.send(event.data) }
56
+ end
57
+ ws.on :close do |event|
58
+ #p [:close, ws.object_id, event.code, event.reason]
59
+ Caboose.log("Closing server web socket for image #{image_id}...")
60
+ @image_ids.delete(ws.object_id)
61
+ ws = nil
62
+ end
63
+ ws.rack_response
64
+ end
65
+
66
+ else
67
+ @app.call(env)
68
+ end
69
+
70
+ end
71
+ end
72
+ end
73
+
@@ -136,14 +136,16 @@ class Caboose::Schema < Caboose::Utilities::Schema
136
136
  [ :name , :string ]
137
137
  ],
138
138
  Caboose::MediaImage => [
139
- [ :media_category_id , :integer ],
140
- [ :name , :string ],
141
- [ :description , :text ]
139
+ [ :media_category_id , :integer ],
140
+ [ :name , :string ],
141
+ [ :description , :text ],
142
+ [ :image , :attachment ]
142
143
  ],
143
144
  Caboose::MediaFile => [
144
- [ :media_category_id , :integer ],
145
- [ :name , :string ],
146
- [ :description , :text ]
145
+ [ :media_category_id , :integer ],
146
+ [ :name , :string ],
147
+ [ :description , :text ],
148
+ [ :file , :attachment ]
147
149
  ],
148
150
  Caboose::Page => [
149
151
  [ :site_id , :integer ],
@@ -0,0 +1,7 @@
1
+ <div id='block_<%= block.id %>'>
2
+ <% if editing %>
3
+ <p style='border: #ccc 1px solid;'>Controller view content</p>
4
+ <% else %>
5
+ <%= raw controller_view_content %>
6
+ <% end %>
7
+ </div>
@@ -0,0 +1,3 @@
1
+ <h1>Invalid Site</h1>
2
+
3
+ <p>It doesn't look like this site is configured for the current domain. Please <a href='/admin/sites'>configure your sites</a>.</p>
@@ -0,0 +1,60 @@
1
+ <%
2
+ img = @media_image
3
+ %>
4
+ <div id='crumbtrail'>
5
+ <a href='/admin'>Admin</a> >
6
+ <a href='/admin/images'>Images</a>
7
+ </div>
8
+
9
+ <h1>Edit Image</h1>
10
+ <img src='<%= img.image.url(:thumb) %>' style='float: right;' />
11
+ <p><div id='mediaimage_<%= img.id %>_name' ></div></p>
12
+ <p><div id='mediaimage_<%= img.id %>_description' ></div></p>
13
+
14
+ <div id='message'></div>
15
+ <p>
16
+ <input type='button' value='< Back' onclick="window.location='/admin/images?media_category_id=<%= img.media_category_id %>';" />
17
+ <input type='button' value='Delete Image' onclick="delete_image(<%= img.id %>);" />
18
+ </p>
19
+
20
+ <% content_for :caboose_js do %>
21
+ <%= javascript_include_tag "caboose/model/all" %>
22
+ <script type="text/javascript">
23
+
24
+ function delete_image(image_id, confirm)
25
+ {
26
+ if (!confirm)
27
+ {
28
+ var p = $('<p/>').addClass('note warning')
29
+ .append('Are you sure you want to delete the image? ')
30
+ .append($('<input/>').attr('type', 'button').val('Yes').click(function() { delete_image(image_id, true); })).append(" ")
31
+ .append($('<input/>').attr('type', 'button').val('No' ).click(function() { $('#message').empty(); }));
32
+ $('#message').empty().append(p);
33
+ return;
34
+ }
35
+ $('#message').empty().append($('<p/>').addClass('loading').html('Deleting image...'));
36
+ $.ajax({
37
+ url: '/admin/images/' + image_id,
38
+ type: 'delete',
39
+ success: function(resp) {
40
+ if (resp.error) $('#message').empty().append($('<p/>').addClass('note error').html(resp.error));
41
+ if (resp.redirect) window.location = resp.redirect;
42
+ }
43
+ });
44
+ }
45
+
46
+ $(document).ready(function() {
47
+ m = new ModelBinder({
48
+ name: 'MediaImage',
49
+ id: <%= img.id %>,
50
+ update_url: '/admin/images/<%= img.id %>',
51
+ authenticity_token: '<%= form_authenticity_token %>',
52
+ attributes: [
53
+ { name: 'name' , nice_name: 'Name' , type: 'text' , value: <%= raw Caboose.json(img.name) %>, width: 400 },
54
+ { name: 'description' , nice_name: 'Description' , type: 'textarea' , value: <%= raw Caboose.json(img.description) %>, width: 400, height: 200 }
55
+ ]
56
+ });
57
+ });
58
+
59
+ </script>
60
+ <% end %>
@@ -1,106 +1,57 @@
1
1
  <h1>Images</h1>
2
2
 
3
- <% if @domain && @media_category %>
3
+ <% if @site && @media_category %>
4
+ <%
5
+ arr = []
6
+ cat = @media_category
7
+ arr << cat
8
+ while cat.parent_id
9
+ cat = cat.parent
10
+ arr << cat
11
+ end
12
+ crumb_trail = arr.collect{ |cat| "<a href='/admin/images?media_category_id=#{cat.id}'>#{cat.name}</a>" }.reverse.join(" > ")
13
+ %>
14
+ <p id='crumb_trail'><%= raw crumb_trail %></p>
15
+
4
16
  <form action='/admin/images/sign-s3' method='post' id='new_image_form' enctype='multipart/form-data'>
5
17
  <input type='hidden' name='key' value='' />
6
18
  <input type='hidden' name='AWSAccessKeyId' value='' />
7
19
  <input type='hidden' name='acl' value='' />
8
- <input type='hidden' name='success_action_status' value='' />
9
- <!--<input type='hidden' name='success_action_redirect' value='' />-->
20
+ <input type='hidden' name='success_action_status' value='' />
10
21
  <input type='hidden' name='policy' value='' />
11
- <input type='hidden' name='signature' value='' />
12
- <input type="file" name="file" id="file" multiple='true' />
22
+ <input type='hidden' name='signature' value='' />
23
+ <input type="file" name="file" id="file" multiple='true' style='display: none;' />
24
+ <p>
25
+ <a href='#' id='new_cat_link'>New Category</a> |
26
+ <a href='#' onclick="$('#file').click();">Upload Files</a>
27
+ </p>
13
28
  <div id='progress'><div id='bar'></div></div>
14
- </form>
15
- <p><a href='/admin/images/new-category?parent_id=<%= @media_category.id %>'>New Category</a></p>
16
- </p>
17
- <% if @media_category.children.count > 0 || @media_category.media_images.count > 0 %>
18
- <ul class='media'>
19
- <% @media_category.children.each do |cat| %>
20
- <li class='category' id='cat<%= cat.id %>'><a href='/admin/images?media_category_id=<%= cat.id %>'><%= cat.name %></a></li>
21
- <% end %>
22
- <% @media_category.media_images.each do |mi| %>
23
- <li class='image' id='image<%= mi.id %>'><a href='/admin/images/<%= mi.id %>'><img src='<%= mi.image.url(:thumb) %>' /><span><%= mi.name %></span></a></li>
24
- <% end %>
25
- </ul>
26
- <% else %>
27
- <p>This category is empty.</p>
28
- <% end %>
29
- <% elsif @domain && @media_category.nil? %>
29
+ </form>
30
+ <div id='new_cat_message'></div>
31
+ </p>
32
+ <div id='media'></div>
33
+ <% elsif @site && @media_category.nil? %>
30
34
  <p>Invalid media category.</p>
31
35
  <% else %>
32
36
  <p>It doesn't look like this site is configured for the current domain. Please <a href='/admin/sites'>configure your sites</a>.</p>
33
37
  <% end %>
34
38
 
35
39
  <% content_for :caboose_css do %>
36
- <style type='text/css'>
37
- ul.media li.image { list-style: none; margin: 0; padding: 0; float: left; }
38
- ul.media li.image { list-style: none; margin: 0; padding: 0; float: left; }
39
- ul.media li.image img {}
40
- .progress { max-width: 600px; margin: 0.2em 0 0.2em 0; }
41
- .progress .bar { height: 1.2em; padding: 0.2em; color: white; display: none; }
42
- </style>
40
+ <%= stylesheet_link_tag 'caboose/icomoon_fonts' %>
41
+ <%= stylesheet_link_tag 'caboose/admin_images_index' %>
43
42
  <% end %>
44
43
 
45
44
  <% content_for :caboose_js do %>
46
45
  <%= javascript_include_tag 'jquery.ui.widget' %>
47
46
  <%= javascript_include_tag 'caboose/jquery.iframe-transport.js' %>
48
47
  <%= javascript_include_tag 'caboose/jquery.fileupload.js' %>
48
+ <%= javascript_include_tag 'caboose/admin_images_index.js' %>
49
49
  <script type='text/javascript'>
50
50
 
51
- var image_ids = [];
52
- $(document).ready(function() {
53
- $('#file').fileupload({
54
- //forceIframeTransport: true,
55
- autoUpload: true,
56
- //replaceFileInput: true,
57
- //singleFileUploads: false,
58
- add: function(e, data) {
59
- $.ajax({
60
- url: '/admin/images/s3',
61
- type: 'get',
62
- data: {
63
- name: data.files[0].name,
64
- media_category_id: <%= @media_category.id %>
65
- },
66
- async: false,
67
- success: function(resp) {
68
- image_ids.push(resp.media_image_id);
69
- var form = $('#new_image_form');
70
- for (var i in resp.fields)
71
- form.find("input[name=" + i + "]").val(resp.fields[i]);
72
- form.attr('action', resp.url);
73
- }
74
- });
75
- data.submit();
76
- },
77
- progressall: function (e, data) {
78
- $('#bar').css('width', parseInt(data.loaded / data.total * 100, 10) + '%')
79
- },
80
- start: function (e) {
81
- $('#file').hide();
82
- $('#bar').css('background', 'green').css('display', 'block').css('width', '0%').html("&nbsp;");
83
- },
84
- done: function(e, data) {
85
- console.log("Upload done.");
86
- console.log(data);
87
- setTimeout(function() {
88
- $.each(image_ids, function(i, id) {
89
- $.ajax({
90
- url: '/admin/images/' + id + '/process',
91
- type: 'get',
92
- async: false,
93
- success: function(resp) {}
94
- });
95
- });
96
- window.location.reload(true);
97
- }, 500);
98
- },
99
- fail: function(e, data) {
100
- console.log("Upload failed.");
101
- console.log(data);
102
- $('#bar').css("background", "red").text("Failed");
103
- }
51
+ var controller = false;
52
+ $(document).ready(function() {
53
+ controller = new ImagesController({
54
+ cat_id: <%= @media_category.id %>
104
55
  });
105
56
  });
106
57
 
@@ -73,13 +73,18 @@ Caboose::Engine.routes.draw do
73
73
  get "admin/images/s3" => "images#admin_sign_s3"
74
74
  get "admin/images/s3-result" => "images#admin_s3_result"
75
75
  get "admin/images/new" => "images#admin_new"
76
+ get "admin/images/json" => "images#admin_json"
76
77
  get "admin/images/:id/process" => "images#admin_process"
78
+ get "admin/images/:id/finished" => "images#admin_process_finished"
77
79
  get "admin/images/:id" => "images#admin_edit"
78
80
  put "admin/images/:id" => "images#admin_update"
79
81
  post "admin/images/:id/image" => "images#admin_update_image"
80
82
  post "admin/images" => "images#admin_add"
81
83
  delete "admin/images/:id" => "images#admin_delete"
82
84
 
85
+ post "admin/media-categories" => "media_categories#admin_add"
86
+ put "admin/media-categories/:id" => "media_categories#admin_update"
87
+ delete "admin/media-categories/:id" => "media_categories#admin_delete"
83
88
 
84
89
  get "admin/permissions" => "permissions#index"
85
90
  get "admin/permissions/options" => "permissions#options"
@@ -1,3 +1,3 @@
1
1
  module Caboose
2
- VERSION = '0.4.71'
2
+ VERSION = '0.4.72'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: caboose-cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.71
4
+ version: 0.4.72
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Barry
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-06 00:00:00.000000000 Z
11
+ date: 2014-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -194,6 +194,7 @@ files:
194
194
  - app/assets/images/caboose/search.png
195
195
  - app/assets/javascripts/caboose/admin.js
196
196
  - app/assets/javascripts/caboose/admin_block_edit.js
197
+ - app/assets/javascripts/caboose/admin_images_index.js
197
198
  - app/assets/javascripts/caboose/admin_page_edit_content.js
198
199
  - app/assets/javascripts/caboose/admin_page_edit_content_bak.js
199
200
  - app/assets/javascripts/caboose/admin_page_new_blocks.js
@@ -231,6 +232,7 @@ files:
231
232
  - app/assets/javascripts/caboose/testing.js
232
233
  - app/assets/javascripts/tinymce/plugins/caboose/plugin.js
233
234
  - app/assets/stylesheets/caboose/admin.css
235
+ - app/assets/stylesheets/caboose/admin_images_index.css
234
236
  - app/assets/stylesheets/caboose/admin_page_edit_content.css
235
237
  - app/assets/stylesheets/caboose/application.css
236
238
  - app/assets/stylesheets/caboose/bound_input.css
@@ -265,6 +267,7 @@ files:
265
267
  - app/controllers/caboose/images_controller.rb
266
268
  - app/controllers/caboose/login_controller.rb
267
269
  - app/controllers/caboose/logout_controller.rb
270
+ - app/controllers/caboose/media_categories_controller.rb
268
271
  - app/controllers/caboose/modal_controller.rb
269
272
  - app/controllers/caboose/page_permissions_controller.rb
270
273
  - app/controllers/caboose/pages_controller.rb
@@ -302,6 +305,7 @@ files:
302
305
  - app/models/caboose/media_category.rb
303
306
  - app/models/caboose/media_file.rb
304
307
  - app/models/caboose/media_image.rb
308
+ - app/models/caboose/media_image_socket.rb
305
309
  - app/models/caboose/menu_block.rb
306
310
  - app/models/caboose/page.rb
307
311
  - app/models/caboose/page_bar_generator.rb
@@ -342,6 +346,7 @@ files:
342
346
  - app/views/caboose/block_types/admin_index.html.erb
343
347
  - app/views/caboose/block_types/admin_new.html.erb
344
348
  - app/views/caboose/blocks/_block.html.erb
349
+ - app/views/caboose/blocks/_controller_view_content.html.erb
345
350
  - app/views/caboose/blocks/_file.html.erb
346
351
  - app/views/caboose/blocks/_heading.html.erb
347
352
  - app/views/caboose/blocks/_html.html.erb
@@ -381,6 +386,8 @@ files:
381
386
  - app/views/caboose/blocks/admin_render_second_level.json.erb
382
387
  - app/views/caboose/extras/error.html.erb
383
388
  - app/views/caboose/extras/error404.html.erb
389
+ - app/views/caboose/extras/error_invalid_site.html.erb
390
+ - app/views/caboose/images/admin_edit.html.erb
384
391
  - app/views/caboose/images/admin_index.html.erb
385
392
  - app/views/caboose/images/admin_new.html.erb
386
393
  - app/views/caboose/images/admin_s3_result.html.erb