5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2025-03-14 20:08:19 +00:00

Merge branch 'issue-18074' into 'rails'

Draft: fix: optimizar api de sitios #18074

See merge request sutty/sutty!289
This commit is contained in:
fauno 2025-01-26 05:30:59 +00:00
commit f2ddc1b653
11 changed files with 99 additions and 41 deletions

View file

@ -4,51 +4,88 @@ module Api
module V1 module V1
# API para sitios # API para sitios
class SitesController < BaseController class SitesController < BaseController
SUBDOMAIN = ".#{Site.domain}"
TESTING_SUBDOMAIN = ".testing.#{Site.domain}"
PARTS = Site.domain.split('.').count
if Rails.env.production?
http_basic_authenticate_with name: ENV['HTTP_BASIC_USER'], http_basic_authenticate_with name: ENV['HTTP_BASIC_USER'],
password: ENV['HTTP_BASIC_PASSWORD'] password: ENV['HTTP_BASIC_PASSWORD']
end
# Lista de nombres de dominios a emitir certificados # Lista de nombres de dominios a emitir certificados
def index def index
render json: alternative_names + api_names + www_names all_names = sites_names.concat(alternative_names).concat(www_names).concat(api_names).uniq.map do |name|
canonicalize name
end.reject do |name|
subdomain? name
end.reject do |name|
testing? name
end.uniq
render json: all_names
end end
private private
# @param query [ActiveRecord::Relation]
# @return [Array<String>]
def hostname_of(query)
query.pluck(Arel.sql("values->>'hostname'")).compact.uniq
end
def canonicalize(name) def canonicalize(name)
name.end_with?('.') ? name[0..-2] : "#{name}.#{Site.domain}" name.end_with?('.') ? name[0..-2] : "#{name}.#{Site.domain}"
end end
# Es un subdominio directo del dominio principal
#
# @param name [String]
# @return [Bool]
def subdomain?(name) def subdomain?(name)
name.end_with? ".#{Site.domain}" name.end_with?(SUBDOMAIN) && name.split('.').count == (PARTS + 1)
end end
# Dominios alternativos # Es un dominio de prueba
def alternative_names #
(DeployAlternativeDomain.all.map(&:hostname) + DeployLocalizedDomain.all.map(&:hostname)).map do |name| # @param name [String]
canonicalize name # @return [Bool]
end.reject do |name| def testing?(name)
subdomain? name name.end_with?(TESTING_SUBDOMAIN) && name.split('.').count == (PARTS + 2)
end end
# Nombres de los sitios
#
# @param name [String]
# @return [Array<String>]
def sites_names
Site.all.order(:name).pluck(:name)
end
# Dominios alternativos, incluyendo todas las clases derivadas de
# esta.
#
# @return [Array<String>]
def alternative_names
hostname_of(DeployAlternativeDomain.all)
end end
# Obtener todos los sitios con API habilitada, es decir formulario # Obtener todos los sitios con API habilitada, es decir formulario
# de contacto y/o colaboración anónima. # de contacto y/o colaboración anónima.
# #
# TODO: Optimizar # @return [Array<String>]
def api_names def api_names
Site.where(contact: true) Site.where(contact: true)
.or(Site.where(colaboracion_anonima: true)) .or(Site.where(colaboracion_anonima: true))
.select("'api.' || name as name").map(&:name).map do |name| .pluck(:name).map do |name|
canonicalize name "api.#{name}"
end.reject do |name|
subdomain? name
end end
end end
# Todos los dominios con WWW habilitado # Todos los dominios con WWW habilitado
def www_names def www_names
Site.where(id: DeployWww.all.pluck(:site_id)).select("'www.' || name as name").map(&:name).map do |name| Site.where(id: DeployWww.all.pluck(:site_id)).pluck(:name).map do |name|
canonicalize name "www.#{name}"
end end
end end
end end

View file

@ -2,7 +2,7 @@
# Soportar dominios alternativos # Soportar dominios alternativos
class DeployAlternativeDomain < Deploy class DeployAlternativeDomain < Deploy
store :values, accessors: %i[hostname], coder: JSON store_accessor :values, :hostname
DEPENDENCIES = %i[deploy_local] DEPENDENCIES = %i[deploy_local]

View file

@ -12,7 +12,10 @@ require 'distributed_press/v1/client/site'
# Al ser publicado, envía los archivos en un tarball y actualiza la # Al ser publicado, envía los archivos en un tarball y actualiza la
# información. # información.
class DeployDistributedPress < Deploy class DeployDistributedPress < Deploy
store :values, accessors: %i[hostname remote_site_id remote_info distributed_press_publisher_id], coder: JSON store_accessor :values, :hostname
store_accessor :values, :remote_site_id
store_accessor :values, :remote_info
store_accessor :values, :distributed_press_publisher_id
before_create :create_remote_site! before_create :create_remote_site!
before_destroy :delete_remote_site! before_destroy :delete_remote_site!

View file

@ -2,7 +2,7 @@
# Genera una versión onion # Genera una versión onion
class DeployHiddenService < DeployWww class DeployHiddenService < DeployWww
store :values, accessors: %i[onion], coder: JSON store_accessor :values, :onion
before_create :create_hidden_service! before_create :create_hidden_service!

View file

