pg_rails 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +73 -0
- data/Rakefile +36 -0
- data/app/assets/javascripts/pg_rails/asociacion_creable.js +85 -0
- data/app/assets/javascripts/pg_rails/best_in_place_datepicker.js +58 -0
- data/app/assets/javascripts/pg_rails/librerias.js +13 -0
- data/app/assets/javascripts/pg_rails/librerias_b3.js +14 -0
- data/app/assets/javascripts/pg_rails/validaciones.js +44 -0
- data/app/assets/javascripts/pg_rails.js +318 -0
- data/app/assets/stylesheets/pg_rails/librerias.scss +5 -0
- data/app/assets/stylesheets/pg_rails/pg_chosen.scss +29 -0
- data/app/assets/stylesheets/pg_rails/pg_rails.scss +199 -0
- data/app/assets/stylesheets/pg_rails_b3.scss +10 -0
- data/app/assets/stylesheets/pg_rails_b4.scss +12 -0
- data/app/assets/stylesheets/pg_rails_b5.scss +1 -0
- data/app/controllers/pg_rails/application_controller.rb +316 -0
- data/app/controllers/pg_rails/editar_en_lugar_controller.rb +24 -0
- data/app/decorators/pg_rails/base_decorator.rb +120 -0
- data/app/helpers/pg_rails/editar_en_lugar_helper.rb +106 -0
- data/app/helpers/pg_rails/form_helper.rb +25 -0
- data/app/helpers/pg_rails/postgres_helper.rb +15 -0
- data/app/helpers/pg_rails/print_helper.rb +176 -0
- data/app/inputs/pg_rails/asociacion_creable_input.rb +72 -0
- data/app/inputs/pg_rails/fecha_input.rb +20 -0
- data/app/inputs/pg_rails/selects_dependientes_input.rb +9 -0
- data/app/lib/pg_form_builder.rb +31 -0
- data/app/lib/pg_rails/filtros_builder.rb +338 -0
- data/app/models/pg_rails/application_record.rb +51 -0
- data/app/policies/pg_rails/application_policy.rb +104 -0
- data/app/views/application/_abrir_modal.js.erb +14 -0
- data/app/views/application/_actualizar_smart_listing.html.slim +3 -0
- data/app/views/application/_cerrar_modal.js.erb +8 -0
- data/app/views/application/_modal_ajax_form.js.erb +7 -0
- data/config/brakeman.ignore +42 -0
- data/config/locales/es.yml +17 -0
- data/config/routes.rb +3 -0
- data/config/spring.rb +1 -0
- data/lib/pg_rails/configuracion.rb +24 -0
- data/lib/pg_rails/core_ext.rb +17 -0
- data/lib/pg_rails/engine.rb +42 -0
- data/lib/pg_rails/simple_form/initializer.rb +583 -0
- data/lib/pg_rails/utils/logueador.rb +39 -0
- data/lib/pg_rails/version.rb +5 -0
- data/lib/pg_rails.rb +23 -0
- data/lib/tasks/auto_anotar_modelos.rake +34 -0
- data/lib/tasks/pg_rails_tasks.rake +5 -0
- metadata +89 -0
@@ -0,0 +1,338 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgRails
|
4
|
+
class FiltrosBuilder
|
5
|
+
include ActionView::Helpers
|
6
|
+
include ActionView::Context
|
7
|
+
include PostgresHelper
|
8
|
+
attr_accessor :controller
|
9
|
+
|
10
|
+
SUFIJOS = %w[desde hasta incluye es_igual_a].freeze
|
11
|
+
|
12
|
+
def initialize(controller, clase_modelo, campos)
|
13
|
+
@clase_modelo = clase_modelo
|
14
|
+
@campos = campos
|
15
|
+
@controller = controller
|
16
|
+
@filtros = {}
|
17
|
+
@campos.each { |campo| @filtros[campo] = {} }
|
18
|
+
end
|
19
|
+
|
20
|
+
def opciones(campo, opciones)
|
21
|
+
# TODO: mergear
|
22
|
+
@filtros[campo] = opciones
|
23
|
+
end
|
24
|
+
|
25
|
+
# querys customizadas por campo
|
26
|
+
def query(campo, &block)
|
27
|
+
@filtros[campo] = {} if @filtros[campo].nil?
|
28
|
+
@filtros[campo][:query] = block
|
29
|
+
end
|
30
|
+
|
31
|
+
def scope_asociacion(campo, &block)
|
32
|
+
@filtros[campo] = {} if @filtros[campo].nil?
|
33
|
+
@filtros[campo][:scope_asociacion] = block
|
34
|
+
end
|
35
|
+
|
36
|
+
def algun_filtro_presente?
|
37
|
+
@campos.any? { |campo| parametros_controller[campo].present? }
|
38
|
+
end
|
39
|
+
|
40
|
+
def filtrar(query, parametros = nil)
|
41
|
+
parametros = parametros_controller if parametros.nil?
|
42
|
+
|
43
|
+
# Filtro soft deleted, y sea con paranoia o con discard
|
44
|
+
query = query.without_deleted if query.respond_to?(:without_deleted)
|
45
|
+
query = query.kept if query.respond_to?(:kept)
|
46
|
+
|
47
|
+
@filtros.each do |campo, _opciones|
|
48
|
+
next unless parametros[campo].present?
|
49
|
+
|
50
|
+
if @filtros[campo.to_sym].present? && @filtros[campo.to_sym][:query].present?
|
51
|
+
query = @filtros[campo.to_sym][:query].call(query, parametros[campo])
|
52
|
+
elsif tipo(campo) == :enumerized
|
53
|
+
columna = @clase_modelo.columns.find { |c| c.name == campo.to_s }
|
54
|
+
if columna.array
|
55
|
+
query = query.where("? = any(#{@clase_modelo.table_name}.#{campo})", parametros[campo])
|
56
|
+
else
|
57
|
+
query = query.where("#{@clase_modelo.table_name}.#{campo} = ?", parametros[campo])
|
58
|
+
end
|
59
|
+
elsif tipo(campo).in?(%i[integer float decimal])
|
60
|
+
campo_a_comparar = "#{@clase_modelo.table_name}.#{sin_sufijo(campo)}"
|
61
|
+
query = query.where("#{campo_a_comparar} #{comparador(campo)} ?", parametros[campo])
|
62
|
+
elsif tipo(campo) == :asociacion
|
63
|
+
nombre_campo = sin_sufijo(campo)
|
64
|
+
suf = extraer_sufijo(campo)
|
65
|
+
asociacion = obtener_asociacion(nombre_campo)
|
66
|
+
if asociacion.instance_of?(ActiveRecord::Reflection::HasAndBelongsToManyReflection)
|
67
|
+
array = parametros[campo].instance_of?(Array) ? parametros[campo].join(',') : parametros[campo]
|
68
|
+
query = query.joins(nombre_campo.to_sym).group("#{@clase_modelo.table_name}.id")
|
69
|
+
.having("ARRAY_AGG(#{asociacion.join_table}.#{asociacion.association_foreign_key}) #{comparador_array(suf)} ARRAY[#{array}]::bigint[]")
|
70
|
+
elsif asociacion.instance_of?(ActiveRecord::Reflection::BelongsToReflection)
|
71
|
+
query = query.where("#{@clase_modelo.table_name}.#{campo}_id = ?", parametros[campo])
|
72
|
+
else
|
73
|
+
raise 'filtro de asociacion no soportado'
|
74
|
+
end
|
75
|
+
elsif tipo(campo).in?(%i[string text])
|
76
|
+
match_vector = parametros[campo].split.map { |a| "#{a}:*" }.join(' & ')
|
77
|
+
match_like = "%#{parametros[campo]}%"
|
78
|
+
campo_tabla = "#{@clase_modelo.table_name}.#{campo}"
|
79
|
+
condicion = "to_tsvector(coalesce(unaccent(#{campo_tabla}), '')) @@ to_tsquery( unaccent(?) )"
|
80
|
+
condicion += " OR unaccent(CONCAT(#{campo_tabla})) ILIKE unaccent(?)"
|
81
|
+
query = query.where(condicion, I18n.transliterate(match_vector).to_s,
|
82
|
+
I18n.transliterate(match_like).to_s)
|
83
|
+
elsif tipo(campo) == :boolean
|
84
|
+
if campo.to_s == 'discarded'
|
85
|
+
# Si el nombre del campo es 'discarded' entonces no es un campo
|
86
|
+
# real sino filtro booleano por presencia de discarded_at
|
87
|
+
case parametros[campo]
|
88
|
+
when 'si'
|
89
|
+
query = query.unscope(where: :discarded_at).where("#{@clase_modelo.table_name}.discarded_at IS NOT NULL")
|
90
|
+
when 'no'
|
91
|
+
query = query.unscope(where: :discarded_at).where("#{@clase_modelo.table_name}.discarded_at IS NULL")
|
92
|
+
end
|
93
|
+
else
|
94
|
+
# Si no simplemente hago la query por booleano
|
95
|
+
query = query.where("#{@clase_modelo.table_name}.#{campo} = ?", parametros[campo] == 'si')
|
96
|
+
end
|
97
|
+
elsif tipo(campo) == :date || tipo(campo) == :datetime
|
98
|
+
begin
|
99
|
+
fecha = Date.parse(parametros[campo])
|
100
|
+
fecha = fecha + 1.day - 1.second if tipo(campo) == :datetime && comparador(campo) == '<'
|
101
|
+
campo_a_comparar = "#{@clase_modelo.table_name}.#{sin_sufijo(campo)}"
|
102
|
+
query = query.where("#{campo_a_comparar} #{comparador(campo)} ?", fecha)
|
103
|
+
rescue ArgumentError
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
query
|
108
|
+
end
|
109
|
+
|
110
|
+
def tipo(campo)
|
111
|
+
nombre_campo = sin_sufijo(campo)
|
112
|
+
if @filtros[nombre_campo.to_sym].present? && @filtros[nombre_campo.to_sym][:tipo].present?
|
113
|
+
@filtros[nombre_campo.to_sym][:tipo]
|
114
|
+
elsif @clase_modelo.respond_to?(:enumerized_attributes) && @clase_modelo.enumerized_attributes[nombre_campo.to_s].present?
|
115
|
+
:enumerized
|
116
|
+
elsif @clase_modelo.reflect_on_all_associations.find do |a|
|
117
|
+
a.name == nombre_campo.to_sym
|
118
|
+
end.present?
|
119
|
+
:asociacion
|
120
|
+
else
|
121
|
+
columna = @clase_modelo.columns.find { |c| c.name == nombre_campo.to_s }
|
122
|
+
if columna.nil?
|
123
|
+
return :date if campo.match(/fecha/)
|
124
|
+
|
125
|
+
# Si el nombre del campo es 'discarded' entonces no es un campo
|
126
|
+
# real sino filtro booleano por presencia de discarded_at
|
127
|
+
return :boolean if campo.to_s == 'discarded'
|
128
|
+
|
129
|
+
Rails.logger.warn("no existe el campo: #{nombre_campo}")
|
130
|
+
return
|
131
|
+
end
|
132
|
+
columna.type
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def comparador_array(sufijo)
|
137
|
+
case sufijo
|
138
|
+
when 'es_igual_a'
|
139
|
+
'='
|
140
|
+
else
|
141
|
+
# si es 'incluye'
|
142
|
+
# o si no tiene sufijo que por defecto se use el includes
|
143
|
+
'@>'
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def comparador(campo)
|
148
|
+
if campo.to_s.ends_with?('_desde')
|
149
|
+
'>='
|
150
|
+
elsif campo.to_s.ends_with?('_hasta')
|
151
|
+
'<='
|
152
|
+
else
|
153
|
+
'='
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def extraer_sufijo(campo)
|
158
|
+
SUFIJOS.each do |sufijo|
|
159
|
+
return sufijo if campo.to_s.ends_with?("_#{sufijo}")
|
160
|
+
end
|
161
|
+
nil
|
162
|
+
end
|
163
|
+
|
164
|
+
def sin_sufijo(campo)
|
165
|
+
ret = campo.to_s.dup
|
166
|
+
SUFIJOS.each do |sufijo|
|
167
|
+
ret.gsub!(/_#{sufijo}$/, '')
|
168
|
+
end
|
169
|
+
ret
|
170
|
+
end
|
171
|
+
|
172
|
+
def placeholder_campo(campo)
|
173
|
+
suf = extraer_sufijo(campo)
|
174
|
+
if suf.present?
|
175
|
+
"#{@clase_modelo.human_attribute_name(sin_sufijo(campo))} #{suf}"
|
176
|
+
else
|
177
|
+
@clase_modelo.human_attribute_name(campo)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def filtros_html(options = {})
|
182
|
+
res = ''
|
183
|
+
@filtros.each do |campo, opciones|
|
184
|
+
if opciones[:oculto] ||
|
185
|
+
(options[:except].present? && options[:except].include?(campo.to_sym)) ||
|
186
|
+
(options[:only].present? && !options[:only].include?(campo.to_sym))
|
187
|
+
next
|
188
|
+
end
|
189
|
+
|
190
|
+
res += case tipo(campo)
|
191
|
+
when :select_custom
|
192
|
+
filtro_select_custom(campo, placeholder_campo(campo))
|
193
|
+
when :enumerized
|
194
|
+
filtro_select(campo, placeholder_campo(campo))
|
195
|
+
when :asociacion
|
196
|
+
filtro_asociacion(campo, placeholder_campo(campo))
|
197
|
+
when :date, :datetime
|
198
|
+
filtro_fecha(campo, placeholder_campo(campo))
|
199
|
+
when :boolean
|
200
|
+
filtro_boolean(campo, placeholder_campo(campo))
|
201
|
+
else
|
202
|
+
filtro_texto(campo, placeholder_campo(campo))
|
203
|
+
end
|
204
|
+
end
|
205
|
+
res += hidden_field_tag('order_by', parametros_controller['order_by'])
|
206
|
+
res += hidden_field_tag('order_direction', parametros_controller['order_direction'])
|
207
|
+
res.html_safe
|
208
|
+
end
|
209
|
+
|
210
|
+
def obtener_asociacion(campo)
|
211
|
+
nombre_campo = sin_sufijo(campo)
|
212
|
+
extraer_sufijo(campo)
|
213
|
+
asociacion = @clase_modelo.reflect_on_all_associations.find do |a|
|
214
|
+
a.name == nombre_campo.to_sym
|
215
|
+
end
|
216
|
+
raise 'no se encontró la asociacion' if asociacion.nil?
|
217
|
+
|
218
|
+
if asociacion.instance_of?(ActiveRecord::Reflection::ThroughReflection)
|
219
|
+
through_class = asociacion.through_reflection.class_name.constantize
|
220
|
+
asociacion_posta = through_class.reflect_on_all_associations.find do |a|
|
221
|
+
a.name == nombre_campo.to_sym
|
222
|
+
end
|
223
|
+
raise 'no se encontró la asociacion' if asociacion_posta.nil?
|
224
|
+
|
225
|
+
asociacion_posta
|
226
|
+
else
|
227
|
+
asociacion
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def filtro_asociacion(campo, _placeholder = '')
|
232
|
+
asociacion = obtener_asociacion(campo)
|
233
|
+
multiple = asociacion.instance_of?(ActiveRecord::Reflection::HasAndBelongsToManyReflection)
|
234
|
+
nombre_clase = asociacion.options[:class_name]
|
235
|
+
nombre_clase = asociacion.name.to_s.camelize if nombre_clase.nil?
|
236
|
+
clase_asociacion = Object.const_get(nombre_clase)
|
237
|
+
scope = Pundit.policy_scope!(controller.send(PgRails.configuracion.current_user_method), clase_asociacion)
|
238
|
+
|
239
|
+
# Filtro soft deleted, y sea con paranoia o con discard
|
240
|
+
scope = scope.without_deleted if scope.respond_to?(:without_deleted)
|
241
|
+
scope = scope.kept if scope.respond_to?(:kept)
|
242
|
+
|
243
|
+
if @filtros[campo.to_sym][:scope_asociacion].present?
|
244
|
+
scope = @filtros[campo.to_sym][:scope_asociacion].call(scope)
|
245
|
+
end
|
246
|
+
|
247
|
+
map = scope.map { |o| [o.to_s, o.id] }
|
248
|
+
|
249
|
+
unless @filtros[campo.to_sym].present? && @filtros[campo.to_sym][:include_blank] == false
|
250
|
+
map.unshift ["Seleccionar #{@clase_modelo.human_attribute_name(campo.to_sym).downcase}",
|
251
|
+
nil]
|
252
|
+
end
|
253
|
+
|
254
|
+
default = parametros_controller[campo].nil? ? nil : parametros_controller[campo]
|
255
|
+
content_tag :div, class: 'col-auto' do
|
256
|
+
content_tag :div, class: 'filter' do
|
257
|
+
if multiple
|
258
|
+
select_tag campo, options_for_select(map, default), multiple: true,
|
259
|
+
class: 'form-select form-select-sm selectize pg-input-lg'
|
260
|
+
else
|
261
|
+
select_tag campo, options_for_select(map, default),
|
262
|
+
class: 'form-select form-select-sm chosen-select pg-input-lg'
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def filtro_select(campo, placeholder = '')
|
269
|
+
map = @clase_modelo.send(campo).values.map do |key|
|
270
|
+
[I18n.t("#{@clase_modelo.to_s.underscore}.#{campo}.#{key}", default: key.humanize),
|
271
|
+
key.value]
|
272
|
+
end
|
273
|
+
unless @filtros[campo.to_sym].present? && @filtros[campo.to_sym][:include_blank] == false
|
274
|
+
map.unshift ["Seleccionar #{placeholder.downcase}",
|
275
|
+
nil]
|
276
|
+
end
|
277
|
+
default = parametros_controller[campo].nil? ? nil : parametros_controller[campo]
|
278
|
+
content_tag :div, class: 'col-auto' do
|
279
|
+
content_tag :div, class: 'filter' do
|
280
|
+
select_tag campo, options_for_select(map, default), class: 'form-select form-select-sm pg-input-lg'
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def filtro_select_custom(campo, placeholder = '')
|
286
|
+
map = @filtros[campo.to_sym][:opciones]
|
287
|
+
unless @filtros[campo.to_sym].present? && @filtros[campo.to_sym][:include_blank] == false
|
288
|
+
map.unshift ["Seleccionar #{placeholder.downcase}",
|
289
|
+
nil]
|
290
|
+
end
|
291
|
+
default = parametros_controller[campo].nil? ? nil : parametros_controller[campo]
|
292
|
+
content_tag :div, class: 'col-auto' do
|
293
|
+
content_tag :div, class: 'filter' do
|
294
|
+
select_tag campo, options_for_select(map, default), class: 'form-select form-select-sm pg-input-lg'
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def filtro_texto(campo, placeholder = '')
|
300
|
+
content_tag :div, class: 'col-auto' do
|
301
|
+
content_tag :div, class: 'filter' do
|
302
|
+
text_field_tag(
|
303
|
+
campo, parametros_controller[campo], class: 'form-control form-control-sm allow-enter-submit', placeholder: placeholder, autocomplete: 'off'
|
304
|
+
)
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def filtro_boolean(campo, placeholder = '')
|
310
|
+
map = [%w[Si si], %w[No no]]
|
311
|
+
unless @filtros[campo.to_sym].present? && @filtros[campo.to_sym][:include_blank] == false
|
312
|
+
map.unshift ["¿#{placeholder.titleize}?",
|
313
|
+
nil]
|
314
|
+
end
|
315
|
+
default = parametros_controller[campo].nil? ? nil : parametros_controller[campo]
|
316
|
+
content_tag :div, class: 'col-auto' do
|
317
|
+
content_tag :div, class: 'filter' do
|
318
|
+
select_tag campo, options_for_select(map, default), class: 'form-select form-select-sm pg-input-lg'
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
def filtro_fecha(campo, placeholder = '')
|
324
|
+
content_tag :div, class: 'col-auto' do
|
325
|
+
content_tag :div, class: 'filter' do
|
326
|
+
label_tag(nil, placeholder, class: 'text-muted') + \
|
327
|
+
date_field_tag(
|
328
|
+
campo, parametros_controller[campo], class: 'form-control form-control-sm d-inline-block w-auto ms-1', placeholder: placeholder, autocomplete: 'off'
|
329
|
+
)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
def parametros_controller
|
335
|
+
params
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgRails
|
4
|
+
class ApplicationRecord < ActiveRecord::Base
|
5
|
+
extend Enumerize
|
6
|
+
include PrintHelper
|
7
|
+
include PostgresHelper
|
8
|
+
|
9
|
+
self.abstract_class = true
|
10
|
+
|
11
|
+
attr_accessor :current_user
|
12
|
+
|
13
|
+
before_create :setear_creado_y_actualizado_por
|
14
|
+
before_update :setear_actualizado_por
|
15
|
+
|
16
|
+
def self.nombre_plural
|
17
|
+
model_name.human(count: 2)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.nombre_singular
|
21
|
+
model_name.human(count: 1)
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
%i[nombre name].each do |campo|
|
26
|
+
return send(campo) if try(campo).present?
|
27
|
+
end
|
28
|
+
if id.present?
|
29
|
+
"#{self.class.nombre_singular} ##{id}"
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def setear_creado_y_actualizado_por
|
38
|
+
setear_si_existe :creado_por, current_user
|
39
|
+
setear_si_existe :actualizado_por, current_user
|
40
|
+
end
|
41
|
+
|
42
|
+
def setear_actualizado_por
|
43
|
+
setear_si_existe :actualizado_por, current_user
|
44
|
+
end
|
45
|
+
|
46
|
+
def setear_si_existe(campo, valor)
|
47
|
+
metodo = "#{campo}="
|
48
|
+
send(metodo, valor) if respond_to?(metodo) && valor.present?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgRails
|
4
|
+
class ApplicationPolicy
|
5
|
+
attr_reader :user, :record
|
6
|
+
|
7
|
+
def initialize(user, record)
|
8
|
+
@user = user
|
9
|
+
@record = record
|
10
|
+
end
|
11
|
+
|
12
|
+
def editar_en_lugar?
|
13
|
+
puede_editar?
|
14
|
+
end
|
15
|
+
|
16
|
+
def index?
|
17
|
+
raise "esta policy se llama con la clase modelo y no con #{record.class}" unless record.class
|
18
|
+
|
19
|
+
acceso_total? || Pundit.policy_scope!(user, record).any?
|
20
|
+
end
|
21
|
+
|
22
|
+
def show?
|
23
|
+
# scope.where(id: record.id).exists?
|
24
|
+
acceso_total?
|
25
|
+
end
|
26
|
+
|
27
|
+
def create?
|
28
|
+
puede_crear?
|
29
|
+
end
|
30
|
+
|
31
|
+
def new?
|
32
|
+
create?
|
33
|
+
end
|
34
|
+
|
35
|
+
def update?
|
36
|
+
puede_editar? && !objeto_borrado?
|
37
|
+
end
|
38
|
+
|
39
|
+
def edit?
|
40
|
+
update?
|
41
|
+
end
|
42
|
+
|
43
|
+
def destroy?
|
44
|
+
puede_borrar? && !objeto_borrado?
|
45
|
+
end
|
46
|
+
|
47
|
+
def scope
|
48
|
+
Pundit.policy_scope!(user, record.class)
|
49
|
+
end
|
50
|
+
|
51
|
+
class Scope
|
52
|
+
attr_reader :user, :scope
|
53
|
+
|
54
|
+
def initialize(user, scope)
|
55
|
+
@user = user
|
56
|
+
@scope = scope
|
57
|
+
end
|
58
|
+
|
59
|
+
def resolve
|
60
|
+
if policy.acceso_total?
|
61
|
+
scope.all
|
62
|
+
else
|
63
|
+
scope.none
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def policy
|
68
|
+
raise "el scope debe ser una clase modelo y no #{scope.class}" unless scope.class
|
69
|
+
|
70
|
+
Pundit.policy!(user, scope)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def puede_editar?
|
75
|
+
acceso_total?
|
76
|
+
end
|
77
|
+
|
78
|
+
def puede_crear?
|
79
|
+
acceso_total?
|
80
|
+
end
|
81
|
+
|
82
|
+
def puede_borrar?
|
83
|
+
acceso_total?
|
84
|
+
end
|
85
|
+
|
86
|
+
def export?
|
87
|
+
acceso_total?
|
88
|
+
end
|
89
|
+
|
90
|
+
def acceso_total?
|
91
|
+
user.admin?
|
92
|
+
end
|
93
|
+
|
94
|
+
def objeto_borrado?
|
95
|
+
if record.respond_to?(:deleted?)
|
96
|
+
record.deleted?
|
97
|
+
elsif record.respond_to?(:discarded?)
|
98
|
+
record.discarded?
|
99
|
+
else
|
100
|
+
false
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
$(function() {
|
2
|
+
var modal = $('<%= j render contenido %>').modal();
|
3
|
+
|
4
|
+
<% if defined? extra_js %>
|
5
|
+
<% [extra_js].flatten.each do |partial| %>
|
6
|
+
<%= render partial: partial %>
|
7
|
+
<% end %>
|
8
|
+
<% end %>
|
9
|
+
$(modal).on('hidden.bs.modal', function () {
|
10
|
+
$(this).data('bs.modal', null);
|
11
|
+
$(this).remove();
|
12
|
+
});
|
13
|
+
PgRails.bindear('.modal')
|
14
|
+
});
|
@@ -0,0 +1,42 @@
|
|
1
|
+
{
|
2
|
+
"ignored_warnings": [
|
3
|
+
{
|
4
|
+
"warning_type": "Remote Code Execution",
|
5
|
+
"warning_code": 24,
|
6
|
+
"fingerprint": "8128e4baa0b47430684e599d2c3944b5446ad95caa6fbd263b7fa984a91842cd",
|
7
|
+
"check_name": "UnsafeReflection",
|
8
|
+
"message": "Unsafe reflection method `const_get` called with parameter value",
|
9
|
+
"file": "app/controllers/pg_rails/editar_en_lugar_controller.rb",
|
10
|
+
"line": 7,
|
11
|
+
"link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/",
|
12
|
+
"code": "Kernel.const_get(params.keys[1])",
|
13
|
+
"render_path": null,
|
14
|
+
"location": {
|
15
|
+
"type": "method",
|
16
|
+
"class": "PgRails::EditarEnLugarController",
|
17
|
+
"method": "actualizar"
|
18
|
+
},
|
19
|
+
"user_input": "params.keys[1]",
|
20
|
+
"confidence": "High",
|
21
|
+
"note": ""
|
22
|
+
},
|
23
|
+
{
|
24
|
+
"warning_type": "Cross-Site Scripting",
|
25
|
+
"warning_code": 106,
|
26
|
+
"fingerprint": "c8adc1c0caf2c9251d1d8de588fb949070212d0eed5e1580aee88bab2287b772",
|
27
|
+
"check_name": "SanitizeMethods",
|
28
|
+
"message": "loofah gem 2.12.0 is vulnerable (CVE-2018-8048). Upgrade to 2.2.1",
|
29
|
+
"file": "Gemfile.lock",
|
30
|
+
"line": 201,
|
31
|
+
"link": "https://github.com/flavorjones/loofah/issues/144",
|
32
|
+
"code": null,
|
33
|
+
"render_path": null,
|
34
|
+
"location": null,
|
35
|
+
"user_input": null,
|
36
|
+
"confidence": "Medium",
|
37
|
+
"note": ""
|
38
|
+
}
|
39
|
+
],
|
40
|
+
"updated": "2021-09-09 15:02:20 -0300",
|
41
|
+
"brakeman_version": "4.10.0"
|
42
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
es:
|
2
|
+
created_at: Fecha de creación
|
3
|
+
updated_at: Fecha de actualización
|
4
|
+
deleted_at: Fecha de borrado
|
5
|
+
discarded_at: Fecha de borrado
|
6
|
+
actualizado_por: Actualizado por
|
7
|
+
creado_por: Creado por
|
8
|
+
ancestry:
|
9
|
+
exclude_self: No puede ser hijx de si mismx
|
10
|
+
simple_form:
|
11
|
+
# labels:
|
12
|
+
# user:
|
13
|
+
# username: 'User name'
|
14
|
+
# password: 'Password'
|
15
|
+
# hints:
|
16
|
+
error_notification:
|
17
|
+
default_message: "hubo algunos errores:"
|
data/config/routes.rb
ADDED
data/config/spring.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Spring.application_root = 'spec/dummy'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgRails
|
4
|
+
class Configuracion
|
5
|
+
attr_accessor :sistema_iconos, :clase_botones_chicos, :boton_destroy, :boton_edit,
|
6
|
+
:boton_show, :boton_light, :icono_destroy, :icono_edit, :icono_show, :boton_export, :bootstrap_version,
|
7
|
+
:current_user_method
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@sistema_iconos = 'bi'
|
11
|
+
@clase_botones_chicos = 'btn-sm'
|
12
|
+
@boton_destroy = 'light'
|
13
|
+
@boton_export = 'warning'
|
14
|
+
@boton_edit = 'light'
|
15
|
+
@boton_show = 'light'
|
16
|
+
@boton_light = 'light'
|
17
|
+
@icono_destroy = 'trash-fill'
|
18
|
+
@icono_edit = 'pencil'
|
19
|
+
@icono_show = 'eye-fill'
|
20
|
+
@bootstrap_version = 5
|
21
|
+
@current_user_method = :current_user
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# require 'activesupport/time'
|
4
|
+
module ActiveSupport
|
5
|
+
class TimeWithZone
|
6
|
+
def to_s(format = :default)
|
7
|
+
if format == :db
|
8
|
+
utc.to_s(format)
|
9
|
+
elsif formatter = ::Time::DATE_FORMATS[format] # rubocop:disable Lint/AssignmentInCondition
|
10
|
+
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
11
|
+
else
|
12
|
+
# "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
|
13
|
+
time.strftime('%d/%m/%Y %H:%M')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# unless Rails.env.production?
|
4
|
+
# # require 'byebug'
|
5
|
+
# require 'factory_bot_rails'
|
6
|
+
# end
|
7
|
+
|
8
|
+
# require 'font-awesome-rails'
|
9
|
+
# require 'nested_form'
|
10
|
+
# require 'audited'
|
11
|
+
# # require 'best_in_place'
|
12
|
+
# # require 'bootstrap'
|
13
|
+
# # require 'bootstrap-datepicker-rails'
|
14
|
+
# require 'breadcrumbs_on_rails'
|
15
|
+
# require 'caxlsx_rails'
|
16
|
+
# require 'devise'
|
17
|
+
# require 'devise-i18n'
|
18
|
+
# require 'devise/orm/active_record'
|
19
|
+
# require 'draper'
|
20
|
+
# require 'enumerize'
|
21
|
+
# # require 'jquery-rails'
|
22
|
+
# require 'pundit'
|
23
|
+
# # require 'rails-assets-chosen'
|
24
|
+
# require 'rails-i18n'
|
25
|
+
# # require 'rollbar'
|
26
|
+
# # require 'selectize-rails'
|
27
|
+
# require 'simple_form'
|
28
|
+
# require 'slim'
|
29
|
+
# # require 'smart_listing'
|
30
|
+
# require 'kaminari'
|
31
|
+
# require 'kaminari-i18n'
|
32
|
+
|
33
|
+
require 'pg_rails/utils/logueador'
|
34
|
+
|
35
|
+
module PgRails
|
36
|
+
class Engine < ::Rails::Engine
|
37
|
+
isolate_namespace PgRails
|
38
|
+
|
39
|
+
config.i18n.default_locale = :es
|
40
|
+
config.time_zone = 'America/Argentina/Buenos_Aires'
|
41
|
+
end
|
42
|
+
end
|