fat_free_crm 0.22.0 → 0.23.0

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.

Potentially problematic release.


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

Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/application.js.erb +1 -0
  3. data/app/assets/javascripts/crm.js.coffee +6 -3
  4. data/app/assets/javascripts/crm_select2.js.coffee +4 -1
  5. data/app/assets/javascripts/crm_tags.js.coffee +4 -4
  6. data/app/assets/javascripts/crm_textarea_autocomplete.js.coffee +6 -9
  7. data/app/assets/javascripts/crm_validations.js.coffee +12 -0
  8. data/app/assets/stylesheets/bootstrap-custom.scss +3 -3
  9. data/app/assets/stylesheets/common.scss +9 -0
  10. data/app/assets/stylesheets/rails.scss +1 -1
  11. data/app/controllers/admin/fields_controller.rb +16 -13
  12. data/app/controllers/application_controller.rb +1 -1
  13. data/app/controllers/emails_controller.rb +1 -1
  14. data/app/controllers/entities/contacts_controller.rb +1 -1
  15. data/app/controllers/entities_controller.rb +1 -1
  16. data/app/controllers/lists_controller.rb +5 -4
  17. data/app/controllers/users_controller.rb +15 -3
  18. data/app/helpers/application_helper.rb +5 -5
  19. data/app/helpers/leads_helper.rb +1 -1
  20. data/app/helpers/opportunities_helper.rb +5 -3
  21. data/app/helpers/users_helper.rb +1 -1
  22. data/app/models/entities/campaign.rb +3 -3
  23. data/app/models/fields/custom_field_pair.rb +6 -7
  24. data/app/models/fields/field.rb +1 -3
  25. data/app/models/list.rb +1 -1
  26. data/app/models/observers/lead_observer.rb +2 -1
  27. data/app/models/observers/task_observer.rb +2 -1
  28. data/app/models/polymorphic/address.rb +2 -1
  29. data/app/models/polymorphic/comment.rb +3 -4
  30. data/app/models/polymorphic/task.rb +1 -1
  31. data/app/models/users/user.rb +7 -1
  32. data/app/views/accounts/_contact_info.html.haml +1 -1
  33. data/app/views/accounts/_top_section.html.haml +3 -3
  34. data/app/views/accounts/show.js.haml +1 -1
  35. data/app/views/accounts/update.js.haml +1 -0
  36. data/app/views/admin/custom_fields/_check_boxes_field.html.haml +4 -1
  37. data/app/views/admin/custom_fields/_date_pair_field.html.haml +1 -1
  38. data/app/views/campaigns/_top_section.html.haml +2 -2
  39. data/app/views/campaigns/show.js.haml +1 -1
  40. data/app/views/campaigns/update.js.haml +1 -0
  41. data/app/views/contacts/_top_section.html.haml +5 -5
  42. data/app/views/contacts/show.js.haml +2 -3
  43. data/app/views/contacts/update.js.haml +1 -0
  44. data/app/views/devise/sessions/new.html.haml +4 -5
  45. data/app/views/fields/_group.html.haml +5 -2
  46. data/app/views/fields/_group_table.html.haml +4 -5
  47. data/app/views/fields/_group_view.html.haml +4 -1
  48. data/app/views/fields/_sidebar_show.html.haml +5 -8
  49. data/app/views/fields/group.js.erb +3 -1
  50. data/app/views/layouts/application.html.haml +2 -4
  51. data/app/views/leads/_top_section.html.haml +4 -4
  52. data/app/views/leads/show.js.haml +1 -1
  53. data/app/views/leads/update.js.haml +1 -0
  54. data/app/views/opportunities/_top_section.html.haml +2 -2
  55. data/app/views/opportunities/show.js.haml +1 -1
  56. data/app/views/opportunities/update.js.haml +1 -0
  57. data/app/views/shared/_add_comment.html.haml +1 -1
  58. data/app/views/shared/_address.html.haml +1 -1
  59. data/app/views/tasks/_top_section.html.haml +4 -4
  60. data/config/application.rb +2 -0
  61. data/config/database.yml +9 -12
  62. data/config/environments/development.rb +15 -0
  63. data/config/initializers/action_mailer.rb +1 -1
  64. data/config/initializers/application_controller_renderer.rb +1 -0
  65. data/config/initializers/backtrace_silencers.rb +1 -0
  66. data/config/initializers/content_security_policy.rb +1 -0
  67. data/config/initializers/custom_field_ransack_translations.rb +2 -2
  68. data/config/initializers/devise.rb +1 -0
  69. data/config/initializers/inflections.rb +1 -0
  70. data/config/initializers/permissions_policy.rb +1 -0
  71. data/config/routes.rb +1 -3
  72. data/config/settings.default.yml +2 -1
  73. data/db/fat_free_crm_development.sqlite3 +0 -0
  74. data/db/fat_free_crm_test.sqlite3 +0 -0
  75. data/db/migrate/20230422234321_optionally_create_action_text_tables.action_text.rb +29 -0
  76. data/db/migrate/20230526211831_create_active_storage_tables.active_storage.rb +3 -3
  77. data/db/migrate/20230526212613_convert_to_active_storage.rb +11 -14
  78. data/db/schema.rb +16 -9
  79. data/db/seeds.rb +1 -0
  80. data/lib/fat_free_crm/callback.rb +0 -1
  81. data/lib/fat_free_crm/core_ext/string.rb +1 -1
  82. data/lib/fat_free_crm/custom_fields.rb +1 -0
  83. data/lib/fat_free_crm/mail_processor/base.rb +6 -10
  84. data/lib/fat_free_crm/version.rb +1 -1
  85. metadata +7 -31
  86. data/public/avatars/User/2/large_rails.png +0 -0
  87. data/public/avatars/User/2/medium_rails.png +0 -0
  88. data/public/avatars/User/2/original_rails.png +0 -0
  89. data/public/avatars/User/2/small_rails.png +0 -0
  90. data/public/avatars/User/2/thumb_rails.png +0 -0
  91. data/public/avatars/User/3/large_rails.png +0 -0
  92. data/public/avatars/User/3/medium_rails.png +0 -0
  93. data/public/avatars/User/3/original_rails.png +0 -0
  94. data/public/avatars/User/3/small_rails.png +0 -0
  95. data/public/avatars/User/3/thumb_rails.png +0 -0
  96. data/public/avatars/User/4/large_rails.png +0 -0
  97. data/public/avatars/User/4/medium_rails.png +0 -0
  98. data/public/avatars/User/4/original_rails.png +0 -0
  99. data/public/avatars/User/4/small_rails.png +0 -0
  100. data/public/avatars/User/4/thumb_rails.png +0 -0
  101. data/public/avatars/User/6/large_rails.png +0 -0
  102. data/public/avatars/User/6/medium_rails.png +0 -0
  103. data/public/avatars/User/6/original_rails.png +0 -0
  104. data/public/avatars/User/6/small_rails.png +0 -0
  105. data/public/avatars/User/6/thumb_rails.png +0 -0
  106. data/public/avatars/User/7/large_rails.png +0 -0
  107. data/public/avatars/User/7/medium_rails.png +0 -0
  108. data/public/avatars/User/7/original_rails.png +0 -0
  109. data/public/avatars/User/7/small_rails.png +0 -0
  110. data/public/avatars/User/7/thumb_rails.png +0 -0
