5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-11-16 17:36:22 +00:00

Merge branch 'rails' of 0xacab.org:sutty/sutty into issue-13498

This commit is contained in:
f 2023-11-29 10:49:11 -03:00
commit 959da50dac
No known key found for this signature in database
11 changed files with 224 additions and 74 deletions

View file

@ -40,7 +40,6 @@ gem 'devise'
gem 'devise-i18n' gem 'devise-i18n'
gem 'devise_invitable' gem 'devise_invitable'
gem 'distributed-press-api-client', '~> 0.3.0rc0' gem 'distributed-press-api-client', '~> 0.3.0rc0'
gem 'njalla-api-client', '~> 0.2.0'
gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n'
gem 'exception_notification' gem 'exception_notification'
gem 'fast_blank' gem 'fast_blank'

View file

@ -366,9 +366,6 @@ GEM
net-ssh (7.1.0) net-ssh (7.1.0)
netaddr (2.0.6) netaddr (2.0.6)
nio4r (2.5.9-x86_64-linux-musl) nio4r (2.5.9-x86_64-linux-musl)
njalla-api-client (0.2.0)
dry-schema
httparty (~> 0.18)
nokogiri (1.15.4-x86_64-linux-musl) nokogiri (1.15.4-x86_64-linux-musl)
mini_portile2 (~> 2.8.2) mini_portile2 (~> 2.8.2)
racc (~> 1.4) racc (~> 1.4)
@ -636,7 +633,6 @@ DEPENDENCIES
mini_magick mini_magick
mobility mobility
net-ssh net-ssh
njalla-api-client (~> 0.2.0)
nokogiri nokogiri
pg pg
pg_search pg_search

View file

@ -56,6 +56,10 @@ class DeployJob < ApplicationJob
rescue URI::Error rescue URI::Error
nil nil
end.compact end.compact
if d == @site.deployment_list.last && !status
raise DeployException, 'Falló la compilación'
end
rescue StandardError => e rescue StandardError => e
status = false status = false
seconds ||= 0 seconds ||= 0

View file

@ -5,9 +5,12 @@
class GitPullJob < ApplicationJob class GitPullJob < ApplicationJob
# @param :site [Site] # @param :site [Site]
# @param :usuarie [Usuarie] # @param :usuarie [Usuarie]
# @param :message [String]
# @return [nil] # @return [nil]
def perform(site, usuarie, message) def perform(site, usuarie)
site.repository.merge(usuarie, message) if site.repository.fetch&.positive? return unless site.repository.origin
return unless site.repository.fetch.positive?
site.repository.merge(usuarie)
site.reindex_changes!
end end
end end