@ -3,8 +3,6 @@
# Alojamiento local, solo genera el sitio, con lo que no necesita hacer # Alojamiento local, solo genera el sitio, con lo que no necesita hacer
# nada más # nada más
class DeployLocal < Deploy class DeployLocal < Deploy
store :values, accessors: %i[], coder: JSON
before_destroy :remove_destination! before_destroy :remove_destination!
def bundle(output: false) def bundle(output: false)

View file

@ -2,7 +2,8 @@
# Soportar dominios localizados # Soportar dominios localizados
class DeployLocalizedDomain < DeployAlternativeDomain class DeployLocalizedDomain < DeployAlternativeDomain
store :values, accessors: %i[hostname locale], coder: JSON store_accessor :values, :hostname
store_accessor :values, :locale
# Generar un link simbólico del sitio principal al alternativo # Generar un link simbólico del sitio principal al alternativo
def deploy(**) def deploy(**)

View file

@ -3,11 +3,15 @@
# Sincroniza sitios a servidores remotos usando Rsync. El servidor # Sincroniza sitios a servidores remotos usando Rsync. El servidor
# remoto tiene que tener rsync instalado. # remoto tiene que tener rsync instalado.
class DeployRsync < Deploy class DeployRsync < Deploy
store :values, accessors: %i[hostname destination host_keys], coder: JSON store_accessor :values, :hostname
store_accessor :values, :destination
store_accessor :values, :host_keys
DEPENDENCIES = %i[deploy_local deploy_zip] DEPENDENCIES = %i[deploy_local deploy_zip]
def deploy(output: false) def deploy(output: false)
raise(ArgumentError, 'destination no está configurado') if destination.blank?
ssh? && rsync(output: output) ssh? && rsync(output: output)
end end
@ -18,13 +22,6 @@ class DeployRsync < Deploy
deploy_local.size deploy_local.size
end end
# Devolver el destino o lanzar un error si no está configurado
def destination
values[:destination].tap do |d|
raise(ArgumentError, 'destination no está configurado') if d.blank?
end
end
# @return [String] # @return [String]
def url def url
"https://#{hostname}/" "https://#{hostname}/"
@ -43,9 +40,9 @@ class DeployRsync < Deploy
ssh_available = false ssh_available = false
Net::SSH.start(host, user, verify_host_key: tofu, timeout: 5) do |ssh| Net::SSH.start(host, user, verify_host_key: tofu, timeout: 5) do |ssh|
if values[:host_keys].blank? if self.host_keys.blank?
# Guardar las llaves que se encontraron en la primera conexión # Guardar las llaves que se encontraron en la primera conexión
values[:host_keys] = ssh.transport.host_keys.map do |host_key| self.host_keys = ssh.transport.host_keys.map do |host_key|
"#{host_key.ssh_type} #{host_key.fingerprint}" "#{host_key.ssh_type} #{host_key.fingerprint}"
end end
@ -74,7 +71,7 @@ class DeployRsync < Deploy
# #
# @return [Symbol] # @return [Symbol]
def tofu def tofu
values[:host_keys].present? ? :always : :accept_new self.host_keys.present? ? :always : :accept_new
end end
# Devuelve el par user host # Devuelve el par user host

View file

@ -2,8 +2,6 @@
# Vincula la versión del sitio con www a la versión sin # Vincula la versión del sitio con www a la versión sin
class DeployWww < Deploy class DeployWww < Deploy
store :values, accessors: %i[], coder: JSON
DEPENDENCIES = %i[deploy_local] DEPENDENCIES = %i[deploy_local]
before_destroy :remove_destination! before_destroy :remove_destination!

View file

@ -6,8 +6,6 @@ require 'zip'
# #
# TODO: Firmar con minisign # TODO: Firmar con minisign
class DeployZip < Deploy class DeployZip < Deploy
store :values, accessors: %i[], coder: JSON
DEPENDENCIES = %i[deploy_local] DEPENDENCIES = %i[deploy_local]
# Una vez que el sitio está generado, tomar todos los archivos y # Una vez que el sitio está generado, tomar todos los archivos y

View file

@ -0,0 +1,25 @@
# frozen_string_literal: true
class ChangeDeploysValuesTypeToJsonB < ActiveRecord::Migration[6.1]
def up
add_column :deploys, :values_2, :jsonb, default: {}
Deploy.find_each do |deploy|
deploy.update values_2: JSON.parse(deploy.values)
end
remove_column :deploys, :values
rename_column :deploys, :values_2, :values
end
def down
add_column :deploys, :values_2, :text
Deploy.find_each do |deploy|
deploy.update values_2: deploy.values.to_json
end
remove_column :deploys, :values
rename_column :deploys, :values_2, :values
end
end

View file

@ -882,8 +882,8 @@ CREATE TABLE public.deploys (
updated_at timestamp without time zone NOT NULL, updated_at timestamp without time zone NOT NULL,
site_id integer, site_id integer,
type character varying, type character varying,
"values" text, rol_id integer,
rol_id integer "values" jsonb DEFAULT '{}'::jsonb
); );
@ -2719,6 +2719,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20240316203721'), ('20240316203721'),
('20240318183846'), ('20240318183846'),
('20240319124212'), ('20240319124212'),
('20240319144735'); ('20240319144735'),
('20241223185830');