caboose-cms 0.9.166 → 0.9.167

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/caboose/block_content_controller_dragdrop.js +1 -1
  3. data/app/assets/javascripts/caboose/model/index_table.js +3 -3
  4. data/app/assets/stylesheets/caboose/admin_edit_page_content_dragdrop.scss +20 -1
  5. data/app/assets/stylesheets/caboose/admin_main.css.scss +142 -9
  6. data/app/assets/stylesheets/caboose/message_boxes.css.scss +45 -29
  7. data/app/assets/stylesheets/caboose/modal_inline.css +10 -2
  8. data/app/controllers/caboose/block_type_store_controller.rb +1 -2
  9. data/app/controllers/caboose/login_controller.rb +1 -1
  10. data/app/controllers/caboose/login_logs_controller.rb +9 -1
  11. data/app/controllers/caboose/page_templates_controller.rb +76 -0
  12. data/app/controllers/caboose/pages_controller.rb +76 -42
  13. data/app/controllers/caboose/sites_controller.rb +20 -11
  14. data/app/controllers/caboose/themes_controller.rb +108 -0
  15. data/app/models/caboose/block.rb +7 -3
  16. data/app/models/caboose/block_type.rb +2 -0
  17. data/app/models/caboose/core_plugin.rb +2 -0
  18. data/app/models/caboose/page.rb +1 -0
  19. data/app/models/caboose/page_template.rb +17 -0
  20. data/app/models/caboose/page_template_category.rb +20 -0
  21. data/app/models/caboose/schema.rb +80 -1
  22. data/app/models/caboose/site.rb +15 -2
  23. data/app/models/caboose/theme.rb +146 -0
  24. data/app/models/caboose/user.rb +14 -16
  25. data/app/views/caboose/block_type_sources/admin_edit.html.erb +1 -1
  26. data/app/views/caboose/block_type_sources/admin_index.html.erb +1 -1
  27. data/app/views/caboose/block_type_store/admin_details.html.erb +2 -2
  28. data/app/views/caboose/block_type_store/admin_index.html.erb +3 -3
  29. data/app/views/caboose/fonts/admin_index.html.erb +23 -0
  30. data/app/views/caboose/login_logs/admin_index.html.erb +6 -1
  31. data/app/views/caboose/login_logs/admin_index_for_user.html.erb +36 -0
  32. data/app/views/caboose/page_templates/admin_edit.html.erb +68 -0
  33. data/app/views/caboose/page_templates/admin_index.html.erb +24 -0
  34. data/app/views/caboose/page_templates/admin_new.html.erb +38 -0
  35. data/app/views/caboose/pages/admin_delete_form.html.erb +5 -4
  36. data/app/views/caboose/pages/admin_edit_content.html.erb +0 -9
  37. data/app/views/caboose/pages/admin_new.html.erb +139 -41
  38. data/app/views/caboose/pages/admin_new_old.html.erb +46 -0
  39. data/app/views/caboose/posts/admin_edit_content.html.erb +0 -8
  40. data/app/views/caboose/sites/admin_index.html.erb +2 -1
  41. data/app/views/caboose/themes/admin_edit.html.erb +242 -0
  42. data/app/views/caboose/users/_admin_header.html.erb +2 -2
  43. data/app/views/caboose/users/admin_delete_form.html.erb +0 -2
  44. data/app/views/caboose/users/admin_edit.html.erb +24 -7
  45. data/app/views/caboose/users/admin_edit_password.html.erb +1 -1
  46. data/app/views/caboose/users/admin_edit_roles.html.erb +2 -0
  47. data/app/views/layouts/caboose/application.html.erb +8 -0
  48. data/lib/caboose/version.rb +1 -1
  49. metadata +13 -2
@@ -9,7 +9,7 @@ class Caboose::Site < ActiveRecord::Base
9
9
  has_many :domains, :class_name => 'Caboose::Domain', :dependent => :delete_all
10
10
  has_many :fonts, :class_name => 'Caboose::Font', :dependent => :delete_all
11
11
  has_many :post_categories, :class_name => 'Caboose::PostCategory'
12
- has_one :store_config
12
+ has_one :store_config
13
13
  has_attached_file :logo,
14
14
  :path => ':caboose_prefixsite_logos/:id_:style.:extension',