View file

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'distributed_press/v1/client/site' require 'distributed_press/v1/client/site'
require 'njalla/v1'
# Soportar Distributed Press APIv1 # Soportar Distributed Press APIv1
# #
@ -15,8 +14,8 @@ require 'njalla/v1'
class DeployDistributedPress < Deploy class DeployDistributedPress < Deploy
store :values, accessors: %i[hostname remote_site_id remote_info], coder: JSON store :values, accessors: %i[hostname remote_site_id remote_info], coder: JSON
before_create :create_remote_site!, :create_njalla_records! before_create :create_remote_site!
before_destroy :delete_remote_site!, :delete_njalla_records! before_destroy :delete_remote_site!
DEPENDENCIES = %i[deploy_local] DEPENDENCIES = %i[deploy_local]
@ -31,17 +30,12 @@ class DeployDistributedPress < Deploy
time_start time_start
create_remote_site! if remote_site_id.blank? create_remote_site! if remote_site_id.blank?
create_njalla_records!
save save
if remote_site_id.blank? if remote_site_id.blank?
raise DeployJob::DeployException, 'El sitio no se creó en Distributed Press' raise DeployJob::DeployException, 'El sitio no se creó en Distributed Press'
end end
if create_njalla_records? && remote_info[:njalla].blank?
raise DeployJob::DeployException, 'No se pudieron crear los registros necesarios en Njalla'
end
site_client.tap do |c| site_client.tap do |c|
stdout = Thread.new(publisher.logger_out) do |io| stdout = Thread.new(publisher.logger_out) do |io|
until io.eof? until io.eof?
@ -145,29 +139,6 @@ class DeployDistributedPress < Deploy
nil nil
end end
# Crea los registros en Njalla
#
# XXX: Esto depende de nuestro DNS actual, cuando lo migremos hay
# que eliminarlo.
#
# @return [nil]
def create_njalla_records!
return unless create_njalla_records?
self.remote_info ||= {}
self.remote_info[:njalla] ||= {}
self.remote_info[:njalla][:a] ||= njalla.add_record(name: site.name, type: 'CNAME', content: "#{Site.domain}.").to_h
self.remote_info[:njalla][:cname] ||= njalla.add_record(name: "www.#{site.name}", type: 'CNAME', content: "#{Site.domain}.").to_h
self.remote_info[:njalla][:ns] ||= njalla.add_record(name: "_dnslink.#{site.name}", type: 'NS', content: "#{publisher.hostname}.").to_h
nil
rescue HTTParty::Error => e
ExceptionNotifier.notify_exception(e, data: { site: site.name })
self.remote_info.delete :njalla
ensure
nil
end
# Registra lo que sucedió # Registra lo que sucedió
# #
# @param status [Bool] # @param status [Bool]
@ -185,31 +156,4 @@ class DeployDistributedPress < Deploy
ExceptionNotifier.notify_exception(e, data: { site: site.name }) ExceptionNotifier.notify_exception(e, data: { site: site.name })
nil nil
end end
def delete_njalla_records!
return unless create_njalla_records?
%w[a ns cname].each do |type|
next if (id = remote_info.dig('njalla', type, 'id')).blank?
njalla.remove_record(id: id.to_i)
end
end
# Actualizar registros en Njalla
#
# @return [Njalla::V1::Domain]
def njalla
@njalla ||=
begin
client = Njalla::V1::Client.new(token: Rails.application.credentials.njalla)
Njalla::V1::Domain.new(domain: Site.domain, client: client)
end
end
# Detecta si tenemos que crear registros en Njalla
def create_njalla_records?
!site.name.end_with?('.')
end
end end

View file

@ -36,6 +36,15 @@ class IndexedPost < ApplicationRecord
belongs_to :site belongs_to :site
# Encuentra el post original
#
# @return [nil,Post]
def post
return if post_id.blank?
@post ||= site.posts(lang: locale).find(post_id, uuid: true)
end
# Convertir locale a direccionario de PG # Convertir locale a direccionario de PG
# #
# @param [String,Symbol] # @param [String,Symbol]

View file

@ -1,19 +1,124 @@
# frozen_string_literal: true # frozen_string_literal: true
class Site
# Indexa todos los artículos de un sitio # Indexa todos los artículos de un sitio
# #
# TODO: Hacer opcional # TODO: Hacer opcional
class Site
module Index module Index
extend ActiveSupport::Concern extend ActiveSupport::Concern
included do included do
has_many :indexed_posts, dependent: :destroy has_many :indexed_posts, dependent: :destroy
MODIFIED_STATUSES = %i[added modified].freeze
DELETED_STATUSES = %i[deleted].freeze
LOCALE_FROM_PATH = /\A_/.freeze
def index_posts! def index_posts!
Site.transaction do Site.transaction do
docs.each(&:index!) docs.each(&:index!)
end
update(last_indexed_commit: repository.head_commit.oid)
end
end
# Encuentra los artículos modificados entre dos commits y los
# reindexa.
def reindex_changes!
return unless reindexable?
Site.transaction do
remove_deleted_posts!
reindex_modified_posts!
update(last_indexed_commit: repository.head_commit.oid)
end
end
# No hacer nada si el repositorio no cambió o no hubo cambios
# necesarios
def reindexable?
return false if last_indexed_commit.blank?
return false if last_indexed_commit == repository.head_commit.oid
!indexable_posts.empty?
end
private
# Trae el último commit indexado desde el repositorio
#
# @return [Rugged::Commit]
def indexed_commit
@indexed_commit ||= repository.rugged.lookup(last_indexed_commit)
end
# Calcula la diferencia entre el último commit indexado y el
# actual
#
# XXX: Esto no tiene en cuenta modificaciones en la historia como
# cambio de ramas, reverts y etc, solo asume que se mueve hacia
# adelante en la misma rama o las dos ramas están relacionadas.
#
# @return [Rugged::Diff]
def diff_with_head
@diff_with_head ||= indexed_commit.diff(repository.head_commit)
end
# Obtiene todos los archivos a reindexar
#
# @return [Array<Rugged::Delta>]
def indexable_posts
@indexable_posts ||=
diff_with_head.each_delta.select do |delta|
locales.any? do |locale|
delta.old_file[:path].start_with? "_#{locale}/"
end
end
end
# Elimina los artículos eliminados o que cambiaron de ubicación
# del índice
def remove_deleted_posts!
indexable_posts.select do |delta|
DELETED_STATUSES.include? delta.status
end.each do |delta|
locale, path = locale_and_path_from(delta.old_file[:path])
indexed_posts.destroy_by(locale: locale, path: path).tap do |destroyed_posts|
next unless destroyed_posts.empty?
Rails.logger.info I18n.t('indexed_posts.deleted', site: name, path: path, records: destroyed_posts.count)
end
end
end
# Reindexa artículos que cambiaron de ubicación, se agregaron
# o fueron modificados
def reindex_modified_posts!
indexable_posts.select do |delta|
MODIFIED_STATUSES.include? delta.status
end.each do |delta|
locale, path = locale_and_path_from(delta.new_file[:path])
posts(lang: locale).find(path).index!
end
end
# Obtiene el idioma y la ruta del post a partir de la ubicación en
# el disco.
#
# Las rutas vienen en ASCII-9BIT desde Rugged, pero en realidad
# son UTF-8
#
# @return [Array<String>]
def locale_and_path_from(path)
locale, path = path.force_encoding('utf-8').split(File::SEPARATOR, 2)
[
locale.sub(LOCALE_FROM_PATH, ''),
File.basename(path, '.*')
]
end end
end end
end end