@@ -7,6 +7,7 @@
7
7
  crm.flip_form('edit_#{entity_name}');
8
8
  crm.set_title('edit_#{entity_name}', '#{j @entity.name}');
9
9
  = refresh_sidebar(:show)
10
+ $('#summary').html('#{ j (render partial: "#{entity_name.pluralize}/sidebar_show", entity_name => @entity) }');
10
11
  - else
11
12
  $('##{id}').replaceWith('#{ j render(partial: entity_name, collection: [ @entity ]) }');
12
13
  $('##{id}').effect("highlight", { duration:1500 });
@@ -1,6 +1,9 @@
1
1
  %div
2
2
  .label.top.req
3
3
  = "Select Options (pipe separated):"
4
- = f.text_field :collection_string, class: 'field_collection_string', size: 78
4
+ = f.text_field :collection_string, class: 'field_collection_string', size: 78, placeholder: "Option 1|Option 2|Option 3"
5
5
 
6
6
  = render partial: 'admin/custom_fields/base_field', locals: {f: f}
7
+
8
+ - if f.object.new_record?
9
+ .info2 After saving, you must restart all instances of the Rails server to apply column serialization.
@@ -1,5 +1,5 @@
1
1
  - field1 = f.object || CustomFieldPair.new
2
- - field2 = f.object.respond_to?(:paired_with) ? field1.paired_with : CustomFieldPair.new
2
+ - field2 = (field1.pair || CustomFieldPair.new)
3
3
 
