wco_models 3.1.0.52 → 3.1.0.54

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ae41306d1c2d1a86acdc705f296feae8ba6cb9d31dcef4c1794cabaa69d8b2c
4
- data.tar.gz: 1d34eb80dc069bb504a62a08ee25da17c92cebb5805399ff570954c8bd163c3e
3
+ metadata.gz: 41ed3d61aaea366b6925edbffd7cc4cf955bfffaf21a46f029ab1e3d463e7e17
4
+ data.tar.gz: efcfd16d8db203ab26fcbe58ea9b82cb08a4d32023c986de52a9a9f61d5eb740
5
5
  SHA512:
6
- metadata.gz: 46d410929c0405cffbd123b8b376a3629fc748e75df699b56bd94d70b9576c22c09358e64c32f3bfea59fc6b1bd7ed471cb70af2c9c4cd60170b75599df4a0d6
7
- data.tar.gz: 5b7280694b1ba7790c33e70e1f0c8555733f6d2912e7af2bdaba73516adfe6417e1594384ca84896cf1d7b6ea3f9cdd1dcf419188f38dd19f0fc69ce1f20a37c
6
+ metadata.gz: 2be84afa6c6de2b06ba0257553f100523fe052fabddc365292ae9cbe450070e95bb34e2a152eb026751f582e1167ea03b3253566448e42b4e69d2e485a2a6674
7
+ data.tar.gz: 1a627331788250f7664b617dba05db34a74991aab270bc1604a2c3906860828a1940f8db049fc41ec7c335eaa15d38156bb3e8136bef46471450e62167fd7302
@@ -113,6 +113,10 @@ h5.title {
113
113
  display: flex;
114
114
  }
115
115
 
116
+ .h-500px {
117
+ min-height: 500px;
118
+ }
119
+
116
120
  /* M */
117
121
 
118
122
  .maxwidth {
@@ -7,23 +7,24 @@ class Wco::Gallery
7
7
  include Wco::Utils
8
8
  store_in collection: 'galleries'
9
9
 
10
- PER_PAGE = 6
11
10
 
12
11
  field :name
13
12
  validates :name, :uniqueness => true
14
13
  index({ :name => -1 }) ## 2023-09-23 removed uniqueness
15
14
 
15
+ field :slug
16
+ index({ :slug => -1 }, { :unique => true })
17
+ validates :slug, presence: true, uniqueness: true
18
+ before_validation :set_slug, :on => :create
19
+
16
20
  field :subhead
17
21
  field :descr, :as => :description
18
22
 
19
23
  field :is_public, type: Boolean, default: false
20
24
  # has_and_belongs_to_many :shared_profiles, :class_name => 'Wco::Profile', :inverse_of => :shared_galleries
21
25
 
22
- field :is_trash, type: Boolean, default: false
23
- field :is_done, type: Boolean, default: false
24
-
25
26
  def published
26
- where({ :is_public => true, :is_trash => false }).order_by({ :created_at => :desc })
27
+ where({ :is_public => true }).order_by({ :created_at => :desc })
27
28
  end
28
29
 
29
30
  field :x, :type => Float
@@ -31,15 +32,9 @@ class Wco::Gallery
31
32
  field :z, :type => Float
32
33
 
33
34
  field :lang, :default => 'en'
34
- # field :username
35
- # field :lead_id, type: :integer
36
35
 
37
- field :slug
38
- index({ :slug => -1 }, { :unique => true })
39
- validates :slug, presence: true, uniqueness: true
40
- before_validation :set_slug, :on => :create
41
36
 
42
- def self.list conditions = { :is_trash => false }
37
+ def self.list conditions = {}
43
38
  out = self.unscoped.where( conditions ).order_by( :created_at => :desc )
44
39
  [['', nil]] + out.map { |item| [ "#{item.created_at.strftime('%Y%m%d')} #{item.name}", item.id ] }
45
40
  end
@@ -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
@@ -51,14 +51,10 @@ class Wco::Photo
51
51
  s3_region: ::S3_CREDENTIALS[:region]
52
52
  validates_attachment_content_type :photo, :content_type => ["image/webp", "image/jpg", "image/jpeg", "image/png", "image/gif", 'application/octet-stream' ]
53
53
 
54
- def self.n_per_manager_gallery
55
- 25
56
- end
57
-
58
54
  def export_fields
59
55
  %w|
60
56
  gallery_id
61
- name descr weight is_public is_trash
57
+ name descr weight
62
58
 
63
59
  photo_file_name photo_content_type photo_file_size photo_updated_at photo_fingerprint
64
60
  |
@@ -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
- else
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.from_email_list
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.id, p.slug ] }
134
+ all.map { |p| [ p.slug, p.id ] }
122
135
  end
123
136
 
124
137
  end
@@ -67,7 +67,7 @@ class WcoEmail::Message
67
67
  def received_at ; date ; end
68
68
 
69
69
  belongs_to :conversation, class_name: 'WcoEmail::Conversation'
70
- def conv ; email_conversation ; end
70
+ def conv ; conversation ; end
71
71
 
72
72
  belongs_to :stub, class_name: 'WcoEmail::MessageStub'
73
73
 
@@ -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: 'status_pending' ) }
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
- ## This only saves a local messafe from mbox to s3.
35
- def do_process message
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
- do_process message
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
- do_process message
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.52
4
+ version: 3.1.0.54
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-10 00:00:00.000000000 Z
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