15
15
  :default_url => 'http://placehold.it/300x300',
@@ -38,9 +38,22 @@ class Caboose::Site < ActiveRecord::Base
38
38
  :sitemap_xml ,
39
39
  :robots_txt ,
40
40
  :theme_color ,
41
- :assets_url
41
+ :assets_url ,
42
+ :theme_id
42
43
 
43
44
  before_save :validate_presence_of_store_config
45
+
46
+ def theme
47
+ Caboose::Theme.where(:id => self.theme_id).first
48
+ end
49
+
50
+ def build_new_site
51
+ # if defined?(SuiteBuilder) == 'constant' && SuiteBuilder.class == Class
52
+ helper = Caboose::SiteBuilder.new(self.name)
53
+ helper.create_site_blocks(self.id)
54
+ # end
55
+ # self.init_users_and_roles
56
+ end
44
57
 
45
58
  def validate_presence_of_store_config
46
59
  if self.use_store && !Caboose::StoreConfig.where(:site_id => self.id).exists?
@@ -0,0 +1,146 @@
1
+ class Caboose::Theme < ActiveRecord::Base
2
+
3
+ self.table_name = "themes"
4
+
5
+ has_attached_file :default_banner_image,
6
+ :path => 'banner_images/:id_:style.:extension',
7
+ :default_url => 'https://res.cloudinary.com/caboose/image/upload/c_scale,f_auto,q_auto:good,w_1800/v1539265856/default_banner.jpg',
8
+ :s3_protocol => :https,
9
+ :styles => {
10
+ huge: '1800x1800>'
11
+ }
12
+ do_not_validate_attachment_file_type :default_banner_image
13
+
14
+ attr_accessible :id,
15
+ :color_main,
16
+ :color_alt,
17
+ :color_dark,
18
+ :color_light,
19
+ :max_width,
20
+ :body_bg_color,
21
+ :font_size,
22
+ :header_height,
23
+ :header_bg_color,
24
+ :header_font_color,
25
+ :dropdown_color,
26
+ :mobile_menu_bg_color,
27
+ :mobile_menu_font_color,
28
+ :mobile_menu_border_color,
29
+ :mobile_menu_icon_color,
30
+ :mobile_menu_icon_top,
31
+ :footer_height,
32
+ :footer_bg_color,
33
+ :footer_font_color,
34
+ :btn_border_radius,
35
+ :btn_border_width,
36
+ :btn_border_color,
37
+ :btn_font_color,
38
+ :btn_font_size,
39
+ :btn_font_weight,
40
+ :btn_font_case,
41
+ :btn_border_side,
42
+ :input_border_radius,
43
+ :input_bg_color,
44
+ :input_border_color,
45
+ :input_border_width,
46
+ :input_font_color,
47
+ :input_font_size,
48
+ :input_padding,
49
+
50
+ :body_line_height,
51
+ :body_font_color,
52
+ :button_padding,
53
+ :button_line_height,
54
+ :footer_padding,
55
+ :footer_font_size,
56
+ :header_font_size,
57
+ :note_padding,
58
+ :header_nav_spacing,
59
+ :logo_width,
60
+ :logo_height,
61
+ :logo_top_padding,
62
+ :heading_line_height,
63
+ :mobile_menu_nav_padding,
64
+ :mobile_menu_font_size,
65
+ :banner_padding,
66
+ :banner_overlay_color,
67
+ :banner_overlay_opacity,
68
+ :default_header_style,
69
+ :default_header_position,
70
+ :sidebar_width,
71
+ :sidebar_bg_color,
72
+
73
+ :digest
74
+
75
+ def compile(for_site_id = 0)
76
+ theme = self
77
+ theme_name = 'default'
78
+ path = Rails.root.join(Caboose::site_assets_path, 'themes', "#{theme_name}.scss.erb")
79
+ body = ERB.new(File.read(File.join(path))).result(theme.get_binding(for_site_id))
80
+ tmp_themes_path = File.join(Rails.root, 'tmp', 'themes')
81
+ tmp_asset_name = "theme_#{self.id}_site_#{for_site_id}"
82
+ FileUtils.mkdir_p(tmp_themes_path) unless File.directory?(tmp_themes_path)
83
+ File.open(File.join(tmp_themes_path, "#{tmp_asset_name}.scss"), 'w') { |f| f.write(body) }
84
+ begin
85
+ env = if Rails.application.assets.is_a?(Sprockets::Index)
86
+ Rails.application.assets.instance_variable_get('@environment')
87
+ else
88
+ Rails.application.assets
89
+ end
90
+ asset = env.find_asset(tmp_asset_name)
91
+ compressed_body = ::Sass::Engine.new(asset.body, {
92
+ :syntax => :scss,
93
+ :cache => false,
94
+ :read_cache => false,
95
+ :style => :compressed
96
+ }).render
97
+ str = StringIO.new(compressed_body)
98
+ theme.delete_asset
99
+ if Rails.env.production?
100
+ config = YAML.load(File.read(Rails.root.join('config', 'aws.yml')))[Rails.env]
101
+ AWS.config(:access_key_id => config['access_key_id'], :secret_access_key => config['secret_access_key'])
102
+ bucket = AWS::S3.new.buckets[config['bucket']]
103
+ bucket.objects[theme.asset_path(asset.digest, for_site_id)].write(str, :acl => 'public-read', :content_type => 'text/css')
104
+ else
105
+ File.open(File.join(Rails.root, 'public', theme.asset_path(asset.digest, for_site_id)), 'w') { |f| f.write(compressed_body) }
106
+ end
107
+ self.update_digest(asset.digest)
108
+ rescue Sass::SyntaxError => error
109
+ theme.revert
110
+ end
111
+ end
112
+
113
+ def revert
114
+ Caboose.log("reverting theme")
115
+ end
116
+
117
+ def get_binding(site_id)
118
+ binding
119
+ end
120
+
121
+ def delete_asset
122
+ return unless digest?
123
+ end
124
+
125
+ def asset_path(digest = self.digest, site_id = 0)
126
+ "assets/themes/#{asset_name(digest, site_id)}.css"
127
+ end
128
+
129
+ def asset_name(digest = self.digest, site_id = 0)
130
+ "theme_#{self.id}_site_#{site_id}-#{digest}"
131
+ end
132
+
133
+ def asset_url(site_id = 0)
134
+ "#{ActionController::Base.asset_host}/#{asset_path(self.digest,site_id)}"
135
+ end
136
+
137
+ def js_url
138
+ # TODO - figure out how to do this
139
+ "https://cabooseit.s3.amazonaws.com/assets/natureseyenri/js/application.js"
140
+ end
141
+
142
+ def update_digest(digest)
143
+ self.update_column('digest', digest)
144
+ end
145
+
146
+ end
@@ -50,24 +50,22 @@ class Caboose::User < ActiveRecord::Base
50
50
  self.email
