2019-08-13 23:33:57 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
# Este servicio se encarga de crear artículos y guardarlos en git,
|
|
|
|
# asignándoselos a une usuarie
|
|
|
|
PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
|
2023-10-25 18:29:22 +00:00
|
|
|
# Crea un artículo nuevo y modificar las asociaciones
|
2019-08-13 23:33:57 +00:00
|
|
|
#
|
|
|
|
# @return Post
|
|
|
|
def create
|
2023-10-06 13:16:47 +00:00
|
|
|
self.post = Post.build(site: site, locale: locale, layout: layout)
|
2019-09-25 22:31:33 +00:00
|
|
|
post.usuaries << usuarie
|
2019-09-30 18:41:50 +00:00
|
|
|
params[:post][:draft] = true if site.invitade? usuarie
|
2019-09-17 21:27:51 +00:00
|
|
|
|
2023-03-22 22:54:04 +00:00
|
|
|
params.require(:post).permit(:slug).tap do |p|
|
|
|
|
post.slug.value = p[:slug] if p[:slug].present?
|
|
|
|
end
|
|
|
|
|
2023-10-25 18:29:22 +00:00
|
|
|
if post.update(post_params)
|
|
|
|
added_paths = []
|
|
|
|
added_paths << post.path.value
|
|
|
|
|
|
|
|
# Recorrer todas las asociaciones y agregarse donde corresponda
|
2023-10-26 15:24:41 +00:00
|
|
|
update_associations(post)
|
2019-08-14 21:19:01 +00:00
|
|
|
|
2023-10-25 18:29:22 +00:00
|
|
|
commit(action: :created, add: added_paths)
|
|
|
|
end
|
2023-04-03 19:58:22 +00:00
|
|
|
|
2019-08-14 21:19:01 +00:00
|
|
|
# Devolver el post aunque no se haya salvado para poder rescatar los
|
|
|
|
# errores
|
|
|
|
post
|
|
|
|
end
|
|
|
|
|
2020-06-16 22:10:54 +00:00
|
|
|
# Crear un post anónimo, con opciones más limitadas. No usamos post.
|
2023-10-25 18:29:22 +00:00
|
|
|
#
|
|
|
|
# @todo Permitir asociaciones?
|
2020-02-18 16:45:08 +00:00
|
|
|
def create_anonymous
|
|
|
|
# XXX: Confiamos en el parámetro de idioma porque estamos
|
|
|
|
# verificándolos en Site#posts
|
2023-10-06 13:16:47 +00:00
|
|
|
self.post = Post.build(site: site, locale: locale, layout: layouts)
|
2020-02-18 16:45:08 +00:00
|
|
|
# Los artículos anónimos siempre son borradores
|
2020-06-16 22:10:54 +00:00
|
|
|
params[:draft] = true
|
2020-02-18 16:45:08 +00:00
|
|
|
|
2023-07-03 16:23:54 +00:00
|
|
|
commit(action: :created, add: [post.path.absolute]) if post.update(anon_post_params)
|
2020-02-18 16:45:08 +00:00
|
|
|
post
|
|
|
|
end
|
|
|
|
|
2023-10-25 18:29:22 +00:00
|
|
|
# Al actualizar, modificamos un post pre-existente, todas las
|
|
|
|
# relaciones anteriores y las relaciones actuales.
|
2019-08-14 21:19:01 +00:00
|
|
|
def update
|
2019-09-25 22:31:33 +00:00
|
|
|
post.usuaries << usuarie
|
2019-09-30 18:41:50 +00:00
|
|
|
params[:post][:draft] = true if site.invitade? usuarie
|
|
|
|
|
2023-07-03 16:38:29 +00:00
|
|
|
if post.update(post_params)
|
2023-10-25 18:29:22 +00:00
|
|
|
# Eliminar ("mover") el archivo si cambió de ubicación.
|
2023-07-03 16:38:29 +00:00
|
|
|
rm = []
|
|
|
|
rm << post.path.value_was if post.path.changed?
|
2019-08-13 23:33:57 +00:00
|
|
|
|
2023-10-25 18:29:22 +00:00
|
|
|
added_paths = []
|
|
|
|
added_paths << post.path.value
|
|
|
|
|
|
|
|
# Recorrer todas las asociaciones y agregarse donde corresponda
|
2023-10-26 15:24:41 +00:00
|
|
|
update_associations(post)
|
2023-10-25 18:29:22 +00:00
|
|
|
|
|
|
|
commit(action: :updated, add: added_paths, rm: rm)
|
2023-07-03 16:38:29 +00:00
|
|
|
end
|
2023-04-03 19:58:22 +00:00
|
|
|
|
2019-08-13 23:33:57 +00:00
|
|
|
# Devolver el post aunque no se haya salvado para poder rescatar los
|
|
|
|
# errores
|
|
|
|
post
|
|
|
|
end
|
|
|
|
|
2019-08-16 23:12:22 +00:00
|
|
|
def destroy
|
2019-09-17 21:27:51 +00:00
|
|
|
post.destroy!
|
|
|
|
|
2023-07-03 16:23:54 +00:00
|
|
|
commit(action: :destroyed, rm: [post.path.absolute]) if post.destroyed?
|
2019-08-16 23:12:22 +00:00
|
|
|
|
|
|
|
post
|
|
|
|
end
|
|
|
|
|
2019-11-06 22:35:48 +00:00
|
|
|
# Reordena todos los posts que soporten orden de acuerdo a un hash de
|
2020-01-02 23:29:04 +00:00
|
|
|
# uuids y nuevas posiciones. La posición actual la da la posición en
|
2019-10-18 20:35:09 +00:00
|
|
|
# el array.
|
|
|
|
#
|
2020-01-02 23:29:04 +00:00
|
|
|
# { uuid => 2, uuid => 1, uuid => 0 }
|
2019-10-18 20:35:09 +00:00
|
|
|
def reorder
|
2020-10-04 00:32:32 +00:00
|
|
|
reorder = params.require(:post).permit(reorder: {})&.dig(:reorder)&.transform_values(&:to_i)
|
2023-10-06 13:00:50 +00:00
|
|
|
posts = site.indexed_posts(locale: locale).where(post_id: reorder.keys).map(&:post)
|
2019-10-18 20:35:09 +00:00
|
|
|
|
2020-08-28 16:48:04 +00:00
|
|
|
files = posts.map do |post|
|
|
|
|
next unless post.attribute? :order
|
|
|
|
|
|
|
|
order = reorder[post.uuid.value]
|
2019-12-11 20:05:31 +00:00
|
|
|
|
|
|
|
next if post.order.value == order
|
2019-10-18 20:35:09 +00:00
|
|
|
|
2019-12-11 20:05:31 +00:00
|
|
|
post.order.value = order
|
2019-10-18 20:35:09 +00:00
|
|
|
post.path.absolute
|
|
|
|
end.compact
|
|
|
|
|
2020-08-28 16:48:04 +00:00
|
|
|
return if files.empty?
|
|
|
|
|
2019-10-18 20:35:09 +00:00
|
|
|
# TODO: Implementar transacciones!
|
2020-08-28 16:48:04 +00:00
|
|
|
posts.save_all(validate: false) &&
|
2023-07-03 16:23:54 +00:00
|
|
|
commit(action: :reorder, add: files)
|
2019-10-18 20:35:09 +00:00
|
|
|
end
|
|
|
|
|
2019-08-13 23:33:57 +00:00
|
|
|
private
|
|
|
|
|
2023-07-03 16:23:54 +00:00
|
|
|
def commit(action:, add: [], rm: [])
|
|
|
|
site.repository.commit(add: add,
|
|
|
|
rm: rm,
|
2019-08-14 21:19:01 +00:00
|
|
|
usuarie: usuarie,
|
|
|
|
message: I18n.t("post_service.#{action}",
|
2020-10-04 00:32:32 +00:00
|
|
|
title: post&.title&.value))
|
2023-08-16 20:35:20 +00:00
|
|
|
|
|
|
|
GitPushJob.perform_later(site)
|
2019-08-14 21:19:01 +00:00
|
|
|
end
|
|
|
|
|
2019-08-13 23:33:57 +00:00
|
|
|
# Solo permitir cambiar estos atributos de cada articulo
|
|
|
|
def post_params
|
|
|
|
params.require(:post).permit(post.params)
|
|
|
|
end
|
2019-10-18 20:35:09 +00:00
|
|
|
|
2020-02-18 16:45:08 +00:00
|
|
|
# Eliminar metadatos internos
|
|
|
|
def anon_post_params
|
2020-05-23 15:38:03 +00:00
|
|
|
params.permit(post.params).delete_if do |k, _|
|
2020-08-07 14:15:06 +00:00
|
|
|
%w[date slug order uuid].include? k.to_s
|
2020-02-18 16:45:08 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-10-06 13:16:47 +00:00
|
|
|
# @return [Symbol]
|
2020-05-23 15:38:03 +00:00
|
|
|
def locale
|
2021-03-03 12:43:15 +00:00
|
|
|
params.dig(:post, :lang)&.to_sym || I18n.locale
|
2020-03-19 18:31:29 +00:00
|
|
|
end
|
|
|
|
|
2023-10-06 13:16:47 +00:00
|
|
|
# @return [Layout]
|
2020-03-19 18:31:29 +00:00
|
|
|
def layout
|
2023-10-06 13:16:47 +00:00
|
|
|
site.layouts[
|
|
|
|
(params.dig(:post, :layout) || params[:layout]).to_sym
|
|
|
|
]
|
2019-10-18 20:35:09 +00:00
|
|
|
end
|
2020-07-21 22:19:40 +00:00
|
|
|
|
2023-10-25 18:29:22 +00:00
|
|
|
# Si les usuaries modifican o crean una licencia, considerarla
|
|
|
|
# personalizada en el panel.
|
|
|
|
def update_site_license!
|
|
|
|
if site.usuarie?(usuarie) && post.layout.name == :license && !site.licencia.custom?
|
|
|
|
site.update licencia: Licencia.find_by_icons('custom')
|
|
|
|
end
|
|
|
|
end
|
2020-07-21 22:19:40 +00:00
|
|
|
|
2023-10-25 18:29:22 +00:00
|
|
|
# @return [Array<String>]
|
|
|
|
def associated_posts_to_save
|
|
|
|
@associated_posts_to_save ||= Set.new
|
|
|
|
end
|
2020-07-21 22:19:40 +00:00
|
|
|
|
2023-10-25 18:29:22 +00:00
|
|
|
# Recolectar campos asociados que no estén vacíos
|
|
|
|
#
|
|
|
|
# @param [Post]
|
|
|
|
# @return [Array<Symbol>]
|
|
|
|
def association_attributes(post)
|
|
|
|
post.attributes.select do |attribute|
|
|
|
|
post[attribute].try(:inverse?)
|
2020-07-21 22:19:40 +00:00
|
|
|
end
|
2023-10-25 18:29:22 +00:00
|
|
|
end
|
2020-07-21 22:19:40 +00:00
|
|
|
|
2023-10-25 18:29:22 +00:00
|
|
|
# @param :post_ids [Array<String>]
|
|
|
|
# @return [Association]
|
|
|
|
def associated_posts(post_ids)
|
|
|
|
site.indexed_posts.where(post_id: post_ids).map(&:post)
|
2020-07-21 22:19:40 +00:00
|
|
|
end
|
2023-04-03 19:58:22 +00:00
|
|
|
|
2023-10-26 19:41:33 +00:00
|
|
|
# Modificar las asociaciones en cascada, manteniendo reciprocidad
|
|
|
|
# y guardando los archivos correspondientes.
|
|
|
|
#
|
|
|
|
# HABTM, Locales: si se rompe de un lado se elimina en el otro y lo
|
|
|
|
# mismo si se agrega.
|
|
|
|
#
|
|
|
|
# HasMany: la relación es de uno a muchos. Al quitar uno, se elimina
|
|
|
|
# la relación inversa. Al agregar uno, se elimina su relación
|
|
|
|
# anterior en el tercer Post y se actualiza con la nueva.
|
|
|
|
#
|
|
|
|
# BelongsTo: la inversa de HasMany. Al cambiarla, se quita de la
|
|
|
|
# relación anterior y se agrega en la nueva.
|
|
|
|
#
|
|
|
|
# @param :post [Post]
|
|
|
|
# @return [nil]
|
2023-10-26 15:24:41 +00:00
|
|
|
def update_associations(post)
|
2023-10-25 18:29:22 +00:00
|
|
|
association_attributes(post).each do |attribute|
|
|
|
|
metadata = post[attribute]
|
|
|
|
|
|
|
|
next unless metadata.changed?
|
|
|
|
|
|
|
|
inverse_attribute = post[attribute].inverse
|
|
|
|
value_was = metadata.value_was.dup
|
2023-10-26 15:24:41 +00:00
|
|
|
value = metadata.value.dup
|
2023-10-25 18:29:22 +00:00
|
|
|
|
|
|
|
case metadata.type
|
2023-10-26 19:36:29 +00:00
|
|
|
when 'has_and_belongs_to_many', 'locales'
|
2023-10-25 18:29:22 +00:00
|
|
|
associated_posts(value_was - value).each do |remove_post|
|
2023-10-26 19:27:01 +00:00
|
|
|
remove_relation_from(remove_post[inverse_attribute], post.uuid.value)
|
2023-10-25 18:29:22 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
associated_posts(value - value_was).each do |add_post|
|
2023-10-26 19:29:58 +00:00
|
|
|
add_relation_to(add_post[inverse_attribute], post.uuid.value)
|
2023-10-25 18:29:22 +00:00
|
|
|
end
|
|
|
|
when 'has_many'
|
2023-10-26 15:24:41 +00:00
|
|
|
associated_posts(value_was - value).each do |remove_post|
|
2023-10-26 19:27:01 +00:00
|
|
|
remove_relation_from(remove_post[inverse_attribute], '')
|
2023-10-26 15:24:41 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
associated_posts(value - value_was).each do |add_post|
|
|
|
|
associated_posts(add_post[inverse_attribute].value_was).each do |remove_post|
|
2023-10-26 19:27:01 +00:00
|
|
|
remove_relation_from(remove_post[attribute], add_post.uuid.value)
|
2023-10-26 15:24:41 +00:00
|
|
|
end
|
|
|
|
|
2023-10-26 19:29:58 +00:00
|
|
|
add_relation_to(add_post[inverse_attribute], post.uuid.value)
|
2023-10-26 15:24:41 +00:00
|
|
|
end
|
2023-10-25 18:29:22 +00:00
|
|
|
when 'belongs_to'
|
2023-10-26 15:24:41 +00:00
|
|
|
if value_was.present?
|
|
|
|
associated_posts(value_was).each do |remove_post|
|
2023-10-26 19:27:01 +00:00
|
|
|
remove_relation_from(remove_post[inverse_attribute], value_was)
|
2023-10-26 15:24:41 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
associated_posts(value).each do |add_post|
|
2023-10-26 19:29:58 +00:00
|
|
|
add_relation_to(add_post[inverse_attribute], post.uuid.value)
|
2023-10-26 15:24:41 +00:00
|
|
|
end
|
2023-10-25 18:29:22 +00:00
|
|
|
end
|
2023-04-03 19:58:22 +00:00
|
|
|
end
|
2023-10-26 19:31:34 +00:00
|
|
|
|
|
|
|
associated_posts_to_save.each do |associated_post|
|
|
|
|
next unless associated_post.save(validate: false)
|
|
|
|
|
|
|
|
added_paths << associated_post.path.value
|
|
|
|
end
|
2023-10-26 19:41:33 +00:00
|
|
|
|
|
|
|
nil
|
2023-04-03 19:58:22 +00:00
|
|
|
end
|
2023-10-26 19:27:01 +00:00
|
|
|
|
|
|
|
# @todo por qué no podemos usar nil para deshabilitar un valor?
|
2023-10-26 19:36:29 +00:00
|
|
|
# @param :metadata [MetadataTemplate]
|
|
|
|
# @param :value [String]
|
|
|
|
# @return [nil]
|
2023-10-26 19:27:01 +00:00
|
|
|
def remove_relation_from(metadata, value)
|
|
|
|
case metadata.value
|
|
|
|
when Array then metadata.value.delete(value)
|
|
|
|
when String then metadata.value = ''
|
|
|
|
end
|
|
|
|
|
|
|
|
associated_posts_to_save << metadata.post
|
|
|
|
nil
|
|
|
|
end
|
2023-10-26 19:29:58 +00:00
|
|
|
|
|
|
|
# @todo El validador ya debería eliminar valores duplicados
|
2023-10-26 19:36:29 +00:00
|
|
|
# @param :metadata [MetadataTemplate]
|
|
|
|
# @param :value [String]
|
|
|
|
# @return [nil]
|
2023-10-26 19:29:58 +00:00
|
|
|
def add_relation_to(metadata, value)
|
|
|
|
case metadata.value
|
|
|
|
when Array
|
|
|
|
metadata.value << value
|
|
|
|
metadata.uniq!
|
|
|
|
when String then metadata.value = value
|
|
|
|
end
|
|
|
|
|
|
|
|
associated_posts_to_save << metadata.post
|
|
|
|
nil
|
|
|
|
end
|
2019-08-13 23:33:57 +00:00
|
|
|
end
|