From c6c638fb60edf3d8f7a6eddbc7dab819b01e1d15 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 29 Aug 2023 17:43:19 -0300 Subject: [PATCH 01/23] feat: almacenar la llave privada --- app/models/site.rb | 1 + app/models/site/social_distributed_press.rb | 12 ++++++++++++ ...204127_add_private_key_pem_ciphertext_to_sites.rb | 9 +++++++++ 3 files changed, 22 insertions(+) create mode 100644 app/models/site/social_distributed_press.rb create mode 100644 db/migrate/20230829204127_add_private_key_pem_ciphertext_to_sites.rb diff --git a/app/models/site.rb b/app/models/site.rb index 24644b9c..9ec21561 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -10,6 +10,7 @@ class Site < ApplicationRecord include Site::DeployDependencies include Site::BuildStats include Site::LayoutOrdering + include Site::SocialDistributedPress include Tienda # Cifrar la llave privada que cifra y decifra campos ocultos. Sutty diff --git a/app/models/site/social_distributed_press.rb b/app/models/site/social_distributed_press.rb new file mode 100644 index 00000000..9d283103 --- /dev/null +++ b/app/models/site/social_distributed_press.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class Site + # Agrega soporte para Social Distributed Press en los sitios + module SocialDistributedPress + extend ActiveSupport::Concern + + included do + encrypts :private_key_pem + end + end +end diff --git a/db/migrate/20230829204127_add_private_key_pem_ciphertext_to_sites.rb b/db/migrate/20230829204127_add_private_key_pem_ciphertext_to_sites.rb new file mode 100644 index 00000000..9f26f21a --- /dev/null +++ b/db/migrate/20230829204127_add_private_key_pem_ciphertext_to_sites.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +# Almacena las llaves privadas de cada sitio +class AddPrivateKeyPemCiphertextToSites < ActiveRecord::Migration[6.1] + # Agrega la columna cifrada + def change + add_column :sites, :private_key_pem_ciphertext, :text + end +end From 4de3352950f700bd303d2f5e472f5045a06c1810 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 29 Aug 2023 17:49:25 -0300 Subject: [PATCH 02/23] feat: generar la llave privada #14169 --- app/models/site/social_distributed_press.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/models/site/social_distributed_press.rb b/app/models/site/social_distributed_press.rb index 9d283103..5d469f03 100644 --- a/app/models/site/social_distributed_press.rb +++ b/app/models/site/social_distributed_press.rb @@ -7,6 +7,17 @@ class Site included do encrypts :private_key_pem + + before_save :generate_private_key_pem!, unless: :private_key_pem? + + private + + # Genera la llave privada y la almacena + # + # @return [nil] + def generate_private_key_pem! + self.private_key_pem ||= DistributedPress::V1::Social::Client.new(public_key_url: nil, key_size: 2048).private_key.export + end end end end From 8b0b0199f60ad67b733c781fbc3425d5f6546fba Mon Sep 17 00:00:00 2001 From: f Date: Tue, 29 Aug 2023 18:26:03 -0300 Subject: [PATCH 03/23] feat: correr un comando obteniendo la llave dentro de un archivo temporal --- app/models/deploy.rb | 15 +++++++++++++++ app/models/deploy_local.rb | 6 +++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index a92708c0..77e5b8d8 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -109,6 +109,21 @@ class Deploy < ApplicationRecord private + # Escribe el contenido en un archivo temporal y ejecuta el bloque + # provisto con el archivo como parámetro + # + # @param :content [String] + def with_tempfile(content, &block) + Tempfile.create(SecureRandom.hex) do |file| + file.write content.to_s + file.rewind + file.close + + # @yieldparam :file [File] + yield file + end + end + # @param [String] # @return [String] def readable_cmd(cmd) diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 75ea8b1c..e66bb003 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -141,8 +141,12 @@ class DeployLocal < Deploy run %(bundle install --deployment --no-cache --path="#{gems_dir}" --clean --without test development), output: output end + # TODO: Esto significa que todos los sitios van a tener activity pub + # activado def jekyll_build(output: false) - run %(bundle exec jekyll build --trace --profile --destination "#{escaped_destination}"), output: output + with_tempfile(site.private_key_pem) do |file| + run %(bundle exec jekyll build --trace --profile --key #{file.path} --destination "#{escaped_destination}"), output: output + end end # no debería haber espacios ni caracteres especiales, pero por si From 9ac404ae06286e69e8981c5322c2a9256ff04f99 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 30 Aug 2023 10:47:08 -0300 Subject: [PATCH 04/23] feat: habilitar/deshabilitar activity pub --- .../_deploy_social_distributed_press.haml | 21 +++++++++++++++++++ config/locales/en.yml | 12 +++++++++++ config/locales/es.yml | 12 +++++++++++ 3 files changed, 45 insertions(+) create mode 100644 app/views/deploys/_deploy_social_distributed_press.haml diff --git a/app/views/deploys/_deploy_social_distributed_press.haml b/app/views/deploys/_deploy_social_distributed_press.haml new file mode 100644 index 00000000..5c73b262 --- /dev/null +++ b/app/views/deploys/_deploy_social_distributed_press.haml @@ -0,0 +1,21 @@ +-# Publicar a la web distribuida + +.row + .col + = deploy.hidden_field :id + = deploy.hidden_field :type + .custom-control.custom-switch + -# + El checkbox invierte la lógica de destrucción porque queremos + crear el deploy si está activado y destruirlo si está + desactivado. + = deploy.check_box :_destroy, + { checked: deploy.object.persisted?, class: 'custom-control-input' }, + '0', '1' + = deploy.label :_destroy, class: 'custom-control-label' do + %h3= t('.title') + = sanitize_markdown t('.help'), + tags: %w[p strong em a] + + +%hr/ diff --git a/config/locales/en.yml b/config/locales/en.yml index 5f97a8b9..0dad2e68 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -123,6 +123,10 @@ en: title: Distributed Web success: Success! error: Error + deploy_social_distributed_press: + title: Fediverse + success: Success! + error: Error deploy_reindex: title: Reindex success: Success! @@ -307,6 +311,14 @@ en: indefinitely. [Learn more](https://sutty.nl/learn-more-about-publish-to-dweb-functionality/) + deploy_social_distributed_press: + title: 'Publish on the Fediverse' + help: | + By using the ActivityPub protocol, people on the Fediverse + ([Mastodon](https://joinmastodon.org/servers), + [Pixelfed](https://pixelfed.social/site/about), and + [others](https://fediverse.party/)) can follow your site, + receive news and interact with them. stats: index: title: Statistics diff --git a/config/locales/es.yml b/config/locales/es.yml index 9e0b8945..d899b99c 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -123,6 +123,10 @@ es: title: Web distribuida success: ¡Éxito! error: Hubo un error + deploy_social_distributed_press: + title: Fediverso + success: ¡Éxito! + error: Hubo un error deploy_reindex: title: Reindexación success: ¡Éxito! @@ -312,6 +316,14 @@ es: copias de tu contenido indefinidamente. [Saber más](https://sutty.nl/saber-mas-sobre-publicar-a-la-web-distribuida/) + deploy_social_distributed_press: + title: 'Publicar al Fediverso' + help: | + Utilizando el protocolo ActivityPub, otras personas en el + Fediverso ([Mastodon](https://joinmastodon.org/servers), + [Pixelfed](https://pixelfed.social/site/about) y + [otros](https://fediverse.party/)) pueden seguir a tu sitio, + recibir novedades e interactuar con ellas. stats: index: title: Estadísticas From f019805314735c813847043fadf051961ad5837a Mon Sep 17 00:00:00 2001 From: f Date: Wed, 30 Aug 2023 10:47:27 -0300 Subject: [PATCH 05/23] =?UTF-8?q?fix:=20generar=20todos=20los=20deploys=20?= =?UTF-8?q?autom=C3=A1ticamente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/site.rb | 4 ---- app/services/site_service.rb | 5 ++--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/app/models/site.rb b/app/models/site.rb index 9ec21561..961831d5 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -19,10 +19,6 @@ class Site < ApplicationRecord # protege de acceso al panel de Sutty! encrypts :private_key - # TODO: Hacer que los diferentes tipos de deploy se auto registren - # @see app/services/site_service.rb - DEPLOYS = %i[local private www zip hidden_service distributed_press].freeze - validates :name, uniqueness: true, hostname: { allow_root_label: true } diff --git a/app/services/site_service.rb b/app/services/site_service.rb index b1df3d10..5bd89888 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -54,9 +54,8 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # Genera los Deploy necesarios para el sitio a menos que ya los tenga. def build_deploys - Site::DEPLOYS.map { |deploy| "Deploy#{deploy.to_s.camelcase}" } - .each do |deploy| - next if site.deploys.find_by type: deploy + Deploy.subclasses.each do |deploy| + next if site.deploys.find_by type: deploy.name site.deploys.build type: deploy end From 4ade0944def7484ddcbee854c63ed184067b0f1c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 30 Aug 2023 10:58:52 -0300 Subject: [PATCH 06/23] =?UTF-8?q?feat:=20los=20deploys=20pueden=20pasar=20?= =?UTF-8?q?opciones=20de=20compilaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy.rb | 5 ++++ app/models/deploy_local.rb | 16 ++++++++++--- app/models/deploy_social_distributed_press.rb | 24 +++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 app/models/deploy_social_distributed_press.rb diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 77e5b8d8..abf5591f 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -100,6 +100,11 @@ class Deploy < ApplicationRecord @local_env ||= {} end + # Devuelve opciones para jekyll build + # + # @return [String,nil] + def flags_for_build(**args); end + # Trae todas las dependencias # # @return [Array] diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index e66bb003..9228581f 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -141,11 +141,11 @@ class DeployLocal < Deploy run %(bundle install --deployment --no-cache --path="#{gems_dir}" --clean --without test development), output: output end - # TODO: Esto significa que todos los sitios van a tener activity pub - # activado def jekyll_build(output: false) with_tempfile(site.private_key_pem) do |file| - run %(bundle exec jekyll build --trace --profile --key #{file.path} --destination "#{escaped_destination}"), output: output + flags = extra_flags(private_key: file) + + run %(bundle exec jekyll build --trace --profile #{flags} --destination "#{escaped_destination}"), output: output end end @@ -173,4 +173,14 @@ class DeployLocal < Deploy end end end + + # Genera opciones extra desde los otros deploys + # + # @param :args [Hash] + # @return [String] + def extra_flags(**args) + non_local_deploys.map do |deploy| + deploy.flags_for_build(**args) + end.compact.join(' ') + end end diff --git a/app/models/deploy_social_distributed_press.rb b/app/models/deploy_social_distributed_press.rb new file mode 100644 index 00000000..47464ea9 --- /dev/null +++ b/app/models/deploy_social_distributed_press.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'distributed_press/v1/social/client' + +# Publicar novedades al Fediverso +class DeploySocialDistributedPress < Deploy + # Solo luego de publicar remotamente + DEPENDENCIES = %i[deploy_distributed_press deploy_rsync deploy_full_rsync] + + # Envía las notificaciones + def deploy(output: false) + with_tempfile(site.private_key_pem) do |file| + run %(bundle exec jekyll notify --trace --key #{file.path} --destination "#{escaped_destination}"), output: output + end + end + + # Genera la opción de llave privada para jekyll build + # + # @params :args [Hash] + # @return [String] + def flags_for_build(**args) + "--key #{Shellwords.escape args[:private_key].path}" + end +end From 26f57a8467241e825b87fefcccdf76c4e9c3561d Mon Sep 17 00:00:00 2001 From: f Date: Wed, 30 Aug 2023 11:09:08 -0300 Subject: [PATCH 07/23] =?UTF-8?q?feat:=20m=C3=A9todos=20de=20deploy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_social_distributed_press.rb | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/app/models/deploy_social_distributed_press.rb b/app/models/deploy_social_distributed_press.rb index 47464ea9..db555ab7 100644 --- a/app/models/deploy_social_distributed_press.rb +++ b/app/models/deploy_social_distributed_press.rb @@ -10,10 +10,41 @@ class DeploySocialDistributedPress < Deploy # Envía las notificaciones def deploy(output: false) with_tempfile(site.private_key_pem) do |file| - run %(bundle exec jekyll notify --trace --key #{file.path} --destination "#{escaped_destination}"), output: output + key = Shellwords.escape file.path + dest = Shellwords.escape destination + + run %(bundle exec jekyll notify --trace --key #{key} --destination "#{dest}"), output: output end end + # Igual que DeployLocal + # + # @return [String] + def destination + File.join(Rails.root, '_deploy', site.hostname) + end + + # Solo uno + # + # @return [Integer] + def limit + 1 + end + + # Espacio ocupado, pero no podemos calcularlo + # + # @return [Integer] + def size + 0 + end + + # El perfil de actor + # + # @return [String,nil] + def url + site.data.dig('activity_pub', 'actor') + end + # Genera la opción de llave privada para jekyll build # # @params :args [Hash] From 2a4073178a7b431e6f1ea1b7798fcfc1d7b8a10b Mon Sep 17 00:00:00 2001 From: f Date: Wed, 30 Aug 2023 11:13:49 -0300 Subject: [PATCH 08/23] fix: actualizar la gema --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index dd880219..5ccee727 100644 --- a/Gemfile +++ b/Gemfile @@ -39,7 +39,7 @@ gem 'commonmarker' gem 'devise' gem 'devise-i18n' gem 'devise_invitable' -gem 'distributed-press-api-client', '~> 0.2.3' +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 'exception_notification' diff --git a/Gemfile.lock b/Gemfile.lock index f71053d7..6c3dae96 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -153,7 +153,7 @@ GEM devise_invitable (2.0.8) actionmailer (>= 5.0) devise (>= 4.6) - distributed-press-api-client (0.2.4) + distributed-press-api-client (0.3.0rc0) addressable (~> 2.3, >= 2.3.0) climate_control dry-schema @@ -595,7 +595,7 @@ DEPENDENCIES devise devise-i18n devise_invitable - distributed-press-api-client (~> 0.2.3) + distributed-press-api-client (~> 0.3.0rc0) dotenv-rails down ed25519 From c9866a0eecfca61d5c3136ffa412045687728dc3 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 30 Aug 2023 15:33:48 -0300 Subject: [PATCH 09/23] =?UTF-8?q?fix:=20mover=20m=C3=A9todos=20a=20deploy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy.rb | 36 ++++++++++++++++++++++++++++++++++++ app/models/deploy_local.rb | 36 ------------------------------------ 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index abf5591f..c01a378f 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -55,6 +55,28 @@ class Deploy < ApplicationRecord @gems_dir ||= Rails.root.join('_storage', 'gems', site.name) end + # Un entorno que solo tiene lo que necesitamos + # + # @return [Hash] + def env + # XXX: This doesn't support Windows paths :B + paths = [File.dirname(`which bundle`), '/usr/local/bin', '/usr/bin', '/bin'] + + # Las variables de entorno extra no pueden superponerse al local. + extra_env.merge({ + 'HOME' => home_dir, + 'PATH' => paths.join(':'), + 'SPREE_API_KEY' => site.tienda_api_key, + 'SPREE_URL' => site.tienda_url, + 'AIRBRAKE_PROJECT_ID' => site.id.to_s, + 'AIRBRAKE_PROJECT_KEY' => site.airbrake_api_key, + 'JEKYLL_ENV' => Rails.env, + 'LANG' => ENV['LANG'], + 'YARN_CACHE_FOLDER' => yarn_cache_dir, + 'GEMS_SOURCE' => ENV['GEMS_SOURCE'] + }) + end + # Corre un comando, lo registra en la base de datos y devuelve el # estado. # @@ -142,4 +164,18 @@ class Deploy < ApplicationRecord def non_local_deploys @non_local_deploys ||= site.deploys.where.not(type: 'DeployLocal') end + + # Consigue todas las variables de entorno configuradas por otros + # deploys. + # + # @deprecated Solo tenía sentido para Distributed Press v0 + # @return [Hash] + def extra_env + @extra_env ||= + non_local_deploys.reduce({}) do |extra_env, deploy| + extra_env.tap do |e| + e.merge! deploy.local_env + end + end + end end diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 9228581f..edf85bf5 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -68,28 +68,6 @@ class DeployLocal < Deploy FileUtils.mkdir_p destination end - # Un entorno que solo tiene lo que necesitamos - # - # @return [Hash] - def env - # XXX: This doesn't support Windows paths :B - paths = [File.dirname(`which bundle`), '/usr/local/bin', '/usr/bin', '/bin'] - - # Las variables de entorno extra no pueden superponerse al local. - extra_env.merge({ - 'HOME' => home_dir, - 'PATH' => paths.join(':'), - 'SPREE_API_KEY' => site.tienda_api_key, - 'SPREE_URL' => site.tienda_url, - 'AIRBRAKE_PROJECT_ID' => site.id.to_s, - 'AIRBRAKE_PROJECT_KEY' => site.airbrake_api_key, - 'JEKYLL_ENV' => Rails.env, - 'LANG' => ENV['LANG'], - 'YARN_CACHE_FOLDER' => yarn_cache_dir, - 'GEMS_SOURCE' => ENV['GEMS_SOURCE'] - }) - end - def yarn_cache_dir Rails.root.join('_yarn_cache').to_s end @@ -160,20 +138,6 @@ class DeployLocal < Deploy FileUtils.rm_rf destination end - # Consigue todas las variables de entorno configuradas por otros - # deploys. - # - # @deprecated Solo tenía sentido para Distributed Press v0 - # @return [Hash] - def extra_env - @extra_env ||= - non_local_deploys.reduce({}) do |extra_env, deploy| - extra_env.tap do |e| - e.merge! deploy.local_env - end - end - end - # Genera opciones extra desde los otros deploys # # @param :args [Hash] From f337e4967b1ac422062b696a8fc705f9f49d9e34 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 30 Aug 2023 16:40:33 -0300 Subject: [PATCH 10/23] fix: recolectar variables de entorno --- app/models/deploy.rb | 17 ++--------------- app/models/deploy_local.rb | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index c01a378f..55ec46f6 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -66,14 +66,8 @@ class Deploy < ApplicationRecord extra_env.merge({ 'HOME' => home_dir, 'PATH' => paths.join(':'), - 'SPREE_API_KEY' => site.tienda_api_key, - 'SPREE_URL' => site.tienda_url, - 'AIRBRAKE_PROJECT_ID' => site.id.to_s, - 'AIRBRAKE_PROJECT_KEY' => site.airbrake_api_key, 'JEKYLL_ENV' => Rails.env, 'LANG' => ENV['LANG'], - 'YARN_CACHE_FOLDER' => yarn_cache_dir, - 'GEMS_SOURCE' => ENV['GEMS_SOURCE'] }) end @@ -161,21 +155,14 @@ class Deploy < ApplicationRecord @deploy_local ||= site.deploys.find_by(type: 'DeployLocal') end - def non_local_deploys - @non_local_deploys ||= site.deploys.where.not(type: 'DeployLocal') - end - # Consigue todas las variables de entorno configuradas por otros # deploys. # - # @deprecated Solo tenía sentido para Distributed Press v0 # @return [Hash] def extra_env @extra_env ||= - non_local_deploys.reduce({}) do |extra_env, deploy| - extra_env.tap do |e| - e.merge! deploy.local_env - end + site.deployment_list.reduce({}) do |extra, deploy| + extra.merge deploy.local_env end end end diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index edf85bf5..0bb3958f 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -62,6 +62,20 @@ class DeployLocal < Deploy FileUtils.rm_rf(File.join(site.path, '.jekyll-cache')) end + # Opciones necesarias para la compilación del sitio + # + # @return [Hash] + def local_env + @local_env ||= { + 'SPREE_API_KEY' => site.tienda_api_key, + 'SPREE_URL' => site.tienda_url, + 'AIRBRAKE_PROJECT_ID' => site.id.to_s, + 'AIRBRAKE_PROJECT_KEY' => site.airbrake_api_key, + 'YARN_CACHE_FOLDER' => yarn_cache_dir, + 'GEMS_SOURCE' => ENV['GEMS_SOURCE'] + } + end + private def mkdir @@ -143,7 +157,7 @@ class DeployLocal < Deploy # @param :args [Hash] # @return [String] def extra_flags(**args) - non_local_deploys.map do |deploy| + site.deployment_list.map do |deploy| deploy.flags_for_build(**args) end.compact.join(' ') end From cd7c21792063c815adb4886540d6a64fe9c0ecf3 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 30 Aug 2023 17:17:04 -0300 Subject: [PATCH 11/23] fix: poder asignar valor por defecto a los campos boolean --- app/models/metadata_boolean.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/metadata_boolean.rb b/app/models/metadata_boolean.rb index 90c002a7..9932c6fd 100644 --- a/app/models/metadata_boolean.rb +++ b/app/models/metadata_boolean.rb @@ -4,8 +4,12 @@ # # Esto es increíblemente difícil de lograr que salga bien! class MetadataBoolean < MetadataTemplate + # El valor por defecto es una versión booleana de lo que diga (o no + # diga) el esquema + # + # @return [Boolean] def default_value - false + !!super end # Los checkboxes son especiales porque la especificación de HTML From d8e21c97e2efcc6ffbfdc294119545b58b538cd0 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 31 Aug 2023 14:41:34 -0300 Subject: [PATCH 12/23] fix: solo vincular urls que tienen protocolo --- app/controllers/build_stats_controller.rb | 7 ++++++- app/jobs/deploy_job.rb | 6 +++++- app/mailers/deploy_mailer.rb | 2 +- app/views/build_stats/index.haml | 2 +- app/views/deploy_mailer/deployed.html.haml | 2 +- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/controllers/build_stats_controller.rb b/app/controllers/build_stats_controller.rb index 31a4c5d6..6961cf45 100644 --- a/app/controllers/build_stats_controller.rb +++ b/app/controllers/build_stats_controller.rb @@ -22,7 +22,12 @@ class BuildStatsController < ApplicationController @table = site.deployment_list.map do |deploy| type = deploy.class.name.underscore - urls = deploy.respond_to?(:urls) ? deploy.urls : [deploy.url].compact + urls = (deploy.respond_to?(:urls) ? deploy.urls : [deploy.url].compact).map do |url| + URI.parse(url) + rescue URI::Error + nil + end.compact + urls = [nil] if urls.empty? build_stat = deploy.build_stats.where(status: true).last seconds = build_stat&.seconds || 0 diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index a5cda360..6f486f29 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -51,7 +51,11 @@ class DeployJob < ApplicationJob status = d.deploy(output: @output) seconds = d.build_stats.last.try(:seconds) || 0 size = d.size - urls = d.respond_to?(:urls) ? d.urls : [d.url].compact + urls = (d.respond_to?(:urls) ? d.urls : [d.url].compact).map do |url| + URI.parse url + rescue URI::Error + nil + end.compact rescue StandardError => e status = false seconds ||= 0 diff --git a/app/mailers/deploy_mailer.rb b/app/mailers/deploy_mailer.rb index b7b464cb..37748b42 100644 --- a/app/mailers/deploy_mailer.rb +++ b/app/mailers/deploy_mailer.rb @@ -52,7 +52,7 @@ class DeployMailer < ApplicationMailer t << (row.map do |k, v| case k when :seconds then v[:human] - when :urls then url + when :urls then url.to_s else v end end) diff --git a/app/views/build_stats/index.haml b/app/views/build_stats/index.haml index 27c063f9..0b0e7755 100644 --- a/app/views/build_stats/index.haml +++ b/app/views/build_stats/index.haml @@ -14,7 +14,7 @@ - row[:urls].each do |url| %tr %th{ scope: 'row' }= row[:title] - %td= link_to_if url.present?, url, url, class: 'word-break-all' + %td= link_to_if (url.present? && uri.scheme.present?), url.to_s, url.to_s, class: 'word-break-all' %td %time{ datetime: row[:seconds][:machine] }= row[:seconds][:human] %td= row[:size] diff --git a/app/views/deploy_mailer/deployed.html.haml b/app/views/deploy_mailer/deployed.html.haml index f5afe5de..b3463db6 100644 --- a/app/views/deploy_mailer/deployed.html.haml +++ b/app/views/deploy_mailer/deployed.html.haml @@ -13,7 +13,7 @@ %tr %td= row[:title] %td= row[:status] - %td= link_to_if url.present?, url, url + %td= link_to_if (url.present? && uri.scheme.present?), url.to_s, url.to_s %td %time{ datetime: row[:seconds][:machine] }= row[:seconds][:human] %td= row[:size] From f076838be5137821ca2a2ca18f9e89c53047ea5f Mon Sep 17 00:00:00 2001 From: f Date: Thu, 31 Aug 2023 14:47:44 -0300 Subject: [PATCH 13/23] fixup! fix: solo vincular urls que tienen protocolo --- app/jobs/deploy_job.rb | 2 +- app/views/deploy_mailer/deployed.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 6f486f29..00ae7585 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -70,7 +70,7 @@ class DeployJob < ApplicationJob status: status, seconds: seconds, size: size, - urls: urls + urls: urls.map(&:to_s) } end diff --git a/app/views/deploy_mailer/deployed.html.haml b/app/views/deploy_mailer/deployed.html.haml index b3463db6..762bf4db 100644 --- a/app/views/deploy_mailer/deployed.html.haml +++ b/app/views/deploy_mailer/deployed.html.haml @@ -13,7 +13,7 @@ %tr %td= row[:title] %td= row[:status] - %td= link_to_if (url.present? && uri.scheme.present?), url.to_s, url.to_s + %td= link_to_if (url.present? && url.scheme.present?), url.to_s, url.to_s %td %time{ datetime: row[:seconds][:machine] }= row[:seconds][:human] %td= row[:size] From a6195fbcccf80e47245429228f6631b9139aced4 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 31 Aug 2023 14:52:49 -0300 Subject: [PATCH 14/23] fix: simplificar --- app/controllers/build_stats_controller.rb | 2 +- app/jobs/deploy_job.rb | 2 +- app/models/deploy.rb | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/controllers/build_stats_controller.rb b/app/controllers/build_stats_controller.rb index 6961cf45..339f17f0 100644 --- a/app/controllers/build_stats_controller.rb +++ b/app/controllers/build_stats_controller.rb @@ -22,7 +22,7 @@ class BuildStatsController < ApplicationController @table = site.deployment_list.map do |deploy| type = deploy.class.name.underscore - urls = (deploy.respond_to?(:urls) ? deploy.urls : [deploy.url].compact).map do |url| + urls = deploy.urls.map do |url| URI.parse(url) rescue URI::Error nil diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 00ae7585..0870b827 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -51,7 +51,7 @@ class DeployJob < ApplicationJob status = d.deploy(output: @output) seconds = d.build_stats.last.try(:seconds) || 0 size = d.size - urls = (d.respond_to?(:urls) ? d.urls : [d.url].compact).map do |url| + urls = d.urls.map do |url| URI.parse url rescue URI::Error nil diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 55ec46f6..811047f1 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -23,6 +23,11 @@ class Deploy < ApplicationRecord raise NotImplementedError end + # @return [Array] + def urls + [url].compact + end + def limit raise NotImplementedError end From 927f92d985e7b1af86424cb332e48f900d988a83 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 31 Aug 2023 14:56:00 -0300 Subject: [PATCH 15/23] fix: typo --- app/views/build_stats/index.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/build_stats/index.haml b/app/views/build_stats/index.haml index 0b0e7755..de04d84d 100644 --- a/app/views/build_stats/index.haml +++ b/app/views/build_stats/index.haml @@ -14,7 +14,7 @@ - row[:urls].each do |url| %tr %th{ scope: 'row' }= row[:title] - %td= link_to_if (url.present? && uri.scheme.present?), url.to_s, url.to_s, class: 'word-break-all' + %td= link_to_if (url.present? && url.scheme.present?), url.to_s, url.to_s, class: 'word-break-all' %td %time{ datetime: row[:seconds][:machine] }= row[:seconds][:human] %td= row[:size] From 3dedd84db78512e017706cd90610318c677879d4 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 31 Aug 2023 14:58:16 -0300 Subject: [PATCH 16/23] fix: enviar urls parseadas --- app/jobs/deploy_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 0870b827..291991c7 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -70,7 +70,7 @@ class DeployJob < ApplicationJob status: status, seconds: seconds, size: size, - urls: urls.map(&:to_s) + urls: urls } end From 6aa0f7d6cf6a54f4f0cee94d27d3c8206a849c86 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 1 Sep 2023 20:11:46 -0300 Subject: [PATCH 17/23] =?UTF-8?q?feat:=20guardar=20la=20fecha=20de=20creac?= =?UTF-8?q?i=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/post.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/post.rb b/app/models/post.rb index 5cc1c5ea..6265a313 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -267,6 +267,7 @@ class Post # Y que no se procese liquid yaml['liquid'] = false yaml['usuaries'] = usuaries.map(&:id).uniq + yaml['created_at'] ||= Time.now yaml['last_modified_at'] = modified_at "#{yaml.to_yaml}---\n\n#{body}" From 10d958e50aed0f92dfae7140bde7650d371b1d22 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Sep 2023 12:44:57 -0300 Subject: [PATCH 18/23] =?UTF-8?q?fix:=20compartir=20la=20misma=20fecha=20d?= =?UTF-8?q?e=20creaci=C3=B3n=20y=20de=20actualizaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/post.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/post.rb b/app/models/post.rb index 6265a313..f31c33b6 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -267,7 +267,7 @@ class Post # Y que no se procese liquid yaml['liquid'] = false yaml['usuaries'] = usuaries.map(&:id).uniq - yaml['created_at'] ||= Time.now + yaml['created_at'] ||= modified_at yaml['last_modified_at'] = modified_at "#{yaml.to_yaml}---\n\n#{body}" From 8ae5dd597501d81d4e266bedbbf62edbe7778761 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 12 Sep 2023 14:49:17 -0300 Subject: [PATCH 19/23] fix: no compartir la misma instancia sutty/jekyll/jekyll-activitypub#42 --- app/models/post.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/post.rb b/app/models/post.rb index f31c33b6..36a0b02e 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -267,7 +267,7 @@ class Post # Y que no se procese liquid yaml['liquid'] = false yaml['usuaries'] = usuaries.map(&:id).uniq - yaml['created_at'] ||= modified_at + yaml['created_at'] ||= modified_at.dup yaml['last_modified_at'] = modified_at "#{yaml.to_yaml}---\n\n#{body}" From 6b1eccade35aec862160950549123f59be7d1fe7 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Sep 2023 17:52:21 -0300 Subject: [PATCH 20/23] =?UTF-8?q?feat:=20fecha=20de=20creaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/metadata_created_at.rb | 14 ++++++++++++++ app/models/post.rb | 8 ++++++-- app/views/posts/attribute_ro/_created_at.haml | 4 ++++ app/views/posts/attributes/_created_at.haml | 1 + config/locales/en.yml | 2 ++ config/locales/es.yml | 2 ++ 6 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 app/models/metadata_created_at.rb create mode 100644 app/views/posts/attribute_ro/_created_at.haml create mode 100644 app/views/posts/attributes/_created_at.haml diff --git a/app/models/metadata_created_at.rb b/app/models/metadata_created_at.rb new file mode 100644 index 00000000..2a7c07ed --- /dev/null +++ b/app/models/metadata_created_at.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Fecha y hora de creación +class MetadataCreatedAt < MetadataTemplate + # Por defecto la hora actual + def default_value + Time.now + end + + # Nunca cambia + def value=(new_value) + value + end +end diff --git a/app/models/post.rb b/app/models/post.rb index 36a0b02e..8bd5dab3 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -12,7 +12,7 @@ class Post DEFAULT_ATTRIBUTES = %i[site document layout].freeze # Otros atributos que no vienen en los metadatos PRIVATE_ATTRIBUTES = %i[path slug attributes errors].freeze - PUBLIC_ATTRIBUTES = %i[lang date uuid].freeze + PUBLIC_ATTRIBUTES = %i[lang date uuid created_at].freeze ATTR_SUFFIXES = %w[? =].freeze attr_reader :attributes, :errors, :layout, :site, :document @@ -217,6 +217,11 @@ class Post post: self, required: true) end + # La fecha de creación inmodificable del post + def created_at + @metadata[:created_at] ||= MetadataCreatedAt.new(document: document, site: site, layout: layout, name: :created_at, type: :timestamp, post: self, required: true) + end + # Detecta si es un atributo válido o no, a partir de la tabla de la # plantilla def attribute?(mid) @@ -267,7 +272,6 @@ class Post # Y que no se procese liquid yaml['liquid'] = false yaml['usuaries'] = usuaries.map(&:id).uniq - yaml['created_at'] ||= modified_at.dup yaml['last_modified_at'] = modified_at "#{yaml.to_yaml}---\n\n#{body}" diff --git a/app/views/posts/attribute_ro/_created_at.haml b/app/views/posts/attribute_ro/_created_at.haml new file mode 100644 index 00000000..04f6d716 --- /dev/null +++ b/app/views/posts/attribute_ro/_created_at.haml @@ -0,0 +1,4 @@ +%tr{ id: attribute } + %th= post_label_t(attribute, post: post) + %td{ dir: dir, lang: locale } + %time{ datetime: metadata.value.xmlschema }= l metadata.value diff --git a/app/views/posts/attributes/_created_at.haml b/app/views/posts/attributes/_created_at.haml new file mode 100644 index 00000000..0aab9802 --- /dev/null +++ b/app/views/posts/attributes/_created_at.haml @@ -0,0 +1 @@ +-# nada diff --git a/config/locales/en.yml b/config/locales/en.yml index 0dad2e68..5c00701c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -524,6 +524,8 @@ en: feedback: 'This field cannot be empty!' uuid: label: 'Unique identifier' + created_at: + label: 'Created at' geo: uri: 'Open in app' osm: 'Open in web map' diff --git a/config/locales/es.yml b/config/locales/es.yml index d899b99c..0ff7e1c8 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -532,6 +532,8 @@ es: feedback: '¡Este campo no puede estar vacío!' uuid: label: 'Identificador único' + created_at: + label: 'Fecha de creación' geo: uri: 'Abrir en aplicación' osm: 'Abrir en mapa web' From 35e8a087163683c77de16fd398006d8b71c5bec8 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Sep 2023 17:53:51 -0300 Subject: [PATCH 21/23] =?UTF-8?q?fixup!=20feat:=20fecha=20de=20creaci?= =?UTF-8?q?=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/post.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/post.rb b/app/models/post.rb index 8bd5dab3..73785cad 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -219,7 +219,7 @@ class Post # La fecha de creación inmodificable del post def created_at - @metadata[:created_at] ||= MetadataCreatedAt.new(document: document, site: site, layout: layout, name: :created_at, type: :timestamp, post: self, required: true) + @metadata[:created_at] ||= MetadataCreatedAt.new(document: document, site: site, layout: layout, name: :created_at, type: :created_at, post: self, required: true) end # Detecta si es un atributo válido o no, a partir de la tabla de la From d27717ed3b7a21413361e86030ef59f4c3b84b3c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Sep 2023 17:59:50 -0300 Subject: [PATCH 22/23] fix: agregar created_at al front matter --- app/models/post.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/post.rb b/app/models/post.rb index 73785cad..fab9ab06 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -272,6 +272,7 @@ class Post # Y que no se procese liquid yaml['liquid'] = false yaml['usuaries'] = usuaries.map(&:id).uniq + yaml['created_at'] = created_at.value yaml['last_modified_at'] = modified_at "#{yaml.to_yaml}---\n\n#{body}" From 99c919e5e6cfca0e6affcd138da52a0565b6fd32 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Sep 2023 18:07:25 -0300 Subject: [PATCH 23/23] fix: retrocompatibilidad --- app/models/metadata_created_at.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/models/metadata_created_at.rb b/app/models/metadata_created_at.rb index 2a7c07ed..d31b3a1c 100644 --- a/app/models/metadata_created_at.rb +++ b/app/models/metadata_created_at.rb @@ -2,9 +2,14 @@ # Fecha y hora de creación class MetadataCreatedAt < MetadataTemplate - # Por defecto la hora actual + # Por defecto la hora actual, pero por retrocompatibilidad, queremos + # la fecha de publicación def default_value - Time.now + if post.date.value.to_date < Time.now.to_date + post.date.value + else + Time.now + end end # Nunca cambia