51
51
  end
52
52
 
53
- def is_allowed(resource, action)
54
- elo = Caboose::Role.logged_out_role(self.site_id)
55
- elo_is_allowed = elo.is_allowed(resource, action)
56
- return true if elo_is_allowed
57
- return false if !elo_is_allowed && self.is_logged_out_user?
58
- eli = Caboose::Role.logged_in_role(self.site_id)
59
- return true if self.id != elo.id && eli.is_allowed(resource, action)
60
- for role in roles
61
- #Caboose.log("Checking permissions for #{role.name} role")
62
- if role.is_allowed(resource, action)
63
- #Caboose.log("Role #{role.name} is allowed to view page")
64
- return true
65
- else
66
- #Caboose.log("Role #{role.name} is not allowed to view page")
53
+ def is_allowed(resource, action)
54
+ if self.username == 'elo'
55
+ elo = Caboose::Role.logged_out_role(self.site_id)
56
+ elo_is_allowed = elo.is_allowed(resource, action)
57
+ return true if elo_is_allowed
58
+ return false if !elo_is_allowed && self.is_logged_out_user?
59
+ eli = Caboose::Role.logged_in_role(self.site_id)
60
+ return true if self.id != elo.id && eli.is_allowed(resource, action)
61
+ else
62
+ for role in roles
63
+ if role.is_allowed(resource, action)
64
+ return true
65
+ end
67
66
  end
68
- #return true if role.is_allowed(resource, action)
69
67
  end
