fat_free_crm 0.13.0 → 0.13.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fat_free_crm might be problematic. Click here for more details.

Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/Capfile +1 -4
  3. data/Gemfile.lock +0 -1
  4. data/README.md +1 -0
  5. data/app/assets/javascripts/lists.js.coffee +1 -2
  6. data/app/controllers/application_controller.rb +27 -25
  7. data/app/controllers/emails_controller.rb +1 -30
  8. data/app/controllers/entities/contacts_controller.rb +1 -1
  9. data/app/controllers/entities/opportunities_controller.rb +1 -1
  10. data/app/controllers/entities_controller.rb +0 -1
  11. data/app/controllers/home_controller.rb +0 -4
  12. data/app/controllers/passwords_controller.rb +3 -3
  13. data/app/controllers/tasks_controller.rb +17 -10
  14. data/app/controllers/users_controller.rb +23 -46
  15. data/app/helpers/application_helper.rb +0 -3
  16. data/app/helpers/campaigns_helper.rb +0 -1
  17. data/app/helpers/leads_helper.rb +0 -11
  18. data/app/helpers/opportunities_helper.rb +0 -1
  19. data/app/helpers/tags_helper.rb +0 -8
  20. data/app/helpers/versions_helper.rb +1 -1
  21. data/app/models/entities/account_contact.rb +1 -1
  22. data/app/models/entities/campaign.rb +3 -3
  23. data/app/models/entities/contact.rb +3 -3
  24. data/app/models/entities/lead.rb +5 -5
  25. data/app/models/entities/opportunity.rb +1 -3
  26. data/app/models/fields/field_group.rb +1 -0
  27. data/app/models/list.rb +2 -1
  28. data/app/models/polymorphic/avatar.rb +1 -1
  29. data/app/models/polymorphic/task.rb +7 -4
  30. data/app/models/setting.rb +0 -3
  31. data/app/models/users/ability.rb +13 -2
  32. data/app/models/users/user.rb +4 -1
  33. data/app/views/home/index.html.haml +0 -4
  34. data/app/views/layouts/application.html.haml +7 -5
  35. data/app/views/leads/_contact.html.haml +0 -3
  36. data/app/views/lists/_personal_sidebar.html.haml +2 -2
  37. data/app/views/lists/_sidebar.html.haml +2 -2
  38. data/config/application.rb +2 -2
  39. data/config/environments/development.rb +2 -0
  40. data/config/environments/production.rb +2 -3
  41. data/config/initializers/secret_token.rb +25 -1
  42. data/config/locales/en-US_fat_free_crm.yml +1 -1
  43. data/config/routes.rb +27 -32
  44. data/config/settings.default.yml +3 -4
  45. data/lib/development_tasks/rspec.rake +1 -5
  46. data/lib/fat_free_crm.rb +11 -1
  47. data/lib/fat_free_crm/fields.rb +1 -1
  48. data/lib/fat_free_crm/gem_ext/rails/text_helper.rb +1 -2
  49. data/lib/fat_free_crm/secret_token_generator.rb +59 -0
  50. data/lib/fat_free_crm/version.rb +1 -1
  51. data/spec/controllers/admin/users_controller_spec.rb +1 -3
  52. data/spec/controllers/home_controller_spec.rb +0 -7
  53. data/spec/controllers/passwords_controller_spec.rb +23 -5
  54. data/spec/controllers/users_controller_spec.rb +45 -17
  55. data/spec/lib/secret_token_generator_spec.rb +55 -0
  56. data/spec/models/users/abilities/user_ability_spec.rb +58 -0
  57. data/spec/routing/emails_routing_spec.rb +13 -14
  58. data/spec/spec_helper.rb +2 -1
  59. metadata +5 -2
@@ -302,7 +302,6 @@ module ApplicationHelper
302
302
  args = { :class => 'gravatar', :size => :large }.merge(args)
303
303
 
304
304
  if model.respond_to?(:avatar) and model.avatar.present?
305
- Avatar
306
305
  image_tag(model.avatar.image.url(args[:size]), args)
307
306
  else
308
307
  args = Avatar.size_from_style!(args) # convert size format :large => '75x75'
@@ -400,7 +399,6 @@ module ApplicationHelper
400
399
  check_box_tag("#{name}[]", value, checked, :id => value, :onclick => onclick)
401
400
  end
402
401
 
403
-
404
402
  # Create a column in the 'asset_attributes' table.
