# frozen_string_literal: true # Se encargar de guardar cambios en sitios # TODO: Implementar rollback en la configuración SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do def deploy site.enqueue! DeployJob.perform_later site.id end # Crea un sitio, agrega un rol nuevo y guarda los cambios a la # configuración en el repositorio git def create self.site = Site.new params add_role temporal: false, rol: 'usuarie' site.deploys.build type: 'DeployLocal' # Los sitios de testing no se sincronizan sync_nodes unless site.name.end_with? '.testing' I18n.with_locale(usuarie.lang.to_sym || I18n.default_locale) do # No se puede llamar a site.config antes de save porque el sitio # todavía no existe. # # TODO: hacer que el repositorio se cree cuando es necesario, para # que no haya estados intermedios. site.locales = [usuarie.lang] + I18n.available_locales site.save && site.config.write && commit_config(action: :create) && site.reset.nil? && add_licencias && add_code_of_conduct && add_privacy_policy && deploy end site end # Actualiza el sitio y guarda los cambios en la configuración def update I18n.with_locale(usuarie&.lang&.to_sym || I18n.default_locale) do site.update(params) && site.config.write && commit_config(action: :update) && site.reset.nil? && change_licencias end site end # Genera los Deploy necesarios para el sitio a menos que ya los tenga. def build_deploys Deploy.subclasses.each do |deploy| next if site.deploys.find_by type: deploy.name site.deploys.build type: deploy end end # Agregar una dirección oculta de Tor al DeployHiddenService y a la # configuración del Site. def add_onion onion = params[:onion] deploy = params[:deploy] return false unless !onion.blank? && deploy site.config['onion-location'] = onion site.config.write commit_config(action: :tor) end # Trae cambios desde la rama remota y reindexa los artículos. # # @return [Boolean] def merge result = site.repository.merge(usuarie) # TODO: Implementar callbacks site.try(:index_posts!) if result result.present? end def rename(name) return if name == site.name moved = false site.name = name Site.transaction do raise ActiveRecord::Rollback if File.exists?(site.path) FileUtils.mv (site.path_was, site.path) moved = true ActiveStorage::Blob.where(service_name: site.name_was).update_all(service_name: site.name) site.save rescue StandardError FileUtils.mv (site.path, site.path_was) if moved raise end end private # Guarda los cambios de la configuración en el repositorio git def commit_config(action:) site.repository .commit(usuarie: usuarie, add: [site.config.path], message: I18n.t("site_service.#{action}", name: site.name)) GitPushJob.perform_later(site) end def add_role(temporal: true, rol: 'invitade') site.roles << Rol.new(site: site, usuarie: usuarie, temporal: temporal, rol: rol) end # Crea la licencia del sitio para cada locale disponible en el sitio # # @return [Boolean] def add_licencias return true unless site.layout? :license return true if site.licencia.custom? with_all_locales do |locale| add_licencia lang: locale end.compact.map(&:valid?).all? end # Crea una licencia # # @return [Post] def add_licencia(lang:) params = ActionController::Parameters.new( post: { layout: 'license', slug: Jekyll::Utils.slugify(I18n.t('activerecord.models.licencia')), lang: lang, title: site.licencia.name, description: site.licencia.short_description, content: CommonMarker.render_html(site.licencia.deed) } ) PostService.new(site: site, usuarie: usuarie, params: params).create end # Encuentra la licencia a partir de su enlace permanente y le cambia # el contenido # # @return [Boolean] def change_licencias return true unless site.layout? :license return true if site.licencia.custom? with_all_locales do |locale| post = site.posts(lang: locale).find_by(layout: 'license') change_licencia(post: post) if post end.compact.map(&:valid?).all? end # Cambia una licencia # # @param :post [Post] # @return [Post] def change_licencia(post:) params = ActionController::Parameters.new( post: { title: site.licencia.name, description: site.licencia.short_description, content: CommonMarker.render_html(site.licencia.deed) } ) PostService.new(site: site, usuarie: usuarie, post: post, params: params).update end # Agrega un código de conducta # # @return [Boolean] def add_code_of_conduct return true unless site.layout?(:code_of_conduct) || site.layout?(:page) # TODO: soportar más códigos de conducta coc = CodeOfConduct.first with_all_locales do |locale| params = ActionController::Parameters.new( post: { layout: site.layout?(:code_of_conduct) ? 'code_of_conduct' : 'page', lang: locale.to_s, title: coc.title, description: coc.description, content: CommonMarker.render_html(coc.content) } ) PostService.new(site: site, usuarie: usuarie, params: params).create end.compact.map(&:valid?).all? end # Agrega política de privacidad # # @return [Boolean] def add_privacy_policy return true unless site.layout?(:privacy_policy) || site.layout?(:page) pp = PrivacyPolicy.first with_all_locales do |locale| params = ActionController::Parameters.new( post: { layout: site.layout?(:privacy_policy) ? 'privacy_policy' : 'page', lang: locale.to_s, title: pp.title, description: pp.description, content: CommonMarker.render_html(pp.content) } ) PostService.new(site: site, usuarie: usuarie, params: params).create end.compact.map(&:valid?).all? end # Crea los deploys necesarios para sincronizar a otros nodos de Sutty def sync_nodes Rails.application.nodes.each do |node| site.deploys.build(type: 'DeployFullRsync', destination: "rsync://rsyncd.#{node}/deploys/", hostname: node) end end private def with_all_locales(&block) site.locales.map do |locale| next unless I18n.available_locales.include? locale Mobility.with_locale(locale) do yield locale end end end end