4
4
  %table{class: :pairs}
5
5
  = fields_for("pair[0]", field1) do |first|
@@ -2,9 +2,9 @@
2
2
  .section
3
3
  %table
4
4
  %tr
5
- %td(colspan="5")
5
+ %td{class: (@campaign.errors['name'].present? ? 'fieldWithErrors' : nil)}(colspan="5")
6
6
  .label.top.req #{t :name}:
7
- = f.text_field :name, autofocus: true, style: "width:500px"
7
+ = f.text_field :name, autofocus: true, style: "width:500px", required: "required"
8
8
  %tr
9
9
  %td
10
10
  .label #{t :start_date}:
@@ -1,5 +1,5 @@
1
1
  - entity_name = controller.controller_name.singularize.underscore #account
2
2
  - @entity = instance_variable_get("@#{entity_name}")
3
3
 
4
- $('#main').html('#{ j (render template: "#{entity_name.pluralize}/show.html", entity_name => @entity) }');
4
+ $('#main').html('#{ j (render template: "#{entity_name.pluralize}/show", formats: [:html], entity_name => @entity) }');
5
5
  = raw generate_js_for_popups(@entity, :tasks, :leads, :opportunities)
@@ -7,6 +7,7 @@
7
7
  crm.flip_form('edit_#{entity_name}');
8
8
  crm.set_title('edit_#{entity_name}', '#{h @entity.name}');
9
9
  = refresh_sidebar(:show)
10
+ $('#summary').html('#{ j (render partial: "#{entity_name.pluralize}/sidebar_show", entity_name => @entity) }');
10
11
  - else
11
12
  $('##{id}').replaceWith('#{ j render(partial: entity_name, collection: [ @entity ]) }');
12
13
  $('##{id}').effect("highlight", { duration:1500 });
@@ -3,13 +3,13 @@
3
3
  .section
4
4
  %table
5
5
  %tr
6
- %td
7
- .label.top.req{ class: "#{Setting.require_first_names ? 'req' : nil}" } #{t :first_name}:
8
- = f.text_field :first_name, autofocus: true
6
+ %td{class: (@contact.errors['first_name'].present? ? 'fieldWithErrors' : nil)}
7
+ .label.top{ class: "#{Setting.require_first_names ? 'req' : nil}" } #{t :first_name}:
8
+ = f.text_field :first_name, autofocus: true, required: (Setting.require_first_names ? "required" : nil)
9
9
  %td= spacer
10
- %td
10
+ %td{class: (@contact.errors['last_name'].present? ? 'fieldWithErrors' : nil)}
11
11
  .label.top{ class: "#{Setting.require_last_names ? 'req' : nil}" } #{t :last_name}:
12
- = f.text_field :last_name
12
+ = f.text_field :last_name, required: (Setting.require_last_names ? "required" : nil)
13
13
  %tr
14
14
  %td
15
15
  .label #{t :email}:
@@ -1,5 +1,4 @@
1
- - entity_name = controller.controller_name.singularize.underscore #account
1
+ - entity_name = controller.controller_name.singularize.underscore
2
2
  - @entity = instance_variable_get("@#{entity_name}")
3
-
4
- $('#main').html('#{ j (render template: "#{entity_name.pluralize}/show.html", entity_name => @entity) }');
3
+ $('#main').html('#{ j (render template: "#{entity_name.pluralize}/show", formats: [:html], entity_name => @entity) }');
5
4
  = raw generate_js_for_popups(@entity, :tasks, :opportunities)
@@ -8,6 +8,7 @@
8
8
  crm.flip_form('edit_#{entity_name}');
9
9
  crm.set_title('edit_#{entity_name}', '#{h @entity.full_name}');
10
10
  = refresh_sidebar(:show)
11
+ $('#summary').html('#{ j (render partial: "#{entity_name.pluralize}/sidebar_show", entity_name => @entity) }');
11
12
  - else
12
13
  $('##{id}').replaceWith('#{ j render(partial: entity_name, collection: [ @entity ]) }');
