mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-26 19:46:23 +00:00
Merge branch 'indexed-posts' into panel.sutty.nl
This commit is contained in:
commit
9b9bc9a5e9
3 changed files with 20 additions and 362 deletions
|
@ -14,9 +14,8 @@ class Post
|
||||||
#
|
#
|
||||||
# @return [IndexedPost]
|
# @return [IndexedPost]
|
||||||
def to_index
|
def to_index
|
||||||
IndexedPost.find_or_create_by(id: uuid.value).tap do |indexed_post|
|
IndexedPost.find_or_create_by(post_id: uuid.value, site_id: site.id).tap do |indexed_post|
|
||||||
indexed_post.layout = layout.name
|
indexed_post.layout = layout.name
|
||||||
indexed_post.site_id = site.id
|
|
||||||
indexed_post.path = path.basename
|
indexed_post.path = path.basename
|
||||||
indexed_post.locale = locale.value
|
indexed_post.locale = locale.value
|
||||||
indexed_post.dictionary = IndexedPost.to_dictionary(locale: locale.value)
|
indexed_post.dictionary = IndexedPost.to_dictionary(locale: locale.value)
|
||||||
|
|
|
@ -1,360 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
# Representa los distintos tipos de campos que pueden venir de una
|
|
||||||
# plantilla compleja
|
|
||||||
class Post
|
|
||||||
class TemplateField
|
|
||||||
attr_reader :post, :contents, :key
|
|
||||||
|
|
||||||
STRING_VALUES = %w[string text url number email password date year
|
|
||||||
image video audio document].freeze
|
|
||||||
|
|
||||||
# Tipo de valores que son archivos
|
|
||||||
FILE_TYPES = %w[image video audio document].freeze
|
|
||||||
|
|
||||||
def initialize(post, key, contents)
|
|
||||||
@post = post
|
|
||||||
@key = key
|
|
||||||
@contents = contents
|
|
||||||
end
|
|
||||||
|
|
||||||
def title
|
|
||||||
contents.dig('title') if complex?
|
|
||||||
end
|
|
||||||
|
|
||||||
def subtitle
|
|
||||||
contents.dig('subtitle') if complex?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Obtiene el valor
|
|
||||||
def value
|
|
||||||
complex? ? contents.dig('value') : contents
|
|
||||||
end
|
|
||||||
|
|
||||||
def max
|
|
||||||
return 0 if simple?
|
|
||||||
|
|
||||||
contents.fetch('max', 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
def min
|
|
||||||
return 0 if simple?
|
|
||||||
|
|
||||||
contents.fetch('min', 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
# TODO: volver elegante!
|
|
||||||
def type
|
|
||||||
return @type if @type
|
|
||||||
|
|
||||||
if image?
|
|
||||||
@type = 'image'
|
|
||||||
elsif email?
|
|
||||||
@type = 'email'
|
|
||||||
elsif url?
|
|
||||||
@type = 'url'
|
|
||||||
elsif number?
|
|
||||||
@type = 'number'
|
|
||||||
elsif password?
|
|
||||||
@type = 'password'
|
|
||||||
elsif date?
|
|
||||||
@type = 'date'
|
|
||||||
elsif year?
|
|
||||||
@type = 'year'
|
|
||||||
elsif text_area?
|
|
||||||
@type = 'text_area'
|
|
||||||
elsif check_box_group?
|
|
||||||
@type = 'check_box_group'
|
|
||||||
elsif radio_group?
|
|
||||||
@type = 'radio_group'
|
|
||||||
elsif string?
|
|
||||||
@type = 'text'
|
|
||||||
# TODO: volver a hacer funcionar esto y ahorranos los multiple:
|
|
||||||
# false
|
|
||||||
elsif string? && contents.split('/', 2).count == 2
|
|
||||||
@type = 'select'
|
|
||||||
elsif nested?
|
|
||||||
@type = 'table'
|
|
||||||
elsif array?
|
|
||||||
@type = 'select'
|
|
||||||
elsif boolean?
|
|
||||||
@type = 'check_box'
|
|
||||||
end
|
|
||||||
|
|
||||||
@type
|
|
||||||
end
|
|
||||||
|
|
||||||
# Devuelve los valores vacíos según el tipo
|
|
||||||
def empty_value
|
|
||||||
if string?
|
|
||||||
''
|
|
||||||
elsif nested?
|
|
||||||
# TODO: devolver las keys también
|
|
||||||
{}
|
|
||||||
elsif array?
|
|
||||||
[]
|
|
||||||
elsif boolean?
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def cols
|
|
||||||
complex? && contents.dig('cols')
|
|
||||||
end
|
|
||||||
|
|
||||||
def align
|
|
||||||
complex? && contents.dig('align')
|
|
||||||
end
|
|
||||||
|
|
||||||
# El campo es requerido si es complejo y se especifica que lo sea
|
|
||||||
def required?
|
|
||||||
complex? && contents.dig('required')
|
|
||||||
end
|
|
||||||
|
|
||||||
def boolean?
|
|
||||||
value.is_a?(FalseClass) || value.is_a?(TrueClass)
|
|
||||||
end
|
|
||||||
|
|
||||||
def string?
|
|
||||||
value.is_a? String
|
|
||||||
end
|
|
||||||
|
|
||||||
def text_area?
|
|
||||||
value == 'text'
|
|
||||||
end
|
|
||||||
|
|
||||||
def url?
|
|
||||||
value == 'url'
|
|
||||||
end
|
|
||||||
|
|
||||||
def email?
|
|
||||||
value == 'email' || value == 'mail'
|
|
||||||
end
|
|
||||||
alias mail? email?
|
|
||||||
|
|
||||||
def date?
|
|
||||||
value == 'date'
|
|
||||||
end
|
|
||||||
|
|
||||||
def password?
|
|
||||||
value == 'password'
|
|
||||||
end
|
|
||||||
|
|
||||||
def number?
|
|
||||||
value == 'number'
|
|
||||||
end
|
|
||||||
|
|
||||||
def year?
|
|
||||||
value == 'year'
|
|
||||||
end
|
|
||||||
|
|
||||||
def file?
|
|
||||||
string? && FILE_TYPES.include?(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
def image?
|
|
||||||
array? ? value.first == 'image' : value == 'image'
|
|
||||||
end
|
|
||||||
|
|
||||||
# Si la plantilla es simple no está admitiendo Hashes como valores
|
|
||||||
def simple?
|
|
||||||
!complex?
|
|
||||||
end
|
|
||||||
|
|
||||||
def complex?
|
|
||||||
contents.is_a? Hash
|
|
||||||
end
|
|
||||||
|
|
||||||
# XXX Retrocompatibilidad
|
|
||||||
def to_s
|
|
||||||
key
|
|
||||||
end
|
|
||||||
|
|
||||||
# Convierte el campo en un parámetro
|
|
||||||
def to_param
|
|
||||||
if nested?
|
|
||||||
{ key.to_sym => {} }
|
|
||||||
elsif array? && multiple?
|
|
||||||
{ key.to_sym => [] }
|
|
||||||
else
|
|
||||||
key.to_sym
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Convierte la plantilla en el formato de front_matter
|
|
||||||
def to_front_matter
|
|
||||||
{ key => empty_value }
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_box_group?
|
|
||||||
array? && (complex? && contents.fetch('checkbox', false))
|
|
||||||
end
|
|
||||||
|
|
||||||
def radio_group?
|
|
||||||
array? && (complex? && contents.fetch('radio', false))
|
|
||||||
end
|
|
||||||
|
|
||||||
def array?
|
|
||||||
value.is_a? Array
|
|
||||||
end
|
|
||||||
|
|
||||||
# TODO: detectar cuando es complejo y tomar el valor de :multiple
|
|
||||||
def multiple?
|
|
||||||
# si la plantilla es simple, es multiple cuando tenemos un array
|
|
||||||
return array? if simple?
|
|
||||||
|
|
||||||
array? && contents.fetch('multiple', true)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Detecta si el valor es una tabla de campos
|
|
||||||
def nested?
|
|
||||||
value.is_a?(Hash) || (array? && value.first.is_a?(Hash))
|
|
||||||
end
|
|
||||||
|
|
||||||
# Un campo acepta valores abiertos si no es un array con múltiples
|
|
||||||
# elementos
|
|
||||||
def open?
|
|
||||||
# Todos los valores simples son abiertos
|
|
||||||
return true unless complex?
|
|
||||||
return false unless array?
|
|
||||||
|
|
||||||
# La cosa se complejiza cuando tenemos valores complejos
|
|
||||||
#
|
|
||||||
# Si tenemos una lista cerrada de valores, necesitamos saber si el
|
|
||||||
# campo es abierto o cerrado. Si la lista tiene varios elementos,
|
|
||||||
# es una lista cerrada, opcionalmente abierta. Si la lista tiene
|
|
||||||
# un elemento, quiere decir que estamos autocompletando desde otro
|
|
||||||
# lado.
|
|
||||||
contents.fetch('open', value.count < 2)
|
|
||||||
end
|
|
||||||
|
|
||||||
def closed?
|
|
||||||
!open?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Determina si los valores del campo serán públicos después
|
|
||||||
#
|
|
||||||
# XXX Esto es solo una indicación, el theme Jekyll tiene que
|
|
||||||
# respetarlos por su lado luego
|
|
||||||
def public?
|
|
||||||
# Todos los campos son públicos a menos que se indique lo
|
|
||||||
# contrario
|
|
||||||
simple? || contents.fetch('public', true)
|
|
||||||
end
|
|
||||||
|
|
||||||
def private?
|
|
||||||
!public?
|
|
||||||
end
|
|
||||||
|
|
||||||
def human
|
|
||||||
h = key.humanize
|
|
||||||
|
|
||||||
h
|
|
||||||
end
|
|
||||||
|
|
||||||
def label
|
|
||||||
h = (complex? && contents.dig('label')) || human
|
|
||||||
h += ' *' if required?
|
|
||||||
|
|
||||||
h
|
|
||||||
end
|
|
||||||
|
|
||||||
def help
|
|
||||||
complex? && contents.dig('help')
|
|
||||||
end
|
|
||||||
|
|
||||||
def nested_fields
|
|
||||||
return unless nested?
|
|
||||||
|
|
||||||
v = value
|
|
||||||
v = value.first if array?
|
|
||||||
|
|
||||||
@nested_fields ||= v.map do |k, sv|
|
|
||||||
Post::TemplateField.new post, k, sv
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Obtiene los valores posibles para el campo de la plantilla
|
|
||||||
def values
|
|
||||||
return 'false' if value == false
|
|
||||||
return 'true' if value == true
|
|
||||||
# XXX por alguna razón `value` no refiere a value() :/
|
|
||||||
return '' if STRING_VALUES.include? value
|
|
||||||
# Las listas cerradas no necesitan mayor procesamiento
|
|
||||||
return value if array? && closed? && value.count > 1
|
|
||||||
# Y las vacías tampoco
|
|
||||||
return value if array? && value.empty?
|
|
||||||
# Ahorrarnos el trabajo
|
|
||||||
return @values if @values
|
|
||||||
|
|
||||||
# Duplicar el valor para no tener efectos secundarios luego (?)
|
|
||||||
value = self.value.dup
|
|
||||||
|
|
||||||
# Para obtener los valores posibles, hay que procesar la string y
|
|
||||||
# convertirla a parametros
|
|
||||||
|
|
||||||
# Si es una array de un solo elemento, es un indicador de que
|
|
||||||
# tenemos que rellenarla con los valores que indica.
|
|
||||||
#
|
|
||||||
# El primer valor es el que trae la string de autocompletado
|
|
||||||
values = array? ? value.shift : value
|
|
||||||
|
|
||||||
# Si el valor es un array con más de un elemento, queremos usar
|
|
||||||
# esas opciones. Pero si además es abierto, queremos traer los
|
|
||||||
# valores cargados anteriormente.
|
|
||||||
|
|
||||||
# Procesamos el valor, buscando : como separador de campos que
|
|
||||||
# queremos encontrar y luego los unimos
|
|
||||||
_value = (values&.split(':', 2) || []).map do |v|
|
|
||||||
# Tenemos hasta tres niveles de búsqueda
|
|
||||||
collection, attr, subattr = v.split('/', 3)
|
|
||||||
|
|
||||||
if collection == 'site'
|
|
||||||
# TODO: puede ser peligroso permitir acceder a cualquier
|
|
||||||
# atributo de site? No estamos trayendo nada fuera de
|
|
||||||
# lo normal
|
|
||||||
post.site.send(attr.to_sym)
|
|
||||||
# Si hay un subatributo, tenemos que averiguar todos los
|
|
||||||
# valores dentro de el
|
|
||||||
# TODO volver elegante!
|
|
||||||
# TODO volver recursivo!
|
|
||||||
elsif subattr
|
|
||||||
post.site.everything_of(attr, lang: collection)
|
|
||||||
.compact
|
|
||||||
.map { |sv| sv[subattr] }
|
|
||||||
.flatten
|
|
||||||
.compact
|
|
||||||
.uniq
|
|
||||||
else
|
|
||||||
post.site.everything_of(attr, lang: collection).compact
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Si el valor es abierto, sumar los valores auto-completados a
|
|
||||||
# lo pre-cargados.
|
|
||||||
#
|
|
||||||
# En este punto _value es un array de 1 o 2 arrays, si es de uno,
|
|
||||||
# value tambien tiene que serlo. Si es de 2, hay que unir cada
|
|
||||||
# una
|
|
||||||
if open?
|
|
||||||
if _value.count == 1
|
|
||||||
_value = [(_value.first + value).uniq]
|
|
||||||
elsif _value.count == 2
|
|
||||||
_value = _value.each_with_index.map do |v, i|
|
|
||||||
v + value.fetch(i, [])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Crea un array de arrays, útil para los select
|
|
||||||
# [ [ 1, a ], [ 2, b ] ]
|
|
||||||
# aunque si no hay un : en el autocompletado, el array queda
|
|
||||||
# [ [ 1, 1 ], [ 2, 2 ] ]
|
|
||||||
values = _value.empty? ? [] : _value.last.zip(_value.first)
|
|
||||||
|
|
||||||
# En última instancia, traer el valor por defecto y ahorrarnos
|
|
||||||
# volver a procesar
|
|
||||||
@values = values
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# No podemos compartir el uuid entre indexed_posts y posts porque
|
||||||
|
# podemos tener sitios duplicados. Al menos hasta que los sitios de
|
||||||
|
# testeo estén integrados en el panel vamos a tener que generar otros
|
||||||
|
# UUID.
|
||||||
|
class IndexedPostsByUuidAndSiteId < ActiveRecord::Migration[6.1]
|
||||||
|
def up
|
||||||
|
add_column :indexed_posts, :post_id, :uuid, index: true
|
||||||
|
|
||||||
|
IndexedPost.transaction do
|
||||||
|
ActiveRecord::Base.connection.execute('update indexed_posts set post_id = id where post_id is null')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_column :indexed_posts, :post_id
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue