wco_models 3.1.0.189 → 3.1.0.191
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/wco/api/tags_controller.rb +9 -0
- data/app/controllers/wco/api_controller.rb +0 -1
- data/app/models/wco/tag.rb +10 -5
- data/app/models/wco_email/email_filter.rb +67 -14
- data/app/models/wco_email/email_filter_action.rb +47 -0
- data/app/models/wco_email/email_filter_condition.rb +19 -4
- data/app/models/wco_email/message.rb +21 -1
- data/app/models/wco_email/message_stub.rb +19 -1
- data/app/models/wco_hosting/appliance_tmpl.rb +2 -0
- data/app/views/wco/api/tags/index.json.jbuilder +7 -0
- data/app/views/wco/profiles/_form.haml +1 -1
- data/config/routes.rb +2 -0
- data/lib/wco_models.rb +24 -2
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9bff74466afd78d598eeb38f3b23283337a17e0b5a8b92b0e26f845f0bb8911a
|
4
|
+
data.tar.gz: e4f9e670080defcc68b180349aff8fd16b5de911bfc2951a97032f57a5a3400e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2aa5e46bf8e08e735d816278ecc948d47e99cd70e7c85e8d17bf7a7f196310c6096f12a14fd9d03158f426025580cec2648995c4325ff21bfe0940193f35ce73
|
7
|
+
data.tar.gz: d59c6bd87089bbb5a3ac0092a365696cf0d0fde26c2eb2573f00a1b6bc304ba53b2ef96a45ffa8212ef43b17ac7a0c13fa8d9d4c0c464454ccc42c18f2bc2cc4
|
data/app/models/wco/tag.rb
CHANGED
@@ -30,16 +30,21 @@ class Wco::Tag
|
|
30
30
|
find_or_create_by({ slug: INBOX })
|
31
31
|
end
|
32
32
|
|
33
|
-
TRASH = 'trash'
|
34
|
-
def self.trash
|
35
|
-
find_or_create_by({ slug: TRASH })
|
36
|
-
end
|
37
|
-
|
38
33
|
SPAM = 'spam'
|
39
34
|
def self.spam
|
40
35
|
find_or_create_by({ slug: SPAM })
|
41
36
|
end
|
42
37
|
|
38
|
+
NOT_SPAM = 'not-spam'
|
39
|
+
def self.not_spam
|
40
|
+
find_or_create_by({ slug: NOT_SPAM })
|
41
|
+
end
|
42
|
+
|
43
|
+
TRASH = 'trash'
|
44
|
+
def self.trash
|
45
|
+
find_or_create_by({ slug: TRASH })
|
46
|
+
end
|
47
|
+
|
43
48
|
def to_s
|
44
49
|
slug
|
45
50
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
|
2
|
+
|
2
3
|
##
|
3
4
|
## 2023-03-04 _vp_ When I receive one.
|
4
5
|
##
|
@@ -10,9 +11,6 @@ class WcoEmail::EmailFilter
|
|
10
11
|
|
11
12
|
PAGE_PARAM_NAME = :filters_page
|
12
13
|
|
13
|
-
FIELD_OPTS = [ :subject, :from, :to, :to_and_cc, :body, ]
|
14
|
-
MATCHTYPE_OPTS = [ :regex, :exact_insensitive, ]
|
15
|
-
|
16
14
|
field :from_regex
|
17
15
|
field :from_exact
|
18
16
|
field :subject_regex
|
@@ -23,13 +21,33 @@ class WcoEmail::EmailFilter
|
|
23
21
|
field :skip_from_regex
|
24
22
|
field :skip_to_exact
|
25
23
|
|
26
|
-
has_many :
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
24
|
+
has_many :actions, class_name: '::WcoEmail::EmailFilterAction', inverse_of: :email_filter
|
25
|
+
accepts_nested_attributes_for :actions, allow_destroy: true
|
26
|
+
validate :validate_actions
|
27
|
+
def validate_actions
|
28
|
+
if actions.length == 0
|
29
|
+
errors.add(:actions, 'must be present')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
## 'and' - all conditions must match, for filter to match
|
34
|
+
has_many :conditions, class_name: '::WcoEmail::EmailFilterCondition', inverse_of: :email_filter
|
35
|
+
accepts_nested_attributes_for :conditions, allow_destroy: true
|
36
|
+
|
37
|
+
## 'and' - all conditions must match, for filter to match
|
38
|
+
has_many :skip_conditions, class_name: '::WcoEmail::EmailFilterCondition', inverse_of: :email_skip_filter
|
39
|
+
accepts_nested_attributes_for :skip_conditions, allow_destroy: true
|
40
|
+
validate :validate_conditions
|
41
|
+
def validate_conditions
|
42
|
+
if conditions.length + skip_conditions.length == 0
|
43
|
+
errors.add(:conditions, 'Either conditions or skip conditions must be present.')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
has_and_belongs_to_many :action_tmpls, class_name: '::Wco::OfficeActionTemplate'
|
48
|
+
has_and_belongs_to_many :leadsets, class_name: '::Wco::Leadset'
|
49
|
+
|
50
|
+
belongs_to :tag, class_name: '::Wco::Tag', inverse_of: :email_filters, optional: true
|
33
51
|
|
34
52
|
KIND_AUTORESPOND_TMPL = 'autorespond-template'
|
35
53
|
KIND_AUTORESPOND_EACT = 'autorespond-email-action'
|
@@ -46,10 +64,45 @@ class WcoEmail::EmailFilter
|
|
46
64
|
field :kind
|
47
65
|
|
48
66
|
|
49
|
-
belongs_to :email_template, class_name: 'WcoEmail::EmailTemplate', optional: true
|
50
|
-
belongs_to :email_action_template, class_name: 'WcoEmail::EmailActionTemplate', optional: true
|
67
|
+
belongs_to :email_template, class_name: '::WcoEmail::EmailTemplate', optional: true
|
68
|
+
belongs_to :email_action_template, class_name: '::WcoEmail::EmailActionTemplate', optional: true
|
69
|
+
|
70
|
+
## @TODO: change to has_and_belongs_to_many, test-driven.
|
71
|
+
has_many :conversations, class_name: '::WcoEmail::Conversation', inverse_of: :filter
|
72
|
+
|
73
|
+
def to_s
|
74
|
+
"EmailFilter: #{from_regex} #{from_exact} #{conditions.map { |c| c.to_s }.join }"
|
75
|
+
end
|
76
|
+
def to_s_full
|
77
|
+
# inn = ""
|
78
|
+
# inn = "#{inn}#{conditions.map { |c| c.to_s_full }.join }" if conditions.present?
|
79
|
+
# inn = "#{inn}#{skip_conditions.map { |c| c.to_s_full }.join }" if skip_conditions.present?
|
80
|
+
out =<<-AOL
|
81
|
+
<EmailFilter #{from_regex} #{from_exact}>
|
82
|
+
#{conditions.map { |c| c.to_s_full( indent: 2) }.join }
|
83
|
+
#{skip_conditions.map { |c| c.to_s_full( indent: 2) }.join }
|
84
|
+
#{actions.map { |c| c.to_s_full( indent: 2) }.join }
|
85
|
+
</EmailFilter>"
|
86
|
+
AOL
|
87
|
+
while out.match(/\n\n/) do
|
88
|
+
out = out.gsub(/\n\n/, "\n")
|
89
|
+
end
|
90
|
+
out
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_xml
|
94
|
+
attrs = ''
|
95
|
+
children = ''
|
96
|
+
if from_regex || from_exact
|
97
|
+
attrs = "#{attrs} from=#{from_regex}#{from_exact}"
|
98
|
+
end
|
99
|
+
if conditions.present?
|
100
|
+
children = "#{children}#{conditions.map { |c| c.to_s }.join('') }"
|
101
|
+
end
|
102
|
+
return "<EF #{attrs}>#{children}</EF>\n"
|
103
|
+
end
|
51
104
|
|
52
|
-
has_many :conversations, class_name: 'WcoEmail::Conversation', inverse_of: :filter
|
53
105
|
|
54
|
-
end
|
55
106
|
|
107
|
+
end
|
108
|
+
::EF = WcoEmail::EmailFilter
|
@@ -0,0 +1,47 @@
|
|
1
|
+
|
2
|
+
class WcoEmail::EmailFilterAction
|
3
|
+
include Mongoid::Document
|
4
|
+
include Mongoid::Timestamps
|
5
|
+
store_in collection: 'email_filter_actions'
|
6
|
+
|
7
|
+
belongs_to :email_filter
|
8
|
+
|
9
|
+
KIND_EXE = 'exe'
|
10
|
+
KIND_REMOVE_TAG = ::WcoEmail::ACTION_REMOVE_TAG
|
11
|
+
KIND_ADD_TAG = ::WcoEmail::ACTION_ADD_TAG
|
12
|
+
KIND_AUTORESPOND = ::WcoEmail::ACTION_AUTORESPOND
|
13
|
+
KIND_SCHEDULE_EMAIL_ACTION = 'autorespond-email-action'
|
14
|
+
KIND_REMOVE_EMAIL_ACTION = 'remove-email-action'
|
15
|
+
field :kind
|
16
|
+
validates :kind, inclusion: ::WcoEmail::ACTIONS
|
17
|
+
|
18
|
+
field :value # the id of a tag, or email template, or email action
|
19
|
+
|
20
|
+
|
21
|
+
before_validation :check_value
|
22
|
+
def check_value
|
23
|
+
case kind
|
24
|
+
when KIND_AUTORESPOND
|
25
|
+
existing = WcoEmail::EmailTemplate.where({ id: value }).first
|
26
|
+
if !existing
|
27
|
+
errors.add( :base, 'missing EmailTemplate id when creating an EmailFilterAction' )
|
28
|
+
throw :abort
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
"<EFA #{kind} #{value} />\n"
|
36
|
+
end
|
37
|
+
def to_s_full indent: 0
|
38
|
+
_value = value
|
39
|
+
if [ KIND_ADD_TAG, KIND_REMOVE_TAG ].include?( kind )
|
40
|
+
_value = Wco::Tag.find( value )
|
41
|
+
end
|
42
|
+
if [ KIND_AUTORESPOND ].include?( kind )
|
43
|
+
_value = WcoEmail::EmailTemplate.find( value )
|
44
|
+
end
|
45
|
+
"#{" " * indent }<EmailFilterAction #{kind} `#{_value}` />\n"
|
46
|
+
end
|
47
|
+
end
|
@@ -5,13 +5,28 @@ class WcoEmail::EmailFilterCondition
|
|
5
5
|
include Mongoid::Paranoia
|
6
6
|
store_in collection: 'office_email_filter_conditions'
|
7
7
|
|
8
|
-
belongs_to :email_filter, inverse_of: :
|
9
|
-
belongs_to :
|
8
|
+
belongs_to :email_filter, class_name: '::WcoEmail::EmailFilter', inverse_of: :conditions, optional: true
|
9
|
+
belongs_to :email_skip_filter, class_name: '::WcoEmail::EmailFilter', inverse_of: :skip_conditions, optional: true
|
10
10
|
|
11
|
+
## see WcoEmail::FIELD_*
|
11
12
|
field :field
|
12
|
-
field :
|
13
|
-
|
13
|
+
validates :field, presence: true
|
14
|
+
|
15
|
+
field :operator, type: String
|
16
|
+
validates :operator, presence: true, inclusion: ::WcoEmail::OPERATORS
|
14
17
|
|
18
|
+
field :value
|
19
|
+
validates :value, presence: true
|
15
20
|
|
21
|
+
def to_s
|
22
|
+
"<EFC #{field} #{operator} #{value} />"
|
23
|
+
end
|
24
|
+
def to_s_full indent: 0
|
25
|
+
_value = value
|
26
|
+
if [ OPERATOR_HAS_TAG, OPERATOR_NOT_HAS_TAG ].include?( operator )
|
27
|
+
_value = Wco::Tag.find( value )
|
28
|
+
end
|
29
|
+
"#{" " * indent }<EmailFilterCondition #{field} #{operator} `#{_value}` />\n"
|
30
|
+
end
|
16
31
|
end
|
17
32
|
|
@@ -124,7 +124,27 @@ class WcoEmail::Message
|
|
124
124
|
})
|
125
125
|
|
126
126
|
else
|
127
|
-
|
127
|
+
if filter.actions.present?
|
128
|
+
filter.actions.each do |act|
|
129
|
+
case act.kind
|
130
|
+
when ::WcoEmail::ACTION_REMOVE_TAG
|
131
|
+
this_tag = Wco::Tag.find( act.value )
|
132
|
+
conv.tags -= [ this_tag ]
|
133
|
+
when ::WcoEmail::ACTION_ADD_TAG
|
134
|
+
this_tag = Wco::Tag.find( act.value )
|
135
|
+
conv.tags += [ this_tag ]
|
136
|
+
when ::WcoEmail::ACTION_AUTORESPOND
|
137
|
+
this_template = WcoEmail::EmailTemplate.find( act.value )
|
138
|
+
WcoEmail::Context.create!({
|
139
|
+
email_template: this_template,
|
140
|
+
lead_id: lead.id,
|
141
|
+
send_at: Time.now,
|
142
|
+
})
|
143
|
+
end
|
144
|
+
end
|
145
|
+
else
|
146
|
+
raise "unknown filter kind: #{filter.kind}"
|
147
|
+
end
|
128
148
|
end
|
129
149
|
|
130
150
|
conv.save!
|
@@ -57,7 +57,7 @@ class WcoEmail::MessageStub
|
|
57
57
|
raw = @client.get_object( bucket: stub.bucket, key: stub.object_key ).body.read
|
58
58
|
raw = raw.encode('utf-8', invalid: :replace, undef: :replace, replace: '_' )
|
59
59
|
the_mail = Mail.new( raw )
|
60
|
-
puts! the_mail, 'the_mail'
|
60
|
+
# puts! the_mail, 'the_mail'
|
61
61
|
|
62
62
|
message_id = the_mail.header['message-id']&.decoded
|
63
63
|
message_id ||= "#{the_mail.date&.iso8601}::#{the_mail.from}"
|
@@ -199,6 +199,24 @@ class WcoEmail::MessageStub
|
|
199
199
|
reason = 'subject_exact'
|
200
200
|
end
|
201
201
|
|
202
|
+
filter.conditions.each do |cond|
|
203
|
+
case cond.field
|
204
|
+
when WcoEmail::FIELD_LEADSET
|
205
|
+
if cond.operator == WcoEmail::OPERATOR_NOT_HAS_TAG
|
206
|
+
this_tag = Wco::Tag.find cond.value
|
207
|
+
if leadset.tags.include?( this_tag )
|
208
|
+
;
|
209
|
+
else
|
210
|
+
reason = "condition leadset not-has-tag #{this_tag} NOT met"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
when WcoEmail::FIELD_TO
|
214
|
+
if @message.to == cond.value
|
215
|
+
reason = "condition to = #{cond.value}"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
202
220
|
if reason
|
203
221
|
puts! "Applying filter #{filter} to conv #{@message.conversation} for matching #{reason}" if DEBUG
|
204
222
|
|
data/config/routes.rb
CHANGED
data/lib/wco_models.rb
CHANGED
@@ -31,7 +31,30 @@ INACTIVE = 'inactive'
|
|
31
31
|
STATUSES = [ nil, ACTIVE, INACTIVE ]
|
32
32
|
|
33
33
|
module Wco; end
|
34
|
-
|
34
|
+
|
35
|
+
module WcoEmail
|
36
|
+
ACTION_ADD_TAG = 'add-tag'
|
37
|
+
ACTION_AUTORESPOND = 'autorespond-template'
|
38
|
+
ACTION_EXE = 'exe'
|
39
|
+
ACTION_SCHEDULE_EMAIL_ACTION = 'autorespond-email-action'
|
40
|
+
ACTION_REMOVE_EMAIL_ACTION = 'remove-email-action'
|
41
|
+
ACTION_REMOVE_TAG = 'remove-tag'
|
42
|
+
ACTIONS = [ 'add-tag', 'autorespond-email-action', 'autorespond-template', 'exe', 'remove-email-action', 'remove-tag' ]
|
43
|
+
|
44
|
+
FIELD_BODY = 'body'
|
45
|
+
FIELD_EXE = 'exe'
|
46
|
+
FIELD_FROM = 'from'
|
47
|
+
FIELD_LEADSET = 'leadset'
|
48
|
+
FIELD_SUBJECT = 'subject'
|
49
|
+
FIELD_TO = 'to'
|
50
|
+
|
51
|
+
OPERATOR_EQUALS = 'equals'
|
52
|
+
OPERATOR_HAS_TAG = 'has-tag'
|
53
|
+
OPERATOR_NOT_HAS_TAG = 'not-has-tag'
|
54
|
+
OPERATOR_TEXT_INPUT = 'text-input'
|
55
|
+
OPERATORS = [ 'equals', 'has-tag', 'not-has-tag', 'text-input' ]
|
56
|
+
end
|
57
|
+
|
35
58
|
module WcoHosting; end
|
36
59
|
|
37
60
|
class Wco::HTTParty
|
@@ -40,4 +63,3 @@ class Wco::HTTParty
|
|
40
63
|
end
|
41
64
|
|
42
65
|
ActiveSupport.escape_html_entities_in_json = true
|
43
|
-
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wco_models
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.0.
|
4
|
+
version: 3.1.0.191
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Victor Pudeyev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-01-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ahoy_matey
|
@@ -429,6 +429,7 @@ files:
|
|
429
429
|
- app/assets/stylesheets/wco/videos.scss
|
430
430
|
- app/controllers/wco/api/leads_controller.rb
|
431
431
|
- app/controllers/wco/api/obfuscated_redirects_controller.rb
|
432
|
+
- app/controllers/wco/api/tags_controller.rb
|
432
433
|
- app/controllers/wco/api_controller.rb
|
433
434
|
- app/controllers/wco/application_controller.rb
|
434
435
|
- app/controllers/wco/galleries_controller.rb
|
@@ -499,6 +500,7 @@ files:
|
|
499
500
|
- app/models/wco_email/email_action_template.rb
|
500
501
|
- app/models/wco_email/email_action_template_tie.rb
|
501
502
|
- app/models/wco_email/email_filter.rb
|
503
|
+
- app/models/wco_email/email_filter_action.rb
|
502
504
|
- app/models/wco_email/email_filter_condition.rb
|
503
505
|
- app/models/wco_email/email_template.rb
|
504
506
|
- app/models/wco_email/message.rb
|
@@ -525,6 +527,7 @@ files:
|
|
525
527
|
- app/views/wco/_search.haml
|
526
528
|
- app/views/wco/_select_all.haml
|
527
529
|
- app/views/wco/api/leads/index_hash.jbuilder
|
530
|
+
- app/views/wco/api/tags/index.json.jbuilder
|
528
531
|
- app/views/wco/application/_alerts_notices.haml
|
529
532
|
- app/views/wco/application/_auth_widget.haml
|
530
533
|
- app/views/wco/application/_debug.haml
|