pg_rails 7.0.8.pre.alpha.82 → 7.0.8.pre.alpha.84
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/pg_engine/app/admin/email_logs.rb +37 -0
- data/pg_engine/app/controllers/admin/email_logs_controller.rb +50 -0
- data/pg_engine/app/controllers/pg_engine/base_controller.rb +3 -0
- data/pg_engine/app/controllers/public/webhooks_controller.rb +77 -0
- data/pg_engine/app/decorators/email_log_decorator.rb +16 -0
- data/pg_engine/app/models/email.rb +16 -2
- data/pg_engine/app/models/email_log.rb +59 -0
- data/pg_engine/app/policies/email_log_policy.rb +31 -0
- data/pg_engine/app/views/admin/email_logs/_email_log.html.slim +1 -0
- data/pg_engine/app/views/admin/email_logs/_form.html.slim +16 -0
- data/pg_engine/app/views/admin/email_logs/show.html.slim +18 -0
- data/pg_engine/app/views/admin/emails/show.html.slim +20 -4
- data/pg_engine/app/views/pg_engine/base/index.html.slim +2 -0
- data/pg_engine/config/locales/es.yml +1 -0
- data/pg_engine/config/routes.rb +26 -0
- data/pg_engine/db/migrate/20240523183651_create_email_logs.rb +19 -0
- data/pg_engine/lib/pg_engine/email_observer.rb +4 -2
- data/pg_engine/lib/pg_engine/mailgun/log_sync.rb +36 -35
- data/pg_engine/lib/pg_engine/utils/check_invalid_records.rb +39 -0
- data/pg_engine/lib/pg_engine/utils/pg_logger.rb +20 -2
- data/pg_engine/spec/controllers/admin/email_logs_controller_spec.rb +179 -0
- data/pg_engine/spec/controllers/pg_engine/base_controller_spec.rb +11 -0
- data/pg_engine/spec/controllers/public/webhooks_controller_spec.rb +142 -0
- data/pg_engine/spec/factories/email_logs.rb +20 -0
- data/pg_engine/spec/lib/pg_engine/mailgun/log_sync_spec.rb +81 -7
- data/pg_engine/spec/models/email_log_spec.rb +48 -0
- data/pg_engine/spec/models/email_spec.rb +35 -0
- data/pg_layout/app/views/layouts/pg_layout/base.html.slim +11 -0
- data/pg_rails/lib/pg_rails/rspec_logger_matchers.rb +62 -0
- data/pg_rails/lib/version.rb +1 -1
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c61900d2d0b3a827718b84a3cab67f4851b2eb3087e7fbc1d313f0acf163bf3
|
4
|
+
data.tar.gz: bfca92cbb58ba292877ccb61b15b08049a0d800fdc13408f82647e9ea7c66ee9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2282deaa98881e20bd0b754c6496fc9da679214760ea45fd5f8c2f0b64a0903e1557cffb2f8d4c13b156d46e62b237113bf8f24bdba676436a404eb1e57e37c5
|
7
|
+
data.tar.gz: d9ece2e6b39c53169548c253afdb18fb9707d76bc762b0b86b7cc2656e563a4efea6d303f51814aac22926effd37ef1ec1d6c6a6d00bded153476864586f6b14
|
@@ -0,0 +1,37 @@
|
|
1
|
+
ActiveAdmin.register EmailLog do
|
2
|
+
permit_params :email_id, :log_id, :event, :log_level, :severity, :timestamp, :message_id
|
3
|
+
|
4
|
+
index do
|
5
|
+
selectable_column
|
6
|
+
id_column
|
7
|
+
column :email
|
8
|
+
column :log_id
|
9
|
+
column :event
|
10
|
+
column :log_level
|
11
|
+
column :severity
|
12
|
+
column :timestamp
|
13
|
+
column :message_id
|
14
|
+
actions
|
15
|
+
end
|
16
|
+
|
17
|
+
filter :email
|
18
|
+
filter :log_id
|
19
|
+
filter :event
|
20
|
+
filter :log_level
|
21
|
+
filter :severity
|
22
|
+
filter :timestamp
|
23
|
+
filter :message_id
|
24
|
+
|
25
|
+
form do |f|
|
26
|
+
f.inputs do
|
27
|
+
f.input :email
|
28
|
+
f.input :log_id
|
29
|
+
f.input :event
|
30
|
+
f.input :log_level
|
31
|
+
f.input :severity
|
32
|
+
f.input :timestamp
|
33
|
+
f.input :message_id
|
34
|
+
end
|
35
|
+
f.actions
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# generado con pg_rails
|
4
|
+
|
5
|
+
module Admin
|
6
|
+
class EmailLogsController < AdminController
|
7
|
+
include PgEngine::Resource
|
8
|
+
|
9
|
+
before_action { @clase_modelo = EmailLog }
|
10
|
+
|
11
|
+
before_action(only: :index) { authorize EmailLog }
|
12
|
+
|
13
|
+
before_action :set_instancia_modelo, only: %i[new create show edit update destroy]
|
14
|
+
|
15
|
+
add_breadcrumb EmailLog.nombre_plural, :admin_email_logs_path
|
16
|
+
|
17
|
+
before_action do
|
18
|
+
@actions = [
|
19
|
+
["Mailgun sync: #{ENV.fetch('MAILGUN_DOMAIN', nil)}", mailgun_sync_admin_email_logs_path, {
|
20
|
+
'data-turbo-method': :post, class: 'me-2 btn btn-primary btn-sm'
|
21
|
+
}]
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
def mailgun_sync
|
26
|
+
@new_items = PgEngine::Mailgun::LogSync.download
|
27
|
+
flash[:success] = "#{@new_items.length} nuevos items"
|
28
|
+
|
29
|
+
redirect_to admin_email_logs_path
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def atributos_permitidos
|
35
|
+
%i[email_id log_id event log_level severity timestamp message_id]
|
36
|
+
end
|
37
|
+
|
38
|
+
def atributos_para_buscar
|
39
|
+
%i[email log_id event log_level severity timestamp message_id]
|
40
|
+
end
|
41
|
+
|
42
|
+
def atributos_para_listar
|
43
|
+
%i[email log_id event log_level severity timestamp message_id]
|
44
|
+
end
|
45
|
+
|
46
|
+
def atributos_para_mostrar
|
47
|
+
%i[email log_id event log_level severity timestamp message_id]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Public
|
2
|
+
class WebhooksController < PublicController
|
3
|
+
skip_before_action :verify_authenticity_token
|
4
|
+
|
5
|
+
before_action :verify_signature, only: :mailgun
|
6
|
+
|
7
|
+
rescue_from StandardError do
|
8
|
+
pg_err 'webhook internal server error', request.body.read
|
9
|
+
head :internal_server_error
|
10
|
+
end
|
11
|
+
|
12
|
+
rescue_from ActionDispatch::Http::Parameters::ParseError do
|
13
|
+
pg_warn 'webhook parser error', request.body.read
|
14
|
+
head :bad_request
|
15
|
+
end
|
16
|
+
|
17
|
+
def mailgun
|
18
|
+
if PgEngine::Mailgun::LogSync.digest(params['event-data'])
|
19
|
+
head :ok
|
20
|
+
else
|
21
|
+
# Si no se guardó el log es porque ya existía un log con ese ID
|
22
|
+
# Mando :not_acceptable (406) para que Mailgun no vuelva a intentar
|
23
|
+
# https://documentation.mailgun.com/docs/mailgun/user-manual/tracking-messages
|
24
|
+
pg_warn 'ya existía un log con ese id, raaaaro', params
|
25
|
+
head :not_acceptable
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def used_tokens
|
32
|
+
Kredis.unique_list 'mailgun_webhook_used_tokens'
|
33
|
+
end
|
34
|
+
|
35
|
+
def not_used_token(token)
|
36
|
+
if used_tokens.elements.include?(token)
|
37
|
+
pg_warn 'Mailgun Webhook: refusing used token'
|
38
|
+
head :ok
|
39
|
+
|
40
|
+
false
|
41
|
+
else
|
42
|
+
used_tokens << token
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def timestamp_not_too_far(timestamp)
|
48
|
+
if (Time.zone.at(timestamp.to_i) - Time.zone.now).abs > 1.hour
|
49
|
+
pg_warn 'Mailgun Webhook: refusing due to timestamp too far'
|
50
|
+
head :ok
|
51
|
+
|
52
|
+
false
|
53
|
+
else
|
54
|
+
true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def verify_signature
|
59
|
+
timestamp = params['signature']['timestamp']
|
60
|
+
token = params['signature']['token']
|
61
|
+
signature = params['signature']['signature']
|
62
|
+
hexdigest = encode(timestamp + token)
|
63
|
+
|
64
|
+
return unless not_used_token(token)
|
65
|
+
return unless timestamp_not_too_far(timestamp)
|
66
|
+
return unless hexdigest != signature
|
67
|
+
|
68
|
+
pg_warn 'Mailgun Webhook: refusing invalid signature'
|
69
|
+
head :ok
|
70
|
+
end
|
71
|
+
|
72
|
+
def encode(data)
|
73
|
+
webhook_secret_key = Rails.application.credentials.dig(:mailgun, :webhook_secret_key)
|
74
|
+
OpenSSL::HMAC.hexdigest('sha256', webhook_secret_key, data)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# generado con pg_rails
|
4
|
+
|
5
|
+
class EmailLogDecorator < PgEngine::BaseRecordDecorator
|
6
|
+
delegate_all
|
7
|
+
|
8
|
+
# Define presentation-specific methods here. Helpers are accessed through
|
9
|
+
# `helpers` (aka `h`). You can override attributes, for example:
|
10
|
+
#
|
11
|
+
# def created_at
|
12
|
+
# helpers.content_tag :span, class: 'time' do
|
13
|
+
# object.created_at.strftime("%a %m/%d/%y")
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
end
|
@@ -45,10 +45,10 @@ class Email < ApplicationRecord
|
|
45
45
|
belongs_to :creado_por, optional: true, class_name: 'User'
|
46
46
|
belongs_to :actualizado_por, optional: true, class_name: 'User'
|
47
47
|
|
48
|
-
|
48
|
+
has_many :email_logs, dependent: :destroy
|
49
49
|
|
50
50
|
# TODO: y el fallido temporario?
|
51
|
-
enumerize :status, in: { pending: 0, failed: 1, sent: 2, accepted: 3, delivered: 4, rejected: 5 }
|
51
|
+
enumerize :status, in: { pending: 0, failed: 1, sent: 2, accepted: 3, delivered: 4, rejected: 5 }, scope: true
|
52
52
|
|
53
53
|
validates :from_address, :to, :status, presence: true
|
54
54
|
|
@@ -74,4 +74,18 @@ class Email < ApplicationRecord
|
|
74
74
|
end
|
75
75
|
|
76
76
|
# validates_format_of :subject, with: /\A[[[:alpha:]]\(\)\w\s.,;!¡?¿-]+\z/
|
77
|
+
|
78
|
+
def update_status!
|
79
|
+
statuses = email_logs.map(&:status_for_email).compact
|
80
|
+
|
81
|
+
# Aprovechando que los values de status están dispuestos de manera "cronologica"
|
82
|
+
new_status = statuses.map { |st| Email.status.find_value(st).value }.max
|
83
|
+
return unless new_status
|
84
|
+
|
85
|
+
self.status = new_status
|
86
|
+
return unless changed?
|
87
|
+
|
88
|
+
self.audit_comment = 'Actualizando status desde logs'
|
89
|
+
save!
|
90
|
+
end
|
77
91
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: email_logs
|
6
|
+
#
|
7
|
+
# id :bigint not null, primary key
|
8
|
+
# event :string
|
9
|
+
# log_level :string
|
10
|
+
# severity :string
|
11
|
+
# timestamp :bigint
|
12
|
+
# created_at :datetime not null
|
13
|
+
# updated_at :datetime not null
|
14
|
+
# email_id :bigint indexed
|
15
|
+
# log_id :string
|
16
|
+
# message_id :string
|
17
|
+
#
|
18
|
+
# Foreign Keys
|
19
|
+
#
|
20
|
+
# fk_rails_... (email_id => emails.id)
|
21
|
+
#
|
22
|
+
# generado con pg_rails
|
23
|
+
|
24
|
+
class EmailLog < ApplicationRecord
|
25
|
+
audited
|
26
|
+
|
27
|
+
belongs_to :email, optional: true
|
28
|
+
|
29
|
+
after_create_commit do
|
30
|
+
email.update_status! if email.present?
|
31
|
+
end
|
32
|
+
|
33
|
+
def status_for_email
|
34
|
+
case event
|
35
|
+
when 'accepted'
|
36
|
+
'accepted'
|
37
|
+
when 'delivered'
|
38
|
+
'delivered'
|
39
|
+
when 'failed'
|
40
|
+
if severity == 'permanent'
|
41
|
+
'rejected'
|
42
|
+
elsif severity == 'temporary'
|
43
|
+
'accepted'
|
44
|
+
else
|
45
|
+
# :nocov:
|
46
|
+
pg_warn 'No se pudo detectar el status de email', self
|
47
|
+
nil
|
48
|
+
# :nocov:
|
49
|
+
end
|
50
|
+
when 'opened'
|
51
|
+
# No cambia el status
|
52
|
+
else
|
53
|
+
# :nocov:
|
54
|
+
pg_warn 'No se pudo detectar el status de email', self
|
55
|
+
nil
|
56
|
+
# :nocov:
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# generado con pg_rails
|
4
|
+
|
5
|
+
class EmailLogPolicy < ApplicationPolicy
|
6
|
+
class Scope < ApplicationPolicy::Scope
|
7
|
+
# def resolve
|
8
|
+
# if policy.acceso_total?
|
9
|
+
# scope.all
|
10
|
+
# else
|
11
|
+
# scope.none
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
end
|
15
|
+
|
16
|
+
# def puede_editar?
|
17
|
+
# acceso_total? && !record.readonly?
|
18
|
+
# end
|
19
|
+
|
20
|
+
# def puede_crear?
|
21
|
+
# acceso_total? || user.asesor?
|
22
|
+
# end
|
23
|
+
|
24
|
+
# def puede_borrar?
|
25
|
+
# acceso_total? && !record.readonly?
|
26
|
+
# end
|
27
|
+
|
28
|
+
# def acceso_total?
|
29
|
+
# user.developer?
|
30
|
+
# end
|
31
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
h1 el partiaaal
|
@@ -0,0 +1,16 @@
|
|
1
|
+
/ # locals: (object: nil, asociable: false)
|
2
|
+
|
3
|
+
div style="max-width: 22em" data-controller="pg_form"
|
4
|
+
= pg_form_for(@email_log || object, asociable:) do |f|
|
5
|
+
= f.mensajes_de_error
|
6
|
+
|
7
|
+
= hidden_field_tag :asociable, true if asociable
|
8
|
+
= f.pg_associable :email
|
9
|
+
= f.input :log_id
|
10
|
+
= f.input :event
|
11
|
+
= f.input :log_level
|
12
|
+
= f.input :severity
|
13
|
+
= f.input :timestamp
|
14
|
+
= f.input :message_id
|
15
|
+
.mt-2
|
16
|
+
= f.button :submit
|
@@ -0,0 +1,18 @@
|
|
1
|
+
- content_for :title do
|
2
|
+
= @email_log.to_s
|
3
|
+
- content_for :actions do
|
4
|
+
= @email_log.destroy_link_redirect
|
5
|
+
.ms-1
|
6
|
+
= @email_log.edit_link
|
7
|
+
|
8
|
+
table.table.table-borderless.table-sm.w-auto.mb-0.m-3
|
9
|
+
- atributos_para_mostrar.each do |att|
|
10
|
+
tr
|
11
|
+
th = @clase_modelo.human_attribute_name(att)
|
12
|
+
td = @email_log.send(att)
|
13
|
+
tr
|
14
|
+
th = t('attributes.created_at')
|
15
|
+
td = @email_log.created_at
|
16
|
+
tr
|
17
|
+
th = t('attributes.updated_at')
|
18
|
+
td = @email_log.updated_at
|
@@ -23,7 +23,23 @@ table.table.table-borderless.table-sm.w-auto.mb-0.m-3
|
|
23
23
|
th = t('attributes.updated_at')
|
24
24
|
td = @email.updated_at
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
.m-4
|
27
|
+
h4 Logs
|
28
|
+
table.table
|
29
|
+
tr
|
30
|
+
th log_id
|
31
|
+
th event
|
32
|
+
th log_level
|
33
|
+
th severity
|
34
|
+
th timestamp
|
35
|
+
th created_at
|
36
|
+
th updated_at
|
37
|
+
- @email.email_logs.order(timestamp: :desc).each do |log|
|
38
|
+
tr
|
39
|
+
td = log.log_id
|
40
|
+
td = log.event
|
41
|
+
td = log.log_level
|
42
|
+
td = log.severity
|
43
|
+
td = log.timestamp
|
44
|
+
td = log.created_at
|
45
|
+
td = log.updated_at
|
@@ -69,6 +69,7 @@ es:
|
|
69
69
|
new:
|
70
70
|
sign_up: Crear una cuenta
|
71
71
|
passwords:
|
72
|
+
send_instructions: Vas a recibir un correo con instrucciones sobre cómo resetear tu contraseña en unos pocos minutos.
|
72
73
|
new:
|
73
74
|
send_me_reset_password_instructions: Enviar instrucciones para restablecer contraseña
|
74
75
|
forgot_your_password: ¿Olvidaste tu contraseña?
|
data/pg_engine/config/routes.rb
CHANGED
@@ -3,6 +3,7 @@ include PgEngine::RouteHelpers
|
|
3
3
|
Rails.application.routes.draw do
|
4
4
|
namespace :public, path: '' do
|
5
5
|
pg_resource(:mensaje_contactos, only: [:new, :create], path: 'contacto')
|
6
|
+
post 'webhook/mailgun', to: 'webhooks#mailgun'
|
6
7
|
end
|
7
8
|
devise_for :users, controllers: {
|
8
9
|
confirmations: 'users/confirmations',
|
@@ -10,6 +11,11 @@ Rails.application.routes.draw do
|
|
10
11
|
}, failure_app: PgEngine::DeviseFailureApp
|
11
12
|
namespace :admin, path: 'a' do
|
12
13
|
pg_resource(:emails)
|
14
|
+
pg_resource(:email_logs) do
|
15
|
+
collection do
|
16
|
+
post :mailgun_sync
|
17
|
+
end
|
18
|
+
end
|
13
19
|
pg_resource(:users)
|
14
20
|
pg_resource(:accounts)
|
15
21
|
pg_resource(:user_accounts)
|
@@ -102,6 +108,17 @@ end
|
|
102
108
|
# PATCH /a/emails/:id(.:format) admin/emails#update
|
103
109
|
# PUT /a/emails/:id(.:format) admin/emails#update
|
104
110
|
# DELETE /a/emails/:id(.:format) admin/emails#destroy
|
111
|
+
# abrir_modal_admin_email_logs GET /a/email_logs/abrir_modal(.:format) admin/email_logs#abrir_modal
|
112
|
+
# buscar_admin_email_logs POST /a/email_logs/buscar(.:format) admin/email_logs#buscar
|
113
|
+
# mailgun_sync_admin_email_logs POST /a/email_logs/mailgun_sync(.:format) admin/email_logs#mailgun_sync
|
114
|
+
# admin_email_logs GET /a/email_logs(.:format) admin/email_logs#index
|
115
|
+
# POST /a/email_logs(.:format) admin/email_logs#create
|
116
|
+
# new_admin_email_log GET /a/email_logs/new(.:format) admin/email_logs#new
|
117
|
+
# edit_admin_email_log GET /a/email_logs/:id/edit(.:format) admin/email_logs#edit
|
118
|
+
# admin_email_log GET /a/email_logs/:id(.:format) admin/email_logs#show
|
119
|
+
# PATCH /a/email_logs/:id(.:format) admin/email_logs#update
|
120
|
+
# PUT /a/email_logs/:id(.:format) admin/email_logs#update
|
121
|
+
# DELETE /a/email_logs/:id(.:format) admin/email_logs#destroy
|
105
122
|
# abrir_modal_admin_users GET /a/users/abrir_modal(.:format) admin/users#abrir_modal
|
106
123
|
# buscar_admin_users POST /a/users/buscar(.:format) admin/users#buscar
|
107
124
|
# admin_users GET /a/users(.:format) admin/users#index
|
@@ -165,6 +182,15 @@ end
|
|
165
182
|
# active_admin_audited_audits GET /active_admin/audited_audits(.:format) active_admin/audited_audits#index
|
166
183
|
# active_admin_audited_audit GET /active_admin/audited_audits/:id(.:format) active_admin/audited_audits#show
|
167
184
|
# active_admin_dashboard GET /active_admin/dashboard(.:format) active_admin/dashboard#index
|
185
|
+
# batch_action_active_admin_email_logs POST /active_admin/email_logs/batch_action(.:format) active_admin/email_logs#batch_action
|
186
|
+
# active_admin_email_logs GET /active_admin/email_logs(.:format) active_admin/email_logs#index
|
187
|
+
# POST /active_admin/email_logs(.:format) active_admin/email_logs#create
|
188
|
+
# new_active_admin_email_log GET /active_admin/email_logs/new(.:format) active_admin/email_logs#new
|
189
|
+
# edit_active_admin_email_log GET /active_admin/email_logs/:id/edit(.:format) active_admin/email_logs#edit
|
190
|
+
# active_admin_email_log GET /active_admin/email_logs/:id(.:format) active_admin/email_logs#show
|
191
|
+
# PATCH /active_admin/email_logs/:id(.:format) active_admin/email_logs#update
|
192
|
+
# PUT /active_admin/email_logs/:id(.:format) active_admin/email_logs#update
|
193
|
+
# DELETE /active_admin/email_logs/:id(.:format) active_admin/email_logs#destroy
|
168
194
|
# batch_action_active_admin_emails POST /active_admin/emails/batch_action(.:format) active_admin/emails#batch_action
|
169
195
|
# active_admin_emails GET /active_admin/emails(.:format) active_admin/emails#index
|
170
196
|
# active_admin_email GET /active_admin/emails/:id(.:format) active_admin/emails#show
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# generado con pg_rails
|
2
|
+
|
3
|
+
class CreateEmailLogs < ActiveRecord::Migration[7.1]
|
4
|
+
def change
|
5
|
+
create_table :email_logs do |t|
|
6
|
+
t.references :email, foreign_key: true
|
7
|
+
t.string :log_id
|
8
|
+
t.string :event
|
9
|
+
t.string :log_level
|
10
|
+
t.string :severity
|
11
|
+
t.bigint :timestamp
|
12
|
+
t.string :message_id
|
13
|
+
|
14
|
+
|
15
|
+
t.timestamps
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -20,8 +20,10 @@ module PgEngine
|
|
20
20
|
pg_err e
|
21
21
|
end
|
22
22
|
|
23
|
-
def self.get_status(
|
24
|
-
|
23
|
+
def self.get_status(_message)
|
24
|
+
# TODO: falta implementar el interceptor y habría que dar algún detalle de por uqé se bloqueó
|
25
|
+
# message.perform_deliveries ? :sent : :failed
|
26
|
+
:sent
|
25
27
|
end
|
26
28
|
end
|
27
29
|
end
|
@@ -8,8 +8,6 @@ module PgEngine
|
|
8
8
|
module Mailgun
|
9
9
|
class LogSync
|
10
10
|
def self.download # rubocop:disable Metrics/AbcSize
|
11
|
-
domain = ENV.fetch('MAILGUN_DOMAIN')
|
12
|
-
|
13
11
|
key = Rails.application.credentials.dig(:mailgun, :api_key)
|
14
12
|
mg_client = ::Mailgun::Client.new(key)
|
15
13
|
items = []
|
@@ -17,54 +15,57 @@ module PgEngine
|
|
17
15
|
start_time = DateTime.now - 3.days
|
18
16
|
range = 1.day
|
19
17
|
current = end_time - range
|
18
|
+
|
20
19
|
loop do
|
21
20
|
get = "#{domain}/events?begin=#{current.to_i}&end=#{(current + range).to_i}&limit=300"
|
22
21
|
result = mg_client.get(get)
|
23
22
|
result.to_h!
|
24
|
-
items.push(result.body['items'])
|
25
|
-
# puts "Current: #{current}. Items count: #{result.body['items'].length}"
|
23
|
+
items.push(*result.body['items'])
|
26
24
|
current -= range
|
27
25
|
|
28
26
|
break if current < start_time
|
29
27
|
end
|
30
28
|
|
31
|
-
|
29
|
+
write_log(items)
|
32
30
|
|
33
|
-
|
31
|
+
items.map do |item|
|
32
|
+
digest(item)
|
33
|
+
end.compact
|
34
34
|
end
|
35
35
|
|
36
|
-
def self.
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
36
|
+
def self.digest(item)
|
37
|
+
message_id = item['message']['headers']['message-id']
|
38
|
+
|
39
|
+
return if EmailLog.exists?(log_id: item['id'])
|
40
|
+
|
41
|
+
EmailLog.create!(
|
42
|
+
email: Email.where(message_id:).first,
|
43
|
+
log_id: item['id'],
|
44
|
+
event: item['event'],
|
45
|
+
log_level: item['log-level'],
|
46
|
+
severity: item['severity'],
|
47
|
+
timestamp: item['timestamp'],
|
48
|
+
message_id:
|
49
|
+
)
|
42
50
|
end
|
43
51
|
|
44
|
-
def self.
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
52
|
+
def self.write_log(items)
|
53
|
+
FileUtils.mkdir_p(log_dir)
|
54
|
+
File.write("#{log_dir}/#{domain}_#{Time.zone.now.strftime('%Y-%m-%d_%H.%M.%S')}.json", items.to_json)
|
55
|
+
end
|
49
56
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
if email
|
63
|
-
email.logs << i.to_json
|
64
|
-
else
|
65
|
-
pg_warn "No existe el mail con message_id = #{message_id}", :warn
|
66
|
-
end
|
67
|
-
end
|
57
|
+
def self.domain
|
58
|
+
ENV.fetch('MAILGUN_DOMAIN')
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.log_dir
|
62
|
+
@log_dir ||= if Rails.env.test?
|
63
|
+
File.expand_path 'tmp/mailgun_logs', Rails.root
|
64
|
+
else
|
65
|
+
# :nocov:
|
66
|
+
File.expand_path 'log/mailgun_logs', Rails.root
|
67
|
+
# :nocov:
|
68
|
+
end
|
68
69
|
end
|
69
70
|
end
|
70
71
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# :nocov:
|
2
|
+
module PgEngine
|
3
|
+
module Utils
|
4
|
+
class CheckInvalidRecords
|
5
|
+
def run
|
6
|
+
invalids = []
|
7
|
+
classes.each do |klass|
|
8
|
+
klass.find_each do |record|
|
9
|
+
invalids << record unless record.valid?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
invalids.map do |r|
|
13
|
+
[
|
14
|
+
(r.account.to_s if r.respond_to?(:account)),
|
15
|
+
r.class.to_s,
|
16
|
+
r.id,
|
17
|
+
r.errors.full_messages
|
18
|
+
]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def classes
|
23
|
+
ActiveRecord::Base.descendants - ignored_classes
|
24
|
+
end
|
25
|
+
|
26
|
+
def ignored_classes
|
27
|
+
[
|
28
|
+
ActiveStorage::Record,
|
29
|
+
PgEngine::BaseRecord,
|
30
|
+
ActiveAdmin::Comment,
|
31
|
+
Audited::Audit,
|
32
|
+
ActiveStorage::Blob,
|
33
|
+
ApplicationRecord
|
34
|
+
]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
# :nocov:
|