405
403
  #----------------------------------------------------------------------------
406
404
  def col(title, value, last = false, email = false)
@@ -493,5 +491,4 @@ module ApplicationHelper
493
491
  end
494
492
  end
495
493
 
496
-
497
494
  end
@@ -33,4 +33,3 @@ module CampaignsHelper
33
33
  "#{t(campaign.status)}, " << [ status, metrics ].map { |str| strip_tags(str) }.join(' ').gsub("\n", '')
34
34
  end
35
35
  end
36
-
@@ -53,16 +53,6 @@ module LeadsHelper
53
53
  end
54
54
  end
55
55
 
56
- # Returns default permissions intro for leads.
57
- #----------------------------------------------------------------------------
58
- def get_lead_default_permissions_intro(access)
59
- case access
60
- when "Private" then t(:lead_permissions_intro_private, t(:opportunity_small))
61
- when "Public" then t(:lead_permissions_intro_public, t(:opportunity_small))
62
- when "Shared" then t(:lead_permissions_intro_shared, t(:opportunity_small))
63
- end
64
- end
65
-
66
56
  # Do not offer :converted status choice if we are creating a new lead or
67
57
  # editing existing lead that hasn't been converted before.
68
58
  #----------------------------------------------------------------------------
@@ -93,4 +83,3 @@ module LeadsHelper
93
83
  summary.join(', ')
94
84
  end
95
85
  end
96
-
@@ -31,4 +31,3 @@ module OpportunitiesHelper
31
31
  summary.compact.join(', ')
32
32
  end
33
33
  end
34
-
@@ -28,12 +28,4 @@ module TagsHelper
28
28
  end.html_safe
29
29
  end
30
30
 
31
- # Generate tag links for the asset landing page (shown on a sidebar).
32
- #----------------------------------------------------------------------------
33
- def tags_for_show(model)
34
- model.tag_list.inject([]) do |arr, tag|
35
- arr << link_to(tag, url_for(:action => "tagged", :id => tag), :title => tag)
36
- end.join(" ").html_safe
37
- end
38
-
39
31
  end
@@ -8,7 +8,7 @@ module VersionsHelper
8
8
  # Parse the changes for each version
9
9
  #----------------------------------------------------------------------------
10
10
  def parse_version(attr_name, change)
11
- if attr_name =~ /^cf_/ and (field = CustomField.where(:name => attr_name).first).present?
11
+ if attr_name =~ /\Acf_/ and (field = CustomField.where(:name => attr_name).first).present?
12
12
  label = field.label
13
13
  first = field.render(change.first)
14
14
  second = field.render(change.second)
@@ -21,7 +21,7 @@ class AccountContact < ActiveRecord::Base
21
21
 
22
22
  has_paper_trail :meta => { :related => :contact }, :ignore => [ :id, :created_at, :updated_at, :contact_id ]
23
23
 
24
- validates :account_id, :presence => true
24
+ validates_presence_of :account_id, :contact_id
25
25
 
26
26
  ActiveSupport.run_load_hooks(:fat_free_crm_account_contact, self)
27
27
  end
@@ -32,7 +32,7 @@
32
32
  class Campaign < ActiveRecord::Base
33
33
  belongs_to :user
34
34
  belongs_to :assignee, :class_name => "User", :foreign_key => :assigned_to
35
- has_many :tasks, :as => :asset, :dependent => :destroy#, :order => 'created_at DESC'
35
+ has_many :tasks, :as => :asset, :dependent => :destroy
36
36
  has_many :leads, :dependent => :destroy, :order => "id DESC"
37
37
  has_many :opportunities, :dependent => :destroy, :order => "id DESC"
38
38
  has_many :emails, :as => :mediator
@@ -42,8 +42,8 @@ class Campaign < ActiveRecord::Base
42
42
  scope :state, ->(filters) {
43
43
  where('status IN (?)' + (filters.delete('other') ? ' OR status IS NULL' : ''), filters)
44
44
  }
45
- scope :created_by, ->(user) { where('user_id = ?' , user.id) }
46
- scope :assigned_to, ->(user) { where('assigned_to = ?', user.id) }
45
+ scope :created_by, ->(user) { where( user_id: user.id ) }
46
+ scope :assigned_to, ->(user) { where( assigned_to: user.id ) }
47
47
 
48
48
  scope :text_search, ->(query) { search('name_cont' => query).result }
