caboose-cms 0.6.16 → 0.6.17

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Nestable
3
+ */
4
+
5
+ .dd { position: relative; display: block; margin: 0; padding: 0; max-width: 600px; list-style: none; font-size: 13px; line-height: 20px; }
6
+
7
+ .dd-list { display: block; position: relative; margin: 0; padding: 0; list-style: none; }
8
+ .dd-list .dd-list { padding-left: 10px; }
9
+ .dd-collapsed .dd-list { display: none; }
10
+
11
+ .dd-item,
12
+ .dd-empty,
13
+ .dd-placeholder { display: block; position: relative; margin: 0; padding: 0; min-height: 20px; font-size: 13px; line-height: 20px; }
14
+
15
+ .dd-handle { display: block; height: 30px; margin: 2px 0; padding: 5px 10px; color: #333; text-decoration: none; font-weight: bold; border: 1px solid #ccc;
16
+ background: #fafafa;
17
+ background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%);
18
+ background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%);
19
+ background: linear-gradient(top, #fafafa 0%, #eee 100%);
20
+ -webkit-border-radius: 3px;
21
+ border-radius: 3px;
22
+ box-sizing: border-box; -moz-box-sizing: border-box;
23
+ }
24
+ .dd-handle:hover { color: #2ea8e5; background: #fff; }
25
+
26
+ .dd-item > button { display: block; position: relative; cursor: pointer; float: left; width: 25px; height: 20px; margin: 5px 0; padding: 0; text-indent: 100%; white-space: nowrap; overflow: hidden; border: 0; background: transparent; font-size: 12px; line-height: 1; text-align: center; font-weight: bold; }
27
+ .dd-item > button:before { content: '+'; display: block; position: absolute; width: 100%; text-align: center; text-indent: 0; }
28
+ .dd-item > button[data-action="collapse"]:before { content: '-'; }
29
+
30
+ .dd-placeholder,
31
+ .dd-empty { margin: 5px 0; padding: 0; min-height: 30px; background: #f2fbff; border: 1px dashed #b6bcbf; box-sizing: border-box; -moz-box-sizing: border-box; }
32
+ .dd-empty { border: 1px dashed #bbb; min-height: 100px; background-color: #e5e5e5;
33
+ background-image: -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
34
+ background-image: -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
35
+ background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
36
+ background-size: 60px 60px;
37
+ background-position: 0 0, 30px 30px;
38
+ }
39
+
40
+ .dd-dragel { position: absolute; pointer-events: none; z-index: 9999; }
41
+ .dd-dragel > .dd-item .dd-handle { margin-top: 0; }
42
+ .dd-dragel .dd-handle {
43
+ -webkit-box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
44
+ box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
45
+ }
46
+
47
+ /**
48
+ * Nestable Extras
49
+ */
50
+
51
+ .nestable-lists { display: block; clear: both; padding: 30px 0; width: 100%; border: 0; border-top: 2px solid #ddd; border-bottom: 2px solid #ddd; }
52
+
53
+ #categories-menu { padding: 0; margin: 20px 0; }
54
+
55
+ #categories-output,
56
+ #categories2-output { width: 100%; height: 7em; font-size: 0.75em; line-height: 1.333333em; font-family: Consolas, monospace; padding: 5px; box-sizing: border-box; -moz-box-sizing: border-box; }
57
+
58
+ #categories2 .dd-handle {
59
+ color: #fff;
60
+ border: 1px solid #999;
61
+ background: #bbb;
62
+ background: -webkit-linear-gradient(top, #bbb 0%, #999 100%);
63
+ background: -moz-linear-gradient(top, #bbb 0%, #999 100%);
64
+ background: linear-gradient(top, #bbb 0%, #999 100%);
65
+ }
66
+ #categories2 .dd-handle:hover { background: #bbb; }
67
+ #categories2 .dd-item > button:before { color: #fff; }
68
+
69
+ @media only screen and (min-width: 700px) {
70
+
71
+ .dd { float: left; width: 48%; }
72
+ .dd + .dd { margin-left: 2%; }
73
+
74
+ }
75
+
76
+ .dd-hover > .dd-handle { background: #2ea8e5 !important; }
77
+
78
+ /**
79
+ * Nestable Draggable Handles
80
+ */
81
+
82
+ .dd3-content { display: block; height: 30px; margin: 5px 0; padding: 5px 10px 5px 40px; color: #333; text-decoration: none; font-weight: bold; border: 1px solid #ccc;
83
+ background: #fafafa;
84
+ background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%);
85
+ background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%);
86
+ background: linear-gradient(top, #fafafa 0%, #eee 100%);
87
+ -webkit-border-radius: 3px;
88
+ border-radius: 3px;
89
+ box-sizing: border-box; -moz-box-sizing: border-box;
90
+ }
91
+ .dd3-content:hover { color: #2ea8e5; background: #fff; }
92
+
93
+ .dd-dragel > .dd3-item > .dd3-content { margin: 0; }
94
+
95
+ .dd3-item > button { margin-left: 30px; }
96
+
97
+ .dd3-handle { position: absolute; margin: 0; left: 0; top: 0; cursor: pointer; width: 30px; text-indent: 100%; white-space: nowrap; overflow: hidden;
98
+ border: 1px solid #aaa;
99
+ background: #ddd;
100
+ background: -webkit-linear-gradient(top, #ddd 0%, #bbb 100%);
101
+ background: -moz-linear-gradient(top, #ddd 0%, #bbb 100%);
102
+ background: linear-gradient(top, #ddd 0%, #bbb 100%);
103
+ border-top-right-radius: 0;
104
+ border-bottom-right-radius: 0;
105
+ }
106
+ .dd3-handle:before { content: '≡'; display: block; position: absolute; left: 0; top: 3px; width: 100%; text-align: center; text-indent: 0; color: #fff; font-size: 20px; font-weight: normal; }
107
+ .dd3-handle:hover { background: #ddd; }
@@ -31,7 +31,7 @@ module Caboose
31
31
  else
32
32
  bouncer_class = Caboose::authenticator_class.constantize
33
33
  bouncer = bouncer_class.new
34
- login_resp = bouncer.authenticate(username, password, @site)
34
+ login_resp = bouncer.authenticate(username, password, @site, request)
35
35
 
36
36
  if login_resp.error
37
37
  resp.error = login_resp.error
@@ -0,0 +1,34 @@
1
+
2
+ module Caboose
3
+ class LoginLogsController < ApplicationController
4
+ layout 'caboose/admin'
5
+
6
+ def before_action
7
+ @page = Page.page_with_uri(request.host_with_port, '/admin')
8
+ end
9
+
10
+ # GET /admin/login-logs
11
+ def index
12
+ return if !user_is_allowed('users', 'view')
13
+
14
+ @gen = PageBarGenerator.new(params, {
15
+ 'site_id' => @site.id,
16
+ 'username_like' => '',
17
+ 'user_id' => '',
18
+ 'date_attempted_lte' => '',
19
+ 'date_attempted_gte' => '',
20
+ 'ip_like' => '',
21
+ 'success' => ''
22
+ },{
23
+ 'model' => 'Caboose::LoginLog',
24
+ 'sort' => 'date_attempted',
25
+ 'desc' => false,
26
+ 'base_url' => '/admin/login-logs',
27
+ 'use_url_params' => false
28
+ })
29
+ @logs = @gen.items
30
+ end
31
+
32
+ end
33
+ end
34
+
@@ -16,7 +16,7 @@ module Caboose
16
16
  tree = Caboose::MediaCategory.flat_tree(@site.id, prefix)
17
17
  render :json => tree
18
18
  end
19
-
19
+
20
20
  # GET /admin/media-categories/options
21
21
  def admin_options
22
22
  return unless user_is_allowed('mediacategories', 'view')
@@ -25,6 +25,12 @@ module Caboose
25
25
  options = tree.collect{ |mc| { 'value' => mc[:id], 'text' => mc[:name] }}
26
26
  render :json => options
27
27
  end
28
+
29
+ # GET /admin/media-categories/tree
30
+ def admin_tree
31
+ return unless user_is_allowed('mediacategories', 'view')
32
+ render :json => Caboose::MediaCategory.tree_hash(@site.id)
33
+ end
28
34
 
29
35
  # POST /admin/media-categories
30
36
  def admin_add
@@ -35,6 +35,7 @@ module Caboose
35
35
  when 'google_plus_url' then sc.google_plus_url = value
36
36
  when 'linkedin_url' then sc.linkedin_url = value
37
37
  when 'google_analytics_id' then sc.google_analytics_id = value
38
+ when 'google_analytics_id2' then sc.google_analytics_id2 = value
38
39
  when 'auto_ga_js' then sc.auto_ga_js = value
39
40
  end
40
41
  end
@@ -179,7 +179,8 @@ module Caboose
179
179
  when 'zip' then user.zip = value
180
180
  when 'phone' then user.phone = value
181
181
  when 'fax' then user.fax = value
182
- when 'utc_offset' then user.utc_offset = value.to_f
182
+ when 'utc_offset' then user.utc_offset = value.to_f
183
+ when 'locked' then user.locked = value
183
184
  when "password"
184
185
  confirm = params[:password2]
185
186
  if (value != confirm)
@@ -4,6 +4,11 @@ module Caboose
4
4
  def forgot_password_email(user)
5
5
  @user = user
6
6
  mail(:to => user.email, :subject => "#{Caboose::website_name} Forgot Password")
7
+ end
8
+
9
+ def locked_account(user)
10
+ @user = user
11
+ mail(:to => user.email, :subject => "#{Caboose::website_name} Locked Account")
7
12
  end
8
13
 
9
14
  end
@@ -1,40 +1,62 @@
1
1
 
2
- class Caboose::Authenticator
2
+ module Caboose
3
+ class Authenticator
3
4
 
4
- def authenticate(username, password, site = nil)
5
- resp = Caboose::StdClass.new(
6
- 'error' => nil,
7
- 'user' => nil
8
- )
9
- pass = Digest::SHA1.hexdigest(Caboose::salt + password)
10
-
11
- user = Caboose::User.where(:username => username, :site_id => site.id).first
12
- user = Caboose::User.where(:email => username, :site_id => site.id).first if user.nil?
13
-
14
- valid_credentials = false
15
- if user && user.password == pass
16
- valid_credentials = true
17
- elsif site
18
- mp = Caboose::Setting.where(:site_id => site.id, :name => 'master_password').first
19
- mp = mp ? mp.value : nil
20
- if mp && mp.strip.length > 0 && mp == pass
5
+ def authenticate(username, password, site = nil, request = nil)
6
+ resp = StdClass.new
7
+ pass = Digest::SHA1.hexdigest(Caboose::salt + password)
8
+
9
+ user = User.where(:username => username, :site_id => site.id).first
10
+ user = User.where(:email => username, :site_id => site.id).first if user.nil?
11
+
12
+ ll = LoginLog.new
13
+ ll.username = username
14
+ ll.date_attempted = DateTime.now.utc
15
+ ll.user_id = user.id if user
16
+ ll.site_id = user.site_id if user
17
+ ll.ip = request.remote_ip if request
18
+
19
+ valid_credentials = false
20
+ if user && user.password == pass
21
21
  valid_credentials = true
22
+ resp.user = user
23
+ ll.success = true
24
+
25
+ elsif user && user.password != pass
26
+
27
+ fail_count = Caboose::LoginLog.fail_count(user)
28
+ if (fail_count+1) >= user.site.login_fail_lock_count
29
+ user.locked = true
30
+ user.save
31
+ LoginMailer.locked_account(user).deliver
32
+ resp.error = "Too many failed login attempts. Your account has been locked and the site administrator has been notified."
33
+ ll.success = false
34
+ else
35
+ attempts_left = user.site.login_fail_lock_count - fail_count - 1
36
+ resp.error = "Invalid password. You have #{attempts_left} attempt#{attempts_left == 1 ? '' : 's'} left before your account is locked."
37
+ ll.success = false
38
+ end
39
+
40
+ elsif site
41
+
42
+ mp = Setting.where(:site_id => site.id, :name => 'master_password').first
43
+ mp = mp ? mp.value : nil
44
+ if mp && mp.strip.length > 0 && mp == pass
45
+ resp.user = user
46
+ ll.success = true
47
+ else
48
+ resp.error = "Invalid credentials"
49
+ ll.success = false
50
+ end
51
+
52
+ else
53
+ resp.error = "Invalid credentials"
54
+ ll.success = false
22
55
  end
56
+
57
+ ll.save
58
+ return resp
23
59
  end
24
60
 
25
- if valid_credentials
26
- resp.user = user
27
- else
28
- resp.error = "Invalid credentials"
29
- end
30
-
31
- #resp.user = Caboose::User.where(:username => username, :password => pass).first
32
- #if (resp.user.nil?)
33
- # resp.user = Caboose::User.where(:email => username, :password => pass).first
34
- #end
35
- #resp.error = "Invalid credentials" if resp.user.nil?
36
-
37
- return resp
38
61
  end
39
-
40
62
  end
@@ -0,0 +1,22 @@
1
+
2
+ class Caboose::LoginLog < ActiveRecord::Base
3
+ self.table_name = "login_logs"
4
+
5
+ belongs_to :site, :class_name => 'Caboose::Site'
6
+ belongs_to :user, :class_name => 'Caboose::User'
7
+
8
+ attr_accessible :id,
9
+ :site_id ,
10
+ :username ,
11
+ :user_id ,
12
+ :date_attempted ,
13
+ :ip ,
14
+ :success
15
+
16
+ def self.fail_count(user)
17
+ last_successful_login = Caboose::LoginLog.where(:user_id => user.id, :success => true).reorder("date_attempted desc").first
18
+ id = last_successful_login ? last_successful_login.id : 1
19
+ return Caboose::LoginLog.where("user_id = ? and success = ? and id > ?", user.id, false, id).count
20
+ end
21
+
22
+ end
@@ -50,6 +50,20 @@ class Caboose::MediaCategory < ActiveRecord::Base
50
50
  return arr
51
51
  end
52
52
 
53
+ def self.tree_hash(site_id)
54
+ top_cat = self.where(:parent_id => nil, :site_id => site_id).first
55
+ return self.tree_hash_helper(top_cat)
56
+ end
57
+
58
+ def self.tree_hash_helper(cat)
59
+ return {
60
+ :id => cat.id,
61
+ :name => cat.name,
62
+ :media_count => cat.media.count,
63
+ :children => cat.children.collect{ |kid| self.tree_hash_helper(kid) }
64
+ }
65
+ end
66
+
53
67
  def is_ancestor_of?(cat)
54
68
  if cat.is_a?(Integer) || cat.is_a?(String)
55
69
  cat_id = cat.to_i
@@ -325,6 +325,14 @@ class Caboose::Schema < Caboose::Utilities::Schema
325
325
  [ :modification_value_id , :integer ],
326
326
  [ :input , :string ]
327
327
  ],
328
+ Caboose::LoginLog => [
329
+ [ :site_id , :integer ],
330
+ [ :username , :string ],
331
+ [ :user_id , :integer ],
332
+ [ :date_attempted , :datetime ],
333
+ [ :ip , :string ],
334
+ [ :success , :boolean , { :default => false }]
335
+ ],
328
336
  Caboose::MediaCategory => [
329
337
  [ :parent_id , :integer ],
330
338
  [ :site_id , :integer ],
@@ -620,11 +628,12 @@ class Caboose::Schema < Caboose::Utilities::Schema
620
628
  [ :use_fonts , :boolean , { :default => true }],
621
629
  [ :logo , :attachment ],
622
630
  [ :is_master , :boolean , { :default => false }],
623
- [ :analytics_id , :string ],
631
+ [ :analytics_id , :string ],
624
632
  [ :use_retargeting , :boolean , { :default => false }],
625
633
  [ :date_js_updated , :datetime ],
626
634
  [ :date_css_updated , :datetime ],
627
- [ :default_layout_id , :integer ]
635
+ [ :default_layout_id , :integer ],
636
+ [ :login_fail_lock_count , :integer , { :default => 5 }]
628
637
  ],
629
638
  Caboose::SiteMembership => [
630
639
  [ :site_id , :integer ],
@@ -653,6 +662,7 @@ class Caboose::Schema < Caboose::Utilities::Schema
653
662
  [ :google_plus_url , :string ],
654
663
  [ :linkedin_url , :string ],
655
664
  [ :google_analytics_id , :string ],
665
+ [ :google_analytics_id2 , :string ],
656
666
  [ :auto_ga_js , :boolean , { :default => false }]
657
667
  ],
658
668
  Caboose::StackableGroup => [
@@ -724,16 +734,17 @@ class Caboose::Schema < Caboose::Utilities::Schema
724
734
  [ :zip , :string ],
725
735
  [ :phone , :string ],
726
736
  [ :fax , :string ],
727
- [ :timezone , :string , { :default => 'Central Time (US & Canada)' }],
737
+ [ :timezone , :string , { :default => 'Central Time (US & Canada)' }],
728
738
  [ :password , :string ],
729
739
  [ :password_reset_id , :string ],
730
740
  [ :password_reset_sent , :datetime ],
731
741
  [ :token , :string ],
732
742
  [ :date_created , :datetime ],
733
743
  [ :image , :attachment ],
734
- [ :is_guest , :boolean , { :default => false }],
744
+ [ :is_guest , :boolean , { :default => false }],
735
745
  [ :customer_profile_id , :string ],
736
- [ :payment_profile_id , :string ]
746
+ [ :payment_profile_id , :string ],
747
+ [ :locked , :boolean , { :default => false }]
737
748
  ],
738
749
  Caboose::Variant => [
739
750
  [ :product_id , :integer ],
@@ -745,21 +756,21 @@ class Caboose::Schema < Caboose::Utilities::Schema
745
756
  [ :date_sale_starts , :datetime ],
746
757
  [ :date_sale_ends , :datetime ],
747
758
  [ :date_sale_end , :datetime ],
748
- [ :available , :boolean ],
749
- [ :quantity_in_stock , :integer , :default => 0 ],
750
- [ :ignore_quantity , :boolean ],
751
- [ :allow_backorder , :boolean ],
759
+ [ :available , :boolean , { :default => true }],
760
+ [ :quantity_in_stock , :integer , { :default => 0 }],
761
+ [ :ignore_quantity , :boolean , { :default => false }],
762
+ [ :allow_backorder , :boolean , { :default => false }],
752
763
  [ :weight , :decimal ],
753
764
  [ :length , :decimal ],
754
765
  [ :width , :decimal ],
755
766
  [ :height , :decimal ],
756
767
  [ :volume , :decimal ],
757
- [ :cylinder , :boolean ],
768
+ [ :cylinder , :boolean , { :default => false }],
758
769
  [ :option1 , :string ],
759
770
  [ :option2 , :string ],
760
771
  [ :option3 , :string ],
761
- [ :requires_shipping , :boolean ],
762
- [ :taxable , :boolean ],
772
+ [ :requires_shipping , :boolean , { :default => true }],
773
+ [ :taxable , :boolean , { :default => true }],
763
774
  [ :shipping_unit_value , :numeric ],
764
775
  [ :flat_rate_shipping , :boolean , { :default => false }],
765
776
  [ :flat_rate_shipping_package_id , :integer ],
@@ -796,6 +807,8 @@ class Caboose::Schema < Caboose::Utilities::Schema
796
807
  # end
797
808
  # c.remove_column(:pages, :content)
798
809
  #end
810
+
811
+ #c.change_column :store_variants, :taxable, :boolean
799
812
 
800
813
  admin_user = nil
801
814
  if !Caboose::User.exists?(:username => 'admin')
@@ -23,5 +23,23 @@ if sc.auto_ga_js && sc.google_analytics_id
23
23
  ga('send', 'event'<% arr2.each do |x| %>, <%= raw Caboose.json(x) %><% end %>);
24
24
  <% end %>
25
25
  <% end %>
26
+ <% if sc.google_analytics_id2 && sc.google_analytics_id2.strip.length > 0 %>
27
+ ga('create', '<%= raw sc.google_analytics_id2 %>', 'auto', {'name': 'property2'});
28
+ ga('property2.send', 'pageview');
29
+ <% if ga_events && ga_events.count > 0 %>
30
+ <% ga_events.each do |arr| %>
31
+ <%
32
+ cat = arr[0] ? arr[0] : nil
33
+ action = arr[1] ? arr[1] : nil
34
+ label = arr[2] ? arr[2] : nil
35
+ value = arr[3] ? arr[3] : nil
36
+ arr2 = [cat, action]
37
+ arr2 << (label ? label : '') if label || (label.nil? && value)
38
+ arr2 << value if value
39
+ %>
40
+ ga('property2.send', 'event'<% arr2.each do |x| %>, <%= raw Caboose.json(x) %><% end %>);
41
+ <% end %>
42
+ <% end %>
43
+ <% end %>
26
44
  </script>
27
45
  <% end %>