89 lines
2.3 KiB
Ruby
89 lines
2.3 KiB
Ruby
|
# Esta clase se encarga de guardan los archivos YAML de idiomas
|
||
|
#
|
||
|
# TODO se podría convertir en una clase genérica de editor de YAML
|
||
|
class JekyllI18n
|
||
|
attr_reader :site, :lang, :attributes
|
||
|
|
||
|
def initialize(site:, lang:, attributes:)
|
||
|
unless site.is_a? Site
|
||
|
raise ArgumentError, I18n.t('errors.argument_error', argument: :site, class: Site)
|
||
|
end
|
||
|
|
||
|
unless I18n.available_locales.include? lang.to_sym
|
||
|
raise ArgumentError, I18n.t('errors.unknown_locale', locale: lang)
|
||
|
end
|
||
|
|
||
|
@site = site
|
||
|
@lang = lang.to_sym
|
||
|
@attributes = attributes.to_hash # porque enviamos parametros
|
||
|
end
|
||
|
|
||
|
# Vuelva los datos a YAML y los guarda en el archivo correspondiente
|
||
|
#
|
||
|
# TODO es necesario evitar que se agreguen llaves nuevas? No veo nada
|
||
|
# inseguro...
|
||
|
#
|
||
|
# https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/
|
||
|
#
|
||
|
# Pero parece que ya se resolvió hace rato. En general es mala
|
||
|
# práctica aceptar cualquier input de las usuarias, pero en este caso
|
||
|
# parece que no nos tenemos que preocupar?
|
||
|
#
|
||
|
# En cualquier caso habría que hacer un deep_merge, descartando las
|
||
|
# llaves que no están en el original y/o en el destino (pero queremos
|
||
|
# que el destino se parezca al original) y chequeando que no haya
|
||
|
# deserialización de objetos
|
||
|
#
|
||
|
# Jekyll usa SafeYAML para cargar los datos, con lo que estaríamos
|
||
|
# bien en cuanto a inyección de código.
|
||
|
def save
|
||
|
# Reemplaza los datos en el sitio
|
||
|
replace_lang_in_site
|
||
|
# Escribe los cambios en disco
|
||
|
write
|
||
|
end
|
||
|
|
||
|
# Obtiene la ruta a partir del sitio y el idioma
|
||
|
def path
|
||
|
File.join(@site.path, '_data', "#{@lang.to_s}.yml")
|
||
|
end
|
||
|
|
||
|
def exist?
|
||
|
File.exist? path
|
||
|
end
|
||
|
|
||
|
private
|
||
|
|
||
|
def replace_lang_in_site
|
||
|
@site.data[@lang.to_s] = @attributes
|
||
|
end
|
||
|
|
||
|
# Escribe los cambios en disco
|
||
|
#
|
||
|
# TODO unificar con Post.write
|
||
|
def write
|
||
|
r = File.open(path, File::RDWR | File::CREAT, 0o640) do |f|
|
||
|
# Bloquear el archivo para que no sea accedido por otro
|
||
|
# proceso u otra editora
|
||
|
f.flock(File::LOCK_EX)
|
||
|
|
||
|
# Empezar por el principio
|
||
|
f.rewind
|
||
|
|
||
|
# Escribir
|
||
|
f.write(content)
|
||
|
|
||
|
# Eliminar el resto
|
||
|
f.flush
|
||
|
f.truncate(f.pos)
|
||
|
end
|
||
|
|
||
|
return true if r.zero?
|
||
|
false
|
||
|
end
|
||
|
|
||
|
def content
|
||
|
@attributes.to_yaml
|
||
|
end
|
||
|
end
|