13
14
  $('##{id}').effect("highlight", { duration:1500 });
@@ -23,10 +23,9 @@
23
23
  .label= t(:password)
24
24
  = f.input_field :password
25
25
 
26
- %div(style="margin-left:12px")
26
+ .section
27
27
  = f.input :remember_me, as: :boolean, inline_label: t('remember_me')
28
- %br
29
- .buttonbar
30
- = f.submit t(:login)
31
- = t(:or)
28
+ = f.submit t(:login), class: 'btn btn-primary'
29
+
30
+ .section
32
31
  = link_to t(:forgot_password) + '?', new_password_path(resource_name)
@@ -1,6 +1,9 @@
1
1
  - if field_group.name != 'custom_fields'
2
- -# start a new section
3
- - collapsed = session[field_group.key].nil?
2
+ - # Ensure field groups containing validation errors are expanded
3
+ - required_field_names = field_group.fields.select(&:required?).map(&:name)
4
+ - fields_with_errors = f.object.errors.map{|e| e.attribute.to_s}
5
+ - force_open = (required_field_names & fields_with_errors).any?
6
+ - collapsed = session[field_group.key].nil? && !force_open
4
7
  %div{ id: "#{field_group.key}_container", :"data-tag" => field_group.tag.try(:name) }
5
8
  = subtitle field_group.key, collapsed, t(field_group.name, default: field_group.label)
6
9
  .section
@@ -2,12 +2,11 @@
2
2
  - field_group.fields.without_pairs.in_groups_of(2, false) do |group|
3
3
  %tr
4
4
  - group.each_with_index do |field, i|
5
- %td
5
+ %td{class: (f.object.errors[field.name].present? ? 'fieldWithErrors' : nil)}
6
6
  - if field.hint.present?
7
7
  = image_tag "info_tiny.png", title: field.hint, class: "tooltip-icon"
8
- - if field.as == 'check_boxes'
9
- - value = f.object.send(field.name)
10
- - checked = YAML.load(value.to_s)
11
- = f.input field.name, field.input_options.merge(checked: checked)
8
+ .label.top{class: (field.required? ? 'req': nil)}
9
+ = "#{field.label}:"
10
+ = f.input_field field.name, field.input_options
12
11
  - if i == 0
13
12
  %td= spacer
@@ -4,7 +4,10 @@
4
4
  %tr
5
5
  - group.each do |field|
6
6
  = col(field.label, (i == groups.size - 1) ? :last : nil) do
7
- = field.render_value(entity)
7
+ - if field.as == "text"
8
+ = simple_format(field.render_value(entity))
9
+ - else
10
+ = field.render_value(entity)
8
11
  - if group.size == 1
9
12
  %th.last
10
13
  %td.last
@@ -1,9 +1,6 @@
1
1
  - asset.field_groups.each do |field_group|
2
- - fg = field_group.fields.without_pairs
3
- - if fg.select{|f| asset.send(f.name).present? }.any?
4
- %div
5
- - unless field_group.name == 'custom_fields'
6
- .caption #{field_group.label_i18n}
7
- - fg.each do |field|
8
- - if (value = field.render_value(asset)).present?
9
- == #{field.label}:<br /> <b>#{truncate(value, length: 35)}</b><br />
2
+ - fields = field_group.fields.without_pairs
3
+ - if fields.select{|f| asset.send(f.name).present? }.any?
4
+ - unless field_group.name == 'custom_fields'
5
+ .caption #{field_group.label_i18n}
6
+ = render("fields/group_view", fields: fields, entity: asset) unless fields.nil?
@@ -1,3 +1,5 @@
1
1
  <%= simple_fields_for(@asset) do |f| %>
2
- $('#field_groups').append('<%= j render(partial: 'fields/group', locals: {f: f, field_group: @field_group, fields: @field_group.fields}) %>')
2
+ <% @field_groups.each do |field_group| %>
3
+ $('#field_groups').append('<%= j render(partial: 'fields/group', locals: {f: f, field_group: field_group, fields: field_group.fields}) %>')
4
+ <% end %>
3
5
  <% end %>
@@ -26,9 +26,7 @@
26
26
  - if current_user.present?
27
27
  :javascript
28
28
  #{yield :javascript}