70
- return false;
68
+ return false
71
69
  end
72
70
 
73
71
  def self.validate_token(token)
@@ -4,7 +4,7 @@ bts = @block_type_source
4
4
  <div id='crumbtrail'>
5
5
  <a href='/admin'>Admin</a> >
6
6
  <a href='/admin/block-types'>Block Types</a> >
7
- <a href='/admin/block-types/store'>Store</a> >
7
+ <a href='/admin/block-type-store'>Store</a> >
8
8
  <a href='/admin/block-types/store/sources'>Sources</a>
9
9
  </div>
10
10
 
@@ -16,7 +16,7 @@
16
16
  <th>URL</th>
17
17
  </tr>
18
18
  <% @block_type_sources.each do |bts| %>
19
- <tr onclick="window.location='/admin/block-types/store/sources/<%= bts.id %>/edit';">
19
+ <tr onclick="window.location='/admin/block-types/store/sources/<%= bts.id %>';">
20
20
  <td><%= bts.name %></td>
21
21
  <td><%= bts.url %></td>
22
22
  </tr>
@@ -4,7 +4,7 @@ bts = @block_type_summary
4
4
  <div id='crumbtrail'>
5
5
  <a href='/admin'>Admin</a> >
6
6
  <a href='/admin/block-types'>Block Types</a> >
7
- <a href='/admin/block-types/store'>Store</a>
7
+ <a href='/admin/block-type-store'>Store</a>
8
8
  </div>
9
9
 
10
10
  <h1>Block Type Details</h1>
@@ -13,7 +13,7 @@ bts = @block_type_summary
13
13
  <p>Description: <%= bts.description %></p>
14
14
  <div id='message'></div>
15
15
  <p>
16
- <input type='button' value='< Back' onclick="window.location='/admin/block-types/store';" />
16
+ <input type='button' value='< Back' onclick="window.location='/admin/block-type-store';" />
17
17
  <input type='button' value='Download from Source' onclick="download_block_type(<%= bts.id %>);" />
18
18
  </p>
19
19
 
@@ -7,15 +7,15 @@
7
7
 
8
8
  <p><a href='/admin/block-types/store/sources'>Store Sources</a></p>
9
9
 
10
- <form action='/admin/block-types/store' method='get'>
10
+ <form action='/admin/block-type-store' method='get'>
11
11
  <table>
12
12
  <tr><td>Source:</td><td>
13
13
  <select name='block_type_source_id'>
14
14
  <option value=''>-- Any Source --</option>
15
15
  <% Caboose::BlockTypeSource.reorder(:name).all.each do |bts| %><option value='<%= bts.id %>'><%= bts.name %></option><% end %>
16
16
  </select></td></tr>
17
- <tr><td><p>Name: </td><td><input type='name_like' value="<%= @pager.params['name_like'] %>" /></td></tr>
18
- <tr><td><p>Description: </td><td><input type='name_like' value="<%= @pager.params['name_like'] %>" /></td></tr>
17
+ <tr><td><p>Name: </td><td><input type="text" name='name_like' value="<%= @pager.params['name_like'] %>" /></td></tr>
18
+ <tr><td><p>Description: </td><td><input type="text" name='description_like' value="<%= @pager.params['description_like'] %>" /></td></tr>
19
19
  </table>
20
20
  <p><input type='submit' value='Search' /></p>
21
21
  </form>
@@ -75,6 +75,13 @@
75
75
  </div>
76
76
  </div>
77
77
 
78
+ <% if @site.theme %>
79
+ <div style="text-align:center;">
80
+ <a href="#" id="compile-btn" class="caboose-btn">Compile Theme</a>
81
+ <div id="cmessage"></div>
82
+ </div>
83
+ <% end %>
84
+
78
85
  <% content_for :caboose_css do %>
79
86
  <style>
80
87
  #font-form {
@@ -248,6 +255,22 @@
248
255
 
249
256
  <% content_for :caboose_js do %>
250
257
  <script>
