wco_models 3.1.0.53 → 3.1.0.55
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/wco/utils.scss +4 -0
- data/app/models/wco/lead.rb +6 -0
- data/app/models/wco_email/context.rb +4 -2
- data/app/models/wco_email/email_template.rb +16 -3
- data/app/models/wco_email/message.rb +1 -1
- data/app/models/wco_email/message_stub.rb +184 -6
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ae4d6cc7110308649e7a5712cbfe581d43d60020e4033bf2df363578ee65db2
|
4
|
+
data.tar.gz: 842a7799e8f0d6808b1899913ce4aeb6f6088e10df079c6ecdf845329ed566c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99f8d28d0370c8c0d080c3c622ef6f1f989c8384be29ba28ba062edd60a05f12183a7a37e73c4b19f9e05f10cd4c4d575e7d81ca5112a2c7d6497d793268f845
|
7
|
+
data.tar.gz: e85181146abbaf57ef9cbca611620fade206ea94ee0f0af5853ed912fa0647c181729e309f24080e3c278e6e9ceb2ddc67d8396eeaa4d9f6ece5437d6f9a0492
|
data/app/models/wco/lead.rb
CHANGED
@@ -14,6 +14,12 @@ class Wco::Lead
|
|
14
14
|
field :address
|
15
15
|
|
16
16
|
belongs_to :leadset, class_name: 'Wco::Leadset'
|
17
|
+
before_validation :set_leadset, on: :create
|
18
|
+
def set_leadset
|
19
|
+
domain = email.split('@')[1]
|
20
|
+
self.leadset ||= Wco::Leadset.find_or_create_by({ company_url: domain })
|
21
|
+
end
|
22
|
+
|
17
23
|
has_one :photo, class_name: 'Wco::Photo'
|
18
24
|
|
19
25
|
has_many :email_messages, class_name: '::WcoEmail::Message', inverse_of: :lead
|
@@ -25,7 +25,7 @@ class WcoEmail::Context
|
|
25
25
|
if self[:body].presence
|
26
26
|
return self[:body]
|
27
27
|
else
|
28
|
-
return tmpl
|
28
|
+
return tmpl&.body || ''
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -35,8 +35,10 @@ class WcoEmail::Context
|
|
35
35
|
def from_email
|
36
36
|
if self[:from_email].presence
|
37
37
|
return self[:from_email]
|
38
|
-
|
38
|
+
elsif tmpl&.from_email
|
39
39
|
return tmpl.from_email
|
40
|
+
else
|
41
|
+
return DEFAULT_FROM_EMAIL
|
40
42
|
end
|
41
43
|
end
|
42
44
|
|
@@ -1,4 +1,6 @@
|
|
1
1
|
|
2
|
+
DEFAULT_FROM_EMAIL = 'victor@wasya.co'
|
3
|
+
|
2
4
|
class WcoEmail::EmailTemplate
|
3
5
|
include Mongoid::Document
|
4
6
|
include Mongoid::Timestamps
|
@@ -86,9 +88,20 @@ class WcoEmail::EmailTemplate
|
|
86
88
|
'Wasya Co Mailer <no-reply@wco.com.de>',
|
87
89
|
'Wasya Co Mailer <wasyacomailer@gmail.com>',
|
88
90
|
];
|
91
|
+
FROM_EMAILS_2 = [
|
92
|
+
|
93
|
+
[ 'Victor Pudeyev <piousbox@gmail.com>', 'piousbox@gmail.com' ],
|
94
|
+
[ 'Victor Pudeyev <victor@piousbox.com>', 'victor@piousbox.com' ],
|
95
|
+
[ 'Victor Pudeyev <no-reply@piousbox.com>', 'no-reply@piousbox.com' ],
|
96
|
+
|
97
|
+
[ 'WasyaCo Consulting <no-reply@wasya.co>', 'no-reply@wasya.co' ],
|
98
|
+
[ 'Victor Pudeyev <victor@wasya.co>', 'victor@wasya.co' ],
|
99
|
+
|
100
|
+
];
|
89
101
|
field :from_email
|
90
|
-
def self.
|
91
|
-
[ [nil, nil] ] + FROM_EMAILS.map { |i| [i, i] }
|
102
|
+
def self.from_emails_list
|
103
|
+
# [ [nil, nil] ] + FROM_EMAILS.map { |i| [i, i] }
|
104
|
+
FROM_EMAILS_2
|
92
105
|
end
|
93
106
|
|
94
107
|
SIGNATURE = <<~AOL
|
@@ -118,7 +131,7 @@ class WcoEmail::EmailTemplate
|
|
118
131
|
def self.blank; self.blank_template; end
|
119
132
|
|
120
133
|
def self.list
|
121
|
-
all.map { |p| [ p.
|
134
|
+
all.map { |p| [ p.slug, p.id ] }
|
122
135
|
end
|
123
136
|
|
124
137
|
end
|
@@ -1,4 +1,10 @@
|
|
1
1
|
|
2
|
+
=begin
|
3
|
+
|
4
|
+
key = '01070861907736276273039d9ee-c69a3509-5c85-481d-822e-ba65c204e1ba-000000@eu-central-1.amazonses.com'
|
5
|
+
|
6
|
+
=end
|
7
|
+
|
2
8
|
##
|
3
9
|
## Only object_key, no validations.
|
4
10
|
## 2023-12-28 _vp_ Continue.
|
@@ -13,9 +19,9 @@ class WcoEmail::MessageStub
|
|
13
19
|
STATUS_PENDING = 'status_pending'
|
14
20
|
STATUS_PROCESSED = 'status_processed'
|
15
21
|
STATUS_FAILED = 'status_failed'
|
16
|
-
STATUSES = [ STATUS_PENDING, STATUS_PROCESSED ]
|
22
|
+
STATUSES = [ STATUS_PENDING, STATUS_PROCESSED, STATUS_FAILED ]
|
17
23
|
field :status, default: STATUS_PENDING
|
18
|
-
scope :pending, ->{ where( status:
|
24
|
+
scope :pending, ->{ where( status: STATUS_PENDING ) }
|
19
25
|
|
20
26
|
field :bucket # 'ish-ses', 'ish-ses-2024'
|
21
27
|
|
@@ -31,8 +37,180 @@ class WcoEmail::MessageStub
|
|
31
37
|
{}
|
32
38
|
AOL
|
33
39
|
|
34
|
-
|
35
|
-
|
40
|
+
def do_process
|
41
|
+
@client ||= Aws::S3::Client.new({
|
42
|
+
region: ::S3_CREDENTIALS[:region_ses],
|
43
|
+
access_key_id: ::S3_CREDENTIALS[:access_key_id_ses],
|
44
|
+
secret_access_key: ::S3_CREDENTIALS[:secret_access_key_ses],
|
45
|
+
})
|
46
|
+
stub = self
|
47
|
+
|
48
|
+
raw = @client.get_object( bucket: stub.bucket, key: stub.object_key ).body.read
|
49
|
+
the_mail = Mail.new( raw )
|
50
|
+
|
51
|
+
message_id = the_mail.header['message-id']&.decoded
|
52
|
+
message_id ||= "#{the_mail.date&.iso8601}::#{the_mail.from}"
|
53
|
+
# puts! message_id, 'message_id'
|
54
|
+
|
55
|
+
in_reply_to_id = the_mail.header['in-reply-to']&.to_s
|
56
|
+
puts! in_reply_to_id, 'in_reply_to_id'
|
57
|
+
|
58
|
+
the_mail.to = [ 'NO-RECIPIENT' ] if !the_mail.to
|
59
|
+
subject = WcoEmail::Message.strip_emoji( the_mail.subject || '(wco-no-subject)' )
|
60
|
+
puts! subject, 'subject'
|
61
|
+
|
62
|
+
## Conversation
|
63
|
+
if in_reply_to_id
|
64
|
+
in_reply_to_msg = WcoEmail::Message.where({ message_id: in_reply_to_id }).first
|
65
|
+
if !in_reply_to_msg
|
66
|
+
conv = WcoEmail::Conversation.find_or_create_by({
|
67
|
+
subject: subject,
|
68
|
+
})
|
69
|
+
in_reply_to_msg = WcoEmail::Message.find_or_create_by({
|
70
|
+
message_id: in_reply_to_id,
|
71
|
+
conversation: conv,
|
72
|
+
})
|
73
|
+
end
|
74
|
+
conv = in_reply_to_msg.conversation
|
75
|
+
else
|
76
|
+
conv = WcoEmail::Conversation.find_or_create_by({
|
77
|
+
subject: subject,
|
78
|
+
})
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
## Leadset, Lead
|
83
|
+
from = the_mail.from ? the_mail.from[0] : "nobody@unknown-doma.in"
|
84
|
+
domain = from.split('@')[1]
|
85
|
+
leadset = Wco::Leadset.where( company_url: domain ).first
|
86
|
+
leadset ||= Wco::Leadset.create( company_url: domain, email: from )
|
87
|
+
lead = Wco::Lead.find_or_create_by( email: from, leadset: leadset )
|
88
|
+
|
89
|
+
|
90
|
+
message = WcoEmail::Message.unscoped.where( message_id: message_id ).first
|
91
|
+
if message
|
92
|
+
message.message_id = "#{Time.now.strftime('%Y%m%d')}-trash-#{message.message_id}"
|
93
|
+
message.object_key = "#{Time.now.strftime('%Y%m%d')}-trash-#{message.object_key}"
|
94
|
+
message.save!( validate: false )
|
95
|
+
message.delete
|
96
|
+
end
|
97
|
+
@message = WcoEmail::Message.create!({
|
98
|
+
stub: stub,
|
99
|
+
conversation: conv,
|
100
|
+
lead: lead,
|
101
|
+
|
102
|
+
message_id: message_id,
|
103
|
+
in_reply_to_id: in_reply_to_id,
|
104
|
+
object_key: stub.object_key,
|
105
|
+
|
106
|
+
subject: subject,
|
107
|
+
date: the_mail.date,
|
108
|
+
|
109
|
+
from: from,
|
110
|
+
froms: the_mail.from,
|
111
|
+
|
112
|
+
to: the_mail.to ? the_mail.to[0] : nil,
|
113
|
+
tos: the_mail.to,
|
114
|
+
|
115
|
+
cc: the_mail.cc ? the_mail.cc[0] : nil,
|
116
|
+
ccs: the_mail.cc,
|
117
|
+
})
|
118
|
+
|
119
|
+
## Parts
|
120
|
+
the_mail.parts.each do |part|
|
121
|
+
@message.churn_subpart( part )
|
122
|
+
end
|
123
|
+
@message.save
|
124
|
+
|
125
|
+
if the_mail.parts.length == 0
|
126
|
+
body = the_mail.body.decoded.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?')
|
127
|
+
if the_mail.content_type&.include?('text/html')
|
128
|
+
@message.part_html = body
|
129
|
+
elsif the_mail.content_type&.include?('text/plain')
|
130
|
+
@message.part_txt = body
|
131
|
+
elsif the_mail.content_type.blank?
|
132
|
+
@message.part_txt = body
|
133
|
+
else
|
134
|
+
@message.logs.push "mail body of unknown type: #{the_mail.content_type}"
|
135
|
+
end
|
136
|
+
@message.save
|
137
|
+
end
|
138
|
+
|
139
|
+
## Attachments
|
140
|
+
the_mail.attachments.each do |att|
|
141
|
+
@message.save_attachment( att )
|
142
|
+
end
|
143
|
+
|
144
|
+
if !@message.save
|
145
|
+
puts! @message.errors.full_messages.join(", "), "Could not save @message"
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
conv.leads.push lead
|
150
|
+
conv.save
|
151
|
+
# lead.conversations.push conv
|
152
|
+
# lead.save
|
153
|
+
|
154
|
+
the_mail.cc&.each do |cc|
|
155
|
+
domain = cc.split('@')[1] rescue 'unknown.domain'
|
156
|
+
leadset = Wco::Leadset.find_or_create_by( company_url: domain )
|
157
|
+
Wco::Lead.find_or_create_by( email: cc, leadset: leadset )
|
158
|
+
end
|
159
|
+
|
160
|
+
conv.update_attributes({
|
161
|
+
status: WcoEmail::Conversation::STATUS_UNREAD,
|
162
|
+
latest_at: the_mail.date || Time.now.to_datetime,
|
163
|
+
from_emails: ( conv.from_emails + the_mail.from ).uniq,
|
164
|
+
preview: @message.preview_str,
|
165
|
+
})
|
166
|
+
|
167
|
+
##
|
168
|
+
## Tags
|
169
|
+
##
|
170
|
+
inbox_tag = Wco::Tag.inbox
|
171
|
+
conv.tags.push inbox_tag
|
172
|
+
conv.tags.push stub.tags
|
173
|
+
conv.save
|
174
|
+
# inbox_tag.conversations.push conv
|
175
|
+
# inbox_tag.save
|
176
|
+
|
177
|
+
|
178
|
+
## Actions & Filters
|
179
|
+
email_filters = WcoEmail::EmailFilter.active
|
180
|
+
email_filters.each do |filter|
|
181
|
+
if ( filter.from_regex.blank? || @message.from.match( filter.from_regex ) ) &&
|
182
|
+
( filter.from_exact.blank? || @message.from.downcase.include?( filter.from_exact&.downcase ) ) &&
|
183
|
+
( filter.body_exact.blank? || @message.part_html&.include?( filter.body_exact ) ) &&
|
184
|
+
( filter.subject_regex.blank? || @message.subject.match( filter.subject_regex ) ) &&
|
185
|
+
( filter.subject_exact.blank? || @message.subject.downcase.include?( filter.subject_exact&.downcase ) )
|
186
|
+
|
187
|
+
# || MiaTagger.analyze( @message.part_html, :is_spammy_recruite ).score > .5
|
188
|
+
|
189
|
+
puts! "applying filter #{filter} to conv #{conv}" if DEBUG
|
190
|
+
|
191
|
+
@message.apply_filter( filter )
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
stub.update_attributes({ status: WcoEmail::MessageStub::STATUS_PROCESSED })
|
196
|
+
|
197
|
+
## Notification
|
198
|
+
config = JSON.parse(stub.config)
|
199
|
+
if config['skip_notification']
|
200
|
+
;
|
201
|
+
else
|
202
|
+
conv = WcoEmail::Conversation.find( conv.id )
|
203
|
+
if conv.tags.include? inbox_tag
|
204
|
+
out = WcoEmail::ApplicationMailer.forwarder_notify( @message.id.to_s )
|
205
|
+
Rails.env.production? ? out.deliver_later : out.deliver_now
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
puts 'ok'
|
210
|
+
end
|
211
|
+
|
212
|
+
## This only saves a local message from mbox to s3.
|
213
|
+
def save_mbox_to_m3 message
|
36
214
|
the_mail = Mail.new(message)
|
37
215
|
key = the_mail.message_id || "no-key-#{Time.now.to_i}.#{rand(1000)}"
|
38
216
|
|
@@ -82,7 +260,7 @@ class WcoEmail::MessageStub
|
|
82
260
|
|
83
261
|
if message
|
84
262
|
if skip < @count
|
85
|
-
|
263
|
+
save_mbox_to_m3 message
|
86
264
|
print "#{@count}."
|
87
265
|
else
|
88
266
|
print "s-#{@count}."
|
@@ -98,7 +276,7 @@ class WcoEmail::MessageStub
|
|
98
276
|
|
99
277
|
if message
|
100
278
|
if skip < @count
|
101
|
-
|
279
|
+
save_mbox_to_m3 message
|
102
280
|
print "#{@count}."
|
103
281
|
else
|
104
282
|
print "s-#{@count}."
|
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.55
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Victor Pudeyev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-01-
|
11
|
+
date: 2024-01-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-s3
|