29
- var _ffcrm_users = [
30
- #{raw User.all.map{|u| "'#{j u.full_name} (@#{j u.username})'" }.join(",\n")}
31
- ];
29
+
32
30
 
33
31
  <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
34
32
  <link rel="icon" href="/favicon.ico" type="image/x-icon">
@@ -42,7 +40,7 @@
42
40
  = render "layouts/footer"
43
41
 
44
42
  %script{type: "text/javascript"}
45
- = "crm.base_url = '#{Setting.base_url}';" unless Setting.base_url.blank?
43
+ = "crm.base_url = '#{h Setting.base_url}';".html_safe unless Setting.base_url.blank?
46
44
  = get_browser_timezone_offset
47
45
  = content_for :javascript_epilogue
48
46
  = hook(:javascript_epilogue, self)
@@ -3,13 +3,13 @@
3
3
  .section
4
4
  %table
5
5
  %tr
6
- %td
6
+ %td{ class: (@lead.errors['first_name'].present? ? 'fieldWithErrors' : nil)}
7
7
  .label.top{ class: "#{Setting.require_first_names ? 'req' : nil}" } #{t :first_name}:
8
- = f.text_field :first_name, autofocus: true
8
+ = f.text_field :first_name, autofocus: true, required: (Setting.require_first_names ? "required" : nil)
9
9
  %td= spacer
10
- %td
10
+ %td{ class: (@lead.errors['last_name'].present? ? 'fieldWithErrors' : nil)}
11
11
  .label.top{ class: "#{Setting.require_last_names ? 'req' : nil}" } #{t :last_name}:
12
- = f.text_field :last_name
12
+ = f.text_field :last_name, required: (Setting.require_last_names ? "required" : nil)
13
13
  %tr
14
14
  %td
15
15
  .label #{t :email}:
@@ -1,5 +1,5 @@
1
1
  - entity_name = controller.controller_name.singularize.underscore #account
2
2
  - @entity = instance_variable_get("@#{entity_name}")
3
3
 
4
- $('#main').html('#{ j (render template: "#{entity_name.pluralize}/show.html", entity_name => @entity) }');
4
+ $('#main').html('#{ j (render template: "#{entity_name.pluralize}/show", formats: [:html], entity_name => @entity) }');
5
5
  = raw generate_js_for_popups(@entity, :tasks)
@@ -7,6 +7,7 @@
7
7
  crm.flip_form('edit_#{entity_name}');
8
8
  crm.set_title('edit_#{entity_name}', '#{h @entity.full_name}');
9
9
  = refresh_sidebar(:show)
10
+ $('#summary').html('#{ j (render partial: "#{entity_name.pluralize}/sidebar_show", entity_name => @entity) }');
10
11
  - else
11
12
  $('##{id}').replaceWith('#{ j render(partial: entity_name, collection: [ @entity ]) }');
12
13
  $('##{id}').effect("highlight", { duration:1500 });
@@ -2,9 +2,9 @@
2
2
  .section
3
3
  %table
4
4
  %tr
5
- %td
5
+ %td{class: (@opportunity.errors['name'].present? ? 'fieldWithErrors' : nil)}
6
6
  .label.req.top #{t :name}:
7
- = f.text_field :name, autofocus: true, style: "width:325px"
7
+ = f.text_field :name, autofocus: true, style: "width:325px", required: "required"
8
8
  %td= spacer
9
9
  %td
10
10
  .label.req.top #{t :stage}:
@@ -1,5 +1,5 @@
1
1
  - entity_name = controller.controller_name.singularize.underscore #account
2
2
  - @entity = instance_variable_get("@#{entity_name}")
3
3
 
4
- $('#main').html('#{ j (render template: "#{entity_name.pluralize}/show.html", entity_name => @entity) }');
4
+ $('#main').html('#{ j (render template: "#{entity_name.pluralize}/show", formats: [:html], entity_name => @entity) }');
5
5
  = raw generate_js_for_popups(@entity, :tasks, :contacts)
@@ -7,6 +7,7 @@
7
7
  crm.flip_form('edit_#{entity_name}');
8
8
  crm.set_title('edit_#{entity_name}', '#{h @entity.name}');
9
9
  = refresh_sidebar(:show)
10
+ $('#summary').html('#{ j (render partial: "#{entity_name.pluralize}/sidebar_show", entity_name => @entity) }');
10
11
  - else