258
+
259
+ $("#compile-btn").click(function(e) {
260
+ $('#cmessage').html("<p class='note loading'>Compiling theme...</p>").fadeIn();
261
+ e.preventDefault();
262
+ $.ajax({
263
+ url: '/admin/themes/<%= @site.theme_id %>/compile',
264
+ type: 'get',
265
+ success: function(resp) {
266
+ if (resp.error) $('#cmessage').html("<p class='note error'>" + resp.error + "</p>").fadeIn();
267
+ if (resp.success && resp.message) {
268
+ $('#cmessage').html("<p class='note success'>" + resp.message + "</p>").fadeIn().delay(2000).fadeOut();
269
+ }
270
+ }
271
+ });
272
+ });
273
+
251
274
  window.google_fonts = [];
252
275
 
253
276
  $(".page-link#next").click(function(event) {
@@ -1,5 +1,10 @@
1
+ <% if request && request.url.include?('user_id') %>
2
+ <%= render :partial => 'caboose/users/admin_header' %>
3
+ <% else %>
4
+ <h1>Login Logs</h1>
5
+ <h4><%= request.url %></h4>
6
+ <% end %>
1
7
 
2
- <h1>Login Logs</h1>
3
8
  <div id='login_logs'></div>
4
9
 
5
10
  <% content_for :caboose_js do %>
@@ -0,0 +1,36 @@
1
+ <%= render :partial => 'caboose/users/admin_header' %>
2
+
3
+ <div id='login_logs'></div>
4
+
5
+ <% content_for :caboose_js do %>
6
+ <%= javascript_include_tag 'caboose/model/all' %>
7
+ <script type='text/javascript'>
8
+
9
+ $(document).ready(function() {
10
+ var that = this;
11
+ var table = new IndexTable({
12
+ form_authenticity_token: '<%= form_authenticity_token %>',
13
+ container: 'login_logs',
14
+ base_url: '/admin/login-logs',
15
+ allow_add: false,
16
+ allow_bulk_import: false,
17
+ allow_bulk_edit: false,
18
+ allow_bulk_delete: false,
19
+ allow_duplicate: false,
20
+ allow_advanced_edit: false,
21
+ fields: [
22
+ { show: true, name: 'date_attempted' , nice_name: 'Date' , sort: 'date_attempted' , type: 'text' , value: function(ll) { return ll.date_attempted }, width: 150, align: 'left', bulk_edit: false, editable: false },
23
+ { show: true, name: 'ip' , nice_name: 'IP Address' , sort: 'ip' , type: 'text' , value: function(ll) { return ll.ip }, width: 150, align: 'left', bulk_edit: false, editable: false },
24
+ { show: true, name: 'success' , nice_name: 'Success' , sort: 'success' , type: 'checkbox' , value: function(ll) { return ll.success ? 'Yes' : 'No' }, width: 150, align: 'left', bulk_edit: false, editable: false }
25
+ ],
26
+ search_fields: [
27
+ { name: 'date_attempted_gte' , nice_name: 'Date Min' , type: 'text' , width: 150, align: 'left' },
28
+ { name: 'date_attempted_lte' , nice_name: 'Date Max' , type: 'text' , width: 150, align: 'left' },
29
+ { name: 'ip_like' , nice_name: 'IP Address' , type: 'text' , width: 150, align: 'left' }
30
+ ],
31
+ no_models_text: "There are no login logs right now."
32
+ });
33
+ });
34
+
35
+ </script>
36
+ <% end %>
@@ -0,0 +1,68 @@
1
+ <h1>Edit Page Template</h1>
2
+
3
+ <div id='pagetemplate_<%= @template.id %>_title' ></div>
4
+ <div id='pagetemplate_<%= @template.id %>_description' ></div>
5
+ <div id='pagetemplate_<%= @template.id %>_category_id' ></div>
6
+ <div id='pagetemplate_<%= @template.id %>_page_id' ></div>
7
+ <div id='pagetemplate_<%= @template.id %>_sort_order' ></div>
8
+ <div id='pagetemplate_<%= @template.id %>_screenshot' ></div>
9
+
10
+ <div id="message"></div>
11
+ <br />
12
+ <p>
13
+ <input type='button' value='Back' onclick="window.location='/admin/templates';" >
14
+ <input type='button' value='Delete Page Template' onclick="delete_template(<%= @template.id %>);" >
15
+ </p>
16
+
17
+ <% content_for :caboose_css do %>
18
+ <style>
19
+ .mb_container {
20
+ margin-bottom: 15px;
21
+ clear: both;
22
+ }
23
+ </style>
24
+ <% end %>
25
+
26
+ <% content_for :caboose_js do %>
27
+ <%= javascript_include_tag "caboose/model/all" %>
28
+ <script type='text/javascript'>
29
+ function delete_template(rep_id, confirm)
30
+ {
31
+ if (!confirm)
32
+ {
33
+ var p = $('<p/>').addClass('note warning')
34
+ .append("Are you sure you want to delete the template? ")
35
+ .append($('<input/>').attr('type','button').val('Yes').click(function() { delete_template(rep_id, true); })).append(' ')
36
+ .append($('<input/>').attr('type','button').val('No').click(function() { $('#message').empty(); }));
37
+ $('#message').empty().append(p);
38
+ return;
39
+ }
40
+ $('#message').empty().html($('<p/>').addClass('loading').html("Deleting template..."));
41
+ $.ajax({
42
+ url: '/admin/templates/' + rep_id,
43
+ type: 'delete',
44
+ success: function(resp) {
45
+ if (resp.error) $('#message').html("<p class='note error'>" + resp.error + "</p>");
46
+ if (resp.redirect) window.location = resp.redirect;
47
+ }
48
+ });
49
+ }
50
+ $(document).ready(function() {
51
+ m = new ModelBinder({
52
+ name: 'PageTemplate',
53
+ id: <%= @template.id %>,
54
+ update_url: '/admin/templates/<%= @template.id %>',
55
+ authenticity_token: '<%= form_authenticity_token %>',
56
+ attributes: [
57
+ { name: 'title' , nice_name: 'Title' , type: 'text' , value: <%= raw Caboose.json(@template.title ) %> , width: 500 },
58
+ { name: 'description' , nice_name: 'Description' , type: 'textarea' , value: <%= raw Caboose.json(@template.description ) %> , width: 500, height: 250 },
59
+ { name: 'page_id' , nice_name: 'Reference Page ID' , type: 'text' , value: <%= raw Caboose.json(@template.page_id ) %> , width: 500 },
60
+ { name: 'category_id' , nice_name: 'Category' , type: 'select' , value: <%= raw Caboose.json(@template.category_id ) %>, options: <%== Caboose::PageTemplateCategory.all_options(true) %> , width: 500 },
61
+ { name: 'sort_order' , nice_name: 'Sort Order' , type: 'text' , value: <%= raw Caboose.json(@template.sort_order ) %> , width: 500 },
62
+ { name: 'screenshot' , nice_name: 'Screenshot (800x800)' , type: 'image' , value: <%= raw Caboose.json(@template.screenshot ? @template.screenshot.url(:small) : 'https://cabooseit.s3.amazonaws.com/assets/shared/template.png') %>, width: 300, update_url: '/admin/templates/<%= @template.id %>/screenshot' }
63
+ ]
64
+ });
65
+ });
66
+
67
+ </script>
68
+ <% end %>
@@ -0,0 +1,24 @@
1
+ <h1>Page Templates</h1>
2
+
3
+ <div class="page-templates-wrapper">
4
+ <% @categories.each do |cat| %>
5
+ <div class="category clearfix">
6
+ <h3><%= cat.title %></h3>
7
+ <p class="description"><%= cat.description %></p>
8
+ <div class="cat-templates">
9
+ <% cat.page_templates.order(:sort_order).each do |tem| %>
10
+ <a href="/admin/templates/<%= tem.id %>" class="template">
11
+ <img src="<%= tem.screenshot.url(:small) %>" width="200" height="200" alt="<%= tem.title %>" srcset="<%= tem.screenshot.url(:medium) %> 2x" />
12
+ <div class="text">
13
+ <span class="title"><%= tem.title.blank? ? 'New Template' : tem.title %></span>
14
+ <% if !tem.description.blank? %><span class="desc"><%= tem.description %></span><% end %>
15
+ </div>
16
+ </a>
17
+ <% end %>
18
+ </div>
19
+ <div class="btn-holder">
20
+ <a href="/admin/templates/new?category=<%= cat.id %>" class="caboose-btn-white">New Page Template</a>
21
+ </div>
22
+ </div>
23
+ <% end %>
24
+ </div>