pg_rails 7.0.8.pre.alpha.84 → 7.0.8.pre.alpha.86
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/controllers/admin/emails_controller.rb +1 -1
- data/pg_engine/app/controllers/admin/users_controller.rb +1 -0
- data/pg_engine/app/controllers/concerns/pg_engine/resource.rb +3 -1
- data/pg_engine/app/controllers/public/webhooks_controller.rb +7 -6
- data/pg_engine/app/decorators/email_decorator.rb +31 -1
- data/pg_engine/app/mailers/pg_engine/base_mailer.rb +1 -0
- data/pg_engine/app/models/email.rb +4 -1
- data/pg_engine/app/policies/mensaje_contacto_policy.rb +1 -1
- data/pg_engine/app/policies/pg_engine/{application_policy.rb → base_policy.rb} +14 -19
- data/pg_engine/app/views/admin/emails/_form.html.slim +8 -7
- data/pg_engine/config/locales/es.yml +9 -2
- data/pg_engine/lib/pg_engine/utils/check_invalid_records.rb +10 -2
- data/pg_engine/lib/pg_engine.rb +6 -0
- data/pg_engine/spec/controllers/public/mensaje_contactos_controller_spec.rb +0 -6
- data/pg_engine/spec/decorators/email_decorator_spec.rb +18 -0
- data/pg_engine/spec/factories/emails.rb +1 -0
- data/pg_engine/spec/lib/pg_engine/mailgun/log_sync_spec.rb +1 -1
- data/pg_engine/spec/models/email_spec.rb +1 -1
- data/pg_engine/spec/{features → system}/destroy_spec.rb +13 -13
- data/pg_engine/spec/{features → system}/login_spec.rb +14 -14
- data/pg_engine/spec/{features → system}/signup_spec.rb +13 -13
- data/pg_layout/app/javascript/application.js +0 -91
- data/pg_layout/app/javascript/channels/consumer.js +36 -1
- data/pg_layout/app/javascript/config/bootstrap.js +42 -0
- data/pg_layout/app/javascript/config/cable_ready.js +0 -26
- data/pg_layout/app/javascript/config/index.js +3 -0
- data/pg_layout/app/javascript/config/rollbar.js +28 -0
- data/pg_layout/app/javascript/config/turbo_rails/index.js +27 -0
- data/pg_layout/app/javascript/config/turbo_rails/set_consumer.js +4 -0
- data/pg_layout/app/javascript/controllers/application.js +6 -4
- data/pg_layout/app/javascript/controllers/index.js +2 -0
- data/pg_layout/app/lib/navbar.rb +1 -0
- data/pg_layout/app/views/layouts/pg_layout/base.html.slim +3 -2
- data/pg_rails/js/index.js +1 -1
- data/pg_rails/lib/pg_rails/rspec_logger_matchers.rb +2 -1
- data/pg_rails/lib/version.rb +1 -1
- data/pg_scaffold/lib/generators/pg_pundit/templates/policy.rb +10 -6
- data/pg_scaffold/spec/generators_spec.rb +2 -1
- metadata +11 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 777adfba6510fb280d827dab94dc0a924f851608924a38e16eeedc43c3bba896
|
4
|
+
data.tar.gz: 9d099949a82596a82e8c2d62e71aaef3bda568cfc3a58793daaa2ab4d53f1d1b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 142b66b567ed6f4aa81666b04f7157bb327af673420d4a3a333c723ffb2aa85895e6c80acbfa826a4f81b1db363f025a46d2d850b9dc6b399b4fad281caffa42
|
7
|
+
data.tar.gz: 8317ed39418fe41a693810801ed8fdd5936d3b3dd4670f6247e92575c3a566962e61565c388cced8f5f8512a5910be7b06ca7d9d4b58ffe155168eca61f28749
|
@@ -17,7 +17,7 @@ module Admin
|
|
17
17
|
private
|
18
18
|
|
19
19
|
def atributos_permitidos
|
20
|
-
%i[from_address from_name reply_to to subject body_input associated_id associated_type]
|
20
|
+
%i[status from_address from_name reply_to to subject body_input associated_id associated_type]
|
21
21
|
end
|
22
22
|
|
23
23
|
def atributos_para_buscar
|
@@ -229,7 +229,9 @@ module PgEngine
|
|
229
229
|
instancia_modelo.assign_attributes(modelo_params) if action_name.in? %w[update]
|
230
230
|
end
|
231
231
|
|
232
|
-
|
232
|
+
# FIXME: estaría bueno delegar directamente a pundit, pero habría que
|
233
|
+
# arreglar tema policies
|
234
|
+
Current.user&.developer? || authorize(instancia_modelo)
|
233
235
|
|
234
236
|
# TODO: problema en create y update cuando falla la validacion
|
235
237
|
# Reproducir el error antes de arreglarlo
|
@@ -4,8 +4,8 @@ module Public
|
|
4
4
|
|
5
5
|
before_action :verify_signature, only: :mailgun
|
6
6
|
|
7
|
-
rescue_from StandardError do
|
8
|
-
pg_err 'webhook internal server error', request.body.read
|
7
|
+
rescue_from StandardError do |err|
|
8
|
+
pg_err err, 'webhook internal server error', request.body.read
|
9
9
|
head :internal_server_error
|
10
10
|
end
|
11
11
|
|
@@ -21,7 +21,7 @@ module Public
|
|
21
21
|
# Si no se guardó el log es porque ya existía un log con ese ID
|
22
22
|
# Mando :not_acceptable (406) para que Mailgun no vuelva a intentar
|
23
23
|
# https://documentation.mailgun.com/docs/mailgun/user-manual/tracking-messages
|
24
|
-
pg_warn 'ya existía un log con ese id, raaaaro',
|
24
|
+
pg_warn 'ya existía un log con ese id, raaaaro', request.body.read
|
25
25
|
head :not_acceptable
|
26
26
|
end
|
27
27
|
end
|
@@ -34,7 +34,7 @@ module Public
|
|
34
34
|
|
35
35
|
def not_used_token(token)
|
36
36
|
if used_tokens.elements.include?(token)
|
37
|
-
pg_warn 'Mailgun Webhook: refusing used token'
|
37
|
+
pg_warn 'Mailgun Webhook: refusing used token', request.body.read
|
38
38
|
head :ok
|
39
39
|
|
40
40
|
false
|
@@ -46,7 +46,7 @@ module Public
|
|
46
46
|
|
47
47
|
def timestamp_not_too_far(timestamp)
|
48
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'
|
49
|
+
pg_warn 'Mailgun Webhook: refusing due to timestamp too far', request.body.read
|
50
50
|
head :ok
|
51
51
|
|
52
52
|
false
|
@@ -65,12 +65,13 @@ module Public
|
|
65
65
|
return unless timestamp_not_too_far(timestamp)
|
66
66
|
return unless hexdigest != signature
|
67
67
|
|
68
|
-
pg_warn 'Mailgun Webhook: refusing invalid signature'
|
68
|
+
pg_warn 'Mailgun Webhook: refusing invalid signature', request.body.read
|
69
69
|
head :ok
|
70
70
|
end
|
71
71
|
|
72
72
|
def encode(data)
|
73
73
|
webhook_secret_key = Rails.application.credentials.dig(:mailgun, :webhook_secret_key)
|
74
|
+
# TODO: raise if nil
|
74
75
|
OpenSSL::HMAC.hexdigest('sha256', webhook_secret_key, data)
|
75
76
|
end
|
76
77
|
end
|
@@ -14,9 +14,39 @@ class EmailDecorator < PgEngine::BaseRecordDecorator
|
|
14
14
|
# end
|
15
15
|
# end
|
16
16
|
|
17
|
+
def status_f
|
18
|
+
klass = "badge align-content-center #{status_badge_class}"
|
19
|
+
content_tag :span, id: dom_id(object, :status), class: klass do
|
20
|
+
status_text
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def status_text
|
25
|
+
{
|
26
|
+
'pending' => 'Enviando',
|
27
|
+
'failed' => 'Falló',
|
28
|
+
'sent' => 'Enviando',
|
29
|
+
'accepted' => 'Enviando',
|
30
|
+
'delivered' => 'Entregado',
|
31
|
+
'rejected' => 'Falló'
|
32
|
+
}[object.status]
|
33
|
+
end
|
34
|
+
|
35
|
+
def status_badge_class
|
36
|
+
{
|
37
|
+
'pending' => 'text-bg-warning',
|
38
|
+
'failed' => 'text-bg-danger',
|
39
|
+
'sent' => 'text-bg-warning',
|
40
|
+
'accepted' => 'text-bg-warning',
|
41
|
+
'delivered' => 'text-bg-success',
|
42
|
+
'rejected' => 'text-bg-danger'
|
43
|
+
}[object.status]
|
44
|
+
end
|
45
|
+
|
17
46
|
def encoded_eml_link
|
18
47
|
return if object.encoded_eml.blank?
|
19
48
|
|
20
|
-
link_to 'Download', helpers.rails_blob_path(object.encoded_eml),
|
49
|
+
link_to 'Download', helpers.rails_blob_path(object.encoded_eml),
|
50
|
+
target: :_blank, rel: :noopener
|
21
51
|
end
|
22
52
|
end
|
@@ -36,6 +36,10 @@ class Email < ApplicationRecord
|
|
36
36
|
include Hashid::Rails
|
37
37
|
audited
|
38
38
|
|
39
|
+
after_commit do
|
40
|
+
associated.email_updated(self) if associated.respond_to? :email_updated
|
41
|
+
end
|
42
|
+
|
39
43
|
attr_accessor :require_body_input
|
40
44
|
|
41
45
|
has_one_attached :encoded_eml
|
@@ -63,7 +67,6 @@ class Email < ApplicationRecord
|
|
63
67
|
validates :from_name, length: { within: 0..80 }
|
64
68
|
validates :to, length: { within: 3..200 }
|
65
69
|
|
66
|
-
validates :body_input, length: { minimum: 10 }, if: -> { require_body_input }
|
67
70
|
validates :body_input, presence: true, if: -> { require_body_input }
|
68
71
|
|
69
72
|
validates :from_name, :subject, :to,
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module PgEngine
|
4
|
-
class
|
4
|
+
class BasePolicy
|
5
5
|
attr_reader :user, :record
|
6
6
|
|
7
7
|
def initialize(user, record)
|
@@ -9,19 +9,12 @@ module PgEngine
|
|
9
9
|
@record = record
|
10
10
|
end
|
11
11
|
|
12
|
-
def editar_en_lugar?
|
13
|
-
puede_editar?
|
14
|
-
end
|
15
|
-
|
16
12
|
def index?
|
17
|
-
|
18
|
-
|
19
|
-
acceso_total? || Pundit.policy_scope!(user, record).any?
|
13
|
+
base_access_to_collection?
|
20
14
|
end
|
21
15
|
|
22
16
|
def show?
|
23
|
-
|
24
|
-
acceso_total?
|
17
|
+
base_access_to_record?
|
25
18
|
end
|
26
19
|
|
27
20
|
def create?
|
@@ -57,7 +50,7 @@ module PgEngine
|
|
57
50
|
end
|
58
51
|
|
59
52
|
def resolve
|
60
|
-
if policy.
|
53
|
+
if policy.base_access_to_collection?
|
61
54
|
scope.all
|
62
55
|
else
|
63
56
|
scope.none
|
@@ -72,29 +65,31 @@ module PgEngine
|
|
72
65
|
end
|
73
66
|
|
74
67
|
def puede_editar?
|
75
|
-
|
68
|
+
base_access_to_record?
|
76
69
|
end
|
77
70
|
|
78
71
|
def puede_crear?
|
79
|
-
|
72
|
+
base_access_to_collection?
|
80
73
|
end
|
81
74
|
|
82
75
|
def puede_borrar?
|
83
|
-
|
76
|
+
base_access_to_record?
|
84
77
|
end
|
85
78
|
|
86
79
|
def export?
|
87
|
-
|
80
|
+
base_access_to_collection?
|
81
|
+
end
|
82
|
+
|
83
|
+
def base_access_to_record?
|
84
|
+
user&.developer?
|
88
85
|
end
|
89
86
|
|
90
|
-
def
|
87
|
+
def base_access_to_collection?
|
91
88
|
user&.developer?
|
92
89
|
end
|
93
90
|
|
94
91
|
def objeto_borrado?
|
95
|
-
if record.respond_to?(:
|
96
|
-
record.deleted?
|
97
|
-
elsif record.respond_to?(:discarded?)
|
92
|
+
if record.respond_to?(:discarded?)
|
98
93
|
record.discarded?
|
99
94
|
else
|
100
95
|
false
|
@@ -4,13 +4,14 @@ div style="max-width: 22em" data-controller="pg_form"
|
|
4
4
|
= pg_form_for(@email || object, asociable:) do |f|
|
5
5
|
= f.mensajes_de_error
|
6
6
|
|
7
|
-
= hidden_field_tag :asociable, true if asociable
|
8
|
-
= f.input :from_address
|
9
|
-
= f.input :from_name
|
10
|
-
= f.input :reply_to
|
11
|
-
= f.input :to
|
12
|
-
= f.input :subject
|
13
|
-
= f.input :body_input, as: :text
|
7
|
+
/ = hidden_field_tag :asociable, true if asociable
|
8
|
+
/ = f.input :from_address
|
9
|
+
/ = f.input :from_name
|
10
|
+
/ = f.input :reply_to
|
11
|
+
/ = f.input :to
|
12
|
+
/ = f.input :subject
|
13
|
+
/ = f.input :body_input, as: :text
|
14
|
+
= f.input :status
|
14
15
|
|
15
16
|
.mt-2
|
16
17
|
= f.button :submit
|
@@ -11,8 +11,15 @@ es:
|
|
11
11
|
confirmed_at: Fecha de confirmación
|
12
12
|
actualizado_por: Actualizado por
|
13
13
|
creado_por: Creado por
|
14
|
-
|
15
|
-
|
14
|
+
enumerize:
|
15
|
+
email:
|
16
|
+
status:
|
17
|
+
pending: Enviando
|
18
|
+
failed: Falló
|
19
|
+
sent: Enviando
|
20
|
+
accepted: Aceptado
|
21
|
+
delivered: Entregado
|
22
|
+
rejected: Rechazado
|
16
23
|
simple_form:
|
17
24
|
"yes": 'Sí'
|
18
25
|
"no": 'No'
|
@@ -20,15 +20,23 @@ module PgEngine
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def classes
|
23
|
-
ActiveRecord::Base.descendants
|
23
|
+
all = ActiveRecord::Base.descendants.select { |m| m.table_name.present? }
|
24
|
+
all - ignored_classes
|
24
25
|
end
|
25
26
|
|
26
27
|
def ignored_classes
|
27
28
|
[
|
29
|
+
ActionText::Record,
|
30
|
+
ActionMailbox::Record,
|
31
|
+
ActiveAdmin::Comment,
|
28
32
|
ActiveStorage::Record,
|
29
33
|
PgEngine::BaseRecord,
|
30
|
-
ActiveAdmin::Comment,
|
31
34
|
Audited::Audit,
|
35
|
+
ActionText::RichText,
|
36
|
+
ActionText::EncryptedRichText,
|
37
|
+
ActionMailbox::InboundEmail,
|
38
|
+
ActiveStorage::VariantRecord,
|
39
|
+
ActiveStorage::Attachment,
|
32
40
|
ActiveStorage::Blob,
|
33
41
|
ApplicationRecord
|
34
42
|
]
|
data/pg_engine/lib/pg_engine.rb
CHANGED
@@ -42,12 +42,6 @@ RSpec.describe Public::MensajeContactosController do
|
|
42
42
|
}
|
43
43
|
end
|
44
44
|
|
45
|
-
let(:logged_user) { create :user, :developer }
|
46
|
-
|
47
|
-
before do
|
48
|
-
sign_in logged_user if logged_user.present?
|
49
|
-
end
|
50
|
-
|
51
45
|
describe 'routing' do
|
52
46
|
it 'routes GET index correctly' do
|
53
47
|
route = { get: '/contacto/new' }
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe EmailDecorator do
|
4
|
+
let(:email) { create :email, status: }
|
5
|
+
let(:decorator) { email.decorate }
|
6
|
+
|
7
|
+
describe '#status_f' do
|
8
|
+
subject { decorator.status_f }
|
9
|
+
|
10
|
+
context 'cuando está entregado' do
|
11
|
+
let(:status) { :delivered }
|
12
|
+
|
13
|
+
it 'tiene badge success' do
|
14
|
+
expect(subject).to include('text-bg-success').and(include('Entregado'))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -13,6 +13,7 @@ FactoryBot.define do
|
|
13
13
|
to { Faker::Internet.email }
|
14
14
|
subject { Faker::Lorem.sentence }
|
15
15
|
body_input { Faker::Lorem.sentence }
|
16
|
+
status { Email.status.values.sample }
|
16
17
|
# tags { Faker::Lorem.sentence }
|
17
18
|
# associated
|
18
19
|
# message_id { Faker::Lorem.sentence }
|
@@ -75,7 +75,7 @@ describe PgEngine::Mailgun::LogSync, vcr: { cassette_name: 'mailgun/log_sync_dow
|
|
75
75
|
end
|
76
76
|
|
77
77
|
context 'cuando se asocia a un email' do
|
78
|
-
let!(:email) { create :email, message_id: 'msgid@fakeapp2024.mail' }
|
78
|
+
let!(:email) { create :email, status: :pending, message_id: 'msgid@fakeapp2024.mail' }
|
79
79
|
|
80
80
|
it do
|
81
81
|
expect(subject.email).to eq email
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'rails_helper'
|
4
4
|
|
5
|
-
describe 'Sign in'
|
5
|
+
describe 'Sign in' do
|
6
6
|
include ActionView::RecordIdentifier
|
7
7
|
|
8
8
|
shared_examples 'destroy from index' do
|
@@ -50,21 +50,21 @@ describe 'Sign in', :js do
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
]
|
60
|
-
# drivers = %i[selenium_chrome_headless_notebook]
|
61
|
-
# drivers = %i[selenium_chrome_debugger]
|
62
|
-
# drivers = %i[selenium]
|
63
|
-
# drivers = %i[selenium_chrome]
|
53
|
+
# drivers = %i[
|
54
|
+
# selenium_headless
|
55
|
+
# selenium_chrome_headless
|
56
|
+
# selenium_chrome_headless_notebook
|
57
|
+
# selenium_chrome_headless_iphone
|
58
|
+
# ]
|
59
|
+
drivers = %i[selenium_chrome_headless_iphone]
|
64
60
|
drivers = [ENV['DRIVER'].to_sym] if ENV['DRIVER'].present?
|
65
61
|
|
66
62
|
drivers.each do |driver|
|
67
|
-
context("with driver '#{driver}'"
|
63
|
+
context("with driver '#{driver}'") do
|
64
|
+
before do
|
65
|
+
driven_by driver
|
66
|
+
end
|
67
|
+
|
68
68
|
it_behaves_like 'destroy from index'
|
69
69
|
it_behaves_like 'destroy from show'
|
70
70
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'rails_helper'
|
4
4
|
|
5
|
-
describe 'Sign in'
|
5
|
+
describe 'Sign in' do
|
6
6
|
shared_examples 'sign_in' do
|
7
7
|
subject do
|
8
8
|
visit '/users/sign_in'
|
@@ -20,22 +20,22 @@ describe 'Sign in', :js do
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
]
|
30
|
-
# drivers = %i[selenium_chrome_headless_notebook]
|
31
|
-
# drivers = %i[selenium_chrome_debugger]
|
32
|
-
# drivers = %i[selenium]
|
33
|
-
# drivers = %i[selenium_chrome]
|
23
|
+
# drivers = %i[
|
24
|
+
# selenium_headless
|
25
|
+
# selenium_chrome_headless
|
26
|
+
# selenium_chrome_headless_notebook
|
27
|
+
# selenium_chrome_headless_iphone
|
28
|
+
# ]
|
29
|
+
drivers = %i[selenium_chrome_headless_iphone]
|
34
30
|
drivers = [ENV['DRIVER'].to_sym] if ENV['DRIVER'].present?
|
35
31
|
|
36
32
|
drivers.each do |driver|
|
37
|
-
context("with driver '#{driver}'"
|
38
|
-
|
33
|
+
context("with driver '#{driver}'") do
|
34
|
+
before do
|
35
|
+
driven_by driver
|
36
|
+
end
|
37
|
+
|
38
|
+
it_behaves_like 'sign_in'
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'rails_helper'
|
4
4
|
|
5
|
-
describe 'Al Registrarse'
|
5
|
+
describe 'Al Registrarse' do
|
6
6
|
include ActiveJob::TestHelper
|
7
7
|
|
8
8
|
find_scroll = proc do |selector, options = {}|
|
@@ -56,21 +56,21 @@ describe 'Al Registrarse', :js do
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
#
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
]
|
66
|
-
# drivers = %i[selenium_chrome_headless_notebook]
|
67
|
-
# drivers = %i[selenium_chrome_debugger]
|
68
|
-
# drivers = %i[selenium]
|
69
|
-
# drivers = %i[selenium_chrome]
|
59
|
+
# drivers = %i[
|
60
|
+
# selenium_headless
|
61
|
+
# selenium_chrome_headless
|
62
|
+
# selenium_chrome_headless_notebook
|
63
|
+
# selenium_chrome_headless_iphone
|
64
|
+
# ]
|
65
|
+
drivers = %i[selenium_chrome_headless_iphone]
|
70
66
|
drivers = [ENV['DRIVER'].to_sym] if ENV['DRIVER'].present?
|
71
67
|
|
72
68
|
drivers.each do |driver|
|
73
|
-
context("with driver '#{driver}'"
|
69
|
+
context("with driver '#{driver}'") do
|
70
|
+
before do
|
71
|
+
driven_by driver
|
72
|
+
end
|
73
|
+
|
74
74
|
it_behaves_like 'sign_up'
|
75
75
|
it_behaves_like 'edit user'
|
76
76
|
end
|
@@ -1,94 +1,3 @@
|
|
1
|
-
import Rollbar from 'rollbar'
|
2
|
-
|
3
1
|
import './config'
|
4
2
|
import './channels'
|
5
3
|
import './controllers'
|
6
|
-
|
7
|
-
// Bootstrap's toasts
|
8
|
-
import * as bootstrap from 'bootstrap'
|
9
|
-
|
10
|
-
let rollbarToken = document.head.querySelector('meta[name=rollbar-token]')
|
11
|
-
rollbarToken = rollbarToken && rollbarToken.content
|
12
|
-
|
13
|
-
let rollbarEnv = document.head.querySelector('meta[name=rollbar-env]')
|
14
|
-
rollbarEnv = rollbarEnv && rollbarEnv.content
|
15
|
-
rollbarEnv = rollbarEnv || 'unknown'
|
16
|
-
|
17
|
-
window.Rollbar = Rollbar
|
18
|
-
|
19
|
-
Rollbar.init()
|
20
|
-
|
21
|
-
Rollbar.global({
|
22
|
-
itemsPerMinute: 2,
|
23
|
-
maxItems: 5
|
24
|
-
})
|
25
|
-
Rollbar.configure({
|
26
|
-
enabled: !!rollbarToken,
|
27
|
-
accessToken: rollbarToken,
|
28
|
-
captureUncaught: true,
|
29
|
-
captureUnhandledRejections: true,
|
30
|
-
reportLevel: 'warning',
|
31
|
-
payload: {
|
32
|
-
environment: rollbarEnv
|
33
|
-
}
|
34
|
-
})
|
35
|
-
|
36
|
-
document.addEventListener('turbo:load', bindAndObserveToasts)
|
37
|
-
document.addEventListener('turbo:render', bindAndObserveToasts)
|
38
|
-
|
39
|
-
document.addEventListener('turbo:before-cache', () => {
|
40
|
-
document.querySelectorAll('#flash .alert').forEach((el) => {
|
41
|
-
el.remove()
|
42
|
-
})
|
43
|
-
document.querySelectorAll('.offcanvas-backdrop').forEach((el) => {
|
44
|
-
el.remove()
|
45
|
-
})
|
46
|
-
document.querySelectorAll('.offcanvas').forEach((el) => {
|
47
|
-
el.classList.remove('show')
|
48
|
-
})
|
49
|
-
})
|
50
|
-
|
51
|
-
function bindToastElements () {
|
52
|
-
const toastQuery = '.pg-toast:not(.hide):not(.show)'
|
53
|
-
|
54
|
-
const toastElList = document.querySelectorAll(toastQuery)
|
55
|
-
Array.from(toastElList).map(toastEl => {
|
56
|
-
toastEl.addEventListener('hidden.bs.toast', () => {
|
57
|
-
toastEl.remove()
|
58
|
-
})
|
59
|
-
return new bootstrap.Toast(toastEl).show()
|
60
|
-
})
|
61
|
-
}
|
62
|
-
|
63
|
-
function bindAndObserveToasts () {
|
64
|
-
bindToastElements()
|
65
|
-
|
66
|
-
// Select the node that will be observed for mutations
|
67
|
-
const targetNode = document.getElementById('flash')
|
68
|
-
|
69
|
-
// Options for the observer (which mutations to observe)
|
70
|
-
const config = { attributes: true, childList: true, subtree: true }
|
71
|
-
|
72
|
-
// Callback function to execute when mutations are observed
|
73
|
-
const callback = (mutationList, observer) => {
|
74
|
-
for (const mutation of mutationList) {
|
75
|
-
if (mutation.type === 'childList') {
|
76
|
-
bindToastElements()
|
77
|
-
}
|
78
|
-
}
|
79
|
-
}
|
80
|
-
|
81
|
-
// Create an observer instance linked to the callback function
|
82
|
-
const observer = new MutationObserver(callback)
|
83
|
-
|
84
|
-
// Start observing the target node for configured mutations
|
85
|
-
observer.observe(targetNode, config)
|
86
|
-
}
|
87
|
-
|
88
|
-
// document.addEventListener('turbo:before-stream-render', function () { console.log('turbo:before-stream-render') })
|
89
|
-
// document.addEventListener('turbo:render', function () { console.log('turbo:render') })
|
90
|
-
// document.addEventListener('turbo:before-render', function () { console.log('turbo:before-render') })
|
91
|
-
// document.addEventListener('turbo:before-frame-render', function () { console.log('turbo:before-frame-render') })
|
92
|
-
// document.addEventListener('turbo:frame-load', function () { console.log('turbo:frame-load') })
|
93
|
-
// document.addEventListener('turbo:before-fetch-request', function () { console.log('turbo:before-fetch-request') })
|
94
|
-
// document.addEventListener('turbo:fetch-request-error', function () { console.log('turbo:fetch-request-error') })
|
@@ -2,11 +2,46 @@
|
|
2
2
|
// You can generate new channels where WebSocket features live using the `bin/rails generate channel` command.
|
3
3
|
|
4
4
|
import { createConsumer } from '@anycable/web'
|
5
|
+
import Rollbar from 'rollbar'
|
5
6
|
|
6
7
|
let cableProtocol = document.head.querySelector('meta[name=actioncable-protocol]')
|
7
8
|
cableProtocol = cableProtocol && cableProtocol.content
|
8
9
|
cableProtocol = cableProtocol || 'actioncable-v1-ext-json'
|
9
10
|
|
10
|
-
|
11
|
+
const consumer = createConsumer({
|
11
12
|
protocol: cableProtocol
|
12
13
|
})
|
14
|
+
|
15
|
+
const anycable = consumer.cable
|
16
|
+
|
17
|
+
if (anycable) {
|
18
|
+
anycable.on('connect', ev => {
|
19
|
+
document.head.dataset.cableConnected = true
|
20
|
+
if (ev.reconnect) {
|
21
|
+
console.log('Welcome back!')
|
22
|
+
} else {
|
23
|
+
console.log('Welcome!')
|
24
|
+
}
|
25
|
+
})
|
26
|
+
|
27
|
+
anycable.on('disconnect', ev => {
|
28
|
+
document.head.dataset.cableConnected = false
|
29
|
+
// document.head.dataset.cableDisconnectedEvent = ev
|
30
|
+
if (ev.reason) {
|
31
|
+
if (ev.reason === 'transport_closed') {
|
32
|
+
// no hago nada (?
|
33
|
+
} else {
|
34
|
+
Rollbar.warning(`Disconnected because: ${ev.reason}`)
|
35
|
+
}
|
36
|
+
console.log(`Disconnected because: ${ev.reason}`)
|
37
|
+
} else {
|
38
|
+
Rollbar.warning('Disconnected for unknown reason')
|
39
|
+
console.log('Disconnected for unknown reason')
|
40
|
+
}
|
41
|
+
})
|
42
|
+
}
|
43
|
+
|
44
|
+
// Para desconectar
|
45
|
+
// anycable.disconnect()
|
46
|
+
|
47
|
+
export default consumer
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import * as bootstrap from 'bootstrap'
|
2
|
+
|
3
|
+
document.addEventListener('turbo:load', bindAndObserveToasts)
|
4
|
+
document.addEventListener('turbo:render', bindAndObserveToasts)
|
5
|
+
|
6
|
+
// TODO: testear con capybara
|
7
|
+
function bindToastElements () {
|
8
|
+
const toastQuery = '.pg-toast:not(.hide):not(.show)'
|
9
|
+
|
10
|
+
const toastElList = document.querySelectorAll(toastQuery)
|
11
|
+
Array.from(toastElList).map(toastEl => {
|
12
|
+
toastEl.addEventListener('hidden.bs.toast', () => {
|
13
|
+
toastEl.remove()
|
14
|
+
})
|
15
|
+
return new bootstrap.Toast(toastEl).show()
|
16
|
+
})
|
17
|
+
}
|
18
|
+
|
19
|
+
function bindAndObserveToasts () {
|
20
|
+
bindToastElements()
|
21
|
+
|
22
|
+
// Select the node that will be observed for mutations
|
23
|
+
const targetNode = document.getElementById('flash')
|
24
|
+
|
25
|
+
// Options for the observer (which mutations to observe)
|
26
|
+
const config = { attributes: true, childList: true, subtree: true }
|
27
|
+
|
28
|
+
// Callback function to execute when mutations are observed
|
29
|
+
const callback = (mutationList, observer) => {
|
30
|
+
for (const mutation of mutationList) {
|
31
|
+
if (mutation.type === 'childList') {
|
32
|
+
bindToastElements()
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
// Create an observer instance linked to the callback function
|
38
|
+
const observer = new MutationObserver(callback)
|
39
|
+
|
40
|
+
// Start observing the target node for configured mutations
|
41
|
+
observer.observe(targetNode, config)
|
42
|
+
}
|
@@ -1,30 +1,4 @@
|
|
1
1
|
import consumer from '../channels/consumer'
|
2
2
|
import CableReady from 'cable_ready'
|
3
|
-
import Rollbar from 'rollbar'
|
4
|
-
|
5
|
-
const anycable = consumer.cable
|
6
|
-
|
7
|
-
if (anycable) {
|
8
|
-
anycable.on('connect', ev => {
|
9
|
-
document.head.dataset.cableConnected = true
|
10
|
-
if (ev.reconnect) {
|
11
|
-
console.log('Welcome back!')
|
12
|
-
} else {
|
13
|
-
console.log('Welcome!')
|
14
|
-
}
|
15
|
-
})
|
16
|
-
|
17
|
-
anycable.on('disconnect', ev => {
|
18
|
-
document.head.dataset.cableConnected = false
|
19
|
-
// document.head.dataset.cableDisconnectedEvent = ev
|
20
|
-
if (ev.reason) {
|
21
|
-
Rollbar.warning(`Disconnected because: ${ev.reason}`)
|
22
|
-
console.log(`Disconnected because: ${ev.reason}`)
|
23
|
-
} else {
|
24
|
-
Rollbar.warning('Disconnected for unknown reason')
|
25
|
-
console.log('Disconnected for unknown reason')
|
26
|
-
}
|
27
|
-
})
|
28
|
-
}
|
29
3
|
|
30
4
|
CableReady.initialize({ consumer })
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import Rollbar from 'rollbar'
|
2
|
+
|
3
|
+
// TODO: testear con capybara, si se puede
|
4
|
+
let rollbarToken = document.head.querySelector('meta[name=rollbar-token]')
|
5
|
+
rollbarToken = rollbarToken && rollbarToken.content
|
6
|
+
|
7
|
+
let rollbarEnv = document.head.querySelector('meta[name=rollbar-env]')
|
8
|
+
rollbarEnv = rollbarEnv && rollbarEnv.content
|
9
|
+
rollbarEnv = rollbarEnv || 'unknown'
|
10
|
+
|
11
|
+
window.Rollbar = Rollbar
|
12
|
+
|
13
|
+
Rollbar.init()
|
14
|
+
|
15
|
+
Rollbar.global({
|
16
|
+
itemsPerMinute: 2,
|
17
|
+
maxItems: 5
|
18
|
+
})
|
19
|
+
Rollbar.configure({
|
20
|
+
enabled: !!rollbarToken,
|
21
|
+
accessToken: rollbarToken,
|
22
|
+
captureUncaught: true,
|
23
|
+
captureUnhandledRejections: true,
|
24
|
+
reportLevel: 'warning',
|
25
|
+
payload: {
|
26
|
+
environment: rollbarEnv
|
27
|
+
}
|
28
|
+
})
|
@@ -0,0 +1,27 @@
|
|
1
|
+
// Es necesario que el consumer se setee antes de cargar la librería
|
2
|
+
// para que lo tomen los TurboCableStreamSourceElement's
|
3
|
+
|
4
|
+
import './set_consumer'
|
5
|
+
|
6
|
+
import '@hotwired/turbo-rails'
|
7
|
+
|
8
|
+
// TODO: testear con capybara
|
9
|
+
document.addEventListener('turbo:before-cache', () => {
|
10
|
+
document.querySelectorAll('#flash .alert').forEach((el) => {
|
11
|
+
el.remove()
|
12
|
+
})
|
13
|
+
document.querySelectorAll('.offcanvas-backdrop').forEach((el) => {
|
14
|
+
el.remove()
|
15
|
+
})
|
16
|
+
document.querySelectorAll('.offcanvas').forEach((el) => {
|
17
|
+
el.classList.remove('show')
|
18
|
+
})
|
19
|
+
})
|
20
|
+
|
21
|
+
// document.addEventListener('turbo:before-stream-render', function () { console.log('turbo:before-stream-render') })
|
22
|
+
// document.addEventListener('turbo:render', function () { console.log('turbo:render') })
|
23
|
+
// document.addEventListener('turbo:before-render', function () { console.log('turbo:before-render') })
|
24
|
+
// document.addEventListener('turbo:before-frame-render', function () { console.log('turbo:before-frame-render') })
|
25
|
+
// document.addEventListener('turbo:frame-load', function () { console.log('turbo:frame-load') })
|
26
|
+
// document.addEventListener('turbo:before-fetch-request', function () { console.log('turbo:before-fetch-request') })
|
27
|
+
// document.addEventListener('turbo:fetch-request-error', function () { console.log('turbo:fetch-request-error') })
|
@@ -1,7 +1,9 @@
|
|
1
|
-
|
2
|
-
console.error('window.Stimulus must be set')
|
3
|
-
}
|
1
|
+
import { Application } from '@hotwired/stimulus'
|
4
2
|
|
5
|
-
const application =
|
3
|
+
const application = Application.start()
|
4
|
+
|
5
|
+
// Configure Stimulus development experience
|
6
|
+
application.debug = false
|
7
|
+
window.Stimulus = application
|
6
8
|
|
7
9
|
export { application }
|
@@ -15,3 +15,5 @@ application.register('fadein_onload', FadeinOnloadController)
|
|
15
15
|
application.register('clear-timeout', ClearTimeoutController)
|
16
16
|
application.register('switcher', SwitcherController)
|
17
17
|
application.register('filtros', FiltrosController)
|
18
|
+
|
19
|
+
// TODO: testear con capybara todo lo que se pueda
|
data/pg_layout/app/lib/navbar.rb
CHANGED
@@ -36,7 +36,8 @@ html
|
|
36
36
|
|
37
37
|
link rel="preconnect" href="https://fonts.googleapis.com"
|
38
38
|
link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="crossorigin"
|
39
|
-
link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;
|
39
|
+
link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400; \
|
40
|
+
0,500;0,700;1,300;1,400;1,500;1,700&display=swap" rel="stylesheet"
|
40
41
|
css:
|
41
42
|
body {
|
42
43
|
font-family: "Ubuntu", sans-serif;
|
@@ -59,7 +60,7 @@ html
|
|
59
60
|
nav aria-label="breadcrumb"
|
60
61
|
= render_breadcrumbs
|
61
62
|
/ = render_breadcrumbs builder: ::Bootstrap4BreadcrumbsBuilder
|
62
|
-
.btn-toolbar
|
63
|
+
.btn-toolbar.gap-1
|
63
64
|
= yield(:actions)
|
64
65
|
hr.my-0
|
65
66
|
- content = content_for?(:content) ? yield(:content) : yield
|
data/pg_rails/js/index.js
CHANGED
@@ -36,12 +36,13 @@ module PgEngine
|
|
36
36
|
def failure_message
|
37
37
|
msg = "expected to #{@level || log}"
|
38
38
|
msg << "with text: #{@text}" if @text.present?
|
39
|
-
return unless @new_messages.any?
|
39
|
+
return msg unless @new_messages.any?
|
40
40
|
|
41
41
|
msg << "\nLogged messages:"
|
42
42
|
@new_messages.each do |level, message|
|
43
43
|
msg << "\n #{level}: #{message[0..200]}"
|
44
44
|
end
|
45
|
+
msg
|
45
46
|
end
|
46
47
|
|
47
48
|
def supports_block_expectations?
|
data/pg_rails/lib/version.rb
CHANGED
@@ -10,7 +10,7 @@ require_dependency "<%= namespaced_path %>/application_policy"
|
|
10
10
|
class <%= class_name %>Policy < ApplicationPolicy
|
11
11
|
class Scope < ApplicationPolicy::Scope
|
12
12
|
# def resolve
|
13
|
-
# if policy.
|
13
|
+
# if policy.base_access_to_collection?
|
14
14
|
# scope.all
|
15
15
|
# else
|
16
16
|
# scope.none
|
@@ -19,19 +19,23 @@ class <%= class_name %>Policy < ApplicationPolicy
|
|
19
19
|
end
|
20
20
|
|
21
21
|
# def puede_editar?
|
22
|
-
#
|
22
|
+
# base_access_to_record?
|
23
23
|
# end
|
24
24
|
|
25
25
|
# def puede_crear?
|
26
|
-
#
|
26
|
+
# base_access_to_collection?
|
27
27
|
# end
|
28
28
|
|
29
29
|
# def puede_borrar?
|
30
|
-
#
|
30
|
+
# base_access_to_record?
|
31
31
|
# end
|
32
32
|
|
33
|
-
# def
|
34
|
-
#
|
33
|
+
# def base_access_to_record?
|
34
|
+
# base_access_to_collection? && record.account == Current.account
|
35
|
+
# end
|
36
|
+
|
37
|
+
# def base_access_to_collection?
|
38
|
+
# user.present?
|
35
39
|
# end
|
36
40
|
end
|
37
41
|
<% end -%>
|
@@ -4,7 +4,8 @@ require 'generators/pg_rspec/scaffold/scaffold_generator'
|
|
4
4
|
require 'generators/pg_decorator/pg_decorator_generator'
|
5
5
|
require 'generators/pg_active_record/model/model_generator'
|
6
6
|
|
7
|
-
|
7
|
+
TEST_ENV_NUMBER = ENV.fetch('TEST_ENV_NUMBER', '')
|
8
|
+
DESTINATION_PATH = File.expand_path("./../../tmp/generator_testing#{TEST_ENV_NUMBER}", __dir__)
|
8
9
|
|
9
10
|
describe 'Generators', type: :generator do
|
10
11
|
describe 'PgDecoratorGenerator' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.0.8.pre.alpha.
|
4
|
+
version: 7.0.8.pre.alpha.86
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martín Rosso
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-05-
|
11
|
+
date: 2024-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -1002,7 +1002,7 @@ files:
|
|
1002
1002
|
- pg_engine/app/policies/email_log_policy.rb
|
1003
1003
|
- pg_engine/app/policies/email_policy.rb
|
1004
1004
|
- pg_engine/app/policies/mensaje_contacto_policy.rb
|
1005
|
-
- pg_engine/app/policies/pg_engine/
|
1005
|
+
- pg_engine/app/policies/pg_engine/base_policy.rb
|
1006
1006
|
- pg_engine/app/policies/user_account_policy.rb
|
1007
1007
|
- pg_engine/app/policies/user_policy.rb
|
1008
1008
|
- pg_engine/app/policies/user_registration_policy.rb
|
@@ -1082,15 +1082,13 @@ files:
|
|
1082
1082
|
- pg_engine/spec/controllers/public/webhooks_controller_spec.rb
|
1083
1083
|
- pg_engine/spec/controllers/users/confirmations_controller_spec.rb
|
1084
1084
|
- pg_engine/spec/controllers/users/registrations_controller_spec.rb
|
1085
|
+
- pg_engine/spec/decorators/email_decorator_spec.rb
|
1085
1086
|
- pg_engine/spec/factories/accounts.rb
|
1086
1087
|
- pg_engine/spec/factories/email_logs.rb
|
1087
1088
|
- pg_engine/spec/factories/emails.rb
|
1088
1089
|
- pg_engine/spec/factories/mensaje_contactos.rb
|
1089
1090
|
- pg_engine/spec/factories/user_accounts.rb
|
1090
1091
|
- pg_engine/spec/factories/users.rb
|
1091
|
-
- pg_engine/spec/features/destroy_spec.rb
|
1092
|
-
- pg_engine/spec/features/login_spec.rb
|
1093
|
-
- pg_engine/spec/features/signup_spec.rb
|
1094
1092
|
- pg_engine/spec/fixtures/test.pdf
|
1095
1093
|
- pg_engine/spec/helpers/pg_engine/pg_rails_helper_spec.rb
|
1096
1094
|
- pg_engine/spec/helpers/pg_engine/print_helper_spec.rb
|
@@ -1107,13 +1105,20 @@ files:
|
|
1107
1105
|
- pg_engine/spec/models/user_account_spec.rb
|
1108
1106
|
- pg_engine/spec/models/user_spec.rb
|
1109
1107
|
- pg_engine/spec/pg_engine/pdf_preview_generator_spec.rb
|
1108
|
+
- pg_engine/spec/system/destroy_spec.rb
|
1109
|
+
- pg_engine/spec/system/login_spec.rb
|
1110
|
+
- pg_engine/spec/system/signup_spec.rb
|
1110
1111
|
- pg_layout/app/assets/stylesheets/animations.scss
|
1111
1112
|
- pg_layout/app/assets/stylesheets/sidebar.scss
|
1112
1113
|
- pg_layout/app/javascript/application.js
|
1113
1114
|
- pg_layout/app/javascript/channels/consumer.js
|
1114
1115
|
- pg_layout/app/javascript/channels/index.js
|
1116
|
+
- pg_layout/app/javascript/config/bootstrap.js
|
1115
1117
|
- pg_layout/app/javascript/config/cable_ready.js
|
1116
1118
|
- pg_layout/app/javascript/config/index.js
|
1119
|
+
- pg_layout/app/javascript/config/rollbar.js
|
1120
|
+
- pg_layout/app/javascript/config/turbo_rails/index.js
|
1121
|
+
- pg_layout/app/javascript/config/turbo_rails/set_consumer.js
|
1117
1122
|
- pg_layout/app/javascript/controllers/application.js
|
1118
1123
|
- pg_layout/app/javascript/controllers/clear_timeout_controller.js
|
1119
1124
|
- pg_layout/app/javascript/controllers/fadein_onload_controller.js
|