11
12
  $('##{id}').replaceWith('#{ j render(partial: entity_name, collection: [ @entity ]) }');
12
13
  $('##{id}').effect("highlight", { duration:1500 });
@@ -1,5 +1,5 @@
1
1
  - edit ||= false
2
- - collapsed = @comment_body.nil? && f.object.errors.empty?
2
+ - collapsed = session[:comment].nil?
3
3
  = subtitle :comment, collapsed, t(:comment)
4
4
  .section
5
5
  %small#comment_intro{ hidden_if(!collapsed) }
@@ -41,4 +41,4 @@
41
41
  = address_field(a, :zipcode, "width:80px;")
42
42
  %td= spacer
43
43
  %td
44
- = a.country_select(:country, priority_countries: priority_countries, include_blank: "", :"data-placeholder" => t(:select_a_country), style: "width:150px; margin-top:6px", class: 'select2')
44
+ = a.country_select(:country, {priority_countries: priority_countries, include_blank: true}, {data: { placeholder: t(:select_a_country)}, class: 'select2'})
@@ -3,10 +3,10 @@
3
3
  %tr
4
4
  %td(colspan="5")
5
5
  .label.top.req #{t :name}:
6
- = f.text_field :name, autofocus: true, style: "width:500px"
6
+ = f.text_field :name, autofocus: true, style: "width:500px", required: "required"
7
7
  %tr
8
8
  %td
9
- .label.req #{t :due}:
9
+ .label #{t :due}:
10
10
  - bucket = (params[:bucket].blank? ? @task.bucket : params[:bucket]) || "due_asap"
11
11
  - with_time = Setting.task_calendar_with_time
12
12
  - if @task.bucket != "specific_time"
@@ -18,11 +18,11 @@
18
18
  = f.text_field :calendar, value: f.object.due_at.strftime(fmt), style: "width:160px;", autocomplete: :off, class: (with_time ? 'datetime' : 'date')
19
19
  %td= spacer
20
20
  %td
21
- .label.req #{t :assign_to}:
21
+ .label #{t :assign_to}:
22
22
  = user_select(:task, all_users, current_user)
23
23
  %td= spacer
24
24
  %td
25
- .label.req #{t :category}:
25
+ .label #{t :category}:
26
26
  = f.select :category, @category, { selected: @task.category.blank? ? nil : @task.category.to_sym, include_blank: t(:select_blank) }, { style: "width:160px", class: 'select2' }
27
27
 
28
28
  - if Setting.background_info && Setting.background_info.include?(:task)
@@ -85,6 +85,8 @@ module FatFreeCRM
85
85
  ::ActiveSupport::HashWithIndifferentAccess, # for Field#settings serialization see app/models/fields/field.rb
86
86
  ::ActiveSupport::TimeWithZone,
87
87
  ::ActiveSupport::TimeZone,
88
+ ::ActsAsTaggableOn::TagList,
89
+ ::ActsAsTaggableOn::DefaultParser,
88
90
  ::BigDecimal,
89
91
  ::Date,
90
92
  ::Symbol,
data/config/database.yml CHANGED
@@ -1,26 +1,23 @@
1
+ # SQLite version 3.x
2
+ # gem install sqlite3-ruby (not necessary on OS X Leopard)
1
3
  ---
2
4
  development: &development
3
- adapter: postgresql
4
- database: fat_free_crm_development
5
- username: postgres
6
- password:
7
- host: localhost
8
- port: 5432
9
- schema_search_path: public
10
- min_messages: warning
5
+ adapter: sqlite3
6
+ database: db/fat_free_crm_development.sqlite3
7
+ pool: 5
8
+ timeout: 5000
11
9
 
12
10
  # Warning: The database defined as "test" will be erased and
13
11
  # re-generated from your development database when you run "rake".
14
12
  # Do not set this db to the same as development or production.
15
13
  test:
16
14
  <<: *development
17
- database: fat_free_crm_test
15
+ database: db/fat_free_crm_test.sqlite3
18
16
 
19
17
  production:
20
18
  <<: *development
21
- database: fat_free_crm_production
19
+ database: db/fat_free_crm_production.sqlite3
22
20
 
23
21
  staging:
24
22
  <<: *development