49
49
 
@@ -45,7 +45,7 @@ class Contact < ActiveRecord::Base
45
45
  has_one :account, :through => :account_contact
46
46
  has_many :contact_opportunities, :dependent => :destroy
47
47
  has_many :opportunities, :through => :contact_opportunities, :uniq => true, :order => "opportunities.id DESC"
48
- has_many :tasks, :as => :asset, :dependent => :destroy#, :order => 'created_at DESC'
48
+ has_many :tasks, :as => :asset, :dependent => :destroy
49
49
  has_one :business_address, :dependent => :destroy, :as => :addressable, :class_name => "Address", :conditions => "address_type = 'Business'"
50
50
  has_many :addresses, :dependent => :destroy, :as => :addressable, :class_name => "Address" # advanced search uses this
51
51
  has_many :emails, :as => :mediator
@@ -59,8 +59,8 @@ class Contact < ActiveRecord::Base
59
59
 
60
60
  accepts_nested_attributes_for :business_address, :allow_destroy => true, :reject_if => proc {|attributes| Address.reject_address(attributes)}
61
61
 
62
- scope :created_by, ->(user) { where("user_id = ?", user.id) }
63
- scope :assigned_to, ->(user) { where("assigned_to = ?", user.id) }
62
+ scope :created_by, ->(user) { where( user_id: user.id ) }
63
+ scope :assigned_to, ->(user) { where( assigned_to: user.id ) }
64
64
 
