fat_free_crm 0.22.1 → 0.24.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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/crm_textarea_autocomplete.js.coffee +6 -9
- data/app/controllers/admin/fields_controller.rb +2 -2
- data/app/controllers/application_controller.rb +1 -1
- data/app/controllers/emails_controller.rb +1 -1
- data/app/controllers/entities/contacts_controller.rb +1 -1
- data/app/controllers/users_controller.rb +15 -3
- data/app/helpers/application_helper.rb +1 -1
- data/app/helpers/leads_helper.rb +1 -1
- data/app/helpers/opportunities_helper.rb +1 -1
- data/app/models/entities/account.rb +1 -1
- data/app/models/entities/campaign.rb +2 -2
- data/app/models/entities/contact.rb +1 -1
- data/app/models/entities/lead.rb +1 -1
- data/app/models/entities/opportunity.rb +1 -1
- data/app/models/fields/field.rb +1 -1
- data/app/models/observers/lead_observer.rb +2 -1
- data/app/models/observers/task_observer.rb +2 -1
- data/app/models/polymorphic/address.rb +2 -1
- data/app/models/polymorphic/comment.rb +3 -4
- data/app/models/polymorphic/task.rb +2 -2
- data/app/models/users/user.rb +7 -1
- data/app/views/layouts/application.html.haml +1 -3
- data/config/application.rb +2 -0
- data/config/database.yml +9 -11
- data/config/environments/development.rb +15 -0
- data/config/initializers/application_controller_renderer.rb +1 -0
- data/config/initializers/backtrace_silencers.rb +1 -0
- data/config/initializers/content_security_policy.rb +1 -0
- data/config/initializers/devise.rb +1 -0
- data/config/initializers/inflections.rb +1 -0
- data/config/initializers/permissions_policy.rb +1 -0
- data/config/routes.rb +1 -3
- data/db/fat_free_crm_development.sqlite3 +0 -0
- data/db/fat_free_crm_test.sqlite3 +0 -0
- data/db/migrate/20230422234321_optionally_create_action_text_tables.action_text.rb +29 -0
- data/db/migrate/20230526211831_create_active_storage_tables.active_storage.rb +3 -3
- data/db/migrate/20230526212613_convert_to_active_storage.rb +10 -13
- data/db/schema.rb +16 -9
- data/db/seeds.rb +1 -0
- data/lib/fat_free_crm/callback.rb +0 -1
- data/lib/fat_free_crm/core_ext/string.rb +1 -1
- data/lib/fat_free_crm/mail_processor/base.rb +6 -10
- data/lib/fat_free_crm/version.rb +2 -2
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 583c16095787930cb44e9c376e303f5bb44d96d2acd85a2b87574d302afb23ab
|
4
|
+
data.tar.gz: 72ca4114ddd58c79a7259abc6bd96d07a2d7b34d2e6315ccbc78661091fc522e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3bb966d52f44f40cc2e439286cfd7f596c21ac4afb7b445131d87b654ab8eff66b2c15ec87b188b34fcfa4b531addb73db195ca92ec1b0c56d1ef8ecfde5eb4f
|
7
|
+
data.tar.gz: 076fd28ff58929818419f1960ad37e990ba3044b64ac80f6132f896bf5acb6f07c6ce4fc89e7c19a450813051286d15c81fdef00fd6840c91e476c14d77c0256
|
@@ -17,17 +17,14 @@
|
|
17
17
|
|
18
18
|
# Only autocomplete if search term starts with '@'
|
19
19
|
return [] unless text.indexOf("@") is 0
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
i++
|
27
|
-
cb words, text.replace("@", "")
|
20
|
+
$.ajax
|
21
|
+
url: "/users/auto_complete"
|
22
|
+
data:
|
23
|
+
term: text.replace("@", "")
|
24
|
+
success: (response) ->
|
25
|
+
cb response, text.replace("@", "")
|
28
26
|
|
29
27
|
selected: (text, data) ->
|
30
28
|
username_regEx = new RegExp("\\((@[^)]+)\\)")
|
31
29
|
text.match(username_regEx)[1]
|
32
|
-
|
33
30
|
) jQuery
|
@@ -42,7 +42,7 @@ class Admin::FieldsController < Admin::ApplicationController
|
|
42
42
|
#----------------------------------------------------------------------------
|
43
43
|
def create
|
44
44
|
as = field_params["as"]
|
45
|
-
klass= Field.lookup_class(as).safe_constantize
|
45
|
+
klass = Field.lookup_class(as).safe_constantize
|
46
46
|
@field =
|
47
47
|
if as.match?(/pair/)
|
48
48
|
klass.create_pair("pair" => pair_params, "field" => field_params).first
|
@@ -117,7 +117,7 @@ class Admin::FieldsController < Admin::ApplicationController
|
|
117
117
|
end
|
118
118
|
|
119
119
|
def pair_params
|
120
|
-
params.require(:pair).permit("0": [
|
120
|
+
params.require(:pair).permit("0": %i[hint required disabled id], "1": %i[hint required disabled id])
|
121
121
|
end
|
122
122
|
|
123
123
|
def setup_current_tab
|
@@ -79,7 +79,7 @@ class ApplicationController < ActionController::Base
|
|
79
79
|
# See http://blog.nvisium.com/2014/09/understanding-protectfromforgery.html for more details.
|
80
80
|
#----------------------------------------------------------------------------
|
81
81
|
def handle_unverified_request
|
82
|
-
raise ActionController::InvalidAuthenticityToken
|
82
|
+
raise ActionController::InvalidAuthenticityToken unless ENV.fetch('CODESPACE_NAME', nil) && Rails.env.development?
|
83
83
|
end
|
84
84
|
|
85
85
|
#
|
@@ -63,9 +63,7 @@ class UsersController < ApplicationController
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
responds_to_parent do
|
66
|
-
|
67
|
-
# within the block and after yield in responds_to_parent.
|
68
|
-
render && (return if Rails.env.test?)
|
66
|
+
render
|
69
67
|
end
|
70
68
|
end
|
71
69
|
end
|
@@ -111,6 +109,20 @@ class UsersController < ApplicationController
|
|
111
109
|
@unassigned_opportunities = Opportunity.my(current_user).unassigned.pipeline.order(:stage).includes(:account, :user, :tags)
|
112
110
|
end
|
113
111
|
|
112
|
+
def auto_complete
|
113
|
+
@query = params[:term] || ''
|
114
|
+
@users = User.my(current_user).text_search(@query).limit(10).order(:first_name, :last_name)
|
115
|
+
|
116
|
+
respond_to do |format|
|
117
|
+
format.json do
|
118
|
+
results = @users.map do |a|
|
119
|
+
helpers.j(a.full_name + " (@" + a.username + ")")
|
120
|
+
end
|
121
|
+
render json: results
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
114
126
|
protected
|
115
127
|
|
116
128
|
def user_params
|
@@ -155,7 +155,7 @@ module ApplicationHelper
|
|
155
155
|
#----------------------------------------------------------------------------
|
156
156
|
def link_to_email(email, length = nil, &_block)
|
157
157
|
name = (length ? truncate(email, length: length) : email)
|
158
|
-
bcc = Setting
|
158
|
+
bcc = Setting.email_dropbox
|
159
159
|
mailto = if bcc && bcc[:address].present?
|
160
160
|
"#{email}?bcc=#{bcc[:address]}"
|
161
161
|
else
|
data/app/helpers/leads_helper.rb
CHANGED
@@ -69,7 +69,7 @@ module LeadsHelper
|
|
69
69
|
#----------------------------------------------------------------------------
|
70
70
|
def lead_summary(lead)
|
71
71
|
summary = []
|
72
|
-
summary <<
|
72
|
+
summary << t(lead.status || :other)
|
73
73
|
|
74
74
|
if lead.company? && lead.title?
|
75
75
|
summary << t(:works_at, job_title: lead.title, company: lead.company)
|
@@ -17,7 +17,7 @@ module OpportunitiesHelper
|
|
17
17
|
def opportunity_summary(opportunity)
|
18
18
|
summary = []
|
19
19
|
amount = []
|
20
|
-
summary <<
|
20
|
+
summary << t(opportunity.stage || :other)
|
21
21
|
summary << number_to_currency(opportunity.weighted_amount, precision: 0)
|
22
22
|
unless %w[won lost].include?(opportunity.stage)
|
23
23
|
amount << number_to_currency(opportunity.amount.to_f, precision: 0)
|
@@ -41,7 +41,7 @@ class Account < ActiveRecord::Base
|
|
41
41
|
has_many :addresses, dependent: :destroy, as: :addressable, class_name: "Address" # advanced search uses this
|
42
42
|
has_many :emails, as: :mediator
|
43
43
|
|
44
|
-
serialize :subscribed_users, Array
|
44
|
+
serialize :subscribed_users, type: Array
|
45
45
|
|
46
46
|
accepts_nested_attributes_for :billing_address, allow_destroy: true, reject_if: proc { |attributes| Address.reject_address(attributes) }
|
47
47
|
accepts_nested_attributes_for :shipping_address, allow_destroy: true, reject_if: proc { |attributes| Address.reject_address(attributes) }
|
@@ -39,7 +39,7 @@ class Campaign < ActiveRecord::Base
|
|
39
39
|
has_many :opportunities, -> { order "id DESC" }
|
40
40
|
has_many :emails, as: :mediator
|
41
41
|
|
42
|
-
serialize :subscribed_users, Array
|
42
|
+
serialize :subscribed_users, type: Array
|
43
43
|
|
44
44
|
scope :state, lambda { |filters|
|
45
45
|
where('status IN (?)' + (filters.delete('other') ? ' OR status IS NULL' : ''), filters)
|
@@ -103,7 +103,7 @@ class Campaign < ActiveRecord::Base
|
|
103
103
|
# Make sure end date > start date.
|
104
104
|
#----------------------------------------------------------------------------
|
105
105
|
def start_and_end_dates
|
106
|
-
errors.add(:ends_on, :dates_not_in_sequence) if
|
106
|
+
errors.add(:ends_on, :dates_not_in_sequence) if starts_on && ends_on && (starts_on > ends_on)
|
107
107
|
end
|
108
108
|
|
109
109
|
# Make sure at least one user has been selected if the campaign is being shared.
|
@@ -57,7 +57,7 @@ class Contact < ActiveRecord::Base
|
|
57
57
|
has_ransackable_associations %w[account opportunities tags activities emails addresses comments tasks]
|
58
58
|
ransack_can_autocomplete
|
59
59
|
|
60
|
-
serialize :subscribed_users, Array
|
60
|
+
serialize :subscribed_users, type: Array
|
61
61
|
|
62
62
|
accepts_nested_attributes_for :business_address, allow_destroy: true, reject_if: proc { |attributes| Address.reject_address(attributes) }
|
63
63
|
|
data/app/models/entities/lead.rb
CHANGED
@@ -48,7 +48,7 @@ class Lead < ActiveRecord::Base
|
|
48
48
|
has_many :addresses, dependent: :destroy, as: :addressable, class_name: "Address" # advanced search uses this
|
49
49
|
has_many :emails, as: :mediator
|
50
50
|
|
51
|
-
serialize :subscribed_users, Array
|
51
|
+
serialize :subscribed_users, type: Array
|
52
52
|
|
53
53
|
accepts_nested_attributes_for :business_address, allow_destroy: true, reject_if: proc { |attributes| Address.reject_address(attributes) }
|
54
54
|
|
@@ -38,7 +38,7 @@ class Opportunity < ActiveRecord::Base
|
|
38
38
|
has_many :tasks, as: :asset, dependent: :destroy # , :order => 'created_at DESC'
|
39
39
|
has_many :emails, as: :mediator
|
40
40
|
|
41
|
-
serialize :subscribed_users, Array
|
41
|
+
serialize :subscribed_users, type: Array
|
42
42
|
|
43
43
|
scope :state, lambda { |filters|
|
44
44
|
where('stage IN (?)' + (filters.delete('other') ? ' OR stage IS NULL' : ''), filters)
|
data/app/models/fields/field.rb
CHANGED
@@ -16,7 +16,8 @@ class LeadObserver < ActiveRecord::Observer
|
|
16
16
|
|
17
17
|
def after_update(item)
|
18
18
|
original = @@leads.delete(item.id)
|
19
|
-
|
19
|
+
|
20
|
+
log_activity(item, :reject) if original&.status != "rejected" && item.status == "rejected"
|
20
21
|
end
|
21
22
|
|
22
23
|
private
|
@@ -19,7 +19,8 @@ class TaskObserver < ActiveRecord::Observer
|
|
19
19
|
if original
|
20
20
|
return log_activity(item, :complete) if item.completed_at && original.completed_at.nil?
|
21
21
|
return log_activity(item, :reassign) if item.assigned_to != original.assigned_to
|
22
|
-
|
22
|
+
|
23
|
+
log_activity(item, :reschedule) if item.bucket != original.bucket
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
@@ -54,7 +54,8 @@ class Address < ActiveRecord::Base
|
|
54
54
|
exists = attributes['id'].present?
|
55
55
|
empty = %w[street1 street2 city state zipcode country full_address].map { |name| attributes[name].blank? }.all?
|
56
56
|
attributes[:_destroy] = 1 if exists && empty
|
57
|
-
|
57
|
+
|
58
|
+
!exists && empty
|
58
59
|
end
|
59
60
|
|
60
61
|
ActiveSupport.run_load_hooks(:fat_free_crm_address, self)
|
@@ -52,10 +52,9 @@ class Comment < ActiveRecord::Base
|
|
52
52
|
|
53
53
|
# Notify subscribed users when a comment is added, unless user created this comment
|
54
54
|
def notify_subscribers
|
55
|
-
commentable.subscribed_users.reject { |user_id| user_id == user.id }
|
56
|
-
|
57
|
-
|
58
|
-
end
|
55
|
+
users_to_notify = User.where(id: commentable.subscribed_users.reject { |user_id| user_id == user.id })
|
56
|
+
users_to_notify.select(&:emailable?).each do |subscriber|
|
57
|
+
SubscriptionMailer.comment_notification(subscriber, self).deliver_later
|
59
58
|
end
|
60
59
|
end
|
61
60
|
|
@@ -39,7 +39,7 @@ class Task < ActiveRecord::Base
|
|
39
39
|
belongs_to :completor, class_name: "User", foreign_key: :completed_by, optional: true # TODO: Is this really optional?
|
40
40
|
belongs_to :asset, polymorphic: true, optional: true # TODO: Is this really optional?
|
41
41
|
|
42
|
-
serialize :subscribed_users, Array
|
42
|
+
serialize :subscribed_users, type: Array
|
43
43
|
|
44
44
|
# Tasks created by the user for herself, or assigned to her by others. That's
|
45
45
|
# what gets shown on Tasks/Pending and Tasks/Completed pages.
|
@@ -103,7 +103,7 @@ class Task < ActiveRecord::Base
|
|
103
103
|
scope :completed_last_month, -> { where('completed_at >= ? AND completed_at < ?', (Time.zone.now.beginning_of_month.utc - 1.day).beginning_of_month.utc, Time.zone.now.beginning_of_month.utc) }
|
104
104
|
|
105
105
|
scope :text_search, lambda { |query|
|
106
|
-
query = query.gsub(/[^\w\s
|
106
|
+
query = query.gsub(/[^\w\s\-.'\p{L}]/u, '').strip
|
107
107
|
where('upper(name) LIKE upper(?)', "%#{query}%")
|
108
108
|
}
|
109
109
|
|
data/app/models/users/user.rb
CHANGED
@@ -73,7 +73,7 @@ class User < ActiveRecord::Base
|
|
73
73
|
scope :by_name, -> { order('first_name, last_name, email') }
|
74
74
|
|
75
75
|
scope :text_search, lambda { |query|
|
76
|
-
query = query.gsub(/[^\w\s
|
76
|
+
query = query.gsub(/[^\w\s\-.'\p{L}]/u, '').strip
|
77
77
|
where('upper(username) LIKE upper(:s) OR upper(email) LIKE upper(:s) OR upper(first_name) LIKE upper(:s) OR upper(last_name) LIKE upper(:s)', s: "%#{query}%")
|
78
78
|
}
|
79
79
|
|
@@ -134,6 +134,12 @@ class User < ActiveRecord::Base
|
|
134
134
|
end
|
135
135
|
end
|
136
136
|
|
137
|
+
# Send emails to active users only
|
138
|
+
#----------------------------------------------------------------------------
|
139
|
+
def emailable?
|
140
|
+
confirmed? && !awaits_approval? && !suspended? && email.present?
|
141
|
+
end
|
142
|
+
|
137
143
|
#----------------------------------------------------------------------------
|
138
144
|
def preference
|
139
145
|
@preference ||= preferences.build
|
@@ -26,9 +26,7 @@
|
|
26
26
|
- if current_user.present?
|
27
27
|
:javascript
|
28
28
|
#{yield :javascript}
|
29
|
-
|
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">
|
data/config/application.rb
CHANGED
@@ -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,25 +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:
|
4
|
-
database: fat_free_crm_development
|
5
|
-
|
6
|
-
|
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
|
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
|
@@ -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,
|
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
|
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|
|
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)
|
19
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.
|
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.
|
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}, ?)
|
data/db/schema.rb
CHANGED
@@ -11,9 +11,6 @@
|
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
12
12
|
|
13
13
|
ActiveRecord::Schema[7.0].define(version: 2023_05_26_212613) do
|
14
|
-
# These are extensions that must be enabled in order to support this database
|
15
|
-
enable_extension "plpgsql"
|
16
|
-
|
17
14
|
create_table "account_contacts", force: :cascade do |t|
|
18
15
|
t.integer "account_id"
|
19
16
|
t.integer "contact_id"
|
@@ -55,6 +52,16 @@ ActiveRecord::Schema[7.0].define(version: 2023_05_26_212613) do
|
|
55
52
|
t.index ["user_id", "name", "deleted_at"], name: "index_accounts_on_user_id_and_name_and_deleted_at", unique: true
|
56
53
|
end
|
57
54
|
|
55
|
+
create_table "action_text_rich_texts", force: :cascade do |t|
|
56
|
+
t.string "name", null: false
|
57
|
+
t.text "body"
|
58
|
+
t.string "record_type", null: false
|
59
|
+
t.bigint "record_id", null: false
|
60
|
+
t.datetime "created_at", null: false
|
61
|
+
t.datetime "updated_at", null: false
|
62
|
+
t.index ["record_type", "record_id", "name"], name: "index_action_text_rich_texts_uniqueness", unique: true
|
63
|
+
end
|
64
|
+
|
58
65
|
create_table "active_storage_attachments", force: :cascade do |t|
|
59
66
|
t.string "name", null: false
|
60
67
|
t.string "record_type", null: false
|
@@ -247,12 +254,12 @@ ActiveRecord::Schema[7.0].define(version: 2023_05_26_212613) do
|
|
247
254
|
t.text "collection"
|
248
255
|
t.boolean "disabled"
|
249
256
|
t.boolean "required"
|
250
|
-
t.integer "maxlength"
|
257
|
+
t.integer "maxlength", limit: 4
|
251
258
|
t.datetime "created_at", precision: nil
|
252
259
|
t.datetime "updated_at", precision: nil
|
253
260
|
t.integer "pair_id"
|
254
261
|
t.text "settings"
|
255
|
-
t.integer "minlength", default: 0
|
262
|
+
t.integer "minlength", limit: 4, default: 0
|
256
263
|
t.string "pattern"
|
257
264
|
t.string "autofocus"
|
258
265
|
t.string "autocomplete"
|
@@ -417,7 +424,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_05_26_212613) do
|
|
417
424
|
|
418
425
|
create_table "users", force: :cascade do |t|
|
419
426
|
t.string "username", limit: 32, default: "", null: false
|
420
|
-
t.string "email", limit: 254
|
427
|
+
t.string "email", limit: 254
|
421
428
|
t.string "first_name", limit: 32
|
422
429
|
t.string "last_name", limit: 32
|
423
430
|
t.string "title", limit: 64
|
@@ -448,8 +455,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_05_26_212613) do
|
|
448
455
|
t.datetime "remember_created_at", precision: nil
|
449
456
|
t.string "authentication_token"
|
450
457
|
t.string "confirmation_token", limit: 255
|
451
|
-
t.datetime "confirmed_at"
|
452
|
-
t.datetime "confirmation_sent_at"
|
458
|
+
t.datetime "confirmed_at"
|
459
|
+
t.datetime "confirmation_sent_at"
|
453
460
|
t.index ["authentication_token"], name: "index_users_on_authentication_token", unique: true
|
454
461
|
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
|
455
462
|
t.index ["email"], name: "index_users_on_email"
|
@@ -461,7 +468,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_05_26_212613) do
|
|
461
468
|
create_table "versions", force: :cascade do |t|
|
462
469
|
t.string "item_type", null: false
|
463
470
|
t.integer "item_id", null: false
|
464
|
-
t.string "event", limit: 512
|
471
|
+
t.string "event", limit: 512
|
465
472
|
t.string "whodunnit"
|
466
473
|
t.text "object"
|
467
474
|
t.datetime "created_at", precision: nil
|
data/db/seeds.rb
CHANGED
@@ -108,7 +108,6 @@ module FatFreeCRM
|
|
108
108
|
#--------------------------------------------------------------------------
|
109
109
|
module Helper
|
110
110
|
def hook(method, caller, context = {}, &block)
|
111
|
-
|
112
111
|
# In a view template context, hooks are able to replace, append or prepend content.
|
113
112
|
if caller.is_a?(ActionView::Base)
|
114
113
|
hooks = FatFreeCRM::Callback.view_hook(method, caller, context)
|
@@ -36,7 +36,7 @@ class String
|
|
36
36
|
# A query with 4 words will generate 6 permutations
|
37
37
|
def name_permutations
|
38
38
|
parts = split(" ")
|
39
|
-
Array.new(
|
39
|
+
Array.new(parts.size - 1) do |i|
|
40
40
|
# ["A", "B", "C", "D"] => [["A B C", "D"], ["A B", "C D"], ["A", "B C D"]]
|
41
41
|
[parts[(0..i)].join(" "), parts[(i + 1)..-1].join(" ")]
|
42
42
|
end.each_with_object([]) do |perm, arr|
|
@@ -104,10 +104,8 @@ module FatFreeCRM
|
|
104
104
|
discard(uid)
|
105
105
|
end
|
106
106
|
rescue Exception => e
|
107
|
-
|
108
|
-
|
109
|
-
warn e.backtrace
|
110
|
-
end
|
107
|
+
warn e
|
108
|
+
warn e.backtrace
|
111
109
|
log "error processing email: #{e.inspect}", email
|
112
110
|
discard(uid)
|
113
111
|
end
|
@@ -181,12 +179,10 @@ module FatFreeCRM
|
|
181
179
|
# Centralized logging.
|
182
180
|
#--------------------------------------------------------------------------------------
|
183
181
|
def log(message, email = nil)
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
puts "[#{Time.now.rfc822}] #{klass}: From: #{email.from}, Subject: #{email.subject} (#{email.message_id})" if email
|
189
|
-
end
|
182
|
+
klass = self.class.to_s.split("::").last
|
183
|
+
klass << " [Dry Run]" if @dry_run
|
184
|
+
Rails.logger.info("[#{Time.now.rfc822}] #{klass}: #{message}")
|
185
|
+
Rails.logger.info("[#{Time.now.rfc822}] #{klass}: From: #{email.from}, Subject: #{email.subject} (#{email.message_id})") if email
|
190
186
|
end
|
191
187
|
|
192
188
|
# Returns the plain-text version of an email, or strips html tags
|
data/lib/fat_free_crm/version.rb
CHANGED
metadata
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fat_free_crm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.24.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Dvorkin
|
8
8
|
- Stephen Kenworthy
|
9
9
|
- Daniel O'Connor
|
10
|
-
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date:
|
12
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: rails
|
@@ -18,7 +17,7 @@ dependencies:
|
|
18
17
|
requirements:
|
19
18
|
- - ">="
|
20
19
|
- !ruby/object:Gem::Version
|
21
|
-
version: 7.
|
20
|
+
version: 7.1.0
|
22
21
|
- - "<"
|
23
22
|
- !ruby/object:Gem::Version
|
24
23
|
version: 7.3.0
|
@@ -28,7 +27,7 @@ dependencies:
|
|
28
27
|
requirements:
|
29
28
|
- - ">="
|
30
29
|
- !ruby/object:Gem::Version
|
31
|
-
version: 7.
|
30
|
+
version: 7.1.0
|
32
31
|
- - "<"
|
33
32
|
- !ruby/object:Gem::Version
|
34
33
|
version: 7.3.0
|
@@ -1090,6 +1089,8 @@ files:
|
|
1090
1089
|
- db/demo/settings.yml
|
1091
1090
|
- db/demo/tasks.yml
|
1092
1091
|
- db/demo/users.yml
|
1092
|
+
- db/fat_free_crm_development.sqlite3
|
1093
|
+
- db/fat_free_crm_test.sqlite3
|
1093
1094
|
- db/migrate/20100928030598_create_sessions.rb
|
1094
1095
|
- db/migrate/20100928030599_create_users.rb
|
1095
1096
|
- db/migrate/20100928030600_create_openid_tables.rb
|
@@ -1162,6 +1163,7 @@ files:
|
|
1162
1163
|
- db/migrate/20180107082701_authlogic_to_devise.rb
|
1163
1164
|
- db/migrate/20200806004152_add_pattern_to_fields.rb
|
1164
1165
|
- db/migrate/20200806004459_add_html5_to_fields.rb
|
1166
|
+
- db/migrate/20230422234321_optionally_create_action_text_tables.action_text.rb
|
1165
1167
|
- db/migrate/20230526211831_create_active_storage_tables.active_storage.rb
|
1166
1168
|
- db/migrate/20230526212613_convert_to_active_storage.rb
|
1167
1169
|
- db/schema.rb
|
@@ -1314,7 +1316,6 @@ homepage: http://fatfreecrm.com
|
|
1314
1316
|
licenses:
|
1315
1317
|
- MIT
|
1316
1318
|
metadata: {}
|
1317
|
-
post_install_message:
|
1318
1319
|
rdoc_options: []
|
1319
1320
|
require_paths:
|
1320
1321
|
- lib
|
@@ -1329,8 +1330,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1329
1330
|
- !ruby/object:Gem::Version
|
1330
1331
|
version: '0'
|
1331
1332
|
requirements: []
|
1332
|
-
rubygems_version: 3.
|
1333
|
-
signing_key:
|
1333
|
+
rubygems_version: 3.6.9
|
1334
1334
|
specification_version: 4
|
1335
1335
|
summary: Fat Free CRM
|
1336
1336
|
test_files: []
|