25
- database: fat_free_crm_staging
26
-
23
+ database: db/fat_free_crm_staging.sqlite3
@@ -83,5 +83,20 @@ if defined?(FatFreeCRM::Application)
83
83
  # Checks for improperly declared sprockets dependencies.
84
84
  # Raises helpful error messages.
85
85
  config.assets.raise_runtime_errors = true
86
+
87
+ # Are we running in a GitHub Codespace?
88
+ if ENV.fetch('CODESPACE_NAME', nil)
89
+ config.host = "#{ENV.fetch('CODESPACE_NAME', nil)}-3000.app.github.dev:443"
90
+ config.hosts << ".preview.app.github.dev"
91
+ config.hosts << ".app.github.dev"
92
+
93
+ config.force_ssl = true
94
+ config.action_dispatch.cookies_same_site_protection = :lax
95
+
96
+ config.action_dispatch.trusted_proxies = [
97
+ # Trust all IPs (safe in dev only)
98
+ IPAddr.new("0.0.0.0/0"), IPAddr.new("::/0")
99
+ ]
100
+ end
86
101
  end
87
102
  end
@@ -10,7 +10,7 @@
10
10
  # ActionMailer is setup in test mode later on
11
11
  #
12
12
  unless Rails.env.test?
13
- require './app/models/setting'
13
+ require 'setting'
14
14
 
15
15
  smtp_settings = Setting.smtp || {}
16
16
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # Be sure to restart your server when you modify this file.
3
4
 
4
5
  # ActiveSupport::Reloader.to_prepare do
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # Be sure to restart your server when you modify this file.
3
4
 
4
5
  # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # Be sure to restart your server when you modify this file.
3
4
 
4
5
  # Define an application-wide content security policy.
@@ -6,8 +6,8 @@
6
6
  # See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
7
7
  #------------------------------------------------------------------------------
8
8
  # Load field names for custom fields, for Ransack search
9
- require './app/models/setting'
10
- if Setting.database_and_table_exists?
9
+ require 'setting'
10
+ if Setting.database_and_table_exists? && ActiveRecord::Base.connection.table_exists?(:custom_fields)
11
11
  Rails.application.config.after_initialize do
12
12
  I18n.backend.load_translations
13
13
 
@@ -16,6 +16,7 @@ Devise.setup do |config|
16
16
  # Devise will use the `secret_key_base` as its `secret_key`
17
17
  # by default. You can change it below and use your own secret key.
18
18
  # config.secret_key = SecureRandom.hex(64)
19
+ config.secret_key = Rails.application.secret_key_base
19
20
 
20
21
  # ==> Mailer Configuration
21
22
  # Configure the e-mail address which will be shown in Devise::Mailer,
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # Be sure to restart your server when you modify this file.
3
4
 
4
5
  # Add new inflection rules using the following format. Inflections
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # Define an application-wide HTTP permissions policy. For further
3
4
  # information see https://developers.google.com/web/updates/2018/06/feature-policy
4
5
  #
data/config/routes.rb CHANGED
@@ -23,6 +23,7 @@ Rails.application.routes.draw do
23
23
  resources :users, only: %i[index show] do
24
24
  collection do
25
25
  get :opportunities_overview
26
+ match :auto_complete, via: %i[get post]
26
27
  end
27
28
  end
28
29
  end
@@ -159,9 +160,6 @@ Rails.application.routes.draw do
159
160
  patch :change_password
160
161
  post :redraw
161
162
  end
162
- collection do
163
- match :auto_complete, via: %i[get post]
164
- end
165
163
  end
166
164
 
167
165
  namespace :admin do
@@ -192,7 +192,8 @@
192
192
  #------------------------------------------------------------------------------
193
193
  # Specify which countries (if any) should appear at the top of country pickers
194
194
  # priority_countries:
195
- # - Burkina Faso
195
+ # - AU
196
+ # - BF
196
197
 
197
198
  # Main and Admin Tabs
198
199
  #------------------------------------------------------------------------------