View file

@ -0,0 +1,66 @@
# frozen_string_literal: true
# Política de acceso a artículos
class IndexedPostPolicy
attr_reader :indexed_post, :usuarie, :site
def initialize(usuarie, indexed_post)
@usuarie = usuarie
@indexed_post = indexed_post
@site = indexed_post.site
end
def index?
true
end
# Les invitades solo pueden ver sus propios posts
def show?
site.usuarie?(usuarie) || site.indexed_posts.by_usuarie(usuarie.id).find_by_post_id(indexed_post.post_id).present?
end
def preview?
show?
end
def new?
create?
end
def create?
true
end
def edit?
update?
end
# Les invitades solo pueden modificar sus propios artículos
def update?
show?
end
# Solo las usuarias pueden eliminar artículos. Les invitades pueden
# borrar sus propios artículos
def destroy?
update?
end
# Las usuarias pueden ver todos los posts
#
# Les invitades solo pueden ver sus propios posts
class Scope
attr_reader :usuarie, :scope
def initialize(usuarie, scope)
@usuarie = usuarie
@scope = scope
end
def resolve
return scope if scope&.first&.site&.usuarie? usuarie
scope.by_usuarie(usuarie.id)
end
end
end

View file

@ -171,6 +171,7 @@ en:
usuarie: User usuarie: User
licencia: License licencia: License
design: Design design: Design
indexed_post: Indexed post
attributes: attributes:
usuarie: usuarie:
email: 'E-mail address' email: 'E-mail address'
@ -733,3 +734,5 @@ en:
build_stats: build_stats:
index: index:
title: "Publications" title: "Publications"
indexed_posts:
deleted: "Deleted indexed post %{path} from %{site} (records: %{records})"

View file

@ -171,6 +171,7 @@ es:
usuarie: Usuarie usuarie: Usuarie
licencia: Licencia licencia: Licencia
design: Diseño design: Diseño
indexed_post: Artículo indexado
attributes: attributes:
usuarie: usuarie:
email: 'Correo electrónico' email: 'Correo electrónico'
@ -741,3 +742,5 @@ es:
build_stats: build_stats:
index: index:
title: "Publicaciones" title: "Publicaciones"
indexed_posts:
deleted: "Eliminado artículo %{path} de %{site} (filas: %{records})"

View file

@ -0,0 +1,18 @@
# frozen_string_literal: true
# Almacenar el último commit indexado
class AddLastIndexedCommitToSites < ActiveRecord::Migration[6.1]
def up
add_column :sites, :last_indexed_commit, :string, null: true
Site.find_each do |site|
site.update_columns(last_indexed_commit: site.repository.head_commit.oid)
rescue Rugged::Error, Rugged::OSError => e
puts "Falló #{site.name}, ignorando: #{e.message}"
end
end
def down
remove_column :sites, :last_indexed_commit
end
end