5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-11-22 14:36:21 +00:00
panel/app/services/post_service.rb

222 lines
5.9 KiB
Ruby
Raw Normal View History

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
# Si estamos pasando el UUID con los parámetros, el post quizás
# existe.
#
# @return [Post]
def create_or_update
uuid = params.require(base).permit(:uuid).values.first
if uuid.blank?
create
elsif (indexed_post = site.indexed_posts.find_by(post_id: uuid)).present?
self.post = indexed_post.post
update
else
create
end
end
2019-08-13 23:33:57 +00:00
# Crea un artículo nuevo
#
# @return Post
def create
self.post ||= site.posts(lang: locale).build(layout: layout)
post.usuaries << usuarie
post.draft.value = true if post.attribute?(:draft) && site.invitade?(usuarie)
2024-04-17 21:06:56 +00:00
post.assign_attributes(post_params)
params.require(base).permit(:slug).tap do |p|
post.slug.value = p[:slug] if p[:slug].present?
end
2024-04-17 21:09:05 +00:00
# Crea los posts anidados
2024-05-23 18:24:49 +00:00
create_nested_posts! post, params[base]
post.save
update_related_posts
2024-05-23 18:24:49 +00:00
commit(action: :created, add: files) if post.valid?
update_site_license!
# 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.
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
2020-05-23 15:38:03 +00:00
self.post = site.posts(lang: locale)
.build(layout: layout)
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
commit(action: :created, add: files) if post.update(anon_post_params)
2020-02-18 16:45:08 +00:00
post
end
def update
post.usuaries << usuarie
2024-05-23 18:24:49 +00:00
params[base][:draft] = true if site.invitade? usuarie
# Eliminar ("mover") el archivo si cambió de ubicación.
if post.update(post_params)
rm = []
rm << post.path.value_was if post.path.changed?
2019-08-13 23:33:57 +00:00
2024-05-23 18:24:49 +00:00
create_nested_posts! post, params[base]
update_related_posts
# Es importante que el artículo se guarde primero y luego los
# relacionados.
commit(action: :updated, add: files, rm: rm)
2019-08-13 23:33:57 +00:00
update_site_license!
end
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
post.destroy!
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
reorder = params.require(base).permit(reorder: {})&.dig(:reorder)&.transform_values(&:to_i)
2020-08-28 16:48:04 +00:00
posts = site.posts(lang: locale).where(uuid: reorder.keys)
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]
next if post.order.value == order
2019-10-18 20:35:09 +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) &&
commit(action: :reorder, add: files)
2019-10-18 20:35:09 +00:00
end
2019-08-13 23:33:57 +00:00
private
# La base donde buscar los parámetros
#
# @return [Symbol]
def base
@base ||= params.permit(:base).try(:[], :base).try(:to_sym) || :post
end
# Una lista de archivos a modificar
#
# @return [Set]
def files
@files ||= Set.new.tap do |f|
f << post.path.absolute
end
end
def commit(action:, add: [], rm: [])
site.repository.commit(add: add,
rm: rm,
usuarie: usuarie,
message: I18n.t("post_service.#{action}",
2020-10-04 00:32:32 +00:00
title: post&.title&.value))
GitPushJob.perform_later(site)
end
2019-08-13 23:33:57 +00:00
# Solo permitir cambiar estos atributos de cada articulo
def post_params
@post_params ||= params.require(base).permit(post.params).to_h
2019-08-13 23:33:57 +00:00
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
2020-05-23 15:38:03 +00:00
def locale
2024-05-23 18:24:49 +00:00
params.dig(base, :lang)&.to_sym || I18n.locale
2020-03-19 18:31:29 +00:00
end
def layout
2024-05-23 18:24:49 +00:00
params.dig(base, :layout) || params[:layout]
2019-10-18 20:35:09 +00:00
end
# Actualiza los artículos relacionados según los métodos que los
# metadatos declaren.
#
# Este método se asegura que todos los artículos se guardan una sola
# vez.
#
# @return [Array] Lista de archivos modificados
def update_related_posts
posts = Set.new
post.attributes.each do |a|
2020-07-22 23:35:43 +00:00
post[a].related_methods.each do |m|
next unless post[a].respond_to? m
# La respuesta puede ser una PostRelation también
posts.merge [post[a].public_send(m)].flatten.compact
end
end
posts.map do |p|
next unless p.save(validate: false)
files << p.path.absolute
end
end
# Si les usuaries modifican o crean una licencia, considerarla
# personalizada en el panel.
def update_site_license!
2024-05-24 16:22:28 +00:00
return unless site.usuarie?(usuarie) && post.layout.name == :license && !site.licencia.custom?
site.update licencia: Licencia.find_by_icons('custom')
end
2024-04-17 21:09:05 +00:00
# Encuentra todos los posts anidados y los crea o modifica
def create_nested_posts!(post, params)
post.nested_attributes.each do |nested_attribute|
2024-05-24 16:22:28 +00:00
nested_metadata = post[nested_attribute]
next unless params[nested_metadata].present?
2024-05-24 16:22:28 +00:00
# @todo find_or_initialize
nested_post = nested_metadata.has_one || site.posts(lang: post.lang.value).build(layout: nested_metadata.nested)
nested_params = params.require(nested_attribute).permit(nested_post.params).to_hash
2024-04-17 21:09:05 +00:00
2024-05-24 16:22:28 +00:00
# Completa la relación 1:1
nested_params[nested_metadata.inverse.to_s] = post.uuid.value
post[nested_attribute].value = nested_post.uuid.value
2024-04-17 21:09:05 +00:00
2024-05-24 16:22:28 +00:00
files << nested_post.path.absolute if nested_post.update(nested_params)
2024-04-17 21:09:05 +00:00
end
end
2019-08-13 23:33:57 +00:00
end