65
65
  scope :text_search, ->(query) {
66
66
  t = Contact.arel_table
@@ -41,7 +41,7 @@ class Lead < ActiveRecord::Base
41
41
  belongs_to :campaign
42
42
  belongs_to :assignee, :class_name => "User", :foreign_key => :assigned_to
43
43
  has_one :contact, :dependent => :nullify # On destroy keep the contact, but nullify its lead_id
44
- has_many :tasks, :as => :asset, :dependent => :destroy#, :order => 'created_at DESC'
44
+ has_many :tasks, :as => :asset, :dependent => :destroy
45
45
  has_one :business_address, :dependent => :destroy, :as => :addressable, :class_name => "Address", :conditions => "address_type='Business'"
46
46
  has_many :addresses, :dependent => :destroy, :as => :addressable, :class_name => "Address" # advanced search uses this
47
47
  has_many :emails, :as => :mediator
@@ -53,10 +53,10 @@ class Lead < ActiveRecord::Base
53
53
  scope :state, ->(filters) {
54
54
  where([ 'status IN (?)' + (filters.delete('other') ? ' OR status IS NULL' : ''), filters ])
55
55
  }
56
- scope :converted, -> { where(:status => 'converted') }
57
- scope :for_campaign, ->(id) { where('campaign_id = ?', id) }
58
- scope :created_by, ->(user) { where('user_id = ?' , user.id) }
59
- scope :assigned_to, ->(user) { where('assigned_to = ?' , user.id) }
56
+ scope :converted, -> { where( status: 'converted' ) }
57
+ scope :for_campaign, ->(id) { where( campaign_id: id ) }
58
+ scope :created_by, ->(user) { where( user_id: user.id ) }
59
+ scope :assigned_to, ->(user) { where( assigned_to: user.id ) }
60
60
 
61
61
  scope :text_search, ->(query) { search('first_name_or_last_name_or_company_or_email_cont' => query).result }
62
62
 
@@ -51,9 +51,7 @@ class Opportunity < ActiveRecord::Base
51
51
 
52
52
  # Search by name OR id
53
53
  scope :text_search, ->(query) {
54
- # postgresql does not like to compare string to integer field
55
- if query =~ /^\d+$/
56
- query = query.gsub(/[^\w\s\-\.'\p{L}]/u, '').strip
54
+ if query =~ /\A\d+\z/
57
55
  where('upper(name) LIKE upper(:name) OR opportunities.id = :id', :name => "%#{query}%", :id => query)
58
56
  else
59
57
  search('name_cont' => query).result
@@ -46,6 +46,7 @@ class FieldGroup < ActiveRecord::Base
46
46
  end
47
47
 
48
48
  private
49
+
49
50
  # Can't delete default field group
50
51
  def not_default_field_group
51
52
  name != "custom_fields"
data/app/models/list.rb CHANGED
@@ -9,7 +9,8 @@ class List < ActiveRecord::Base
9
9
 
10
10
  # Parses the controller from the url
11
11
  def controller
12
- (url || "").sub(/^\//,'').split(/\/|\?/).first
12
+ (url || "").sub(/\A\//,'').split(/\/|\?/).first
13
13
  end
14
+
14
15
  ActiveSupport.run_load_hooks(:fat_free_crm_list, self)
15
16
  end
@@ -45,7 +45,7 @@ class Avatar < ActiveRecord::Base
45
45
  if options[:width] && options[:height]
46
46
  options[:size] = [:width, :height].map{|d| options[d]}.join("x")
47
47
  elsif Avatar::STYLES.keys.include?(options[:size])
48
- options[:size] = Avatar::STYLES[options[:size]].sub(/\#$/,'')
48
+ options[:size] = Avatar::STYLES[options[:size]].sub(/\#\z/,'')
49
49
  end
50
50
  options
51
51
  end
@@ -27,6 +27,7 @@
27
27
 
28
28
  class Task < ActiveRecord::Base
29
29
  attr_accessor :calendar
30
+ ALLOWED_VIEWS = %w(pending assigned completed)
30
31
 
31
32
  belongs_to :user
32
33
  belongs_to :assignee, :class_name => "User", :foreign_key => :assigned_to
@@ -46,8 +47,8 @@ class Task < ActiveRecord::Base
46
47
  limit(options[:limit]) # nil selects all records
47
48
  }
48
49
 
49
- scope :created_by, ->(user) { where(:user_id => user.id) }
50
- scope :assigned_to, ->(user) { where(:assigned_to => user.id) }
50
+ scope :created_by, ->(user) { where( user_id: user.id ) }
51
+ scope :assigned_to, ->(user) { where( assigned_to: user.id ) }
51
52
 
52
53
  # Tasks assigned by the user to others. That's what we see on Tasks/Assigned.
53
54
  scope :assigned_by, ->(user) {
@@ -62,8 +63,8 @@ class Task < ActiveRecord::Base
62
63
  where('user_id = ? OR assigned_to = ?', user.id, user.id)
63
64
  }
64
65
 
66
+ # Show opportunities which either belong to the user and are unassigned, or are assigned to the user
65
67
  scope :visible_on_dashboard, ->(user) {
66
- # Show opportunities which either belong to the user and are unassigned, or are assigned to the user
67
68
  where('(user_id = :user_id AND assigned_to IS NULL) OR assigned_to = :user_id', :user_id => user.id).where('completed_at IS NULL')
68
69
  }
69
70
 
@@ -171,6 +172,7 @@ class Task < ActiveRecord::Base
171
172
  # Returns list of tasks grouping them by due date as required by tasks/index.
172
173
  #----------------------------------------------------------------------------
173
174
  def self.find_all_grouped(user, view)
175
+ return {} unless ALLOWED_VIEWS.include?(view)
174
176
  settings = (view == "completed" ? Setting.task_completed : Setting.task_bucket)
175
177
  Hash[
176
178
  settings.map do |key, value|
@@ -182,7 +184,7 @@ class Task < ActiveRecord::Base
182
184
  # Returns bucket if it's empty (i.e. we have to hide it), nil otherwise.
183
185
  #----------------------------------------------------------------------------
184
186
  def self.bucket_empty?(bucket, user, view = "pending")
185
- return false if bucket.blank?
187
+ return false if bucket.blank? or !ALLOWED_VIEWS.include?(view)
186
188
  if view == "assigned"
187
189
  assigned_by(user).send(bucket).pending.count
188
190
  else
@@ -193,6 +195,7 @@ class Task < ActiveRecord::Base
193
195
  # Returns task totals for each of the views as needed by tasks sidebar.
194
196
  #----------------------------------------------------------------------------
195
197
  def self.totals(user, view = "pending")
198
+ return {} unless ALLOWED_VIEWS.include?(view)
196
199
  settings = (view == "completed" ? Setting.task_completed : Setting.task_bucket)
197
200
  settings.inject({ :all => 0 }) do |hash, key|
198
201
  hash[key] = (view == "assigned" ? assigned_by(user).send(key).pending.count : my(user).send(key).send(view).count)
@@ -71,7 +71,6 @@ class Setting < ActiveRecord::Base
71
71
  end
72
72
  end
73
73
 
74
-
75
74
  # Set setting value
76
75
  #-------------------------------------------------------------------
77
76
  def []=(name, value)
@@ -82,7 +81,6 @@ class Setting < ActiveRecord::Base
82
81
  cache[name] = value
83
82
  end
84
83
 
85
-
86
84
  # Unrolls [ :one, :two ] settings array into [[ "One", :one ], [ "Two", :two ]]
87
85
  # picking symbol translations from locale. If setting is not a symbol but
88
86
  # string it gets copied without translation.
@@ -98,7 +96,6 @@ class Setting < ActiveRecord::Base
98
96
  table_exists? rescue false
99
97
  end
100
98
 
101
-
102
99
  # Loads settings from YAML files
103
100
  def load_settings_from_yaml(file)
104
101
  settings = YAML.load_file(file)
@@ -9,11 +9,22 @@ class Ability
9
9
  include CanCan::Ability
10
10
 
11
11
  def initialize(user)
12
+
13
+ # handle signup
14
+ can(:create, User) if User.can_signup?
15
+
12
16
  if user.present?
13
17
  entities = [Account, Campaign, Contact, Lead, Opportunity]
14
18
 
15
- can :create, :all
16
- can :read, [User] # for search autocomplete
19
+ # User
20
+ can :manage, User, id: user.id # can do any action on themselves
21
+
22
+ # Tasks
23
+ can :create, Task
24
+ can :manage, Task, user: user.id
25
+ can :manage, Task, assigned_to: user.id
26
+
27
+ # Entities
17
28
  can :manage, entities, :access => 'Public'
18
29
  can :manage, entities + [Task], :user_id => user.id
19
30
  can :manage, entities + [Task], :assigned_to => user.id
@@ -61,7 +61,6 @@ class User < ActiveRecord::Base
61
61
 
62
62
  has_paper_trail :ignore => [:last_request_at, :perishable_token]
63
63
 
64
- # For some reason this does not play nice with has_paper_trail when set as default scope
65
64
  scope :by_id, -> { order('id DESC') }
66
65
  scope :except, ->(user) { where('id != ?', user.id).by_name }
67
66
  scope :by_name, -> { order('first_name, last_name, email') }
@@ -188,6 +187,10 @@ class User < ActiveRecord::Base
188
187
  Ability.new(User.current_user)
189
188
  end
190
189
 
190
+ def can_signup?
191
+ [ :allowed, :needs_approval ].include? Setting.user_signup
192
+ end
193
+
191
194
  end
192
195
 
193
196
  ActiveSupport.run_load_hooks(:fat_free_crm_user, self)
@@ -44,7 +44,3 @@
44
44
 
45
45
 
46
46
  #export= render "shared/export"
47
- /
48
- Check out HTML source to view the output of the hook if you have sample plugin installed
49
- http://github.com/michaeldv/crm_sample_plugin/tree/master
50
- = hook(:home_view, self, :hello => "world!", :welcome => "home")
@@ -21,13 +21,15 @@
21
21
 
22
22
  :javascript
23
23
  crm.language = "#{I18n.locale}"
24
- #{yield :javascript}
25
- var _ffcrm_users = [
26
- #{User.all.map{|u| "\"#{u.full_name} (@#{u.username})\"" }.join(",\n")}
27
- ];
28
-
29
24
  window.controller = "#{controller.controller_name}"
30
25
 
26
+ - if current_user.present?
27
+ :javascript
28
+ #{yield :javascript}
29
+ var _ffcrm_users = [
30
+ #{User.all.map{|u| "\"#{u.full_name} (@#{u.username})\"" }.join(",\n")}
31
+ ];
32
+
31
33
  <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
32
34
  <link rel="icon" href="/favicon.ico" type="image/x-icon">
33
35
 
@@ -33,6 +33,3 @@
33
33
  .check_box
34
34
  = f.check_box :do_not_call, {}, true
35
35
  #{t :do_not_call}
36
-
37
-
38
-
@@ -8,8 +8,8 @@
8
8
  - else
9
9
  - @personal_lists.sort.each_with_index do |list, i|
10
10
  %li[list]{ :class => i < @personal_lists.size - 1 ? "" : "last" }
11
- %dt= link_to(truncate(list.name, :length => 25), list.url, :title => list.name)
12
- %tt
11
+ %dt= link_to(truncate(list.name, :length => 25), h(list.url), :title => list.name)
12
+ %tt
13
13
  = link_to(url_for(list), :method => :delete, :confirm => 'Are you sure?', :remote => true, :class => "list_icon delete_on_hover") do
14
14
  %i.fa{:"data-controller" => list.controller, class: get_icon(list.controller)}
15
15
 
@@ -8,8 +8,8 @@
8
8
  - else
9
9
  - @global_lists.sort.each_with_index do |list, i|
10
10
  %li[list]{ :class => i < @global_lists.size - 1 ? "" : "last" }
11
- %dt= link_to(truncate(list.name, :length => 25), list.url, :title => list.name)
12
- %tt
11
+ %dt= link_to(truncate(list.name, :length => 25), h(list.url), :title => list.name)
12
+ %tt
13
13
  = link_to(url_for(list), :method => :delete, :confirm => 'Are you sure?', :remote => true, :class => "list_icon delete_on_hover") do
14
14
  %i.fa{:"data-controller" => list.controller, class: get_icon(list.controller)}
15
15
 
@@ -28,7 +28,7 @@ module FatFreeCRM
28
28
  config.autoload_paths += Dir[Rails.root.join("app/models/**")] +
29
29
  Dir[Rails.root.join("app/controllers/entities")]
30
30
 
31
- # Prevent Field class from being reloading more than once as this clears registered customfields
31
+ # Prevent Field class from being reloaded more than once as this clears registered customfields
32
32
  config.autoload_once_paths += [File.expand_path("../app/models/fields/field.rb", __FILE__)]
33
33
 
34
34
  # Activate observers that should always be running.
@@ -62,7 +62,7 @@ module FatFreeCRM
62
62
  config.encoding = "utf-8"
63
63
 
64
64
  # Configure sensitive parameters which will be filtered from the log file.
65
- config.filter_parameters += [:password]
65
+ config.filter_parameters += [:password, :password_hash, :password_salt, :password_confirmation]
66
66
 
67
67
  # Use SQL instead of Active Record's schema dumper when creating the database.
68
68
  # This is necessary if your schema can't be completely dumped by the schema dumper,
@@ -19,6 +19,8 @@ if defined?(FatFreeCRM::Application)
19
19
  config.consider_all_requests_local = true
20
20
  config.action_controller.perform_caching = false
21
21
 
22
+ config.action_mailer.delivery_method = :file
23
+
22
24
  # Don't care if the mailer can't send
23
25
  config.action_mailer.raise_delivery_errors = true
24
26
 
@@ -10,9 +10,8 @@ if defined?(FatFreeCRM::Application)
10
10
  # Code is not reloaded between requests
11
11
  config.cache_classes = true
12
12
 
13
- # Full error reports are enabled, since this is an internal application.
14
- config.consider_all_requests_local = true
15
- # Caching is turned on
13
+ # Full error reports are disabled and caching is turned on.
14
+ config.consider_all_requests_local = false
16
15
  config.action_controller.perform_caching = true
17
16
 
18
17
  # Disable Rails's static asset server (Apache or nginx will already do this)
@@ -1 +1,25 @@
1
- FatFreeCRM::Application.config.secret_token = 'be17625f6b1d92df0ed33a3ea57905ed321ef6089c213f23b2dff44a9b236d836b854451068ae030741b182d29ac25c5dbd075c993cabfd624d825e66e073071'
1
+ # Copyright (c) 2008-2013 Michael Dvorkin and contributors.
2
+ #
3
+ # Fat Free CRM is freely distributable under the terms of MIT license.
4
+ # See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
5
+ #------------------------------------------------------------------------------
6
+
7
+ # Be sure to restart your server when you modify this file.
8
+
9
+ # Your secret key is used for verifying the integrity of signed cookies.
10
+ # If you change this key, all old signed cookies will become invalid!
11
+
12
+ # Make sure the secret is at least 30 characters and all random,
13
+ # no regular words or you'll be exposed to dictionary attacks.
14
+ # You can use `rake secret` to generate a secure secret key.
15
+
16
+ # Make sure your secret_key_base is kept private
17
+ # if you're sharing your code publicly.
18
+
19
+ #
20
+ # We should setup a secret token if FFCRM is running in application mode but NOT in engine mode.
21
+ # This functionality has been extracted to lib so it can be tested.
22
+ if FatFreeCRM.application?
23
+ require 'fat_free_crm/secret_token_generator'
24
+ FatFreeCRM::SecretTokenGenerator.setup!
25
+ end