caboose-cms 0.4.71 → 0.4.72

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.
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