# frozen_string_literal: true # Este servicio se encarga de crear artículos y guardarlos en git, # asignándoselos a une usuarie # rubocop:disable Metrics/BlockLength PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do # Crea un artículo nuevo # # @return Post def create self.post = site.posts(lang: locale) .build(layout: layout) post.usuaries << usuarie params[:post][:draft] = true if site.invitade? usuarie commit(action: :created, file: update_related_posts) if post.update(post_params) # Devolver el post aunque no se haya salvado para poder rescatar los # errores post end # Crear un post anónimo, con opciones más limitadas. No usamos post. def create_anonymous # XXX: Confiamos en el parámetro de idioma porque estamos # verificándolos en Site#posts self.post = site.posts(lang: locale) .build(layout: layout) # Los artículos anónimos siempre son borradores params[:draft] = true commit(action: :created) if post.update(anon_post_params) post end def update post.usuaries << usuarie params[:post][:draft] = true if site.invitade? usuarie commit(action: :updated, file: update_related_posts) if post.update(post_params) # Devolver el post aunque no se haya salvado para poder rescatar los # errores post end def destroy post.destroy! commit(action: :destroyed) if post.destroyed? post end # Reordena todos los posts que soporten orden de acuerdo a un hash de # uuids y nuevas posiciones. La posición actual la da la posición en # el array. # # { uuid => 2, uuid => 1, uuid => 0 } def reorder posts = site.posts(lang: locale) reorder = params.require(:post).permit(reorder: {}).try(:[], :reorder) modified = PostRelation.new(site: site) files = reorder.keys.map do |uuid| post = posts.find(uuid, uuid: true) order = reorder[uuid].to_i next unless post next unless post.attributes.include? :order next if post.order.value == order modified << post post.order.value = order post.path.absolute end.compact # TODO: Implementar transacciones! modified.save_all(validate: false) && commit(action: :reorder, file: files) end private def commit(action:, file: nil) site.repository.commit(file: file || post.path.absolute, usuarie: usuarie, remove: action == :destroyed, message: I18n.t("post_service.#{action}", title: post.try(:title).try(:value))) end # Solo permitir cambiar estos atributos de cada articulo def post_params params.require(:post).permit(post.params) end # Eliminar metadatos internos def anon_post_params params.permit(post.params).delete_if do |k, _| %w[date slug order uuid].include? k.to_s end end def locale params.dig(:post, :lang) || I18n.locale end def layout params.dig(:post, :layout) || params[:layout] end # Actualiza los artículos relacionados según los métodos que los # metadatos declaren. # # @return [Array] Lista de archivos modificados def update_related_posts files = [post.path.absolute] post.attributes.each do |a| next unless post[a].related_posts? post[a].related_methods.each do |m| next unless post[a].respond_to? m # La respuesta puede ser una PostRelation también [post[a].public_send(m)].flatten.compact.each do |p| files << p.path.absolute if p.save(validate: false) end end end files end end # rubocop:enable Metrics/BlockLength