Binary file
File without changes
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This migration comes from action_text (originally 20180528164100)
4
+ class OptionallyCreateActionTextTables < ActiveRecord::Migration[6.0]
5
+ def change
6
+ # Use Active Record's configured type for primary and foreign keys
7
+ primary_key_type, foreign_key_type = primary_and_foreign_key_types
8
+
9
+ create_table :action_text_rich_texts, id: primary_key_type, if_not_exists: true do |t|
10
+ t.string :name, null: false
11
+ t.text :body, size: :long
12
+ t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type
13
+
14
+ t.timestamps
15
+
16
+ t.index %i[record_type record_id name], name: "index_action_text_rich_texts_uniqueness", unique: true
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def primary_and_foreign_key_types
23
+ config = Rails.configuration.generators
24
+ setting = config.options[config.orm][:primary_key_type]
25
+ primary_key_type = setting || :primary_key
26
+ foreign_key_type = setting || :bigint
27
+ [primary_key_type, foreign_key_type]
28
+ end
29
+ end
@@ -6,7 +6,7 @@ class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
6
6
  # Use Active Record's configured type for primary and foreign keys
7
7
  primary_key_type, foreign_key_type = primary_and_foreign_key_types
8
8
 
9
- create_table :active_storage_blobs, id: primary_key_type do |t|
9
+ create_table :active_storage_blobs, id: primary_key_type, if_not_exists: true do |t|
10
10
  t.string :key, null: false
11
11
  t.string :filename, null: false
12
12
  t.string :content_type
@@ -19,7 +19,7 @@ class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
19
19
  t.index [:key], unique: true
20
20
  end
21
21
 
22
- create_table :active_storage_attachments, id: primary_key_type do |t|
22
+ create_table :active_storage_attachments, id: primary_key_type, if_not_exists: true do |t|
23
23
  t.string :name, null: false
24
24
  t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type
25
25
  t.references :blob, null: false, type: foreign_key_type
@@ -30,7 +30,7 @@ class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
30
30
  t.foreign_key :active_storage_blobs, column: :blob_id
31
31
  end
32
32
 
33
- create_table :active_storage_variant_records, id: primary_key_type do |t|
33
+ create_table :active_storage_variant_records, id: primary_key_type, if_not_exists: true do |t|
34
34
  t.belongs_to :blob, null: false, index: false, type: foreign_key_type
35
35
  t.string :variation_digest, null: false
36
36
 
@@ -4,19 +4,16 @@ class ConvertToActiveStorage < ActiveRecord::Migration[5.2]
4
4
  require 'open-uri'
5
5
 
6
6
  def up
7
- get_blob_id = case ENV['CI'] && ENV['DB']
8
- when 'sqlite'
9
- 'LAST_INSERT_ROWID()'
10
- when 'mysql'
11
- 'LAST_INSERT_ID()'
12
- when 'postgres'
13
- 'LASTVAL()'
14
- else
15
- 'LASTVAL()'
16
- end
17
-
18
7
  ActiveRecord::Base.connection.raw_connection.then do |conn|
19
- if conn.is_a?(PG::Connection)
8
+ get_blob_id = case ENV['CI'] && ENV['DB']
9
+ when 'mysql'
10
+ 'LAST_INSERT_ID()'
11
+ else
12
+ 'LASTVAL()'
13
+ end
14
+ get_blob_id = 'LAST_INSERT_ROWID()' if conn.is_a?(SQLite3::Database)
15
+ if conn.is_a?(::PG::Connection)
16
+ get_blob_id = 'LASTVAL()'
20
17
  conn.prepare('active_storage_blobs', <<-SQL)
21
18
  INSERT INTO active_storage_blobs (
22
19
  key, filename, content_type, metadata, byte_size, checksum, created_at
@@ -29,13 +26,13 @@ class ConvertToActiveStorage < ActiveRecord::Migration[5.2]
29
26
  ) VALUES ($1, $2, $3, #{get_blob_id}, $4)
30
27
  SQL
31
28
  else
32
- conn.raw_connection.prepare(<<-SQL)
29
+ conn.prepare(<<-SQL)
33
30
  INSERT INTO active_storage_blobs (
34
31
  `key`, filename, content_type, metadata, byte_size, checksum, created_at
35
32
  ) VALUES (?, ?, ?, '{}', ?, ?, ?)
36
33
  SQL
37
34
 
38
- conn.raw_connection.prepare(<<-SQL)
35
+ conn.prepare(<<-SQL)
39
36
  INSERT INTO active_storage_attachments (
40
37
  name, record_type, record_id, blob_id, created_at
41
38
  ) VALUES (?, ?, ?, #{get_blob_id}, ?)