From 8fc705158847a10c5c928c703e3a12d6f5a49c6d Mon Sep 17 00:00:00 2001 From: f Date: Fri, 24 Dec 2021 10:08:09 -0300 Subject: [PATCH 001/453] limpiar gemas al terminar de instalar --- app/models/deploy.rb | 1 + app/models/deploy_local.rb | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 3f034ad5..d08aa239 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -39,6 +39,7 @@ class Deploy < ApplicationRecord site.path end + # XXX: Ver DeployLocal#bundle def gems_dir @gems_dir ||= Rails.root.join('_storage', 'gems', site.name) end diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 4fa588f5..a4f60e28 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -92,7 +92,9 @@ class DeployLocal < Deploy def bundle if Rails.env.production? - run %(bundle install --no-cache --path="#{gems_dir}") + # XXX: Desde que ya no compartimos el directorio de gemas, tenemos + # que hacer limpieza después de instalar. + run %(bundle install --no-cache --path="#{gems_dir}" --clean) else run %(bundle install) end From d70ce8efdb8bfe103acf526361199dea22cf83be Mon Sep 17 00:00:00 2001 From: f Date: Fri, 24 Dec 2021 10:19:18 -0300 Subject: [PATCH 002/453] no instalar las gemas de desarrollo --- app/models/deploy_local.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index a4f60e28..6365f602 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -94,7 +94,7 @@ class DeployLocal < Deploy if Rails.env.production? # XXX: Desde que ya no compartimos el directorio de gemas, tenemos # que hacer limpieza después de instalar. - run %(bundle install --no-cache --path="#{gems_dir}" --clean) + run %(bundle install --no-cache --path="#{gems_dir}" --clean --without test development) else run %(bundle install) end From e9c338a8b94271284f04888fd5925521085ffd6b Mon Sep 17 00:00:00 2001 From: f Date: Mon, 27 Dec 2021 11:25:24 -0300 Subject: [PATCH 003/453] no setear un permalink por defecto MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit es algo que quisiéramos retomar pero la implementación actual depende de los mecanismos internos de jekyll, que son problemáticos porque espera que se seteen algunos valores antes de poder usarlo. de lo contrario el permalink termina siendo /, haciendo conflicto con la portada del sitio. hasta que lo podamos resolver, lo dejamos vacío. closes #3635 --- app/models/metadata_permalink.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/models/metadata_permalink.rb b/app/models/metadata_permalink.rb index 59b68461..58feb9e5 100644 --- a/app/models/metadata_permalink.rb +++ b/app/models/metadata_permalink.rb @@ -2,12 +2,6 @@ # Este metadato permite generar rutas manuales. class MetadataPermalink < MetadataString - # El valor por defecto una vez creado es la URL que le asigne Jekyll, - # de forma que nunca cambia aunque se cambie el título. - def default_value - document.url.sub(%r{\A/}, '') unless post.new? - end - # Los permalinks nunca pueden ser privados def private? false From a664c2dcd3db20cbb62c42ac4e3154b076772480 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 1 Feb 2022 17:11:00 -0300 Subject: [PATCH 004/453] mapa no geografico --- .../controllers/non_geo_controller.js | 72 +++++++++++++++++++ app/models/metadata_non_geo.rb | 3 + app/views/posts/attribute_ro/_non_geo.haml | 6 ++ app/views/posts/attributes/_non_geo.haml | 24 +++++++ 4 files changed, 105 insertions(+) create mode 100644 app/javascript/controllers/non_geo_controller.js create mode 100644 app/models/metadata_non_geo.rb create mode 100644 app/views/posts/attribute_ro/_non_geo.haml create mode 100644 app/views/posts/attributes/_non_geo.haml diff --git a/app/javascript/controllers/non_geo_controller.js b/app/javascript/controllers/non_geo_controller.js new file mode 100644 index 00000000..072c1b83 --- /dev/null +++ b/app/javascript/controllers/non_geo_controller.js @@ -0,0 +1,72 @@ +import { Controller } from 'stimulus' + +require("leaflet/dist/leaflet.css") +import L from 'leaflet' +delete L.Icon.Default.prototype._getIconUrl + +L.Icon.Default.mergeOptions({ + iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'), + iconUrl: require('leaflet/dist/images/marker-icon.png'), + shadowUrl: require('leaflet/dist/images/marker-shadow.png'), +}) + +export default class extends Controller { + static targets = [ 'lat', 'lng', 'map', 'overlay' ] + + async connect () { + this.marker() + + this.latTarget.addEventListener('change', event => this.marker()) + this.lngTarget.addEventListener('change', event => this.marker()) + window.addEventListener('resize', event => this.map.invalidateSize()) + + const res = await fetch(this.element.dataset.map); + this.overlayTarget.innerHTML = await res.text(); + + this.map.on('click', event => { + this.latTarget.value = event.latlng.lat + this.lngTarget.value = event.latlng.lng + + this.latTarget.dispatchEvent(new Event('change')) + }) + } + + marker () { + if (this._marker) this.map.removeLayer(this._marker) + + this._marker = L.marker(this.coords).addTo(this.map) + + return this._marker + } + + get lat () { + const lat = parseFloat(this.latTarget.value) + + return isNaN(lat) ? 0 : lat + } + + get lng () { + const lng = parseFloat(this.lngTarget.value) + + return isNaN(lng) ? 0 : lng + } + + get coords () { + return [this.lat, this.lng] + } + + get map () { + if (!this._map) { + this._map = L.map(this.mapTarget).setView(this.coords, 13); + + const bounds = [[0,0], [this.mapTarget.clientHeight, this.mapTarget.clientWidth]]; + + L.svgOverlay(this.overlayTarget.querySelector('svg'), bounds).addTo(this._map); + + this._map.fitBounds(bounds); + this._map.setMaxBounds(bounds); + } + + return this._map + } +} diff --git a/app/models/metadata_non_geo.rb b/app/models/metadata_non_geo.rb new file mode 100644 index 00000000..6aec8461 --- /dev/null +++ b/app/models/metadata_non_geo.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +class MetadataNonGeo < MetadataGeo; end diff --git a/app/views/posts/attribute_ro/_non_geo.haml b/app/views/posts/attribute_ro/_non_geo.haml new file mode 100644 index 00000000..75f8d2ef --- /dev/null +++ b/app/views/posts/attribute_ro/_non_geo.haml @@ -0,0 +1,6 @@ +- lat = metadata.value['lat'] +- lng = metadata.value['lng'] +%tr{ id: attribute } + %th= post_label_t(attribute, post: post) + %td + = "#{lat},#{lng}" diff --git a/app/views/posts/attributes/_non_geo.haml b/app/views/posts/attributes/_non_geo.haml new file mode 100644 index 00000000..ad454d96 --- /dev/null +++ b/app/views/posts/attributes/_non_geo.haml @@ -0,0 +1,24 @@ +.row{ data: { controller: 'non-geo', map: "#{site.url}/public/map.svg" } } + .d-none{ hidden: true, data: { target: 'non-geo.overlay' }} + .col + .form-group + = label_tag "#{base}_#{attribute}_lat", + post_label_t(attribute, :lat, post: post) + = text_field(*field_name_for(base, attribute, :lat), + value: metadata.value['lat'], + **field_options(attribute, metadata), + data: { target: 'non-geo.lat' }) + = render 'posts/attribute_feedback', + post: post, attribute: [attribute, :lat], metadata: metadata + .col + .form-group + = label_tag "#{base}_#{attribute}_lng", + post_label_t(attribute, :lng, post: post) + = text_field(*field_name_for(base, attribute, :lng), + value: metadata.value['lng'], + **field_options(attribute, metadata), + data: { target: 'non-geo.lng' }) + = render 'posts/attribute_feedback', + post: post, attribute: [attribute, :lng], metadata: metadata + .col-12.mb-3 + %div{ data: { target: 'non-geo.map' }, style: 'height: 250px' } From c77fb503668c11580f2f920bffa4df9afa5e970f Mon Sep 17 00:00:00 2001 From: f Date: Tue, 1 Feb 2022 17:38:29 -0300 Subject: [PATCH 005/453] obtener el overlay antes que nada --- app/javascript/controllers/non_geo_controller.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/javascript/controllers/non_geo_controller.js b/app/javascript/controllers/non_geo_controller.js index 072c1b83..f8b86643 100644 --- a/app/javascript/controllers/non_geo_controller.js +++ b/app/javascript/controllers/non_geo_controller.js @@ -14,15 +14,15 @@ export default class extends Controller { static targets = [ 'lat', 'lng', 'map', 'overlay' ] async connect () { + const res = await fetch(this.element.dataset.map); + this.overlayTarget.innerHTML = await res.text(); + this.marker() this.latTarget.addEventListener('change', event => this.marker()) this.lngTarget.addEventListener('change', event => this.marker()) window.addEventListener('resize', event => this.map.invalidateSize()) - const res = await fetch(this.element.dataset.map); - this.overlayTarget.innerHTML = await res.text(); - this.map.on('click', event => { this.latTarget.value = event.latlng.lat this.lngTarget.value = event.latlng.lng From 417559399ac7a727e6375ed4ceed1a11d2f5b923 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 1 Feb 2022 17:52:40 -0300 Subject: [PATCH 006/453] traer archivos subidos localmente --- app/views/posts/attributes/_non_geo.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/posts/attributes/_non_geo.haml b/app/views/posts/attributes/_non_geo.haml index ad454d96..84b1cb00 100644 --- a/app/views/posts/attributes/_non_geo.haml +++ b/app/views/posts/attributes/_non_geo.haml @@ -1,4 +1,4 @@ -.row{ data: { controller: 'non-geo', map: "#{site.url}/public/map.svg" } } +.row{ data: { controller: 'non-geo', map: url_for(site.static_files.blobs.find_by_filename('map.svg').attachments.first) } } .d-none{ hidden: true, data: { target: 'non-geo.overlay' }} .col .form-group From cf5341eec4bba6b42c45bc01d921300b28ad30f3 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 1 Feb 2022 18:20:19 -0300 Subject: [PATCH 007/453] =?UTF-8?q?usar=20el=20tama=C3=B1o=20del=20svg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/non_geo_controller.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/app/javascript/controllers/non_geo_controller.js b/app/javascript/controllers/non_geo_controller.js index f8b86643..1a7775f2 100644 --- a/app/javascript/controllers/non_geo_controller.js +++ b/app/javascript/controllers/non_geo_controller.js @@ -55,13 +55,25 @@ export default class extends Controller { return [this.lat, this.lng] } + get svgOverlay () { + return this.overlayTarget.querySelector('svg'); + } + + get bounds () { + return [ + [0, 0], + [ + this.svgOverlay.viewBox.baseVal.height, + this.svgOverlay.viewBox.baseVal.width, + ] + ]; + } + get map () { if (!this._map) { this._map = L.map(this.mapTarget).setView(this.coords, 13); - const bounds = [[0,0], [this.mapTarget.clientHeight, this.mapTarget.clientWidth]]; - - L.svgOverlay(this.overlayTarget.querySelector('svg'), bounds).addTo(this._map); + L.svgOverlay(this.svgOverlay, this.bounds).addTo(this._map); this._map.fitBounds(bounds); this._map.setMaxBounds(bounds); From c68508f89af6d566ad4063869f7d84615672e2c2 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 1 Feb 2022 18:21:32 -0300 Subject: [PATCH 008/453] usar el sistema de coordenadas simplificado --- app/javascript/controllers/non_geo_controller.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/javascript/controllers/non_geo_controller.js b/app/javascript/controllers/non_geo_controller.js index 1a7775f2..1da5511a 100644 --- a/app/javascript/controllers/non_geo_controller.js +++ b/app/javascript/controllers/non_geo_controller.js @@ -71,7 +71,10 @@ export default class extends Controller { get map () { if (!this._map) { - this._map = L.map(this.mapTarget).setView(this.coords, 13); + this._map = L.map(this.mapTarget, { + crs: L.CRS.Simple, + zoomSnap: 0.1 + }).setView(this.coords, 13); L.svgOverlay(this.svgOverlay, this.bounds).addTo(this._map); From c5c96c8f3cee253e7e327714bd0785d37f509313 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 1 Feb 2022 18:28:27 -0300 Subject: [PATCH 009/453] ajustar al contenido --- app/javascript/controllers/non_geo_controller.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/javascript/controllers/non_geo_controller.js b/app/javascript/controllers/non_geo_controller.js index 1da5511a..419e3c6a 100644 --- a/app/javascript/controllers/non_geo_controller.js +++ b/app/javascript/controllers/non_geo_controller.js @@ -72,11 +72,14 @@ export default class extends Controller { get map () { if (!this._map) { this._map = L.map(this.mapTarget, { + minZoom: -5, crs: L.CRS.Simple, zoomSnap: 0.1 }).setView(this.coords, 13); - L.svgOverlay(this.svgOverlay, this.bounds).addTo(this._map); + const bounds = this.bounds; + + L.svgOverlay(this.svgOverlay, bounds).addTo(this._map); this._map.fitBounds(bounds); this._map.setMaxBounds(bounds); From aa3cbc209ee30ad3efc3db9e477d57c19d60e2a0 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 10 Feb 2022 15:18:49 -0300 Subject: [PATCH 010/453] =?UTF-8?q?vincular=20a=20un=20idioma=20seg=C3=BAn?= =?UTF-8?q?=20el=20dominio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #4545 --- app/models/deploy_localized_domain.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 app/models/deploy_localized_domain.rb diff --git a/app/models/deploy_localized_domain.rb b/app/models/deploy_localized_domain.rb new file mode 100644 index 00000000..6e89c794 --- /dev/null +++ b/app/models/deploy_localized_domain.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +# Soportar dominios localizados +class DeployLocalizedDomain < DeployAlternativeDomain + store :values, accessors: %i[hostname locale], coder: JSON + + # Generar un link simbólico del sitio principal al alternativo + def deploy + File.symlink?(destination) || + File.symlink(File.join(site.hostname, locale), destination).zero? + end +end From 958306ce06213b852e7b6bf2e917eeb7b63d588c Mon Sep 17 00:00:00 2001 From: f Date: Thu, 10 Feb 2022 15:26:20 -0300 Subject: [PATCH 011/453] expedir certificados para los dominios localizados --- app/controllers/api/v1/sites_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/v1/sites_controller.rb b/app/controllers/api/v1/sites_controller.rb index 6abff704..0de21669 100644 --- a/app/controllers/api/v1/sites_controller.rb +++ b/app/controllers/api/v1/sites_controller.rb @@ -46,7 +46,7 @@ module Api # Dominios alternativos def alternative_names - DeployAlternativeDomain.all.map(&:hostname) + DeployAlternativeDomain.all.map(&:hostname) + DeployLocalizedDomain.all.map(&:hostname) end # Obtener todos los sitios con API habilitada, es decir formulario From 05fba76ab81a03e4b4cad0b2c152181c048a4f5c Mon Sep 17 00:00:00 2001 From: f Date: Thu, 10 Feb 2022 19:00:25 -0300 Subject: [PATCH 012/453] usar mosaicos en lugar de svg --- .../controllers/non_geo_controller.js | 22 +++++++------------ app/views/posts/attributes/_non_geo.haml | 2 +- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/app/javascript/controllers/non_geo_controller.js b/app/javascript/controllers/non_geo_controller.js index 419e3c6a..965c561e 100644 --- a/app/javascript/controllers/non_geo_controller.js +++ b/app/javascript/controllers/non_geo_controller.js @@ -55,10 +55,6 @@ export default class extends Controller { return [this.lat, this.lng] } - get svgOverlay () { - return this.overlayTarget.querySelector('svg'); - } - get bounds () { return [ [0, 0], @@ -72,17 +68,15 @@ export default class extends Controller { get map () { if (!this._map) { this._map = L.map(this.mapTarget, { - minZoom: -5, - crs: L.CRS.Simple, - zoomSnap: 0.1 - }).setView(this.coords, 13); + minZoom: 0, + maxZoom: 5 + }).setView(this.coords, 0); - const bounds = this.bounds; - - L.svgOverlay(this.svgOverlay, bounds).addTo(this._map); - - this._map.fitBounds(bounds); - this._map.setMaxBounds(bounds); + this._layer = L.tileLayer(`${this.element.dataset.site}public/map/{z}/{y}/{x}.png`, { + minNativeZoom: 0, + maxNativeZoom: 5, + noWrap: true + }).addTo(this._map); } return this._map diff --git a/app/views/posts/attributes/_non_geo.haml b/app/views/posts/attributes/_non_geo.haml index 84b1cb00..fd4e85ea 100644 --- a/app/views/posts/attributes/_non_geo.haml +++ b/app/views/posts/attributes/_non_geo.haml @@ -1,4 +1,4 @@ -.row{ data: { controller: 'non-geo', map: url_for(site.static_files.blobs.find_by_filename('map.svg').attachments.first) } } +.row{ data: { controller: 'non-geo', site: site.url } } .d-none{ hidden: true, data: { target: 'non-geo.overlay' }} .col .form-group From 53ce970bb0892f74faa0acb7878c7c34646289f4 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 11 Feb 2022 13:57:53 -0300 Subject: [PATCH 013/453] no intentar descargar el mapa --- app/javascript/controllers/non_geo_controller.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/javascript/controllers/non_geo_controller.js b/app/javascript/controllers/non_geo_controller.js index 965c561e..1c618fcb 100644 --- a/app/javascript/controllers/non_geo_controller.js +++ b/app/javascript/controllers/non_geo_controller.js @@ -14,9 +14,6 @@ export default class extends Controller { static targets = [ 'lat', 'lng', 'map', 'overlay' ] async connect () { - const res = await fetch(this.element.dataset.map); - this.overlayTarget.innerHTML = await res.text(); - this.marker() this.latTarget.addEventListener('change', event => this.marker()) From b54a8280a56ca554753f4627673c9dfc73041aee Mon Sep 17 00:00:00 2001 From: f Date: Wed, 2 Mar 2022 13:56:19 -0300 Subject: [PATCH 014/453] =?UTF-8?q?soportar=20m=C3=A1s=20idiomas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/routes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 2aa0056f..e52405d6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -57,7 +57,7 @@ Rails.application.routes.draw do # Gestionar artículos según idioma nested do - scope '/(:locale)', constraint: /[a-z]{2}/ do + scope '/(:locale)', constraint: /[a-z]{2}(-[A-Z]{2})?/ do post :'posts/reorder', to: 'posts#reorder' resources :posts do get 'p/:page', action: :index, on: :collection From 38c34f7b4ffb4dc70188413a2c7b3f1bec4e0c26 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 2 Mar 2022 14:01:17 -0300 Subject: [PATCH 015/453] =?UTF-8?q?usar=20la=20direcci=C3=B3n=20desde=20el?= =?UTF-8?q?=20sitio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/posts/index.haml | 2 +- app/views/posts/show.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 90d65670..b636a891 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -86,7 +86,7 @@ %div %tbody - - dir = t("locales.#{@locale}.dir") + - dir = @site.data.dig(params[:locale], 'dir') - size = @posts.size - @posts.each_with_index do |post, i| -# diff --git a/app/views/posts/show.haml b/app/views/posts/show.haml index da6ac9db..d6ad724c 100644 --- a/app/views/posts/show.haml +++ b/app/views/posts/show.haml @@ -1,4 +1,4 @@ -- dir = t("locales.#{@locale}.dir") +- dir = @site.data.dig(params[:locale], 'dir') .row.justify-content-center .col-md-8 %article.content.table-responsive-md From d7f9f0c9b1f1c3d43632cc92872805d5608687cc Mon Sep 17 00:00:00 2001 From: f Date: Tue, 8 Mar 2022 15:09:31 -0300 Subject: [PATCH 016/453] devolver todos los dominios --- app/controllers/api/v1/sites_controller.rb | 28 ++++++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/v1/sites_controller.rb b/app/controllers/api/v1/sites_controller.rb index 6abff704..32fdae1d 100644 --- a/app/controllers/api/v1/sites_controller.rb +++ b/app/controllers/api/v1/sites_controller.rb @@ -9,7 +9,7 @@ module Api # Lista de nombres de dominios a emitir certificados def index - render json: sites_names + alternative_names + api_names + render json: sites_names + alternative_names + api_names + www_names end # Sitios con hidden service de Tor @@ -28,7 +28,7 @@ module Api site = Site.find_by(name: params[:name]) if site - usuarie = GitAuthor.new email: 'tor@' + Site.domain, name: 'Tor' + usuarie = GitAuthor.new email: "tor@#{Site.domain}", name: 'Tor' service = SiteService.new site: site, usuarie: usuarie, params: params service.add_onion @@ -39,14 +39,22 @@ module Api private + def canonicalize(name) + name.end_with?('.') ? name[0..-2] : "#{name}.#{Site.domain}" + end + # Nombres de los sitios def sites_names - Site.all.order(:name).pluck(:name) + Site.all.order(:name).pluck(:name).map do |name| + canonicalize name + end end # Dominios alternativos def alternative_names - DeployAlternativeDomain.all.map(&:hostname) + (DeployAlternativeDomain.all.map(&:hostname) + DeployLocalizedDomain.all.map(&:hostname)).map do |name| + canonicalize name + end end # Obtener todos los sitios con API habilitada, es decir formulario @@ -56,7 +64,17 @@ module Api def api_names Site.where(contact: true) .or(Site.where(colaboracion_anonima: true)) - .select("'api.' || name as name").map(&:name) + .select("'api.' || name as name").map(&:name).map do |name| + canonicalize name + end + end + + def www_names + Site.where(contact: true) + .or(Site.where(colaboracion_anonima: true)) + .select("'www.' || name as name").map(&:name).map do |name| + canonicalize name + end end end end From 437d5ff230f69f4b6b498cb02f041357098fbf03 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 8 Mar 2022 21:54:25 -0300 Subject: [PATCH 017/453] etiquetas --- app/views/posts/attributes/_geo.haml | 4 ++++ app/views/posts/attributes/_non_geo.haml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/app/views/posts/attributes/_geo.haml b/app/views/posts/attributes/_geo.haml index d048565e..4ed7a395 100644 --- a/app/views/posts/attributes/_geo.haml +++ b/app/views/posts/attributes/_geo.haml @@ -1,4 +1,8 @@ .row{ data: { controller: 'geo' } } + .col-12 + %p= post_label_t(attribute, post: post) + = render 'posts/attribute_feedback', + post: post, attribute: attribute, metadata: metadata .col .form-group = label_tag "#{base}_#{attribute}_lat", diff --git a/app/views/posts/attributes/_non_geo.haml b/app/views/posts/attributes/_non_geo.haml index fd4e85ea..a5a7ea12 100644 --- a/app/views/posts/attributes/_non_geo.haml +++ b/app/views/posts/attributes/_non_geo.haml @@ -1,5 +1,9 @@ .row{ data: { controller: 'non-geo', site: site.url } } .d-none{ hidden: true, data: { target: 'non-geo.overlay' }} + .col-12 + %p= post_label_t(attribute, post: post) + = render 'posts/attribute_feedback', + post: post, attribute: attribute, metadata: metadata .col .form-group = label_tag "#{base}_#{attribute}_lat", From 6801d5655bf36d9e84025ff37f5f8f52f63752c0 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 8 Mar 2022 21:56:41 -0300 Subject: [PATCH 018/453] mejorar estilo --- app/views/posts/attributes/_geo.haml | 4 ++-- app/views/posts/attributes/_non_geo.haml | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/views/posts/attributes/_geo.haml b/app/views/posts/attributes/_geo.haml index 4ed7a395..dee4707e 100644 --- a/app/views/posts/attributes/_geo.haml +++ b/app/views/posts/attributes/_geo.haml @@ -1,6 +1,6 @@ .row{ data: { controller: 'geo' } } - .col-12 - %p= post_label_t(attribute, post: post) + .col-12.mb-3 + %p.mb-0= post_label_t(attribute, post: post) = render 'posts/attribute_feedback', post: post, attribute: attribute, metadata: metadata .col diff --git a/app/views/posts/attributes/_non_geo.haml b/app/views/posts/attributes/_non_geo.haml index a5a7ea12..3f6a75a6 100644 --- a/app/views/posts/attributes/_non_geo.haml +++ b/app/views/posts/attributes/_non_geo.haml @@ -1,6 +1,7 @@ .row{ data: { controller: 'non-geo', site: site.url } } .d-none{ hidden: true, data: { target: 'non-geo.overlay' }} - .col-12 + .col-12.mb-3 + %p.mb-0= post_label_t(attribute, post: post) %p= post_label_t(attribute, post: post) = render 'posts/attribute_feedback', post: post, attribute: attribute, metadata: metadata From ef00ce4d128093a46be68a86006b2e9390db6257 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 14 Mar 2022 13:39:54 -0300 Subject: [PATCH 019/453] poder ver la salida opcionalmente --- app/models/deploy.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 3f034ad5..0a11f1b8 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -48,7 +48,7 @@ class Deploy < ApplicationRecord # # @param [String] # @return [Boolean] - def run(cmd) + def run(cmd, output: false) r = nil lines = [] @@ -61,6 +61,7 @@ class Deploy < ApplicationRecord # TODO: Enviar a un websocket para ver el proceso en vivo? o.each do |line| lines << line + puts line if output end end end From 8e89643bdb03a73ba3d65cd698575e5139ea3987 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 14 Mar 2022 13:40:17 -0300 Subject: [PATCH 020/453] leer la salida por separado para no bloquear el programa --- app/models/deploy.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 0a11f1b8..427e7091 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -55,14 +55,15 @@ class Deploy < ApplicationRecord time_start Dir.chdir(site.path) do Open3.popen2e(env, cmd, unsetenv_others: true) do |_, o, t| - r = t.value - # XXX: Tenemos que leer línea por línea porque en salidas largas - # se cuelga la IO # TODO: Enviar a un websocket para ver el proceso en vivo? - o.each do |line| - lines << line - puts line if output + Thread.new do + o.each do |line| + lines << line + + puts line if output + end end + r = t.value end end time_stop From f3c3da81e0fe35ddc971333fd49658e8784846e8 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 15 Mar 2022 16:03:16 -0300 Subject: [PATCH 021/453] poder ver la salida si lo ejecutamos desde la terminal --- app/jobs/deploy_job.rb | 10 ++++++---- app/models/deploy_local.rb | 26 +++++++++++++------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 70997ce1..4146abad 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -5,7 +5,9 @@ class DeployJob < ApplicationJob class DeployException < StandardError; end # rubocop:disable Metrics/MethodLength - def perform(site, notify = true, time = Time.now) + def perform(site, notify: true, time: Time.now, output: false) + @output = output + ActiveRecord::Base.connection_pool.with_connection do @site = Site.find(site) @@ -21,7 +23,7 @@ class DeployJob < ApplicationJob "#{@site.name} la tarea estuvo más de 10 minutos esperando, volviendo al estado original" end - DeployJob.perform_in(60, site, notify, time) + DeployJob.perform_in(60, site, notify: notify, time: time, output: output) return end @@ -55,12 +57,12 @@ class DeployJob < ApplicationJob end def deploy_locally - deploy_local.deploy + deploy_local.deploy(output: @output) end def deploy_others @site.deploys.where.not(type: 'DeployLocal').find_each do |d| - @deployed[d.type.underscore.to_sym] = d.deploy + @deployed[d.type.underscore.to_sym] = d.deploy(output: @output) end end diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 4fa588f5..4f9318d8 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -12,12 +12,12 @@ class DeployLocal < Deploy # # Pasamos variables de entorno mínimas para no filtrar secretos de # Sutty - def deploy + def deploy(output: false) return false unless mkdir - return false unless yarn - return false unless bundle + return false unless yarn(output: output) + return false unless bundle(output: output) - jekyll_build + jekyll_build(output: output) end # Sólo permitimos un deploy local @@ -79,27 +79,27 @@ class DeployLocal < Deploy File.exist? yarn_lock end - def gem - run %(gem install bundler --no-document) + def gem(output: false) + run %(gem install bundler --no-document), output: output end # Corre yarn dentro del repositorio - def yarn + def yarn(output: false) return true unless yarn_lock? - run 'yarn install --production' + run 'yarn install --production', output: output end - def bundle + def bundle(output: false) if Rails.env.production? - run %(bundle install --no-cache --path="#{gems_dir}") + run %(bundle install --no-cache --path="#{gems_dir}"), output: output else - run %(bundle install) + run %(bundle install), output: output end end - def jekyll_build - run %(bundle exec jekyll build --trace --profile --destination "#{escaped_destination}") + def jekyll_build(output: false) + run %(bundle exec jekyll build --trace --profile --destination "#{escaped_destination}"), output: output end # no debería haber espacios ni caracteres especiales, pero por si From 3160b30dec8a8661e7bebac92e011f3acef19059 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 16 Mar 2022 17:49:28 -0300 Subject: [PATCH 022/453] eliminar atributo style del editor --- app/models/metadata_content.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/models/metadata_content.rb b/app/models/metadata_content.rb index 9d3a1040..9516b907 100644 --- a/app/models/metadata_content.rb +++ b/app/models/metadata_content.rb @@ -72,6 +72,17 @@ class MetadataContent < MetadataTemplate resource['controls'] = true end + # Elimina los estilos salvo los que asigne el editor + html.css('*').each do |element| + next if elements_with_style.include? element.name.downcase + + element.remove_attribute('style') + end + html.to_s.html_safe end + + def elements_with_style + @elements_with_style ||= %w[div mark].freeze + end end From 1071eba2005c3d3857101bd264c188897a9efe22 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 16 Mar 2022 18:19:04 -0300 Subject: [PATCH 023/453] implementar la misma api en todos los deploys --- app/models/deploy.rb | 2 +- app/models/deploy_alternative_domain.rb | 2 +- app/models/deploy_hidden_service.rb | 2 +- app/models/deploy_localized_domain.rb | 12 ++++++++++++ app/models/deploy_private.rb | 4 ++-- app/models/deploy_www.rb | 2 +- app/models/deploy_zip.rb | 2 +- 7 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 app/models/deploy_localized_domain.rb diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 427e7091..0cc92ff1 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -11,7 +11,7 @@ class Deploy < ApplicationRecord belongs_to :site has_many :build_stats, dependent: :destroy - def deploy + def deploy(**) raise NotImplementedError end diff --git a/app/models/deploy_alternative_domain.rb b/app/models/deploy_alternative_domain.rb index e4960e65..ae0ff300 100644 --- a/app/models/deploy_alternative_domain.rb +++ b/app/models/deploy_alternative_domain.rb @@ -5,7 +5,7 @@ class DeployAlternativeDomain < Deploy store :values, accessors: %i[hostname], coder: JSON # Generar un link simbólico del sitio principal al alternativo - def deploy + def deploy(**) File.symlink?(destination) || File.symlink(site.hostname, destination).zero? end diff --git a/app/models/deploy_hidden_service.rb b/app/models/deploy_hidden_service.rb index d4d2b822..dcac712e 100644 --- a/app/models/deploy_hidden_service.rb +++ b/app/models/deploy_hidden_service.rb @@ -2,7 +2,7 @@ # Genera una versión onion class DeployHiddenService < DeployWww - def deploy + def deploy(**) return true if fqdn.blank? super diff --git a/app/models/deploy_localized_domain.rb b/app/models/deploy_localized_domain.rb new file mode 100644 index 00000000..59e17dcd --- /dev/null +++ b/app/models/deploy_localized_domain.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +# Soportar dominios localizados +class DeployLocalizedDomain < DeployAlternativeDomain + store :values, accessors: %i[hostname locale], coder: JSON + + # Generar un link simbólico del sitio principal al alternativo + def deploy(**) + File.symlink?(destination) || + File.symlink(File.join(site.hostname, locale), destination).zero? + end +end diff --git a/app/models/deploy_private.rb b/app/models/deploy_private.rb index 3a6595f9..134c5876 100644 --- a/app/models/deploy_private.rb +++ b/app/models/deploy_private.rb @@ -7,8 +7,8 @@ # jekyll-private-data class DeployPrivate < DeployLocal # No es necesario volver a instalar dependencias - def deploy - jekyll_build + def deploy(output: false) + jekyll_build(output: output) end # Hacer el deploy a un directorio privado diff --git a/app/models/deploy_www.rb b/app/models/deploy_www.rb index 5602b0fc..db552bf2 100644 --- a/app/models/deploy_www.rb +++ b/app/models/deploy_www.rb @@ -6,7 +6,7 @@ class DeployWww < Deploy before_destroy :remove_destination! - def deploy + def deploy(**) File.symlink?(destination) || File.symlink(site.hostname, destination).zero? end diff --git a/app/models/deploy_zip.rb b/app/models/deploy_zip.rb index ec8973d1..f1726e6e 100644 --- a/app/models/deploy_zip.rb +++ b/app/models/deploy_zip.rb @@ -12,7 +12,7 @@ class DeployZip < Deploy # y generar un zip accesible públicamente. # # rubocop:disable Metrics/MethodLength - def deploy + def deploy(**) FileUtils.rm_f path time_start From 6ce0cb2c415a4d78c0e1e085046b8b9ebb46716b Mon Sep 17 00:00:00 2001 From: f Date: Tue, 5 Apr 2022 16:25:47 -0300 Subject: [PATCH 024/453] descartar el deploy si el sitio no existe --- app/jobs/deploy_job.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 70997ce1..6dd4b8eb 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -4,6 +4,8 @@ class DeployJob < ApplicationJob class DeployException < StandardError; end + discard_on ActiveRecord::RecordNotFound + # rubocop:disable Metrics/MethodLength def perform(site, notify = true, time = Time.now) ActiveRecord::Base.connection_pool.with_connection do From 87cdba9bec0a45ab48802c409830478ca045ff6e Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Apr 2022 20:07:14 -0300 Subject: [PATCH 025/453] =?UTF-8?q?enviar=20m=C3=A1s=20informaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/deploy_job.rb | 14 ++++++++++++-- app/models/deploy.rb | 4 ++++ app/models/deploy_alternative_domain.rb | 6 +++++- app/models/deploy_hidden_service.rb | 2 +- app/models/deploy_local.rb | 4 ++++ app/models/deploy_private.rb | 4 ++++ app/models/deploy_www.rb | 4 ++++ app/models/deploy_zip.rb | 4 ++++ app/views/deploy_mailer/deployed.html.haml | 9 +++++++-- app/views/deploy_mailer/deployed.text.haml | 7 +++---- config/locales/en.yml | 2 ++ config/locales/es.yml | 2 ++ 12 files changed, 52 insertions(+), 10 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 70997ce1..db91672b 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -27,7 +27,13 @@ class DeployJob < ApplicationJob @site.update status: 'building' # Asegurarse que DeployLocal sea el primero! - @deployed = { deploy_local: deploy_locally } + @deployed = { + deploy_local: { + status: deploy_locally, + seconds: deploy_local.build_stats.last.seconds, + url: site.url + } + } # No es opcional unless @deployed[:deploy_local] @@ -60,7 +66,11 @@ class DeployJob < ApplicationJob def deploy_others @site.deploys.where.not(type: 'DeployLocal').find_each do |d| - @deployed[d.type.underscore.to_sym] = d.deploy + @deployed[d.type.underscore.to_sym] = { + status: d.deploy, + seconds: d.build_stats.last.seconds, + url: d.url + } end end diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 3f034ad5..1aefe126 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -15,6 +15,10 @@ class Deploy < ApplicationRecord raise NotImplementedError end + def url + raise NotImplementedError + end + def limit raise NotImplementedError end diff --git a/app/models/deploy_alternative_domain.rb b/app/models/deploy_alternative_domain.rb index e4960e65..d245ac21 100644 --- a/app/models/deploy_alternative_domain.rb +++ b/app/models/deploy_alternative_domain.rb @@ -18,6 +18,10 @@ class DeployAlternativeDomain < Deploy end def destination - File.join(Rails.root, '_deploy', hostname.gsub(/\.\z/, '')) + @destination ||= File.join(Rails.root, '_deploy', hostname.gsub(/\.\z/, '')) + end + + def url + "https://#{File.basename destination}" end end diff --git a/app/models/deploy_hidden_service.rb b/app/models/deploy_hidden_service.rb index d4d2b822..8df46c2e 100644 --- a/app/models/deploy_hidden_service.rb +++ b/app/models/deploy_hidden_service.rb @@ -13,6 +13,6 @@ class DeployHiddenService < DeployWww end def url - 'http://' + fqdn + "http://#{fqdn}" end end diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 4fa588f5..b6fa407f 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -25,6 +25,10 @@ class DeployLocal < Deploy 1 end + def url + site.url + end + # Obtener el tamaño de todos los archivos y directorios (los # directorios son archivos :) def size diff --git a/app/models/deploy_private.rb b/app/models/deploy_private.rb index 3a6595f9..0d79811d 100644 --- a/app/models/deploy_private.rb +++ b/app/models/deploy_private.rb @@ -16,6 +16,10 @@ class DeployPrivate < DeployLocal File.join(Rails.root, '_private', site.name) end + def url + "#{ENV['PANEL_URL']}/sites/private/#{site.name}" + end + # No usar recursos en compresión y habilitar los datos privados def env @env ||= super.merge({ diff --git a/app/models/deploy_www.rb b/app/models/deploy_www.rb index 5602b0fc..3c9feb3b 100644 --- a/app/models/deploy_www.rb +++ b/app/models/deploy_www.rb @@ -27,6 +27,10 @@ class DeployWww < Deploy "www.#{site.hostname}" end + def url + "https://www.#{site.hostname}/" + end + private def remove_destination! diff --git a/app/models/deploy_zip.rb b/app/models/deploy_zip.rb index ec8973d1..0a66b602 100644 --- a/app/models/deploy_zip.rb +++ b/app/models/deploy_zip.rb @@ -49,6 +49,10 @@ class DeployZip < Deploy "#{site.hostname}.zip" end + def url + "#{site.url}#{file}" + end + def path File.join(destination, file) end diff --git a/app/views/deploy_mailer/deployed.html.haml b/app/views/deploy_mailer/deployed.html.haml index e8b2e7af..23e99469 100644 --- a/app/views/deploy_mailer/deployed.html.haml +++ b/app/views/deploy_mailer/deployed.html.haml @@ -8,10 +8,15 @@ %tr %th= t('.th.type') %th= t('.th.status') + %th= t('.th.url') + %th= t('.th.seconds') %tbody - - @deploys.each do |deploy, value| + - @deploys.each_pair do |deploy, value| %tr %td= t(".#{deploy}.title") - %td= value ? t(".#{deploy}.success") : t(".#{deploy}.error") + %td= value[:status] ? t(".#{deploy}.success") : t(".#{deploy}.error") + %td= link_to value[:url], value[:url] + %td + %time{ datetime: "PT#{value[:seconds]}S" }= distance_of_time_in_words value[:seconds].seconds = sanitize_markdown t('.help'), tags: %w[p a strong em] diff --git a/app/views/deploy_mailer/deployed.text.haml b/app/views/deploy_mailer/deployed.text.haml index 53a9b008..a3073a61 100644 --- a/app/views/deploy_mailer/deployed.text.haml +++ b/app/views/deploy_mailer/deployed.text.haml @@ -3,10 +3,9 @@ = t('.explanation', fqdn: @deploy_local.site.hostname) \ = Terminal::Table.new do |table| - - table << [t('.th.type'), t('.th.status')] + - table << [t('.th.type'), t('.th.status'), t('.th.url'), t('.th.seconds')] - table.add_separator - - @deploys.each do |deploy, value| - - table << [t(".#{deploy}.title"), - value ? t(".#{deploy}.success") : t(".#{deploy}.error")] + - @deploys.each_pair do |deploy, value| + - table << [ t(".#{deploy}.title"), value[:status] ? t(".#{deploy}.success") : t(".#{deploy}.error"), value[:url], distance_of_time_in_words(value[:seconds].seconds) ] \ = t('.help') diff --git a/config/locales/en.yml b/config/locales/en.yml index b814796d..c8df9150 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -76,6 +76,8 @@ en: th: type: Type status: Status + seconds: Duration + url: Address deploy_local: title: Build the site success: Success! diff --git a/config/locales/es.yml b/config/locales/es.yml index a6fbd407..e94f623a 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -76,6 +76,8 @@ es: th: type: Tipo status: Estado + seconds: Duración + url: Dirección deploy_local: title: Generar el sitio success: ¡Éxito! From c47b4f179cfa07b492edd3834c162508e2c198dc Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Apr 2022 20:16:31 -0300 Subject: [PATCH 026/453] =?UTF-8?q?fixup!=20enviar=20m=C3=A1s=20informaci?= =?UTF-8?q?=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 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 db91672b..79cfa134 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -31,7 +31,7 @@ class DeployJob < ApplicationJob deploy_local: { status: deploy_locally, seconds: deploy_local.build_stats.last.seconds, - url: site.url + url: deploy_local.url } } From 92866704249f0fa8d8156557e5e8e8365bab5b79 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Apr 2022 20:42:40 -0300 Subject: [PATCH 027/453] mostrar espacio utilizado --- app/jobs/deploy_job.rb | 2 ++ app/views/deploy_mailer/deployed.html.haml | 2 ++ app/views/deploy_mailer/deployed.text.haml | 2 +- config/locales/en.yml | 1 + config/locales/es.yml | 1 + 5 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 79cfa134..38bb0429 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -31,6 +31,7 @@ class DeployJob < ApplicationJob deploy_local: { status: deploy_locally, seconds: deploy_local.build_stats.last.seconds, + size: deploy_local.build_stats.last.size, url: deploy_local.url } } @@ -69,6 +70,7 @@ class DeployJob < ApplicationJob @deployed[d.type.underscore.to_sym] = { status: d.deploy, seconds: d.build_stats.last.seconds, + size: d.build_stats.last.size, url: d.url } end diff --git a/app/views/deploy_mailer/deployed.html.haml b/app/views/deploy_mailer/deployed.html.haml index 23e99469..0053accf 100644 --- a/app/views/deploy_mailer/deployed.html.haml +++ b/app/views/deploy_mailer/deployed.html.haml @@ -10,6 +10,7 @@ %th= t('.th.status') %th= t('.th.url') %th= t('.th.seconds') + %th= t('.th.size') %tbody - @deploys.each_pair do |deploy, value| %tr @@ -18,5 +19,6 @@ %td= link_to value[:url], value[:url] %td %time{ datetime: "PT#{value[:seconds]}S" }= distance_of_time_in_words value[:seconds].seconds + %td= number_to_human_size value[:size], precision: 2 = sanitize_markdown t('.help'), tags: %w[p a strong em] diff --git a/app/views/deploy_mailer/deployed.text.haml b/app/views/deploy_mailer/deployed.text.haml index a3073a61..0188c303 100644 --- a/app/views/deploy_mailer/deployed.text.haml +++ b/app/views/deploy_mailer/deployed.text.haml @@ -6,6 +6,6 @@ - table << [t('.th.type'), t('.th.status'), t('.th.url'), t('.th.seconds')] - table.add_separator - @deploys.each_pair do |deploy, value| - - table << [ t(".#{deploy}.title"), value[:status] ? t(".#{deploy}.success") : t(".#{deploy}.error"), value[:url], distance_of_time_in_words(value[:seconds].seconds) ] + - table << [t(".#{deploy}.title"), value[:status] ? t(".#{deploy}.success") : t(".#{deploy}.error"), value[:url], distance_of_time_in_words(value[:seconds].seconds), number_to_human_size(value[:size], precision: 2)] \ = t('.help') diff --git a/config/locales/en.yml b/config/locales/en.yml index c8df9150..75fbcc94 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -77,6 +77,7 @@ en: type: Type status: Status seconds: Duration + size: Space used url: Address deploy_local: title: Build the site diff --git a/config/locales/es.yml b/config/locales/es.yml index e94f623a..73467149 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -77,6 +77,7 @@ es: type: Tipo status: Estado seconds: Duración + size: Espacio ocupado url: Dirección deploy_local: title: Generar el sitio From 9024a13490288013f852a57e2a546161d9e47420 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Apr 2022 20:48:14 -0300 Subject: [PATCH 028/453] algunos deploys no generan build_stats --- app/jobs/deploy_job.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 38bb0429..97438650 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -67,10 +67,13 @@ class DeployJob < ApplicationJob def deploy_others @site.deploys.where.not(type: 'DeployLocal').find_each do |d| + status = d.deploy + build_stat = d.build_stats.last + @deployed[d.type.underscore.to_sym] = { - status: d.deploy, - seconds: d.build_stats.last.seconds, - size: d.build_stats.last.size, + status: status, + seconds: build_stat.try(:seconds) || 0, + size: build_stat.try(:size) || 0, url: d.url } end From ef2589a4f162552d7903f98005cb43303fbdcf65 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Apr 2022 20:51:45 -0300 Subject: [PATCH 029/453] =?UTF-8?q?no=20es=20necesario=20traer=20el=20tama?= =?UTF-8?q?=C3=B1o=20de=20los=20build=5Fstats?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/deploy_job.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 97438650..ae6cb279 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -31,7 +31,7 @@ class DeployJob < ApplicationJob deploy_local: { status: deploy_locally, seconds: deploy_local.build_stats.last.seconds, - size: deploy_local.build_stats.last.size, + size: deploy_local.size, url: deploy_local.url } } @@ -73,7 +73,7 @@ class DeployJob < ApplicationJob @deployed[d.type.underscore.to_sym] = { status: status, seconds: build_stat.try(:seconds) || 0, - size: build_stat.try(:size) || 0, + size: d.size, url: d.url } end From 106029b48f4bba2576e92928dfb9cba857d99de3 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 7 Apr 2022 13:34:12 -0300 Subject: [PATCH 030/453] header --- app/views/deploy_mailer/deployed.text.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/deploy_mailer/deployed.text.haml b/app/views/deploy_mailer/deployed.text.haml index 0188c303..48e8000c 100644 --- a/app/views/deploy_mailer/deployed.text.haml +++ b/app/views/deploy_mailer/deployed.text.haml @@ -3,7 +3,7 @@ = t('.explanation', fqdn: @deploy_local.site.hostname) \ = Terminal::Table.new do |table| - - table << [t('.th.type'), t('.th.status'), t('.th.url'), t('.th.seconds')] + - table << [t('.th.type'), t('.th.status'), t('.th.url'), t('.th.seconds'), t('.th.size')] - table.add_separator - @deploys.each_pair do |deploy, value| - table << [t(".#{deploy}.title"), value[:status] ? t(".#{deploy}.success") : t(".#{deploy}.error"), value[:url], distance_of_time_in_words(value[:seconds].seconds), number_to_human_size(value[:size], precision: 2)] From 026b3879e3fff88a5ca5f997875fc74f9423fa6f Mon Sep 17 00:00:00 2001 From: f Date: Mon, 11 Apr 2022 13:29:42 -0300 Subject: [PATCH 031/453] resolver la ruta real MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit para que en el contenedor los sitios y deploys estén en el mismo sistema de archivos los colocamos en el mismo volumen `data` y los vinculamos a la raíz del proyecto. esto es configurable para los sitios pero no para los deploys. algunas verificaciones de seguridad de jekyll resuelven las rutas reales (`realpath`) de los archivos y fallan porque convierte en el symlink en la ruta real. esto rompe cosas como la previsualización de artículos. closes #5140 closes #5122 closes #5121 closes #5086 closes #4958 --- app/models/site.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/site.rb b/app/models/site.rb index 5b78d625..38953543 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -413,7 +413,7 @@ class Site < ApplicationRecord # El directorio donde se almacenan los sitios def self.site_path - @site_path ||= ENV.fetch('SITE_PATH', Rails.root.join('_sites')) + @site_path ||= File.realpath(ENV.fetch('SITE_PATH', Rails.root.join('_sites'))) end def self.default From f9e0ad698b5facc7802e726c3d6354b741b6a8b1 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 11 Apr 2022 14:56:58 -0300 Subject: [PATCH 032/453] reemplazar todos los elementos que traen archivos de public/ --- app/models/post.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/models/post.rb b/app/models/post.rb index cab7665f..9bc51c51 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -93,13 +93,14 @@ class Post # Renderizar lo estrictamente necesario y convertir a HTML para # poder reemplazar valores. html = Nokogiri::HTML document.renderer.render_document - # Las imágenes se cargan directamente desde el repositorio, porque + # Los archivos se cargan directamente desde el repositorio, porque # no son públicas hasta que se publica el artículo. - html.css('img').each do |img| - next if %r{\Ahttps?://} =~ img.attributes['src'] + html.css('img,audio,video,iframe').each do |element| + src = element.attributes['src'] - img.attributes['src'].value = Rails.application.routes.url_helpers.site_static_file_url(site, - file: img.attributes['src'].value) + next unless src&.value&.start_with? 'public/' + + src.value = Rails.application.routes.url_helpers.site_static_file_url(site, file: src.value) end # Notificar a les usuaries que están viendo una previsualización From 02d72f4227a1ce3913bb1b608889e7abded966af Mon Sep 17 00:00:00 2001 From: f Date: Mon, 11 Apr 2022 14:57:28 -0300 Subject: [PATCH 033/453] rubocop --- app/models/post.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/post.rb b/app/models/post.rb index 9bc51c51..9c1fea25 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -29,7 +29,7 @@ class Post # TODO: Reemplazar cuando leamos el contenido del Document # a demanda? def find_layout(path) - IO.foreach(path).lazy.grep(/^layout: /).take(1).first&.split(' ')&.last&.tr('\'', '')&.tr('"', '')&.to_sym + File.foreach(path).lazy.grep(/^layout: /).take(1).first&.split(' ')&.last&.tr('\'', '')&.tr('"', '')&.to_sym end end @@ -114,7 +114,7 @@ class Post # Devuelve una llave para poder guardar el post en una cache def cache_key - 'posts/' + uuid.value + "posts/#{uuid.value}" end def cache_version @@ -124,7 +124,7 @@ class Post # Agregar el timestamp para saber si cambió, siguiendo el módulo # ActiveRecord::Integration def cache_key_with_version - cache_key + '-' + cache_version + "#{cache_key}-#{cache_version}" end # TODO: Convertir a UUID? From c021cf0e0e114665da834388d8cc3589e6cdb3e4 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 11 Apr 2022 15:25:07 -0300 Subject: [PATCH 034/453] actualizar jekyll-images produce una excepcion --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 8df2d77e..65f950ce 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -289,7 +289,7 @@ GEM jekyll (~> 4) jekyll-ignore-layouts (0.1.2) jekyll (~> 4) - jekyll-images (0.3.0) + jekyll-images (0.3.2) jekyll (~> 4) ruby-filemagic (~> 0.7) ruby-vips (~> 2) From dd32a5a0c1838e3e464e8fdbe80a4d1a9c2f8235 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Apr 2022 12:31:36 -0300 Subject: [PATCH 035/453] woodpecker --- .woodpecker.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .woodpecker.yml diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 00000000..81af8efb --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,26 @@ +pipeline: + publish: + image: plugins/docker + settings: + registry: registry.nulo.in + username: sutty + repo: registry.nulo.in/sutty/panel + tags: + - ${ALPINE_VERSION}-${RUBY_VERSION}.${RUBY_PATCH} + - latest + build_args: + - RUBY_VERSION=${RUBY_VERSION} + - RUBY_PATCH=${RUBY_PATCH} + - ALPINE_VERSION=${ALPINE_VERSION} + - BASE_IMAGE=registry.nulo.in/sutty/rails + purge: false + secrets: + - docker_password + when: + branch: antifascista + event: push +matrix: + include: + - ALPINE_VERSION: 3.13.10 + RUBY_VERSION: 2.7 + RUBY_PATCH: 6 From d9a5f7ff238b10795022b160dfbabb1716ce4c29 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Apr 2022 12:34:42 -0300 Subject: [PATCH 036/453] actualizar pandoc --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ecf43cbc..68ec6188 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM registry.nulo.in/sutty/rails:3.13.6-2.7.5 -ARG PANDOC_VERSION=2.17.1.1 +ARG PANDOC_VERSION=2.18 ENV RAILS_ENV production # Instalar las dependencias, separamos la librería de base de datos para From 244a8de406b6afaf471da8934e4ce9bec300701c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Apr 2022 12:37:13 -0300 Subject: [PATCH 037/453] ramas que provocan deploys --- .woodpecker.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 81af8efb..db2b307d 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -17,7 +17,9 @@ pipeline: secrets: - docker_password when: - branch: antifascista + branch: + - rails + - panel.sutty.nl event: push matrix: include: From d9e2291f264b273b53ecfe579d7b7d610045752a Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Apr 2022 16:44:52 -0300 Subject: [PATCH 038/453] usar argumentos --- Dockerfile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 68ec6188..ac90a548 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,8 @@ -FROM registry.nulo.in/sutty/rails:3.13.6-2.7.5 +ARG RUBY_VERSION=2.7 +ARG RUBY_PATCH=6 +ARG ALPINE_VERSION=3.13.10 +ARG BASE_IMAGE=registry.nulo.in/sutty/rails +FROM ${BASE_IMAGE}:${ALPINE_VERSION}-${RUBY_VERSION}.${RUBY_PATCH} ARG PANDOC_VERSION=2.18 ENV RAILS_ENV production From 78c0bdcc3930c5d6035682ecc2982498f88cd0d6 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Apr 2022 10:39:44 -0300 Subject: [PATCH 039/453] cada deploy puede ejecutar tareas de limpieza MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pero la mayoría no lo va a necesitar --- app/models/deploy.rb | 3 +++ app/models/deploy_local.rb | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 3f034ad5..42bfd345 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -23,6 +23,9 @@ class Deploy < ApplicationRecord raise NotImplementedError end + # Realizar tareas de limpieza. + def cleanup!; end + def time_start @start = Time.now end diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 4fa588f5..66412df2 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -43,6 +43,17 @@ class DeployLocal < Deploy File.join(Rails.root, '_deploy', site.hostname) end + # Libera espacio eliminando archivos temporales + # + # @return [nil] + def cleanup! + FileUtils.rm_rf(gems_dir) + FileUtils.rm_rf(yarn_cache_dir) + FileUtils.rm_rf(File.join(site.path, 'node_modules')) + FileUtils.rm_rf(File.join(site.path, '.sass-cache')) + FileUtils.rm_rf(File.join(site.path, '.jekyll-cache')) + end + private def mkdir From 1e0fb95825b7aed00d7a5c77512e7cb6c1efa770 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Apr 2022 10:40:18 -0300 Subject: [PATCH 040/453] =?UTF-8?q?correr=20la=20recolecci=C3=B3n=20de=20b?= =?UTF-8?q?asura=20de=20git?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/site/repository.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/app/models/site/repository.rb b/app/models/site/repository.rb index 74db2549..f63288d4 100644 --- a/app/models/site/repository.rb +++ b/app/models/site/repository.rb @@ -147,6 +147,23 @@ class Site rugged.index.remove(relativize(file)) end + # Garbage collection + # + # @return [Boolean] + def gc + env = { 'PATH' => '/usr/bin', 'LANG' => ENV['LANG'], 'HOME' => path } + cmd = 'git gc' + + r = nil + Dir.chdir(path) do + Open3.popen2e(env, cmd, unsetenv_others: true) do |_, _, t| + r = t.value + end + end + + r&.success? + end + private # Si Sutty tiene una llave privada de tipo ED25519, devuelve las From 9fefc0f554e7142de3c70efac2a3e66d53b61782 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Apr 2022 10:41:22 -0300 Subject: [PATCH 041/453] abl --- app/services/cleanup_service.rb | 47 +++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 app/services/cleanup_service.rb diff --git a/app/services/cleanup_service.rb b/app/services/cleanup_service.rb new file mode 100644 index 00000000..ad87cf9a --- /dev/null +++ b/app/services/cleanup_service.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +# Realiza tareas de limpieza en todos los sitios, para optimizar y +# liberar espacio. +class CleanupService + # Días de antigüedad de los sitios + attr_reader :before + + # @param :before [ActiveSupport::TimeWithZone] Cuánto tiempo lleva sin usarse un sitio. + def initialize(before: 30.days.ago) + @before = before + end + + # Limpieza general + # + # @return [nil] + def cleanup_everything! + cleanup_older_sites! + cleanup_newer_sites! + end + + # Encuentra todos los sitios sin actualizar y realiza limpieza. + # + # @return [nil] + def cleanup_older_sites! + Site.where('updated_at < ?', before).find_each do |site| + next unless File.directory? site.path + + site.deploys.find_each(&:cleanup!) + + site.repository.gc + site.touch + end + end + + # Tareas para los sitios en uso + # + # @return [nil] + def cleanup_newer_sites! + Site.where('updated_at >= ?', before).find_each do |site| + next unless File.directory? site.path + + site.repository.gc + site.touch + end + end +end From 170cbeb69eeddde6e6176a7dcd8f5dbdb13fe7d2 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Apr 2022 10:41:53 -0300 Subject: [PATCH 042/453] poder hacer limpieza desde la terminal --- lib/tasks/cleanup.rake | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 lib/tasks/cleanup.rake diff --git a/lib/tasks/cleanup.rake b/lib/tasks/cleanup.rake new file mode 100644 index 00000000..e14693bc --- /dev/null +++ b/lib/tasks/cleanup.rake @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +namespace :cleanup do + desc 'Cleanup sites' + task everything: :environment do + before = ENV.fetch('BEFORE', '30').to_i.days.ago + service = CleanupService.new(before: before) + + service.cleanup_everything! + end +end From 3b616198eaf64f122e1a2684ed0e2d345ed38d1e Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Apr 2022 10:57:51 -0300 Subject: [PATCH 043/453] realizar la limpieza mensualmente --- .dockerignore | 1 + Dockerfile | 2 ++ Procfile | 8 +------- monit.conf | 30 ++++-------------------------- 4 files changed, 8 insertions(+), 33 deletions(-) diff --git a/.dockerignore b/.dockerignore index afe4e8d7..7b84d429 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,3 +2,4 @@ * # Solo agregar lo que usamos en COPY # !./archivo +!./monit.conf diff --git a/Dockerfile b/Dockerfile index ecf43cbc..342c2750 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,6 +15,8 @@ RUN apk add --no-cache libxslt libxml2 postgresql-libs libssh2 \ RUN gem install --no-document --no-user-install foreman RUN wget https://github.com/jgm/pandoc/releases/download/${PANDOC_VERSION}/pandoc-${PANDOC_VERSION}-linux-amd64.tar.gz -O - | tar --strip-components 1 -xvzf - pandoc-${PANDOC_VERSION}/bin/pandoc && mv /bin/pandoc /usr/bin/pandoc +COPY ./monit.conf /etc/monit.d/sutty.conf + VOLUME "/srv" EXPOSE 3000 diff --git a/Procfile b/Procfile index b308ffd5..48931e8d 100644 --- a/Procfile +++ b/Procfile @@ -1,7 +1 @@ -migrate: bundle exec rake db:prepare db:seed -sutty: bundle exec puma config.ru -blazer_5m: bundle exec rake blazer:run_checks SCHEDULE="5 minutes" -blazer_1h: bundle exec rake blazer:run_checks SCHEDULE="1 hour" -blazer_1d: bundle exec rake blazer:run_checks SCHEDULE="1 day" -blazer: bundle exec rake blazer:send_failing_checks -prometheus: bundle exec prometheus_exporter -b 0.0.0.0 --prefix "sutty_" +cleanup: rake cleanup:everything diff --git a/monit.conf b/monit.conf index 96c08d8a..07cd1c1e 100644 --- a/monit.conf +++ b/monit.conf @@ -1,27 +1,5 @@ -check process sutty with pidfile /srv/tmp/puma.pid - start program = "/usr/local/bin/sutty start" - stop program = "/usr/local/bin/sutty stop" - -check process prometheus with pidfile /tmp/prometheus.pid - start program = "/usr/local/bin/sutty prometheus start" - stop program = "/usr/local/bin/sutty prometheus start" - -check program blazer_5m - with path "/usr/local/bin/sutty blazer 5m" - every 5 cycles - if status != 0 then alert - -check program blazer_1h - with path "/usr/local/bin/sutty blazer 1h" - every 60 cycles - if status != 0 then alert - -check program blazer_1d - with path "/usr/local/bin/sutty blazer 1d" - every 1440 cycles - if status != 0 then alert - -check program blazer - with path "/usr/local/bin/sutty blazer" - every 61 cycles +# Limpiar mensualmente +check program cleanup + with path "/usr/bin/foreman run -f /srv/Procfile -d /srv " as uid "rails" gid "http-data" + every "0 3 1 * *" if status != 0 then alert From f2eea5fbcbf746bb061fcbfb363f06bf8e68d85f Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Apr 2022 17:27:43 -0300 Subject: [PATCH 044/453] no fallar al cerrarse la salida --- app/models/deploy.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 0cc92ff1..b45fa350 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -62,7 +62,10 @@ class Deploy < ApplicationRecord puts line if output end + rescue IOError => e + ExceptionNotifier.notify(e, data: { site: site.name }) end + r = t.value end end From bfeb513b6b5c52265b3a2820165188dbf15662cd Mon Sep 17 00:00:00 2001 From: f Date: Thu, 28 Apr 2022 10:56:47 -0300 Subject: [PATCH 045/453] =?UTF-8?q?agregar=20modo=20de=20slugificaci=C3=B3?= =?UTF-8?q?n=20en=20el=20sitio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/metadata_slug.rb | 2 +- db/migrate/20220428135113_add_slugify_mode_to_sites.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20220428135113_add_slugify_mode_to_sites.rb diff --git a/app/models/metadata_slug.rb b/app/models/metadata_slug.rb index 09da23f9..a37451d9 100644 --- a/app/models/metadata_slug.rb +++ b/app/models/metadata_slug.rb @@ -25,7 +25,7 @@ require 'jekyll/utils' class MetadataSlug < MetadataTemplate # Trae el slug desde el título si existe o una string al azar def default_value - title ? Jekyll::Utils.slugify(title) : SecureRandom.uuid + title ? Jekyll::Utils.slugify(title, mode: site.slugify_mode) : SecureRandom.uuid end def value diff --git a/db/migrate/20220428135113_add_slugify_mode_to_sites.rb b/db/migrate/20220428135113_add_slugify_mode_to_sites.rb new file mode 100644 index 00000000..fd887886 --- /dev/null +++ b/db/migrate/20220428135113_add_slugify_mode_to_sites.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# Permite a los sitios elegir el método de slugificación +class AddSlugifyModeToSites < ActiveRecord::Migration[6.1] + def change + add_column :sites, :slugify_mode, :string, default: 'default' + end +end From cadb3ad6a6fb00547df734a10271d0a4069d7a1c Mon Sep 17 00:00:00 2001 From: f Date: Thu, 28 Apr 2022 10:57:28 -0300 Subject: [PATCH 046/453] normalizar unicode en la string --- app/models/metadata_slug.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/metadata_slug.rb b/app/models/metadata_slug.rb index a37451d9..b0fe8cec 100644 --- a/app/models/metadata_slug.rb +++ b/app/models/metadata_slug.rb @@ -39,6 +39,6 @@ class MetadataSlug < MetadataTemplate return if post.title&.private? return if post.title&.value&.blank? - post.title&.value&.to_s + post.title&.value&.to_s&.unicode_normalize end end From 6a7511a5e1c1398f770ca67194acc7b00f935c72 Mon Sep 17 00:00:00 2001 From: Nulo Date: Mon, 2 May 2022 18:55:35 +0000 Subject: [PATCH 047/453] Arreglar scroll al reordenar posts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Utilizaba https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoViewIfNeeded que es propietario. Ahora usa scrollIntoView siempre, configurado para que prácticamente siempre se pueda ver el post al reordenar. --- app/javascript/controllers/reorder_controller.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/javascript/controllers/reorder_controller.js b/app/javascript/controllers/reorder_controller.js index dca6e166..2cba4163 100644 --- a/app/javascript/controllers/reorder_controller.js +++ b/app/javascript/controllers/reorder_controller.js @@ -103,11 +103,7 @@ export default class extends Controller { this.reorder() // Mantenemos el primero a la vista - if ("scrollIntoViewIfNeeded" in rows[0].row) { - rows[0].row.scrollIntoViewIfNeeded() - } else { - rows[0].row.scrollIntoView() - } + rows[0].row.scrollIntoView({ block: "center" }); } counter () { @@ -146,7 +142,7 @@ export default class extends Controller { this.reorder() // Mantenemos el primero a la vista - rows[0].row.scrollIntoViewIfNeeded() + rows[0].row.scrollIntoView({ block: "center" }); } bottom (event) { @@ -167,7 +163,7 @@ export default class extends Controller { this.reorder() // Mantenemos el primero a la vista - rows[0].row.scrollIntoViewIfNeeded() + rows[0].row.scrollIntoView({ block: "center" }); } /* From 87c09323dc60f1f21856edec9330efcc673fa0ef Mon Sep 17 00:00:00 2001 From: f Date: Thu, 5 May 2022 19:37:14 -0300 Subject: [PATCH 048/453] ignorar posts sin layout pero notificar closes #5828 closes #3251 --- app/models/site.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/site.rb b/app/models/site.rb index 7d4875e5..141baf22 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -230,6 +230,8 @@ class Site < ApplicationRecord layout = layouts[Post.find_layout(doc.path)] @posts[lang].build(document: doc, layout: layout, lang: lang) + rescue TypeError => e + ExceptionNotifier.notify_exception(e, data: { site: name, site_id: id, path: doc.path }) end @posts[lang] From a0441a858e960360997d412ce44192f4393e49a3 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 11 Jun 2022 19:51:11 -0300 Subject: [PATCH 049/453] comandos correctos --- Procfile | 2 +- monit.conf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Procfile b/Procfile index 48931e8d..112b6042 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -cleanup: rake cleanup:everything +cleanup: bundle exec rake cleanup:everything diff --git a/monit.conf b/monit.conf index 07cd1c1e..ea6925fd 100644 --- a/monit.conf +++ b/monit.conf @@ -1,5 +1,5 @@ # Limpiar mensualmente check program cleanup - with path "/usr/bin/foreman run -f /srv/Procfile -d /srv " as uid "rails" gid "http-data" + with path "/usr/bin/foreman run -f /srv/Procfile -d /srv cleanup" as uid "rails" gid "http-data" every "0 3 1 * *" if status != 0 then alert From 369b0c9937ea1b7baf8112d36e17b7df2f5dd45c Mon Sep 17 00:00:00 2001 From: f Date: Sat, 11 Jun 2022 19:52:38 -0300 Subject: [PATCH 050/453] fixup! comandos correctos --- monit.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monit.conf b/monit.conf index ea6925fd..20e4c703 100644 --- a/monit.conf +++ b/monit.conf @@ -1,5 +1,5 @@ # Limpiar mensualmente check program cleanup - with path "/usr/bin/foreman run -f /srv/Procfile -d /srv cleanup" as uid "rails" gid "http-data" + with path "/usr/bin/foreman run -f /srv/Procfile -d /srv cleanup" as uid "rails" gid "www-data" every "0 3 1 * *" if status != 0 then alert From a4eef2edc096db2e185e94b3aa5588e72e9e02bf Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Jun 2022 15:07:08 -0300 Subject: [PATCH 051/453] =?UTF-8?q?notificar=20correctamente=20la=20excepc?= =?UTF-8?q?i=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index b45fa350..1c730c06 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -63,7 +63,7 @@ class Deploy < ApplicationRecord puts line if output end rescue IOError => e - ExceptionNotifier.notify(e, data: { site: site.name }) + ExceptionNotifier.notify_exception(e, data: { site: site.name }) end r = t.value From d18536f5871bc860d749edfdea3f9765e47d98d3 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 29 Jun 2022 18:41:51 -0300 Subject: [PATCH 052/453] no generar issues para log --- app/models/deploy.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 1c730c06..65159bce 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -63,7 +63,8 @@ class Deploy < ApplicationRecord puts line if output end rescue IOError => e - ExceptionNotifier.notify_exception(e, data: { site: site.name }) + lines << e.message + puts e.message if output end r = t.value From 9e531e49955801bd41a4a8a48ca8d764ebfe342a Mon Sep 17 00:00:00 2001 From: f Date: Tue, 12 Jul 2022 15:38:16 -0300 Subject: [PATCH 053/453] no cambiar el valor si no se pudo cargar el archivo esto hace que sutilmente desaparezcan archivos --- app/models/metadata_file.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/models/metadata_file.rb b/app/models/metadata_file.rb index 71d3f049..2b628a57 100644 --- a/app/models/metadata_file.rb +++ b/app/models/metadata_file.rb @@ -41,14 +41,10 @@ class MetadataFile < MetadataTemplate end # Asociar la imagen subida al sitio y obtener la ruta - # - # XXX: Si evitamos guardar cambios con changed? no tenemos forma de - # saber que un archivo subido manualmente se convirtió en - # un Attachment y cada vez que lo editemos vamos a subir una imagen - # repetida. + # @return [Boolean] def save value['description'] = sanitize value['description'] - value['path'] = static_file ? relative_destination_path_with_filename.to_s : nil + value['path'] = relative_destination_path_with_filename.to_s if static_file true end From 0b06bf35417b1f23176f798611c70ffc49822985 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 12 Jul 2022 15:39:08 -0300 Subject: [PATCH 054/453] notificar cuando no se pudo cargar el archivo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit no perder información silenciosamente --- app/models/metadata_file.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/models/metadata_file.rb b/app/models/metadata_file.rb index 2b628a57..942b448d 100644 --- a/app/models/metadata_file.rb +++ b/app/models/metadata_file.rb @@ -58,9 +58,6 @@ class MetadataFile < MetadataTemplate # * El archivo es una ruta que apunta a un archivo asociado al sitio # * El archivo es una ruta a un archivo dentro del repositorio # - # XXX: La última opción provoca archivos duplicados, pero es lo mejor - # que tenemos hasta que resolvamos https://0xacab.org/sutty/sutty/-/issues/213 - # # @todo encontrar una forma de obtener el attachment sin tener que # recurrir al último subido. # @@ -77,8 +74,12 @@ class MetadataFile < MetadataTemplate site.static_files.last.tap do |s| s.blob.update(key: key_from_path) end + else + raise ArgumentError, 'No se pudo subir el archivo' end end + rescue ArgumentError => e + ExceptionNotifier.notify_exception(e, data: { site: site.name, path: value['path'] }) end # Obtiene la ruta absoluta al archivo From def4402313e0d142b72321192c1b09783fdfe520 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 12 Jul 2022 15:39:42 -0300 Subject: [PATCH 055/453] permitir cargar archivos con la misma key podemos tener sitios distintos con la misma llave identificatoria. ahora permitimos solo una llave por cada sitio distinto. si subimos un archivo duplicado en un mismo sitio el error va a seguir siendo el mismo. --- app/models/metadata_file.rb | 2 +- ...nge_blob_key_uniqueness_to_include_service_name.rb | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20220712135053_change_blob_key_uniqueness_to_include_service_name.rb diff --git a/app/models/metadata_file.rb b/app/models/metadata_file.rb index 942b448d..fa570ac0 100644 --- a/app/models/metadata_file.rb +++ b/app/models/metadata_file.rb @@ -68,7 +68,7 @@ class MetadataFile < MetadataTemplate when ActionDispatch::Http::UploadedFile site.static_files.last if site.static_files.attach(value['path']) when String - if (blob_id = ActiveStorage::Blob.where(key: key_from_path).pluck(:id).first) + if (blob_id = ActiveStorage::Blob.where(key: key_from_path, service_name: site.name).pluck(:id).first) site.static_files.find_by(blob_id: blob_id) elsif path? && pathname.exist? && site.static_files.attach(io: pathname.open, filename: pathname.basename) site.static_files.last.tap do |s| diff --git a/db/migrate/20220712135053_change_blob_key_uniqueness_to_include_service_name.rb b/db/migrate/20220712135053_change_blob_key_uniqueness_to_include_service_name.rb new file mode 100644 index 00000000..00bae7ea --- /dev/null +++ b/db/migrate/20220712135053_change_blob_key_uniqueness_to_include_service_name.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +# Cambia el índice único para incluir el nombre del servicio, de forma +# que podamos tener varias copias del mismo sitio (por ejemplo para +# test) sin que falle la creación de archivos. +class ChangeBlobKeyUniquenessToIncludeServiceName < ActiveRecord::Migration[6.1] + def change + remove_index :active_storage_blobs, %i[key], unique: true + add_index :active_storage_blobs, %i[key service_name], unique: true + end +end From cd523babade074fd69471e9c54cf1c391a2730da Mon Sep 17 00:00:00 2001 From: f Date: Tue, 12 Jul 2022 15:58:31 -0300 Subject: [PATCH 056/453] siempre devolver Pathname closes #6982 closes #6979 closes #6974 closes #6973 closes #6972 closes #6970 closes #6968 closes #6967 --- app/models/metadata_file.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/metadata_file.rb b/app/models/metadata_file.rb index fa570ac0..4ea026b4 100644 --- a/app/models/metadata_file.rb +++ b/app/models/metadata_file.rb @@ -126,7 +126,7 @@ class MetadataFile < MetadataTemplate rescue Errno::ENOENT => e ExceptionNotifier.notify_exception(e) - value['path'] + Pathname.new(value['path']) end def relative_destination_path_with_filename From aab8ed9fed5c1411da527814a78e5ad7db132bd6 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Jul 2022 13:34:45 -0300 Subject: [PATCH 057/453] =?UTF-8?q?informar=20cuando=20el=20nombre=20de=20?= =?UTF-8?q?archivo=20est=C3=A1=20vac=C3=ADo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/active_storage/service/jekyll_service.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/lib/active_storage/service/jekyll_service.rb b/app/lib/active_storage/service/jekyll_service.rb index 92b26e0e..3edd2653 100644 --- a/app/lib/active_storage/service/jekyll_service.rb +++ b/app/lib/active_storage/service/jekyll_service.rb @@ -67,7 +67,9 @@ module ActiveStorage # @param :key [String] # @return [String] def filename_for(key) - ActiveStorage::Blob.where(key: key).limit(1).pluck(:filename).first + ActiveStorage::Blob.where(key: key).limit(1).pluck(:filename).first.tap do |filename| + raise ArgumentError, "Filename for key #{key} is blank" if filename.blank? + end end # Crea una ruta para la llave con un nombre conocido. From 5397ae66a2709aeb30da2dbb2b9064cf3e42e8c7 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Jul 2022 14:18:39 -0300 Subject: [PATCH 058/453] informar con mas detalle cuando el archivo no existe closes #6991 closes #6990 closes #6985 closes #6969 closes #6966 --- app/models/metadata_file.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/metadata_file.rb b/app/models/metadata_file.rb index 4ea026b4..00ac7af0 100644 --- a/app/models/metadata_file.rb +++ b/app/models/metadata_file.rb @@ -124,13 +124,15 @@ class MetadataFile < MetadataTemplate # devolvemos la ruta original, que puede ser el archivo que no existe # o vacía si se está subiendo uno. rescue Errno::ENOENT => e - ExceptionNotifier.notify_exception(e) + ExceptionNotifier.notify_exception(e, data: { site: site.name, path: value['path'] }) Pathname.new(value['path']) end def relative_destination_path_with_filename destination_path_with_filename.relative_path_from(Pathname.new(site.path).realpath) + rescue ArgumentError => e + ExceptionNotifier.notify_exception(e, data: { site: site.name, path: value['path'] }) end def static_file_path From 83384b686af0ddb9be18ee3fbbb10d1a9d3ea899 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Jul 2022 18:22:06 -0300 Subject: [PATCH 059/453] solo copiar el archivo si no existe --- app/lib/active_storage/service/jekyll_service.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/lib/active_storage/service/jekyll_service.rb b/app/lib/active_storage/service/jekyll_service.rb index 3edd2653..88ffa83c 100644 --- a/app/lib/active_storage/service/jekyll_service.rb +++ b/app/lib/active_storage/service/jekyll_service.rb @@ -20,6 +20,18 @@ module ActiveStorage end end + # Solo copiamos el archivo si no existe + # + # @param :key [String] + # @param :io [IO] + # @param :checksum [String] + def upload(key, io, checksum: nil, **) + instrument :upload, key: key, checksum: checksum do + IO.copy_stream(io, make_path_for(key)) unless exist?(key) + ensure_integrity_of(key, checksum) if checksum + end + end + # Lo mismo que en DiskService agregando el nombre de archivo en la # firma. Esto permite que luego podamos guardar el archivo donde # corresponde. From 6c62c20572a1a763ceb23b62eea924fed4b86e25 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Jul 2022 19:32:06 -0300 Subject: [PATCH 060/453] subir directamente los archivos a la base de datos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cuando subimos un archivo usando attach en realidad estábamos generando una copia y dejándola huérfana en el repositorio del sitio. usando blob podemos imitar un servicio de subida de archivos sin generar io innecesario. --- app/models/metadata_file.rb | 42 ++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/app/models/metadata_file.rb b/app/models/metadata_file.rb index 00ac7af0..c7296de4 100644 --- a/app/models/metadata_file.rb +++ b/app/models/metadata_file.rb @@ -68,18 +68,8 @@ class MetadataFile < MetadataTemplate when ActionDispatch::Http::UploadedFile site.static_files.last if site.static_files.attach(value['path']) when String - if (blob_id = ActiveStorage::Blob.where(key: key_from_path, service_name: site.name).pluck(:id).first) - site.static_files.find_by(blob_id: blob_id) - elsif path? && pathname.exist? && site.static_files.attach(io: pathname.open, filename: pathname.basename) - site.static_files.last.tap do |s| - s.blob.update(key: key_from_path) - end - else - raise ArgumentError, 'No se pudo subir el archivo' - end + site.static_files.find_by(blob_id: blob_id) || migrate_static_file! end - rescue ArgumentError => e - ExceptionNotifier.notify_exception(e, data: { site: site.name, path: value['path'] }) end # Obtiene la ruta absoluta al archivo @@ -95,7 +85,7 @@ class MetadataFile < MetadataTemplate # # @return [String] def key_from_path - pathname.dirname.basename.to_s + @key_from_path ||= pathname.dirname.basename.to_s end def path? @@ -148,4 +138,32 @@ class MetadataFile < MetadataTemplate def no_file_for_description? !path? && description? end + + # Obtiene el id del blob asociado + # + # @return [Integer,nil] + def blob_id + @blob_id ||= ActiveStorage::Blob.where(key: key_from_path, service_name: site.name).pluck(:id).first + end + + # Genera el blob para un archivo que ya se encuentra en el + # repositorio y lo agrega a la base de datos. + # + # @return [ActiveStorage::Attachment] + def migrate_static_file! + raise ArgumentError, 'El archivo no existe' unless path? && pathname.exist? + + Site.transaction do + blob = + ActiveStorage::Blob.create_after_unfurling!(key: key_from_path, + io: pathname.open, + filename: pathname.basename, + service_name: site.name) + + ActiveStorage::Attachment.create!(name: 'static_files', record: site, blob: blob) + end + rescue ArgumentError => e + ExceptionNotifier.notify_exception(e, data: { site: site.name, path: value['path'] }) + nil + end end From 0d6a2c020c0a7efa0f16c3af41d70cafc41f688a Mon Sep 17 00:00:00 2001 From: f Date: Tue, 26 Jul 2022 13:49:59 -0300 Subject: [PATCH 061/453] reindexar los sitios al terminar de compilarlos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit para poder soportar modificaciones durante la generación del sitio --- app/models/deploy_reindex.rb | 19 +++++++++++++++++++ app/views/deploys/_deploy_reindex.haml | 1 + config/locales/en.yml | 4 ++++ config/locales/es.yml | 4 ++++ 4 files changed, 28 insertions(+) create mode 100644 app/models/deploy_reindex.rb create mode 100644 app/views/deploys/_deploy_reindex.haml diff --git a/app/models/deploy_reindex.rb b/app/models/deploy_reindex.rb new file mode 100644 index 00000000..d2ff0679 --- /dev/null +++ b/app/models/deploy_reindex.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# Reindexa los artículos al terminar la compilación +class DeployReindex < Deploy + def deploy + site.reset + site.indexed_posts.destroy_all + site.index_posts! + site.touch + end + + def limit + 1 + end + + def hostname + nil + end +end diff --git a/app/views/deploys/_deploy_reindex.haml b/app/views/deploys/_deploy_reindex.haml new file mode 100644 index 00000000..af058968 --- /dev/null +++ b/app/views/deploys/_deploy_reindex.haml @@ -0,0 +1 @@ +-# NADA diff --git a/config/locales/en.yml b/config/locales/en.yml index 530a9381..b08ddc95 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -102,6 +102,10 @@ en: title: Alternative domain name success: Success! error: Error + deploy_reindex: + title: Reindex + success: Success! + error: Error help: You can contact us by replying to this e-mail maintenance_mailer: notice: diff --git a/config/locales/es.yml b/config/locales/es.yml index eaa23137..026f2bc5 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -102,6 +102,10 @@ es: title: Dominio alternativo success: ¡Éxito! error: Hubo un error + deploy_reindex: + title: Reindexación + success: ¡Éxito! + error: Hubo un error help: Por cualquier duda, responde este correo para contactarte con nosotres. maintenance_mailer: notice: From b983353223c8f46e8c03a4d9a6336500e011fc57 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 26 Jul 2022 14:13:54 -0300 Subject: [PATCH 062/453] =?UTF-8?q?log=20de=20reindexaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_reindex.rb | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/app/models/deploy_reindex.rb b/app/models/deploy_reindex.rb index d2ff0679..2bc8f642 100644 --- a/app/models/deploy_reindex.rb +++ b/app/models/deploy_reindex.rb @@ -3,12 +3,29 @@ # Reindexa los artículos al terminar la compilación class DeployReindex < Deploy def deploy + time_start + site.reset - site.indexed_posts.destroy_all - site.index_posts! + + Site.transaction do + site.indexed_posts.destroy_all + site.index_posts! + end + + time_stop + + build_stats.create action: 'reindex', + log: 'Reindex', + seconds: time_spent_in_seconds, + bytes: size, + status: true site.touch end + def size + 0 + end + def limit 1 end From 70ee31325467db20b0f33fcf67d999846e838c85 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 26 Jul 2022 14:50:46 -0300 Subject: [PATCH 063/453] tampoco tienen url --- app/models/deploy_reindex.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/deploy_reindex.rb b/app/models/deploy_reindex.rb index 2bc8f642..921451d9 100644 --- a/app/models/deploy_reindex.rb +++ b/app/models/deploy_reindex.rb @@ -33,4 +33,8 @@ class DeployReindex < Deploy def hostname nil end + + def url + nil + end end From d5f6d3c61b5ccee54f1ef58f7bfdbe1063fd09c8 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 3 Aug 2022 12:56:39 -0300 Subject: [PATCH 064/453] =?UTF-8?q?no=20compartir=20el=20uuid=20del=20post?= =?UTF-8?q?=20con=20su=20indexaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aunque los uuid son únicos, en el contexto de un sitio los posts son únicos por cada sitio. si tenemos sitios duplicados (por ejemplo un sitio de testing), la indexación funciona pero va moviendo posts de un panel a otro. ahora los uuid de cada post se guardan por separado y las indexaciones tienen sus propios uuids únicos. por ahora no los estamos usando para nada, pero cuando tengamos permalinks, los registros van a estar relacionados con sus posts indexados. --- app/models/post/indexable.rb | 3 +-- ...53308_indexed_posts_by_uuid_and_site_id.rb | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20220802153308_indexed_posts_by_uuid_and_site_id.rb diff --git a/app/models/post/indexable.rb b/app/models/post/indexable.rb index 7757e7f7..48dc6b0d 100644 --- a/app/models/post/indexable.rb +++ b/app/models/post/indexable.rb @@ -14,9 +14,8 @@ class Post # # @return [IndexedPost] def to_index - IndexedPost.find_or_create_by(id: uuid.value).tap do |indexed_post| + IndexedPost.find_or_create_by(post_id: uuid.value, site_id: site.id).tap do |indexed_post| indexed_post.layout = layout.name - indexed_post.site_id = site.id indexed_post.path = path.basename indexed_post.locale = locale.value indexed_post.dictionary = IndexedPost.to_dictionary(locale: locale.value) diff --git a/db/migrate/20220802153308_indexed_posts_by_uuid_and_site_id.rb b/db/migrate/20220802153308_indexed_posts_by_uuid_and_site_id.rb new file mode 100644 index 00000000..e6572ffb --- /dev/null +++ b/db/migrate/20220802153308_indexed_posts_by_uuid_and_site_id.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# No podemos compartir el uuid entre indexed_posts y posts porque +# podemos tener sitios duplicados. Al menos hasta que los sitios de +# testeo estén integrados en el panel vamos a tener que generar otros +# UUID. +class IndexedPostsByUuidAndSiteId < ActiveRecord::Migration[6.1] + def up + add_column :indexed_posts, :post_id, :uuid, index: true + + IndexedPost.transaction do + ActiveRecord::Base.connection.execute('update indexed_posts set post_id = id where post_id is null') + end + end + + def down + remove_column :indexed_posts, :post_id + end +end From 3e442865ab8d5f7559f5fb42e80dc27eed003647 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 3 Aug 2022 13:11:06 -0300 Subject: [PATCH 065/453] permitir indexar --- app/models/post/indexable.rb | 6 +++--- app/models/site/index.rb | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/app/models/post/indexable.rb b/app/models/post/indexable.rb index 48dc6b0d..4e46d7b2 100644 --- a/app/models/post/indexable.rb +++ b/app/models/post/indexable.rb @@ -14,7 +14,7 @@ class Post # # @return [IndexedPost] def to_index - IndexedPost.find_or_create_by(post_id: uuid.value, site_id: site.id).tap do |indexed_post| + IndexedPost.find_or_initialize_by(post_id: uuid.value, site_id: site.id).tap do |indexed_post| indexed_post.layout = layout.name indexed_post.path = path.basename indexed_post.locale = locale.value @@ -27,8 +27,6 @@ class Post end end - private - # Indexa o reindexa el Post # # @return [Boolean] @@ -40,6 +38,8 @@ class Post to_index.destroy.destroyed? end + private + # Los metadatos que se almacenan como objetos JSON. Empezamos con # las categorías porque se usan para filtrar en el listado de # artículos. diff --git a/app/models/site/index.rb b/app/models/site/index.rb index e10fa523..e11095e3 100644 --- a/app/models/site/index.rb +++ b/app/models/site/index.rb @@ -14,9 +14,7 @@ class Site def index_posts! Site.transaction do - docs.each do |post| - post.to_index.save - end + docs.each(&:index!) end end end From fff679b98184f5ab0ee20e30bb40382f3aed483c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 3 Aug 2022 13:23:03 -0300 Subject: [PATCH 066/453] no devolver un destino closes #7151 closes #7152 closes #7153 closes #7154 closes #7167 closes #7168 closes #7169 closes #7170 closes #7380 closes #7381 closes #7382 closes #7383 closes #7394 closes #7395 closes #7396 closes #7397 closes #7405 closes #7406 closes #7407 closes #7408 closes #7491 closes #7492 closes #7493 closes #7494 closes #7509 closes #7510 closes #7511 closes #7512 closes #7527 closes #7528 closes #7529 closes #7530 --- app/models/deploy_reindex.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/models/deploy_reindex.rb b/app/models/deploy_reindex.rb index 921451d9..d6b2be65 100644 --- a/app/models/deploy_reindex.rb +++ b/app/models/deploy_reindex.rb @@ -30,11 +30,9 @@ class DeployReindex < Deploy 1 end - def hostname - nil - end + def hostname; end - def url - nil - end + def url; end + + def destination; end end From 2d0090c488b2befff5b7eca8b01a8641b2489e4b Mon Sep 17 00:00:00 2001 From: f Date: Wed, 24 Aug 2022 18:00:18 -0300 Subject: [PATCH 067/453] usar el uuid del post para reordenar --- app/views/posts/index.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 90d65670..70748570 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -93,15 +93,15 @@ TODO: Solo les usuaries cachean porque tenemos que separar les botones por permisos. - cache_if @usuarie, [post, I18n.locale] do - - checkbox_id = "checkbox-#{post.id}" - %tr{ id: post.id, data: { target: 'reorder.row' } } + - checkbox_id = "checkbox-#{post.post_id}" + %tr{ id: post.post_id, data: { target: 'reorder.row' } } %td .custom-control.custom-checkbox %input.custom-control-input{ id: checkbox_id, type: 'checkbox', autocomplete: 'off', data: { action: 'reorder#select' } } %label.custom-control-label{ for: checkbox_id } %span.sr-only= t('posts.reorder.select') -# Orden más alto es mayor prioridad - = hidden_field 'post[reorder]', post.id, + = hidden_field 'post[reorder]', post.post_id, value: size - i, data: { reorder: true } %td.w-100{ class: dir } From 0afe4b6aba50264634045b05bee6ecf3ec033425 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 27 Aug 2022 19:30:52 -0300 Subject: [PATCH 068/453] permitir a les usuaries elegir idioma y registrarse con ese --- app/controllers/application_controller.rb | 2 +- app/models/usuarie.rb | 9 +++++++++ app/views/devise/registrations/new.haml | 2 +- app/views/devise/shared/_links.haml | 14 ++++++++------ app/views/layouts/_breadcrumb.haml | 3 +++ 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index acd0134d..823e3264 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -54,7 +54,7 @@ class ApplicationController < ActionController::Base # corresponde con el idioma de los artículos, porque puede querer # traducirlos. def set_locale(&action) - I18n.with_locale(current_locale(include_params: false), &action) + I18n.with_locale(current_locale(include_params: params[:controller].start_with?('devise')), &action) end # Muestra una página 404 diff --git a/app/models/usuarie.rb b/app/models/usuarie.rb index 6de7ba4b..9126885a 100644 --- a/app/models/usuarie.rb +++ b/app/models/usuarie.rb @@ -9,6 +9,8 @@ class Usuarie < ApplicationRecord validates_uniqueness_of :email validates_with EmailAddress::ActiveRecordValidator, field: :email + before_create :lang_from_locale! + has_many :roles has_many :sites, through: :roles @@ -36,4 +38,11 @@ class Usuarie < ApplicationRecord increment_failed_attempts lock_access! if attempts_exceeded? && !access_locked? end + + private + + def lang_from_locale! + binding.pry + self.lang = I18n.locale.to_s + end end diff --git a/app/views/devise/registrations/new.haml b/app/views/devise/registrations/new.haml index cb6ff0d1..21676556 100644 --- a/app/views/devise/registrations/new.haml +++ b/app/views/devise/registrations/new.haml @@ -8,7 +8,7 @@ = form_for(resource, as: resource_name, - url: registration_path(resource_name)) do |f| + url: registration_path(resource_name, params: { locale: params[:locale] })) do |f| = render 'devise/shared/error_messages', resource: resource diff --git a/app/views/devise/shared/_links.haml b/app/views/devise/shared/_links.haml index c182d323..c8a6c041 100644 --- a/app/views/devise/shared/_links.haml +++ b/app/views/devise/shared/_links.haml @@ -1,35 +1,37 @@ %hr/ +- locale = params.permit(:locale) + - if controller_name != 'sessions' - = link_to t('.sign_in'), new_session_path(resource_name) + = link_to t('.sign_in'), new_session_path(resource_name, params: locale) %br/ - if devise_mapping.registerable? && controller_name != 'registrations' - = link_to t('.sign_up'), new_registration_path(resource_name), + = link_to t('.sign_up'), new_registration_path(resource_name, params: locale), class: 'btn btn-lg btn-block btn-success' %br/ - if devise_mapping.recoverable? - unless %w[passwords registrations].include?(controller_name) = link_to t('.forgot_your_password'), - new_password_path(resource_name) + new_password_path(resource_name, params: locale) %br/ - if devise_mapping.confirmable? && controller_name != 'confirmations' = link_to t('.didn_t_receive_confirmation_instructions'), - new_confirmation_path(resource_name) + new_confirmation_path(resource_name, params: locale) %br/ - if devise_mapping.lockable? - if resource_class.unlock_strategy_enabled?(:email) - if controller_name != 'unlocks' = link_to t('.didn_t_receive_unlock_instructions'), - new_unlock_path(resource_name) + new_unlock_path(resource_name, params: locale) %br/ - if devise_mapping.omniauthable? - resource_class.omniauth_providers.each do |provider| = link_to t('.sign_in_with_provider', provider: OmniAuth::Utils.camelize(provider)), - omniauth_authorize_path(resource_name, provider) + omniauth_authorize_path(resource_name, provider, params: locale) %br/ diff --git a/app/views/layouts/_breadcrumb.haml b/app/views/layouts/_breadcrumb.haml index c4920bc7..04375ca4 100644 --- a/app/views/layouts/_breadcrumb.haml +++ b/app/views/layouts/_breadcrumb.haml @@ -22,3 +22,6 @@ %li.nav-item = link_to t('.logout'), destroy_usuarie_session_path, method: :delete, role: 'button', class: 'btn' + - else + - other_locale = I18n.available_locales.find { |locale| locale != I18n.locale } + = link_to t(other_locale), "?locale=#{other_locale}" From 3595342d3a2df840e7b040c50b6151a010fe3f9d Mon Sep 17 00:00:00 2001 From: f Date: Sat, 3 Sep 2022 10:51:58 -0300 Subject: [PATCH 069/453] pry! --- app/models/usuarie.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/usuarie.rb b/app/models/usuarie.rb index 9126885a..605eb819 100644 --- a/app/models/usuarie.rb +++ b/app/models/usuarie.rb @@ -42,7 +42,6 @@ class Usuarie < ApplicationRecord private def lang_from_locale! - binding.pry self.lang = I18n.locale.to_s end end From 44de5227646c3ae0549e863bb5b2c0a9b0918c94 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 5 Oct 2022 18:44:23 -0300 Subject: [PATCH 070/453] soportar distributed press apiv0 #7839 --- app/models/deploy.rb | 15 ++++++++++ app/models/deploy_distributed_press.rb | 34 +++++++++++++++++++++++ app/models/deploy_local.rb | 38 ++++++++++++++++++-------- 3 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 app/models/deploy_distributed_press.rb diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 3f034ad5..c7e83539 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -75,6 +75,13 @@ class Deploy < ApplicationRecord r&.success? end + # Variables de entorno + # + # @return [Hash] + def local_env + @local_env ||= {} + end + private # @param [String] @@ -82,4 +89,12 @@ class Deploy < ApplicationRecord def readable_cmd(cmd) cmd.split(' -', 2).first.tr(' ', '_') end + + def deploy_local + @deploy_local ||= site.deploys.find_by(type: 'DeployLocal') + end + + def non_local_deploys + @non_local_deploys ||= site.deploys.where.not(type: 'DeployLocal') + end end diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb new file mode 100644 index 00000000..51788865 --- /dev/null +++ b/app/models/deploy_distributed_press.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +# Soportar Distributed Press APIv0 +# +# No se realiza ninguna acción porque el deploy se hace desde el plugin +# local. +class DeployDistributedPress < Deploy + store :values, accessors: %i[api_key hostname], coder: JSON + + def deploy; end + + def limit; end + + def size + deploy_local.size + end + + # TODO: Devolver hyper:// y otras + def url + "ipfs://#{hostname}/" + end + + # Devuelve variables de entorno para enviarle a DeployLocal + # + # @return [Hash] + def local_env + { + 'DISTRIBUTED_PRESS_PROJECT_DOMAIN' => hostname, + 'DISTRIBUTED_PRESS_API_KEY' => api_key + } + end + + def destination; end +end diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 4fa588f5..4b22d728 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -50,21 +50,24 @@ class DeployLocal < Deploy 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/bin', '/bin'] - { - '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 - } + # 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 + }) end def yarn_cache_dir @@ -112,4 +115,17 @@ class DeployLocal < Deploy def remove_destination! FileUtils.rm_rf destination end + + # Consigue todas las variables de entorno configuradas por otros + # deploys. + # + # @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 From 6c7ddb082df96249cf0c20b7e021b1ba2e8d48a2 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 1 Nov 2022 13:08:06 -0300 Subject: [PATCH 071/453] fix: no guardar el valor en texto plano si estuvo cifrado MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cuando un campo está cifrado y no fue modificado, al guardar se guardaba en texto plano y luego salían errores de decifrado. closes #1515 closes #1938 closes #1939 closes #1940 closes #1942 closes #1943 closes #1944 closes #8204 --- app/models/metadata_template.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/metadata_template.rb b/app/models/metadata_template.rb index c778e1b2..5de54be1 100644 --- a/app/models/metadata_template.rb +++ b/app/models/metadata_template.rb @@ -134,7 +134,11 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type, # En caso de que algún campo necesite realizar acciones antes de ser # guardado def save - return true unless changed? + if !changed? + self[:value] = document_value if private? + + return true + end self[:value] = sanitize value self[:value] = encrypt(value) if private? From 3d8c9b4031d4290a27c3faaecd02323f6b9c6a77 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 1 Nov 2022 13:17:03 -0300 Subject: [PATCH 072/453] feat: implementar campo de tipo password #8342 --- app/models/metadata_password.rb | 25 +++++++++++++++++++++ app/views/posts/attribute_ro/_password.haml | 6 +++++ app/views/posts/attributes/_password.haml | 7 ++++++ config/locales/en.yml | 2 ++ config/locales/es.yml | 2 ++ 5 files changed, 42 insertions(+) create mode 100644 app/models/metadata_password.rb create mode 100644 app/views/posts/attribute_ro/_password.haml create mode 100644 app/views/posts/attributes/_password.haml diff --git a/app/models/metadata_password.rb b/app/models/metadata_password.rb new file mode 100644 index 00000000..1e0e2698 --- /dev/null +++ b/app/models/metadata_password.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +# Almacena una contraseña +class MetadataPassword < MetadataString + # Las contraseñas no son indexables + # + # @return [boolean] + def indexable? + false + end + + private + + alias_method :original_sanitize, :sanitize + + # Sanitizar la string y generar un hash Bcrypt + # + # @param :string [String] + # @return [String] + def sanitize(string) + string = original_sanitize string + + ::BCrypt::Password.create(string).to_s + end +end diff --git a/app/views/posts/attribute_ro/_password.haml b/app/views/posts/attribute_ro/_password.haml new file mode 100644 index 00000000..e55b021f --- /dev/null +++ b/app/views/posts/attribute_ro/_password.haml @@ -0,0 +1,6 @@ +%tr{ id: attribute } + %th= post_label_t(attribute, post: post) + %td{ dir: dir, lang: locale } + = metadata.value + %br/ + %small= t('.safety') diff --git a/app/views/posts/attributes/_password.haml b/app/views/posts/attributes/_password.haml new file mode 100644 index 00000000..0aace30f --- /dev/null +++ b/app/views/posts/attributes/_password.haml @@ -0,0 +1,7 @@ +.form-group + = label_tag "#{base}_#{attribute}", post_label_t(attribute, post: post) + = password_field base, attribute, value: metadata.value, + dir: dir, lang: locale, + **field_options(attribute, metadata) + = render 'posts/attribute_feedback', + post: post, attribute: attribute, metadata: metadata diff --git a/config/locales/en.yml b/config/locales/en.yml index 530a9381..b9d4d8f9 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -414,6 +414,8 @@ en: attribute_ro: file: download: Download file + password: + safety: Passwords are stored safely show: front_matter: Post metadata submit: diff --git a/config/locales/es.yml b/config/locales/es.yml index eaa23137..b737f5c2 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -422,6 +422,8 @@ es: attribute_ro: file: download: Descargar archivo + password: + safety: Las contraseñas se almacenan de forma segura show: front_matter: Metadatos del artículo submit: From 2dc01cef9c1aedc27a46e4f898fabd216da4e1d1 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 4 Nov 2022 14:13:44 -0300 Subject: [PATCH 073/453] fix: actualizar contenedor a alpine 3.14 #8369 --- .woodpecker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index db2b307d..087b2e90 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -23,6 +23,6 @@ pipeline: event: push matrix: include: - - ALPINE_VERSION: 3.13.10 + - ALPINE_VERSION: 3.14.8 RUBY_VERSION: 2.7 RUBY_PATCH: 6 From f582e692ef784fcea3fd2a264afc324d4c9fb5bb Mon Sep 17 00:00:00 2001 From: f Date: Wed, 9 Nov 2022 18:43:55 -0300 Subject: [PATCH 074/453] =?UTF-8?q?fix:=20explicar=20mejor=20por=20qu?= =?UTF-8?q?=C3=A9=20no=20es=20una=20preview=20completa=20#8400?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 530a9381..ec5171ec 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -475,7 +475,7 @@ en: preview: btn: 'Preliminary version' alert: 'Not every article type has a preliminary version' - message: 'This is a preliminary version, use the Publish changes button back on the panel to publish the article onto your site.' + message: 'This is a preview of your post with some contextual elements from your site.' open: 'Tip: You can add new options by typing them and pressing Enter' private: '🔒 The values of this field will remain private' select: diff --git a/config/locales/es.yml b/config/locales/es.yml index eaa23137..b9f45032 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -483,7 +483,7 @@ es: preview: btn: 'Versión preliminar' alert: 'No todos los tipos de artículos poseen vista preliminar :)' - message: 'Esta es una versión preliminar, para que el artículo aparezca en tu sitio utiliza el botón Publicar cambios en el panel' + message: 'Esta es la vista previa de tu artículo, con algunos elementos contextuales del sitio' open: 'Nota: Puedes agregar más opciones a medida que las escribes y presionas Entrar' private: '🔒 Los valores de este campo serán privados' select: From b141b09ee452aa75e92b5755ffe24b549333a345 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 9 Nov 2022 18:44:27 -0300 Subject: [PATCH 075/453] fix: poder mostrar la vista previa sin errores de liquid closes #8397 closes #8263 closes #8153 --- app/models/post.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/post.rb b/app/models/post.rb index cab7665f..3e824108 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -90,6 +90,10 @@ class Post 'page' => document.to_liquid } + # No tener errores de Liquid + site.jekyll.config['liquid']['strict_filters'] = false + site.jekyll.config['liquid']['strict_variables'] = false + # Renderizar lo estrictamente necesario y convertir a HTML para # poder reemplazar valores. html = Nokogiri::HTML document.renderer.render_document From 5a5d41448237870e5c8c5d1d763b3502d1f56e28 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 11 Nov 2022 19:09:38 -0300 Subject: [PATCH 076/453] =?UTF-8?q?fix:=20traducci=C3=B3n=20de=20algunos?= =?UTF-8?q?=20locales=20en=20uso=20#8427?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/en.yml | 9 +++++++++ config/locales/es.yml | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index 530a9381..a07533a9 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -13,6 +13,15 @@ en: ar: name: Arabic dir: rtl + zh: + name: Chinese + dir: ltr + de: + name: German + dir: ltr + fr: + name: French + dir: ltr login: email: E-mail address password: Password diff --git a/config/locales/es.yml b/config/locales/es.yml index eaa23137..3d6a2e10 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -13,6 +13,15 @@ es: ar: name: Árabe dir: rtl + zh: + name: Chino + dir: ltr + de: + name: Alemán + dir: ltr + fr: + name: Francés + dir: ltr login: email: Correo electrónico password: Contraseña From d05b93d85ef3830e51131a6c09f48f47e2fd164b Mon Sep 17 00:00:00 2001 From: f Date: Fri, 18 Nov 2022 15:56:59 -0300 Subject: [PATCH 077/453] feat: poder modificar la url de distributed press --- app/models/deploy_distributed_press.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 51788865..a24ae62c 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -5,7 +5,7 @@ # No se realiza ninguna acción porque el deploy se hace desde el plugin # local. class DeployDistributedPress < Deploy - store :values, accessors: %i[api_key hostname], coder: JSON + store :values, accessors: %i[api_url api_key hostname], coder: JSON def deploy; end @@ -26,7 +26,8 @@ class DeployDistributedPress < Deploy def local_env { 'DISTRIBUTED_PRESS_PROJECT_DOMAIN' => hostname, - 'DISTRIBUTED_PRESS_API_KEY' => api_key + 'DISTRIBUTED_PRESS_API_KEY' => api_key, + 'DISTRIBUTED_PRESS_API_URL' => api_url } end From 4fc2ece2d5bd7f913559a9a501bd6a724ef01fa4 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 28 Nov 2022 19:30:20 -0300 Subject: [PATCH 078/453] =?UTF-8?q?fix:=20permitir=20borrar=20la=20imagen?= =?UTF-8?q?=20sin=20vaciar=20la=20descripci=C3=B3n=20#8347?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sin embargo no estamos pudiendo distinguir entre imagen borrada e imagen sin subir, con lo que perdimos una verificación --- app/models/metadata_file.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/models/metadata_file.rb b/app/models/metadata_file.rb index c7296de4..e67761b2 100644 --- a/app/models/metadata_file.rb +++ b/app/models/metadata_file.rb @@ -23,7 +23,6 @@ class MetadataFile < MetadataTemplate errors << I18n.t("metadata.#{type}.site_invalid") if site.invalid? errors << I18n.t("metadata.#{type}.path_required") if path_missing? - errors << I18n.t("metadata.#{type}.no_file_for_description") if no_file_for_description? errors << I18n.t("metadata.#{type}.attachment_missing") if path? && !static_file errors.compact! @@ -134,11 +133,6 @@ class MetadataFile < MetadataTemplate end end - # No hay archivo pero se lo describió - def no_file_for_description? - !path? && description? - end - # Obtiene el id del blob asociado # # @return [Integer,nil] From 581e8e10c2af693a9d0b43fc38e398bc12c8b000 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 28 Nov 2022 19:31:09 -0300 Subject: [PATCH 079/453] fix: vaciar la imagen al borrarla --- app/models/metadata_file.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/models/metadata_file.rb b/app/models/metadata_file.rb index e67761b2..a155a414 100644 --- a/app/models/metadata_file.rb +++ b/app/models/metadata_file.rb @@ -42,8 +42,12 @@ class MetadataFile < MetadataTemplate # Asociar la imagen subida al sitio y obtener la ruta # @return [Boolean] def save - value['description'] = sanitize value['description'] - value['path'] = relative_destination_path_with_filename.to_s if static_file + if value['path'].blank? + self[:value] = default_value + else + value['description'] = sanitize value['description'] + value['path'] = relative_destination_path_with_filename.to_s if static_file + end true end From 7e8e47387bda0f4d07d07566fcada290b7fc15cc Mon Sep 17 00:00:00 2001 From: f Date: Tue, 27 Dec 2022 17:35:37 -0300 Subject: [PATCH 080/453] feat: eliminar dependencia en plantillas instaladas #1849 --- Gemfile | 12 ------- Gemfile.lock | 99 ---------------------------------------------------- 2 files changed, 111 deletions(-) diff --git a/Gemfile b/Gemfile index 2b304ee0..f7744b30 100644 --- a/Gemfile +++ b/Gemfile @@ -99,18 +99,6 @@ gem 'net-ssh' gem 'ed25519' gem 'bcrypt_pbkdf' -group :themes do - gem 'adhesiones-jekyll-theme', require: false - gem 'editorial-autogestiva-jekyll-theme', require: false - gem 'minima', require: false - gem 'sutty-minima', require: false - gem 'radios-comunitarias-jekyll-theme', require: false - gem 'share-to-fediverse-jekyll-theme', require: false - gem 'sutty-donaciones-jekyll-theme', require: false - gem 'sutty-jekyll-theme', require: false - gem 'recursero-jekyll-theme', require: false -end - group :production do gem 'lograge' end diff --git a/Gemfile.lock b/Gemfile.lock index 8df2d77e..00520efa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -88,15 +88,6 @@ GEM zeitwerk (~> 2.3) addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) - adhesiones-jekyll-theme (0.2.1) - jekyll (~> 4.0) - jekyll-data (~> 1.1) - jekyll-feed (~> 0.9) - jekyll-images (~> 0.2) - jekyll-include-cache (~> 0) - jekyll-locales (~> 0.1) - jekyll-relative-urls (~> 0.0) - jekyll-seo-tag (~> 2.1) ast (2.4.2) autoprefixer-rails (10.3.3.0) execjs (~> 2) @@ -169,25 +160,6 @@ GEM down (5.2.4) addressable (~> 2.8) ed25519 (1.2.4-x86_64-linux-musl) - editorial-autogestiva-jekyll-theme (0.3.4) - jekyll (~> 4) - jekyll-commonmark (~> 1.3) - jekyll-data (~> 1.1) - jekyll-dotenv (>= 0.2) - jekyll-feed (~> 0.15) - jekyll-hardlinks (~> 0) - jekyll-ignore-layouts (~> 0) - jekyll-images (~> 0.2) - jekyll-include-cache (~> 0) - jekyll-linked-posts (~> 0) - jekyll-locales (~> 0.1) - jekyll-order (~> 0) - jekyll-relative-urls (~> 0) - jekyll-seo-tag (~> 2) - jekyll-spree-client (~> 0) - jekyll-unique-urls (~> 0) - jekyll-write-and-commit-changes (~> 0) - sutty-liquid (~> 0) em-websocket (0.5.3) eventmachine (>= 0.12.9) http_parser.rb (~> 0) @@ -369,10 +341,6 @@ GEM mini_magick (4.11.0) mini_mime (1.1.2) mini_portile2 (2.6.1) - minima (2.5.1) - jekyll (>= 3.5, < 5.0) - jekyll-feed (~> 0.9) - jekyll-seo-tag (~> 2.1) minitest (5.14.4) mobility (1.2.4) i18n (>= 0.6.10, < 2) @@ -415,17 +383,6 @@ GEM rack rack-test (1.1.0) rack (>= 1.0, < 3) - radios-comunitarias-jekyll-theme (0.1.5) - jekyll (~> 4.0) - jekyll-data (~> 1.1) - jekyll-feed (~> 0.9) - jekyll-images (~> 0.2) - jekyll-include-cache (~> 0) - jekyll-linked-posts (~> 0) - jekyll-locales (~> 0.1) - jekyll-relative-urls (~> 0.0) - jekyll-seo-tag (~> 2.1) - jekyll-turbolinks (~> 0) rails (6.1.4.1) actioncable (= 6.1.4.1) actionmailbox (= 6.1.4.1) @@ -462,24 +419,6 @@ GEM rb-fsevent (0.11.0) rb-inotify (0.10.1) ffi (~> 1.0) - recursero-jekyll-theme (0.2.0) - jekyll (~> 4) - jekyll-commonmark (~> 1.3) - jekyll-data (~> 1.1) - jekyll-dotenv (>= 0.2) - jekyll-feed (~> 0.15) - jekyll-ignore-layouts (~> 0) - jekyll-images (~> 0.2) - jekyll-include-cache (~> 0) - jekyll-linked-posts (~> 0) - jekyll-locales (~> 0.1) - jekyll-lunr (~> 0.1) - jekyll-order (~> 0) - jekyll-relative-urls (~> 0) - jekyll-seo-tag (~> 2) - jekyll-unique-urls (~> 0.1) - sutty-archives (~> 2.2) - sutty-liquid (~> 0) redis (4.5.1) redis-actionpack (5.2.0) actionpack (>= 5, < 7) @@ -552,14 +491,6 @@ GEM rubyzip (>= 1.2.2) semantic_range (3.0.0) sexp_processor (4.16.0) - share-to-fediverse-jekyll-theme (0.1.4) - jekyll (~> 4.0) - jekyll-data (~> 1.1) - jekyll-feed (~> 0.9) - jekyll-images (~> 0.2) - jekyll-include-cache (~> 0) - jekyll-relative-urls (~> 0.0) - jekyll-seo-tag (~> 2.1) simpleidn (0.2.1) unf (~> 0.1.4) sourcemap (0.1.1) @@ -583,30 +514,9 @@ GEM concurrent-ruby (~> 1.0) sutty-archives (2.5.4) jekyll (>= 3.6, < 5.0) - sutty-donaciones-jekyll-theme (0.1.2) - jekyll (~> 4.0) - jekyll-data (~> 1.1) - jekyll-feed (~> 0.9) - jekyll-images (~> 0.2) - jekyll-include-cache (~> 0) - jekyll-locales (~> 0.1) - jekyll-relative-urls (~> 0.0) - jekyll-seo-tag (~> 2.1) - sutty-archives (~> 2.2) - sutty-jekyll-theme (0.1.2) - jekyll (~> 4.0) - jekyll-feed (~> 0.9) - jekyll-images (~> 0.2) - jekyll-include-cache (~> 0) - jekyll-relative-urls (~> 0.0) - jekyll-seo-tag (~> 2.1) sutty-liquid (0.7.4) fast_blank (~> 1.0) jekyll (~> 4) - sutty-minima (2.5.0) - jekyll (>= 3.5, < 5.0) - jekyll-feed (~> 0.9) - jekyll-seo-tag (~> 2.1) symbol-fstring (1.0.2-x86_64-linux-musl) sysexits (1.2.0) temple (0.8.2) @@ -654,7 +564,6 @@ PLATFORMS x86_64-linux-musl DEPENDENCIES - adhesiones-jekyll-theme bcrypt (~> 3.1.7) bcrypt_pbkdf blazer @@ -672,7 +581,6 @@ DEPENDENCIES dotenv-rails down ed25519 - editorial-autogestiva-jekyll-theme email_address! exception_notification factory_bot_rails @@ -702,7 +610,6 @@ DEPENDENCIES lograge memory_profiler mini_magick - minima mobility net-ssh nokogiri @@ -714,11 +621,9 @@ DEPENDENCIES pundit rack-cors rack-mini-profiler - radios-comunitarias-jekyll-theme rails (~> 6) rails-i18n rails_warden - recursero-jekyll-theme redis redis-rails rollups! @@ -728,17 +633,13 @@ DEPENDENCIES safe_yaml! sassc-rails selenium-webdriver - share-to-fediverse-jekyll-theme sourcemap spring spring-watcher-listen (~> 2.0.0) sqlite3 stackprof sucker_punch - sutty-donaciones-jekyll-theme - sutty-jekyll-theme sutty-liquid (>= 0.7.3) - sutty-minima symbol-fstring terminal-table timecop From e6068fa7ecbde7826193fa80e44b994a5217e560 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 27 Dec 2022 17:36:32 -0300 Subject: [PATCH 081/453] fix: traer gemas del mismo repositorio --- Gemfile | 4 ++-- Gemfile.lock | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index f7744b30..0f26071b 100644 --- a/Gemfile +++ b/Gemfile @@ -48,9 +48,9 @@ gem 'image_processing' gem 'icalendar' gem 'inline_svg' gem 'httparty' -gem 'safe_yaml', source: 'https://gems.sutty.nl' +gem 'safe_yaml' gem 'jekyll', '~> 4.2' -gem 'jekyll-data', source: 'https://gems.sutty.nl' +gem 'jekyll-data' gem 'jekyll-commonmark' gem 'jekyll-images' gem 'jekyll-include-cache' diff --git a/Gemfile.lock b/Gemfile.lock index 00520efa..db7e601a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -599,7 +599,7 @@ DEPENDENCIES jbuilder (~> 2.5) jekyll (~> 4.2) jekyll-commonmark - jekyll-data! + jekyll-data jekyll-images jekyll-include-cache kaminari @@ -630,7 +630,7 @@ DEPENDENCIES rubocop-rails rubyzip rugged - safe_yaml! + safe_yaml sassc-rails selenium-webdriver sourcemap From 072b01e4d94e5a22c1d5646bfc63cd25c1affedf Mon Sep 17 00:00:00 2001 From: f Date: Tue, 27 Dec 2022 17:37:47 -0300 Subject: [PATCH 082/453] fix: siempre instalar las gemas localmente --- app/models/deploy_local.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 4fa588f5..88b84930 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -91,11 +91,7 @@ class DeployLocal < Deploy end def bundle - if Rails.env.production? run %(bundle install --no-cache --path="#{gems_dir}") - else - run %(bundle install) - end end def jekyll_build From 47f1a8e530053b81e5978f36f71763fd4e822228 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 27 Dec 2022 17:42:00 -0300 Subject: [PATCH 083/453] feat: leer datos de las plantillas directamente #1849 usando el lockfile de cada repositorio, acceder directamente al directorio de datos usando jekyll-data. --- app/models/site.rb | 22 +++--------- config/initializers/core_extensions.rb | 47 ++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 18 deletions(-) diff --git a/app/models/site.rb b/app/models/site.rb index 638b3f47..5dee0b85 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -335,7 +335,10 @@ class Site < ApplicationRecord def jekyll run_in_path do - @jekyll ||= Jekyll::Site.new(configuration) + @jekyll ||= + Jekyll::Site.new(configuration).tap do |site| + site.reader = JekyllData::Reader.new(site) if site.theme + end end end @@ -382,9 +385,6 @@ class Site < ApplicationRecord @configuration[unneeded] = [] if @configuration.key? unneeded end - # Eliminar el theme si no es una gema válida - @configuration.delete('theme') unless theme_available? - # Si estamos usando nuestro propio plugin de i18n, los posts están # en "colecciones" locales.map(&:to_s).each do |i| @@ -394,20 +394,6 @@ class Site < ApplicationRecord @configuration end - # Lista los nombres de las plantillas disponibles como gemas, - # tomándolas dinámicamente de las que agreguemos en el grupo :themes - # del Gemfile. - def available_themes - @available_themes ||= Bundler.load.current_dependencies.select do |gem| - gem.groups.include? :themes - end.map(&:name) - end - - # Detecta si el tema actual es una gema - def theme_available? - available_themes.include? design&.gem - end - # Devuelve el dominio actual def self.domain ENV.fetch('SUTTY', 'sutty.nl') diff --git a/config/initializers/core_extensions.rb b/config/initializers/core_extensions.rb index 66d2c92b..1516a43a 100644 --- a/config/initializers/core_extensions.rb +++ b/config/initializers/core_extensions.rb @@ -37,6 +37,13 @@ end # # TODO: Aplicar monkey patches en otro lado... module Jekyll + Site.class_eval do + def configure_theme + self.theme = nil + self.theme = Jekyll::Theme.new(config['theme'], self) unless config['theme'].nil? + end + end + Reader.class_eval do # No necesitamos otros posts def retrieve_posts(_); end @@ -69,6 +76,46 @@ module Jekyll end end + Theme.class_eval do + attr_reader :site + + def initialize(name, site) + @name = name.downcase.strip + @site = site + end + + def root + @root ||= begin + lockfile = Bundler::LockfileParser.new(File.read(site.in_source_dir('Gemfile.lock'))) + spec = lockfile.specs.find do |spec| + spec.name == name + end + + ruby_version = Gem::Version.new(RUBY_VERSION) + ruby_version.canonical_segments[2] = 0 + base_path = Rails.root.join('_storage', 'gems', File.basename(site.source), 'ruby', + ruby_version.canonical_segments.join('.')) + + File.realpath( + case spec.source + when Bundler::Source::Git + File.join(base_path, 'bundler', 'gems', spec.source.extension_dir_name) + when Bundler::Source::Rubygems + File.join(base_path, 'gems', spec.full_name) + end + ) + end + end + + def runtime_dependencies + [] + end + + private + + def gemspec; end + end + # No necesitamos los archivos de la plantilla ThemeAssetsReader.class_eval do def read; end From e258e6e2d9928a8d721bdbfc991f5c390bf46327 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 27 Dec 2022 18:41:36 -0300 Subject: [PATCH 084/453] =?UTF-8?q?fix:=20asegurarse=20que=20las=20gemas?= =?UTF-8?q?=20est=C3=A1n=20instaladas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/site.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/models/site.rb b/app/models/site.rb index 5dee0b85..dfc4f034 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -56,8 +56,8 @@ class Site < ApplicationRecord before_destroy :remove_directories! # Carga el sitio Jekyll una vez que se inicializa el modelo o después # de crearlo - after_initialize :load_jekyll - after_create :load_jekyll + after_initialize :install_gems, :load_jekyll + after_create :install_gems, :load_jekyll # Cambiar el nombre del directorio before_update :update_name! before_save :add_private_key_if_missing! @@ -515,4 +515,11 @@ class Site < ApplicationRecord def run_in_path(&block) Dir.chdir path, &block end + + def install_gems + return unless persisted? + return if Rails.root.join('_storage', 'gems', name).directory? + + deploys.find_by_type('DeployLocal').send(:bundle) + end end From 3ec546eb82890490ad761014a23c6ea157c9fe1d Mon Sep 17 00:00:00 2001 From: f Date: Thu, 29 Dec 2022 14:55:30 -0300 Subject: [PATCH 085/453] fix: dependencias faltantes --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ac90a548..871e6fb0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ ENV RAILS_ENV production # principal RUN apk add --no-cache libxslt libxml2 postgresql-libs libssh2 \ rsync git jpegoptim vips tectonic oxipng git-lfs openssh-client \ - yarn daemonize ruby-webrick + yarn daemonize ruby-webrick postgresql-client dateutils file RUN gem install --no-document --no-user-install foreman RUN wget https://github.com/jgm/pandoc/releases/download/${PANDOC_VERSION}/pandoc-${PANDOC_VERSION}-linux-amd64.tar.gz -O - | tar --strip-components 1 -xvzf - pandoc-${PANDOC_VERSION}/bin/pandoc && mv /bin/pandoc /usr/bin/pandoc From a265caad9770a76b5c4c0091e889f0bcb4ea34ef Mon Sep 17 00:00:00 2001 From: f Date: Thu, 29 Dec 2022 16:38:17 -0300 Subject: [PATCH 086/453] feat: eliminar archivos que no se usan de las gemas para liberar espacio --- app/models/deploy_local.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 88b84930..5bee9ff5 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -92,6 +92,11 @@ class DeployLocal < Deploy def bundle run %(bundle install --no-cache --path="#{gems_dir}") + + # Eliminar archivos que no se usan + Dir.glob("#{gems_dir}/ruby/2.7.0/{cache/*,gems/*/{spec,test,ext,vendor}}").each do |dir| + FileUtils.rm_rf(dir) + end end def jekyll_build From d896a111b8128ff24be33b6233f8c85bd5ffdd0a Mon Sep 17 00:00:00 2001 From: f Date: Fri, 30 Dec 2022 10:55:10 -0300 Subject: [PATCH 087/453] fix: no cargar el sitio hasta que no se usen los posts --- app/models/site.rb | 6 +++++- app/views/sites/index.haml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/models/site.rb b/app/models/site.rb index dfc4f034..ac290403 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -333,6 +333,10 @@ class Site < ApplicationRecord status == 'building' end + def jekyll? + File.directory? path + end + def jekyll run_in_path do @jekyll ||= @@ -432,7 +436,7 @@ class Site < ApplicationRecord # Clona el esqueleto de Sutty para crear el sitio nuevo, no pasa nada # si el sitio ya existe def clone_skel! - return if File.directory? path + return if jekyll? Rugged::Repository.clone_at ENV['SKEL_SUTTY'], path end diff --git a/app/views/sites/index.haml b/app/views/sites/index.haml index d69dbeac..56178775 100644 --- a/app/views/sites/index.haml +++ b/app/views/sites/index.haml @@ -14,7 +14,7 @@ %table.table.table-condensed %tbody - @sites.each do |site| - - next unless site.jekyll + - next unless site.jekyll? - rol = current_usuarie.rol_for_site(site) -# TODO: Solo les usuaries cachean porque tenemos que separar From f35f4c0f065196efe273ab2be70636545e9d4bea Mon Sep 17 00:00:00 2001 From: f Date: Fri, 30 Dec 2022 10:56:00 -0300 Subject: [PATCH 088/453] fix: cargar jekyll cuando realmente se lo usa --- app/models/site.rb | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/app/models/site.rb b/app/models/site.rb index ac290403..f38500eb 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -54,10 +54,6 @@ class Site < ApplicationRecord before_create :clone_skel! # Elimina el directorio al destruir un sitio before_destroy :remove_directories! - # Carga el sitio Jekyll una vez que se inicializa el modelo o después - # de crearlo - after_initialize :install_gems, :load_jekyll - after_create :install_gems, :load_jekyll # Cambiar el nombre del directorio before_update :update_name! before_save :add_private_key_if_missing! @@ -338,12 +334,14 @@ class Site < ApplicationRecord end def jekyll - run_in_path do - @jekyll ||= + @jekyll ||= + begin + install_gems + Jekyll::Site.new(configuration).tap do |site| site.reader = JekyllData::Reader.new(site) if site.theme end - end + end end # Cargar el sitio Jekyll From aaaa1ad7b22943d3335ca8b1e5a3ece44d906134 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 2 Jan 2023 17:07:51 -0300 Subject: [PATCH 089/453] =?UTF-8?q?fix:=20enviar=20el=20per=C3=ADodo=20com?= =?UTF-8?q?o=20par=C3=A1metros=20del=20formulario=20#9359?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/stats/index.haml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/stats/index.haml b/app/views/stats/index.haml index 49fbd023..88e86aa3 100644 --- a/app/views/stats/index.haml +++ b/app/views/stats/index.haml @@ -27,6 +27,8 @@ %p.lead= t('.urls.description') %form{ method: 'get', action: '#custom-urls' } %input{ type: 'hidden', name: 'interval', value: @interval } + %input{ type: 'hidden', name: 'period_start', value: params[:period_start] } + %input{ type: 'hidden', name: 'period_end', value: params[:period_end] } .form-group %label{ for: 'urls' }= t('.urls.label') %textarea#urls.form-control{ name: 'urls', autocomplete: 'on', required: true, rows: @normalized_urls.size + 1, aria_describedby: 'help-urls' }= @normalized_urls.join("\n") From 53b11cba155e4cef51dd5e0801220c5112eae318 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 11 Jan 2023 16:54:45 -0300 Subject: [PATCH 090/453] fix: no devolver 'true' si no existe el archivo closes #9380 closes #9379 closes #9375 closes #9374 closes #9366 closes #8888 closes #8765 closes #8764 closes #8674 closes #8099 closes #8098 closes #7845 closes #7844 closes #7612 closes #7611 closes #9378 closes #9377 closes #9364 closes #9362 --- app/models/metadata_file.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/models/metadata_file.rb b/app/models/metadata_file.rb index a155a414..a55549cb 100644 --- a/app/models/metadata_file.rb +++ b/app/models/metadata_file.rb @@ -122,10 +122,17 @@ class MetadataFile < MetadataTemplate Pathname.new(value['path']) end + # Obtener la ruta relativa al sitio. + # + # Si algo falla, devolver la ruta original para no romper el archivo. + # + # @return [String, nil] def relative_destination_path_with_filename destination_path_with_filename.relative_path_from(Pathname.new(site.path).realpath) rescue ArgumentError => e ExceptionNotifier.notify_exception(e, data: { site: site.name, path: value['path'] }) + + value['path'] end def static_file_path From 5117ffbce3e41ee3315803e25cf3d2f05c8259a9 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 11 Jan 2023 17:04:22 -0300 Subject: [PATCH 091/453] fix: siempre devolver la ruta completa closes #6984 closes #7053 closes #7807 closes #7998 closes #8262 closes #8690 closes #8887 closes #9363 closes #9376 --- app/models/metadata_file.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/metadata_file.rb b/app/models/metadata_file.rb index a55549cb..3ac89c9b 100644 --- a/app/models/metadata_file.rb +++ b/app/models/metadata_file.rb @@ -119,7 +119,7 @@ class MetadataFile < MetadataTemplate rescue Errno::ENOENT => e ExceptionNotifier.notify_exception(e, data: { site: site.name, path: value['path'] }) - Pathname.new(value['path']) + Pathname.new(File.join(site.path, value['path'])) end # Obtener la ruta relativa al sitio. From 2352ce52ec4ee784ca5e1b82859e7070e0c06871 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 12 Jan 2023 13:40:43 -0300 Subject: [PATCH 092/453] fix: no filtrar la url del panel en sitios proxeados #9386 --- app/controllers/api/v1/notices_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/v1/notices_controller.rb b/app/controllers/api/v1/notices_controller.rb index cd44130c..436c78b5 100644 --- a/app/controllers/api/v1/notices_controller.rb +++ b/app/controllers/api/v1/notices_controller.rb @@ -15,7 +15,7 @@ module Api params: airbrake_params.to_h end - render status: 201, json: { id: 1, url: root_url } + render status: 201, json: { id: 1, url: '' } end private From 247e069f2b3a7bc7907f2c388467f0c8d8d082cc Mon Sep 17 00:00:00 2001 From: f Date: Thu, 12 Jan 2023 14:24:21 -0300 Subject: [PATCH 093/453] fix: fast_jsonparser 0.6.0 da segfaults #9386 --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 1e476dde..6ecb7456 100644 --- a/Gemfile +++ b/Gemfile @@ -89,7 +89,7 @@ gem 'stackprof' gem 'prometheus_exporter' # debug -gem 'fast_jsonparser' +gem 'fast_jsonparser', '~> 0.5.0' gem 'down' gem 'sourcemap' gem 'rack-cors' From 5da4c796e0e9fc3afe0767822e4ed6b78d5feb7c Mon Sep 17 00:00:00 2001 From: Maki Date: Tue, 17 Jan 2023 18:31:54 -0300 Subject: [PATCH 094/453] agrego toggler para distributed press --- app/models/site.rb | 2 +- .../deploys/_deploy_distributed_press.haml | 21 +++++++++++++++++++ config/locales/en.yml | 4 ++++ config/locales/es.yml | 4 ++++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 app/views/deploys/_deploy_distributed_press.haml diff --git a/app/models/site.rb b/app/models/site.rb index 638b3f47..fc012d7d 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -17,7 +17,7 @@ class Site < ApplicationRecord # 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].freeze + DEPLOYS = %i[local private www zip hidden_service distributed_press].freeze validates :name, uniqueness: true, hostname: { allow_root_label: true diff --git a/app/views/deploys/_deploy_distributed_press.haml b/app/views/deploys/_deploy_distributed_press.haml new file mode 100644 index 00000000..d7d54db0 --- /dev/null +++ b/app/views/deploys/_deploy_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', public_url: deploy.object.site.url), + tags: %w[p strong em a] + + +%hr/ diff --git a/config/locales/en.yml b/config/locales/en.yml index 530a9381..e7fb4f76 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -248,6 +248,10 @@ en: Only accessible through [Tor Browser](https://www.torproject.org/download/) + deploy_distributed_press: + title: 'Publish on Distributed Press' + help: | + ipfs stats: index: title: Statistics diff --git a/config/locales/es.yml b/config/locales/es.yml index eaa23137..18cf5326 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -253,6 +253,10 @@ es: Sólo será accesible a través del [Navegador Tor](https://www.torproject.org/es/download/). + deploy_distributed_press: + title: 'Alojar en la web distribuida' + help: | + Es para que esté en la web distribuida stats: index: title: Estadísticas From 67c0b29029d5f8731f0eb82c6b2c8c7d02e333e7 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 20 Jan 2023 18:22:08 -0300 Subject: [PATCH 095/453] feat: almacenar y renovar tokens de distributed press --- Gemfile | 1 + Gemfile.lock | 40 ++++++++++- Procfile | 1 + .../renew_distributed_press_tokens_job.rb | 17 +++++ app/models/distributed_press_publisher.rb | 68 +++++++++++++++++++ ...5420_create_distributed_press_publisher.rb | 14 ++++ lib/tasks/distributed_press.rake | 10 +++ monit.conf | 5 ++ 8 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 app/jobs/renew_distributed_press_tokens_job.rb create mode 100644 app/models/distributed_press_publisher.rb create mode 100644 db/migrate/20230119165420_create_distributed_press_publisher.rb create mode 100644 lib/tasks/distributed_press.rake diff --git a/Gemfile b/Gemfile index 2b304ee0..f317487b 100644 --- a/Gemfile +++ b/Gemfile @@ -38,6 +38,7 @@ gem 'commonmarker' gem 'devise' gem 'devise-i18n' gem 'devise_invitable' +gem 'distributed-press-api-client', '~> 0.2.0' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'exception_notification' gem 'fast_blank' diff --git a/Gemfile.lock b/Gemfile.lock index 8df2d77e..cdfe7183 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -124,6 +124,7 @@ GEM xpath (>= 2.0, < 4.0) chartkick (4.1.2) childprocess (4.1.0) + climate_control (1.2.0) coderay (1.1.3) colorator (1.1.0) commonmarker (0.21.2-x86_64-linux-musl) @@ -162,12 +163,45 @@ GEM devise_invitable (2.0.5) actionmailer (>= 5.0) devise (>= 4.6) + distributed-press-api-client (0.2.0) + addressable (~> 2.3, >= 2.3.0) + climate_control + dry-schema + httparty (~> 0.18) + json (~> 2.1, >= 2.1.0) + jwt (~> 2.6.0) dotenv (2.7.6) dotenv-rails (2.7.6) dotenv (= 2.7.6) railties (>= 3.2) down (5.2.4) addressable (~> 2.8) + dry-configurable (1.0.1) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-core (1.0.0) + concurrent-ruby (~> 1.0) + zeitwerk (~> 2.6) + dry-inflector (1.0.0) + dry-initializer (3.1.1) + dry-logic (1.5.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-schema (1.13.0) + concurrent-ruby (~> 1.0) + dry-configurable (~> 1.0, >= 1.0.1) + dry-core (~> 1.0, < 2) + dry-initializer (~> 3.0) + dry-logic (>= 1.5, < 2) + dry-types (>= 1.7, < 2) + zeitwerk (~> 2.6) + dry-types (1.7.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + dry-inflector (~> 1.0, < 2) + dry-logic (>= 1.4, < 2) + zeitwerk (~> 2.6) ed25519 (1.2.4-x86_64-linux-musl) editorial-autogestiva-jekyll-theme (0.3.4) jekyll (~> 4) @@ -244,8 +278,8 @@ GEM thor hiredis (0.6.3-x86_64-linux-musl) http_parser.rb (0.8.0-x86_64-linux-musl) - httparty (0.18.1) - mime-types (~> 3.0) + httparty (0.21.0) + mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) i18n (1.8.11) concurrent-ruby (~> 1.0) @@ -320,6 +354,7 @@ GEM jekyll-write-and-commit-changes (0.2.1) jekyll (~> 4) rugged (~> 1) + jwt (2.6.0) kaminari (1.2.1) activesupport (>= 4.1.0) kaminari-actionview (= 1.2.1) @@ -669,6 +704,7 @@ DEPENDENCIES devise devise-i18n devise_invitable + distributed-press-api-client (~> 0.2.0) dotenv-rails down ed25519 diff --git a/Procfile b/Procfile index b308ffd5..1a4580d3 100644 --- a/Procfile +++ b/Procfile @@ -5,3 +5,4 @@ blazer_1h: bundle exec rake blazer:run_checks SCHEDULE="1 hour" blazer_1d: bundle exec rake blazer:run_checks SCHEDULE="1 day" blazer: bundle exec rake blazer:send_failing_checks prometheus: bundle exec prometheus_exporter -b 0.0.0.0 --prefix "sutty_" +distributed_press_renew_tokens: bundle exec rake distributed_press:tokens:renew diff --git a/app/jobs/renew_distributed_press_tokens_job.rb b/app/jobs/renew_distributed_press_tokens_job.rb new file mode 100644 index 00000000..5664d9fa --- /dev/null +++ b/app/jobs/renew_distributed_press_tokens_job.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# Renueva los tokens de Distributed Press antes que se venzan, +# activando los callbacks que hacen que se refresque el token. +class RenewDistributedPressTokensJob < ApplicationJob + # Renueva todos los tokens a punto de vencer o informa el error sin + # detener la tarea si algo pasa. + def perform + DistributedPressPublisher.with_about_to_expire_tokens.find_each do |publisher| + publisher.touch + rescue DistributedPress::V1::Error => e + data = { instance: publisher.instance, expires_at: publisher.client.token.expires_at } + + ExceptionNotifier.notify_exception(e, data: data) + end + end +end diff --git a/app/models/distributed_press_publisher.rb b/app/models/distributed_press_publisher.rb new file mode 100644 index 00000000..c120811e --- /dev/null +++ b/app/models/distributed_press_publisher.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require 'distributed_press/v1' + +# Almacena el token de autenticación y la URL, por ahora solo vamos +# a tener uno, pero queda abierta la posibilidad de agregar más. +class DistributedPressPublisher < ApplicationRecord + # Cifrar la información del token en la base de datos + has_encrypted :token + + # La instancia es única + validates_uniqueness_of :instance + + # El token es necesario + validates_presence_of :token + + # Mantener la fecha de vencimiento actualizada + before_save :update_expires_at_from_token!, :update_token_from_client! + + # Devuelve todos los tokens que vencen en una hora + scope :with_about_to_expire_tokens, -> do + where('expires_at > ? and expires_at < ?', Time.now, Time.now + 1.hour) + end + + # Al cambiar el token genera un cliente nuevo + # + # @return [String] + def token=(new_token) + @client = nil + super + end + + # Al cambiar la instancia genera un cliente nuevo + # + # @return [String] + def instance=(new_instance) + @client = nil + super + end + + # Instancia un cliente de Distributed Press a partir del token. Al + # cargar un token a punto de vencer se renueva automáticamente. + # + # @return [DistributedPress::V1::Client] + def client + @client ||= DistributedPress::V1::Client.new(url: instance, token: token) + end + + private + + # Actualiza o desactiva la fecha de vencimiento a partir de la + # información del token. + # + # @return [nil] + def update_expires_at_from_token! + self.expires_at = client.token.forever? ? nil : client.token.expires_at + nil + end + + # Actualiza el token a partir del cliente, que ya actualiza el token + # automáticamente. + # + # @return [nil] + def update_token_from_client! + self.token = client.token.to_s + nil + end +end diff --git a/db/migrate/20230119165420_create_distributed_press_publisher.rb b/db/migrate/20230119165420_create_distributed_press_publisher.rb new file mode 100644 index 00000000..8d8de37a --- /dev/null +++ b/db/migrate/20230119165420_create_distributed_press_publisher.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Crea la tabla de publishers de Distributed Press que contiene las +# instancias y tokens +class CreateDistributedPressPublisher < ActiveRecord::Migration[6.1] + def change + create_table :distributed_press_publishers do |t| + t.timestamps + t.string :instance, unique: true + t.text :token_ciphertext, null: false + t.datetime :expires_at, null: true + end + end +end diff --git a/lib/tasks/distributed_press.rake b/lib/tasks/distributed_press.rake new file mode 100644 index 00000000..8ba270ec --- /dev/null +++ b/lib/tasks/distributed_press.rake @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +namespace :distributed_press do + namespace :tokens do + desc 'Renew tokens' + task renew: :environment do + RenewDistributedPressTokensJob.perform_now + end + end +end diff --git a/monit.conf b/monit.conf index 96c08d8a..b785964d 100644 --- a/monit.conf +++ b/monit.conf @@ -25,3 +25,8 @@ check program blazer with path "/usr/local/bin/sutty blazer" every 61 cycles if status != 0 then alert + +check program distributed_press_tokens_renew + with path "/usr/bin/foreman run -f /srv/Procfile -d /srv distributed_press_tokens_renew" as uid "rails" gid "www-data" + every "0 3 * * *" + if status != 0 then alert From cbf7b5892746b544668c6043915da783a13b00d0 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 20 Jan 2023 18:28:29 -0300 Subject: [PATCH 096/453] fixup! feat: almacenar y renovar tokens de distributed press --- app/models/distributed_press_publisher.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/distributed_press_publisher.rb b/app/models/distributed_press_publisher.rb index c120811e..610d698d 100644 --- a/app/models/distributed_press_publisher.rb +++ b/app/models/distributed_press_publisher.rb @@ -18,9 +18,9 @@ class DistributedPressPublisher < ApplicationRecord before_save :update_expires_at_from_token!, :update_token_from_client! # Devuelve todos los tokens que vencen en una hora - scope :with_about_to_expire_tokens, -> do + scope :with_about_to_expire_tokens, lambda { where('expires_at > ? and expires_at < ?', Time.now, Time.now + 1.hour) - end + } # Al cambiar el token genera un cliente nuevo # From 932355fa2e331ac7e4bf142e21b1b879aa161a39 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 20 Jan 2023 20:34:27 -0300 Subject: [PATCH 097/453] feat: crear y publicar el sitio en distributed press v1 --- app/models/deploy_distributed_press.rb | 143 ++++++++++++++++++---- app/models/distributed_press_publisher.rb | 5 + 2 files changed, 125 insertions(+), 23 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index a24ae62c..09ba0364 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -1,13 +1,43 @@ # frozen_string_literal: true -# Soportar Distributed Press APIv0 -# -# No se realiza ninguna acción porque el deploy se hace desde el plugin -# local. -class DeployDistributedPress < Deploy - store :values, accessors: %i[api_url api_key hostname], coder: JSON +require 'distributed_press/v1/client/auth' +require 'distributed_press/v1/client/site' - def deploy; end +# Soportar Distributed Press APIv1 +# +# Usa tokens de publicación efímeros para todas las acciones. +# +# Al ser creado, genera el sitio en la instancia de Distributed Press +# configurada y almacena el ID. +# +# Al ser publicado, envía los archivos en un tarball y actualiza la +# información. +class DeployDistributedPress < Deploy + store :values, accessors: %i[hostname remote_site_id remote_info], coder: JSON + + before_create :create_remote_site! + + # Actualiza la información y luego envía los cambios + # + # @param :output [Bool] + # @return [Bool] + def deploy + time_start + + status = false + + site_client.tap do |c| + update remote_info: c.show(publishing_site).to_h + + status = c.publish(publishing_site, deploy_local.destination) + end + + time_stop + + create_stat! status + + status + end def limit; end @@ -15,21 +45,88 @@ class DeployDistributedPress < Deploy deploy_local.size end - # TODO: Devolver hyper:// y otras - def url - "ipfs://#{hostname}/" - end - - # Devuelve variables de entorno para enviarle a DeployLocal - # - # @return [Hash] - def local_env - { - 'DISTRIBUTED_PRESS_PROJECT_DOMAIN' => hostname, - 'DISTRIBUTED_PRESS_API_KEY' => api_key, - 'DISTRIBUTED_PRESS_API_URL' => api_url - } - end - def destination; end + + private + + # El cliente de la API + # + # TODO: cuando soportemos más, tiene que haber una relación entre + # DeployDistributedPress y DistributedPressPublisher. + # + # @return [DistributedPressPublisher] + def publisher + @publisher ||= DistributedPressPublisher.first + end + + # El cliente de autenticación se encarga de intercambiar un token por + # otro + # + # @return [DistributedPress::V1::Client::Auth] + def auth_client + DistributedPress::V1::Client::Auth.new(publisher.client) + end + + # Genera un token con permisos de publicación + # + # @return [DistributedPress::V1::Schemas::NewTokenPayload] + def publishing_token_payload + DistributedPress::V1::Schemas::NewTokenPayload.new.call(capabilities: %w[publisher]) + end + + # Genera un token efímero para publicar el sitio + # + # @return [DistributedPress::V1::Token] + def publishing_token + auth_client.exchange(publishing_token_payload) + end + + # Genera un cliente para publicar el sitio + # + # @return [DistributedPress::V1::Client] + def publishing_client + DistributedPress::V1::Client.new(url: publisher.instance, token: publishing_token) + end + + # El cliente para actualizar el sitio + # + # @return [DistributedPress::V1::Client::Site] + def site_client + DistributedPress::V1::Client::Site.new(publishing_client) + end + + # Genera el esquema de datos para poder publicar el sitio + # + # @return [DistributedPress::V1::Schemas::PublishingSite] + def publishing_site + DistributedPress::V1::Schemas::PublishingSite.new.call(id: remote_site_id) + end + + # Genera el esquema de datos para crear el sitio + # + # @return [DistributedPressPublisher::V1::Schemas::NewSite] + def create_site + DistributedPress::V1::Schemas::NewSite.new.call(domain: hostname, protocols: { http: true, ipfs: true, hyper: true }) + end + + # Crea el sitio en la instancia con el hostname especificado + # + # @return [nil] + def create_remote_site! + created_site = site_client.create(create_site) + + self.remote_site_id = created_site[:id] + self.remote_info = created_site.to_h + + nil + end + + # Registra lo que sucedió + # + # @param status [Bool] + # @return [nil] + def create_stat!(status) + build_stats.create action: publisher.to_s, seconds: time_spent_in_seconds, bytes: size, status: status + nil + end end diff --git a/app/models/distributed_press_publisher.rb b/app/models/distributed_press_publisher.rb index 610d698d..5358e738 100644 --- a/app/models/distributed_press_publisher.rb +++ b/app/models/distributed_press_publisher.rb @@ -46,6 +46,11 @@ class DistributedPressPublisher < ApplicationRecord @client ||= DistributedPress::V1::Client.new(url: instance, token: token) end + # @return [String] + def to_s + "Distributed Press <#{instance}>" + end + private # Actualiza o desactiva la fecha de vencimiento a partir de la From 8006bd03538dee1285ef7746db382958b6cabce7 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 20 Jan 2023 20:35:39 -0300 Subject: [PATCH 098/453] fix: permitir modificar el token estos parches hacian que no se pueda modificar el token --- app/models/distributed_press_publisher.rb | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/app/models/distributed_press_publisher.rb b/app/models/distributed_press_publisher.rb index 5358e738..acfc4226 100644 --- a/app/models/distributed_press_publisher.rb +++ b/app/models/distributed_press_publisher.rb @@ -22,22 +22,6 @@ class DistributedPressPublisher < ApplicationRecord where('expires_at > ? and expires_at < ?', Time.now, Time.now + 1.hour) } - # Al cambiar el token genera un cliente nuevo - # - # @return [String] - def token=(new_token) - @client = nil - super - end - - # Al cambiar la instancia genera un cliente nuevo - # - # @return [String] - def instance=(new_instance) - @client = nil - super - end - # Instancia un cliente de Distributed Press a partir del token. Al # cargar un token a punto de vencer se renueva automáticamente. # From b28d7946460d8bed6400a6f13d6f0911a12a8f53 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 23 Jan 2023 18:39:10 -0300 Subject: [PATCH 099/453] =?UTF-8?q?feat:=20no=20vamos=20a=20expedir=20toke?= =?UTF-8?q?ns=20ef=C3=ADmeros=20por=20ahora?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_distributed_press.rb | 31 +------------------------- 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 09ba0364..38cb59e3 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -59,40 +59,11 @@ class DeployDistributedPress < Deploy @publisher ||= DistributedPressPublisher.first end - # El cliente de autenticación se encarga de intercambiar un token por - # otro - # - # @return [DistributedPress::V1::Client::Auth] - def auth_client - DistributedPress::V1::Client::Auth.new(publisher.client) - end - - # Genera un token con permisos de publicación - # - # @return [DistributedPress::V1::Schemas::NewTokenPayload] - def publishing_token_payload - DistributedPress::V1::Schemas::NewTokenPayload.new.call(capabilities: %w[publisher]) - end - - # Genera un token efímero para publicar el sitio - # - # @return [DistributedPress::V1::Token] - def publishing_token - auth_client.exchange(publishing_token_payload) - end - - # Genera un cliente para publicar el sitio - # - # @return [DistributedPress::V1::Client] - def publishing_client - DistributedPress::V1::Client.new(url: publisher.instance, token: publishing_token) - end - # El cliente para actualizar el sitio # # @return [DistributedPress::V1::Client::Site] def site_client - DistributedPress::V1::Client::Site.new(publishing_client) + DistributedPress::V1::Client::Site.new(publisher.client) end # Genera el esquema de datos para poder publicar el sitio From ebf1390bdf962c49f2fab7a914a3944060c0c461 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 26 Jan 2023 15:41:54 -0300 Subject: [PATCH 100/453] fix: actualizar api --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index cdfe7183..534ad298 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -163,7 +163,7 @@ GEM devise_invitable (2.0.5) actionmailer (>= 5.0) devise (>= 4.6) - distributed-press-api-client (0.2.0) + distributed-press-api-client (0.2.1) addressable (~> 2.3, >= 2.3.0) climate_control dry-schema From 928bc45920cfbf10a46e088ccbbcece043d24dd5 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 6 Feb 2023 16:09:51 -0300 Subject: [PATCH 101/453] feat: usar pnpm si existe relacionado con sutty/jekyll/sutty-base-jekyll-theme#53 --- Dockerfile | 2 ++ app/models/deploy_local.rb | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Dockerfile b/Dockerfile index ecf43cbc..b2f96612 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,6 +15,8 @@ RUN apk add --no-cache libxslt libxml2 postgresql-libs libssh2 \ RUN gem install --no-document --no-user-install foreman RUN wget https://github.com/jgm/pandoc/releases/download/${PANDOC_VERSION}/pandoc-${PANDOC_VERSION}-linux-amd64.tar.gz -O - | tar --strip-components 1 -xvzf - pandoc-${PANDOC_VERSION}/bin/pandoc && mv /bin/pandoc /usr/bin/pandoc +RUN apk add npm && npm install -g pnpm && apk del npm + VOLUME "/srv" EXPOSE 3000 diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 4b22d728..51baf492 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -15,6 +15,7 @@ class DeployLocal < Deploy def deploy return false unless mkdir return false unless yarn + return false unless pnpm return false unless bundle jekyll_build @@ -74,6 +75,10 @@ class DeployLocal < Deploy Rails.root.join('_yarn_cache').to_s end + def pnpm_cache_dir + Rails.root.join('_pnpm_cache').to_s + end + def yarn_lock File.join(site.path, 'yarn.lock') end @@ -82,6 +87,14 @@ class DeployLocal < Deploy File.exist? yarn_lock end + def pnpm_lock + File.join(site.path, 'pnpm-lock.yaml') + end + + def pnpm_lock? + File.exist? pnpm_lock + end + def gem run %(gem install bundler --no-document) end @@ -93,6 +106,13 @@ class DeployLocal < Deploy run 'yarn install --production' end + def pnpm + return true unless pnpm_lock? + + run %(pnpm config set store-dir "#{pnpm_cache_dir}") + run 'pnpm install --production' + end + def bundle if Rails.env.production? run %(bundle install --no-cache --path="#{gems_dir}") From a73100a436a283533236989c58f162c0fe8dbd4f Mon Sep 17 00:00:00 2001 From: f Date: Mon, 6 Feb 2023 16:16:27 -0300 Subject: [PATCH 102/453] fix: pnpm se instala localmente --- app/models/deploy_local.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 51baf492..e4845d7c 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -55,7 +55,7 @@ class DeployLocal < Deploy # @return [Hash] def env # XXX: This doesn't support Windows paths :B - paths = [File.dirname(`which bundle`), '/usr/bin', '/bin'] + paths = [File.dirname(`which bundle`), '/usr/local/bin', '/usr/bin', '/bin'] # Las variables de entorno extra no pueden superponerse al local. extra_env.merge({ From 75cbed8f6d9610d1a03ef0e299d2a8083c91925b Mon Sep 17 00:00:00 2001 From: f Date: Mon, 6 Feb 2023 16:23:41 -0300 Subject: [PATCH 103/453] fix: no eliminar archivos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gem-compiler sabe mejor cuales se pueden eliminar y cuáles no sutty/gems#3 sutty/gems#1 --- app/models/deploy_local.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 5bee9ff5..02ce97da 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -91,12 +91,7 @@ class DeployLocal < Deploy end def bundle - run %(bundle install --no-cache --path="#{gems_dir}") - - # Eliminar archivos que no se usan - Dir.glob("#{gems_dir}/ruby/2.7.0/{cache/*,gems/*/{spec,test,ext,vendor}}").each do |dir| - FileUtils.rm_rf(dir) - end + run %(bundle install --no-cache --path="#{gems_dir}") end def jekyll_build From 8dcc8596e2e9dfb2aa1c58a5dc16e8c9e2c69b1a Mon Sep 17 00:00:00 2001 From: f Date: Tue, 7 Feb 2023 09:19:38 -0300 Subject: [PATCH 104/453] feat: informar la rama actual del repositorio #9804 --- .profile | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .profile diff --git a/.profile b/.profile new file mode 100644 index 00000000..3c73ffa9 --- /dev/null +++ b/.profile @@ -0,0 +1,9 @@ +Color_Off='\e[0m' +BPurple='\e[1;35m' +BBlue='\e[1;34m' + +is_git() { + git rev-parse --abbrev-ref HEAD 2>/dev/null +} + +PS1="\[${BPurple}\]\$(is_git) \[${BBlue}\]\W\[${Color_Off}\] >_ " From 464ff4841b68affaa694ab0e8e348035cf565a38 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 7 Feb 2023 18:15:25 -0300 Subject: [PATCH 105/453] feat: textos para el panel --- config/locales/en.yml | 16 ++++++++++++++-- config/locales/es.yml | 16 ++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index e7fb4f76..2bbf58ea 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -249,9 +249,21 @@ en: Only accessible through [Tor Browser](https://www.torproject.org/download/) deploy_distributed_press: - title: 'Publish on Distributed Press' + title: 'Publish to the distributed Web' help: | - ipfs + Make your site available through peer-to-peer protocols, + Inter-Planetary File System (IPFS), Hypercore, and via + BitTorrent, so your site is more resilient and can be available + offline, including in community mesh networks. + + **Important:** Only use this option if you would like your data + to be permanently available. If you decide to undo this + selection, a cleared version of the site will be shared in its + place. However, it is possible that nodes on the distributed + storage network may continue retaining copies of the data + indefinitely. + + [Learn more](#) stats: index: title: Statistics diff --git a/config/locales/es.yml b/config/locales/es.yml index 18cf5326..e3b24957 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -254,9 +254,21 @@ es: Sólo será accesible a través del [Navegador Tor](https://www.torproject.org/es/download/). deploy_distributed_press: - title: 'Alojar en la web distribuida' + title: 'Publicar a la Web distribuida' help: | - Es para que esté en la web distribuida + Utiliza protocolos de pares, Inter-Planetary File System (IPFS), + Hypercore y torrents, para que tu sitio sea más resiliente y + esté disponible _offline_, inclusive en redes _mesh_ + comunitarias. + + **Importante:** Sólo usa esta opción si te parece correcto que + tu contenido esté disponible permanentemente. Cuando elijas + des-hacer esta acción, una versión "vacía" del sitio será + compartida en su lugar. Sin embargo, es posible que algunos + nodos en la red de almacenamiento distribuida puedan retener + copias de tu contenido indefinidamente. + + [Saber más](#) stats: index: title: Estadísticas From 9661a34a04396c647f5ad1fe5d6ea75fc3b513ac Mon Sep 17 00:00:00 2001 From: f Date: Wed, 8 Feb 2023 09:38:36 -0300 Subject: [PATCH 106/453] fix: faltaban algunos require --- Gemfile | 2 +- Gemfile.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index f317487b..694358a6 100644 --- a/Gemfile +++ b/Gemfile @@ -38,7 +38,7 @@ gem 'commonmarker' gem 'devise' gem 'devise-i18n' gem 'devise_invitable' -gem 'distributed-press-api-client', '~> 0.2.0' +gem 'distributed-press-api-client', '~> 0.2.1' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'exception_notification' gem 'fast_blank' diff --git a/Gemfile.lock b/Gemfile.lock index 534ad298..5c074a7b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -704,7 +704,7 @@ DEPENDENCIES devise devise-i18n devise_invitable - distributed-press-api-client (~> 0.2.0) + distributed-press-api-client (~> 0.2.1) dotenv-rails down ed25519 From 6683f80aba504c2edca9bcb4ca5f3ce4f24eba9c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 8 Feb 2023 11:55:07 -0300 Subject: [PATCH 107/453] fix: no fallar si tarda mucho dp --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 694358a6..7f4cc6ca 100644 --- a/Gemfile +++ b/Gemfile @@ -38,7 +38,7 @@ gem 'commonmarker' gem 'devise' gem 'devise-i18n' gem 'devise_invitable' -gem 'distributed-press-api-client', '~> 0.2.1' +gem 'distributed-press-api-client', '~> 0.2.2' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'exception_notification' gem 'fast_blank' diff --git a/Gemfile.lock b/Gemfile.lock index 5c074a7b..b5b6fd18 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -163,7 +163,7 @@ GEM devise_invitable (2.0.5) actionmailer (>= 5.0) devise (>= 4.6) - distributed-press-api-client (0.2.1) + distributed-press-api-client (0.2.2) addressable (~> 2.3, >= 2.3.0) climate_control dry-schema @@ -704,7 +704,7 @@ DEPENDENCIES devise devise-i18n devise_invitable - distributed-press-api-client (~> 0.2.1) + distributed-press-api-client (~> 0.2.2) dotenv-rails down ed25519 From ccfd77d9568dce55ea8ce29ea114b2487f7bc0b9 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 8 Feb 2023 17:08:02 -0300 Subject: [PATCH 108/453] =?UTF-8?q?feat:=20guardar=20un=20log=20y=20mostra?= =?UTF-8?q?rlo=20en=20output=20tambi=C3=A9n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_distributed_press.rb | 24 ++++++++++++++++++----- app/models/distributed_press_publisher.rb | 22 ++++++++++++++++++++- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 38cb59e3..d805e923 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -22,19 +22,32 @@ class DeployDistributedPress < Deploy # @param :output [Bool] # @return [Bool] def deploy + status = false + log = [] + time_start - status = false - site_client.tap do |c| + stdout = Thread.new(publisher.logger_out) do |io| + until io.eof? + line = io.gets + + puts line if output + log << line + end + end + update remote_info: c.show(publishing_site).to_h status = c.publish(publishing_site, deploy_local.destination) + + publisher.logger.close + stdout.join end time_stop - create_stat! status + create_stat! status, log.join status end @@ -95,9 +108,10 @@ class DeployDistributedPress < Deploy # Registra lo que sucedió # # @param status [Bool] + # @param log [String] # @return [nil] - def create_stat!(status) - build_stats.create action: publisher.to_s, seconds: time_spent_in_seconds, bytes: size, status: status + def create_stat!(status, log) + build_stats.create action: publisher.to_s,log: log, seconds: time_spent_in_seconds, bytes: size, status: status nil end end diff --git a/app/models/distributed_press_publisher.rb b/app/models/distributed_press_publisher.rb index acfc4226..089f63c6 100644 --- a/app/models/distributed_press_publisher.rb +++ b/app/models/distributed_press_publisher.rb @@ -8,6 +8,11 @@ class DistributedPressPublisher < ApplicationRecord # Cifrar la información del token en la base de datos has_encrypted :token + # La salida del log + # + # @return [IO] + attr_reader :logger_out + # La instancia es única validates_uniqueness_of :instance @@ -27,7 +32,7 @@ class DistributedPressPublisher < ApplicationRecord # # @return [DistributedPress::V1::Client] def client - @client ||= DistributedPress::V1::Client.new(url: instance, token: token) + @client ||= DistributedPress::V1::Client.new(url: instance, token: token, logger: logger) end # @return [String] @@ -35,8 +40,23 @@ class DistributedPressPublisher < ApplicationRecord "Distributed Press <#{instance}>" end + # @return [Logger] + def logger + @logger ||= + begin + @logger_out, @logger_in = IO.pipe + ::Logger.new @logger_in, formatter: formatter + end + end + private + def formatter + @formatter ||= lambda do |_, _, _, msg| + "#{msg}\n" + end + end + # Actualiza o desactiva la fecha de vencimiento a partir de la # información del token. # From 89f5ed90ebe60b2b9132c8bdad1e9ee3a310e970 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 8 Feb 2023 17:44:35 -0300 Subject: [PATCH 109/453] =?UTF-8?q?fix:=20link=20a=20saber=20m=C3=A1s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 2bbf58ea..f37afa7c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -263,7 +263,7 @@ en: storage network may continue retaining copies of the data indefinitely. - [Learn more](#) + [Learn more](https://ffdweb.org/building-distributed-press-a-publishing-tool-for-the-decentralized-web/) stats: index: title: Statistics diff --git a/config/locales/es.yml b/config/locales/es.yml index e3b24957..fef3b6eb 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -268,7 +268,7 @@ es: nodos en la red de almacenamiento distribuida puedan retener copias de tu contenido indefinidamente. - [Saber más](#) + [Saber más (en inglés)](https://ffdweb.org/building-distributed-press-a-publishing-tool-for-the-decentralized-web/) stats: index: title: Estadísticas From 15e6696bcf7b645b59a246c8fcd908db9671ad74 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 8 Feb 2023 18:49:37 -0300 Subject: [PATCH 110/453] feat: un deploy puede tener varias urls --- app/models/deploy_distributed_press.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index d805e923..d3474d50 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -60,6 +60,15 @@ class DeployDistributedPress < Deploy def destination; end + # Devuelve las URLs de todos los protocolos + def urls + remote_info[:links].values.map do |protocol| + [ protocol[:link], protocol[:gateway] ] + end.flatten.compact.select do |link| + link.include? '://' + end + end + private # El cliente de la API From 7ff284d547cd8e0ce8f0f30d4172db182e439430 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 8 Feb 2023 18:52:48 -0300 Subject: [PATCH 111/453] =?UTF-8?q?feat:=20texto=20para=20el=20correo=20de?= =?UTF-8?q?=20notificaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/en.yml | 4 ++++ config/locales/es.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index f37afa7c..ac8d7289 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -102,6 +102,10 @@ en: title: Alternative domain name success: Success! error: Error + deploy_distributed_press: + title: Distributed Web + success: Success! + error: Error help: You can contact us by replying to this e-mail maintenance_mailer: notice: diff --git a/config/locales/es.yml b/config/locales/es.yml index fef3b6eb..335fca66 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -102,6 +102,10 @@ es: title: Dominio alternativo success: ¡Éxito! error: Hubo un error + deploy_distributed_press: + title: Web distribuida + success: ¡Éxito! + error: Hubo un error help: Por cualquier duda, responde este correo para contactarte con nosotres. maintenance_mailer: notice: From b091b3212a71fa182be5ddb884f700faec05f3ae Mon Sep 17 00:00:00 2001 From: f Date: Wed, 8 Feb 2023 18:55:05 -0300 Subject: [PATCH 112/453] feat: refactorizar mailer para que use menos recursors y soporte varias urls --- app/jobs/deploy_job.rb | 4 +- app/mailers/deploy_mailer.rb | 63 ++++++++++++++++++---- app/views/deploy_mailer/deployed.html.haml | 31 +++++------ app/views/deploy_mailer/deployed.text.haml | 12 ++--- 4 files changed, 73 insertions(+), 37 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index ae6cb279..6250cf73 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -32,7 +32,7 @@ class DeployJob < ApplicationJob status: deploy_locally, seconds: deploy_local.build_stats.last.seconds, size: deploy_local.size, - url: deploy_local.url + urls: [deploy_local.url] } } @@ -74,7 +74,7 @@ class DeployJob < ApplicationJob status: status, seconds: build_stat.try(:seconds) || 0, size: d.size, - url: d.url + urls: d.respond_to?(:urls) ? d.urls : [d.url] } end end diff --git a/app/mailers/deploy_mailer.rb b/app/mailers/deploy_mailer.rb index 1d0c7308..aeb13676 100644 --- a/app/mailers/deploy_mailer.rb +++ b/app/mailers/deploy_mailer.rb @@ -8,21 +8,64 @@ # TODO: Agregar firma GPG y header Autocrypt # TODO: Cifrar con GPG si le usuarie nos dio su llave class DeployMailer < ApplicationMailer + include ActionView::Helpers::NumberHelper + include ActionView::Helpers::DateHelper + # rubocop:disable Metrics/AbcSize - def deployed(which_ones) - @usuarie = Usuarie.find(params[:usuarie]) - @site = @usuarie.sites.find(params[:site]) - @deploys = which_ones - @deploy_local = @site.deploys.find_by(type: 'DeployLocal') + def deployed(deploys) + usuarie = Usuarie.find(params[:usuarie]) + site = usuarie.sites.find(params[:site]) + subject = t('.subject', site: site.name) + hostname = site.hostname + + @hi = t('.hi') + @explanation = t('.explanation', fqdn: hostname) + @help = t('.help') + + @headers = %w[type status url seconds size].map do |header| + t(".th.#{header}") + end + + @table = deploys.each_pair.map do |deploy, value| + { + title: t(".#{deploy}.title"), + status: t(".#{deploy}.#{value[:status] ? 'success' : 'error'}"), + urls: value[:urls], + seconds: { + human: distance_of_time_in_words(value[:seconds].seconds), + machine: "PT#{value[:seconds]}S" + }, + size: number_to_human_size(value[:size], precision: 2) + } + end + + @terminal_table = Terminal::Table.new do |t| + t << @headers + t.add_separator + @table.each do |row| + row[:urls].each do |url| + t << (row.map do |k, v| + case k + when :seconds then v[:human] + when :urls then url + else v + end + end) + end + end + end # Informamos a cada quien en su idioma y damos una dirección de # respuesta porque a veces les usuaries nos escriben - I18n.with_locale(@usuarie.lang) do - mail(to: @usuarie.email, - reply_to: "sutty@#{Site.domain}", - subject: I18n.t('deploy_mailer.deployed.subject', - site: @site.name)) + I18n.with_locale(usuarie.lang) do + mail(to: usuarie.email, reply_to: "sutty@#{Site.domain}", subject: subject) end end # rubocop:enable Metrics/AbcSize + + private + + def t(key, **args) + I18n.t("deploy_mailer.deployed#{key}", **args) + end end diff --git a/app/views/deploy_mailer/deployed.html.haml b/app/views/deploy_mailer/deployed.html.haml index 0053accf..20548f16 100644 --- a/app/views/deploy_mailer/deployed.html.haml +++ b/app/views/deploy_mailer/deployed.html.haml @@ -1,24 +1,21 @@ -%h1= t('.hi') +%h1= @hi -= sanitize_markdown t('.explanation', fqdn: @deploy_local.site.hostname), - tags: %w[p a strong em] += sanitize_markdown @explanation, tags: %w[p a strong em] %table %thead %tr - %th= t('.th.type') - %th= t('.th.status') - %th= t('.th.url') - %th= t('.th.seconds') - %th= t('.th.size') + - @headers.each do |header| + %th= header %tbody - - @deploys.each_pair do |deploy, value| - %tr - %td= t(".#{deploy}.title") - %td= value[:status] ? t(".#{deploy}.success") : t(".#{deploy}.error") - %td= link_to value[:url], value[:url] - %td - %time{ datetime: "PT#{value[:seconds]}S" }= distance_of_time_in_words value[:seconds].seconds - %td= number_to_human_size value[:size], precision: 2 + - @table.each do |row| + - row[:urls].each do |url| + %tr + %td= row[:title] + %td= row[:status] + %td= link_to url, url + %td + %time{ datetime: row[:seconds][:machine] }= row[:seconds][:human] + %td= row[:size] -= sanitize_markdown t('.help'), tags: %w[p a strong em] += sanitize_markdown @help, tags: %w[p a strong em] diff --git a/app/views/deploy_mailer/deployed.text.haml b/app/views/deploy_mailer/deployed.text.haml index 48e8000c..b2d0416f 100644 --- a/app/views/deploy_mailer/deployed.text.haml +++ b/app/views/deploy_mailer/deployed.text.haml @@ -1,11 +1,7 @@ -= '# ' + t('.hi') += "# #{@hi}" \ -= t('.explanation', fqdn: @deploy_local.site.hostname) += @explanation \ -= Terminal::Table.new do |table| - - table << [t('.th.type'), t('.th.status'), t('.th.url'), t('.th.seconds'), t('.th.size')] - - table.add_separator - - @deploys.each_pair do |deploy, value| - - table << [t(".#{deploy}.title"), value[:status] ? t(".#{deploy}.success") : t(".#{deploy}.error"), value[:url], distance_of_time_in_words(value[:seconds].seconds), number_to_human_size(value[:size], precision: 2)] += @terminal_table \ -= t('.help') += @help From e81f188147e062400721dcd609eef5d62d8f089c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 8 Feb 2023 19:30:05 -0300 Subject: [PATCH 113/453] =?UTF-8?q?fix:=20no=20generar=20links=20si=20la?= =?UTF-8?q?=20url=20viene=20vac=C3=ADa?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/deploy_mailer/deployed.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/deploy_mailer/deployed.html.haml b/app/views/deploy_mailer/deployed.html.haml index 20548f16..f5afe5de 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 url, url + %td= link_to_if url.present?, url, url %td %time{ datetime: row[:seconds][:machine] }= row[:seconds][:human] %td= row[:size] From 3f7b2484d04bee63bff7877f746721703043e217 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 9 Feb 2023 20:01:22 -0300 Subject: [PATCH 114/453] feat: crear temporalmente los dominios en njalla el problema es que no podemos delegar `_dnslink.*.sutty.nl` hacia distributed press, con lo que es necesario crear un subdominio por cada sitio que lo active. --- Gemfile | 1 + Gemfile.lock | 4 ++++ app/models/deploy_distributed_press.rb | 18 ++++++++++++++++++ app/models/distributed_press_publisher.rb | 7 +++++++ 4 files changed, 30 insertions(+) diff --git a/Gemfile b/Gemfile index 7f4cc6ca..8f742348 100644 --- a/Gemfile +++ b/Gemfile @@ -39,6 +39,7 @@ gem 'devise' gem 'devise-i18n' gem 'devise_invitable' gem 'distributed-press-api-client', '~> 0.2.2' +gem 'njalla-api-client' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'exception_notification' gem 'fast_blank' diff --git a/Gemfile.lock b/Gemfile.lock index b5b6fd18..6469b2db 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -419,6 +419,9 @@ GEM nokogiri (1.12.5-x86_64-linux-musl) mini_portile2 (~> 2.6.1) racc (~> 1.4) + njalla-api-client (0.1.0) + dry-schema + httparty (~> 0.18) orm_adapter (0.5.0) parallel (1.21.0) parser (3.0.2.0) @@ -741,6 +744,7 @@ DEPENDENCIES minima mobility net-ssh + njalla-api-client nokogiri pg pg_search diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index d3474d50..6f2b2c78 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -111,6 +111,12 @@ class DeployDistributedPress < Deploy self.remote_site_id = created_site[:id] self.remote_info = created_site.to_h + # XXX: Esto depende de nuestro DNS actual, cuando lo migremos hay + # que eliminarlo. + 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']['ns'] = njalla.add_record(name: "_dnslink.#{site.name}", type: 'NS', content: "#{publisher.hostname}.").to_h + nil end @@ -123,4 +129,16 @@ class DeployDistributedPress < Deploy build_stats.create action: publisher.to_s,log: log, seconds: time_spent_in_seconds, bytes: size, status: status nil end + + # Actualizar registros en Njalla + # + # @return [Njalla::V1::Domain] + def njalla + @njalla ||= + begin + client = Njalla::V1::Client.new(token: ENV['NJALLA_TOKEN']) + + Njalla::V1::Domain.new(domain: Site.domain, client: client) + end + end end diff --git a/app/models/distributed_press_publisher.rb b/app/models/distributed_press_publisher.rb index 089f63c6..6139db93 100644 --- a/app/models/distributed_press_publisher.rb +++ b/app/models/distributed_press_publisher.rb @@ -40,6 +40,13 @@ class DistributedPressPublisher < ApplicationRecord "Distributed Press <#{instance}>" end + # Devuelve el hostname de la instancia + # + # @return [String] + def hostname + @hostname ||= URI.parse(instance).hostname + end + # @return [Logger] def logger @logger ||= From a849eac17962a645a70b8fd5b5546aa8d285a46e Mon Sep 17 00:00:00 2001 From: f Date: Thu, 9 Feb 2023 20:08:56 -0300 Subject: [PATCH 115/453] fix: no crear subdominios para dominios personalizados esto es por retrocompatibilidad para sitios que no usan DeployAlternativeDomain --- app/models/deploy_distributed_press.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 6f2b2c78..1ae7a2f2 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -113,9 +113,11 @@ class DeployDistributedPress < Deploy # XXX: Esto depende de nuestro DNS actual, cuando lo migremos hay # que eliminarlo. - 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']['ns'] = njalla.add_record(name: "_dnslink.#{site.name}", type: 'NS', content: "#{publisher.hostname}.").to_h + unless site.name.end_with? '.' + 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']['ns'] = njalla.add_record(name: "_dnslink.#{site.name}", type: 'NS', content: "#{publisher.hostname}.").to_h + end nil end From a3c1d7193f8112006cffa60f830e38d9e8d669f2 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 9 Feb 2023 20:11:17 -0300 Subject: [PATCH 116/453] fix: requires --- app/models/deploy_distributed_press.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 1ae7a2f2..41054b99 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require 'distributed_press/v1/client/auth' require 'distributed_press/v1/client/site' +require 'njalla/v1' # Soportar Distributed Press APIv1 # From d821f143058eb515062a55e397a25ad58cd687fd Mon Sep 17 00:00:00 2001 From: f Date: Thu, 9 Mar 2023 15:08:48 -0300 Subject: [PATCH 117/453] fix: temporalmente deshabilitar el boton #9989 --- app/views/posts/show.haml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/views/posts/show.haml b/app/views/posts/show.haml index e46114af..64daee41 100644 --- a/app/views/posts/show.haml +++ b/app/views/posts/show.haml @@ -6,13 +6,6 @@ edit_site_post_path(@site, @post.id), class: 'btn btn-block' - - unless @post.layout.ignored? - = link_to t('posts.preview.btn'), - site_post_preview_path(@site, @post.id), - class: 'btn btn-block', - target: '_blank', - rel: 'noopener' - %table.table.table-condensed %thead %tr From 611a1f0eb043807d8ebc96cca88fb37fa6d5cf83 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 9 Mar 2023 15:08:48 -0300 Subject: [PATCH 118/453] fix: temporalmente deshabilitar el boton #9989 --- app/views/posts/show.haml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/views/posts/show.haml b/app/views/posts/show.haml index e46114af..64daee41 100644 --- a/app/views/posts/show.haml +++ b/app/views/posts/show.haml @@ -6,13 +6,6 @@ edit_site_post_path(@site, @post.id), class: 'btn btn-block' - - unless @post.layout.ignored? - = link_to t('posts.preview.btn'), - site_post_preview_path(@site, @post.id), - class: 'btn btn-block', - target: '_blank', - rel: 'noopener' - %table.table.table-condensed %thead %tr From ffce90daf3af38634a5892fb6bf4111f4f29f2d9 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 9 Mar 2023 15:13:43 -0300 Subject: [PATCH 119/453] =?UTF-8?q?wip:=20no=20mostrar=20errores=20al=20te?= =?UTF-8?q?ner=20errores=20de=20renderizaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pero no muestra nada de nada --- app/models/post.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/post.rb b/app/models/post.rb index cab7665f..bb2afd3c 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -108,6 +108,10 @@ class Post # Cacofonía html.to_html.html_safe + rescue Liquid::Error => e + ExceptionNotifier.notify(e, data: { site: site.name, post: post.id }) + + '' end end From 866b11ff74ff3eba6095389340f62761029cff2a Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 17:29:13 -0300 Subject: [PATCH 120/453] fix: poder distinguir entre errores de deploy --- app/jobs/deploy_job.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 70997ce1..84119416 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -3,6 +3,7 @@ # Realiza el deploy de un sitio class DeployJob < ApplicationJob class DeployException < StandardError; end + class DeployTimedOutException < DeployException; end # rubocop:disable Metrics/MethodLength def perform(site, notify = true, time = Time.now) @@ -17,7 +18,7 @@ class DeployJob < ApplicationJob if @site.building? if 10.minutes.ago >= time @site.update status: 'waiting' - raise DeployException, + raise DeployTimedOutException, "#{@site.name} la tarea estuvo más de 10 minutos esperando, volviendo al estado original" end From e62172e37a188effecdf1319f9e76991dbaa3192 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 18:46:22 -0300 Subject: [PATCH 121/453] =?UTF-8?q?chore:=20secar=20el=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit la primera hipótesis sobre #10031 es que las excepciones cancelan la actualización de la información, como si fueran una transacción, pero haciendo pruebas manuales no pasa. con este cambio al menos el código queda más limpio. --- app/jobs/deploy_job.rb | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 84119416..9c0ed1dd 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -17,7 +17,6 @@ class DeployJob < ApplicationJob # hora original para poder ir haciendo timeouts. if @site.building? if 10.minutes.ago >= time - @site.update status: 'waiting' raise DeployTimedOutException, "#{@site.name} la tarea estuvo más de 10 minutos esperando, volviendo al estado original" end @@ -32,17 +31,13 @@ class DeployJob < ApplicationJob # No es opcional unless @deployed[:deploy_local] - @site.update status: 'waiting' - notify_usuaries if notify - # Hacer fallar la tarea raise DeployException, deploy_local.build_stats.last.log end deploy_others - - # Volver a la espera - @site.update status: 'waiting' + ensure + @site&.update status: 'waiting' notify_usuaries if notify end From 6a7a0dddda284fde2e2eb9f6c8b493e45b407d50 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 18:46:56 -0300 Subject: [PATCH 122/453] fix: no notificar al liberar la tarea --- app/jobs/deploy_job.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 9c0ed1dd..2165ed11 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -17,6 +17,7 @@ class DeployJob < ApplicationJob # hora original para poder ir haciendo timeouts. if @site.building? if 10.minutes.ago >= time + notify = false raise DeployTimedOutException, "#{@site.name} la tarea estuvo más de 10 minutos esperando, volviendo al estado original" end From 955786be0e6a48a88e55510b0e16de595b7680ea Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 18:52:15 -0300 Subject: [PATCH 123/453] =?UTF-8?q?fix:=20cancelar=20la=20compilaci=C3=B3n?= =?UTF-8?q?=20al=20primer=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recupera el comportamiento de #1716 #1730 #1735 #1738 #1739 #1740 #1741 #1743 #1744 #1746 #1832 #1952 #2057 #2058 #2059 #2062 #1104 #1124 #1152 #1153 #1154 #1175 #1191 #1230 #1303 #1461 #1478 #1609 #1610 #1667 #504 --- 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 2165ed11..9f58e3a1 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -31,7 +31,7 @@ class DeployJob < ApplicationJob @deployed = { deploy_local: deploy_locally } # No es opcional - unless @deployed[:deploy_local] + unless @deployed[:deploy_local][:status] # Hacer fallar la tarea raise DeployException, deploy_local.build_stats.last.log end From 1d08b3fdcd080c28702b6a692827399a1c828bd8 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 19:04:55 -0300 Subject: [PATCH 124/453] fix: llegar hasta el final aunque fallen algunos metodos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit al usar ensure en el commit anterior, podemos garantizar que cualquier excepción en otros deploys no deja la compilación en estado de compilación permanente, pero no se notifica a les usuaries. --- app/jobs/deploy_job.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 9f58e3a1..2dacf08e 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -58,6 +58,10 @@ class DeployJob < ApplicationJob def deploy_others @site.deploys.where.not(type: 'DeployLocal').find_each do |d| @deployed[d.type.underscore.to_sym] = d.deploy + rescue StandardError => e + @deployed[d.type.underscore.to_sym] = false + + ExceptionNotifier.notify_exception(e, data: { site: site.id, deploy: d.type }) end end From efe3474f5f4db5bb0b47ab9c4bab6db84691022f Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 19:14:36 -0300 Subject: [PATCH 125/453] fix: hay deploys sin url --- 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 48366bb9..6dd93129 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -78,7 +78,7 @@ class DeployJob < ApplicationJob status: status, seconds: seconds || 0, size: d.size, - urls: d.respond_to?(:urls) ? d.urls : [d.url] + urls: d.respond_to?(:urls) ? d.urls : [d.url].compact } end end From e0a7232643bbad491887d121bb7a237ac95b6923 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 19:27:03 -0300 Subject: [PATCH 126/453] fix: notificar las excepciones manualmente MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit por alguna razón sucker punch dejó de enviarlas! --- app/jobs/deploy_job.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 2dacf08e..e187b6bd 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -37,6 +37,8 @@ class DeployJob < ApplicationJob end deploy_others + rescue DeployException => e + notify_exception e ensure @site&.update status: 'waiting' @@ -47,6 +49,12 @@ class DeployJob < ApplicationJob private + # @param :exception [StandardError] + # @param :deploy [Deploy] + def notify_exception(exception, deploy = nil) + ExceptionNotifier.notify_exception(exception, data: { site: @site.id, deploy: deploy&.type }) + end + def deploy_local @deploy_local ||= @site.deploys.find_by(type: 'DeployLocal') end From 8c5a1096107d7fb904ba327d83e3af12f2f4743d Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 20:04:18 -0300 Subject: [PATCH 127/453] fix: informar cuando no se puede procesar un issue --- app/jobs/gitlab_notifier_job.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index 7218f68a..129697ba 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -3,6 +3,8 @@ # Notifica excepciones a una instancia de Gitlab, como incidencias # nuevas o como comentarios a las incidencias pre-existentes. class GitlabNotifierJob < ApplicationJob + class GitlabNotifierError < StandardError; end + include ExceptionNotifier::BacktraceCleaner # Variables que vamos a acceder luego @@ -18,22 +20,28 @@ class GitlabNotifierJob < ApplicationJob @issue_data = { count: 1 } # Necesitamos saber si el issue ya existía @cached = false + @issue = {} # Traemos los datos desde la caché si existen, sino generamos un # issue nuevo e inicializamos la caché @issue_data = Rails.cache.fetch(cache_key) do - issue = client.new_issue confidential: true, title: title, description: description, issue_type: 'incident' + @issue = client.new_issue confidential: true, title: title, description: description, issue_type: 'incident' @cached = true { count: 1, - issue: issue['iid'], + issue: @issue['iid'], user_agents: [user_agent].compact, params: [request&.filtered_parameters].compact, urls: [url].compact } end + unless @issue['iid'] + Rails.cache.delete(cache_key) + raise GitlabNotifierError, @issue.dig('message', 'title')&.join(', ') + end + # No seguimos actualizando si acabamos de generar el issue return if cached From a0263ad3fbaed7238a9e017e29a89665e009d6aa Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 20:04:53 -0300 Subject: [PATCH 128/453] =?UTF-8?q?fix:=20el=20log=20completo=20hace=20un?= =?UTF-8?q?=20t=C3=ADtulo=20demasiado=20largo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/deploy_job.rb | 10 ++++++++-- app/jobs/gitlab_notifier_job.rb | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index e187b6bd..b411568e 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -33,7 +33,7 @@ class DeployJob < ApplicationJob # No es opcional unless @deployed[:deploy_local][:status] # Hacer fallar la tarea - raise DeployException, deploy_local.build_stats.last.log + raise DeployException, 'Falló la compilación' end deploy_others @@ -52,7 +52,13 @@ class DeployJob < ApplicationJob # @param :exception [StandardError] # @param :deploy [Deploy] def notify_exception(exception, deploy = nil) - ExceptionNotifier.notify_exception(exception, data: { site: @site.id, deploy: deploy&.type }) + data = { + site: @site.id, + deploy: deploy&.type, + log: deploy&.build_stats&.last&.log + } + + ExceptionNotifier.notify_exception(exception, data: data) end def deploy_local diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index 129697ba..701c6789 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -112,6 +112,7 @@ class GitlabNotifierJob < ApplicationJob # @return [String] def description @description ||= ''.dup.tap do |d| + d << log_section d << request_section d << javascript_section d << javascript_footer @@ -159,6 +160,19 @@ class GitlabNotifierJob < ApplicationJob @client ||= GitlabApiClient.new end + # @return [String] + def log_section + return '' unless options[:log] + + <<~LOG + # Log + + ``` + #{options[:log]} + ``` + LOG + end + # Muestra información de la petición # # @return [String] From 6bac8ed65dbb413715631a9477bbd2abc038f8b3 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 20:11:12 -0300 Subject: [PATCH 129/453] fix: agrupar por sitio y enviar el log --- app/jobs/deploy_job.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index b411568e..961f8d69 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -33,12 +33,14 @@ class DeployJob < ApplicationJob # No es opcional unless @deployed[:deploy_local][:status] # Hacer fallar la tarea - raise DeployException, 'Falló la compilación' + raise DeployException, "#{@site.name}: Falló la compilación" end deploy_others - rescue DeployException => e + rescue DeployTimedOutException => e notify_exception e + rescue DeployException => e + notify_exception e, deploy_local ensure @site&.update status: 'waiting' From 8a5ecd98f75a9fcffefa68f8d0f9cb7516aa13c3 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 20:31:16 -0300 Subject: [PATCH 130/453] fix: legible data, remove log section --- app/jobs/gitlab_notifier_job.rb | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index 701c6789..5d9baa9e 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -112,7 +112,6 @@ class GitlabNotifierJob < ApplicationJob # @return [String] def description @description ||= ''.dup.tap do |d| - d << log_section d << request_section d << javascript_section d << javascript_footer @@ -160,19 +159,6 @@ class GitlabNotifierJob < ApplicationJob @client ||= GitlabApiClient.new end - # @return [String] - def log_section - return '' unless options[:log] - - <<~LOG - # Log - - ``` - #{options[:log]} - ``` - LOG - end - # Muestra información de la petición # # @return [String] @@ -257,8 +243,8 @@ class GitlabNotifierJob < ApplicationJob ## Data - ``` - #{pp options[:data]} + ```yaml + #{options[:data].to_yaml} ``` DATA From df3faba784dd47542101175a0d9aacc8606e31a8 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 20:31:39 -0300 Subject: [PATCH 131/453] fix: send sucker punch args --- config/initializers/sucker_punch.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/initializers/sucker_punch.rb b/config/initializers/sucker_punch.rb index 865af32d..19506c2d 100644 --- a/config/initializers/sucker_punch.rb +++ b/config/initializers/sucker_punch.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true # Enviar una notificación cuando falla una tarea -SuckerPunch.exception_handler = lambda { |ex, _klass, _args| - ExceptionNotifier.notify_exception(ex) +SuckerPunch.exception_handler = lambda { |ex, _, args| + ExceptionNotifier.notify_exception(ex, data: args) } From 72f982ee7646b211e16a50d04fc41a0e1346efae Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 20:42:40 -0300 Subject: [PATCH 132/453] fix: no fallar la segunda vez que se reporta el issue --- app/jobs/gitlab_notifier_job.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index 5d9baa9e..d84ecda2 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -37,7 +37,7 @@ class GitlabNotifierJob < ApplicationJob } end - unless @issue['iid'] + if @issue['iid'].blank? && issue_data[:issue].blank? Rails.cache.delete(cache_key) raise GitlabNotifierError, @issue.dig('message', 'title')&.join(', ') end @@ -62,7 +62,7 @@ class GitlabNotifierJob < ApplicationJob # Si este trabajo genera una excepción va a entrar en un loop, así que # la notificamos por correo rescue Exception => e - email_notification.call(e) + email_notification.call(e, data: @issue) email_notification.call(exception, options) end From 347aba67287fedae424c0d52c2728e84a1dec2c2 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 20:47:54 -0300 Subject: [PATCH 133/453] feat: seccion de log --- app/jobs/gitlab_notifier_job.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index d84ecda2..a127beaf 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -112,6 +112,7 @@ class GitlabNotifierJob < ApplicationJob # @return [String] def description @description ||= ''.dup.tap do |d| + d << log_section d << request_section d << javascript_section d << javascript_footer @@ -159,6 +160,21 @@ class GitlabNotifierJob < ApplicationJob @client ||= GitlabApiClient.new end + # @return [String] + def log_section + return if unless options.dig(:data, :log) + + <<~LOG + + # Build log + + ``` + #{option[:data].delete(:log)} + ``` + + LOG + end + # Muestra información de la petición # # @return [String] From 3764e14812309863a194a38efb17013414c3f88d Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 20:49:00 -0300 Subject: [PATCH 134/453] fixup! feat: seccion de log --- app/jobs/gitlab_notifier_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index a127beaf..7c785126 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -162,7 +162,7 @@ class GitlabNotifierJob < ApplicationJob # @return [String] def log_section - return if unless options.dig(:data, :log) + return '' unless options.dig(:data, :log) <<~LOG From 5fe0efeccd7dd1fb9a16f8d89f0d448528934cb0 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 20:50:14 -0300 Subject: [PATCH 135/453] fixup! fixup! feat: seccion de log --- app/jobs/gitlab_notifier_job.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index 7c785126..64caf977 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -126,6 +126,7 @@ class GitlabNotifierJob < ApplicationJob # @return [String] def body @body ||= ''.dup.tap do |b| + d << log_section b << request_section b << javascript_footer b << data_section From d166e669b7ce0e32ce9a0da07900f1dc675d992d Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 20:51:28 -0300 Subject: [PATCH 136/453] fixup! fixup! fixup! feat: seccion de log --- app/jobs/gitlab_notifier_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index 64caf977..edc6cf63 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -126,7 +126,7 @@ class GitlabNotifierJob < ApplicationJob # @return [String] def body @body ||= ''.dup.tap do |b| - d << log_section + b << log_section b << request_section b << javascript_footer b << data_section From b552b0fecd8be260f06cc9c5e6a300cc87a557fe Mon Sep 17 00:00:00 2001 From: f Date: Mon, 13 Mar 2023 20:52:30 -0300 Subject: [PATCH 137/453] fixup! fixup! fixup! fixup! feat: seccion de log --- app/jobs/gitlab_notifier_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index edc6cf63..c8daf220 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -170,7 +170,7 @@ class GitlabNotifierJob < ApplicationJob # Build log ``` - #{option[:data].delete(:log)} + #{options[:data].delete(:log)} ``` LOG From 5822a9b661eecc331f422fb22c5b8365516522d2 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 14 Mar 2023 16:10:59 -0300 Subject: [PATCH 138/453] =?UTF-8?q?fix:=20enviar=20m=C3=A1s=20informaci?= =?UTF-8?q?=C3=B3n=20con=20el=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #10064 closes #10065 closes #10066 closes #10067 closes #10068 closes #10069 closes #10070 closes #10071 closes #10072 closes #10073 closes #10074 closes #10075 closes #10076 closes #10077 closes #10078 closes #10079 closes #10080 closes #10081 closes #10082 closes #10083 closes #10084 closes #10085 closes #10086 closes #10087 closes #10088 closes #10089 closes #10090 closes #10091 closes #10092 closes #10093 closes #10094 closes #10095 closes #10096 closes #10097 closes #10098 closes #10099 closes #10100 closes #10101 closes #10102 closes #10103 closes #10104 closes #10105 closes #10106 closes #10107 closes #10108 closes #10109 closes #10110 closes #10111 closes #10112 closes #10113 closes #10114 closes #10115 closes #10116 closes #10117 closes #10118 closes #10119 closes #10120 closes #10121 closes #10122 closes #10123 closes #10124 closes #10125 closes #10126 closes #10127 closes #10128 closes #10129 closes #10130 closes #10131 closes #10132 closes #10133 closes #10134 closes #10135 closes #10136 closes #10137 closes #10138 closes #10139 closes #10140 closes #10141 closes #10142 closes #10143 closes #10144 closes #10145 closes #10146 closes #10147 closes #10148 closes #10149 closes #10150 closes #10151 closes #10152 closes #10153 closes #10154 closes #10155 closes #10156 closes #10157 closes #10158 closes #10159 closes #10160 closes #10161 closes #10162 closes #10163 closes #10164 closes #10165 closes #10166 closes #10167 closes #10168 closes #10169 closes #10170 closes #10171 closes #10172 closes #10173 closes #10174 closes #10175 closes #10176 closes #10177 closes #10178 closes #10179 closes #10180 closes #10181 closes #10182 closes #10183 closes #10184 closes #10185 closes #10186 closes #10187 closes #10188 closes #10189 closes #10190 closes #10191 closes #10192 closes #10193 closes #10194 closes #10195 closes #10196 closes #10197 closes #10198 closes #10199 closes #10200 closes #10201 closes #10202 closes #10203 closes #10204 closes #10205 closes #10206 closes #10207 closes #10208 closes #10209 closes #10210 closes #10211 closes #10212 closes #10213 closes #10214 closes #10215 closes #10216 closes #10217 closes #10218 closes #10219 closes #10220 closes #10221 closes #10222 closes #10223 closes #10224 closes #10225 closes #10226 closes #10227 closes #10228 closes #10229 closes #10230 closes #10231 closes #10232 closes #10234 closes #10235 closes #10236 closes #10237 closes #10238 closes #10239 closes #10240 closes #10241 closes #10242 closes #10243 closes #10244 --- app/jobs/gitlab_notifier_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index c8daf220..11d4274a 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -63,7 +63,7 @@ class GitlabNotifierJob < ApplicationJob # la notificamos por correo rescue Exception => e email_notification.call(e, data: @issue) - email_notification.call(exception, options) + email_notification.call(exception, data: options) end private From 6f363f2c358a63d6ad74c2c0d962ca93f148c06b Mon Sep 17 00:00:00 2001 From: f Date: Tue, 14 Mar 2023 16:16:46 -0300 Subject: [PATCH 139/453] fix: params a veces es un array?? --- app/jobs/gitlab_notifier_job.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index 11d4274a..291112a5 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -84,10 +84,14 @@ class GitlabNotifierJob < ApplicationJob exception.class.name, Digest::SHA1.hexdigest(exception.message), Digest::SHA1.hexdigest(backtrace&.first.to_s), - Digest::SHA1.hexdigest(options.dig(:data, :params, 'errors').to_s) + Digest::SHA1.hexdigest(errors.to_s) ].join('/') end + def errors + options.dig(:data, :params, 'errors') if options.dig(:data, :params).is_a? Hash + end + # Define si es una excepción de javascript o local # # @see BacktraceJob From 222cc8f62656486c08d6f48e1e3a95c164053f4d Mon Sep 17 00:00:00 2001 From: f Date: Tue, 14 Mar 2023 16:45:39 -0300 Subject: [PATCH 140/453] fix: volver a traducir los correos #9941 --- app/mailers/deploy_mailer.rb | 74 ++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/app/mailers/deploy_mailer.rb b/app/mailers/deploy_mailer.rb index aeb13676..7d939940 100644 --- a/app/mailers/deploy_mailer.rb +++ b/app/mailers/deploy_mailer.rb @@ -18,46 +18,46 @@ class DeployMailer < ApplicationMailer subject = t('.subject', site: site.name) hostname = site.hostname - @hi = t('.hi') - @explanation = t('.explanation', fqdn: hostname) - @help = t('.help') - - @headers = %w[type status url seconds size].map do |header| - t(".th.#{header}") - end - - @table = deploys.each_pair.map do |deploy, value| - { - title: t(".#{deploy}.title"), - status: t(".#{deploy}.#{value[:status] ? 'success' : 'error'}"), - urls: value[:urls], - seconds: { - human: distance_of_time_in_words(value[:seconds].seconds), - machine: "PT#{value[:seconds]}S" - }, - size: number_to_human_size(value[:size], precision: 2) - } - end - - @terminal_table = Terminal::Table.new do |t| - t << @headers - t.add_separator - @table.each do |row| - row[:urls].each do |url| - t << (row.map do |k, v| - case k - when :seconds then v[:human] - when :urls then url - else v - end - end) - end - end - end - # Informamos a cada quien en su idioma y damos una dirección de # respuesta porque a veces les usuaries nos escriben I18n.with_locale(usuarie.lang) do + @hi = t('.hi') + @explanation = t('.explanation', fqdn: hostname) + @help = t('.help') + + @headers = %w[type status url seconds size].map do |header| + t(".th.#{header}") + end + + @table = deploys.each_pair.map do |deploy, value| + { + title: t(".#{deploy}.title"), + status: t(".#{deploy}.#{value[:status] ? 'success' : 'error'}"), + urls: value[:urls], + seconds: { + human: distance_of_time_in_words(value[:seconds].seconds), + machine: "PT#{value[:seconds]}S" + }, + size: number_to_human_size(value[:size], precision: 2) + } + end + + @terminal_table = Terminal::Table.new do |t| + t << @headers + t.add_separator + @table.each do |row| + row[:urls].each do |url| + t << (row.map do |k, v| + case k + when :seconds then v[:human] + when :urls then url + else v + end + end) + end + end + end + mail(to: usuarie.email, reply_to: "sutty@#{Site.domain}", subject: subject) end end From 51c7c57572177632f1971dd8fba61fe1533e2fdd Mon Sep 17 00:00:00 2001 From: f Date: Tue, 14 Mar 2023 16:48:44 -0300 Subject: [PATCH 141/453] fix: strings #10030 --- config/locales/en.yml | 4 ++++ config/locales/es.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index b814796d..6aa9acd3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -100,6 +100,10 @@ en: title: Alternative domain name success: Success! error: Error + deploy_localized_domain: + title: Domain name by language + success: Success! + error: Error help: You can contact us by replying to this e-mail maintenance_mailer: notice: diff --git a/config/locales/es.yml b/config/locales/es.yml index a6fbd407..ff916b07 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -100,6 +100,10 @@ es: title: Dominio alternativo success: ¡Éxito! error: Hubo un error + deploy_localized_domain: + title: Dominio según idioma + success: ¡Éxito! + error: Hubo un error help: Por cualquier duda, responde este correo para contactarte con nosotres. maintenance_mailer: notice: From bbd19f44aee1686defc5039df36378ff8bc75c89 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 25 Jan 2023 14:27:14 -0300 Subject: [PATCH 142/453] ci: compilar assets cuando cambian las dependencias --- .woodpecker.yml | 17 +++++++++++++++++ package.json | 1 + 2 files changed, 18 insertions(+) diff --git a/.woodpecker.yml b/.woodpecker.yml index 087b2e90..b3406f39 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -1,4 +1,21 @@ pipeline: + assets: + image: "registry.nulo.in/sutty/panel:3.14.8-2.7.6" + commands: + - "apk add python2" + - "yarn" + - "RAILS_GROUPS=assets bundle install --path=vendor" + - "RAILS_GROUPS=assets bundle exec rails assets:precompile assets:clean" + - "git add assets && git commit -m \"[skip ci] JS\" || true" + when: + branch: + - "rails" + - "panel.sutty.nl" + path: + include: + - "app/assets/**/*" + - "package.json" + - "yarn.lock" publish: image: plugins/docker settings: diff --git a/package.json b/package.json index d520c8f5..6a5f159f 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "name": "sutty", + "author": "Sutty ", "private": true, "dependencies": { "@airbrake/browser": "^1.4.1", From 1b0c3cb0acf7d6aca045b253e2022065e60a152b Mon Sep 17 00:00:00 2001 From: f Date: Tue, 14 Mar 2023 19:11:18 -0300 Subject: [PATCH 143/453] ci: compilar en cambios de javascript tambien --- .woodpecker.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.woodpecker.yml b/.woodpecker.yml index b3406f39..a2289c12 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -14,6 +14,7 @@ pipeline: path: include: - "app/assets/**/*" + - "app/javascript/**/*" - "package.json" - "yarn.lock" publish: From 0b63ebdd278051ba1b3b5c29fec87b67a6cedb60 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 14 Mar 2023 19:15:26 -0300 Subject: [PATCH 144/453] chore: yaml --- .woodpecker.yml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index a2289c12..de760284 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -18,29 +18,29 @@ pipeline: - "package.json" - "yarn.lock" publish: - image: plugins/docker + image: "plugins/docker" settings: - registry: registry.nulo.in - username: sutty - repo: registry.nulo.in/sutty/panel + registry: "registry.nulo.in" + username: "sutty" + repo: "registry.nulo.in/sutty/panel" tags: - - ${ALPINE_VERSION}-${RUBY_VERSION}.${RUBY_PATCH} - - latest + - "${ALPINE_VERSION}-${RUBY_VERSION}.${RUBY_PATCH}" + - "latest" build_args: - - RUBY_VERSION=${RUBY_VERSION} - - RUBY_PATCH=${RUBY_PATCH} - - ALPINE_VERSION=${ALPINE_VERSION} - - BASE_IMAGE=registry.nulo.in/sutty/rails + - "RUBY_VERSION=${RUBY_VERSION}" + - "RUBY_PATCH=${RUBY_PATCH}" + - "ALPINE_VERSION=${ALPINE_VERSION}" + - "BASE_IMAGE=registry.nulo.in/sutty/rails" purge: false secrets: - - docker_password + - "docker_password" when: branch: - - rails - - panel.sutty.nl - event: push + - "rails" + - "panel.sutty.nl" + event: "push" matrix: include: - - ALPINE_VERSION: 3.14.8 - RUBY_VERSION: 2.7 - RUBY_PATCH: 6 + - ALPINE_VERSION: "3.14.8" + RUBY_VERSION: "2.7" + RUBY_PATCH: "6" From 6d25d71dd13d2dda59f7b8ae493cac597de383aa Mon Sep 17 00:00:00 2001 From: f Date: Tue, 14 Mar 2023 19:17:16 -0300 Subject: [PATCH 145/453] fix: solo compilar el container cuando cambia --- .woodpecker.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.woodpecker.yml b/.woodpecker.yml index de760284..aef70024 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -39,6 +39,10 @@ pipeline: - "rails" - "panel.sutty.nl" event: "push" + path: + include: + - "Dockerfile" + - ".dockerignore" matrix: include: - ALPINE_VERSION: "3.14.8" From 25e6cd62dd797be25c38e35124c8bce3ec11b3c1 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 14 Mar 2023 19:20:13 -0300 Subject: [PATCH 146/453] fix: aplicar una master key --- .woodpecker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index aef70024..07f18570 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -5,7 +5,7 @@ pipeline: - "apk add python2" - "yarn" - "RAILS_GROUPS=assets bundle install --path=vendor" - - "RAILS_GROUPS=assets bundle exec rails assets:precompile assets:clean" + - "RAILS_GROUPS=assets RAILS_MASTER_KEY=nada bundle exec rails assets:precompile assets:clean" - "git add assets && git commit -m \"[skip ci] JS\" || true" when: branch: From 77e209ac9704185fad57271df9a5f058e0583f4e Mon Sep 17 00:00:00 2001 From: f Date: Tue, 14 Mar 2023 19:23:17 -0300 Subject: [PATCH 147/453] fix: traducir el asunto #9941 --- app/mailers/deploy_mailer.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/mailers/deploy_mailer.rb b/app/mailers/deploy_mailer.rb index 7d939940..25efb18d 100644 --- a/app/mailers/deploy_mailer.rb +++ b/app/mailers/deploy_mailer.rb @@ -15,12 +15,13 @@ class DeployMailer < ApplicationMailer def deployed(deploys) usuarie = Usuarie.find(params[:usuarie]) site = usuarie.sites.find(params[:site]) - subject = t('.subject', site: site.name) hostname = site.hostname # Informamos a cada quien en su idioma y damos una dirección de # respuesta porque a veces les usuaries nos escriben I18n.with_locale(usuarie.lang) do + subject = t('.subject', site: site.name) + @hi = t('.hi') @explanation = t('.explanation', fqdn: hostname) @help = t('.help') From 4b575801c539351f640a9cb36bcbebd902724780 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 14 Mar 2023 19:30:58 -0300 Subject: [PATCH 148/453] fix: usar .env --- .env.example | 3 ++- .woodpecker.yml | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index fb086224..3d134dc2 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,8 @@ +RAILS_MASTER_KEY=CHANGEME RAILS_GROUPS=assets DELEGATE=athshe.sutty.nl HAINISH=../haini.sh/haini.sh -DATABASE= +DATABASE_URL=postgres://suttier@postgresql.sutty.local/sutty RAILS_ENV=development IMAP_SERVER= DEFAULT_FROM= diff --git a/.woodpecker.yml b/.woodpecker.yml index 07f18570..1ad83060 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -2,10 +2,11 @@ pipeline: assets: image: "registry.nulo.in/sutty/panel:3.14.8-2.7.6" commands: - - "apk add python2" + - "apk add python2 dotenv" - "yarn" - - "RAILS_GROUPS=assets bundle install --path=vendor" - - "RAILS_GROUPS=assets RAILS_MASTER_KEY=nada bundle exec rails assets:precompile assets:clean" + - "cp .env.example .env" + - "dotenv bundle install --path=vendor" + - "dotenv RAILS_ENV=production bundle exec rails assets:precompile assets:clean" - "git add assets && git commit -m \"[skip ci] JS\" || true" when: branch: From cacd37348f0022c459fe3a59ddc88b3d40ceabb3 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 14 Mar 2023 19:51:46 -0300 Subject: [PATCH 149/453] fix: credenciales de prueba --- .env.example | 3 ++- .gitignore | 1 - config/credentials.yml.enc | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 config/credentials.yml.enc diff --git a/.env.example b/.env.example index 3d134dc2..f3cf48d9 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,5 @@ -RAILS_MASTER_KEY=CHANGEME +# pwgen -1 32 +RAILS_MASTER_KEY=11111111111111111111111111111111 RAILS_GROUPS=assets DELEGATE=athshe.sutty.nl HAINISH=../haini.sh/haini.sh diff --git a/.gitignore b/.gitignore index 496b66cb..baf85364 100644 --- a/.gitignore +++ b/.gitignore @@ -32,7 +32,6 @@ # Ignore master key for decrypting credentials and more. /config/master.key -/config/credentials.yml.enc /public/packs /public/packs-test diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 00000000..ad215f22 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +r7drFxABS9885DuIhjg3ErL++9dkHZdO6/kBlBNlML20R2R2hhYkE1C2Q9fO7zGaHQX3y51FKu9nRAI9Bomp5JCF/RR3oEzP24Je9DsN/Q2lg3smTNuXKV5J8NuqZPRVBZIp7FsyR66xThzI6ZSrk0IFXRpTwQkW83v3Z+FqLKCAFBAiJ84occonkLUxppL0W0IYN4FzNAK0KiPixZDTg/oAqG17pY0suyJRCe86OYkdrvblI/EEmoxKzSPzT4fml4wka26z4KYeRYDjaQmlTJ8/zLK82AruxhYvL9abdtjsUYIVVWHdNrlRRZaVhFP79YIa0AFfHK1KviMKAAfb8EfDar1fivtzW9mb46dzZcEu0ynJB+HDdM1JFiVw33INI6BY8I604pu5B5ebd9Djd1nIP2wNZNu7ZBOgvbPnDJUdenVAnWYZAqmPVAryK1MfwvaG0RmVYnhlIZoQ2HTLENHV9AyAfUOUiZUse7GQ85iOqrn3yk2KxEh7i4U5yqZu2tuMBBmQK8jpDWiu6hEtIIDgL2327EUNTw1uDvMfpD64I9pBwHGXhKBr3Qi02rNwOI6wJBTLTaSHv15oAolVmiI3kWtQca+UO7LfMaU+mLb6xZ4jm3/maNmugKKHD4Ud7FO2nJ6m2FPUB7uolQPiiSY4cnkd2uKNn7aQPMDcWlQn1CQuwriGwhJD27YfYzyJRD5PG33bmR3JSSjUe4BI9cBTv3UZ7XS/B7Z7SEzqef09hpMUVzEsEsw5yW6Qm1MV8AhYaxPuWLOElwiATcObehJ7LyjeKQSwoTioEG4GBlvgujcNTxI5O0RkU7hP6I/A3Q==--3br8yafpyHA5Y6YU--Aq+HRsZsGTHm4pOfvQYyoA== \ No newline at end of file From 12a85bc5856424ed5ee87c9715410e4a05a6d694 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 14 Mar 2023 20:05:57 -0300 Subject: [PATCH 150/453] fix: credentials must be strings --- config/credentials.yml.enc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc index ad215f22..4add450d 100644 --- a/config/credentials.yml.enc +++ b/config/credentials.yml.enc @@ -1 +1 @@ -r7drFxABS9885DuIhjg3ErL++9dkHZdO6/kBlBNlML20R2R2hhYkE1C2Q9fO7zGaHQX3y51FKu9nRAI9Bomp5JCF/RR3oEzP24Je9DsN/Q2lg3smTNuXKV5J8NuqZPRVBZIp7FsyR66xThzI6ZSrk0IFXRpTwQkW83v3Z+FqLKCAFBAiJ84occonkLUxppL0W0IYN4FzNAK0KiPixZDTg/oAqG17pY0suyJRCe86OYkdrvblI/EEmoxKzSPzT4fml4wka26z4KYeRYDjaQmlTJ8/zLK82AruxhYvL9abdtjsUYIVVWHdNrlRRZaVhFP79YIa0AFfHK1KviMKAAfb8EfDar1fivtzW9mb46dzZcEu0ynJB+HDdM1JFiVw33INI6BY8I604pu5B5ebd9Djd1nIP2wNZNu7ZBOgvbPnDJUdenVAnWYZAqmPVAryK1MfwvaG0RmVYnhlIZoQ2HTLENHV9AyAfUOUiZUse7GQ85iOqrn3yk2KxEh7i4U5yqZu2tuMBBmQK8jpDWiu6hEtIIDgL2327EUNTw1uDvMfpD64I9pBwHGXhKBr3Qi02rNwOI6wJBTLTaSHv15oAolVmiI3kWtQca+UO7LfMaU+mLb6xZ4jm3/maNmugKKHD4Ud7FO2nJ6m2FPUB7uolQPiiSY4cnkd2uKNn7aQPMDcWlQn1CQuwriGwhJD27YfYzyJRD5PG33bmR3JSSjUe4BI9cBTv3UZ7XS/B7Z7SEzqef09hpMUVzEsEsw5yW6Qm1MV8AhYaxPuWLOElwiATcObehJ7LyjeKQSwoTioEG4GBlvgujcNTxI5O0RkU7hP6I/A3Q==--3br8yafpyHA5Y6YU--Aq+HRsZsGTHm4pOfvQYyoA== \ No newline at end of file +1jEfzfldP9tT4+HWfhP48I9hw31gYCnnxHWpYjPrcTm/pgkFdiG+mDa6y31EOxzs50w6FEw2GO127BnyBSUIPIxuWY0cR96xL5pVrS3vjyzM84QN4lJF9ER0Tz1AQ9S7NJ54CelSkMfFt/rf+O4YM8cLtdSVsVC/HlGbp16p3D1pm4MFo5cQb0hEmlyyYlzEn4oJtsp/MCIwI4+z8oFhxKdMIxdbiw+KS/7PBRfMm1h5rdGORCnD69iVmnXseMvVtZn9A7N7uR6+gFlhxlD5yyEW0pwTj3tbu9NeIOVbtmYOL5ZhLW9REXtGTqR5Op/LN+ukIXbDNEScKltJXUdWfa9Pd/QjVT8IMURZ04POEMDgs1cw363yz4f+WQForhSco9oYLDOd5hTGRXoZ9fnjnfJSTjINM62hkfDY3w3+s844nNbjbj+lPTJHU/QjRhcuNqBDDxWUfwTmRIqm5zrelnHnZnuFmFwCNet6NChC6EFUAFjrals6kTSQllyMt4xImqA+HL7DnjWj6VURSH+nGQTA4tQvDdfbDwTzg/PvRkJcsy2dRd135RQdmRZ+8KXBviLabwdR256vaCqSO1j+jyeUPGLll35ghyLxncyBkkAKt1zaDRPDWgVafg0gJ3v7hVV5TYgToPzlv4w88KPCY7cBhkb1qGoXAhtO6iAuZYK9eyZd1gNQJKyqbcLqA5aTTX/ylfdbptWhaZ8ibB8KBgVyn2RmrOHEhB38rDSMHHNfK3Xs4/hhqMFIGHGTGCUYVmjCzhVFd15yRurU32d3YtP8W4L77H7qkFsF1gnvsZx+R084LcJqknwY94dmjtUE4x2u+Qh3ElFj--lr8JoUq1WH9xXNsB--mE8hxHADL7SbDWabAPY1+Q== \ No newline at end of file From 723b8e7974f5a04d1bd775a40e3c9f2c5944ba4a Mon Sep 17 00:00:00 2001 From: f Date: Tue, 14 Mar 2023 20:26:07 -0300 Subject: [PATCH 151/453] ci: publicar los assets --- .woodpecker.yml | 51 +++++++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 1ad83060..3f3c510c 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -1,23 +1,4 @@ pipeline: - assets: - image: "registry.nulo.in/sutty/panel:3.14.8-2.7.6" - commands: - - "apk add python2 dotenv" - - "yarn" - - "cp .env.example .env" - - "dotenv bundle install --path=vendor" - - "dotenv RAILS_ENV=production bundle exec rails assets:precompile assets:clean" - - "git add assets && git commit -m \"[skip ci] JS\" || true" - when: - branch: - - "rails" - - "panel.sutty.nl" - path: - include: - - "app/assets/**/*" - - "app/javascript/**/*" - - "package.json" - - "yarn.lock" publish: image: "plugins/docker" settings: @@ -44,6 +25,38 @@ pipeline: include: - "Dockerfile" - ".dockerignore" + assets: + image: "registry.nulo.in/sutty/panel:${ALPINE_VERSION}-${RUBY_VERSION}.${RUBY_PATCH}" + commands: + - "apk add python2 dotenv openssh-client" + - "mkdir ~/.ssh/" + - "echo \"$${KNOW_HOSTS}\" | base64 -d >> ~/.ssh/known_hosts" + - "eval $(ssh-agent -s)" + - "echo \"$${SSH_KEY}\" | base64 -d | ssh-add -" + - "git config user.name Woodpecker" + - "git config user.email ci@sutty.coop.ar" + - "git remote add origin ${ORIGIN}" + - "git checkout -B ${CI_COMMIT_BRANCH}" + - "yarn" + - "cp .env.example .env" + - "dotenv bundle install --path=vendor" + - "dotenv RAILS_ENV=production bundle exec rails assets:precompile assets:clean" + - "git add public && git commit -m \"ci: assets [skip ci]\"" + - "git push origin ${CI_COMMIT_BRANCH}" + secrets: + - "SSH_KEY" + - "KNOWN_HOSTS" + - "ORIGIN" + when: + branch: + - "rails" + - "panel.sutty.nl" + path: + include: + - "app/assets/**/*" + - "app/javascript/**/*" + - "package.json" + - "yarn.lock" matrix: include: - ALPINE_VERSION: "3.14.8" From 08cad58b77f418b983d03317e0a748153f336e07 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 14 Mar 2023 20:29:58 -0300 Subject: [PATCH 152/453] fixup! ci: publicar los assets --- .woodpecker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 3f3c510c..198f5a99 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -35,7 +35,7 @@ pipeline: - "echo \"$${SSH_KEY}\" | base64 -d | ssh-add -" - "git config user.name Woodpecker" - "git config user.email ci@sutty.coop.ar" - - "git remote add origin ${ORIGIN}" + - "git remote add origin $${ORIGIN}" - "git checkout -B ${CI_COMMIT_BRANCH}" - "yarn" - "cp .env.example .env" From 8b479d1743a2dd94603b550024ccff9639ad5304 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 15 Mar 2023 18:22:20 -0300 Subject: [PATCH 153/453] refactor: convertir deploy en un servicio --- app/controllers/sites_controller.rb | 4 +--- app/services/site_service.rb | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/controllers/sites_controller.rb b/app/controllers/sites_controller.rb index b4826226..f0eff0dc 100644 --- a/app/controllers/sites_controller.rb +++ b/app/controllers/sites_controller.rb @@ -68,9 +68,7 @@ class SitesController < ApplicationController def enqueue authorize site - # XXX: Convertir en una máquina de estados? - site.enqueue! - DeployJob.perform_async site.id + SiteService.new(site: site).deploy redirect_to site_posts_path(site, locale: site.default_locale) end diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 22423bb8..e9a134b5 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -3,6 +3,11 @@ # 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_async site.id + end + # Crea un sitio, agrega un rol nuevo y guarda los cambios a la # configuración en el repositorio git def create From 805eb28273abf02fce6853e8c792fb81532dbd17 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 15 Mar 2023 18:23:06 -0300 Subject: [PATCH 154/453] feat: publicar cambios apenas se crea el sitio #2466 --- app/services/site_service.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index e9a134b5..9e5a4988 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -24,6 +24,8 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do add_licencias + deploy + site end From 9773285e9f4d060473eafb16a1b76edbf171b475 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 15 Mar 2023 11:23:35 -0300 Subject: [PATCH 155/453] fix: no duplicar el remote --- .woodpecker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 198f5a99..41dc85a3 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -35,14 +35,14 @@ pipeline: - "echo \"$${SSH_KEY}\" | base64 -d | ssh-add -" - "git config user.name Woodpecker" - "git config user.email ci@sutty.coop.ar" - - "git remote add origin $${ORIGIN}" + - "git remote add upstream $${ORIGIN}" - "git checkout -B ${CI_COMMIT_BRANCH}" - "yarn" - "cp .env.example .env" - "dotenv bundle install --path=vendor" - "dotenv RAILS_ENV=production bundle exec rails assets:precompile assets:clean" - "git add public && git commit -m \"ci: assets [skip ci]\"" - - "git push origin ${CI_COMMIT_BRANCH}" + - "git push upstream ${CI_COMMIT_BRANCH}" secrets: - "SSH_KEY" - "KNOWN_HOSTS" From c9d7ac437bd5e88531dac3d375250a2bb096a5cd Mon Sep 17 00:00:00 2001 From: f Date: Thu, 16 Mar 2023 09:51:28 -0300 Subject: [PATCH 156/453] =?UTF-8?q?ci:=20probar=20conexi=C3=B3n=20a=20ssh?= =?UTF-8?q?=20antes=20de=20perder=20tiempo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .woodpecker.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 41dc85a3..84101fdf 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -29,10 +29,12 @@ pipeline: image: "registry.nulo.in/sutty/panel:${ALPINE_VERSION}-${RUBY_VERSION}.${RUBY_PATCH}" commands: - "apk add python2 dotenv openssh-client" - - "mkdir ~/.ssh/" - - "echo \"$${KNOW_HOSTS}\" | base64 -d >> ~/.ssh/known_hosts" + - "install -d -m 700 ~/.ssh/" + - "echo \"$${KNOWN_HOSTS}\" | base64 -d >> ~/.ssh/known_hosts" + - "chmod 600 ~/.ssh/known_hosts" - "eval $(ssh-agent -s)" - "echo \"$${SSH_KEY}\" | base64 -d | ssh-add -" + - "ssh $${ORIGIN%:*}" - "git config user.name Woodpecker" - "git config user.email ci@sutty.coop.ar" - "git remote add upstream $${ORIGIN}" From b51748ddcbc903838fb76c4d1c3df1ee490153bf Mon Sep 17 00:00:00 2001 From: f Date: Thu, 16 Mar 2023 10:18:42 -0300 Subject: [PATCH 157/453] ci: limpiar assets por separado --- .woodpecker.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 84101fdf..e550afbe 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -42,7 +42,8 @@ pipeline: - "yarn" - "cp .env.example .env" - "dotenv bundle install --path=vendor" - - "dotenv RAILS_ENV=production bundle exec rails assets:precompile assets:clean" + - "dotenv RAILS_ENV=production bundle exec rails assets:precompile" + - "dotenv RAILS_ENV=production bundle exec rails assets:clean" - "git add public && git commit -m \"ci: assets [skip ci]\"" - "git push upstream ${CI_COMMIT_BRANCH}" secrets: From 4de942a7ca5536260a092c0e2aa07e57f4f1d283 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 16 Mar 2023 10:23:11 -0300 Subject: [PATCH 158/453] ci: eliminar packs antes de recompilarlos --- .woodpecker.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.woodpecker.yml b/.woodpecker.yml index e550afbe..0492cee2 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -42,6 +42,7 @@ pipeline: - "yarn" - "cp .env.example .env" - "dotenv bundle install --path=vendor" + - "dotenv RAILS_ENV=production bundle exec rails webpacker:clobber" - "dotenv RAILS_ENV=production bundle exec rails assets:precompile" - "dotenv RAILS_ENV=production bundle exec rails assets:clean" - "git add public && git commit -m \"ci: assets [skip ci]\"" From 800386e52ccbe6d40dfe08469d83f1bfa8696040 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 16 Mar 2023 11:24:38 -0300 Subject: [PATCH 159/453] =?UTF-8?q?ci:=20no=20hacer=20conflicto=20con=20la?= =?UTF-8?q?s=20credenciales=20de=20producci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .woodpecker.yml | 1 + config/{credentials.yml.enc => credentials.yml.enc.ci} | 0 2 files changed, 1 insertion(+) rename config/{credentials.yml.enc => credentials.yml.enc.ci} (100%) diff --git a/.woodpecker.yml b/.woodpecker.yml index 0492cee2..ab4887ac 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -39,6 +39,7 @@ pipeline: - "git config user.email ci@sutty.coop.ar" - "git remote add upstream $${ORIGIN}" - "git checkout -B ${CI_COMMIT_BRANCH}" + - "mv config/credentials.yml.enc.ci config/credentials.yml.enc" - "yarn" - "cp .env.example .env" - "dotenv bundle install --path=vendor" diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc.ci similarity index 100% rename from config/credentials.yml.enc rename to config/credentials.yml.enc.ci From a97da5b821768a1a2fdcf0eba185835d70cc2ee7 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 16 Mar 2023 12:22:37 -0300 Subject: [PATCH 160/453] fix: volver a ignorar los secretos --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index baf85364..496b66cb 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ # Ignore master key for decrypting credentials and more. /config/master.key +/config/credentials.yml.enc /public/packs /public/packs-test From bf45707be48b9f850975eefabf118df40a759663 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 16 Mar 2023 13:17:39 -0300 Subject: [PATCH 161/453] fix: obtener correctamente los dominios con www #10452 --- app/controllers/api/v1/sites_controller.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/v1/sites_controller.rb b/app/controllers/api/v1/sites_controller.rb index 32fdae1d..10a92907 100644 --- a/app/controllers/api/v1/sites_controller.rb +++ b/app/controllers/api/v1/sites_controller.rb @@ -69,12 +69,11 @@ module Api end end + # Todos los dominios con WWW habilitado def www_names - Site.where(contact: true) - .or(Site.where(colaboracion_anonima: true)) - .select("'www.' || name as name").map(&:name).map do |name| - canonicalize name - end + Site.where(id: DeployWww.all.pluck(:site_id)).select("'www.' || name as name").map(&:name).map do |name| + canonicalize name + end end end end From 74af7512648f997f34a4ad4ced4b0a7c268101d3 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 16 Mar 2023 18:26:17 -0300 Subject: [PATCH 162/453] feat: al crear un sitio configurarlo con el idioma de le usuarie #10022 --- app/models/site.rb | 11 +++++++++++ app/services/site_service.rb | 9 ++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/models/site.rb b/app/models/site.rb index 8cab0ae0..b8050591 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -179,10 +179,20 @@ class Site < ApplicationRecord # Siempre tiene que tener algo porque las traducciones están # incorporadas a los sitios de Sutty, aunque les usuaries no traduzcan # sus sitios. + # + # @return [Array] def locales @locales ||= config.fetch('locales', I18n.available_locales).map(&:to_sym) end + # Modificar los locales disponibles + # + # @param :new_locales [Array] + # @return [Array] + def locales=(new_locales) + @locales = new_locales.map(&:to_sym).uniq + end + # Similar a site.i18n en jekyll-locales # # @return [Hash] @@ -484,6 +494,7 @@ class Site < ApplicationRecord config.title = title config.url = url(slash: false) config.hostname = hostname + config.locales = locales.map(&:to_s) end # Valida si el sitio tiene al menos una forma de alojamiento asociada diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 22423bb8..d21bd597 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -11,7 +11,14 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do add_role temporal: false, rol: 'usuarie' sync_nodes - I18n.with_locale(usuarie&.lang&.to_sym || I18n.default_locale) do + 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) From 59bbc04230baeacee6a4dc0ec9b8a2ce3bf6b1ed Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 14:05:47 -0300 Subject: [PATCH 163/453] fix: actualizar el hash solo cuando se escribir cambios y devolver el resultado de Site::Writer#save --- app/models/site/config.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/site/config.rb b/app/models/site/config.rb index 3215277e..d2e78d98 100644 --- a/app/models/site/config.rb +++ b/app/models/site/config.rb @@ -33,10 +33,10 @@ class Site def write return if persisted? - @saved = Site::Writer.new(site: site, file: path, - content: content.to_yaml).save - # Actualizar el hash para no escribir dos veces - @hash = content.hash + @saved = Site::Writer.new(site: site, file: path, content: content.to_yaml).save.tap do |result| + # Actualizar el hash para no escribir dos veces + @hash = content.hash + end end alias save write From 2f3a596fa5033d99c859e2b8cfde0d4175623b8a Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 15:27:06 -0300 Subject: [PATCH 164/453] =?UTF-8?q?feat:=20cambiar=20el=20idioma=20en=20to?= =?UTF-8?q?da=20la=20sesi=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/application_controller.rb | 18 ++++++++++++++---- app/views/layouts/_breadcrumb.haml | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 79fc7d73..c72392c7 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -46,17 +46,19 @@ class ApplicationController < ActionController::Base # defecto. # # Esto se refiere al idioma de la interfaz, no de los artículos. - def current_locale(include_params: true, site: nil) - return params[:locale] if include_params && params[:locale].present? + # + # @return [String,Symbol] + def current_locale + session[:locale] ||= params[:change_locale_to] - current_usuarie&.lang || I18n.locale + session[:locale] || current_usuarie&.lang || I18n.locale end # El idioma es el preferido por le usuarie, pero no necesariamente se # corresponde con el idioma de los artículos, porque puede querer # traducirlos. def set_locale(&action) - I18n.with_locale(current_locale(include_params: params[:controller].start_with?('devise')), &action) + I18n.with_locale(current_locale, &action) end # Muestra una página 404 @@ -88,4 +90,12 @@ class ApplicationController < ActionController::Base def prepare_exception_notifier request.env['exception_notifier.exception_data'] = { usuarie: current_usuarie } end + + # Olvidar el idioma elegido antes de iniciar la sesión y reenviar a + # los sitios en el idioma de le usuarie. + def after_sign_in_path_for(resource) + session[:locale] = nil + + sites_path + end end diff --git a/app/views/layouts/_breadcrumb.haml b/app/views/layouts/_breadcrumb.haml index 131c3281..0823b1be 100644 --- a/app/views/layouts/_breadcrumb.haml +++ b/app/views/layouts/_breadcrumb.haml @@ -24,4 +24,4 @@ method: :delete, role: 'button', class: 'btn' - else - other_locale = I18n.available_locales.find { |locale| locale != I18n.locale } - = link_to t(other_locale), "?locale=#{other_locale}" + = link_to t(other_locale), "?change_locale_to=#{other_locale}" From 5ac72f8b2bec443ef3009164e4dfc4a276df4b44 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 15:32:56 -0300 Subject: [PATCH 165/453] feat: soportar varios idiomas --- app/views/layouts/_breadcrumb.haml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/views/layouts/_breadcrumb.haml b/app/views/layouts/_breadcrumb.haml index 0823b1be..099ddde4 100644 --- a/app/views/layouts/_breadcrumb.haml +++ b/app/views/layouts/_breadcrumb.haml @@ -23,5 +23,6 @@ = link_to t('.logout'), main_app.destroy_usuarie_session_path, method: :delete, role: 'button', class: 'btn' - else - - other_locale = I18n.available_locales.find { |locale| locale != I18n.locale } - = link_to t(other_locale), "?change_locale_to=#{other_locale}" + - I18n.available_locales.each do |locale| + - next if locale == I18n.locale + = link_to t(locale), "?change_locale_to=#{locale}" From da721ddaaf611cffd33f862d22291b0ffacb7ecd Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 15:49:26 -0300 Subject: [PATCH 166/453] =?UTF-8?q?feat:=20enviar=20el=20idioma=20en=20el?= =?UTF-8?q?=20correo=20de=20confirmaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/devise/mailer/confirmation_instructions.html.haml | 2 +- app/views/devise/mailer/confirmation_instructions.text.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/devise/mailer/confirmation_instructions.html.haml b/app/views/devise/mailer/confirmation_instructions.html.haml index 46706c40..76b10d7f 100644 --- a/app/views/devise/mailer/confirmation_instructions.html.haml +++ b/app/views/devise/mailer/confirmation_instructions.html.haml @@ -1,3 +1,3 @@ %p= t('.greeting', recipient: @email) %p= t('.instruction') -%p= link_to t('.action'), confirmation_url(@resource, confirmation_token: @token) +%p= link_to t('.action'), confirmation_url(@resource, confirmation_token: @token, change_locale_to: @resource.lang) diff --git a/app/views/devise/mailer/confirmation_instructions.text.haml b/app/views/devise/mailer/confirmation_instructions.text.haml index 38e4c548..7123a738 100644 --- a/app/views/devise/mailer/confirmation_instructions.text.haml +++ b/app/views/devise/mailer/confirmation_instructions.text.haml @@ -2,4 +2,4 @@ \ = t('.instruction') \ -= confirmation_url(@resource, confirmation_token: @token) += confirmation_url(@resource, confirmation_token: @token, change_locale_to: @resource.lang) From 6887e5319a8f0c07f493a5543a5849163f3d0e18 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 15:52:10 -0300 Subject: [PATCH 167/453] =?UTF-8?q?feat:=20mantener=20el=20idioma=20de=20l?= =?UTF-8?q?e=20usuarie=20en=20todos=20los=20links=20que=20env=C3=ADe=20dev?= =?UTF-8?q?ise?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/devise/mailer/invitation_instructions.html.haml | 2 +- app/views/devise/mailer/invitation_instructions.text.haml | 2 +- app/views/devise/mailer/reset_password_instructions.html.haml | 2 +- app/views/devise/mailer/reset_password_instructions.text.haml | 2 +- app/views/devise/mailer/unlock_instructions.html.haml | 2 +- app/views/devise/mailer/unlock_instructions.text.haml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/views/devise/mailer/invitation_instructions.html.haml b/app/views/devise/mailer/invitation_instructions.html.haml index 74193878..a2434abd 100644 --- a/app/views/devise/mailer/invitation_instructions.html.haml +++ b/app/views/devise/mailer/invitation_instructions.html.haml @@ -9,7 +9,7 @@ %p= site.description %p= link_to t('devise.mailer.invitation_instructions.accept'), - accept_invitation_url(@resource, invitation_token: @token) + accept_invitation_url(@resource, invitation_token: @token, change_locale_to: @resource.lang) - if @resource.invitation_due_at %p= t('devise.mailer.invitation_instructions.accept_until', diff --git a/app/views/devise/mailer/invitation_instructions.text.haml b/app/views/devise/mailer/invitation_instructions.text.haml index 16a9f0a8..27b1580c 100644 --- a/app/views/devise/mailer/invitation_instructions.text.haml +++ b/app/views/devise/mailer/invitation_instructions.text.haml @@ -9,7 +9,7 @@ \ = site.description \ -= accept_invitation_url(@resource, invitation_token: @token) += accept_invitation_url(@resource, invitation_token: @token, change_locale_to: @resource.lang) \ - if @resource.invitation_due_at = t('devise.mailer.invitation_instructions.accept_until', diff --git a/app/views/devise/mailer/reset_password_instructions.html.haml b/app/views/devise/mailer/reset_password_instructions.html.haml index ccc4aa55..8d8f5919 100644 --- a/app/views/devise/mailer/reset_password_instructions.html.haml +++ b/app/views/devise/mailer/reset_password_instructions.html.haml @@ -1,5 +1,5 @@ %p= t('.greeting', recipient: @resource.email) %p= t('.instruction') -%p= link_to t('.action'), edit_password_url(@resource, reset_password_token: @token) +%p= link_to t('.action'), edit_password_url(@resource, reset_password_token: @token, change_locale_to: @resource.lang) %p= t('.instruction_2') %p= t('.instruction_3') diff --git a/app/views/devise/mailer/reset_password_instructions.text.haml b/app/views/devise/mailer/reset_password_instructions.text.haml index 3d0fe64d..923c2a0c 100644 --- a/app/views/devise/mailer/reset_password_instructions.text.haml +++ b/app/views/devise/mailer/reset_password_instructions.text.haml @@ -2,7 +2,7 @@ \ = t('.instruction') \ -= edit_password_url(@resource, reset_password_token: @token) += edit_password_url(@resource, reset_password_token: @token, change_locale_to: @resource.lang) \ = t('.instruction_2') \ diff --git a/app/views/devise/mailer/unlock_instructions.html.haml b/app/views/devise/mailer/unlock_instructions.html.haml index d68bf7c7..9f8cd492 100644 --- a/app/views/devise/mailer/unlock_instructions.html.haml +++ b/app/views/devise/mailer/unlock_instructions.html.haml @@ -1,4 +1,4 @@ %p= t('.greeting', recipient: @resource.email) %p= t('.message') %p= t('.instruction') -%p= link_to t('.action'), unlock_url(@resource, unlock_token: @token) +%p= link_to t('.action'), unlock_url(@resource, unlock_token: @token, change_locale_to: @resource.lang) diff --git a/app/views/devise/mailer/unlock_instructions.text.haml b/app/views/devise/mailer/unlock_instructions.text.haml index cf06927b..950e04b7 100644 --- a/app/views/devise/mailer/unlock_instructions.text.haml +++ b/app/views/devise/mailer/unlock_instructions.text.haml @@ -4,4 +4,4 @@ \ = t('.instruction') \ -= unlock_url(@resource, unlock_token: @token) += unlock_url(@resource, unlock_token: @token, change_locale_to: @resource.lang) From 0910753437697a1f2e6f1f158a56574fef97390d Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 15:53:56 -0300 Subject: [PATCH 168/453] =?UTF-8?q?fix:=20login=20como=20bot=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/devise/shared/_links.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/devise/shared/_links.haml b/app/views/devise/shared/_links.haml index c8a6c041..b4b89175 100644 --- a/app/views/devise/shared/_links.haml +++ b/app/views/devise/shared/_links.haml @@ -3,7 +3,8 @@ - locale = params.permit(:locale) - if controller_name != 'sessions' - = link_to t('.sign_in'), new_session_path(resource_name, params: locale) + = link_to t('.sign_in'), new_session_path(resource_name, params: locale), + class: 'btn btn-lg btn-block btn-success' %br/ - if devise_mapping.registerable? && controller_name != 'registrations' From a2660485b8bc3ae7e59435e1755efadf86580d03 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 16:03:11 -0300 Subject: [PATCH 169/453] fix: poder cambiar el idioma! --- app/controllers/application_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c72392c7..e80c279d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -49,7 +49,7 @@ class ApplicationController < ActionController::Base # # @return [String,Symbol] def current_locale - session[:locale] ||= params[:change_locale_to] + session[:locale] = params[:change_locale_to] if params[:change_locale_to].present? session[:locale] || current_usuarie&.lang || I18n.locale end From f2e79a733d26f1cf578d1f49f995aea14376a246 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 17:33:52 -0300 Subject: [PATCH 170/453] fix: no fallar si hay errores remotos closes #10467 closes #10506 closes #10509 --- app/models/deploy_distributed_press.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 41054b99..09410201 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -118,7 +118,9 @@ class DeployDistributedPress < Deploy self.remote_info['njalla']['a'] = njalla.add_record(name: 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 end - + rescue DistributedPress::V1::Error, HTTParty::Error => e + ExceptionNotifier.notify_exception(e, data: { site: site.name }) + ensure nil end From 0c674d6ca12fc0f98645a922e18efd13de85cd09 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 17:37:48 -0300 Subject: [PATCH 171/453] fix: crear el sitio remoto si no se pudo crear antes --- app/models/deploy_distributed_press.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 09410201..bd80dca4 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -27,6 +27,11 @@ class DeployDistributedPress < Deploy time_start + if remote_site_id.blank? || remote_info['njalla'].blank? + create_remote_site! + save + end + site_client.tap do |c| stdout = Thread.new(publisher.logger_out) do |io| until io.eof? From 698b3a0bf6bbbaf6b84a8c0c961de081e2c1989b Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 17:39:41 -0300 Subject: [PATCH 172/453] =?UTF-8?q?feat:=20separar=20la=20creaci=C3=B3n=20?= =?UTF-8?q?de=20DP=20de=20njalla?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_distributed_press.rb | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index bd80dca4..9afc6a5d 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -15,7 +15,7 @@ require 'njalla/v1' class DeployDistributedPress < Deploy store :values, accessors: %i[hostname remote_site_id remote_info], coder: JSON - before_create :create_remote_site! + before_create :create_remote_site!, :create_njalla_records! # Actualiza la información y luego envía los cambios # @@ -27,10 +27,9 @@ class DeployDistributedPress < Deploy time_start - if remote_site_id.blank? || remote_info['njalla'].blank? - create_remote_site! - save - end + create_remote_site! if remote_site_id.blank? + create_njalla_records! if remote_info['njalla'].blank? + save site_client.tap do |c| stdout = Thread.new(publisher.logger_out) do |io| @@ -115,7 +114,16 @@ class DeployDistributedPress < Deploy self.remote_site_id = created_site[:id] self.remote_info = created_site.to_h + rescue DistributedPress::V1::Error + ExceptionNotifier.notify_exception(e, data: { site: site.name }) + ensure + nil + end + # Crea los registros en Njalla + # + # @return [nil] + def create_njalla_records! # XXX: Esto depende de nuestro DNS actual, cuando lo migremos hay # que eliminarlo. unless site.name.end_with? '.' @@ -123,7 +131,7 @@ class DeployDistributedPress < Deploy self.remote_info['njalla']['a'] = njalla.add_record(name: 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 end - rescue DistributedPress::V1::Error, HTTParty::Error => e + rescue HTTParty::Error => e ExceptionNotifier.notify_exception(e, data: { site: site.name }) ensure nil From b297800933ae0556845f1e710ce181a6d4e158cb Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 17:44:13 -0300 Subject: [PATCH 173/453] fix: volver a fallar si al hacer deploy todavia estan caidos los servicios --- app/models/deploy_distributed_press.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 9afc6a5d..e8d8b095 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -31,6 +31,10 @@ class DeployDistributedPress < Deploy create_njalla_records! if remote_info['njalla'].blank? save + if remote_site_id.blank? || remote_info['njalla'].blank? + raise DeployJob::DeployException, '' + end + site_client.tap do |c| stdout = Thread.new(publisher.logger_out) do |io| until io.eof? @@ -133,6 +137,7 @@ class DeployDistributedPress < Deploy end rescue HTTParty::Error => e ExceptionNotifier.notify_exception(e, data: { site: site.name }) + self.remote_info['njalla'] = nil ensure nil end From 50f1ce51d9219149da38aaba5eef0fb37554da17 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 19:14:12 -0300 Subject: [PATCH 174/453] fix: el locale de los posts es distinto al de le usuarie #10454 --- app/controllers/posts_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index c5dc0f54..3c529c24 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -12,7 +12,7 @@ class PostsController < ApplicationController # Las URLs siempre llevan el idioma actual o el de le usuarie def default_url_options - { locale: current_locale } + { locale: locale } end def index From 7160cb01df19c39fe150d3a6479813105acc5ded Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 19:22:08 -0300 Subject: [PATCH 175/453] fix: la tienda se activa luego de crear el sitio #10512 --- app/views/sites/_form.haml | 40 +++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/app/views/sites/_form.haml b/app/views/sites/_form.haml index 6f15d570..9a044c7f 100644 --- a/app/views/sites/_form.haml +++ b/app/views/sites/_form.haml @@ -104,27 +104,27 @@ %hr/ - .form-group#tienda - %h2= t('.tienda.title') - %p.lead - - if site.tienda? - = t('.tienda.help') - - else - = t('.tienda.first_time_html') - - .row - .col - .form-group - = f.label :tienda_url - = f.url_field :tienda_url, class: 'form-control' - .col - .form-group - = f.label :tienda_api_key - = f.text_field :tienda_api_key, class: 'form-control' - - %hr/ - - if site.persisted? + .form-group#tienda + %h2= t('.tienda.title') + %p.lead + - if site.tienda? + = t('.tienda.help') + - else + = t('.tienda.first_time_html') + + .row + .col + .form-group + = f.label :tienda_url + = f.url_field :tienda_url, class: 'form-control' + .col + .form-group + = f.label :tienda_api_key + = f.text_field :tienda_api_key, class: 'form-control' + + %hr/ + .form-group#contact %h2= t('.contact.title') %p.lead= t('.contact.help') From 5ec698366a524583063cefb84d652084e2841788 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 20 Mar 2023 11:46:21 -0300 Subject: [PATCH 176/453] fix: capturar standard error --- app/jobs/gitlab_notifier_job.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index 291112a5..fb25be10 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -61,7 +61,7 @@ class GitlabNotifierJob < ApplicationJob Rails.cache.write(cache_key, issue_data) # Si este trabajo genera una excepción va a entrar en un loop, así que # la notificamos por correo - rescue Exception => e + rescue StandardError => e email_notification.call(e, data: @issue) email_notification.call(exception, data: options) end @@ -89,7 +89,9 @@ class GitlabNotifierJob < ApplicationJob end def errors - options.dig(:data, :params, 'errors') if options.dig(:data, :params).is_a? Hash + return '' unless javascript? + + options.dig(:data, :params, 'errors') end # Define si es una excepción de javascript o local From 16ed7db1d76ff24ee5c8a6d88b6c35788c22441a Mon Sep 17 00:00:00 2001 From: f Date: Mon, 20 Mar 2023 12:13:51 -0300 Subject: [PATCH 177/453] =?UTF-8?q?fix:=20capturar=20la=20excepci=C3=B3n?= =?UTF-8?q?=20#10546?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_distributed_press.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index e8d8b095..6940a83e 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -118,7 +118,7 @@ class DeployDistributedPress < Deploy self.remote_site_id = created_site[:id] self.remote_info = created_site.to_h - rescue DistributedPress::V1::Error + rescue DistributedPress::V1::Error => e ExceptionNotifier.notify_exception(e, data: { site: site.name }) ensure nil From d25937f536ef072f2a9323b03e1bbaa4809fcd40 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 20 Mar 2023 15:33:28 -0300 Subject: [PATCH 178/453] fix: no producir type error --- app/jobs/gitlab_notifier_job.rb | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index fb25be10..2f39caf9 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -16,7 +16,7 @@ class GitlabNotifierJob < ApplicationJob # @param [Hash] opciones de ExceptionNotifier def perform(exception, **options) @exception = exception - @options = options + @options = fix_options options @issue_data = { count: 1 } # Necesitamos saber si el issue ya existía @cached = false @@ -88,10 +88,9 @@ class GitlabNotifierJob < ApplicationJob ].join('/') end + # @return [Array] def errors - return '' unless javascript? - - options.dig(:data, :params, 'errors') + options.dig(:data, :params, 'errors') || [] end # Define si es una excepción de javascript o local @@ -288,4 +287,15 @@ class GitlabNotifierJob < ApplicationJob def url @url ||= request&.url || options.dig(:data, :params, 'context', 'url') end + + # Define llaves necesarias + # + # @param :options [Hash] + # @return [Hash] + def fix_options(options) + options[:data] ||= {} + options[:data][:params] ||= {} + + options + end end From 7d7fcdc409b34b040218168499c558e0aa3d5e96 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 20 Mar 2023 16:08:37 -0300 Subject: [PATCH 179/453] fix: recuperar el comportamiento esperado #2123 --- app/controllers/usuaries_controller.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index 6d02a35a..c60ea206 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -88,16 +88,16 @@ class UsuariesController < ApplicationController # TODO: Enviar invitación igual! Podemos no usar el Mailer de # DeviseInvitations y usar uno propio que contenga texto y se # envíe de todas formas. - usuarie = Usuarie.invite! email: invitacion.address, - skip_invitation: true + attributes = { email: invitacion.address } + options = { skip_invitation: true } + usuarie = Usuarie.invite! attributes, current_usuarie, options # No invitar al sitio si ya estaba en la lista! # # XXX: En este caso no estamos enviando ninguna invitación next if usuarie.sites.exists? @site.id - @site.roles << Rol.create(usuarie: usuarie, site: @site, - temporal: true, rol: invited_as) + @site.roles.create(usuarie: usuarie, temporal: true, rol: invited_as) # Invitamos después de crear el rol para que el correo de # invitación pueda recibir el sitio. From 61a23cb3d7945171ce08f56e469fcfcf4b666eb1 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 20 Mar 2023 16:54:00 -0300 Subject: [PATCH 180/453] =?UTF-8?q?fix:=20solo=20enviar=20invitaci=C3=B3n?= =?UTF-8?q?=20si=20le=20usuarie=20no=20existe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/usuaries_controller.rb | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index c60ea206..3dd78de1 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -82,26 +82,14 @@ class UsuariesController < ApplicationController # Enviar la invitación si es necesario y agregar al sitio invitaciones.each do |invitacion| - # Si la cuenta no existe, envía una invitación por correo, sino, - # no se envía nada - # - # TODO: Enviar invitación igual! Podemos no usar el Mailer de - # DeviseInvitations y usar uno propio que contenga texto y se - # envíe de todas formas. attributes = { email: invitacion.address } - options = { skip_invitation: true } - usuarie = Usuarie.invite! attributes, current_usuarie, options - # No invitar al sitio si ya estaba en la lista! - # - # XXX: En este caso no estamos enviando ninguna invitación + usuarie = Usuarie.find_by attributes + usuarie ||= Usuarie.invite! attributes, current_usuarie + next if usuarie.sites.exists? @site.id @site.roles.create(usuarie: usuarie, temporal: true, rol: invited_as) - - # Invitamos después de crear el rol para que el correo de - # invitación pueda recibir el sitio. - usuarie.deliver_invitation end redirect_to site_usuaries_path(@site) From 92fa2b89324a9973d31bc5acdb3185246a12db06 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 20 Mar 2023 16:59:27 -0300 Subject: [PATCH 181/453] fix: no llevar registro de quien se conoce con quien aunque es un poco obvio al mirar la lista de usuaries de un sitio --- app/controllers/usuaries_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index 3dd78de1..9cc756f7 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -85,7 +85,7 @@ class UsuariesController < ApplicationController attributes = { email: invitacion.address } usuarie = Usuarie.find_by attributes - usuarie ||= Usuarie.invite! attributes, current_usuarie + usuarie ||= Usuarie.invite! attributes next if usuarie.sites.exists? @site.id From 362e45b51d0bb67fbf4f88d19ead72c35b7f52dc Mon Sep 17 00:00:00 2001 From: f Date: Mon, 20 Mar 2023 17:17:53 -0300 Subject: [PATCH 182/453] fix: efectivamente ignorar mails que ya son usuaries de este sitio --- app/controllers/usuaries_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index 9cc756f7..2dd3ea99 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -84,11 +84,11 @@ class UsuariesController < ApplicationController invitaciones.each do |invitacion| attributes = { email: invitacion.address } + next if Usuarie.where(id: @site.roles.pluck(:usuarie_id)).find_by(attributes) + usuarie = Usuarie.find_by attributes usuarie ||= Usuarie.invite! attributes - next if usuarie.sites.exists? @site.id - @site.roles.create(usuarie: usuarie, temporal: true, rol: invited_as) end From 11e503061cf3dde80bdf5100fe268ecc9fbbdb2d Mon Sep 17 00:00:00 2001 From: f Date: Mon, 20 Mar 2023 17:22:40 -0300 Subject: [PATCH 183/453] =?UTF-8?q?fix:=20enviar=20invitaci=C3=B3n=20sin?= =?UTF-8?q?=20link?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Usuarie#deliver_invitation además generaba un token cuando no era necesario y esto es lo que hacía que les usuaries quedaran flotando. --- app/controllers/usuaries_controller.rb | 5 ++++- .../mailer/invitation_instructions.html.haml | 17 +++++++++------- .../mailer/invitation_instructions.text.haml | 20 +++++++++++-------- config/locales/devise_invitable.en.yml | 1 + config/locales/devise_invitable.es.yml | 1 + 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index 2dd3ea99..7621489e 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -86,7 +86,10 @@ class UsuariesController < ApplicationController next if Usuarie.where(id: @site.roles.pluck(:usuarie_id)).find_by(attributes) - usuarie = Usuarie.find_by attributes + usuarie = Usuarie.find_by(attributes).tap do |u| + u.send(:send_devise_notification, :invitation_instructions, nil) + end + usuarie ||= Usuarie.invite! attributes @site.roles.create(usuarie: usuarie, temporal: true, rol: invited_as) diff --git a/app/views/devise/mailer/invitation_instructions.html.haml b/app/views/devise/mailer/invitation_instructions.html.haml index 74193878..e1fe6812 100644 --- a/app/views/devise/mailer/invitation_instructions.html.haml +++ b/app/views/devise/mailer/invitation_instructions.html.haml @@ -8,12 +8,15 @@ %h1= site.title %p= site.description -%p= link_to t('devise.mailer.invitation_instructions.accept'), - accept_invitation_url(@resource, invitation_token: @token) +- if @resource.created_by_invite? + %p= link_to t('devise.mailer.invitation_instructions.accept'), + accept_invitation_url(@resource, invitation_token: @token) -- if @resource.invitation_due_at - %p= t('devise.mailer.invitation_instructions.accept_until', - due_date: l(@resource.invitation_due_at, - format: :'devise.mailer.invitation_instructions.accept_until_format')) + - if @resource.invitation_due_at + %p= t('devise.mailer.invitation_instructions.accept_until', + due_date: l(@resource.invitation_due_at, + format: :'devise.mailer.invitation_instructions.accept_until_format')) -%p= t('devise.mailer.invitation_instructions.ignore') + %p= t('devise.mailer.invitation_instructions.ignore') +- else + %p= link_to t('devise.mailer.invitation_instructions.sign_in'), root_url diff --git a/app/views/devise/mailer/invitation_instructions.text.haml b/app/views/devise/mailer/invitation_instructions.text.haml index 16a9f0a8..353f2a12 100644 --- a/app/views/devise/mailer/invitation_instructions.text.haml +++ b/app/views/devise/mailer/invitation_instructions.text.haml @@ -9,11 +9,15 @@ \ = site.description \ -= accept_invitation_url(@resource, invitation_token: @token) -\ -- if @resource.invitation_due_at - = t('devise.mailer.invitation_instructions.accept_until', - due_date: l(@resource.invitation_due_at, - format: :'devise.mailer.invitation_instructions.accept_until_format')) -\ -= t('devise.mailer.invitation_instructions.ignore') +- if @resource.created_by_invite? + = accept_invitation_url(@resource, invitation_token: @token) + \ + - if @resource.invitation_due_at + = t('devise.mailer.invitation_instructions.accept_until', + due_date: l(@resource.invitation_due_at, + format: :'devise.mailer.invitation_instructions.accept_until_format')) + \ + = t('devise.mailer.invitation_instructions.ignore') +- else + = root_url(change_locale_to: @resource.lang) + = t('devise.mailer.invitation_instructions.sign_in') diff --git a/config/locales/devise_invitable.en.yml b/config/locales/devise_invitable.en.yml index f6bfee40..39238140 100644 --- a/config/locales/devise_invitable.en.yml +++ b/config/locales/devise_invitable.en.yml @@ -23,6 +23,7 @@ en: accept: "Accept invitation" accept_until: "This invitation will be due in %{due_date}." ignore: "If you don't want to accept the invitation, please ignore this email. Your account won't be created until you access the link above and set your password." + sign_in: "Sign in to your account to accept or decline the invitation." time: formats: devise: diff --git a/config/locales/devise_invitable.es.yml b/config/locales/devise_invitable.es.yml index 144d6df6..e83a703c 100644 --- a/config/locales/devise_invitable.es.yml +++ b/config/locales/devise_invitable.es.yml @@ -23,6 +23,7 @@ es: accept: "Aceptar la invitación" accept_until: "La invitación vencerá el %{due_date}." ignore: "Si no querés aceptar la invitación, por favor ignora este correo. Tu cuenta no será creada hasta que aceptes la invitación y configures una contraseña." + sign_in: "Iniciá sesión con tu cuenta para aceptar o rechazar la invitación." time: formats: devise: From 706ff80b1864b791197741ff5afbd98ab808baae Mon Sep 17 00:00:00 2001 From: f Date: Tue, 21 Mar 2023 14:05:11 -0300 Subject: [PATCH 184/453] =?UTF-8?q?fix:=20algo=20est=C3=A1=20enviando=20la?= =?UTF-8?q?s=20opciones=20como=20array?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/gitlab_notifier_job.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index 2f39caf9..4d57c744 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -293,6 +293,7 @@ class GitlabNotifierJob < ApplicationJob # @param :options [Hash] # @return [Hash] def fix_options(options) + options = { data: options } if options.is_a? Array options[:data] ||= {} options[:data][:params] ||= {} From 1230dc2e96eb2bc117f1f92433e0d97748d4f2bf Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 09:58:00 -0300 Subject: [PATCH 185/453] fix: solo permitimos un hash de opciones --- app/jobs/gitlab_notifier_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index 4d57c744..7b369fab 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -293,7 +293,7 @@ class GitlabNotifierJob < ApplicationJob # @param :options [Hash] # @return [Hash] def fix_options(options) - options = { data: options } if options.is_a? Array + options = { data: options } unless options.is_a? Hash options[:data] ||= {} options[:data][:params] ||= {} From bbb951594b8594d6d71943b77c077573d813b8e1 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 09:59:36 -0300 Subject: [PATCH 186/453] fix: enviar las opciones post limpieza --- app/jobs/gitlab_notifier_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index 7b369fab..575d57d8 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -63,7 +63,7 @@ class GitlabNotifierJob < ApplicationJob # la notificamos por correo rescue StandardError => e email_notification.call(e, data: @issue) - email_notification.call(exception, data: options) + email_notification.call(exception, data: @options) end private From 823ac94e7434282a55a9d6a71fb235a7af553b2c Mon Sep 17 00:00:00 2001 From: Nulo Date: Mon, 2 May 2022 18:55:35 +0000 Subject: [PATCH 187/453] Arreglar scroll al reordenar posts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Utilizaba https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoViewIfNeeded que es propietario. Ahora usa scrollIntoView siempre, configurado para que prácticamente siempre se pueda ver el post al reordenar. --- app/javascript/controllers/reorder_controller.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/javascript/controllers/reorder_controller.js b/app/javascript/controllers/reorder_controller.js index dca6e166..2cba4163 100644 --- a/app/javascript/controllers/reorder_controller.js +++ b/app/javascript/controllers/reorder_controller.js @@ -103,11 +103,7 @@ export default class extends Controller { this.reorder() // Mantenemos el primero a la vista - if ("scrollIntoViewIfNeeded" in rows[0].row) { - rows[0].row.scrollIntoViewIfNeeded() - } else { - rows[0].row.scrollIntoView() - } + rows[0].row.scrollIntoView({ block: "center" }); } counter () { @@ -146,7 +142,7 @@ export default class extends Controller { this.reorder() // Mantenemos el primero a la vista - rows[0].row.scrollIntoViewIfNeeded() + rows[0].row.scrollIntoView({ block: "center" }); } bottom (event) { @@ -167,7 +163,7 @@ export default class extends Controller { this.reorder() // Mantenemos el primero a la vista - rows[0].row.scrollIntoViewIfNeeded() + rows[0].row.scrollIntoView({ block: "center" }); } /* From 88c1ffe4b8f1ff60bca474cf1ffe5263f8d417e9 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 13:43:13 -0300 Subject: [PATCH 188/453] fix: hacer que los locales sean bidireccionales #10491 #12064 --- app/models/metadata_locales.rb | 11 +----- app/views/posts/attributes/_locales.haml | 48 +++++++----------------- 2 files changed, 16 insertions(+), 43 deletions(-) diff --git a/app/models/metadata_locales.rb b/app/models/metadata_locales.rb index 4d540efc..702e1902 100644 --- a/app/models/metadata_locales.rb +++ b/app/models/metadata_locales.rb @@ -1,21 +1,14 @@ # frozen_string_literal: true # Los valores de este metadato son artículos en otros idiomas -class MetadataLocales < MetadataTemplate - def default_value - super || [] - end - +class MetadataLocales < MetadataHasAndBelongsToMany # Todos los valores posibles para cada idioma disponible # - # TODO: Optimizar? - # TODO: Mantener sincronizados - # # @return { lang: { title: uuid } } def values @values ||= site.locales.map do |locale| [locale, site.posts(lang: locale).map do |post| - [post.title.value, post.uuid.value] + [title(post), post.uuid.value] end.to_h] end.to_h end diff --git a/app/views/posts/attributes/_locales.haml b/app/views/posts/attributes/_locales.haml index 8dd7adf6..6d4d3326 100644 --- a/app/views/posts/attributes/_locales.haml +++ b/app/views/posts/attributes/_locales.haml @@ -1,39 +1,19 @@ --# +%fieldset + %legend= post_label_t(attribute, post: post) - Crea un input-map para cada idioma por separado. Podríamos hacer uno - solo que tenga todos los idiomas pero puede ser una interfaz confusa. + = render 'posts/attribute_feedback', + post: post, attribute: attribute, metadata: metadata - TODO: Esto permite seleccionar más de una traducción por idioma... + - site.locales.each do |locale| + - next if post.lang.value == locale + - locale_t = t("locales.#{locale}.name") -- site.locales.each do |locale| - -# Ignorar el idioma actual - - next if post.lang.value == locale - - locale_t = t("locales.#{locale}.name") - - values = metadata.value.select do |x| - - metadata.values[locale].values.include? x + .form-group + = label_tag "#{base}_#{attribute}_#{locale}", locale_t - .form-group - = label_tag "#{base}_#{attribute}_#{locale}", locale_t + = select_tag("#{plain_field_name_for(base, attribute)}[]", + options_for_select(metadata.values[locale]), + **field_options(attribute, metadata), include_blank: t('.empty')) - .mapable{ dir: t("locales.#{locale}.dir"), lang: locale, - data: { values: values.to_json, - 'default-values': metadata.values[locale].to_json, - name: "#{base}[#{attribute}][]", - list: id_for_datalist(attribute, locale), - button: t('posts.attributes.add'), - remove: 'false', legend: locale_t, - described: id_for_help(attribute, locale) } } - - = text_field(*field_name_for(base, attribute, '[]'), - value: values.join(', '), - dir: t("locales.#{locale}.dir"), lang: locale, - **field_options(attribute, metadata)) - - = render 'posts/attribute_feedback', - post: post, - attribute: [attribute, 'mapable'].flatten, - metadata: metadata - - %datalist{ id: id_for_datalist(attribute, locale) } - - metadata.values[locale].keys.each do |value| - %option{ value: value } + = render 'posts/attribute_feedback', + post: post, attribute: attribute, metadata: metadata From ad1d59d6a4616da92048d84587896dcc8041932d Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 13:55:51 -0300 Subject: [PATCH 189/453] fix: recuperar el valor --- app/views/posts/attributes/_locales.haml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/views/posts/attributes/_locales.haml b/app/views/posts/attributes/_locales.haml index 6d4d3326..21d410be 100644 --- a/app/views/posts/attributes/_locales.haml +++ b/app/views/posts/attributes/_locales.haml @@ -7,13 +7,12 @@ - site.locales.each do |locale| - next if post.lang.value == locale - locale_t = t("locales.#{locale}.name") + - value = metadata.value.find do |v| + - metadata.values[locale].values.include? v .form-group = label_tag "#{base}_#{attribute}_#{locale}", locale_t = select_tag("#{plain_field_name_for(base, attribute)}[]", - options_for_select(metadata.values[locale]), + options_for_select(metadata.values[locale], value), **field_options(attribute, metadata), include_blank: t('.empty')) - - = render 'posts/attribute_feedback', - post: post, attribute: attribute, metadata: metadata From 034015938bd07dd9471f006164cba6a6e564af8f Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 14:14:55 -0300 Subject: [PATCH 190/453] =?UTF-8?q?fix:=20mostrar=20el=20idioma=20si=20no?= =?UTF-8?q?=20existe=20una=20traducci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/posts/attributes/_locales.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/posts/attributes/_locales.haml b/app/views/posts/attributes/_locales.haml index 21d410be..23f66700 100644 --- a/app/views/posts/attributes/_locales.haml +++ b/app/views/posts/attributes/_locales.haml @@ -6,7 +6,7 @@ - site.locales.each do |locale| - next if post.lang.value == locale - - locale_t = t("locales.#{locale}.name") + - locale_t = t("locales.#{locale}.name", default: locale.to_s.humanize) - value = metadata.value.find do |v| - metadata.values[locale].values.include? v From 6d59d79e2a086bc653565cb93c9ef6406a9b910c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 14:26:06 -0300 Subject: [PATCH 191/453] =?UTF-8?q?fix:=20establecer=20relaci=C3=B3n=20bid?= =?UTF-8?q?ireccional=20#10491?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/metadata_locales.rb | 36 +++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/app/models/metadata_locales.rb b/app/models/metadata_locales.rb index 702e1902..2e9080c9 100644 --- a/app/models/metadata_locales.rb +++ b/app/models/metadata_locales.rb @@ -7,9 +7,43 @@ class MetadataLocales < MetadataHasAndBelongsToMany # @return { lang: { title: uuid } } def values @values ||= site.locales.map do |locale| - [locale, site.posts(lang: locale).map do |post| + [locale, posts.where(lang: locale).map do |post| [title(post), post.uuid.value] end.to_h] end.to_h end + + # Siempre hay una relación inversa + # + # @return [True] + def inverse? + true + end + + # El campo inverso se llama igual en el otro post + # + # @return [Symbol] + def inverse + :locales + end + + private + + # Obtiene todos los locales distintos a este post + # + # @return [Array] + def other_locales + site.locales.reject do |locale| + locale == post.lang.value.to_sym + end + end + + # Obtiene todos los posts de los otros locales con el mismo layout + # + # @return [PostRelation] + def posts + other_locales.map do |locale| + site.posts(lang: locale).where(layout: post.layout.value) + end.reduce(&:concat) + end end From fc14889d0eeb579e2b86aa6fd2250889d3ae0227 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 14:35:47 -0300 Subject: [PATCH 192/453] fix: soporte para urdu --- config/locales/en.yml | 3 +++ config/locales/es.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index 10a4793b..eb7ef1ec 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -13,6 +13,9 @@ en: ar: name: Arabic dir: rtl + ur: + name: Urdu + dir: rtl login: email: E-mail address password: Password diff --git a/config/locales/es.yml b/config/locales/es.yml index 02973de5..665fb350 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -13,6 +13,9 @@ es: ar: name: Árabe dir: rtl + ur: + name: Urdu + dir: rtl login: email: Correo electrónico password: Contraseña From 59606f32639fd48f849a0e27fcb1ac3fa8d6c589 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 14:38:18 -0300 Subject: [PATCH 193/453] fix: reducir el alto de la leyenda --- app/assets/stylesheets/application.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index b756759a..ba8de715 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -154,6 +154,12 @@ ol.breadcrumb { transition: all 3s; } +fieldset { + legend { + font-size: 1rem; + } +} + .mapable, .taggable { .input-map, From 758f9de36dde570f619d4f56faf6d9d56144981d Mon Sep 17 00:00:00 2001 From: Nulo Date: Mon, 2 May 2022 18:55:35 +0000 Subject: [PATCH 194/453] Arreglar scroll al reordenar posts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Utilizaba https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoViewIfNeeded que es propietario. Ahora usa scrollIntoView siempre, configurado para que prácticamente siempre se pueda ver el post al reordenar. --- app/javascript/controllers/reorder_controller.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/javascript/controllers/reorder_controller.js b/app/javascript/controllers/reorder_controller.js index dca6e166..2cba4163 100644 --- a/app/javascript/controllers/reorder_controller.js +++ b/app/javascript/controllers/reorder_controller.js @@ -103,11 +103,7 @@ export default class extends Controller { this.reorder() // Mantenemos el primero a la vista - if ("scrollIntoViewIfNeeded" in rows[0].row) { - rows[0].row.scrollIntoViewIfNeeded() - } else { - rows[0].row.scrollIntoView() - } + rows[0].row.scrollIntoView({ block: "center" }); } counter () { @@ -146,7 +142,7 @@ export default class extends Controller { this.reorder() // Mantenemos el primero a la vista - rows[0].row.scrollIntoViewIfNeeded() + rows[0].row.scrollIntoView({ block: "center" }); } bottom (event) { @@ -167,7 +163,7 @@ export default class extends Controller { this.reorder() // Mantenemos el primero a la vista - rows[0].row.scrollIntoViewIfNeeded() + rows[0].row.scrollIntoView({ block: "center" }); } /* From abacabff8efa261f79855cdd22c6217806a096fe Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 18:39:56 -0300 Subject: [PATCH 195/453] fix: agregar licencia con layout --- app/services/site_service.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 22423bb8..436bc1c3 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -104,11 +104,10 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do def add_licencia(lang:) params = ActionController::Parameters.new( post: { + layout: 'license', lang: lang, title: site.licencia.name, description: I18n.t('sites.form.licencia.title'), - author: %w[Sutty], - permalink: "#{I18n.t('activerecord.models.licencia').downcase}/", content: CommonMarker.render_html(site.licencia.deed) } ) From 46c20cae7de41225b63ba5ff44eb7e5484a0e4ab Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 18:41:12 -0300 Subject: [PATCH 196/453] feat: no agregar licencia si la plantilla no lo soporta --- app/services/site_service.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 436bc1c3..87a08652 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -92,6 +92,8 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # Crea la licencia del sitio para cada locale disponible en el sitio def add_licencias + return unless site.layout? :license + site.locales.each do |locale| next unless I18n.available_locales.include? locale From 0b353466a4c8113ed7c3fd57bed9f622ca298643 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 18:43:20 -0300 Subject: [PATCH 197/453] fix: solo cambiar la licencia si existe una #159 --- app/services/site_service.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 87a08652..b4fa2fa0 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -119,18 +119,14 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # Encuentra la licencia a partir de su enlace permanente y le cambia # el contenido - # - # TODO: Crear un layout específico para licencias así es más certera - # la búsqueda. def change_licencias site.locales.each do |locale| next unless I18n.available_locales.include? locale Mobility.with_locale(locale) do - permalink = "#{I18n.t('activerecord.models.licencia').downcase}/" - post = site.posts(lang: locale).find_by(permalink: permalink) + post = site.posts(lang: locale).find_by(layout: 'license') - post ? change_licencia(post: post) : add_licencia(lang: locale) + change_licencia(post: post) if post end end end From 7b68bc15692ba4032e7ec9b660f6fc624512250d Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 18:45:41 -0300 Subject: [PATCH 198/453] =?UTF-8?q?fix:=20crear=20las=20licencias=20despu?= =?UTF-8?q?=C3=A9s=20de=20crear=20el=20t=C3=ADtulo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit y los commits también se harían en el idioma de le usuarie --- app/services/site_service.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index b4fa2fa0..e98d2487 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -14,11 +14,10 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do I18n.with_locale(usuarie&.lang&.to_sym || I18n.default_locale) do site.save && site.config.write && - commit_config(action: :create) + commit_config(action: :create) && + add_licencias end - add_licencias - site end @@ -27,11 +26,10 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do I18n.with_locale(usuarie&.lang&.to_sym || I18n.default_locale) do site.update(params) && site.config.write && - commit_config(action: :update) + commit_config(action: :update) && + change_licencias end - change_licencias - site end From ddd2bc07ff62b24745e74af4d6ce7284263e8117 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 19:04:15 -0300 Subject: [PATCH 199/453] =?UTF-8?q?feat:=20incorporar=20los=20c=C3=B3digos?= =?UTF-8?q?=20de=20conducta?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/code_of_conduct.rb | 14 + app/services/site_service.rb | 34 +- config/initializers/inflections.rb | 4 + .../20230322214924_add_code_of_conduct.rb | 22 + db/seeds/codes_of_conduct.yml | 613 ++++++++++++++++++ 5 files changed, 686 insertions(+), 1 deletion(-) create mode 100644 app/models/code_of_conduct.rb create mode 100644 db/migrate/20230322214924_add_code_of_conduct.rb create mode 100644 db/seeds/codes_of_conduct.yml diff --git a/app/models/code_of_conduct.rb b/app/models/code_of_conduct.rb new file mode 100644 index 00000000..87c24c7f --- /dev/null +++ b/app/models/code_of_conduct.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Códigos de conducta +class CodeOfConduct < ApplicationRecord + extend Mobility + + translates :title, type: :string, locale_accessors: true + translates :description, type: :text, locale_accessors: true + translates :content, type: :text, locale_accessors: true + + validates :title, presence: true, uniqueness: true + validates :description, presence: true + validates :content, presence: true +end diff --git a/app/services/site_service.rb b/app/services/site_service.rb index e98d2487..19b95302 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -15,7 +15,8 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do site.save && site.config.write && commit_config(action: :create) && - add_licencias + add_licencias && + add_code_of_conduct end site @@ -141,10 +142,41 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do params: params).update end + def add_code_of_conduct + # TODO: soportar más códigos de conducta + coc = CodeOfConduct.first + + with_all_locales do |locale| + params = ActionController::Parameters.new( + post: { + layout: 'code_of_conduct', + 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 + 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: 'DeployRsync', destination: "sutty@#{node}:#{site.hostname}") end end + + private + + def with_all_locales(&block) + site.locales.each do |locale| + next unless I18n.available_locales.include? locale + + Mobility.with_locale(locale) do + yield locale + end + end + end end diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index 0e18b987..46cb9d78 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -13,6 +13,8 @@ ActiveSupport::Inflector.inflections(:en) do |inflect| inflect.singular 'roles', 'rol' inflect.plural 'rollup', 'rollups' inflect.singular 'rollups', 'rollup' + inflect.plural 'code_of_conduct', 'codes_of_conduct' + inflect.singular 'codes_of_conduct', 'code_of_conduct' end ActiveSupport::Inflector.inflections(:es) do |inflect| @@ -28,4 +30,6 @@ ActiveSupport::Inflector.inflections(:es) do |inflect| inflect.singular 'licencias', 'licencia' inflect.plural 'rollup', 'rollups' inflect.singular 'rollups', 'rollup' + inflect.plural 'code_of_conduct', 'codes_of_conduct' + inflect.singular 'codes_of_conduct', 'code_of_conduct' end diff --git a/db/migrate/20230322214924_add_code_of_conduct.rb b/db/migrate/20230322214924_add_code_of_conduct.rb new file mode 100644 index 00000000..f859b08c --- /dev/null +++ b/db/migrate/20230322214924_add_code_of_conduct.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +# Crea códigos de conducta +class AddCodeOfConduct < ActiveRecord::Migration[6.1] + def up + create_table :codes_of_conduct do |t| + t.timestamps + t.string :title + t.text :description + t.text :content + end + + # XXX: En lugar de ponerlo en las seeds + YAML.safe_load(File.read('db/seeds/codes_of_conduct.yml')).each do |coc| + CodeOfConduct.new(**coc).save! + end + end + + def down + drop_table :codes_of_conduct + end +end diff --git a/db/seeds/codes_of_conduct.yml b/db/seeds/codes_of_conduct.yml new file mode 100644 index 00000000..64582072 --- /dev/null +++ b/db/seeds/codes_of_conduct.yml @@ -0,0 +1,613 @@ +--- +- title_en: "Codes for sharing" + title_es: "Códigos para compartir" + description_en: "Codes of conduct allow inclusive communities." + description_es: "Los códigos de convivencia nos permiten alojar comunidades inclusivas." + content_en: | + # Code for sharing + + > This code of conduct is based in "[Códigos para compartir, hackear, + > piratear en + > libertad](https://utopia.partidopirata.com.ar/zines/codigos_para_compartir.html)" + > published by [Partido Interdimensional + > Pirata](https://partidopirata.com.ar/). + + > We use gender neutral pronouns to include all peoples. In this sense, + > we encourage different forms, strategies and tools used to embody + > practices that aren't anthropocentric, sexist, cis-sexist in our + > language. + + ## Introduction + + This is an example code that strives to give a consensual frame to + enable asistance, permanence and confortable stay to everyone using and + inhabiting [Sutty](https://sutty.nl/), and to welcome new users and + potential allies as well. It sets the floor for desirable and + acceptable, and undesirable and intolerable conducts for its community. + You can use it with or without changes, adapting it to your activities. + This code is in permanent and collective mutation and feeds, copies and + inspires on the following sources: + + * + + * + + * + + * + + We strive to sustain and foment an open community, that invites and + attains participation from more people, in all their diversity. We know + that spaces related to computing and free software are mostly inhabited + by middle class cis white males, even when there's an acknowledgement of + the need to close the gender gap. In this sense, this is our little + contribution, made from collective practices on multiple dimentions, + reflections, readings, and experiences that grow every day. + + ## That everyone needs to be well treated + + Every being that we share space with deserves good treatment, respect + and compassion. Here we share basic criteria for introduction and care. + + ### Towards humans + + Everyone is deserving of care and greetings and we have a right to + assume good intentions from others. + + When we refer to other humans, we try to be careful and respectul + towards their gender identity. For this, these principles are useful: + + * Don't assume, judge or try to "interpret" the gender of others. + + * Don't use gender beforehand. It's related to the previous item, but + puts emphasis towards naturalized gendering behaviour (ie. assuming + someone wearing a dress uses female pronouns...). The proposal is to + discard them. + + * If a person explicits their pronouns and mode in which they want to be + referenced, we respect them, by listening and trying to use their + prefered pronouns. + + * When presentations don't include pronouns, we can ask respectfully + for prefered pronouns. But be careful! This question must be asked + to everyone, otherwise the "suspicion" is loaded towards a person, and + it can become a form of harrassment. + + * Do we need to know the gender of a person to relate with them? Maybe + a better practice is to evade gendering others. But if this means to + use "them" compulsively, some people may be made to feel bad. (For + instance, trans\* people who use female or male pronouns may feel + upset or outed when refering to them as "them", specially if they're + the only ones to be gendered like this in a group! + + * When in doubt, asking and apologizing respectfully is a good way of + being careful towards each other. + + ## Important points to guarantee our space from being expulsive + + **Listening to and between everyone in a caring climate** + + * Listen to what everyone has to say, being mindful that everyone has + something valuable to communicate. + + * For active listening, we prefer to ask first, before making judgement. + + * Sometimes being silent is a condition for others to be able to talk. + To listen is an exercise that requires practice. Also talking. + + * We're interested in what everyone has to say. If you're more trained + in participating, talking, and having opinions, take into account that + not everyone does. Give them space if they want to take it. But + remember that encouraging is not the same as pressuring! + + * We try to check and stop offensive practices to add to the respectful + climate. This doesn't mean to be submissive or to agree to + everything. At the least, it sets a floor of respect towards enabling + a dialogue when necessary. + + * It's at the very least disrepectful to repeat damaging behaviour when + it was already identified as such. It can make others unconfortable, + or hurt and expel them. We'll make this point every time that is + needed and tolerable. + + * We avoid this behaviour ourselves and we help others to notice their + own. + + * When raising attention becomes insufficient, we need to review this + agreements to keep the coexistence. This implies to act in accord to + them, and that this code can be revised and updated when deemed + necessary (there's no consensus). + + * One of the ways in which free software spaces can be and are expulsive + is with attitudes that don't contemplate diversity in knowledges and + interlocutors. By appealing to technicisms, many comrades are kept + out of what's happening, and no one verifies if everyone is keeping up + with the conversation. + + Our fervent recommendation is to be attentive to this dynamic so we + can avoid or revert them. + + * The counter to the previous situation is "mansplaining": a cis-male + person assuming the authoritative place of knowledge to (over-)explain + everything to others, in a patronizing way and without taking into + account what others want to listen or not, to say, what already know + or do, etc. + + * We believe there's no "authoritative voice" to have an opinion and to + participate. Free culture is for everyone to share. + + * "Sharing is caring" v. "Google is your friend". Meritocracy and other + traditional codes in cyber-communities work against free culture. We + support the pirate culture that onboards ever more pirates to their + ships. We believe that culture is for everyone and we defy elitisms. + + * We don't assume that other people shares our likings, beliefs, class + position, sexuality, etc. We can be violent when we misread others. + We recommend to ask respectfully and to avoid comments or jokes that + can be hurtful to others. + + * We speak and act gently and inclusively. + + * We respect different points of view, experiences, beliefs, etc. and we + take them into account when we act collectively so it reflects in our + attitudes. + + * We welcome criticism, specially the constructive kind ;) + + * We focus in what's best for the community, without losing warmth, + respect and diversity amongst ourselves. + + * We show empathy toward others. We want to share and communicate. + + * It's useful to think everyone has different abilities, stories, + experiences... It's possible to not understand some comments. We try + to avoid acting in bad faith and to use every accessibility tool we + can. + + * The last item includes neurodiverse people and those that have + experienced trauma. Sometimes, sarcasm or irony is not well received + or understood by others. We take this into our strategies to include + everyone in our communications. Even more, if we think some topics + could be sensitive to others (memory-triggering, phobias, untolerable, + explicit violence or body images, etc.), we use content warnings (cw) + before what we wanted to share. For instance: "cw: comments about + sexual and physical violence". This allows everyone to opt in to the + content instead of being taken by surprise. + + * We're respectful of limits established by others (personal space, + physical contact, interaction mood, privacy, being photographed, etc.) + + * We want to and believe in welcoming more pirates! + + ## Consent for documenting and sharing in media + + * If you're going to take pictures or record video, ask consent from + people involved. + + * If there're minors, ask their responsible families. + + ## Our commitment against harassment + + In the interest of fomenting an open, diverse and welcoming community, + we contributors and admins make a commitment against harassment in our + projects and community for everyone, without regard of age, body + diversity, capacity, neuro-diversity, ethnicity, gender identity and + expression, experience level, nationality, physical appearance, + religion, sexual identity or orientation. + + Examples of unacceptable behaviour from participants: + + * Offensive comments about gender/s, gender identity and expression, + sexual orientation, capacity, mental sickness, neuro-(a)tipicality, + physical appearance, body size, ethnicity or religion. + + * Unwelcomed comments related to personal and life choices, including + amongst others, those related to food, health, children upbringing, + drug use and employment. + + * Insulting or despective comments and personal or political attacks. + **Trolling**. + + * Assuming others' gender. If you're in doubt, ask politely about + pronouns. Don't use the name(s) that people don't use anymore, use + the name, _nickname_ or pseudonym that they prefer. Do you really + need the name, ID number, biometric data, birth certificate of others? + + * Sexual comments, images or behaviour, unneeded or in spaces where they + weren't appropiate. + + * Unconsented physical contact or repeated after being asked to stop. + + * Threatening others. + + * Inciting violence towards others, including self-damage. + + * Deliberate intimidation. + + * Stalking. + + * To harass by photographing or recording without consent, including + uploading personal information to the Internet. + + * Interrupting a conversation constantly. + + * Making unwanted sexual comments. + + * Unappropiate patterns of social contact, like asking/assuming + inappropiate intimacy levels with others. + + * Trying to interact with a person after being asked not to. + + * Exposing deliberately any aspect of a person identity without consent, + except when necessary for protecting others against intentional abuse. + + * Making public any kind of private conversation. + + * Other kinds of conduct that can be considered inappropiate in an + environment of camaraderie. + + * Repeating attitudes that others find offensive or violatory of this + code. + + ## Consequences + + * Any person that has been asked to stop offensive behaviour is expected + to respond immediately, even when in disagreement. + + * Admins can take any action deemed necessary and adequate, including + expelling the person or removing their site without advertence. This + decision is taken by consensus between admins and is reserved for + extreme cases that compromise the community or the permanence of + others without feeling wronged or threatened. + + * Admins reserve the right to forbid participation to any future + activity or publication. + + As we mentioned before, this code is in permanent collective mutation. + It's main objective is to generate an inclusive and non-expulsive + environment that is also transparent and open without [missing + stairs](https://en.wikipedia.org/wiki/Missing_stair) ("the missing stair + from a house that everyone knows about but no one wants to take + responsibility for"). It's important to adapt it to different + activities and that it nurtures from contributions from its users. + Receiving your comments and input will help us to achieve this + objective. + + ## Let's keep in contact! + + Si pasaste por alguna situación que quieras compartir --te hayas animado + o no a decirlo en el momento--, podés ponerte en contacto con nosotres. + + Con respecto a quejas o avisos acerca de situaciones de violencia, + acoso, abuso o repetición de conductas que se advirtieron como + intolerables, tomamos la responsabilidad de tenerlas en cuenta y + trabajar en ellas para que el resultado sea el favorable al espíritu de + colectiva que elegimos y describimos aquí. Si bien consideramos que las + prácticas punitivistas no van con nosotres, nuestra decisión explícita + es escuchar a la persona que se manifiesta como violentada o víctima y + acompañarla. + + You can contact us if you were part of a situation you want to share + --even if you didn't pointed it in the moment. + + In regards to complaints or notices about violence, harassment, abuse or + repeated untolerable conducts, we take the responsibility of working on + them for a favorable result towards the collective spirit we defined + here. Even when we don't condone punitivist practices, our explicit + decision is for the victim to be listened and accompanied. + content_es: | + # Códigos para compartir + + > Este código de convivencia está basado en los "[Códigos para + > compartir, hackear, piratear en + > libertad](https://utopia.partidopirata.com.ar/zines/codigos_para_compartir.html)" + > publicados por el [Partido Interdimensional + > Pirata](https://partidopirata.com.ar/). + + > Utilizamos preferentemente la 'e' para referirnos a las personas en + > general. En ese sentido, alentamos las diferentes formas, estrategias + > y herramientas para incorporar prácticas no antropocéntricas, + > sexistas, ni cisexistas en la lengua. Otras alternativas que apoyamos + > --y eventualmente usamos-- son el uso del femenino, la letra e, arrobas, + > equis, asteriscos, etc. + + ## Introducción + + Este es un ejemplo de código que busca aportar un marco de consenso para + garantizar la asistencia, permanencia y cómoda estadía de todas las + personas que habitan y utilizan Sutty, así como para bienvenir a nueves + usuaries y potenciales aliades. Para esto, fija un piso de conductas + deseables, aceptables, indeseables y/o intolerables para la comunidad. + Podés usarlo sin cambios o modificarlo para adaptarlo a tus actividades. + Este código está en permanente mutación colectiva y se alimenta, copia e + inspira de las siguientes fuentes: + + * + + * + + * + + * + + Procuramos mantener y fomentar una comunidad abierta, que invite y logre + la participación de cada vez más personas, en toda su diversidad. + Sabemos que los espacios de Software Libre, informática, sistemas, etc. + son habitados mayormente por varones cis, blancos y de clase media, pese + al reconocimiento de la necesidad de eliminar la brecha de géneros. En + este sentido, este es nuestro pequeño aporte, hecho de prácticas + colectivas de múltiples dimensiones, reflexiones, lecturas, experiencias + que crecen día a día. + + ## Que todes les seres sean bien tratades + + Cada ser con el que compartamos el espacio es merecedore de buen trato, + respeto y compasión. En otras palabras, compartimos a continuación los + criterios básicos de presentación y cuidados. + + Para les humanes + + Todes somos dignes de cuidados y de saludos y tenemos derecho a suponer + las buenas intenciones de le otre. + + Para referirnos a otres humanes, trataremos de ser cuidadoses y + respuestuoses de su identidad de género. Para ello, son útiles los + siguientes principios: + + * No presuponer, juzgar o "interpretar" el género de le otre. + + * No generizar de antemano. Se desprende del punto anterior, pero hace + especial énfasis en comportamientos naturalizados de generización (EJ: + presuponer que porque una persona usa un vestido se nombra en + femenino...). La propuesta es desecharlos. + + * Si la persona explicita sus pronombres y modos en que quiere ser + referenciade, lo respetamos, escuchando y procurando referirnos a elle + usando sus pronombres elegidos. + + * Si no se incluye en la presentación los pronombres preferidos, podemos + preguntar respetuosamente qué pronombres se usan. ¡Pero atención! Es + una pregunta que debe dirigirse a todes por igual, de lo contrario, + carga la "sospecha" sobre la persona señalada y puede resultar en una + forma de hostigamiento. + + * ¿Es necesario conocer el género de una persona para relacionarnos o + referirnos a ella? Quizás una buena práctica es evitar generizar para + todas las personas. Pero si esto implica el uso compulsivo de la "e" + para todes, puede ser que alguna persona se sienta molesta. (Por + ejemplo, las personas trans\* que se identifican en femenino o + masculino suelen sentirse molestas y "sacadas del clóset" u *outeadas* + si se refieren a ellas con la "e", ¡en especial si son las únicas en + ser generizadas de esta forma en un grupo!). + + * Ante cualquier duda, preguntar respetuosamente y disculparse + respetuosamente es una buena idea para ayudar a cuidarnos. + + ## Puntos importantes para garantizar que nuestro espacio no resulte expulsivo + + **Escucharnos a todas y entre todas en un clima de cuidados** + + * Escuchar lo que cada quien tiene para decir, conscientes de que todes + tenemos algo valioso para comunicar(nos). + + * Para la escucha activa, preferimos preguntar primero, en lugar de + hacer juicios. + + * Hacer silencio a veces es la condición para que otres puedan animarse + a hablar. Escuchar es un ejercicio que requiere práctica. También lo + es hablar. + + * Nos interesa lo que todes tengan para decir. Por lo tanto, si estás + más entrenade en el ejercicio de participar, hablar, opinar, tené en + cuenta que quizás haya otres que no lo estén tanto: darles el espacio + si quieren tomarlo. ¡Pero recordá que incentivar no es lo mismo que + presionar! + + * Tratamos de revisar y discontinuar alguna práctica que pueda haber + resultado ofensiva, para sumar al clima de respeto. Sin embargo, esto + no significa "bajar la cabeza" o estar necesariamente de acuerdo. Al + menos, fija un piso de respeto para comenzar un diálogo en el caso en + que sea necesario. + + * Es --al menos-- una falta de respeto repetir un comportamiento dañino + que ya se identificó como tal. Puede incomodar, lastimar y expulsar a + otres, por lo que preferimos llamar la atención sobre este punto todas + las veces que sea necesario y tolerable. + + * Evitamos esto nosotres y ayudamos a otres a darse cuenta cuando lo + están haciendo. + + * En los casos en los que los llamados de atención resulten + insuficientes, hemos de revisar estos acuerdos para sostener la + convivencia. Eso implica actuar de acuerdo a ellos. Y también que + estos códigos pueden ser revisados y actualizados en caso de que se + considere necesario (deje de haber consenso). + + * Una manera en la que los espacios de Software Libre y tecnologías + pueden y suelen ser expulsivos es mediante actitudes que no contemplan + la diversidad de saberes e interlocutor\*s. So pretexto de incluir + tecnicismos, muches compañeres quedan al margen de lo que está + sucediendo, muchas veces, sin que nadie tenga la mínima delicadeza de + verificar que todes estén siguiendo la conversación. + + Recomendamos fervientemente estar atentes a estas dinámicas para poder + evitarlas y/o revertirlas. + + * La otra cara de la situación anterior es el famoso _mansplaining_: un + tipo cis poniéndose en el lugar de la autoridad del saber para + (sobre-)explicar todo a le otre, de manera paternalista y sin tener en + cuenta lo que le otre quiere o no escuchar, decir, lo que sabe o hace, + etc. + + * Creemos que no hace falta ser "una voz autorizada" para opinar y + participar. La cultura libre se comparte entre todes. + + * "Compartir es bueno" vs. "Google es tu amigo". La meritocracia y + ciertos códigos tradicionales de ciertas ciber-comunidades suelen + operar de manera contraria a la propuesta de la cultura libre de + compartir. Apoyamos la cultura piratil que suma más piratas a los + barcos. Creemos que la cultura es para todes y desafiamos las + prácticas elitistas. + + * No damos por sentado que la persona con la que estamos interactuando + comparte gustos, creencias, pertenencias de clase, sexualidad, etc. + Podemos ser violentes si hacemos una lectura equivocada de le otre. + Recomendamos siempre preguntar de manera respetuosa y evitar + comentarios o chistes que puedan herir a les otres. + + * Usamos lenguaje amable e inclusivo y mostramos conductas amables e + inclusivas. + + * Respetamos los diferentes puntos de vista, experiencias, creencias, + etc. y lo tenemos en cuenta cuando estamos en grupo para verlo + reflejado en nuestras actitudes. + + * Aceptamos las críticas. En especial las constructivas ;) + + * Nos enfocamos en lo que es mejor para la comunidad, sin por ello + perder de vista la calidez, el respeto y la diversidad entre cada une + de nosotres. + + * Mostramos empatía con les otres. Queremos comunicarnos y compartir. + + * Es útil tener en cuenta que las personas tenemos capacidades, + historias, recorridos... diferentes. Es posible que algunos + comentarios no sean comprendidos. Trataremos de evitar la mala fe y + sumar todas las herramientas de accesibilidad para todas las personas. + + * El punto anterior incluye a personas neurodiversas y con experiencias + de trauma. A veces el sarcasmo o la ironía no es bien recibido o + comprendido por todes. Será útil tenerlo en cuenta para buscar + estrategias que no excluyan a las personas de nuestros intercambios. + Por otro lado, si creemos que determinados temas pueden ser sensibles + (desencadenantes de recuerdos, fobias, difíciles de tolerar o cargados + de violencia o imágenes corporales muy explícitas, por ejemplo) para + algunas personas y nos valemos de las advertencias de contenido o + _content warning_ (cw) (ej: "cw: comentarios de violencia sexual y + violencia física") antes del contenido a introducir. Esto permite que + cada cual pueda elegir si acceder o no a esos contenidos y que no le + tomen por sorpresa. + + * Respetamos los límites que establecen otras personas (espacio + personal, contacto físico, ganas de interactuar, no querer dar datos + de contacto o ser fotografiades, etc.) + + * ¡Queremos y (creemos) en sumar piratas! + + ## Consentimiento para documentar o compartir en medios + + * Si vas a publicar video o fotos, obtené el consentimiento de las + personas. + + * Si hay menores, consultalo con su familia responsable. + + ## Nuestro compromiso contra el acoso + + En el interés de fomentar una comunidad abierta, diversa y hospitalaria, + nosotres como contribuyentes y administradores nos comprometemos a hacer + de la participación en nuestro proyecto y nuestra comunidad una + experiencia libre de acoso para todes, independientemente de la edad, + diversidad corporal, capacidades, neuro-diversidad, etnia, identidad y + expresión de género, nivel de experiencia, nacionalidad, apariencia + física, raza, religión, identidad u orientación sexual y otras. + + Ejemplos de comportamiento inaceptable por parte de participantes: + + * Comentarios ofensivos relacionados con el/los género/s, la identidad + y expresión de género, la orientación sexual, las capacidades, las + enfermedades mentales, la neuro(a)tipicalidad, la apariencia física, + el tamaño corporal, la raza o la religión. + + * Comentarios indeseados relacionados con las elecciones y las prácticas + de estilo de vida de una persona, incluidas, entre otras, las + relacionadas con alimentos, salud, crianza de les hijes, drogas y + empleo. + + * Comentarios insultantes o despectivos (_trolling_) y ataques + personales o políticos. + + * Dar por sentado el género de las demás personas. En caso de duda, + preguntá educadamente por los pronombres. No uses nombres con los que + las personas no se identifican, usá el nombre, _nickname_ o apodo que + hayan elegido (¿Realmente necesitás el nombre y el número de DNI, + datos biométricos, carta natal, etc.?). + + * Comentarios, imágenes o comportamientos sexuales innecesarios o fuera + de lugar en espacios en los que no son apropiados. + + * Contacto físico sin consentimiento o reiterado tras un pedido de cese. + En el mismo sentido, invasión del espacio corporal (y espacios en + general). + + * Amenazas contra otras personas. + + * Incitación a la violencia contra otra persona, que también incluye + alentar a una persona a autolesionarse. + + * Intimidación deliberada. + + * Acechar (_stalkear_) o perseguir. + + * Acosar fotografiando o grabando sin consentimiento, incluyendo también + subir información personal a Internet sobre alguien para acosarle. + + * Interrumpir constantemente en una conversación. + + * Hacer comentarios sexuales indeseados. + + * Patrones de contacto social inapropiados, como por ejemplo + pedir/suponer niveles de intimidad inapropiados con les demás. + + * Seguir tratando de entablar conversación con una persona cuando se te + pidió que no lo hagas. + + * Divulgar deliberadamente cualquier aspecto de la identidad de una + persona sin su consentimiento, excepto que sea necesario para proteger + a otras personas de abuso intencional. + + * Hacer pública una conversación privada de cualquier tipo. + + * Otros tipos de conducta que pudieran considerarse inapropiadas en un + entorno de camaradería. + + * Reiteración de actitudes que les participantes señalen como ofensivas + o violatorias de este código. + + ## Consecuencias + + * Se espera que la persona a la que se la haya pedido que cese un + comportamiento que infringe este código acate el pedido de forma + inmediata, incluso si no está de acuerdo con este. + + * Les administradores pueden tomar cualquier acción que juzguen + necesaria y adecuada, incluyendo expulsar a la persona o dar de baja + sus sitios sin advertencia. Esta decisión la toman les administradores + en consenso y se reserva para casos extremos que comprometan la + continuidad de la comunidad o bien la posibilidad de permanencia en + ella de otres participantes sin sentirse agraviades o amenazades. + + * Les administradores se reservan el derecho a prohibir la asistencia a + cualquier actividad futura o publicación de sitios. + + Como mencionamos antes, este código está en permanente mutación + colectiva. El objetivo principal es generar un ambiente inclusivo y no + expulsivo, un ambiente transparente y abierto en el que no haya + escalones faltantes ("el escalón que falta en la escalera y todo el + mundo sabe y avisa pero nadie se quiere hacer cargo"). Es importante que + se adapte a las actividades y se nutra de las contribuciones de les + usuaries. Recibir tus comentarios y aportes nos ayudará a cumplir con + su objetivo principal. + + ## ¡Sigamos en contacto! + + Si pasaste por alguna situación que quieras compartir --te hayas animado + o no a decirlo en el momento--, podés ponerte en contacto con nosotres. + + Con respecto a quejas o avisos acerca de situaciones de violencia, + acoso, abuso o repetición de conductas que se advirtieron como + intolerables, tomamos la responsabilidad de tenerlas en cuenta y + trabajar en ellas para que el resultado sea el favorable al espíritu de + colectiva que elegimos y describimos aquí. Si bien consideramos que las + prácticas punitivistas no van con nosotres, nuestra decisión explícita + es escuchar a la persona que se manifiesta como violentada o víctima y + acompañarla. From 3f3ef0041092c06ade35df5a0b278a4e79fc976c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 19:06:57 -0300 Subject: [PATCH 200/453] =?UTF-8?q?fix:=20solo=20crear=20el=20c=C3=B3digo?= =?UTF-8?q?=20de=20conducta=20si=20la=20plantilla=20lo=20soporta?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit como fallback usamos page --- app/services/site_service.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 19b95302..e0fe17cd 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -143,13 +143,15 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do end def add_code_of_conduct + return 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: 'code_of_conduct', + layout: site.layout?(:code_of_conduct) ? 'code_of_conduct' : 'page', lang: locale.to_s, title: coc.title, description: coc.description, From 89ef2959e3c93a889677c3051a6987712a3434af Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 19:21:52 -0300 Subject: [PATCH 201/453] feat: usar un slug sino cuando cambia la licencia queda con la url de la anterior --- app/services/site_service.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index e0fe17cd..225c6292 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -106,6 +106,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do params = ActionController::Parameters.new( post: { layout: 'license', + slug: Jekyll::Utils.slugify(I18n.t('activerecord.models.licencia')), lang: lang, title: site.licencia.name, description: I18n.t('sites.form.licencia.title'), From e25b4858a01df490a66e5c818c0676828e45d539 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 19:23:51 -0300 Subject: [PATCH 202/453] fix: no cambiar las licencias si el sitio no las soporta --- app/services/site_service.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 225c6292..e4793453 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -120,6 +120,8 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # Encuentra la licencia a partir de su enlace permanente y le cambia # el contenido def change_licencias + return unless site.layout? :license + site.locales.each do |locale| next unless I18n.available_locales.include? locale From 368001b341bfa0b6891a15088625c615d6839098 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 19:32:52 -0300 Subject: [PATCH 203/453] =?UTF-8?q?fix:=20poder=20encadenar=20licencias=20?= =?UTF-8?q?con=20c=C3=B3digos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/site_service.rb | 46 ++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index e4793453..47b532f4 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -90,18 +90,19 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do end # Crea la licencia del sitio para cada locale disponible en el sitio + # + # @return [Boolean] def add_licencias - return unless site.layout? :license + return true unless site.layout? :license - site.locales.each do |locale| - next unless I18n.available_locales.include? locale - - Mobility.with_locale(locale) do - add_licencia lang: locale - end - end + 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: { @@ -119,20 +120,22 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # Encuentra la licencia a partir de su enlace permanente y le cambia # el contenido + # + # @return [Boolean] def change_licencias - return unless site.layout? :license + return true unless site.layout? :license - site.locales.each do |locale| - next unless I18n.available_locales.include? locale + with_all_locales do |locale| + post = site.posts(lang: locale).find_by(layout: 'license') - Mobility.with_locale(locale) do - post = site.posts(lang: locale).find_by(layout: 'license') - - change_licencia(post: post) if post - end - end + 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: { @@ -145,8 +148,11 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do params: params).update end + # Agrega un código de conducta + # + # @return [Boolean] def add_code_of_conduct - return unless site.layout?(:code_of_conduct) || site.layout?(:page) + return true unless site.layout?(:code_of_conduct) || site.layout?(:page) # TODO: soportar más códigos de conducta coc = CodeOfConduct.first @@ -163,7 +169,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do ) PostService.new(site: site, usuarie: usuarie, params: params).create - end + end.compact.map(&:valid?).all? end # Crea los deploys necesarios para sincronizar a otros nodos de Sutty @@ -176,7 +182,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do private def with_all_locales(&block) - site.locales.each do |locale| + site.locales.map do |locale| next unless I18n.available_locales.include? locale Mobility.with_locale(locale) do From 136a9e3edba9f5fe719c072c4b020996e90a9a28 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 19:44:17 -0300 Subject: [PATCH 204/453] =?UTF-8?q?fix:=20traducir=20la=20descripci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/site_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 47b532f4..449db16a 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -110,7 +110,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do slug: Jekyll::Utils.slugify(I18n.t('activerecord.models.licencia')), lang: lang, title: site.licencia.name, - description: I18n.t('sites.form.licencia.title'), + description: site.licencia.description, content: CommonMarker.render_html(site.licencia.deed) } ) From caa4861d79172cf6e49dab6c0e5cade15abcf023 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 19:54:04 -0300 Subject: [PATCH 205/453] fix: poder pasar el slug como parametro como slug es un atributo privado, hay que asignarlo manualmente --- app/services/post_service.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/services/post_service.rb b/app/services/post_service.rb index e448bb4c..81ebe4a1 100644 --- a/app/services/post_service.rb +++ b/app/services/post_service.rb @@ -12,6 +12,10 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do post.usuaries << usuarie params[:post][:draft] = true if site.invitade? usuarie + params.require(:post).permit(:slug).tap do |p| + post.slug.value = p[:slug] if p[:slug].present? + end + commit(action: :created, file: update_related_posts) if post.update(post_params) # Devolver el post aunque no se haya salvado para poder rescatar los From 0263169074f7795ae719d074f9f90f7aa2163d5c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 20:00:39 -0300 Subject: [PATCH 206/453] fix: devolver true aunque no haga falta modificar la configuracion --- app/models/site/config.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/site/config.rb b/app/models/site/config.rb index 3215277e..11277a19 100644 --- a/app/models/site/config.rb +++ b/app/models/site/config.rb @@ -31,7 +31,7 @@ class Site # Escribe los cambios en el repositorio def write - return if persisted? + return true if persisted? @saved = Site::Writer.new(site: site, file: path, content: content.to_yaml).save From 0817139032ad0a93d4618fa6bcc78e474a4212bb Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 21:01:29 -0300 Subject: [PATCH 207/453] =?UTF-8?q?feat:=20agregar=20pol=C3=ADtica=20de=20?= =?UTF-8?q?privacidad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/privacy_policy.rb | 14 +++ app/services/site_service.rb | 26 +++- config/initializers/inflections.rb | 4 + .../20230322231344_add_privacy_policy.rb | 22 ++++ db/seeds/privacy_policies.yml | 113 ++++++++++++++++++ 5 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 app/models/privacy_policy.rb create mode 100644 db/migrate/20230322231344_add_privacy_policy.rb create mode 100644 db/seeds/privacy_policies.yml diff --git a/app/models/privacy_policy.rb b/app/models/privacy_policy.rb new file mode 100644 index 00000000..8805daa9 --- /dev/null +++ b/app/models/privacy_policy.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Políticas de privacidad +class PrivacyPolicy < ApplicationRecord + extend Mobility + + translates :title, type: :string, locale_accessors: true + translates :description, type: :text, locale_accessors: true + translates :content, type: :text, locale_accessors: true + + validates :title, presence: true, uniqueness: true + validates :description, presence: true + validates :content, presence: true +end diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 449db16a..64b25297 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -16,7 +16,8 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do site.config.write && commit_config(action: :create) && add_licencias && - add_code_of_conduct + add_code_of_conduct && + add_privacy_policy end site @@ -172,6 +173,29 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do 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| diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index 46cb9d78..6002ee65 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -15,6 +15,8 @@ ActiveSupport::Inflector.inflections(:en) do |inflect| inflect.singular 'rollups', 'rollup' inflect.plural 'code_of_conduct', 'codes_of_conduct' inflect.singular 'codes_of_conduct', 'code_of_conduct' + inflect.plural 'privacy_policy', 'privacy_policies' + inflect.singular 'privacy_policies', 'privacy_policy' end ActiveSupport::Inflector.inflections(:es) do |inflect| @@ -32,4 +34,6 @@ ActiveSupport::Inflector.inflections(:es) do |inflect| inflect.singular 'rollups', 'rollup' inflect.plural 'code_of_conduct', 'codes_of_conduct' inflect.singular 'codes_of_conduct', 'code_of_conduct' + inflect.plural 'privacy_policy', 'privacy_policies' + inflect.singular 'privacy_policies', 'privacy_policy' end diff --git a/db/migrate/20230322231344_add_privacy_policy.rb b/db/migrate/20230322231344_add_privacy_policy.rb new file mode 100644 index 00000000..e0d7ae59 --- /dev/null +++ b/db/migrate/20230322231344_add_privacy_policy.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +# Agrega políticas de privacidad +class AddPrivacyPolicy < ActiveRecord::Migration[6.1] + def up + create_table :privacy_policies do |t| + t.timestamps + t.string :title + t.text :description + t.text :content + end + + # XXX: En lugar de ponerlo en las seeds + YAML.safe_load(File.read('db/seeds/privacy_policies.yml')).each do |pp| + PrivacyPolicy.new(**pp).save! + end + end + + def down + drop_table :privacy_policies + end +end diff --git a/db/seeds/privacy_policies.yml b/db/seeds/privacy_policies.yml new file mode 100644 index 00000000..98ce8379 --- /dev/null +++ b/db/seeds/privacy_policies.yml @@ -0,0 +1,113 @@ +--- +- title_en: "Privacy Policy" + title_es: "Políticas de privacidad" + description_en: "With what care does this site handles personal data of its users and visitors?" + description_es: "¿Cuáles son los cuidados de este sitio con respecto a sus usuaries y visitantes?" + content_en: | + > We use "them" as neutral pronoun to refer to people regardless of + > gender identity. + + This document details Sutty's privacy policy, including web site, + platform, other infrastructure (support channels, etc.) and web sites + generated by users. + + ## This is too long! + + * Sutty doesn't collect any kind of personal data. + + * Sutty may only collect statistical data that doesn't identify + individuals. + + ## Analytic data + + Sutty may only collect data for analytics (number of visits, duration, + etc.), not associated to personal data. + + Analytical data collected for every web site can only be used internally + by Sutty. Sutty doesn't share any data privately with any third + parties. Selected analytical data could be used publicly. + + Sutty doesn't recommend personal data collection in any way, but it + doesn't monitor if its users use third party services with their own + privacy policies. We recommend users and visitors to inform themselves + before using third parties analytics services. + + ## No personal data collection + + Sutty doesn't collect IP addresses from users nor visitors in any way. + + Sutty doesn't ask for personal data for registering user accounts in its + platform. + + Sutty only uses session "cookies" to identify users during their use of + the platform. It doesn't use "cookies" to identify visitors of web + sites hosted by Sutty. + + The only exception where Sutty could collect personal data is during + service payment. Digital safety measures will be taken to keep this + information and to discard it if possible after needed. + + Users will be notified when their personal data is removed. + + If users decide to host their web sites with third parties, they must + inform themselves about the corresponding privacy policies. Sutty only + recommends third parties with privacy policies compatible with these. + content_es: | + > Utilizamos la e como pronombre neutro para referirnos a personas + > independientemente de su identidad de género, por ejemplo “usuarie”. + + Este documento detalla la política de privacidad de Sutty, incluyendo + sitio web, plataforma de edición, infraestructura relacionada (salas de + chat, etc.) y sitios creados por sus usuaries a través de la plataforma, + en adelante "Sutty". + + ## ¡Esto es demasiado largo! + + Un resumen: + + * Sutty no recolecta datos personales de ningún tipo + + * Sutty solo recolectaría datos analíticos que no identifican a + personas + + ## Datos analíticos + + La única recolección de datos realizada por Sutty es con fines + analíticos (cantidad de visitas, duración, etc.), no asociados a datos + personales. + + Los datos analíticos recolectados por cada sitio podrán ser utilizados + internamente por Sutty. Sutty no comparte datos analíticos con + terceros en forma privada. Datos analíticos seleccionados podrán ser + utilizados públicamente. + + Sutty no recomienda la recolección de datos personales de ninguna forma, + pero no monitorea que les usuaries utilicen servicios de terceros con + sus propias políticas de privacidad. Recomendamos a les usuaries y + visitantes informarse antes de utilizar servicios de estadísticas de + terceros. + + ## No registro de datos personales + + Sutty no registra direcciones IP de usuaries ni de visitantes de ninguna + forma. + + Sutty no solicita datos personales para el registro de cuentas de + usuarie en su plataforma. + + Sutty solo utiliza “cookies” de sesión para identificar usuaries + mientras utilicen la plataforma. No se utilizan “cookies” para + identificar visitantes a los sitios alojados por Sutty. + + El único caso en el que Sutty podría solicitar datos personales es + durante el pago de servicios. Se tomarán medidas de seguridad digital + para salvaguardar esta información y descartar lo que sea posible una + vez que ya no sea necesaria. + + Se notificará a les usuaries cuando su información personal sea + eliminada. + + Si les usuaries deciden alojar sus sitios con terceros, deberán + informarse de las políticas de privacidad correspondientes. Sutty + recomienda servicios de terceros con políticas de privacidad coherentes + con estas. From 8fa2991bb1771288b8cad46fc30094ed96a365a1 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 11:44:47 -0300 Subject: [PATCH 208/453] =?UTF-8?q?fix:=20enviar=20la=20invitaci=C3=B3n=20?= =?UTF-8?q?luego=20de=20crear=20el=20rol=20#12728?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit de otra forma les usuaries que ya tienen sitios reciben una invitación a un sitio que no es y les que no tienen sitios no reciben nada porque hay un error. --- app/controllers/usuaries_controller.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index 7621489e..3f672110 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -83,16 +83,19 @@ class UsuariesController < ApplicationController # Enviar la invitación si es necesario y agregar al sitio invitaciones.each do |invitacion| attributes = { email: invitacion.address } + options = { skip_invitation: true } next if Usuarie.where(id: @site.roles.pluck(:usuarie_id)).find_by(attributes) - usuarie = Usuarie.find_by(attributes).tap do |u| - u.send(:send_devise_notification, :invitation_instructions, nil) + usuarie = Usuarie.find_by attributes + usuarie ||= Usuarie.invite!(attributes, nil, options).tap do |u| + u.generate_invitation_token! end - usuarie ||= Usuarie.invite! attributes - @site.roles.create(usuarie: usuarie, temporal: true, rol: invited_as) + + # XXX: La invitación tiene que ser enviada luego de crear el rol + usuarie.send(:send_devise_notification, :invitation_instructions, nil) end redirect_to site_usuaries_path(@site) From 1496a6f04bb6ce3c0842bb1791057ee91ce8d1f7 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 11:59:27 -0300 Subject: [PATCH 209/453] fix: a veces no se puede deployear nada closes ##12735 closes ##12733 closes ##12722 closes ##12719 closes ##12716 closes ##10417 --- app/mailers/deploy_mailer.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/mailers/deploy_mailer.rb b/app/mailers/deploy_mailer.rb index 25efb18d..b7b464cb 100644 --- a/app/mailers/deploy_mailer.rb +++ b/app/mailers/deploy_mailer.rb @@ -12,10 +12,11 @@ class DeployMailer < ApplicationMailer include ActionView::Helpers::DateHelper # rubocop:disable Metrics/AbcSize - def deployed(deploys) + def deployed(deploys = {}) usuarie = Usuarie.find(params[:usuarie]) site = usuarie.sites.find(params[:site]) hostname = site.hostname + deploys ||= {} # Informamos a cada quien en su idioma y damos una dirección de # respuesta porque a veces les usuaries nos escriben From 5cda6a440c00879b3ba6418c208fb2af9b8852b5 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 14:11:19 -0300 Subject: [PATCH 210/453] fix: enviar los argumentos como un hash closes ##12742 closes ##12740 closes ##12734 closes ##12732 closes ##12725 closes ##12721 closes ##12718 closes ##12715 --- config/initializers/sucker_punch.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/sucker_punch.rb b/config/initializers/sucker_punch.rb index 19506c2d..ce1209dd 100644 --- a/config/initializers/sucker_punch.rb +++ b/config/initializers/sucker_punch.rb @@ -2,5 +2,5 @@ # Enviar una notificación cuando falla una tarea SuckerPunch.exception_handler = lambda { |ex, _, args| - ExceptionNotifier.notify_exception(ex, data: args) + ExceptionNotifier.notify_exception(ex, data: { args: args }) } From 98b38e4caabcfa354b4d90e05112d1031fefcf7a Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 15:14:53 -0300 Subject: [PATCH 211/453] =?UTF-8?q?fix:=20el=20=C3=BAltimo=20=C3=ADtem=20e?= =?UTF-8?q?s=20un=20hash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #12747 --- config/initializers/sucker_punch.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/sucker_punch.rb b/config/initializers/sucker_punch.rb index ce1209dd..21997139 100644 --- a/config/initializers/sucker_punch.rb +++ b/config/initializers/sucker_punch.rb @@ -2,5 +2,5 @@ # Enviar una notificación cuando falla una tarea SuckerPunch.exception_handler = lambda { |ex, _, args| - ExceptionNotifier.notify_exception(ex, data: { args: args }) + ExceptionNotifier.notify_exception(ex, data: args.last) } From 1ac83140d60353ffc773622b75bb5c531264af65 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 15:32:54 -0300 Subject: [PATCH 212/453] =?UTF-8?q?fix:=20no=20enviar=20la=20invitaci?= =?UTF-8?q?=C3=B3n=20hasta=20=C3=BAltimo=20momento?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/usuaries_controller.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index 3f672110..ab116572 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -82,20 +82,19 @@ class UsuariesController < ApplicationController # Enviar la invitación si es necesario y agregar al sitio invitaciones.each do |invitacion| - attributes = { email: invitacion.address } - options = { skip_invitation: true } + attributes = { email: invitacion.address, skip_invitation: true } next if Usuarie.where(id: @site.roles.pluck(:usuarie_id)).find_by(attributes) usuarie = Usuarie.find_by attributes - usuarie ||= Usuarie.invite!(attributes, nil, options).tap do |u| - u.generate_invitation_token! + usuarie ||= Usuarie.invite!(attributes).tap do |u| + u.send :generate_invitation_token! end @site.roles.create(usuarie: usuarie, temporal: true, rol: invited_as) # XXX: La invitación tiene que ser enviada luego de crear el rol - usuarie.send(:send_devise_notification, :invitation_instructions, nil) + usuarie.deliver_invitation end redirect_to site_usuaries_path(@site) From fce5c0d90b38edef44e8fdae37ec8b87c5758072 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 15:38:46 -0300 Subject: [PATCH 213/453] =?UTF-8?q?fix:=20hacer=20todo=20en=20una=20transa?= =?UTF-8?q?cci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/usuaries_controller.rb | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index ab116572..84bcc13f 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -86,15 +86,17 @@ class UsuariesController < ApplicationController next if Usuarie.where(id: @site.roles.pluck(:usuarie_id)).find_by(attributes) - usuarie = Usuarie.find_by attributes - usuarie ||= Usuarie.invite!(attributes).tap do |u| - u.send :generate_invitation_token! + Usuarie.transaction do + usuarie = Usuarie.find_by attributes + usuarie ||= Usuarie.invite!(attributes).tap do |u| + u.send :generate_invitation_token! + end + + @site.roles.create(usuarie: usuarie, temporal: true, rol: invited_as) + + # XXX: La invitación tiene que ser enviada luego de crear el rol + usuarie.deliver_invitation end - - @site.roles.create(usuarie: usuarie, temporal: true, rol: invited_as) - - # XXX: La invitación tiene que ser enviada luego de crear el rol - usuarie.deliver_invitation end redirect_to site_usuaries_path(@site) From 732db666c7bf10d03696c243d54c351bb8c4e85b Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 15:42:20 -0300 Subject: [PATCH 214/453] =?UTF-8?q?fix:=20usar=20el=20=C3=BAltimo=20sitio?= =?UTF-8?q?=20al=20que=20todav=C3=ADa=20no=20aceptamos=20invitaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/devise/mailer/invitation_instructions.html.haml | 2 +- app/views/devise/mailer/invitation_instructions.text.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/devise/mailer/invitation_instructions.html.haml b/app/views/devise/mailer/invitation_instructions.html.haml index e1fe6812..bc9d9e4e 100644 --- a/app/views/devise/mailer/invitation_instructions.html.haml +++ b/app/views/devise/mailer/invitation_instructions.html.haml @@ -1,4 +1,4 @@ -- site = @resource.sites.last +- site = @resource.roles.where(temporal: true).last&.site %p= t('devise.mailer.invitation_instructions.hello', email: @resource.email) diff --git a/app/views/devise/mailer/invitation_instructions.text.haml b/app/views/devise/mailer/invitation_instructions.text.haml index 353f2a12..a1360bb0 100644 --- a/app/views/devise/mailer/invitation_instructions.text.haml +++ b/app/views/devise/mailer/invitation_instructions.text.haml @@ -1,4 +1,4 @@ -- site = @resource.sites.last +- site = @resource.roles.where(temporal: true).last&.site = t('devise.mailer.invitation_instructions.hello', email: @resource.email) \ From 1fa37b20e1ee5f218e98b21da518927a2512f953 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 15:47:06 -0300 Subject: [PATCH 215/453] fix: solo invitar una vez --- app/views/devise/mailer/invitation_instructions.html.haml | 2 +- app/views/devise/mailer/invitation_instructions.text.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/devise/mailer/invitation_instructions.html.haml b/app/views/devise/mailer/invitation_instructions.html.haml index bc9d9e4e..3cb9704e 100644 --- a/app/views/devise/mailer/invitation_instructions.html.haml +++ b/app/views/devise/mailer/invitation_instructions.html.haml @@ -8,7 +8,7 @@ %h1= site.title %p= site.description -- if @resource.created_by_invite? +- if @resource.created_by_invite? && !@resource.invitation_accepted? %p= link_to t('devise.mailer.invitation_instructions.accept'), accept_invitation_url(@resource, invitation_token: @token) diff --git a/app/views/devise/mailer/invitation_instructions.text.haml b/app/views/devise/mailer/invitation_instructions.text.haml index a1360bb0..2050c19c 100644 --- a/app/views/devise/mailer/invitation_instructions.text.haml +++ b/app/views/devise/mailer/invitation_instructions.text.haml @@ -9,7 +9,7 @@ \ = site.description \ -- if @resource.created_by_invite? +- if @resource.created_by_invite? && !@resource.invitation_accepted? = accept_invitation_url(@resource, invitation_token: @token) \ - if @resource.invitation_due_at From 1bfff4dfdb72ebdd676c324d0a60bcf16f5b2c5a Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 16:24:53 -0300 Subject: [PATCH 216/453] fix: enviar las invitaciones luego de crear el rol --- app/controllers/usuaries_controller.rb | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index 84bcc13f..074694f1 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -81,21 +81,25 @@ class UsuariesController < ApplicationController authorize SiteUsuarie.new(@site, current_usuarie) # Enviar la invitación si es necesario y agregar al sitio - invitaciones.each do |invitacion| - attributes = { email: invitacion.address, skip_invitation: true } - - next if Usuarie.where(id: @site.roles.pluck(:usuarie_id)).find_by(attributes) + invitaciones.each do |address| + next if Usuarie.where(id: @site.roles.pluck(:usuarie_id)).find_by_email(address) Usuarie.transaction do - usuarie = Usuarie.find_by attributes - usuarie ||= Usuarie.invite!(attributes).tap do |u| + usuarie = Usuarie.find_by_email(address) + usuarie ||= Usuarie.invite!({ email: address, skip_invitation: true }).tap do |u| u.send :generate_invitation_token! end - @site.roles.create(usuarie: usuarie, temporal: true, rol: invited_as) + role = @site.roles.create(usuarie: usuarie, temporal: true, rol: invited_as) # XXX: La invitación tiene que ser enviada luego de crear el rol - usuarie.deliver_invitation + if role.persisted? + usuarie.deliver_invitation + else + raise ArgumentError, role.errors.full_messages + end + rescue ArgumentError => e + ExceptionNotifier.notify_exception(e, data: { site: @site.name, address: address }) end end @@ -137,6 +141,8 @@ class UsuariesController < ApplicationController private # Traer todas las invitaciones que al menos tengan usuarie y dominio + # + # @return [Array] def invitaciones # XXX: Podríamos usar EmailAddress pero hace chequeos más lentos params[:invitaciones]&.tr("\r", '')&.split("\n")&.map do |m| @@ -145,7 +151,7 @@ class UsuariesController < ApplicationController nil end.compact.select do |m| m.local && m.domain - end + end.map(&:address) end # El tipo de invitación que tenemos que enviar, si alguien mandó From d01f4ae5e2432b7f34835a1ca50e1629d8ba96c1 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 16:53:06 -0300 Subject: [PATCH 217/453] =?UTF-8?q?fix:=20volver=20a=20leer=20el=20sitio?= =?UTF-8?q?=20despu=C3=A9s=20de=20guardarlo=20#12755?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/site_service.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 64b25297..eaefca3a 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -15,6 +15,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do site.save && site.config.write && commit_config(action: :create) && + site.reset.nil? && add_licencias && add_code_of_conduct && add_privacy_policy @@ -29,6 +30,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do site.update(params) && site.config.write && commit_config(action: :update) && + site.reset.nil? && change_licencias end From 7a13dffc9b29e89525b9a6e37a38714d53fa9993 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 17:21:05 -0300 Subject: [PATCH 218/453] =?UTF-8?q?fix:=20establecer=20un=20par=C3=A1metro?= =?UTF-8?q?=20por=20defecto=20#12754?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/usuaries_controller.rb | 12 ++++++------ app/models/rol.rb | 4 ++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index 6d02a35a..746ee822 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -72,6 +72,8 @@ class UsuariesController < ApplicationController site_usuarie = SiteUsuarie.new(@site, current_usuarie) authorize site_usuarie + params[:invite_as] = invited_as :invite_as + @policy = policy(site_usuarie) end @@ -155,12 +157,10 @@ class UsuariesController < ApplicationController # El tipo de invitación que tenemos que enviar, si alguien mandó # cualquier cosa, usamos el privilegio menor. - def invited_as - if Rol::ROLES.include?(params[:invited_as]) - params[:invited_as] - else - 'invitade' - end + # + # @return [String] + def invited_as(param_key = :invited_as) + Rol.role?(params[param_key]) ? params[param_key] : Rol::INVITADE end def site diff --git a/app/models/rol.rb b/app/models/rol.rb index 5879d666..fcd07037 100644 --- a/app/models/rol.rb +++ b/app/models/rol.rb @@ -21,4 +21,8 @@ class Rol < ApplicationRecord def usuarie? rol == USUARIE end + + def self.role?(rol) + ROLES.include? rol + end end From df8efe800bb6c62b33df9624019e1468d3899cfe Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 17:38:48 -0300 Subject: [PATCH 219/453] fix: no hardcodear roles --- app/controllers/usuaries_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index 746ee822..4db6aafd 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -47,7 +47,7 @@ class UsuariesController < ApplicationController @usuarie = Usuarie.find(params[:usuarie_id]) if @site.usuaries.count > 1 - @usuarie.rol_for_site(@site).update_attribute :rol, 'invitade' + @usuarie.rol_for_site(@site).update_attribute :rol, Rol::INVITADE else flash[:warning] = I18n.t('usuaries.index.demote.denied') end @@ -61,7 +61,7 @@ class UsuariesController < ApplicationController authorize SiteUsuarie.new(@site, current_usuarie) @usuarie = Usuarie.find(params[:usuarie_id]) - @usuarie.rol_for_site(@site).update_attribute :rol, 'usuarie' + @usuarie.rol_for_site(@site).update_attribute :rol, Rol::USUARIE redirect_to site_usuaries_path end From c2fbc06d4102eab6b45a3b567795dfac7a198e47 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 17:50:24 -0300 Subject: [PATCH 220/453] =?UTF-8?q?fix:=20tenemos=20un=20l=C3=ADo=20de=20s?= =?UTF-8?q?ingulares=20y=20plurales?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/usuaries_controller.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index 4db6aafd..716668a9 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -72,7 +72,7 @@ class UsuariesController < ApplicationController site_usuarie = SiteUsuarie.new(@site, current_usuarie) authorize site_usuarie - params[:invite_as] = invited_as :invite_as + params[:invite_as] = invite_as @policy = policy(site_usuarie) end @@ -159,8 +159,12 @@ class UsuariesController < ApplicationController # cualquier cosa, usamos el privilegio menor. # # @return [String] - def invited_as(param_key = :invited_as) - Rol.role?(params[param_key]) ? params[param_key] : Rol::INVITADE + def invited_as + Rol.role?(params[:invited_as]) ? params[:invited_as] : Rol::INVITADE + end + + def invite_as + Rol.role?(params[:invite_as].singularize) ? params[:invite_as] : Rol::INVITADE.pluralize end def site From c9fa518b337b9426abb0a22ec61543582ef3bef5 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 17:53:13 -0300 Subject: [PATCH 221/453] =?UTF-8?q?fix:=20el=20parametro=20puede=20venir?= =?UTF-8?q?=20vac=C3=ADo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/usuaries_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index 716668a9..d75f3c20 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -164,7 +164,7 @@ class UsuariesController < ApplicationController end def invite_as - Rol.role?(params[:invite_as].singularize) ? params[:invite_as] : Rol::INVITADE.pluralize + Rol.role?(params[:invite_as]&.singularize) ? params[:invite_as] : Rol::INVITADE.pluralize end def site From b590396a6bba72d890b4f63fbf292558ce69881f Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 19:11:33 -0300 Subject: [PATCH 222/453] fix: implementar output --- app/models/deploy_reindex.rb | 2 +- app/models/deploy_rsync.rb | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/models/deploy_reindex.rb b/app/models/deploy_reindex.rb index d6b2be65..f3eb3d23 100644 --- a/app/models/deploy_reindex.rb +++ b/app/models/deploy_reindex.rb @@ -2,7 +2,7 @@ # Reindexa los artículos al terminar la compilación class DeployReindex < Deploy - def deploy + def deploy(**) time_start site.reset diff --git a/app/models/deploy_rsync.rb b/app/models/deploy_rsync.rb index 996f8cdd..a658de6b 100644 --- a/app/models/deploy_rsync.rb +++ b/app/models/deploy_rsync.rb @@ -5,8 +5,8 @@ class DeployRsync < Deploy store :values, accessors: %i[destination host_keys], coder: JSON - def deploy - ssh? && rsync + def deploy(output: false) + ssh? && rsync(output: output) end # El espacio remoto es el mismo que el local @@ -83,8 +83,8 @@ class DeployRsync < Deploy # Sincroniza hacia el directorio remoto # # @return [Boolean] - def rsync - run %(rsync -aviH --timeout=5 #{Shellwords.escape source}/ #{Shellwords.escape destination}/) + def rsync(output: output) + run %(rsync -aviH --timeout=5 #{Shellwords.escape source}/ #{Shellwords.escape destination}/), output: output end # El origen es el destino de la compilación From b51eb6856c358414a7d4f86cf45db8f511e8a78d Mon Sep 17 00:00:00 2001 From: f Date: Fri, 24 Mar 2023 11:50:25 -0300 Subject: [PATCH 223/453] =?UTF-8?q?fix:=20siempre=20devolver=20una=20relac?= =?UTF-8?q?i=C3=B3n=20#12768?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/metadata_locales.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/metadata_locales.rb b/app/models/metadata_locales.rb index 2e9080c9..3790b944 100644 --- a/app/models/metadata_locales.rb +++ b/app/models/metadata_locales.rb @@ -44,6 +44,6 @@ class MetadataLocales < MetadataHasAndBelongsToMany def posts other_locales.map do |locale| site.posts(lang: locale).where(layout: post.layout.value) - end.reduce(&:concat) + end.reduce(&:concat) || PostRelation.new end end From 3e6288fefedae54e57bb1ba998d747c78d101808 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 24 Mar 2023 14:36:37 -0300 Subject: [PATCH 224/453] fix: filtrar #12774 --- config/locales/en.yml | 1 + config/locales/es.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index c79bea2d..567ab6bb 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -275,6 +275,7 @@ en: stats: index: title: Statistics + filter: "Filter" help: | These statistics show information about how your site is generated and how many resources it uses. diff --git a/config/locales/es.yml b/config/locales/es.yml index 8e4e594b..0a829e4a 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -280,6 +280,7 @@ es: stats: index: title: Estadísticas + filter: "Filtrar" help: | Las estadísticas visibilizan información sobre cómo se genera y cuántos recursos utiliza tu sitio. From 42b2549f09e5fe9b3f33d6c632995253155400da Mon Sep 17 00:00:00 2001 From: f Date: Sat, 25 Mar 2023 13:46:30 -0300 Subject: [PATCH 225/453] =?UTF-8?q?feat:=20agregar=20una=20descripci=C3=B3?= =?UTF-8?q?n=20corta=20a=20la=20licencia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit que es lo que usan las plantillas como aviso de licencia --- app/services/site_service.rb | 2 +- ...5163802_add_short_description_to_licencias.rb | 16 ++++++++++++++++ db/seeds/licencias.yml | 6 ++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20230325163802_add_short_description_to_licencias.rb diff --git a/app/services/site_service.rb b/app/services/site_service.rb index eaefca3a..2719a26c 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -113,7 +113,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do slug: Jekyll::Utils.slugify(I18n.t('activerecord.models.licencia')), lang: lang, title: site.licencia.name, - description: site.licencia.description, + description: site.licencia.short_description, content: CommonMarker.render_html(site.licencia.deed) } ) diff --git a/db/migrate/20230325163802_add_short_description_to_licencias.rb b/db/migrate/20230325163802_add_short_description_to_licencias.rb new file mode 100644 index 00000000..efcc01e4 --- /dev/null +++ b/db/migrate/20230325163802_add_short_description_to_licencias.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Agrega descripciones cortas a las licencias +class AddShortDescriptionToLicencias < ActiveRecord::Migration[6.1] + def up + add_column :licencias, :short_description, :string + + YAML.safe_load_file('db/seeds/licencias.yml').each do |licencia| + Licencia.find_by_icons(licencia['icons']).update licencia + end + end + + def down + remove_column :licencias, :short_description + end +end diff --git a/db/seeds/licencias.yml b/db/seeds/licencias.yml index cbe3bace..c5e2886a 100644 --- a/db/seeds/licencias.yml +++ b/db/seeds/licencias.yml @@ -1,6 +1,8 @@ --- - name_en: 'Peer Production License' name_es: 'Licencia de Producción de Pares' + short_description_en: "This work is licensed under a Peer Production License" + short_description_es: "Esta obra está bajo una Licencia de Producción de Pares" icons: "/images/ppl.png" url_en: 'https://wiki.p2pfoundation.net/Peer_Production_License' url_es: 'https://endefensadelsl.org/ppl_es.html' @@ -100,6 +102,8 @@ hacerlo es enlazar a esta página. - icons: "/images/by.png" + short_description_en: "This work is licensed under a Creative Commons Attribution 4.0 International License." + short_description_es: "Esta obra está bajo una Licencia Creative Commons Atribución 4.0 Internacional." name_en: 'Creative Commons Attribution 4.0 International (CC BY 4.0)' description_en: "This license gives everyone the freedom to use, adapt, and redistribute the contents of your site by requiring @@ -194,6 +198,8 @@ - icons: "/images/sa.png" name_en: "Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)" name_es: "Creative Commons Atribución-CompartirIgual 4.0 Internacional (CC BY-SA 4.0)" + short_description_en: "This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License." + short_description_es: "Esta obra está bajo una Licencia Creative Commons Atribución-CompartirIgual 4.0 Internacional." url_en: 'https://creativecommons.org/licenses/by-sa/4.0/' url_es: 'https://creativecommons.org/licenses/by-sa/4.0/deed.es' description_en: "This license is the same as the CC-BY 4.0 but it adds From c62d0d3a7254779f728fd14c224e2dc56127082e Mon Sep 17 00:00:00 2001 From: f Date: Sat, 25 Mar 2023 13:48:30 -0300 Subject: [PATCH 226/453] =?UTF-8?q?fixup!=20feat:=20agregar=20una=20descri?= =?UTF-8?q?pci=C3=B3n=20corta=20a=20la=20licencia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/licencia.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/licencia.rb b/app/models/licencia.rb index c0eb1c80..f0a542ef 100644 --- a/app/models/licencia.rb +++ b/app/models/licencia.rb @@ -7,6 +7,7 @@ class Licencia < ApplicationRecord translates :name, type: :string, locale_accessors: true translates :url, type: :string, locale_accessors: true translates :description, type: :text, locale_accessors: true + translates :short_description, type: :string, locale_accessors: true translates :deed, type: :text, locale_accessors: true has_many :sites @@ -14,5 +15,6 @@ class Licencia < ApplicationRecord validates :name, presence: true, uniqueness: true validates :url, presence: true validates :description, presence: true + validates :short_description, presence: true validates :deed, presence: true end From d44ca16f81ec09f39713a94ee74da2b28c8b91e0 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 25 Mar 2023 13:51:07 -0300 Subject: [PATCH 227/453] =?UTF-8?q?fix:=20cambiar=20la=20descripci=C3=B3n?= =?UTF-8?q?=20de=20la=20licencia=20tambi=C3=A9n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/site_service.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 2719a26c..ce596482 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -143,6 +143,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do params = ActionController::Parameters.new( post: { title: site.licencia.name, + description: site.licencia.short_description, content: CommonMarker.render_html(site.licencia.deed) } ) From 960c8dcca450a27ab410833e6c5c35bcb9b8ccbf Mon Sep 17 00:00:00 2001 From: f Date: Sat, 25 Mar 2023 14:50:36 -0300 Subject: [PATCH 228/453] feat: implementar un servicio liviano de git-lfs #9361 --- app/services/lfs_object_service.rb | 64 ++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 app/services/lfs_object_service.rb diff --git a/app/services/lfs_object_service.rb b/app/services/lfs_object_service.rb new file mode 100644 index 00000000..65db113d --- /dev/null +++ b/app/services/lfs_object_service.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +# Representa un objeto git LFS +class LfsObjectService + attr_reader :site, :blob, :usuarie + + # @param :site [Site] + # @param :blob [ActiveStorage::Blob] + def initialize(site:, blob:, usuarie:) + @site = site + @blob = blob + @usuarie = usuarie + end + + def process + # Crear el directorio + FileUtils.mkdir_p(File.dirname(object_path)) + + # Mover el archivo + FileUtils.mv(path, object_path) unless File.exist? object_path + + # Crear el pointer + Site::Writer.new(site: site, file: path, content: pointer).save + + # Commitear el pointer + site.repository.commit(file: path, usuarie: usuarie, message: File.basename(path)) + + # Eliminar el pointer + FileUtils.rm(path) + + # Hacer link duro del objeto al archivo + FileUtils.ln(object_path, path) + end + + # @return [String] + def path + @path ||= blob.service.path_for(blob.key) + end + + # @return [String] + def digest + @digest ||= Digest::SHA256.file(path).hexdigest + end + + # @return [String] + def object_path + @git_lfs_object_path ||= File.join(site.path, '.git', 'lfs', 'objects', digest[0..1], digest[2..3], digest) + end + + # @return [Integer] + def size + @size ||= File.size(File.exist?(object_path) ? object_path : path) + end + + # @return [String] + def pointer + @pointer ||= + <<~POINTER + version https://git-lfs.github.com/spec/v1 + oid sha256:#{digest} + size #{size} + POINTER + end +end From 2215a00727d60d18147e76692dfe797a1183bd38 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 25 Mar 2023 15:22:54 -0300 Subject: [PATCH 229/453] feat: commitear el archivo en lfs al subirlo --- app/lib/active_storage/service/jekyll_service.rb | 15 +++++++++------ app/services/lfs_object_service.rb | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/lib/active_storage/service/jekyll_service.rb b/app/lib/active_storage/service/jekyll_service.rb index 88ffa83c..6763ee0d 100644 --- a/app/lib/active_storage/service/jekyll_service.rb +++ b/app/lib/active_storage/service/jekyll_service.rb @@ -4,11 +4,6 @@ module ActiveStorage class Service # Sube los archivos a cada repositorio y los agrega al LFS de su # repositorio git. - # - # @todo: Implementar LFS. No nos gusta mucho la idea porque duplica - # el espacio en disco, pero es la única forma que tenemos (hasta que - # implementemos IPFS) para poder transferir los archivos junto con el - # sitio. class JekyllService < Service::DiskService # Genera un servicio para un sitio determinado # @@ -27,7 +22,10 @@ module ActiveStorage # @param :checksum [String] def upload(key, io, checksum: nil, **) instrument :upload, key: key, checksum: checksum do - IO.copy_stream(io, make_path_for(key)) unless exist?(key) + unless exist?(key) + IO.copy_stream(io, make_path_for(key)) + LfsObjectService.new(site: site, usuarie: current_usuarie, blob: blob).process + end ensure_integrity_of(key, checksum) if checksum end end @@ -91,6 +89,11 @@ module ActiveStorage def path_for(key) File.join root, folder_for(key), filename_for(key) end + + # @return [Site] + def site + @site ||= Site.find_by_name(File.basename(root)) + end end end end diff --git a/app/services/lfs_object_service.rb b/app/services/lfs_object_service.rb index 65db113d..61775e12 100644 --- a/app/services/lfs_object_service.rb +++ b/app/services/lfs_object_service.rb @@ -44,7 +44,7 @@ class LfsObjectService # @return [String] def object_path - @git_lfs_object_path ||= File.join(site.path, '.git', 'lfs', 'objects', digest[0..1], digest[2..3], digest) + @object_path ||= File.join(site.path, '.git', 'lfs', 'objects', digest[0..1], digest[2..3], digest) end # @return [Integer] From 2940b5d3e818d047afedf173df0d7a2d6b6f0613 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 25 Mar 2023 15:29:49 -0300 Subject: [PATCH 230/453] =?UTF-8?q?fix:=20no=20podemos=20saber=20qui=C3=A9?= =?UTF-8?q?n=20subi=C3=B3=20el=20archivo=20todav=C3=ADa?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/active_storage/service/jekyll_service.rb | 2 +- app/services/lfs_object_service.rb | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/lib/active_storage/service/jekyll_service.rb b/app/lib/active_storage/service/jekyll_service.rb index 6763ee0d..f399f440 100644 --- a/app/lib/active_storage/service/jekyll_service.rb +++ b/app/lib/active_storage/service/jekyll_service.rb @@ -24,7 +24,7 @@ module ActiveStorage instrument :upload, key: key, checksum: checksum do unless exist?(key) IO.copy_stream(io, make_path_for(key)) - LfsObjectService.new(site: site, usuarie: current_usuarie, blob: blob).process + LfsObjectService.new(site: site, blob: blob).process end ensure_integrity_of(key, checksum) if checksum end diff --git a/app/services/lfs_object_service.rb b/app/services/lfs_object_service.rb index 61775e12..bb62301d 100644 --- a/app/services/lfs_object_service.rb +++ b/app/services/lfs_object_service.rb @@ -2,14 +2,13 @@ # Representa un objeto git LFS class LfsObjectService - attr_reader :site, :blob, :usuarie + attr_reader :site, :blob # @param :site [Site] # @param :blob [ActiveStorage::Blob] - def initialize(site:, blob:, usuarie:) + def initialize(site:, blob:) @site = site @blob = blob - @usuarie = usuarie end def process @@ -23,7 +22,7 @@ class LfsObjectService Site::Writer.new(site: site, file: path, content: pointer).save # Commitear el pointer - site.repository.commit(file: path, usuarie: usuarie, message: File.basename(path)) + site.repository.commit(file: path, usuarie: author, message: File.basename(path)) # Eliminar el pointer FileUtils.rm(path) @@ -61,4 +60,8 @@ class LfsObjectService size #{size} POINTER end + + def author + @author ||= GitAuthor.new email: "disk_service@#{Site.domain}", name: 'DiskService' + end end From 2fb5bc24d5d21fdc2d32146ef114518ed96140c8 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 25 Mar 2023 15:34:47 -0300 Subject: [PATCH 231/453] fix: encontrar el blob para este servicio --- app/lib/active_storage/service/jekyll_service.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/lib/active_storage/service/jekyll_service.rb b/app/lib/active_storage/service/jekyll_service.rb index f399f440..e6c5fda6 100644 --- a/app/lib/active_storage/service/jekyll_service.rb +++ b/app/lib/active_storage/service/jekyll_service.rb @@ -24,7 +24,7 @@ module ActiveStorage instrument :upload, key: key, checksum: checksum do unless exist?(key) IO.copy_stream(io, make_path_for(key)) - LfsObjectService.new(site: site, blob: blob).process + LfsObjectService.new(site: site, blob: blob_for(key)).process end ensure_integrity_of(key, checksum) if checksum end @@ -77,7 +77,7 @@ module ActiveStorage # @param :key [String] # @return [String] def filename_for(key) - ActiveStorage::Blob.where(key: key).limit(1).pluck(:filename).first.tap do |filename| + blob_for(key).filename.to_s.tap do |filename| raise ArgumentError, "Filename for key #{key} is blank" if filename.blank? end end @@ -92,7 +92,11 @@ module ActiveStorage # @return [Site] def site - @site ||= Site.find_by_name(File.basename(root)) + @site ||= Site.find_by_name(name) + end + + def blob_for(key) + ActiveStorage::Blob.find_by(key: key, service_name: name) end end end From 6b759c92ce0ad52caae465926af55edccc85f402 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 27 Mar 2023 11:45:23 -0300 Subject: [PATCH 232/453] fix: instalar las gemas cuando sea necesario #12755 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit si se modificó el gemfile queremos volver a instalarlas también --- app/models/site.rb | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/app/models/site.rb b/app/models/site.rb index 4b2a8eb9..6110f104 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -553,10 +553,33 @@ class Site < ApplicationRecord Dir.chdir path, &block end + # Instala las gemas cuando es necesario: + # + # * El sitio existe + # * No están instaladas + # * El archivo Gemfile se modificó + # * El archivo Gemfile.lock se modificó def install_gems return unless persisted? - return if Rails.root.join('_storage', 'gems', name).directory? - deploys.find_by_type('DeployLocal').send(:bundle) + if !gem_dir? || gemfile_updated? || gemfile_lock_updated? + deploys.find_by_type('DeployLocal').send(:bundle) + touch + end + end + + # Detecta si el repositorio de gemas existe + def gem_dir? + Rails.root.join('_storage', 'gems', name).directory? + end + + # Detecta si el Gemfile fue modificado + def gemfile_updated? + updated_at > File.mtime(File.join(path, 'Gemfile')) + end + + # Detecta si el Gemfile.lock fue modificado + def gemfile_lock_updated? + updated_at > File.mtime(File.join(path, 'Gemfile.lock')) end end From 5d40fabe54c34108cdbb5b42ca629568bbaf35d7 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 27 Mar 2023 12:38:31 -0300 Subject: [PATCH 233/453] feat: ordenar los sitios por actividad #12762 --- app/controllers/sites_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/sites_controller.rb b/app/controllers/sites_controller.rb index f0eff0dc..7b1496e9 100644 --- a/app/controllers/sites_controller.rb +++ b/app/controllers/sites_controller.rb @@ -10,7 +10,7 @@ class SitesController < ApplicationController # Ver un listado de sitios def index authorize Site - @sites = current_usuarie.sites.order(:title) + @sites = current_usuarie.sites.order(updated_at: :desc) fresh_when @sites end From 706d829613eb60849847f246d8ef4b99e8992821 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 18:46:41 -0300 Subject: [PATCH 234/453] feat: componente de mensajes resaltados --- app/views/bootstrap/_alert.haml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 app/views/bootstrap/_alert.haml diff --git a/app/views/bootstrap/_alert.haml b/app/views/bootstrap/_alert.haml new file mode 100644 index 00000000..0fb3d2d3 --- /dev/null +++ b/app/views/bootstrap/_alert.haml @@ -0,0 +1,2 @@ +.alert.alert-primary{ role: 'alert', class: local_assigns[:class] } + = yield From d48231e725c9cb1929d9cf9e863d39aaeed3aae5 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 18:52:42 -0300 Subject: [PATCH 235/453] fix: usar siempre el componente --- app/views/invitadxs/show.haml | 2 +- app/views/layouts/_flash.haml | 3 ++- app/views/layouts/_help.haml | 1 + app/views/posts/_form.haml | 8 +++++--- app/views/posts/_submit.haml | 4 ++-- app/views/posts/attributes/_content.haml | 4 ++-- app/views/posts/index.haml | 2 +- app/views/sites/_form.haml | 10 ++++++---- 8 files changed, 20 insertions(+), 14 deletions(-) diff --git a/app/views/invitadxs/show.haml b/app/views/invitadxs/show.haml index e1d47288..0c23522b 100644 --- a/app/views/invitadxs/show.haml +++ b/app/views/invitadxs/show.haml @@ -1,4 +1,4 @@ .row.align-items-center.justify-content-center.full-height .col-md-6.align-self-center - .alert{role: 'alert', class: "alert-success"} + = render 'bootstrap/alert' do = t('.confirmation_sent') diff --git a/app/views/layouts/_flash.haml b/app/views/layouts/_flash.haml index 149f946f..7bd7ec0b 100644 --- a/app/views/layouts/_flash.haml +++ b/app/views/layouts/_flash.haml @@ -1,3 +1,4 @@ - flash.each do |type, message| - unless type == 'js' - .alert{ role: 'alert', class: "alert-#{type}" }= message + = render 'bootstrap/alert' do + = message diff --git a/app/views/layouts/_help.haml b/app/views/layouts/_help.haml index 7a821e2d..6800b524 100644 --- a/app/views/layouts/_help.haml +++ b/app/views/layouts/_help.haml @@ -1,3 +1,4 @@ +-# DEPRECADO .alert.alert-info.alert-dismissible.fade.show{role: 'alert'} - if help.respond_to? :each %ul diff --git a/app/views/posts/_form.haml b/app/views/posts/_form.haml index e46b2eda..f81cef58 100644 --- a/app/views/posts/_form.haml +++ b/app/views/posts/_form.haml @@ -1,7 +1,9 @@ - unless post.errors.empty? - .alert.alert-danger - %h4= t('.errors.title') - %p= t('.errors.help') + - title = t('.errors.title') + - help = t('.errors.help') + = render 'boostrap/alert' do + %h4= title + %p= help %ul - post.errors.each do |attribute, errors| diff --git a/app/views/posts/_submit.haml b/app/views/posts/_submit.haml index b21b5ff2..717b8bfe 100644 --- a/app/views/posts/_submit.haml +++ b/app/views/posts/_submit.haml @@ -1,6 +1,6 @@ .form-group = submit_tag t('.save'), class: 'btn submit-post' - .invalid-help.alert.alert-danger.d-none + = render 'boostrap/alert', class: 'invalid-help d-none' do = site.config.fetch('invalid_help', t('.invalid_help')) - .sending-help.alert.alert-success.d-none + = render 'boostrap/alert', class: 'sending-help d-none' do = site.config.fetch('sending_help', t('.sending_help')) diff --git a/app/views/posts/attributes/_content.haml b/app/views/posts/attributes/_content.haml index 36b88872..5db023fb 100644 --- a/app/views/posts/attributes/_content.haml +++ b/app/views/posts/attributes/_content.haml @@ -6,7 +6,7 @@ .editor{ id: attribute, data: { editor: '' } } -# Esto es para luego decirle al navegador que se olvide estas cosas. = hidden_field_tag 'storage_keys[]', "#{request.original_url}##{attribute}", data: { target: 'storage-key' } - .alert.alert-info + = render 'bootstrap/alert' do :markdown #{t('editor.alert')} = text_area_tag "#{base}[#{attribute}]", '', @@ -123,7 +123,7 @@ %label{ for: 'link-url' }= t('editor.url') %input.form-control{ type: 'url', id: 'link-url', name: 'link-url' }/ - .editor-aviso-word.alert.alert-info + = render 'bootstrap/alert', class: 'editor-aviso-word' do %p= t('editor.word') .editor-content.form-control.h-auto.mt-1{ contenteditable: 'true' } diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index a82616d8..54587fc5 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -34,7 +34,7 @@ = render 'sites/build', site: @site - if @site.design.credits - .alert.alert-primary{ role: 'alert' } + = render 'bootstrap/alert' do = sanitize_markdown @site.design.credits = link_to t('sites.donations.text'), t('sites.donations.url'), class: 'btn' - if @site.design.designer_url diff --git a/app/views/sites/_form.haml b/app/views/sites/_form.haml index 9a044c7f..757b8b48 100644 --- a/app/views/sites/_form.haml +++ b/app/views/sites/_form.haml @@ -1,7 +1,9 @@ - unless site.errors.empty? - .alert.alert-info - %h4= t('.errors.title') - %p.lead= t('.errors.help') + - title = t('.errors.title') + - help = t('.errors.help') + = render 'bootstrap/alert' do + %h4= title + %p.lead= help %ul - site.errors.messages.each_pair do |attr, error| - attr = attr.to_s @@ -48,7 +50,7 @@ %h2= t('.design.title') %p.lead= t('.help.design') - if invalid? site, :design_id - .alert.alert-info + = render 'bootstrap/alert' do = t('activerecord.errors.models.site.attributes.design_id.layout_incompatible.help', layouts: site.incompatible_layouts.to_sentence) .row.designs From 74a19ad9d9ced91d4e64dba51a48b4138ef133bb Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 18:55:48 -0300 Subject: [PATCH 236/453] feat: mostrar los mensajes en todas las vistas #12792 --- app/views/collaborations/collaborate.haml | 1 - app/views/devise/sessions/new.haml | 2 -- app/views/layouts/application.html.haml | 3 +++ app/views/posts/index.haml | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/views/collaborations/collaborate.haml b/app/views/collaborations/collaborate.haml index 50cad809..4d43ad7e 100644 --- a/app/views/collaborations/collaborate.haml +++ b/app/views/collaborations/collaborate.haml @@ -11,7 +11,6 @@ url: site_collaborate_path(@site), method: :post) do |f| - unless current_usuarie - = render 'layouts/flash' .form-group = f.label :email = f.email_field :email, autofocus: true, autocomplete: 'email', diff --git a/app/views/devise/sessions/new.haml b/app/views/devise/sessions/new.haml index b5223e5f..9b396187 100644 --- a/app/views/devise/sessions/new.haml +++ b/app/views/devise/sessions/new.haml @@ -3,8 +3,6 @@ .row.align-items-center.justify-content-center.full-height .col-md-5.align-self-center - = render 'layouts/flash' - .sr-only %h2= t('.sign_in') %p= t('.help') diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 85d5ab22..965a856f 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -21,6 +21,9 @@ %body{ class: yield(:body) } .container-fluid#sutty = render 'layouts/breadcrumb' + = render 'layouts/flash' + = yield + - if flash[:js] .js-flash.d-none{ data: flash[:js] } diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 54587fc5..dbeddaad 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -41,7 +41,6 @@ = link_to t('sites.designer_url'), @site.design.designer_url, class: 'btn' %section.col - = render 'layouts/flash' .d-flex.justify-content-between.align-items-center.pl-2-plus.pr-2-plus.mb-2 %form{ action: site_posts_path } - @filter_params.each do |param, value| From f3845c755f5057ac4512120041ccfdbf30badf75 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 19:03:00 -0300 Subject: [PATCH 237/453] fix: informar que hay que confirmar la cuenta --- config/locales/devise.views.en.yml | 2 +- config/locales/devise.views.es.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/devise.views.en.yml b/config/locales/devise.views.en.yml index fd041b33..ae024645 100644 --- a/config/locales/devise.views.en.yml +++ b/config/locales/devise.views.en.yml @@ -104,7 +104,7 @@ en: new: sign_up: Sign up help: We only ask for an e-mail address and a password. The password is safely stored, no one else besides you knows it! You'll also receive an e-mail to confirm your account. - signed_up: Welcome! You have signed up successfully. + signed_up: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account." signed_up_but_inactive: You have signed up successfully. However, we could not sign you in because your account is not yet activated. signed_up_but_locked: You have signed up successfully. However, we could not sign you in because your account is locked. signed_up_but_unconfirmed: A message with a confirmation link has been sent to your email address. Please follow the link to activate your account. diff --git a/config/locales/devise.views.es.yml b/config/locales/devise.views.es.yml index 73166afc..b9e2e5e4 100644 --- a/config/locales/devise.views.es.yml +++ b/config/locales/devise.views.es.yml @@ -104,7 +104,7 @@ es: new: sign_up: Registrarme help: Para registrarte solo pedimos una dirección de correo y una contraseña. La contraseña se almacena de forma segura, ¡nadie más que vos la sabe! Recibirás un correo de confirmación de cuenta. - signed_up: Bienvenide. Tu cuenta fue creada. + signed_up: "Hemos enviado un mensaje con un enlace de confirmación a tu correo electrónico. Por favor, abrí el enlace para terminar de activar tu cuenta." signed_up_but_inactive: Tu cuenta ha sido creada correctamente. Sin embargo, no hemos podido iniciar la sesión porque tu cuenta aún no está activada. signed_up_but_locked: Tu cuenta ha sido creada correctamente. Sin embargo, no hemos podido iniciar la sesión porque que tu cuenta está bloqueada. signed_up_but_unconfirmed: Para recibir actualizaciones, se ha enviado un mensaje con un enlace de confirmación a tu correo electrónico. Abre el enlace para activar tu cuenta. From b415b3f3cfba3bb8dfc70c71b63038b1674201bd Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 19:05:15 -0300 Subject: [PATCH 238/453] =?UTF-8?q?fix:=20especificar=20d=C3=B3nde=20se=20?= =?UTF-8?q?puede=20pedir=20reconfirmaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/devise.views.en.yml | 2 +- config/locales/devise.views.es.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/devise.views.en.yml b/config/locales/devise.views.en.yml index ae024645..33f7870b 100644 --- a/config/locales/devise.views.en.yml +++ b/config/locales/devise.views.en.yml @@ -138,7 +138,7 @@ en: errors: messages: already_confirmed: was already confirmed, please try signing in - confirmation_period_expired: needs to be confirmed within %{period}, please request a new one + confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one using the \"Didn't receive confirmation instructions?\" link" expired: has expired, please request a new one not_found: not found not_locked: was not locked diff --git a/config/locales/devise.views.es.yml b/config/locales/devise.views.es.yml index b9e2e5e4..63e3ae41 100644 --- a/config/locales/devise.views.es.yml +++ b/config/locales/devise.views.es.yml @@ -138,7 +138,7 @@ es: errors: messages: already_confirmed: ya ha sido confirmada, por favor intenta iniciar sesión - confirmation_period_expired: necesita confirmarse dentro de %{period}, por favor solicita una nueva + confirmation_period_expired: "necesita confirmarse dentro de %{period}, por favor solicita un nuevo código de confirmación usando la opción \"¿No has recibido las instrucciones de confirmación?\"" expired: ha expirado, por favor solicita una nueva not_found: no se ha encontrado not_locked: no estaba bloqueada From 40e68da16a59d9220299ab6c42428e414de293c2 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 19:18:11 -0300 Subject: [PATCH 239/453] fix: mostrar los errores de devise --- app/views/devise/confirmations/new.haml | 4 ++-- app/views/devise/invitations/edit.haml | 3 ++- app/views/devise/invitations/new.haml | 3 ++- app/views/devise/passwords/edit.haml | 3 ++- app/views/devise/passwords/new.haml | 3 ++- app/views/devise/registrations/edit.haml | 4 ++-- app/views/devise/registrations/new.haml | 4 ++-- app/views/devise/shared/_error_messages.haml | 9 ++++----- app/views/devise/unlocks/new.haml | 3 ++- 9 files changed, 20 insertions(+), 16 deletions(-) diff --git a/app/views/devise/confirmations/new.haml b/app/views/devise/confirmations/new.haml index 59568cb7..bc2f77bb 100644 --- a/app/views/devise/confirmations/new.haml +++ b/app/views/devise/confirmations/new.haml @@ -1,6 +1,8 @@ = content_for :body do - 'black-bg' += render 'devise/shared/error_messages', resource: resource + .row.align-items-center.justify-content-center.full-height .col-md-4.align-self-center .sr-only @@ -11,8 +13,6 @@ url: confirmation_path(resource_name), html: { method: :post }) do |f| - = render 'devise/shared/error_messages', resource: resource - :ruby value = if resource.pending_reconfirmation? resource.unconfirmed_email diff --git a/app/views/devise/invitations/edit.haml b/app/views/devise/invitations/edit.haml index 565429a8..ed4980ef 100644 --- a/app/views/devise/invitations/edit.haml +++ b/app/views/devise/invitations/edit.haml @@ -1,6 +1,8 @@ = content_for :body do - 'black-bg' += render 'devise/shared/error_messages', resource: resource + .row.align-items-center.justify-content-center.full-height .col-md-5.align-self-center %h2= t 'devise.invitations.edit.header' @@ -8,7 +10,6 @@ as: resource_name, url: invitation_path(resource_name), html: { method: :put }) do |f| - = render 'devise/shared/error_messages', resource: resource = f.hidden_field :invitation_token, readonly: true - if f.object.class.require_password_on_accepting .form-group diff --git a/app/views/devise/invitations/new.haml b/app/views/devise/invitations/new.haml index 44ceec2e..4ebb8fa7 100644 --- a/app/views/devise/invitations/new.haml +++ b/app/views/devise/invitations/new.haml @@ -1,6 +1,8 @@ = content_for :body do - 'black-bg' += render 'devise/shared/error_messages', resource: resource + .row.align-items-center.justify-content-center.full-height .col-md-5.align-self-center %h2= t 'devise.invitations.new.header' @@ -8,7 +10,6 @@ as: resource_name, url: invitation_path(resource_name), html: { method: :post }) do |f| - = render 'devise/shared/error_messages', resource: resource - resource.class.invite_key_fields.each do |field| .form-group = f.label field diff --git a/app/views/devise/passwords/edit.haml b/app/views/devise/passwords/edit.haml index 7f7b16fb..3a8843c0 100644 --- a/app/views/devise/passwords/edit.haml +++ b/app/views/devise/passwords/edit.haml @@ -1,6 +1,8 @@ = content_for :body do - 'black-bg' += render 'devise/shared/error_messages', resource: resource + .row.align-items-center.justify-content-center.full-height .col-md-5.align-self-center .sr-only @@ -10,7 +12,6 @@ = form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| - = render 'devise/shared/error_messages', resource: resource = f.hidden_field :reset_password_token diff --git a/app/views/devise/passwords/new.haml b/app/views/devise/passwords/new.haml index 3c80b8a0..08dd8d2e 100644 --- a/app/views/devise/passwords/new.haml +++ b/app/views/devise/passwords/new.haml @@ -1,6 +1,8 @@ = content_for :body do - 'black-bg' += render 'devise/shared/error_messages', resource: resource + .row.align-items-center.justify-content-center.full-height .col-md-5.align-self-center .sr-only @@ -11,7 +13,6 @@ as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| - = render 'devise/shared/error_messages', resource: resource .form-group = f.label :email, class: 'sr-only' = f.email_field :email, autofocus: true, autocomplete: 'email', diff --git a/app/views/devise/registrations/edit.haml b/app/views/devise/registrations/edit.haml index 6a25da65..92699ab8 100644 --- a/app/views/devise/registrations/edit.haml +++ b/app/views/devise/registrations/edit.haml @@ -3,6 +3,8 @@ = content_for :body do - 'black-bg' += render 'devise/shared/error_messages', resource: resource + .row.align-items-center.justify-content-center.full-height .col-md-6.align-self-center %h2= t('.title') @@ -11,8 +13,6 @@ url: registration_path(resource_name), html: { method: :put }) do |f| - = render 'devise/shared/error_messages', resource: resource - .form-group = f.label :email = f.email_field :email, autofocus: true, autocomplete: 'email', diff --git a/app/views/devise/registrations/new.haml b/app/views/devise/registrations/new.haml index 21676556..e6bda964 100644 --- a/app/views/devise/registrations/new.haml +++ b/app/views/devise/registrations/new.haml @@ -1,6 +1,8 @@ = content_for :body do - 'black-bg' += render 'devise/shared/error_messages', resource: resource + .row.align-items-center.justify-content-center.full-height .col-md-5.align-self-center %h2= t('.sign_up') @@ -10,8 +12,6 @@ as: resource_name, url: registration_path(resource_name, params: { locale: params[:locale] })) do |f| - = render 'devise/shared/error_messages', resource: resource - .form-group = f.label :email, class: 'sr-only' = f.email_field :email, autofocus: true, autocomplete: 'email', diff --git a/app/views/devise/shared/_error_messages.haml b/app/views/devise/shared/_error_messages.haml index a921fd61..0f0c1835 100644 --- a/app/views/devise/shared/_error_messages.haml +++ b/app/views/devise/shared/_error_messages.haml @@ -1,9 +1,8 @@ - if resource.errors.any? - #error_explanation - %h2 + = render 'bootstrap/alert' do + %h4.alert-heading = I18n.t("errors.messages.not_saved", | count: resource.errors.count, | resource: resource.class.model_name.human.downcase) | - %ul - - resource.errors.full_messages.each do |message| - %li= message + - resource.errors.full_messages.each do |message| + %p= message diff --git a/app/views/devise/unlocks/new.haml b/app/views/devise/unlocks/new.haml index ac511115..09468a52 100644 --- a/app/views/devise/unlocks/new.haml +++ b/app/views/devise/unlocks/new.haml @@ -1,6 +1,8 @@ = content_for :body do - 'black-bg' += render 'devise/shared/error_messages', resource: resource + .row.align-items-center.justify-content-center.full-height .col-md-5.align-self-center .sr-only @@ -11,7 +13,6 @@ as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| - = render 'devise/shared/error_messages', resource: resource .form-group = f.label :email, class: 'sr-only' = f.email_field :email, autofocus: true, autocomplete: 'email', From 944668edbe6c2fa51d0bdce2c8dcb22802760798 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 19:18:30 -0300 Subject: [PATCH 240/453] =?UTF-8?q?fix:=20mostrar=20siempre=20los=20links?= =?UTF-8?q?=20de=20recuperaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit por si se vencen, poder encontrarlos --- app/views/devise/shared/_links.haml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/views/devise/shared/_links.haml b/app/views/devise/shared/_links.haml index b4b89175..479eb457 100644 --- a/app/views/devise/shared/_links.haml +++ b/app/views/devise/shared/_links.haml @@ -18,17 +18,16 @@ new_password_path(resource_name, params: locale) %br/ -- if devise_mapping.confirmable? && controller_name != 'confirmations' +- if devise_mapping.confirmable? = link_to t('.didn_t_receive_confirmation_instructions'), new_confirmation_path(resource_name, params: locale) %br/ - if devise_mapping.lockable? - if resource_class.unlock_strategy_enabled?(:email) - - if controller_name != 'unlocks' - = link_to t('.didn_t_receive_unlock_instructions'), - new_unlock_path(resource_name, params: locale) - %br/ + = link_to t('.didn_t_receive_unlock_instructions'), + new_unlock_path(resource_name, params: locale) + %br/ - if devise_mapping.omniauthable? - resource_class.omniauth_providers.each do |provider| From 79f8241dec54f788910d2f8291b71468e1133f5c Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 19:18:55 -0300 Subject: [PATCH 241/453] fix: ser especificxs --- config/locales/devise.views.en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/devise.views.en.yml b/config/locales/devise.views.en.yml index 33f7870b..027311c9 100644 --- a/config/locales/devise.views.en.yml +++ b/config/locales/devise.views.en.yml @@ -138,7 +138,7 @@ en: errors: messages: already_confirmed: was already confirmed, please try signing in - confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one using the \"Didn't receive confirmation instructions?\" link" + confirmation_period_expired: "needs to be confirmed within %{period}, please request a new confirmation link using the \"Didn't receive confirmation instructions?\" option below" expired: has expired, please request a new one not_found: not found not_locked: was not locked From 445bf26257333d6fb3f96e374721b14d02b88ac6 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 19:21:07 -0300 Subject: [PATCH 242/453] =?UTF-8?q?fix:=20hacer=20la=20caja=20m=C3=A1s=20l?= =?UTF-8?q?egible?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/stylesheets/application.scss | 4 ++++ app/views/bootstrap/_alert.haml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index b756759a..72c7788d 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -25,6 +25,10 @@ $spacers: ( 2-plus: 0.75rem ); +$sizes: ( + "70ch": 70ch, +); + @import "bootstrap"; @import "editor"; diff --git a/app/views/bootstrap/_alert.haml b/app/views/bootstrap/_alert.haml index 0fb3d2d3..395f75d2 100644 --- a/app/views/bootstrap/_alert.haml +++ b/app/views/bootstrap/_alert.haml @@ -1,2 +1,2 @@ -.alert.alert-primary{ role: 'alert', class: local_assigns[:class] } +.alert.alert-primary.mx-auto.content.max-w-70ch{ role: 'alert', class: local_assigns[:class] } = yield From 6856b605176ea40b43e039eff1de69eecb9866b2 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 29 Mar 2023 12:05:55 -0300 Subject: [PATCH 243/453] fixup! fix: usar siempre el componente --- app/views/posts/_form.haml | 2 +- app/views/posts/_submit.haml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/posts/_form.haml b/app/views/posts/_form.haml index f81cef58..7de0ea79 100644 --- a/app/views/posts/_form.haml +++ b/app/views/posts/_form.haml @@ -1,7 +1,7 @@ - unless post.errors.empty? - title = t('.errors.title') - help = t('.errors.help') - = render 'boostrap/alert' do + = render 'bootstrap/alert' do %h4= title %p= help diff --git a/app/views/posts/_submit.haml b/app/views/posts/_submit.haml index 717b8bfe..cad43320 100644 --- a/app/views/posts/_submit.haml +++ b/app/views/posts/_submit.haml @@ -1,6 +1,6 @@ .form-group = submit_tag t('.save'), class: 'btn submit-post' - = render 'boostrap/alert', class: 'invalid-help d-none' do + = render 'bootstrap/alert', class: 'invalid-help d-none' do = site.config.fetch('invalid_help', t('.invalid_help')) - = render 'boostrap/alert', class: 'sending-help d-none' do + = render 'bootstrap/alert', class: 'sending-help d-none' do = site.config.fetch('sending_help', t('.sending_help')) From 40dfa65bc2ae690b684e18478f5a0cde7857fc29 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 29 Mar 2023 16:40:10 -0300 Subject: [PATCH 244/453] =?UTF-8?q?feat:=20anchos=20y=20altos=20m=C3=A1xim?= =?UTF-8?q?os=20y=20m=C3=ADnimos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/stylesheets/application.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 72c7788d..830769a7 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -408,6 +408,8 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); @each $prop, $abbrev in (width: w, height: h) { @each $size, $length in $sizes { .#{$abbrev}-#{$grid-breakpoint}-#{$size} { #{$prop}: $length !important; } + .min-#{$abbrev}#{$infix}-#{$size} { min-#{$prop}: $length !important; } + .max-#{$abbrev}#{$infix}-#{$size} { max-#{$prop}: $length !important; } } } From 951a04574528646272724f4263dd2d5db4fa496d Mon Sep 17 00:00:00 2001 From: f Date: Wed, 29 Mar 2023 16:43:11 -0300 Subject: [PATCH 245/453] =?UTF-8?q?fix:=20no=20mostrar=20un=20t=C3=ADtulo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/devise/shared/_error_messages.haml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/views/devise/shared/_error_messages.haml b/app/views/devise/shared/_error_messages.haml index 0f0c1835..64340e4f 100644 --- a/app/views/devise/shared/_error_messages.haml +++ b/app/views/devise/shared/_error_messages.haml @@ -1,8 +1,4 @@ - if resource.errors.any? = render 'bootstrap/alert' do - %h4.alert-heading - = I18n.t("errors.messages.not_saved", | - count: resource.errors.count, | - resource: resource.class.model_name.human.downcase) | - resource.errors.full_messages.each do |message| %p= message From 167aaf5549106394e15c448731ec938d13ea068d Mon Sep 17 00:00:00 2001 From: f Date: Wed, 29 Mar 2023 16:43:19 -0300 Subject: [PATCH 246/453] =?UTF-8?q?Revert=20"fix:=20mostrar=20siempre=20lo?= =?UTF-8?q?s=20links=20de=20recuperaci=C3=B3n"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 944668edbe6c2fa51d0bdce2c8dcb22802760798. --- app/views/devise/shared/_links.haml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/views/devise/shared/_links.haml b/app/views/devise/shared/_links.haml index 479eb457..b4b89175 100644 --- a/app/views/devise/shared/_links.haml +++ b/app/views/devise/shared/_links.haml @@ -18,16 +18,17 @@ new_password_path(resource_name, params: locale) %br/ -- if devise_mapping.confirmable? +- if devise_mapping.confirmable? && controller_name != 'confirmations' = link_to t('.didn_t_receive_confirmation_instructions'), new_confirmation_path(resource_name, params: locale) %br/ - if devise_mapping.lockable? - if resource_class.unlock_strategy_enabled?(:email) - = link_to t('.didn_t_receive_unlock_instructions'), - new_unlock_path(resource_name, params: locale) - %br/ + - if controller_name != 'unlocks' + = link_to t('.didn_t_receive_unlock_instructions'), + new_unlock_path(resource_name, params: locale) + %br/ - if devise_mapping.omniauthable? - resource_class.omniauth_providers.each do |provider| From 1f921d836f537994fbba18c4df302dea4a9455e5 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 29 Mar 2023 20:18:52 -0300 Subject: [PATCH 247/453] =?UTF-8?q?fixup!=20feat:=20anchos=20y=20altos=20m?= =?UTF-8?q?=C3=A1ximos=20y=20m=C3=ADnimos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/stylesheets/application.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 830769a7..0e602ac0 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -408,8 +408,8 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); @each $prop, $abbrev in (width: w, height: h) { @each $size, $length in $sizes { .#{$abbrev}-#{$grid-breakpoint}-#{$size} { #{$prop}: $length !important; } - .min-#{$abbrev}#{$infix}-#{$size} { min-#{$prop}: $length !important; } - .max-#{$abbrev}#{$infix}-#{$size} { max-#{$prop}: $length !important; } + .min-#{$abbrev}#{$grid-breakpoint}-#{$size} { min-#{$prop}: $length !important; } + .max-#{$abbrev}#{$grid-breakpoint}-#{$size} { max-#{$prop}: $length !important; } } } From ce26c15a505173e8a1579fcdc7578bd4312c74fe Mon Sep 17 00:00:00 2001 From: f Date: Wed, 29 Mar 2023 20:34:54 -0300 Subject: [PATCH 248/453] fix: mejorar el texto --- config/locales/devise.views.en.yml | 2 +- config/locales/devise.views.es.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/devise.views.en.yml b/config/locales/devise.views.en.yml index 027311c9..793f3a0a 100644 --- a/config/locales/devise.views.en.yml +++ b/config/locales/devise.views.en.yml @@ -138,7 +138,7 @@ en: errors: messages: already_confirmed: was already confirmed, please try signing in - confirmation_period_expired: "needs to be confirmed within %{period}, please request a new confirmation link using the \"Didn't receive confirmation instructions?\" option below" + confirmation_period_expired: "wasn't confirmed within %{period}. Please request a new confirmation link by using the \"Resend confirmation instructions\" button below and find it in your inbox." expired: has expired, please request a new one not_found: not found not_locked: was not locked diff --git a/config/locales/devise.views.es.yml b/config/locales/devise.views.es.yml index 63e3ae41..896bcdda 100644 --- a/config/locales/devise.views.es.yml +++ b/config/locales/devise.views.es.yml @@ -138,7 +138,7 @@ es: errors: messages: already_confirmed: ya ha sido confirmada, por favor intenta iniciar sesión - confirmation_period_expired: "necesita confirmarse dentro de %{period}, por favor solicita un nuevo código de confirmación usando la opción \"¿No has recibido las instrucciones de confirmación?\"" + confirmation_period_expired: "sin confirmar luego de %{period}. Por favor, usa el botón \"Reenviar instrucciones de confirmación\" y busca el nuevo link en tu casilla." expired: ha expirado, por favor solicita una nueva not_found: no se ha encontrado not_locked: no estaba bloqueada From a7b199941d5cb3f622712ef065516931792953d7 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 29 Mar 2023 20:39:27 -0300 Subject: [PATCH 249/453] =?UTF-8?q?fixup!=20feat:=20anchos=20y=20altos=20m?= =?UTF-8?q?=C3=A1ximos=20y=20m=C3=ADnimos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/stylesheets/application.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 0e602ac0..2f52829b 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -408,8 +408,8 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); @each $prop, $abbrev in (width: w, height: h) { @each $size, $length in $sizes { .#{$abbrev}-#{$grid-breakpoint}-#{$size} { #{$prop}: $length !important; } - .min-#{$abbrev}#{$grid-breakpoint}-#{$size} { min-#{$prop}: $length !important; } - .max-#{$abbrev}#{$grid-breakpoint}-#{$size} { max-#{$prop}: $length !important; } + .min-#{$abbrev}-#{$grid-breakpoint}-#{$size} { min-#{$prop}: $length !important; } + .max-#{$abbrev}-#{$grid-breakpoint}-#{$size} { max-#{$prop}: $length !important; } } } From be902e33bc4fa7bac1581da3bc2a7f8b5924b66a Mon Sep 17 00:00:00 2001 From: f Date: Wed, 29 Mar 2023 20:45:36 -0300 Subject: [PATCH 250/453] fix: demostrar otro sitio #10233 --- db/seeds/designs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/seeds/designs.yml b/db/seeds/designs.yml index 126a9b12..b1508b84 100644 --- a/db/seeds/designs.yml +++ b/db/seeds/designs.yml @@ -23,7 +23,7 @@ - name_en: 'Sutty' name_es: 'Sutty' gem: 'sutty-jekyll-theme' - url: 'https://rubygems.org/gems/sutty-jekyll-theme/' + url: "https://anarres.sutty.nl" description_en: "The Sutty design" description_es: 'El diseño de Sutty' license: 'https://0xacab.org/sutty/jekyll/sutty-jekyll-theme/-/blob/master/LICENSE.txt' From 117b8502769b1b554878a219b32f15d4a4dfb13b Mon Sep 17 00:00:00 2001 From: f Date: Thu, 30 Mar 2023 10:27:30 -0300 Subject: [PATCH 251/453] fix: hacer pull antes de push --- .woodpecker.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.woodpecker.yml b/.woodpecker.yml index ab4887ac..887d397f 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -47,6 +47,7 @@ pipeline: - "dotenv RAILS_ENV=production bundle exec rails assets:precompile" - "dotenv RAILS_ENV=production bundle exec rails assets:clean" - "git add public && git commit -m \"ci: assets [skip ci]\"" + - "git pull upstream ${CI_COMMIT_BRANCH}" - "git push upstream ${CI_COMMIT_BRANCH}" secrets: - "SSH_KEY" From edd88d04b93aee72429c826ccdf3437a4b2aa0f2 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 30 Mar 2023 11:29:23 -0300 Subject: [PATCH 252/453] =?UTF-8?q?feat:=20pre=20comprimir=20con=20brotli?= =?UTF-8?q?=20tambi=C3=A9n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .woodpecker.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 887d397f..19bd429b 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -28,7 +28,7 @@ pipeline: assets: image: "registry.nulo.in/sutty/panel:${ALPINE_VERSION}-${RUBY_VERSION}.${RUBY_PATCH}" commands: - - "apk add python2 dotenv openssh-client" + - "apk add python2 dotenv openssh-client brotli" - "install -d -m 700 ~/.ssh/" - "echo \"$${KNOWN_HOSTS}\" | base64 -d >> ~/.ssh/known_hosts" - "chmod 600 ~/.ssh/known_hosts" @@ -46,6 +46,7 @@ pipeline: - "dotenv RAILS_ENV=production bundle exec rails webpacker:clobber" - "dotenv RAILS_ENV=production bundle exec rails assets:precompile" - "dotenv RAILS_ENV=production bundle exec rails assets:clean" + - "find public -type f -print0 | xargs -r0 brotli -k9" - "git add public && git commit -m \"ci: assets [skip ci]\"" - "git pull upstream ${CI_COMMIT_BRANCH}" - "git push upstream ${CI_COMMIT_BRANCH}" From 661655abb5d03c2d2e21072de8230a05e324dc28 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 30 Mar 2023 13:51:09 -0300 Subject: [PATCH 253/453] =?UTF-8?q?fix:=20hacer=20el=20deploy=20cuando=20e?= =?UTF-8?q?l=20sitio=20ya=20est=C3=A1=20guardado=20#12276?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/site_service.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 75577226..70824422 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -30,11 +30,10 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do site.reset.nil? && add_licencias && add_code_of_conduct && - add_privacy_policy + add_privacy_policy && + deploy end - deploy - site end From 16c3fa24132037b3ff973b97c97edcb7fbdc8b56 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 30 Mar 2023 14:56:22 -0300 Subject: [PATCH 254/453] =?UTF-8?q?fix:=20ancho=20m=C3=A1ximo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/bootstrap/_alert.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/bootstrap/_alert.haml b/app/views/bootstrap/_alert.haml index 395f75d2..85bcbe84 100644 --- a/app/views/bootstrap/_alert.haml +++ b/app/views/bootstrap/_alert.haml @@ -1,2 +1,2 @@ -.alert.alert-primary.mx-auto.content.max-w-70ch{ role: 'alert', class: local_assigns[:class] } +.alert.alert-primary.mx-auto.content.max-w-md-70ch{ role: 'alert', class: local_assigns[:class] } = yield From aff16fdf779f674257e53f382aa18da71d828d81 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 30 Mar 2023 16:50:45 -0300 Subject: [PATCH 255/453] fix: texto --- config/locales/devise.views.es.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/devise.views.es.yml b/config/locales/devise.views.es.yml index 896bcdda..b745fc5f 100644 --- a/config/locales/devise.views.es.yml +++ b/config/locales/devise.views.es.yml @@ -138,7 +138,7 @@ es: errors: messages: already_confirmed: ya ha sido confirmada, por favor intenta iniciar sesión - confirmation_period_expired: "sin confirmar luego de %{period}. Por favor, usa el botón \"Reenviar instrucciones de confirmación\" y busca el nuevo link en tu casilla." + confirmation_period_expired: "quedó sin confirmar luego de %{period}. Por favor, usa el botón \"Reenviar instrucciones de confirmación\" y busca el nuevo link en tu casilla." expired: ha expirado, por favor solicita una nueva not_found: no se ha encontrado not_locked: no estaba bloqueada From 059230ad6b3249a9dc6c5717bd324102c373345c Mon Sep 17 00:00:00 2001 From: f Date: Thu, 30 Mar 2023 19:33:04 -0300 Subject: [PATCH 256/453] fix: poder cambiar de idioma manteniendo los parametros #12886 --- app/views/layouts/_breadcrumb.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/layouts/_breadcrumb.haml b/app/views/layouts/_breadcrumb.haml index 099ddde4..b1c42cb2 100644 --- a/app/views/layouts/_breadcrumb.haml +++ b/app/views/layouts/_breadcrumb.haml @@ -23,6 +23,7 @@ = link_to t('.logout'), main_app.destroy_usuarie_session_path, method: :delete, role: 'button', class: 'btn' - else + - params.permit! - I18n.available_locales.each do |locale| - next if locale == I18n.locale - = link_to t(locale), "?change_locale_to=#{locale}" + = link_to t(locale), params.to_h.merge(change_locale_to: locale) From 0744e124e350b45a1981080de5981784811dcee7 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 10:56:09 -0300 Subject: [PATCH 257/453] fixup! fix: instalar las gemas cuando sea necesario #12755 --- app/models/site.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/site.rb b/app/models/site.rb index 6110f104..804de42c 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -575,11 +575,11 @@ class Site < ApplicationRecord # Detecta si el Gemfile fue modificado def gemfile_updated? - updated_at > File.mtime(File.join(path, 'Gemfile')) + updated_at < File.mtime(File.join(path, 'Gemfile')) end # Detecta si el Gemfile.lock fue modificado def gemfile_lock_updated? - updated_at > File.mtime(File.join(path, 'Gemfile.lock')) + updated_at < File.mtime(File.join(path, 'Gemfile.lock')) end end From 8c5535c5c7a1dc4af94b57ed0e948c0e191f0350 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 17:39:25 -0300 Subject: [PATCH 258/453] =?UTF-8?q?fix:=20ordenar=20layouts=20alfab=C3=A9t?= =?UTF-8?q?icamente=20#5085?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/posts/index.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index a82616d8..8a2a678d 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -5,7 +5,7 @@ %h3= t('posts.new') %table.mb-3 - - @site.layouts.each do |layout| + - @site.layouts.sort_by(&:humanized_name).each do |layout| - next if layout.hidden? %tr %th= layout.humanized_name From 59e97ef6856fb8617df3edaab6dcf7e2df5554e5 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 18:16:11 -0300 Subject: [PATCH 259/453] =?UTF-8?q?fix:=20forzar=20la=20compilaci=C3=B3n?= =?UTF-8?q?=20de=20brotli?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .woodpecker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 19bd429b..1d760b52 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -46,7 +46,7 @@ pipeline: - "dotenv RAILS_ENV=production bundle exec rails webpacker:clobber" - "dotenv RAILS_ENV=production bundle exec rails assets:precompile" - "dotenv RAILS_ENV=production bundle exec rails assets:clean" - - "find public -type f -print0 | xargs -r0 brotli -k9" + - "find public -type f -print0 | xargs -r0 brotli -k9f" - "git add public && git commit -m \"ci: assets [skip ci]\"" - "git pull upstream ${CI_COMMIT_BRANCH}" - "git push upstream ${CI_COMMIT_BRANCH}" From 0d0c8c8b073598d9a74114d8ec65923c90ab7e32 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 19:31:22 -0300 Subject: [PATCH 260/453] =?UTF-8?q?fix:=20mostrar=20los=20dise=C3=B1os=20e?= =?UTF-8?q?n=20dos=20columnas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/sites/_form.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/sites/_form.haml b/app/views/sites/_form.haml index 757b8b48..2d8ea4fb 100644 --- a/app/views/sites/_form.haml +++ b/app/views/sites/_form.haml @@ -53,10 +53,10 @@ = render 'bootstrap/alert' do = t('activerecord.errors.models.site.attributes.design_id.layout_incompatible.help', layouts: site.incompatible_layouts.to_sentence) - .row.designs + .row.row-cols-1.row-cols-md-2.designs -# Demasiado complejo para un f.collection_radio_buttons - Design.all.find_each do |design| - .design.col-md-4.d-flex.flex-column + .design.col.d-flex.flex-column .custom-control.custom-radio = f.radio_button :design_id, design.id, checked: design.id == site.design_id, From c2fafac7f0556c12015fb0bf8c102cc22c15723f Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 19:32:36 -0300 Subject: [PATCH 261/453] feat: informar el estado del sitio #10492 --- app/models/site.rb | 1 + app/models/site/build_stats.rb | 45 ++++++++++++++++++++++++++++++++++ app/views/posts/index.haml | 4 ++- app/views/sites/_status.haml | 19 ++++++++++++++ config/locales/en.yml | 4 +++ config/locales/es.yml | 4 +++ 6 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 app/models/site/build_stats.rb create mode 100644 app/views/sites/_status.haml diff --git a/app/models/site.rb b/app/models/site.rb index 4b2a8eb9..6aa96612 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -7,6 +7,7 @@ class Site < ApplicationRecord include Site::Forms include Site::FindAndReplace include Site::Api + include Site::BuildStats include Tienda # Cifrar la llave privada que cifra y decifra campos ocultos. Sutty diff --git a/app/models/site/build_stats.rb b/app/models/site/build_stats.rb new file mode 100644 index 00000000..8b23942d --- /dev/null +++ b/app/models/site/build_stats.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +class Site + module BuildStats + extend ActiveSupport::Concern + + included do + # Devuelve el tiempo promedio de publicación para este sitio + # + # @return [Integer] + def average_publication_time + build_stats.group(:action).average(:seconds).values.reduce(:+).round + end + + # Devuelve el tiempo promedio de compilación para sitios similares + # a este. + # + # @return [Integer] + def average_publication_time_for_similar_sites + similar_deploys = Deploy.where(type: deploys.pluck(:type)).pluck(:id) + + BuildStat.where(deploy_id: similar_deploys).group(:action).average(:seconds).values.reduce(:+).round + end + + # Define si podemos calcular el tiempo promedio de publicación + # para este sitio + # + # @return [Boolean] + def average_publication_time_calculable? + build_stats.jekyll.where(status: true).count > 0 + end + + def similar_sites? + !design.no_theme? + end + + # Detecta si el sitio todavía no ha sido publicado + # + # @return [Boolean] + def not_published_yet? + build_stats.jekyll.where(status: true).count.zero? + end + end + end +end diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index dbeddaad..f7b884af 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -1,7 +1,9 @@ %main.row %aside.menu.col-md-3 - %h1= link_to @site.title, @site.url + %h1= @site.title %p.lead= @site.description + - cache_if @usuarie, [@site, I18n.locale] do + = render 'sites/status', site: @site %h3= t('posts.new') %table.mb-3 diff --git a/app/views/sites/_status.haml b/app/views/sites/_status.haml new file mode 100644 index 00000000..fb38896a --- /dev/null +++ b/app/views/sites/_status.haml @@ -0,0 +1,19 @@ +- link = nil +- if site.not_published_yet? + - message = t('.not_published_yet') +- if site.building? + - if site.average_publication_time_calculable? + - average_building_time = site.average_building_time + - elsif !site.similar_sites? + - average_building_time = 60 + - else + - average_building_time = site.average_publication_time_for_similar_sites + + - average_publication_time_human = distance_of_time_in_words average_building_time + - message = t('.building', average_time: average_publication_time_human, seconds: average_building_time) +- else + - message = t('.available') + - link = true + += render 'bootstrap/alert' do + = link_to_if link, message.html_safe, site.url diff --git a/config/locales/en.yml b/config/locales/en.yml index 567ab6bb..ee16f506 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -330,6 +330,10 @@ en: designer_url: 'Support the designer' static_file_migration: 'File migration' find_and_replace: 'Search and replace' + status: + building: "Your site is building, please wait ..." + not_published_yet: "Your site is being published for the first time, please wait up to 1 minute..." + available: "Your site is available! Click here to visit it." index: title: 'My Sites' pull: 'Upgrade' diff --git a/config/locales/es.yml b/config/locales/es.yml index 0a829e4a..e3d3f2ef 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -335,6 +335,10 @@ es: designer_url: 'Apoyá a le(s) diseñadore(s)' static_file_migration: 'Migración de archivos' find_and_replace: 'Búsqueda y reemplazo' + status: + building: "Tu sitio se está publicando, por favor espera ..." + not_published_yet: "Tu sitio se está publicando por primera vez, por favor espera hasta un minuto..." + available: "¡Tu sitio está disponible! Cliquea aquí para visitarlo." index: title: 'Mis sitios' pull: 'Actualizar' From 0442aa1e0672167a9502a5c5b7d14440bd7fdf88 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 19:37:47 -0300 Subject: [PATCH 262/453] fixup! feat: informar el estado del sitio #10492 --- app/views/sites/_status.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/sites/_status.haml b/app/views/sites/_status.haml index fb38896a..52afa3ca 100644 --- a/app/views/sites/_status.haml +++ b/app/views/sites/_status.haml @@ -3,7 +3,7 @@ - message = t('.not_published_yet') - if site.building? - if site.average_publication_time_calculable? - - average_building_time = site.average_building_time + - average_building_time = site.average_publication_time - elsif !site.similar_sites? - average_building_time = 60 - else From 8f19f837cdb11740cfe58d8be7fee4af30a70962 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 20:20:37 -0300 Subject: [PATCH 263/453] =?UTF-8?q?fix:=20hacer=20que=20devise=20respete?= =?UTF-8?q?=20el=20idioma=20de=20la=20sesi=C3=B3n=20#10478?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/devise/failure_app_decorator.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 app/lib/devise/failure_app_decorator.rb diff --git a/app/lib/devise/failure_app_decorator.rb b/app/lib/devise/failure_app_decorator.rb new file mode 100644 index 00000000..f17cb482 --- /dev/null +++ b/app/lib/devise/failure_app_decorator.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Devise + module FailureAppDecorator + extend ActiveSupport::Concern + + included do + include AbstractController::Callbacks + + around_action :set_locale + + private + + def set_locale(&action) + I18n.with_locale(session[:locale] || I18n.locale, &action) + end + end + end +end + +Devise::FailureApp.include Devise::FailureAppDecorator From f62d7fcc800fd5e6c5eeea9306ee60df49ae9943 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 20:51:20 -0300 Subject: [PATCH 264/453] =?UTF-8?q?fix:=20esperar=20a=20que=20la=20primera?= =?UTF-8?q?=20publicaci=C3=B3n=20termine?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/site/build_stats.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/site/build_stats.rb b/app/models/site/build_stats.rb index 8b23942d..6eebcc84 100644 --- a/app/models/site/build_stats.rb +++ b/app/models/site/build_stats.rb @@ -27,7 +27,7 @@ class Site # # @return [Boolean] def average_publication_time_calculable? - build_stats.jekyll.where(status: true).count > 0 + build_stats.jekyll.where(status: true).count > 1 end def similar_sites? From 5ae3fe0b354a9649c8b079c2f5966b23cd7b7eef Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 20:52:35 -0300 Subject: [PATCH 265/453] =?UTF-8?q?fix:=20dar=20una=20acci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index ee16f506..f3e319ee 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -331,7 +331,7 @@ en: static_file_migration: 'File migration' find_and_replace: 'Search and replace' status: - building: "Your site is building, please wait ..." + building: "Your site is building, please wait to refresh this page..." not_published_yet: "Your site is being published for the first time, please wait up to 1 minute..." available: "Your site is available! Click here to visit it." index: diff --git a/config/locales/es.yml b/config/locales/es.yml index e3d3f2ef..98181fb3 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -336,7 +336,7 @@ es: static_file_migration: 'Migración de archivos' find_and_replace: 'Búsqueda y reemplazo' status: - building: "Tu sitio se está publicando, por favor espera ..." + building: "Tu sitio se está publicando, por favor espera para recargar esta página..." not_published_yet: "Tu sitio se está publicando por primera vez, por favor espera hasta un minuto..." available: "¡Tu sitio está disponible! Cliquea aquí para visitarlo." index: From ec47335f04ccc4b0a7424fcbe92ad65d7ce6c129 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 3 Apr 2023 12:44:09 -0300 Subject: [PATCH 266/453] fix: es necesario el arbol actual para ignorar cambios en paralelo cuando estamos guardando un post con archivos subidos y posts relacionados, al no usar el arbol actual se pisaban los archivos modificados y el repositorio quedaba en un estado inconsistente. --- app/models/site/repository.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/models/site/repository.rb b/app/models/site/repository.rb index f63288d4..62e4c45e 100644 --- a/app/models/site/repository.rb +++ b/app/models/site/repository.rb @@ -117,6 +117,9 @@ class Site def commit(file:, usuarie:, message:, remove: false) file = [file] unless file.respond_to? :each + # Cargar el árbol actual + rugged.index.read_tree rugged.head.target.tree + file.each do |f| remove ? rm(f) : add(f) end From ad76fed1b19dac253f67b333be25b7cdd7ee01fa Mon Sep 17 00:00:00 2001 From: f Date: Mon, 3 Apr 2023 13:31:32 -0300 Subject: [PATCH 267/453] fix: alert en modo oscuro --- app/assets/stylesheets/application.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 2f52829b..258698d3 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -52,6 +52,12 @@ $sizes: ( --background: #{$black}; --color: #{$cyan}; } + + .alert-primary { + @include alert-variant(theme-color-level($cyan, $alert-bg-level), + theme-color-level($cyan, $alert-border-level), + theme-color-level($cyan, $alert-color-level)); + } } // TODO: Encontrar la forma de generar esto desde los locales de Rails From bd21f3d9b4806b54b63b3ece2efa5a0d4acbbf5e Mon Sep 17 00:00:00 2001 From: f Date: Mon, 3 Apr 2023 13:47:12 -0300 Subject: [PATCH 268/453] fixup! fix: alert en modo oscuro --- app/assets/stylesheets/application.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 258698d3..99b5a296 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -54,9 +54,9 @@ $sizes: ( } .alert-primary { - @include alert-variant(theme-color-level($cyan, $alert-bg-level), - theme-color-level($cyan, $alert-border-level), - theme-color-level($cyan, $alert-color-level)); + @include alert-variant(theme-color-level("cyan", $alert-bg-level), + theme-color-level("cyan", $alert-border-level), + theme-color-level("cyan", $alert-color-level)); } } From 191dbbd82344a8e7545c4c65e9d84838c435e27e Mon Sep 17 00:00:00 2001 From: f Date: Mon, 3 Apr 2023 13:47:59 -0300 Subject: [PATCH 269/453] fix: indicar que hay un link --- app/views/sites/_status.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/sites/_status.haml b/app/views/sites/_status.haml index 52afa3ca..a731aa7d 100644 --- a/app/views/sites/_status.haml +++ b/app/views/sites/_status.haml @@ -16,4 +16,4 @@ - link = true = render 'bootstrap/alert' do - = link_to_if link, message.html_safe, site.url + = link_to_if link, message.html_safe, site.url, class: 'alert-link' From 3dacef76f1cafb9ecb64cb527737ba34452e9536 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 3 Apr 2023 13:55:21 -0300 Subject: [PATCH 270/453] fix: esto no funciona --- app/assets/stylesheets/application.scss | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 99b5a296..2f52829b 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -52,12 +52,6 @@ $sizes: ( --background: #{$black}; --color: #{$cyan}; } - - .alert-primary { - @include alert-variant(theme-color-level("cyan", $alert-bg-level), - theme-color-level("cyan", $alert-border-level), - theme-color-level("cyan", $alert-color-level)); - } } // TODO: Encontrar la forma de generar esto desde los locales de Rails From b7a27a87dd2879622f89d4102f4a4346aa7c17ac Mon Sep 17 00:00:00 2001 From: f Date: Mon, 3 Apr 2023 16:58:22 -0300 Subject: [PATCH 271/453] feat: cuando se modifica la licencia, considerarla personalizada --- app/models/licencia.rb | 4 ++++ app/services/post_service.rb | 12 ++++++++++++ app/views/sites/_form.haml | 1 + db/seeds/licencias.yml | 6 ++++++ 4 files changed, 23 insertions(+) diff --git a/app/models/licencia.rb b/app/models/licencia.rb index f0a542ef..351a8ae5 100644 --- a/app/models/licencia.rb +++ b/app/models/licencia.rb @@ -17,4 +17,8 @@ class Licencia < ApplicationRecord validates :description, presence: true validates :short_description, presence: true validates :deed, presence: true + + def custom? + url == 'custom' + end end diff --git a/app/services/post_service.rb b/app/services/post_service.rb index 81ebe4a1..f1b9f7c3 100644 --- a/app/services/post_service.rb +++ b/app/services/post_service.rb @@ -18,6 +18,8 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do commit(action: :created, file: update_related_posts) if post.update(post_params) + update_site_license! + # Devolver el post aunque no se haya salvado para poder rescatar los # errores post @@ -44,6 +46,8 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do # relacionados. commit(action: :updated, file: update_related_posts) if post.update(post_params) + update_site_license! + # Devolver el post aunque no se haya salvado para poder rescatar los # errores post @@ -137,4 +141,12 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do p.path.absolute if p.save(validate: false) end.compact << post.path.absolute end + + # Si les usuaries modifican o crean una licencia, considerarla + # personalizada en el panel. + def update_site_license! + if site.usuarie?(usuarie) && post.layout.name == :license + site.update licencia: Licencia.find_by_url('custom') + end + end end diff --git a/app/views/sites/_form.haml b/app/views/sites/_form.haml index 9a044c7f..10f158c8 100644 --- a/app/views/sites/_form.haml +++ b/app/views/sites/_form.haml @@ -79,6 +79,7 @@ %h2= t('.licencia.title') %p.lead= t('.help.licencia') - Licencia.all.find_each do |licencia| + - next if licencia.custom? && site.licencia != licencia .row.license .col .media.mt-1 diff --git a/db/seeds/licencias.yml b/db/seeds/licencias.yml index c5e2886a..402e5d8b 100644 --- a/db/seeds/licencias.yml +++ b/db/seeds/licencias.yml @@ -1,4 +1,10 @@ --- +- name_en: "Custom license" + name_es: "Licencia personalizada" + url_en: "custom" + url_es: "custom" + description_en: "The license terms are provided by you." + description_es: "Los términos de la licencia fueron provistos por vos." - name_en: 'Peer Production License' name_es: 'Licencia de Producción de Pares' short_description_en: "This work is licensed under a Peer Production License" From 94d30ac12aebac141992747613f888b573f5f43f Mon Sep 17 00:00:00 2001 From: f Date: Mon, 3 Apr 2023 17:50:04 -0300 Subject: [PATCH 272/453] fixup! feat: cuando se modifica la licencia, considerarla personalizada --- app/models/licencia.rb | 2 +- app/services/post_service.rb | 4 ++-- app/services/site_service.rb | 2 ++ app/views/sites/_form.haml | 7 ++++--- db/seeds/licencias.yml | 9 +++++++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/models/licencia.rb b/app/models/licencia.rb index 351a8ae5..65009f46 100644 --- a/app/models/licencia.rb +++ b/app/models/licencia.rb @@ -19,6 +19,6 @@ class Licencia < ApplicationRecord validates :deed, presence: true def custom? - url == 'custom' + icons == 'custom' end end diff --git a/app/services/post_service.rb b/app/services/post_service.rb index f1b9f7c3..7b31867d 100644 --- a/app/services/post_service.rb +++ b/app/services/post_service.rb @@ -145,8 +145,8 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do # Si les usuaries modifican o crean una licencia, considerarla # personalizada en el panel. def update_site_license! - if site.usuarie?(usuarie) && post.layout.name == :license - site.update licencia: Licencia.find_by_url('custom') + if site.usuarie?(usuarie) && post.layout.name == :license && !site.licencia.custom? + site.update licencia: Licencia.find_by_icons('custom') end end end diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 70824422..5e1d5055 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -110,6 +110,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # @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 @@ -140,6 +141,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # @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') diff --git a/app/views/sites/_form.haml b/app/views/sites/_form.haml index 10f158c8..137a40b0 100644 --- a/app/views/sites/_form.haml +++ b/app/views/sites/_form.haml @@ -83,7 +83,8 @@ .row.license .col .media.mt-1 - = image_tag licencia.icons, alt: licencia.name, class: 'mr-3 mt-4' + - unless licencia.custom? + = image_tag licencia.icons, alt: licencia.name, class: 'mr-3 mt-4' .media-body .custom-control.custom-radio = f.radio_button :licencia_id, licencia.id, @@ -94,8 +95,8 @@ = sanitize_markdown licencia.description, tags: %w[p a strong em ul ol li h1 h2 h3 h4 h5 h6] - = link_to t('.licencia.url'), licencia.url, - target: '_blank', class: 'btn' + - unless licencia.custom? + = link_to t('.licencia.url'), licencia.url, target: '_blank', class: 'btn', rel: 'noopener' %hr/ diff --git a/db/seeds/licencias.yml b/db/seeds/licencias.yml index 402e5d8b..f6b76296 100644 --- a/db/seeds/licencias.yml +++ b/db/seeds/licencias.yml @@ -1,10 +1,15 @@ --- - name_en: "Custom license" name_es: "Licencia personalizada" - url_en: "custom" - url_es: "custom" + url_en: "" + url_es: "" + icons: "custom" + short_description_en: "" + short_description_es: "" description_en: "The license terms are provided by you." description_es: "Los términos de la licencia fueron provistos por vos." + deed_en: "" + deed_es: "" - name_en: 'Peer Production License' name_es: 'Licencia de Producción de Pares' short_description_en: "This work is licensed under a Peer Production License" From ea71aafe58c233234bcdf1c00df7fac5df2b1cea Mon Sep 17 00:00:00 2001 From: f Date: Tue, 4 Apr 2023 11:33:51 -0300 Subject: [PATCH 273/453] fix: enviar los correos de devise en el idioma de le usuarie #12952 --- app/models/usuarie.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/models/usuarie.rb b/app/models/usuarie.rb index c87d82f9..7b83ee75 100644 --- a/app/models/usuarie.rb +++ b/app/models/usuarie.rb @@ -41,6 +41,12 @@ class Usuarie < ApplicationRecord lock_access! if attempts_exceeded? && !access_locked? end + def send_devise_notification(notification, *args) + I18n.with_locale(lang) do + devise_mailer.send(notification, self, *args).deliver_later + end + end + private def lang_from_locale! From 38d6f6d842ebcb6715aa02427a8875e9c9fd2b3b Mon Sep 17 00:00:00 2001 From: f Date: Tue, 4 Apr 2023 13:21:38 -0300 Subject: [PATCH 274/453] =?UTF-8?q?fix:=20mantener=20la=20notificaci=C3=B3?= =?UTF-8?q?n=20hasta=20que=20se=20confirme=20el=20correo=20#12950?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/application_controller.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e80c279d..0628421f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -9,6 +9,7 @@ class ApplicationController < ActionController::Base before_action :prepare_exception_notifier before_action :configure_permitted_parameters, if: :devise_controller? + before_action :notify_unconfirmed_email, unless: :devise_controller? around_action :set_locale rescue_from Pundit::NilPolicyError, with: :page_not_found @@ -27,6 +28,13 @@ class ApplicationController < ActionController::Base private + def notify_unconfirmed_email + return unless current_usuarie + return if current_usuarie.confirmed? + + flash[:notice] ||= I18n.t('devise.registrations.signed_up') + end + def uuid?(string) /[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}/ =~ string end From 8d31170086d3fa51c946c244fff4814f72b9075f Mon Sep 17 00:00:00 2001 From: f Date: Tue, 4 Apr 2023 13:34:19 -0300 Subject: [PATCH 275/453] fix: usar el idioma de le usuarie --- app/controllers/application_controller.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0628421f..b4be5a97 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -32,7 +32,9 @@ class ApplicationController < ActionController::Base return unless current_usuarie return if current_usuarie.confirmed? - flash[:notice] ||= I18n.t('devise.registrations.signed_up') + I18n.with_locale(current_usuarie.lang) do + flash[:notice] ||= I18n.t('devise.registrations.signed_up') + end end def uuid?(string) @@ -92,6 +94,7 @@ class ApplicationController < ActionController::Base protected def configure_permitted_parameters + devise_parameter_sanitizer.permit(:sign_up, keys: Usuarie::CONSENT_FIELDS) devise_parameter_sanitizer.permit(:account_update, keys: %i[lang]) end From 29be4b26b034ee7e2a78413e9c8dbd6278266fc8 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 5 Apr 2023 19:30:44 -0300 Subject: [PATCH 276/453] fix: no producir un error al no haber locales --- app/models/metadata_locales.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/metadata_locales.rb b/app/models/metadata_locales.rb index 3790b944..37b50286 100644 --- a/app/models/metadata_locales.rb +++ b/app/models/metadata_locales.rb @@ -44,6 +44,6 @@ class MetadataLocales < MetadataHasAndBelongsToMany def posts other_locales.map do |locale| site.posts(lang: locale).where(layout: post.layout.value) - end.reduce(&:concat) || PostRelation.new + end.reduce(&:concat) || PostRelation.new(site: site, lang: 'any') end end From 6bc013c8593bdb9d184fadcd6f091ab1e2d4d8eb Mon Sep 17 00:00:00 2001 From: f Date: Wed, 5 Apr 2023 19:30:59 -0300 Subject: [PATCH 277/453] fix: no mostrar el campo si no hay locales --- app/views/posts/attribute_ro/_locales.haml | 19 +++++++------- app/views/posts/attributes/_locales.haml | 29 +++++++++++----------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/app/views/posts/attribute_ro/_locales.haml b/app/views/posts/attribute_ro/_locales.haml index 3ac22933..16ecb532 100644 --- a/app/views/posts/attribute_ro/_locales.haml +++ b/app/views/posts/attribute_ro/_locales.haml @@ -1,9 +1,10 @@ -%tr{ id: attribute } - %th= post_label_t(attribute, post: post) - %td - %ul - - metadata.value.each do |uuid| - - p = site.docs.find(uuid, uuid: true) - %li{ dir: t("locales.#{p.lang.value}.dir"), lang: p.lang.value } - = link_to p.title.value, - site_post_path(site, p.id, locale: p.lang.value) +- if site.locales.count > 1 + %tr{ id: attribute } + %th= post_label_t(attribute, post: post) + %td + %ul + - metadata.value.each do |uuid| + - p = site.docs.find(uuid, uuid: true) + %li{ dir: t("locales.#{p.lang.value}.dir"), lang: p.lang.value } + = link_to p.title.value, + site_post_path(site, p.id, locale: p.lang.value) diff --git a/app/views/posts/attributes/_locales.haml b/app/views/posts/attributes/_locales.haml index 23f66700..4978f6b4 100644 --- a/app/views/posts/attributes/_locales.haml +++ b/app/views/posts/attributes/_locales.haml @@ -1,18 +1,19 @@ -%fieldset - %legend= post_label_t(attribute, post: post) +- if site.locales.count > 1 + %fieldset + %legend= post_label_t(attribute, post: post) - = render 'posts/attribute_feedback', - post: post, attribute: attribute, metadata: metadata + = render 'posts/attribute_feedback', + post: post, attribute: attribute, metadata: metadata - - site.locales.each do |locale| - - next if post.lang.value == locale - - locale_t = t("locales.#{locale}.name", default: locale.to_s.humanize) - - value = metadata.value.find do |v| - - metadata.values[locale].values.include? v + - site.locales.each do |locale| + - next if post.lang.value == locale + - locale_t = t("locales.#{locale}.name", default: locale.to_s.humanize) + - value = metadata.value.find do |v| + - metadata.values[locale].values.include? v - .form-group - = label_tag "#{base}_#{attribute}_#{locale}", locale_t + .form-group + = label_tag "#{base}_#{attribute}_#{locale}", locale_t - = select_tag("#{plain_field_name_for(base, attribute)}[]", - options_for_select(metadata.values[locale], value), - **field_options(attribute, metadata), include_blank: t('.empty')) + = select_tag("#{plain_field_name_for(base, attribute)}[]", + options_for_select(metadata.values[locale], value), + **field_options(attribute, metadata), include_blank: t('.empty')) From dd3ef04fc4b759d818ac9ef16db88e59761889ab Mon Sep 17 00:00:00 2001 From: f Date: Thu, 6 Apr 2023 11:19:33 -0300 Subject: [PATCH 278/453] =?UTF-8?q?feat:=20generar=20im=C3=A1genes=20p?= =?UTF-8?q?=C3=BAblicas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .woodpecker.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 1d760b52..2e775624 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -1,10 +1,10 @@ pipeline: publish: - image: "plugins/docker" + image: "docker.io/woodpeckerci/plugin-docker-buildx" settings: - registry: "registry.nulo.in" + registry: "gitea.nulo.in" username: "sutty" - repo: "registry.nulo.in/sutty/panel" + repo: "gitea.nulo.in/sutty/panel" tags: - "${ALPINE_VERSION}-${RUBY_VERSION}.${RUBY_PATCH}" - "latest" @@ -12,10 +12,10 @@ pipeline: - "RUBY_VERSION=${RUBY_VERSION}" - "RUBY_PATCH=${RUBY_PATCH}" - "ALPINE_VERSION=${ALPINE_VERSION}" - - "BASE_IMAGE=registry.nulo.in/sutty/rails" + - "BASE_IMAGE=gitea.nulo.in/sutty/rails" purge: false secrets: - - "docker_password" + - "DOCKER_PASSWORD" when: branch: - "rails" @@ -26,7 +26,7 @@ pipeline: - "Dockerfile" - ".dockerignore" assets: - image: "registry.nulo.in/sutty/panel:${ALPINE_VERSION}-${RUBY_VERSION}.${RUBY_PATCH}" + image: "gitea.nulo.in/sutty/panel:${ALPINE_VERSION}-${RUBY_VERSION}.${RUBY_PATCH}" commands: - "apk add python2 dotenv openssh-client brotli" - "install -d -m 700 ~/.ssh/" @@ -66,6 +66,6 @@ pipeline: - "yarn.lock" matrix: include: - - ALPINE_VERSION: "3.14.8" + - ALPINE_VERSION: "3.14.10" RUBY_VERSION: "2.7" - RUBY_PATCH: "6" + RUBY_PATCH: "8" From 34d26a0174b0644d96e430b3bf894c734d366dce Mon Sep 17 00:00:00 2001 From: f Date: Thu, 6 Apr 2023 11:27:28 -0300 Subject: [PATCH 279/453] fix: instalar pnpm 7 porque 8 es incompatible con node 14 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index a6420a35..3da9ffab 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ RUN apk add --no-cache libxslt libxml2 postgresql-libs libssh2 \ RUN gem install --no-document --no-user-install foreman RUN wget https://github.com/jgm/pandoc/releases/download/${PANDOC_VERSION}/pandoc-${PANDOC_VERSION}-linux-amd64.tar.gz -O - | tar --strip-components 1 -xvzf - pandoc-${PANDOC_VERSION}/bin/pandoc && mv /bin/pandoc /usr/bin/pandoc -RUN apk add npm && npm install -g pnpm && apk del npm +RUN apk add npm && npm install -g pnpm@~7 && apk del npm COPY ./monit.conf /etc/monit.d/sutty.conf From 54aa022b8c9dd844aacf2481606ccfe996e6982d Mon Sep 17 00:00:00 2001 From: f Date: Thu, 6 Apr 2023 11:27:28 -0300 Subject: [PATCH 280/453] fix: instalar pnpm 7 porque 8 es incompatible con node 14 --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 342c2750..3da9ffab 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,6 +14,7 @@ RUN apk add --no-cache libxslt libxml2 postgresql-libs libssh2 \ RUN gem install --no-document --no-user-install foreman RUN wget https://github.com/jgm/pandoc/releases/download/${PANDOC_VERSION}/pandoc-${PANDOC_VERSION}-linux-amd64.tar.gz -O - | tar --strip-components 1 -xvzf - pandoc-${PANDOC_VERSION}/bin/pandoc && mv /bin/pandoc /usr/bin/pandoc +RUN apk add npm && npm install -g pnpm@~7 && apk del npm COPY ./monit.conf /etc/monit.d/sutty.conf From c45441430f45dad5061a49e38b4f51aa7f5e3d97 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 6 Apr 2023 15:09:14 -0300 Subject: [PATCH 281/453] =?UTF-8?q?fix:=20indicar=20qu=C3=A9=20acci=C3=B3n?= =?UTF-8?q?=20vamos=20a=20hacer=20#12970?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/layouts/_breadcrumb.haml | 2 +- config/locales/en.yml | 6 ++++-- config/locales/es.yml | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/views/layouts/_breadcrumb.haml b/app/views/layouts/_breadcrumb.haml index 099ddde4..2a72ab11 100644 --- a/app/views/layouts/_breadcrumb.haml +++ b/app/views/layouts/_breadcrumb.haml @@ -25,4 +25,4 @@ - else - I18n.available_locales.each do |locale| - next if locale == I18n.locale - = link_to t(locale), "?change_locale_to=#{locale}" + = link_to t("switch_locale.#{locale}"), "?change_locale_to=#{locale}" diff --git a/config/locales/en.yml b/config/locales/en.yml index 567ab6bb..7798294c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,8 +1,10 @@ en: dir: ltr en: English - es: Castellano - es-AR: Castellano rioplatense + es: Castellano + es-AR: Castellano rioplatense + switch_locale: + es: "Cambiar a castellano" locales: es: name: Castillian Spanish diff --git a/config/locales/es.yml b/config/locales/es.yml index 0a829e4a..a7f06ba8 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -3,6 +3,8 @@ es: en: English es-AR: Castellano Rioplatense dir: ltr + switch_locale: + en: "Switch to English" locales: es: name: Castellano From 6cab61891c9c1fd0fb7c3a260febc816d40178ea Mon Sep 17 00:00:00 2001 From: f Date: Thu, 6 Apr 2023 20:30:47 -0300 Subject: [PATCH 282/453] fix: la tarea estaba mal nombrada --- Procfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Procfile b/Procfile index 950168dd..25a1639d 100644 --- a/Procfile +++ b/Procfile @@ -5,6 +5,6 @@ blazer_1h: bundle exec rake blazer:run_checks SCHEDULE="1 hour" blazer_1d: bundle exec rake blazer:run_checks SCHEDULE="1 day" blazer: bundle exec rake blazer:send_failing_checks prometheus: bundle exec prometheus_exporter -b 0.0.0.0 --prefix "sutty_" -distributed_press_renew_tokens: bundle exec rake distributed_press:tokens:renew +distributed_press_tokens_renew: bundle exec rake distributed_press:tokens:renew cleanup: bundle exec rake cleanup:everything stats: bundle exec rake stats:process_all From 4f8ea0d9a726b860edce4227939e7005c6b1107e Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 18:38:47 -0300 Subject: [PATCH 283/453] feat: los deploys son interdependientes --- app/models/deploy.rb | 7 +++---- app/models/deploy_alternative_domain.rb | 2 ++ app/models/deploy_rsync.rb | 8 ++++++++ app/models/deploy_www.rb | 2 ++ app/models/deploy_zip.rb | 2 ++ 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 9d5c1d27..942336ad 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'open3' + # Este modelo implementa los distintos tipos de alojamiento que provee # Sutty. # @@ -11,11 +12,9 @@ class Deploy < ApplicationRecord belongs_to :site has_many :build_stats, dependent: :destroy - def deploy(**) - raise NotImplementedError - end + DEPENDENCIES = [] - def url + def deploy(**) raise NotImplementedError end diff --git a/app/models/deploy_alternative_domain.rb b/app/models/deploy_alternative_domain.rb index 5ad381d5..114f2aa5 100644 --- a/app/models/deploy_alternative_domain.rb +++ b/app/models/deploy_alternative_domain.rb @@ -4,6 +4,8 @@ class DeployAlternativeDomain < Deploy store :values, accessors: %i[hostname], coder: JSON + DEPENDENCIES = %i[local] + # Generar un link simbólico del sitio principal al alternativo def deploy(**) File.symlink?(destination) || diff --git a/app/models/deploy_rsync.rb b/app/models/deploy_rsync.rb index a658de6b..9ced0bb1 100644 --- a/app/models/deploy_rsync.rb +++ b/app/models/deploy_rsync.rb @@ -5,6 +5,14 @@ class DeployRsync < Deploy store :values, accessors: %i[destination host_keys], coder: JSON + DEPENDENCIES = %i[ + alternative_domain + hidden_service + local + www + zip + ] + def deploy(output: false) ssh? && rsync(output: output) end diff --git a/app/models/deploy_www.rb b/app/models/deploy_www.rb index dff769a6..e6cfe407 100644 --- a/app/models/deploy_www.rb +++ b/app/models/deploy_www.rb @@ -4,6 +4,8 @@ class DeployWww < Deploy store :values, accessors: %i[], coder: JSON + DEPENDENCIES = %i[local] + before_destroy :remove_destination! def deploy(**) diff --git a/app/models/deploy_zip.rb b/app/models/deploy_zip.rb index f1c94083..2f9ac173 100644 --- a/app/models/deploy_zip.rb +++ b/app/models/deploy_zip.rb @@ -8,6 +8,8 @@ require 'zip' class DeployZip < Deploy store :values, accessors: %i[], coder: JSON + DEPENDENCIES = %i[local] + # Una vez que el sitio está generado, tomar todos los archivos y # y generar un zip accesible públicamente. # From db25750ab0580f92d93e5194e4ba7d14ca883ddf Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 18:54:38 -0300 Subject: [PATCH 284/453] feat: usar un grafo dirigido para ordenar las dependencias #10464 --- Gemfile | 1 + Gemfile.lock | 7 ++++++ app/models/site/deploy_dependencies.rb | 30 ++++++++++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 app/models/site/deploy_dependencies.rb diff --git a/Gemfile b/Gemfile index f3799638..489097a6 100644 --- a/Gemfile +++ b/Gemfile @@ -23,6 +23,7 @@ if ENV['RAILS_GROUPS']&.split(',')&.include? 'assets' end gem 'nokogiri' +gem 'rgl' # Turbolinks makes navigating your web application faster. Read more: # https://github.com/turbolinks/turbolinks diff --git a/Gemfile.lock b/Gemfile.lock index abaf45c9..5df84963 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -353,6 +353,7 @@ GEM mini_portile2 (~> 2.6.1) racc (~> 1.4) orm_adapter (0.5.0) + pairing_heap (3.0.0) parallel (1.21.0) parser (3.0.2.0) ast (~> 2.4.1) @@ -443,6 +444,10 @@ GEM actionpack (>= 5.0) railties (>= 5.0) rexml (3.2.5) + rgl (0.6.2) + pairing_heap (>= 0.3.0) + rexml (~> 3.2, >= 3.2.4) + stream (~> 0.5.3) rouge (3.26.1) rubocop (1.23.0) parallel (~> 1.10) @@ -510,6 +515,7 @@ GEM sprockets (>= 3.0.0) sqlite3 (1.4.2-x86_64-linux-musl) stackprof (0.2.17-x86_64-linux-musl) + stream (0.5.5) sucker_punch (3.0.1) concurrent-ruby (~> 1.0) sutty-archives (2.5.4) @@ -626,6 +632,7 @@ DEPENDENCIES rails_warden redis redis-rails + rgl rollups! rubocop-rails rubyzip diff --git a/app/models/site/deploy_dependencies.rb b/app/models/site/deploy_dependencies.rb new file mode 100644 index 00000000..33ed9e37 --- /dev/null +++ b/app/models/site/deploy_dependencies.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'rgl/adjacency' + +class Site + module DeployDependencies + extend ActiveSupport::Concern + + included do + # Genera un grafo dirigido de todos los métodos de publicación + # + # @return [RGL::DirectedAdjacencyGraph] + def deployment_graph + @deployment_graph ||= RGL::DirectedAdjacencyGraph.new.tap do |graph| + deploys.each do |deploy| + graph.add_vertex deploy + end + + deploys.each do |deploy| + deploy.class::DEPENDENCIES.each do |dependency| + deploys.where(type: "Deploy#{dependency.to_s.classify}").each do |deploy_dependency| + graph.add_edge deploy_dependency, deploy + end + end + end + end + end + end + end +end From 0ed01a61f7e85c8ac2580ccf4bb526edb905262c Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 21:37:58 -0300 Subject: [PATCH 285/453] feat: devolver una lista ordenada de metodos de publicacion --- app/models/site/deploy_dependencies.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/models/site/deploy_dependencies.rb b/app/models/site/deploy_dependencies.rb index 33ed9e37..05939320 100644 --- a/app/models/site/deploy_dependencies.rb +++ b/app/models/site/deploy_dependencies.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'rgl/adjacency' +require 'rgl/topsort' class Site module DeployDependencies @@ -25,6 +26,13 @@ class Site end end end + + # Devuelve una lista ordenada de todos los métodos de publicación + # + # @return [Array] + def deployment_list + @deployment_list ||= deployment_graph.topsort_iterator.to_a + end end end end From 607f19f6805512383358b80eea64197d5a20aafe Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 21:38:31 -0300 Subject: [PATCH 286/453] feat: activar ordenamiento de metodos de publicacion --- app/models/site.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/site.rb b/app/models/site.rb index 4b2a8eb9..f88e2e97 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -7,6 +7,7 @@ class Site < ApplicationRecord include Site::Forms include Site::FindAndReplace include Site::Api + include Site::DeployDependencies include Tienda # Cifrar la llave privada que cifra y decifra campos ocultos. Sutty From e5f96c435d8efec81f1a3cee4f5f657c3a32d7d3 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 13:42:47 -0300 Subject: [PATCH 287/453] feat: generar el sitio en orden #10464 --- app/jobs/deploy_job.rb | 86 +++++++++++-------------- app/models/deploy_alternative_domain.rb | 2 +- app/models/deploy_rsync.rb | 10 +-- app/models/deploy_www.rb | 2 +- app/models/deploy_zip.rb | 2 +- app/models/site/deploy_dependencies.rb | 2 +- 6 files changed, 48 insertions(+), 56 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index e018533c..f7d07349 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -30,28 +30,30 @@ class DeployJob < ApplicationJob return end + @deployed = {} @site.update status: 'building' - # Asegurarse que DeployLocal sea el primero! - @deployed = { - deploy_local: { - status: deploy_locally, - seconds: deploy_local.build_stats.last.seconds, - size: deploy_local.size, - urls: [deploy_local.url] + @site.deployment_list.each do |d| + begin + raise DeployException, 'Una dependencia falló' if failed_dependencies? d + + status = d.deploy + seconds = d.build_stats.last.try(:seconds) + rescue StandardError => e + status = false + seconds = 0 + + notify_exception e, d + end + + @deployed[d.type.underscore.to_sym] = { + status: status, + seconds: seconds || 0, + size: d.size, + urls: d.respond_to?(:urls) ? d.urls : [d.url].compact } - } - - # No es opcional - unless @deployed[:deploy_local][:status] - # Hacer fallar la tarea - raise DeployException, "#{@site.name}: Falló la compilación" end - - deploy_others rescue DeployTimedOutException => e notify_exception e - rescue DeployException => e - notify_exception e, deploy_local ensure @site&.update status: 'waiting' @@ -62,47 +64,37 @@ class DeployJob < ApplicationJob private + # Detecta si un método de publicación tiene dependencias fallidas + # + # @param :deploy [Deploy] + # @return [Boolean] + def failed_dependencies?(deploy) + failed_dependencies(deploy).present? + end + + # Obtiene las dependencias fallidas de un deploy + # + # @param :deploy [Deploy] + # @return [Array] + def failed_dependencies(deploy) + deploy.class::DEPENDENCIES & (@deployed.reject do |_, v| + v[:status] + end.keys) + end + # @param :exception [StandardError] # @param :deploy [Deploy] def notify_exception(exception, deploy = nil) data = { site: @site.id, deploy: deploy&.type, - log: deploy&.build_stats&.last&.log + log: deploy&.build_stats&.last&.log, + failed_dependencies: (failed_dependencies(deploy) if deploy) } ExceptionNotifier.notify_exception(exception, data: data) end - def deploy_local - @deploy_local ||= @site.deploys.find_by(type: 'DeployLocal') - end - - def deploy_locally - deploy_local.deploy(output: @output) - end - - def deploy_others - @site.deploys.where.not(type: 'DeployLocal').find_each do |d| - begin - status = d.deploy(output: @output) - seconds = d.build_stats.last.try(:seconds) - rescue StandardError => e - status = false - seconds = 0 - - notify_exception e, d - end - - @deployed[d.type.underscore.to_sym] = { - status: status, - seconds: seconds || 0, - size: d.size, - urls: d.respond_to?(:urls) ? d.urls : [d.url].compact - } - end - end - def notify_usuaries @site.roles.where(rol: 'usuarie', temporal: false).pluck(:usuarie_id).each do |usuarie| DeployMailer.with(usuarie: usuarie, site: @site.id) diff --git a/app/models/deploy_alternative_domain.rb b/app/models/deploy_alternative_domain.rb index 114f2aa5..9b1d63d7 100644 --- a/app/models/deploy_alternative_domain.rb +++ b/app/models/deploy_alternative_domain.rb @@ -4,7 +4,7 @@ class DeployAlternativeDomain < Deploy store :values, accessors: %i[hostname], coder: JSON - DEPENDENCIES = %i[local] + DEPENDENCIES = %i[deploy_local] # Generar un link simbólico del sitio principal al alternativo def deploy(**) diff --git a/app/models/deploy_rsync.rb b/app/models/deploy_rsync.rb index 9ced0bb1..dd7a492b 100644 --- a/app/models/deploy_rsync.rb +++ b/app/models/deploy_rsync.rb @@ -6,11 +6,11 @@ class DeployRsync < Deploy store :values, accessors: %i[destination host_keys], coder: JSON DEPENDENCIES = %i[ - alternative_domain - hidden_service - local - www - zip + deploy_alternative_domain + deploy_hidden_service + deploy_local + deploy_www + deploy_zip ] def deploy(output: false) diff --git a/app/models/deploy_www.rb b/app/models/deploy_www.rb index e6cfe407..d27f77cc 100644 --- a/app/models/deploy_www.rb +++ b/app/models/deploy_www.rb @@ -4,7 +4,7 @@ class DeployWww < Deploy store :values, accessors: %i[], coder: JSON - DEPENDENCIES = %i[local] + DEPENDENCIES = %i[deploy_local] before_destroy :remove_destination! diff --git a/app/models/deploy_zip.rb b/app/models/deploy_zip.rb index 2f9ac173..bba13686 100644 --- a/app/models/deploy_zip.rb +++ b/app/models/deploy_zip.rb @@ -8,7 +8,7 @@ require 'zip' class DeployZip < Deploy store :values, accessors: %i[], coder: JSON - DEPENDENCIES = %i[local] + DEPENDENCIES = %i[deploy_local] # Una vez que el sitio está generado, tomar todos los archivos y # y generar un zip accesible públicamente. diff --git a/app/models/site/deploy_dependencies.rb b/app/models/site/deploy_dependencies.rb index 05939320..a01f99e7 100644 --- a/app/models/site/deploy_dependencies.rb +++ b/app/models/site/deploy_dependencies.rb @@ -19,7 +19,7 @@ class Site deploys.each do |deploy| deploy.class::DEPENDENCIES.each do |dependency| - deploys.where(type: "Deploy#{dependency.to_s.classify}").each do |deploy_dependency| + deploys.where(type: dependency.to_s.classify).each do |deploy_dependency| graph.add_edge deploy_dependency, deploy end end From 3de6f14e63a7922e6670b45a87d4e079830e7244 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 13:47:34 -0300 Subject: [PATCH 288/453] =?UTF-8?q?fix:=20no=20pedir=20el=20tama=C3=B1o=20?= =?UTF-8?q?si=20fall=C3=B3=20la=20compilaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/deploy_job.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index f7d07349..fe344454 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -38,9 +38,11 @@ class DeployJob < ApplicationJob status = d.deploy seconds = d.build_stats.last.try(:seconds) + size = d.size rescue StandardError => e status = false seconds = 0 + size = 0 notify_exception e, d end @@ -48,7 +50,7 @@ class DeployJob < ApplicationJob @deployed[d.type.underscore.to_sym] = { status: status, seconds: seconds || 0, - size: d.size, + size: size, urls: d.respond_to?(:urls) ? d.urls : [d.url].compact } end From ea1ac09f9698be5cc615a4471a3d77b1bdbe9ca2 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 13:54:19 -0300 Subject: [PATCH 289/453] =?UTF-8?q?fix:=20mejorar=20gesti=C3=B3n=20de=20zi?= =?UTF-8?q?p?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_zip.rb | 53 +++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/app/models/deploy_zip.rb b/app/models/deploy_zip.rb index bba13686..5f72a728 100644 --- a/app/models/deploy_zip.rb +++ b/app/models/deploy_zip.rb @@ -14,24 +14,43 @@ class DeployZip < Deploy # y generar un zip accesible públicamente. # # rubocop:disable Metrics/MethodLength - def deploy(**) + def deploy(output: false) FileUtils.rm_f path - time_start - Dir.chdir(destination) do - Zip::File.open(path, Zip::File::CREATE) do |z| - Dir.glob('./**/**').each do |f| - File.directory?(f) ? z.mkdir(f) : z.add(f, f) + Zip::File.open(path, Zip::File::CREATE) do |zip| + Dir.glob(File.join(destination, '**', '**')).each do |file| + entry = Pathname.new(file).relative_path_from(destination).to_s + + if File.directory? file + log "Creando directorio #{entry}", output + + zip.mkdir(entry) + else + log "Comprimiendo #{entry}", output + zip.add(entry, file) end end end + time_stop - build_stats.create action: 'zip', - seconds: time_spent_in_seconds, - bytes: size + File.exist?(path).tap do |status| + build_stats.create action: 'zip', + seconds: time_spent_in_seconds, + bytes: size, + log: @log.join("\n"), + status: status + end + rescue Zip::Error => e + ExceptionNotifier.notify_exception(e, data: { site: site.name }) - File.exist? path + build_stats.create action: 'zip', + seconds: 0, + bytes: 0, + log: @log.join("\n"), + status: false + + false end # rubocop:enable Metrics/MethodLength @@ -43,8 +62,9 @@ class DeployZip < Deploy File.size path end + # @return [String] def destination - File.join(Rails.root, '_deploy', site.hostname) + Rails.root.join('_deploy', site.hostname).realpath.to_s end def file @@ -58,4 +78,15 @@ class DeployZip < Deploy def path File.join(destination, file) end + + private + + # @param :line [String] + # @param :output [Boolean] + def log(line, output) + @log ||= [] + @log << line + + puts line if output + end end From 199199117da9c70b666d851ebff29ea59f5c7ec0 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 16 Mar 2022 18:19:04 -0300 Subject: [PATCH 290/453] implementar la misma api en todos los deploys --- app/models/deploy.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 942336ad..7aedbb19 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -18,6 +18,10 @@ class Deploy < ApplicationRecord raise NotImplementedError end + def url + raise NotImplementedError + end + def limit raise NotImplementedError end From 875f1873d374d14b8fafbc5fb452afbf6ede9b3b Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Apr 2022 17:27:43 -0300 Subject: [PATCH 291/453] no fallar al cerrarse la salida --- app/models/deploy.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 7aedbb19..922c7560 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -74,8 +74,7 @@ class Deploy < ApplicationRecord puts line if output end rescue IOError => e - lines << e.message - puts e.message if output + ExceptionNotifier.notify(e, data: { site: site.name }) end r = t.value From e8746ca385805b288f291866145ad8c005d7f4f0 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Jun 2022 15:07:08 -0300 Subject: [PATCH 292/453] =?UTF-8?q?notificar=20correctamente=20la=20excepc?= =?UTF-8?q?i=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 922c7560..e02602f8 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -74,7 +74,7 @@ class Deploy < ApplicationRecord puts line if output end rescue IOError => e - ExceptionNotifier.notify(e, data: { site: site.name }) + ExceptionNotifier.notify_exception(e, data: { site: site.name }) end r = t.value From 92b97b508b9414384adc2df6e697e7d537ef8d18 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 29 Jun 2022 18:41:51 -0300 Subject: [PATCH 293/453] no generar issues para log --- app/models/deploy.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index e02602f8..7aedbb19 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -74,7 +74,8 @@ class Deploy < ApplicationRecord puts line if output end rescue IOError => e - ExceptionNotifier.notify_exception(e, data: { site: site.name }) + lines << e.message + puts e.message if output end r = t.value From 4ebd9881f558bf443ae58cb566952b0bd91f792e Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 14:31:39 -0300 Subject: [PATCH 294/453] =?UTF-8?q?fix:=20mejorar=20gesti=C3=B3n=20de=20sy?= =?UTF-8?q?mlink?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_www.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/models/deploy_www.rb b/app/models/deploy_www.rb index d27f77cc..bb25cc64 100644 --- a/app/models/deploy_www.rb +++ b/app/models/deploy_www.rb @@ -8,7 +8,9 @@ class DeployWww < Deploy before_destroy :remove_destination! - def deploy(**) + def deploy(output: false) + puts "Creando symlink #{site.hostname} => #{destination}" if output + File.symlink?(destination) || File.symlink(site.hostname, destination).zero? end @@ -30,7 +32,7 @@ class DeployWww < Deploy end def url - "https://www.#{site.hostname}/" + "https://#{fqdn}/" end private From 1e188bab0297ea1a21004239a59e7d118807ec69 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 14:37:52 -0300 Subject: [PATCH 295/453] =?UTF-8?q?fix:=20rsync=20no=20deber=C3=ADa=20depe?= =?UTF-8?q?nder=20de=20zip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aunque el zip no se genere igual queremos poder sincronizar el sitio --- app/models/deploy_rsync.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/deploy_rsync.rb b/app/models/deploy_rsync.rb index dd7a492b..04c33cb8 100644 --- a/app/models/deploy_rsync.rb +++ b/app/models/deploy_rsync.rb @@ -10,7 +10,6 @@ class DeployRsync < Deploy deploy_hidden_service deploy_local deploy_www - deploy_zip ] def deploy(output: false) From 431b7223b6b4c428a6edde72d74f5ab8d030abd7 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 14:38:45 -0300 Subject: [PATCH 296/453] feat: eliminar archivos al sincronizar --- app/models/deploy_rsync.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_rsync.rb b/app/models/deploy_rsync.rb index 04c33cb8..8702449a 100644 --- a/app/models/deploy_rsync.rb +++ b/app/models/deploy_rsync.rb @@ -91,7 +91,7 @@ class DeployRsync < Deploy # # @return [Boolean] def rsync(output: output) - run %(rsync -aviH --timeout=5 #{Shellwords.escape source}/ #{Shellwords.escape destination}/), output: output + run %(rsync -aviH --delete-after --timeout=5 #{Shellwords.escape source}/ #{Shellwords.escape destination}/) end # El origen es el destino de la compilación From f90ca9cd12d1e6019272393864c5ccbc7e203229 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 14:45:35 -0300 Subject: [PATCH 297/453] fix: output para rsync --- app/models/deploy_rsync.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_rsync.rb b/app/models/deploy_rsync.rb index 8702449a..51d7b2d2 100644 --- a/app/models/deploy_rsync.rb +++ b/app/models/deploy_rsync.rb @@ -91,7 +91,7 @@ class DeployRsync < Deploy # # @return [Boolean] def rsync(output: output) - run %(rsync -aviH --delete-after --timeout=5 #{Shellwords.escape source}/ #{Shellwords.escape destination}/) + run %(rsync -aviH --delete-after --timeout=5 #{Shellwords.escape source}/ #{Shellwords.escape destination}/), output: output end # El origen es el destino de la compilación From c6f48f55fcaa602c960c602b70d503bf6e7969d1 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 14:59:34 -0300 Subject: [PATCH 298/453] feat: mostrar una tabla con el resumen en la consola --- app/jobs/deploy_job.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index fe344454..e7ce7ed0 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -54,6 +54,16 @@ class DeployJob < ApplicationJob urls: d.respond_to?(:urls) ? d.urls : [d.url].compact } end + + return unless @output + + puts (Terminal::Table.new do |t| + t << (%w[type] + @deployed.values.first.keys) + t.add_separator + @deployed.each do |type, row| + t << ([type.to_s] + row.values) + end + end) rescue DeployTimedOutException => e notify_exception e ensure From 58dffd00c9111ef2686264ae8f1d867a6fb46456 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 15:10:32 -0300 Subject: [PATCH 299/453] =?UTF-8?q?fix:=20fallar=20el=20hidden=20service?= =?UTF-8?q?=20si=20no=20se=20gener=C3=B3=20el=20onion=20aun?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_hidden_service.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/models/deploy_hidden_service.rb b/app/models/deploy_hidden_service.rb index dc9549f5..79ff1bae 100644 --- a/app/models/deploy_hidden_service.rb +++ b/app/models/deploy_hidden_service.rb @@ -2,14 +2,10 @@ # Genera una versión onion class DeployHiddenService < DeployWww - def deploy(**) - return true if fqdn.blank? - - super - end - def fqdn - values[:onion] + values[:onion].tap do |onion| + raise ArgumentError, 'Aun no se generó la dirección .onion' if onion.blank? + end end def url From d4f4627dab695c73d58c63deb19def3cff5c2d5c Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 15:22:10 -0300 Subject: [PATCH 300/453] fix: capturar todas las posibles excepciones --- app/jobs/deploy_job.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index e7ce7ed0..67548e07 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -39,19 +39,21 @@ class DeployJob < ApplicationJob status = d.deploy seconds = d.build_stats.last.try(:seconds) size = d.size + urls = d.respond_to?(:urls) ? d.urls : [d.url].compact rescue StandardError => e status = false - seconds = 0 - size = 0 + seconds ||= 0 + size ||= 0 + urls ||= [] notify_exception e, d end @deployed[d.type.underscore.to_sym] = { status: status, - seconds: seconds || 0, + seconds: seconds, size: size, - urls: d.respond_to?(:urls) ? d.urls : [d.url].compact + urls: urls } end From 5974a40d027e1f7c6de11585591f7190918efa56 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 15:23:13 -0300 Subject: [PATCH 301/453] feat: hacer sonar una campana --- app/jobs/deploy_job.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 67548e07..3c9b2740 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -66,6 +66,8 @@ class DeployJob < ApplicationJob t << ([type.to_s] + row.values) end end) + + puts "\a" rescue DeployTimedOutException => e notify_exception e ensure From ba91ed56aa89546f494c14cd9dec8bcb1fe59ae9 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 15:50:05 -0300 Subject: [PATCH 302/453] feat: separar rsync de full rsync los segundos se usan para sincronizar todas las versiones de un sitio con otro servidor de sutty. los primeros solo sincronizan los archivos a otro servidor, no necesariamente bajo el mismo nombre. --- app/models/deploy_alternative_domain.rb | 6 ++- app/models/deploy_full_rsync.rb | 22 +++++++++++ app/models/deploy_rsync.rb | 9 +---- app/services/site_service.rb | 2 +- ...ename_deploy_rsync_to_deploy_full_rsync.rb | 37 +++++++++++++++++++ 5 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 app/models/deploy_full_rsync.rb create mode 100644 db/migrate/20230318183722_rename_deploy_rsync_to_deploy_full_rsync.rb diff --git a/app/models/deploy_alternative_domain.rb b/app/models/deploy_alternative_domain.rb index 9b1d63d7..75b69180 100644 --- a/app/models/deploy_alternative_domain.rb +++ b/app/models/deploy_alternative_domain.rb @@ -20,7 +20,11 @@ class DeployAlternativeDomain < Deploy end def destination - @destination ||= File.join(Rails.root, '_deploy', hostname.gsub(/\.\z/, '')) + @destination ||= File.join(Rails.root, '_deploy', fqdn) + end + + def fqdn + hostname.gsub(/\.\z/, '') end def url diff --git a/app/models/deploy_full_rsync.rb b/app/models/deploy_full_rsync.rb new file mode 100644 index 00000000..c0ff84c6 --- /dev/null +++ b/app/models/deploy_full_rsync.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class DeployFullRsync < DeployRsync + DEPENDENCIES = %i[ + deploy_alternative_domain + deploy_hidden_service + deploy_local + deploy_www + ] + + # Sincroniza las ubicaciones alternativas también + # + # @param :output [Boolean] + # @return [Boolean] + def rsync(output: false) + DEPENDENCIES.map(&:to_s).map(&:classify).map do |dependency| + site.deploys.where(type: dependency).find_each.map do |deploy| + run %(rsync -aviH --delete-after --timeout=5 #{Shellwords.escape deploy.destination} #{Shellwords.escape destination}), output: output + end + end.flatten.all? + end +end diff --git a/app/models/deploy_rsync.rb b/app/models/deploy_rsync.rb index 51d7b2d2..6a96a274 100644 --- a/app/models/deploy_rsync.rb +++ b/app/models/deploy_rsync.rb @@ -5,12 +5,7 @@ class DeployRsync < Deploy store :values, accessors: %i[destination host_keys], coder: JSON - DEPENDENCIES = %i[ - deploy_alternative_domain - deploy_hidden_service - deploy_local - deploy_www - ] + DEPENDENCIES = %i[deploy_local] def deploy(output: false) ssh? && rsync(output: output) @@ -90,7 +85,7 @@ class DeployRsync < Deploy # Sincroniza hacia el directorio remoto # # @return [Boolean] - def rsync(output: output) + def rsync(output: false) run %(rsync -aviH --delete-after --timeout=5 #{Shellwords.escape source}/ #{Shellwords.escape destination}/), output: output end diff --git a/app/services/site_service.rb b/app/services/site_service.rb index f5f415e7..0ecccba4 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -163,7 +163,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # Crea los deploys necesarios para sincronizar a otros nodos de Sutty def sync_nodes Rails.application.nodes.each do |node| - site.deploys.build(type: 'DeployRsync', destination: "sutty@#{node}:#{site.hostname}") + site.deploys.build(type: 'DeployFullRsync', destination: "sutty@#{node}:") end end end diff --git a/db/migrate/20230318183722_rename_deploy_rsync_to_deploy_full_rsync.rb b/db/migrate/20230318183722_rename_deploy_rsync_to_deploy_full_rsync.rb new file mode 100644 index 00000000..689dc559 --- /dev/null +++ b/db/migrate/20230318183722_rename_deploy_rsync_to_deploy_full_rsync.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +# Cambia todos los DeployRsync propios de Sutty a DeployFullRsync que se +# encarga de sincronizar todo. +class RenameDeployRsyncToDeployFullRsync < ActiveRecord::Migration[6.1] + def up + DeployRsync.all.find_each do |deploy| + dest = deploy.destination.split(':', 2).first + + next unless nodes.include? dest + + deploy.destination = "#{dest}:" + deploy.type = 'DeployFullRsync' + + deploy.save + end + end + + def down + DeployFullRsync.all.find_each do |deploy| + next unless nodes.include? deploy.destination.split(':', 2).first + + deploy.destination = "#{deploy.destination}#{deploy.site.hostname}" + deploy.type = 'DeployRsync' + + deploy.save + end + end + + private + + def nodes + @nodes ||= Rails.application.nodes.map do |node| + "sutty@#{node}" + end + end +end From 6f4e91d3180005372a5ee9f7bb3e0db140d6c63f Mon Sep 17 00:00:00 2001 From: f Date: Wed, 5 Oct 2022 18:44:23 -0300 Subject: [PATCH 303/453] soportar distributed press apiv0 #7839 --- app/models/deploy.rb | 15 ++++++++++ app/models/deploy_distributed_press.rb | 34 +++++++++++++++++++++++ app/models/deploy_local.rb | 38 ++++++++++++++++++-------- 3 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 app/models/deploy_distributed_press.rb diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 7aedbb19..52031d87 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -92,6 +92,13 @@ class Deploy < ApplicationRecord r&.success? end + # Variables de entorno + # + # @return [Hash] + def local_env + @local_env ||= {} + end + private # @param [String] @@ -99,4 +106,12 @@ class Deploy < ApplicationRecord def readable_cmd(cmd) cmd.split(' -', 2).first.tr(' ', '_') end + + def deploy_local + @deploy_local ||= site.deploys.find_by(type: 'DeployLocal') + end + + def non_local_deploys + @non_local_deploys ||= site.deploys.where.not(type: 'DeployLocal') + end end diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb new file mode 100644 index 00000000..51788865 --- /dev/null +++ b/app/models/deploy_distributed_press.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +# Soportar Distributed Press APIv0 +# +# No se realiza ninguna acción porque el deploy se hace desde el plugin +# local. +class DeployDistributedPress < Deploy + store :values, accessors: %i[api_key hostname], coder: JSON + + def deploy; end + + def limit; end + + def size + deploy_local.size + end + + # TODO: Devolver hyper:// y otras + def url + "ipfs://#{hostname}/" + end + + # Devuelve variables de entorno para enviarle a DeployLocal + # + # @return [Hash] + def local_env + { + 'DISTRIBUTED_PRESS_PROJECT_DOMAIN' => hostname, + 'DISTRIBUTED_PRESS_API_KEY' => api_key + } + end + + def destination; end +end diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 00e0985d..2d77df75 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -67,21 +67,24 @@ class DeployLocal < Deploy 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/bin', '/bin'] - { - '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 - } + # 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 + }) end def yarn_cache_dir @@ -125,4 +128,17 @@ class DeployLocal < Deploy def remove_destination! FileUtils.rm_rf destination end + + # Consigue todas las variables de entorno configuradas por otros + # deploys. + # + # @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 From b7daa8e0eb4a111e880329b1ed57ccf6dc88063a Mon Sep 17 00:00:00 2001 From: f Date: Fri, 18 Nov 2022 15:56:59 -0300 Subject: [PATCH 304/453] feat: poder modificar la url de distributed press --- app/models/deploy_distributed_press.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 51788865..a24ae62c 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -5,7 +5,7 @@ # No se realiza ninguna acción porque el deploy se hace desde el plugin # local. class DeployDistributedPress < Deploy - store :values, accessors: %i[api_key hostname], coder: JSON + store :values, accessors: %i[api_url api_key hostname], coder: JSON def deploy; end @@ -26,7 +26,8 @@ class DeployDistributedPress < Deploy def local_env { 'DISTRIBUTED_PRESS_PROJECT_DOMAIN' => hostname, - 'DISTRIBUTED_PRESS_API_KEY' => api_key + 'DISTRIBUTED_PRESS_API_KEY' => api_key, + 'DISTRIBUTED_PRESS_API_URL' => api_url } end From ecdbfeb56863589f0c2b16031a17ecaf3da5769c Mon Sep 17 00:00:00 2001 From: Maki Date: Tue, 17 Jan 2023 18:31:54 -0300 Subject: [PATCH 305/453] agrego toggler para distributed press --- app/models/site.rb | 2 +- .../deploys/_deploy_distributed_press.haml | 21 +++++++++++++++++++ config/locales/en.yml | 4 ++++ config/locales/es.yml | 4 ++++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 app/views/deploys/_deploy_distributed_press.haml diff --git a/app/models/site.rb b/app/models/site.rb index f88e2e97..af0b2c53 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -18,7 +18,7 @@ class Site < ApplicationRecord # 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].freeze + DEPLOYS = %i[local private www zip hidden_service distributed_press].freeze validates :name, uniqueness: true, hostname: { allow_root_label: true diff --git a/app/views/deploys/_deploy_distributed_press.haml b/app/views/deploys/_deploy_distributed_press.haml new file mode 100644 index 00000000..d7d54db0 --- /dev/null +++ b/app/views/deploys/_deploy_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', public_url: deploy.object.site.url), + tags: %w[p strong em a] + + +%hr/ diff --git a/config/locales/en.yml b/config/locales/en.yml index 567ab6bb..595d6145 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -272,6 +272,10 @@ en: Only accessible through [Tor Browser](https://www.torproject.org/download/) + deploy_distributed_press: + title: 'Publish on Distributed Press' + help: | + ipfs stats: index: title: Statistics diff --git a/config/locales/es.yml b/config/locales/es.yml index 0a829e4a..3be67130 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -277,6 +277,10 @@ es: Sólo será accesible a través del [Navegador Tor](https://www.torproject.org/es/download/). + deploy_distributed_press: + title: 'Alojar en la web distribuida' + help: | + Es para que esté en la web distribuida stats: index: title: Estadísticas From 84b2968cdbf85c66a5a9ab1a4534f75a20463e3a Mon Sep 17 00:00:00 2001 From: f Date: Fri, 20 Jan 2023 18:22:08 -0300 Subject: [PATCH 306/453] feat: almacenar y renovar tokens de distributed press --- Gemfile | 1 + Gemfile.lock | 40 ++++++++++- Procfile | 1 + .../renew_distributed_press_tokens_job.rb | 17 +++++ app/models/distributed_press_publisher.rb | 68 +++++++++++++++++++ ...5420_create_distributed_press_publisher.rb | 14 ++++ lib/tasks/distributed_press.rake | 10 +++ monit.conf | 5 ++ 8 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 app/jobs/renew_distributed_press_tokens_job.rb create mode 100644 app/models/distributed_press_publisher.rb create mode 100644 db/migrate/20230119165420_create_distributed_press_publisher.rb create mode 100644 lib/tasks/distributed_press.rake diff --git a/Gemfile b/Gemfile index 489097a6..fb1f4953 100644 --- a/Gemfile +++ b/Gemfile @@ -39,6 +39,7 @@ gem 'commonmarker' gem 'devise' gem 'devise-i18n' gem 'devise_invitable' +gem 'distributed-press-api-client', '~> 0.2.0' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'exception_notification' gem 'fast_blank' diff --git a/Gemfile.lock b/Gemfile.lock index 5df84963..9a754b83 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -115,6 +115,7 @@ GEM xpath (>= 2.0, < 4.0) chartkick (4.1.2) childprocess (4.1.0) + climate_control (1.2.0) coderay (1.1.3) colorator (1.1.0) commonmarker (0.21.2-x86_64-linux-musl) @@ -153,12 +154,45 @@ GEM devise_invitable (2.0.5) actionmailer (>= 5.0) devise (>= 4.6) + distributed-press-api-client (0.2.0) + addressable (~> 2.3, >= 2.3.0) + climate_control + dry-schema + httparty (~> 0.18) + json (~> 2.1, >= 2.1.0) + jwt (~> 2.6.0) dotenv (2.7.6) dotenv-rails (2.7.6) dotenv (= 2.7.6) railties (>= 3.2) down (5.2.4) addressable (~> 2.8) + dry-configurable (1.0.1) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-core (1.0.0) + concurrent-ruby (~> 1.0) + zeitwerk (~> 2.6) + dry-inflector (1.0.0) + dry-initializer (3.1.1) + dry-logic (1.5.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-schema (1.13.0) + concurrent-ruby (~> 1.0) + dry-configurable (~> 1.0, >= 1.0.1) + dry-core (~> 1.0, < 2) + dry-initializer (~> 3.0) + dry-logic (>= 1.5, < 2) + dry-types (>= 1.7, < 2) + zeitwerk (~> 2.6) + dry-types (1.7.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + dry-inflector (~> 1.0, < 2) + dry-logic (>= 1.4, < 2) + zeitwerk (~> 2.6) ed25519 (1.2.4-x86_64-linux-musl) em-websocket (0.5.3) eventmachine (>= 0.12.9) @@ -216,8 +250,8 @@ GEM thor hiredis (0.6.3-x86_64-linux-musl) http_parser.rb (0.8.0-x86_64-linux-musl) - httparty (0.18.1) - mime-types (~> 3.0) + httparty (0.21.0) + mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) i18n (1.8.11) concurrent-ruby (~> 1.0) @@ -292,6 +326,7 @@ GEM jekyll-write-and-commit-changes (0.2.1) jekyll (~> 4) rugged (~> 1) + jwt (2.6.0) kaminari (1.2.1) activesupport (>= 4.1.0) kaminari-actionview (= 1.2.1) @@ -584,6 +619,7 @@ DEPENDENCIES devise devise-i18n devise_invitable + distributed-press-api-client (~> 0.2.0) dotenv-rails down ed25519 diff --git a/Procfile b/Procfile index 45fe1df7..79daa90b 100644 --- a/Procfile +++ b/Procfile @@ -1,2 +1,3 @@ cleanup: bundle exec rake cleanup:everything stats: bundle exec rake stats:process_all +distributed_press_renew_tokens: bundle exec rake distributed_press:tokens:renew diff --git a/app/jobs/renew_distributed_press_tokens_job.rb b/app/jobs/renew_distributed_press_tokens_job.rb new file mode 100644 index 00000000..5664d9fa --- /dev/null +++ b/app/jobs/renew_distributed_press_tokens_job.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# Renueva los tokens de Distributed Press antes que se venzan, +# activando los callbacks que hacen que se refresque el token. +class RenewDistributedPressTokensJob < ApplicationJob + # Renueva todos los tokens a punto de vencer o informa el error sin + # detener la tarea si algo pasa. + def perform + DistributedPressPublisher.with_about_to_expire_tokens.find_each do |publisher| + publisher.touch + rescue DistributedPress::V1::Error => e + data = { instance: publisher.instance, expires_at: publisher.client.token.expires_at } + + ExceptionNotifier.notify_exception(e, data: data) + end + end +end diff --git a/app/models/distributed_press_publisher.rb b/app/models/distributed_press_publisher.rb new file mode 100644 index 00000000..610d698d --- /dev/null +++ b/app/models/distributed_press_publisher.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require 'distributed_press/v1' + +# Almacena el token de autenticación y la URL, por ahora solo vamos +# a tener uno, pero queda abierta la posibilidad de agregar más. +class DistributedPressPublisher < ApplicationRecord + # Cifrar la información del token en la base de datos + has_encrypted :token + + # La instancia es única + validates_uniqueness_of :instance + + # El token es necesario + validates_presence_of :token + + # Mantener la fecha de vencimiento actualizada + before_save :update_expires_at_from_token!, :update_token_from_client! + + # Devuelve todos los tokens que vencen en una hora + scope :with_about_to_expire_tokens, lambda { + where('expires_at > ? and expires_at < ?', Time.now, Time.now + 1.hour) + } + + # Al cambiar el token genera un cliente nuevo + # + # @return [String] + def token=(new_token) + @client = nil + super + end + + # Al cambiar la instancia genera un cliente nuevo + # + # @return [String] + def instance=(new_instance) + @client = nil + super + end + + # Instancia un cliente de Distributed Press a partir del token. Al + # cargar un token a punto de vencer se renueva automáticamente. + # + # @return [DistributedPress::V1::Client] + def client + @client ||= DistributedPress::V1::Client.new(url: instance, token: token) + end + + private + + # Actualiza o desactiva la fecha de vencimiento a partir de la + # información del token. + # + # @return [nil] + def update_expires_at_from_token! + self.expires_at = client.token.forever? ? nil : client.token.expires_at + nil + end + + # Actualiza el token a partir del cliente, que ya actualiza el token + # automáticamente. + # + # @return [nil] + def update_token_from_client! + self.token = client.token.to_s + nil + end +end diff --git a/db/migrate/20230119165420_create_distributed_press_publisher.rb b/db/migrate/20230119165420_create_distributed_press_publisher.rb new file mode 100644 index 00000000..8d8de37a --- /dev/null +++ b/db/migrate/20230119165420_create_distributed_press_publisher.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Crea la tabla de publishers de Distributed Press que contiene las +# instancias y tokens +class CreateDistributedPressPublisher < ActiveRecord::Migration[6.1] + def change + create_table :distributed_press_publishers do |t| + t.timestamps + t.string :instance, unique: true + t.text :token_ciphertext, null: false + t.datetime :expires_at, null: true + end + end +end diff --git a/lib/tasks/distributed_press.rake b/lib/tasks/distributed_press.rake new file mode 100644 index 00000000..8ba270ec --- /dev/null +++ b/lib/tasks/distributed_press.rake @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +namespace :distributed_press do + namespace :tokens do + desc 'Renew tokens' + task renew: :environment do + RenewDistributedPressTokensJob.perform_now + end + end +end diff --git a/monit.conf b/monit.conf index 39f45d6d..1d6bbae1 100644 --- a/monit.conf +++ b/monit.conf @@ -13,3 +13,8 @@ check program stats with path "/usr/bin/foreman run -f /srv/Procfile -d /srv stats" as uid "rails" gid "www-data" every "0 1 * * *" if status != 0 then alert + +check program distributed_press_tokens_renew + with path "/usr/bin/foreman run -f /srv/Procfile -d /srv distributed_press_tokens_renew" as uid "rails" gid "www-data" + every "0 3 * * *" + if status != 0 then alert From c44584596da1d3e23d8f986ec7d2b9a421bfb1b6 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 20 Jan 2023 20:34:27 -0300 Subject: [PATCH 307/453] feat: crear y publicar el sitio en distributed press v1 --- app/models/deploy_distributed_press.rb | 143 ++++++++++++++++++---- app/models/distributed_press_publisher.rb | 5 + 2 files changed, 125 insertions(+), 23 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index a24ae62c..09ba0364 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -1,13 +1,43 @@ # frozen_string_literal: true -# Soportar Distributed Press APIv0 -# -# No se realiza ninguna acción porque el deploy se hace desde el plugin -# local. -class DeployDistributedPress < Deploy - store :values, accessors: %i[api_url api_key hostname], coder: JSON +require 'distributed_press/v1/client/auth' +require 'distributed_press/v1/client/site' - def deploy; end +# Soportar Distributed Press APIv1 +# +# Usa tokens de publicación efímeros para todas las acciones. +# +# Al ser creado, genera el sitio en la instancia de Distributed Press +# configurada y almacena el ID. +# +# Al ser publicado, envía los archivos en un tarball y actualiza la +# información. +class DeployDistributedPress < Deploy + store :values, accessors: %i[hostname remote_site_id remote_info], coder: JSON + + before_create :create_remote_site! + + # Actualiza la información y luego envía los cambios + # + # @param :output [Bool] + # @return [Bool] + def deploy + time_start + + status = false + + site_client.tap do |c| + update remote_info: c.show(publishing_site).to_h + + status = c.publish(publishing_site, deploy_local.destination) + end + + time_stop + + create_stat! status + + status + end def limit; end @@ -15,21 +45,88 @@ class DeployDistributedPress < Deploy deploy_local.size end - # TODO: Devolver hyper:// y otras - def url - "ipfs://#{hostname}/" - end - - # Devuelve variables de entorno para enviarle a DeployLocal - # - # @return [Hash] - def local_env - { - 'DISTRIBUTED_PRESS_PROJECT_DOMAIN' => hostname, - 'DISTRIBUTED_PRESS_API_KEY' => api_key, - 'DISTRIBUTED_PRESS_API_URL' => api_url - } - end - def destination; end + + private + + # El cliente de la API + # + # TODO: cuando soportemos más, tiene que haber una relación entre + # DeployDistributedPress y DistributedPressPublisher. + # + # @return [DistributedPressPublisher] + def publisher + @publisher ||= DistributedPressPublisher.first + end + + # El cliente de autenticación se encarga de intercambiar un token por + # otro + # + # @return [DistributedPress::V1::Client::Auth] + def auth_client + DistributedPress::V1::Client::Auth.new(publisher.client) + end + + # Genera un token con permisos de publicación + # + # @return [DistributedPress::V1::Schemas::NewTokenPayload] + def publishing_token_payload + DistributedPress::V1::Schemas::NewTokenPayload.new.call(capabilities: %w[publisher]) + end + + # Genera un token efímero para publicar el sitio + # + # @return [DistributedPress::V1::Token] + def publishing_token + auth_client.exchange(publishing_token_payload) + end + + # Genera un cliente para publicar el sitio + # + # @return [DistributedPress::V1::Client] + def publishing_client + DistributedPress::V1::Client.new(url: publisher.instance, token: publishing_token) + end + + # El cliente para actualizar el sitio + # + # @return [DistributedPress::V1::Client::Site] + def site_client + DistributedPress::V1::Client::Site.new(publishing_client) + end + + # Genera el esquema de datos para poder publicar el sitio + # + # @return [DistributedPress::V1::Schemas::PublishingSite] + def publishing_site + DistributedPress::V1::Schemas::PublishingSite.new.call(id: remote_site_id) + end + + # Genera el esquema de datos para crear el sitio + # + # @return [DistributedPressPublisher::V1::Schemas::NewSite] + def create_site + DistributedPress::V1::Schemas::NewSite.new.call(domain: hostname, protocols: { http: true, ipfs: true, hyper: true }) + end + + # Crea el sitio en la instancia con el hostname especificado + # + # @return [nil] + def create_remote_site! + created_site = site_client.create(create_site) + + self.remote_site_id = created_site[:id] + self.remote_info = created_site.to_h + + nil + end + + # Registra lo que sucedió + # + # @param status [Bool] + # @return [nil] + def create_stat!(status) + build_stats.create action: publisher.to_s, seconds: time_spent_in_seconds, bytes: size, status: status + nil + end end diff --git a/app/models/distributed_press_publisher.rb b/app/models/distributed_press_publisher.rb index 610d698d..5358e738 100644 --- a/app/models/distributed_press_publisher.rb +++ b/app/models/distributed_press_publisher.rb @@ -46,6 +46,11 @@ class DistributedPressPublisher < ApplicationRecord @client ||= DistributedPress::V1::Client.new(url: instance, token: token) end + # @return [String] + def to_s + "Distributed Press <#{instance}>" + end + private # Actualiza o desactiva la fecha de vencimiento a partir de la From f190fb2dc82bc5f3a3e829ec1a10aa672f19f890 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 20 Jan 2023 20:35:39 -0300 Subject: [PATCH 308/453] fix: permitir modificar el token estos parches hacian que no se pueda modificar el token --- app/models/distributed_press_publisher.rb | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/app/models/distributed_press_publisher.rb b/app/models/distributed_press_publisher.rb index 5358e738..acfc4226 100644 --- a/app/models/distributed_press_publisher.rb +++ b/app/models/distributed_press_publisher.rb @@ -22,22 +22,6 @@ class DistributedPressPublisher < ApplicationRecord where('expires_at > ? and expires_at < ?', Time.now, Time.now + 1.hour) } - # Al cambiar el token genera un cliente nuevo - # - # @return [String] - def token=(new_token) - @client = nil - super - end - - # Al cambiar la instancia genera un cliente nuevo - # - # @return [String] - def instance=(new_instance) - @client = nil - super - end - # Instancia un cliente de Distributed Press a partir del token. Al # cargar un token a punto de vencer se renueva automáticamente. # From 4ebbd48fde8b8bf8203e163a48ddd9159f1a06df Mon Sep 17 00:00:00 2001 From: f Date: Mon, 23 Jan 2023 18:39:10 -0300 Subject: [PATCH 309/453] =?UTF-8?q?feat:=20no=20vamos=20a=20expedir=20toke?= =?UTF-8?q?ns=20ef=C3=ADmeros=20por=20ahora?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_distributed_press.rb | 31 +------------------------- 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 09ba0364..38cb59e3 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -59,40 +59,11 @@ class DeployDistributedPress < Deploy @publisher ||= DistributedPressPublisher.first end - # El cliente de autenticación se encarga de intercambiar un token por - # otro - # - # @return [DistributedPress::V1::Client::Auth] - def auth_client - DistributedPress::V1::Client::Auth.new(publisher.client) - end - - # Genera un token con permisos de publicación - # - # @return [DistributedPress::V1::Schemas::NewTokenPayload] - def publishing_token_payload - DistributedPress::V1::Schemas::NewTokenPayload.new.call(capabilities: %w[publisher]) - end - - # Genera un token efímero para publicar el sitio - # - # @return [DistributedPress::V1::Token] - def publishing_token - auth_client.exchange(publishing_token_payload) - end - - # Genera un cliente para publicar el sitio - # - # @return [DistributedPress::V1::Client] - def publishing_client - DistributedPress::V1::Client.new(url: publisher.instance, token: publishing_token) - end - # El cliente para actualizar el sitio # # @return [DistributedPress::V1::Client::Site] def site_client - DistributedPress::V1::Client::Site.new(publishing_client) + DistributedPress::V1::Client::Site.new(publisher.client) end # Genera el esquema de datos para poder publicar el sitio From c789813a46834ee675f12c1a05bb7fe987dbb817 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 26 Jan 2023 15:41:54 -0300 Subject: [PATCH 310/453] fix: actualizar api --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9a754b83..c739d86b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -154,7 +154,7 @@ GEM devise_invitable (2.0.5) actionmailer (>= 5.0) devise (>= 4.6) - distributed-press-api-client (0.2.0) + distributed-press-api-client (0.2.1) addressable (~> 2.3, >= 2.3.0) climate_control dry-schema From ea0539bb1f2db3145f3a05b9ab067a9530872d84 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 6 Feb 2023 16:09:51 -0300 Subject: [PATCH 311/453] feat: usar pnpm si existe relacionado con sutty/jekyll/sutty-base-jekyll-theme#53 --- Dockerfile | 2 ++ app/models/deploy_local.rb | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Dockerfile b/Dockerfile index 342c2750..71edc3d5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,6 +17,8 @@ RUN wget https://github.com/jgm/pandoc/releases/download/${PANDOC_VERSION}/pando COPY ./monit.conf /etc/monit.d/sutty.conf +RUN apk add npm && npm install -g pnpm && apk del npm + VOLUME "/srv" EXPOSE 3000 diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 2d77df75..0e4f6c1c 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -15,6 +15,7 @@ class DeployLocal < Deploy def deploy(output: false) return false unless mkdir return false unless yarn(output: output) + return false unless pnpm(output: output) return false unless bundle(output: output) jekyll_build(output: output) @@ -91,6 +92,10 @@ class DeployLocal < Deploy Rails.root.join('_yarn_cache').to_s end + def pnpm_cache_dir + Rails.root.join('_pnpm_cache').to_s + end + def yarn_lock File.join(site.path, 'yarn.lock') end @@ -103,6 +108,14 @@ class DeployLocal < Deploy run %(gem install bundler --no-document), output: output end + def pnpm_lock + File.join(site.path, 'pnpm-lock.yaml') + end + + def pnpm_lock? + File.exist? pnpm_lock + end + # Corre yarn dentro del repositorio def yarn(output: false) return true unless yarn_lock? @@ -114,6 +127,13 @@ class DeployLocal < Deploy run %(bundle install --no-cache --path="#{gems_dir}" --clean --without test development), output: output end + def pnpm + return true unless pnpm_lock? + + run %(pnpm config set store-dir "#{pnpm_cache_dir}") + run 'pnpm install --production' + end + def jekyll_build(output: false) run %(bundle exec jekyll build --trace --profile --destination "#{escaped_destination}"), output: output end From 0bb0698bd45cb2224d9d81e973f7b8cde1c19c90 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 6 Feb 2023 16:16:27 -0300 Subject: [PATCH 312/453] fix: pnpm se instala localmente --- app/models/deploy_local.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 0e4f6c1c..d6dc6c28 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -72,7 +72,7 @@ class DeployLocal < Deploy # @return [Hash] def env # XXX: This doesn't support Windows paths :B - paths = [File.dirname(`which bundle`), '/usr/bin', '/bin'] + paths = [File.dirname(`which bundle`), '/usr/local/bin', '/usr/bin', '/bin'] # Las variables de entorno extra no pueden superponerse al local. extra_env.merge({ From 436b55d3179beca19495a61b273ab2ed22a66474 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 7 Feb 2023 18:15:25 -0300 Subject: [PATCH 313/453] feat: textos para el panel --- config/locales/en.yml | 16 ++++++++++++++-- config/locales/es.yml | 16 ++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 595d6145..66372077 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -273,9 +273,21 @@ en: Only accessible through [Tor Browser](https://www.torproject.org/download/) deploy_distributed_press: - title: 'Publish on Distributed Press' + title: 'Publish to the distributed Web' help: | - ipfs + Make your site available through peer-to-peer protocols, + Inter-Planetary File System (IPFS), Hypercore, and via + BitTorrent, so your site is more resilient and can be available + offline, including in community mesh networks. + + **Important:** Only use this option if you would like your data + to be permanently available. If you decide to undo this + selection, a cleared version of the site will be shared in its + place. However, it is possible that nodes on the distributed + storage network may continue retaining copies of the data + indefinitely. + + [Learn more](#) stats: index: title: Statistics diff --git a/config/locales/es.yml b/config/locales/es.yml index 3be67130..79736137 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -278,9 +278,21 @@ es: Sólo será accesible a través del [Navegador Tor](https://www.torproject.org/es/download/). deploy_distributed_press: - title: 'Alojar en la web distribuida' + title: 'Publicar a la Web distribuida' help: | - Es para que esté en la web distribuida + Utiliza protocolos de pares, Inter-Planetary File System (IPFS), + Hypercore y torrents, para que tu sitio sea más resiliente y + esté disponible _offline_, inclusive en redes _mesh_ + comunitarias. + + **Importante:** Sólo usa esta opción si te parece correcto que + tu contenido esté disponible permanentemente. Cuando elijas + des-hacer esta acción, una versión "vacía" del sitio será + compartida en su lugar. Sin embargo, es posible que algunos + nodos en la red de almacenamiento distribuida puedan retener + copias de tu contenido indefinidamente. + + [Saber más](#) stats: index: title: Estadísticas From 4c6818762d72cca41c3cf22118abbd5e7e163dba Mon Sep 17 00:00:00 2001 From: f Date: Wed, 8 Feb 2023 09:38:36 -0300 Subject: [PATCH 314/453] fix: faltaban algunos require --- Gemfile | 2 +- Gemfile.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index fb1f4953..f92a37bf 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.0' +gem 'distributed-press-api-client', '~> 0.2.1' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'exception_notification' gem 'fast_blank' diff --git a/Gemfile.lock b/Gemfile.lock index c739d86b..244d5511 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -619,7 +619,7 @@ DEPENDENCIES devise devise-i18n devise_invitable - distributed-press-api-client (~> 0.2.0) + distributed-press-api-client (~> 0.2.1) dotenv-rails down ed25519 From 975bf39c2e233b6d78f0e968c43a34359c3aec7c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 8 Feb 2023 11:55:07 -0300 Subject: [PATCH 315/453] fix: no fallar si tarda mucho dp --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index f92a37bf..64869a4b 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.1' +gem 'distributed-press-api-client', '~> 0.2.2' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'exception_notification' gem 'fast_blank' diff --git a/Gemfile.lock b/Gemfile.lock index 244d5511..c214e144 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -154,7 +154,7 @@ GEM devise_invitable (2.0.5) actionmailer (>= 5.0) devise (>= 4.6) - distributed-press-api-client (0.2.1) + distributed-press-api-client (0.2.2) addressable (~> 2.3, >= 2.3.0) climate_control dry-schema @@ -619,7 +619,7 @@ DEPENDENCIES devise devise-i18n devise_invitable - distributed-press-api-client (~> 0.2.1) + distributed-press-api-client (~> 0.2.2) dotenv-rails down ed25519 From 4e1f14a528f44d98199b20c3969e8129e7e274ad Mon Sep 17 00:00:00 2001 From: f Date: Wed, 8 Feb 2023 17:08:02 -0300 Subject: [PATCH 316/453] =?UTF-8?q?feat:=20guardar=20un=20log=20y=20mostra?= =?UTF-8?q?rlo=20en=20output=20tambi=C3=A9n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_distributed_press.rb | 24 ++++++++++++++++++----- app/models/distributed_press_publisher.rb | 22 ++++++++++++++++++++- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 38cb59e3..d805e923 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -22,19 +22,32 @@ class DeployDistributedPress < Deploy # @param :output [Bool] # @return [Bool] def deploy + status = false + log = [] + time_start - status = false - site_client.tap do |c| + stdout = Thread.new(publisher.logger_out) do |io| + until io.eof? + line = io.gets + + puts line if output + log << line + end + end + update remote_info: c.show(publishing_site).to_h status = c.publish(publishing_site, deploy_local.destination) + + publisher.logger.close + stdout.join end time_stop - create_stat! status + create_stat! status, log.join status end @@ -95,9 +108,10 @@ class DeployDistributedPress < Deploy # Registra lo que sucedió # # @param status [Bool] + # @param log [String] # @return [nil] - def create_stat!(status) - build_stats.create action: publisher.to_s, seconds: time_spent_in_seconds, bytes: size, status: status + def create_stat!(status, log) + build_stats.create action: publisher.to_s,log: log, seconds: time_spent_in_seconds, bytes: size, status: status nil end end diff --git a/app/models/distributed_press_publisher.rb b/app/models/distributed_press_publisher.rb index acfc4226..089f63c6 100644 --- a/app/models/distributed_press_publisher.rb +++ b/app/models/distributed_press_publisher.rb @@ -8,6 +8,11 @@ class DistributedPressPublisher < ApplicationRecord # Cifrar la información del token en la base de datos has_encrypted :token + # La salida del log + # + # @return [IO] + attr_reader :logger_out + # La instancia es única validates_uniqueness_of :instance @@ -27,7 +32,7 @@ class DistributedPressPublisher < ApplicationRecord # # @return [DistributedPress::V1::Client] def client - @client ||= DistributedPress::V1::Client.new(url: instance, token: token) + @client ||= DistributedPress::V1::Client.new(url: instance, token: token, logger: logger) end # @return [String] @@ -35,8 +40,23 @@ class DistributedPressPublisher < ApplicationRecord "Distributed Press <#{instance}>" end + # @return [Logger] + def logger + @logger ||= + begin + @logger_out, @logger_in = IO.pipe + ::Logger.new @logger_in, formatter: formatter + end + end + private + def formatter + @formatter ||= lambda do |_, _, _, msg| + "#{msg}\n" + end + end + # Actualiza o desactiva la fecha de vencimiento a partir de la # información del token. # From c291fefa998110ecef8f53486169f504ab0f9bb2 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 8 Feb 2023 17:44:35 -0300 Subject: [PATCH 317/453] =?UTF-8?q?fix:=20link=20a=20saber=20m=C3=A1s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 66372077..531b492f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -287,7 +287,7 @@ en: storage network may continue retaining copies of the data indefinitely. - [Learn more](#) + [Learn more](https://ffdweb.org/building-distributed-press-a-publishing-tool-for-the-decentralized-web/) stats: index: title: Statistics diff --git a/config/locales/es.yml b/config/locales/es.yml index 79736137..84723b81 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -292,7 +292,7 @@ es: nodos en la red de almacenamiento distribuida puedan retener copias de tu contenido indefinidamente. - [Saber más](#) + [Saber más (en inglés)](https://ffdweb.org/building-distributed-press-a-publishing-tool-for-the-decentralized-web/) stats: index: title: Estadísticas From 56a3f2becb0f09909e220dd0c62794b95e8aa9d3 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 8 Feb 2023 18:49:37 -0300 Subject: [PATCH 318/453] feat: un deploy puede tener varias urls --- app/models/deploy_distributed_press.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index d805e923..d3474d50 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -60,6 +60,15 @@ class DeployDistributedPress < Deploy def destination; end + # Devuelve las URLs de todos los protocolos + def urls + remote_info[:links].values.map do |protocol| + [ protocol[:link], protocol[:gateway] ] + end.flatten.compact.select do |link| + link.include? '://' + end + end + private # El cliente de la API From 0b96fc44d6ba7eedf93d9dcb4ee607c777d7970e Mon Sep 17 00:00:00 2001 From: f Date: Wed, 8 Feb 2023 18:52:48 -0300 Subject: [PATCH 319/453] =?UTF-8?q?feat:=20texto=20para=20el=20correo=20de?= =?UTF-8?q?=20notificaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/en.yml | 4 ++++ config/locales/es.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index 531b492f..e040b781 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -126,6 +126,10 @@ en: title: Synchronize to backup server success: Success! error: Error + deploy_distributed_press: + title: Distributed Web + success: Success! + error: Error help: You can contact us by replying to this e-mail maintenance_mailer: notice: diff --git a/config/locales/es.yml b/config/locales/es.yml index 84723b81..f9fdcf29 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -126,6 +126,10 @@ es: title: Sincronizar al servidor alternativo success: ¡Éxito! error: Hubo un error + deploy_distributed_press: + title: Web distribuida + success: ¡Éxito! + error: Hubo un error help: Por cualquier duda, responde este correo para contactarte con nosotres. maintenance_mailer: notice: From 1b5adfb712bf89342993d3b315f236830bf76c6c Mon Sep 17 00:00:00 2001 From: f Date: Thu, 9 Feb 2023 20:01:22 -0300 Subject: [PATCH 320/453] feat: crear temporalmente los dominios en njalla el problema es que no podemos delegar `_dnslink.*.sutty.nl` hacia distributed press, con lo que es necesario crear un subdominio por cada sitio que lo active. --- Gemfile | 1 + Gemfile.lock | 4 ++++ app/models/deploy_distributed_press.rb | 18 ++++++++++++++++++ app/models/distributed_press_publisher.rb | 7 +++++++ 4 files changed, 30 insertions(+) diff --git a/Gemfile b/Gemfile index 64869a4b..9d1b6d67 100644 --- a/Gemfile +++ b/Gemfile @@ -40,6 +40,7 @@ gem 'devise' gem 'devise-i18n' gem 'devise_invitable' gem 'distributed-press-api-client', '~> 0.2.2' +gem 'njalla-api-client' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'exception_notification' gem 'fast_blank' diff --git a/Gemfile.lock b/Gemfile.lock index c214e144..c2c29531 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -387,6 +387,9 @@ GEM nokogiri (1.12.5-x86_64-linux-musl) mini_portile2 (~> 2.6.1) racc (~> 1.4) + njalla-api-client (0.1.0) + dry-schema + httparty (~> 0.18) orm_adapter (0.5.0) pairing_heap (3.0.0) parallel (1.21.0) @@ -654,6 +657,7 @@ DEPENDENCIES mini_magick mobility net-ssh + njalla-api-client nokogiri pg pg_search diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index d3474d50..6f2b2c78 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -111,6 +111,12 @@ class DeployDistributedPress < Deploy self.remote_site_id = created_site[:id] self.remote_info = created_site.to_h + # XXX: Esto depende de nuestro DNS actual, cuando lo migremos hay + # que eliminarlo. + 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']['ns'] = njalla.add_record(name: "_dnslink.#{site.name}", type: 'NS', content: "#{publisher.hostname}.").to_h + nil end @@ -123,4 +129,16 @@ class DeployDistributedPress < Deploy build_stats.create action: publisher.to_s,log: log, seconds: time_spent_in_seconds, bytes: size, status: status nil end + + # Actualizar registros en Njalla + # + # @return [Njalla::V1::Domain] + def njalla + @njalla ||= + begin + client = Njalla::V1::Client.new(token: ENV['NJALLA_TOKEN']) + + Njalla::V1::Domain.new(domain: Site.domain, client: client) + end + end end diff --git a/app/models/distributed_press_publisher.rb b/app/models/distributed_press_publisher.rb index 089f63c6..6139db93 100644 --- a/app/models/distributed_press_publisher.rb +++ b/app/models/distributed_press_publisher.rb @@ -40,6 +40,13 @@ class DistributedPressPublisher < ApplicationRecord "Distributed Press <#{instance}>" end + # Devuelve el hostname de la instancia + # + # @return [String] + def hostname + @hostname ||= URI.parse(instance).hostname + end + # @return [Logger] def logger @logger ||= From 4666e67b5da555380d340b7b263b0c735e65dd51 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 9 Feb 2023 20:08:56 -0300 Subject: [PATCH 321/453] fix: no crear subdominios para dominios personalizados esto es por retrocompatibilidad para sitios que no usan DeployAlternativeDomain --- app/models/deploy_distributed_press.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 6f2b2c78..1ae7a2f2 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -113,9 +113,11 @@ class DeployDistributedPress < Deploy # XXX: Esto depende de nuestro DNS actual, cuando lo migremos hay # que eliminarlo. - 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']['ns'] = njalla.add_record(name: "_dnslink.#{site.name}", type: 'NS', content: "#{publisher.hostname}.").to_h + unless site.name.end_with? '.' + 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']['ns'] = njalla.add_record(name: "_dnslink.#{site.name}", type: 'NS', content: "#{publisher.hostname}.").to_h + end nil end From 812fc0315cc2dfee183e87983894848b6ad03e57 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 9 Feb 2023 20:11:17 -0300 Subject: [PATCH 322/453] fix: requires --- app/models/deploy_distributed_press.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 1ae7a2f2..41054b99 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require 'distributed_press/v1/client/auth' require 'distributed_press/v1/client/site' +require 'njalla/v1' # Soportar Distributed Press APIv1 # From debf45b726cfc1c50cfe379bd73e5365ee9e8faa Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 17:33:52 -0300 Subject: [PATCH 323/453] fix: no fallar si hay errores remotos closes #10467 closes #10506 closes #10509 --- app/models/deploy_distributed_press.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 41054b99..09410201 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -118,7 +118,9 @@ class DeployDistributedPress < Deploy self.remote_info['njalla']['a'] = njalla.add_record(name: 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 end - + rescue DistributedPress::V1::Error, HTTParty::Error => e + ExceptionNotifier.notify_exception(e, data: { site: site.name }) + ensure nil end From 2b340a4488da30a82fbdfb51bcdf8796a37ebc3d Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 17:37:48 -0300 Subject: [PATCH 324/453] fix: crear el sitio remoto si no se pudo crear antes --- app/models/deploy_distributed_press.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 09410201..bd80dca4 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -27,6 +27,11 @@ class DeployDistributedPress < Deploy time_start + if remote_site_id.blank? || remote_info['njalla'].blank? + create_remote_site! + save + end + site_client.tap do |c| stdout = Thread.new(publisher.logger_out) do |io| until io.eof? From 29e1d09986022af9a9257941cfbe9b53ddf6b8e9 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 17:39:41 -0300 Subject: [PATCH 325/453] =?UTF-8?q?feat:=20separar=20la=20creaci=C3=B3n=20?= =?UTF-8?q?de=20DP=20de=20njalla?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_distributed_press.rb | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index bd80dca4..9afc6a5d 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -15,7 +15,7 @@ require 'njalla/v1' class DeployDistributedPress < Deploy store :values, accessors: %i[hostname remote_site_id remote_info], coder: JSON - before_create :create_remote_site! + before_create :create_remote_site!, :create_njalla_records! # Actualiza la información y luego envía los cambios # @@ -27,10 +27,9 @@ class DeployDistributedPress < Deploy time_start - if remote_site_id.blank? || remote_info['njalla'].blank? - create_remote_site! - save - end + create_remote_site! if remote_site_id.blank? + create_njalla_records! if remote_info['njalla'].blank? + save site_client.tap do |c| stdout = Thread.new(publisher.logger_out) do |io| @@ -115,7 +114,16 @@ class DeployDistributedPress < Deploy self.remote_site_id = created_site[:id] self.remote_info = created_site.to_h + rescue DistributedPress::V1::Error + ExceptionNotifier.notify_exception(e, data: { site: site.name }) + ensure + nil + end + # Crea los registros en Njalla + # + # @return [nil] + def create_njalla_records! # XXX: Esto depende de nuestro DNS actual, cuando lo migremos hay # que eliminarlo. unless site.name.end_with? '.' @@ -123,7 +131,7 @@ class DeployDistributedPress < Deploy self.remote_info['njalla']['a'] = njalla.add_record(name: 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 end - rescue DistributedPress::V1::Error, HTTParty::Error => e + rescue HTTParty::Error => e ExceptionNotifier.notify_exception(e, data: { site: site.name }) ensure nil From f0eab9a7b340ca32842373c3937e35794d509602 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 Mar 2023 17:44:13 -0300 Subject: [PATCH 326/453] fix: volver a fallar si al hacer deploy todavia estan caidos los servicios --- app/models/deploy_distributed_press.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 9afc6a5d..e8d8b095 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -31,6 +31,10 @@ class DeployDistributedPress < Deploy create_njalla_records! if remote_info['njalla'].blank? save + if remote_site_id.blank? || remote_info['njalla'].blank? + raise DeployJob::DeployException, '' + end + site_client.tap do |c| stdout = Thread.new(publisher.logger_out) do |io| until io.eof? @@ -133,6 +137,7 @@ class DeployDistributedPress < Deploy end rescue HTTParty::Error => e ExceptionNotifier.notify_exception(e, data: { site: site.name }) + self.remote_info['njalla'] = nil ensure nil end From 78c2fd0053f8491adf71889477e9a76ccb58dada Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 16:40:17 -0300 Subject: [PATCH 327/453] fix: agregar dependencias a distributed press --- app/models/deploy_distributed_press.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index e8d8b095..7f663a0b 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -17,6 +17,8 @@ class DeployDistributedPress < Deploy before_create :create_remote_site!, :create_njalla_records! + DEPENDENCIES = %i[deploy_local] + # Actualiza la información y luego envía los cambios # # @param :output [Bool] From 3dc10c46f80ae1a750a544351ecce69bc8dac9ce Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 16:41:32 -0300 Subject: [PATCH 328/453] =?UTF-8?q?feat:=20todav=C3=ADa=20no=20hay=20inter?= =?UTF-8?q?faz=20para=20estos=20deploys?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/deploys/_deploy_full_rsync.haml | 1 + app/views/deploys/_deploy_localized_domain.haml | 1 + 2 files changed, 2 insertions(+) create mode 100644 app/views/deploys/_deploy_full_rsync.haml create mode 100644 app/views/deploys/_deploy_localized_domain.haml diff --git a/app/views/deploys/_deploy_full_rsync.haml b/app/views/deploys/_deploy_full_rsync.haml new file mode 100644 index 00000000..0aab9802 --- /dev/null +++ b/app/views/deploys/_deploy_full_rsync.haml @@ -0,0 +1 @@ +-# nada diff --git a/app/views/deploys/_deploy_localized_domain.haml b/app/views/deploys/_deploy_localized_domain.haml new file mode 100644 index 00000000..0aab9802 --- /dev/null +++ b/app/views/deploys/_deploy_localized_domain.haml @@ -0,0 +1 @@ +-# nada From 8b10cfb524fd8874126070d1f307b423c881e09e Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 16:48:32 -0300 Subject: [PATCH 329/453] feat: darle url a deploy rsync --- app/models/deploy_rsync.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/models/deploy_rsync.rb b/app/models/deploy_rsync.rb index 6a96a274..ac9f19ec 100644 --- a/app/models/deploy_rsync.rb +++ b/app/models/deploy_rsync.rb @@ -3,7 +3,7 @@ # Sincroniza sitios a servidores remotos usando Rsync. El servidor # remoto tiene que tener rsync instalado. class DeployRsync < Deploy - store :values, accessors: %i[destination host_keys], coder: JSON + store :values, accessors: %i[hostname destination host_keys], coder: JSON DEPENDENCIES = %i[deploy_local] @@ -25,6 +25,11 @@ class DeployRsync < Deploy end end + # @return [String] + def url + "https://#{hostname}/" + end + private # Verificar la conexión SSH implementando Trust On First Use From 91750116a16ba0b64708f69435d7ae0216121881 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 16:52:36 -0300 Subject: [PATCH 330/453] feat: darle url a full rsync --- app/models/deploy_full_rsync.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/deploy_full_rsync.rb b/app/models/deploy_full_rsync.rb index c0ff84c6..8f1d306e 100644 --- a/app/models/deploy_full_rsync.rb +++ b/app/models/deploy_full_rsync.rb @@ -19,4 +19,8 @@ class DeployFullRsync < DeployRsync end end.flatten.all? end + + def url + "https://#{user_host.last}/" + end end From 75621fb5c553368f8c4013a8f4cd2dea856dc5ee Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 16:53:56 -0300 Subject: [PATCH 331/453] fix: traducir metodos de publicacion #10030 --- config/locales/en.yml | 4 ++++ config/locales/es.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index e040b781..8ecdd6d3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -126,6 +126,10 @@ en: title: Synchronize to backup server success: Success! error: Error + deploy_full_rsync: + title: Synchronize to another Sutty node + success: Success! + error: Error deploy_distributed_press: title: Distributed Web success: Success! diff --git a/config/locales/es.yml b/config/locales/es.yml index f9fdcf29..90c07e32 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -126,6 +126,10 @@ es: title: Sincronizar al servidor alternativo success: ¡Éxito! error: Hubo un error + deploy_full_rsync: + title: Sincronizar a otro nodo de Sutty + success: ¡Éxito! + error: Hubo un error deploy_distributed_press: title: Web distribuida success: ¡Éxito! From ad5724be297accc3dd439f0325b615dec9e119e1 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 17:00:29 -0300 Subject: [PATCH 332/453] fix: siempre hay segundos --- 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 3c9b2740..7cc49157 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -37,7 +37,7 @@ class DeployJob < ApplicationJob raise DeployException, 'Una dependencia falló' if failed_dependencies? d status = d.deploy - seconds = d.build_stats.last.try(:seconds) + seconds = d.build_stats.last.try(:seconds) || 0 size = d.size urls = d.respond_to?(:urls) ? d.urls : [d.url].compact rescue StandardError => e From d40c401a7204c277214ddb57cdd955c0eef8e2c7 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 17:01:38 -0300 Subject: [PATCH 333/453] fix: mostrar la salida --- 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 7cc49157..83b17459 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -36,7 +36,7 @@ class DeployJob < ApplicationJob begin raise DeployException, 'Una dependencia falló' if failed_dependencies? d - status = d.deploy + 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 From 54575b3bc3e33f3b7a8425a4c9792957e6c9aa71 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 17:02:38 -0300 Subject: [PATCH 334/453] =?UTF-8?q?fix:=20siempre=20avisar=20cuando=20term?= =?UTF-8?q?in=C3=B3=20el=20deploy=20en=20la=20consola?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/deploy_job.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 83b17459..890f993a 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -66,14 +66,14 @@ class DeployJob < ApplicationJob t << ([type.to_s] + row.values) end end) - - puts "\a" rescue DeployTimedOutException => e notify_exception e ensure @site&.update status: 'waiting' notify_usuaries if notify + + puts "\a" if @output end end # rubocop:enable Metrics/MethodLength From 8b51eb99a3e0224fe0aace172735ebf9025618cd Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 19:01:13 -0300 Subject: [PATCH 335/453] fix: private depende de local para instalar las dependencias --- app/models/deploy_private.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/deploy_private.rb b/app/models/deploy_private.rb index d3bfb50d..1fa42648 100644 --- a/app/models/deploy_private.rb +++ b/app/models/deploy_private.rb @@ -6,6 +6,8 @@ # XXX: La plantilla tiene que soportar esto con el plugin # jekyll-private-data class DeployPrivate < DeployLocal + DEPENDENCIES = %i[deploy_local] + # No es necesario volver a instalar dependencias def deploy(output: false) jekyll_build(output: output) From 94980051b65f8ee9bf44fc2890edf02d89c679bb Mon Sep 17 00:00:00 2001 From: f Date: Sat, 18 Mar 2023 19:33:25 -0300 Subject: [PATCH 336/453] fix: volver a hacer depender la sincronizacion del zip --- app/models/deploy_full_rsync.rb | 1 + app/models/deploy_rsync.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/deploy_full_rsync.rb b/app/models/deploy_full_rsync.rb index 8f1d306e..5bdfeeff 100644 --- a/app/models/deploy_full_rsync.rb +++ b/app/models/deploy_full_rsync.rb @@ -6,6 +6,7 @@ class DeployFullRsync < DeployRsync deploy_hidden_service deploy_local deploy_www + deploy_zip ] # Sincroniza las ubicaciones alternativas también diff --git a/app/models/deploy_rsync.rb b/app/models/deploy_rsync.rb index ac9f19ec..1dff2d99 100644 --- a/app/models/deploy_rsync.rb +++ b/app/models/deploy_rsync.rb @@ -5,7 +5,7 @@ class DeployRsync < Deploy store :values, accessors: %i[hostname destination host_keys], coder: JSON - DEPENDENCIES = %i[deploy_local] + DEPENDENCIES = %i[deploy_local deploy_zip] def deploy(output: false) ssh? && rsync(output: output) From 2a93218ef9d8f412b4116b8463e239cf2e413fb4 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 20 Mar 2023 12:20:50 -0300 Subject: [PATCH 337/453] fix: siempre devolver el destino closes ##10541 closes ##10540 closes ##10539 closes ##10538 closes ##10537 closes ##10536 closes ##10535 closes ##10534 closes ##10533 --- app/models/deploy_zip.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/deploy_zip.rb b/app/models/deploy_zip.rb index 5f72a728..85005470 100644 --- a/app/models/deploy_zip.rb +++ b/app/models/deploy_zip.rb @@ -65,6 +65,8 @@ class DeployZip < Deploy # @return [String] def destination Rails.root.join('_deploy', site.hostname).realpath.to_s + rescue Errno::ENOENT + Rails.root.join('_deploy', site.hostname).to_s end def file From f5274cf34224f3e5cef4ae72dbe1a4cb99d5f1a3 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 20 Mar 2023 12:26:11 -0300 Subject: [PATCH 338/453] =?UTF-8?q?fix:=20no=20hacer=20falla=20la=20config?= =?UTF-8?q?uraci=C3=B3n=20si=20todav=C3=ADa=20no=20se=20gener=C3=B3=20el?= =?UTF-8?q?=20onion=20#10542?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/deploys/_deploy_hidden_service.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/deploys/_deploy_hidden_service.haml b/app/views/deploys/_deploy_hidden_service.haml index d6388123..9ebda012 100644 --- a/app/views/deploys/_deploy_hidden_service.haml +++ b/app/views/deploys/_deploy_hidden_service.haml @@ -17,7 +17,8 @@ = sanitize_markdown t('.help', public_url: deploy.object.site.url), tags: %w[p strong em a] - - if deploy.object.fqdn + - begin = sanitize_markdown t('.help_2', url: deploy.object.url), tags: %w[p strong em a] + - rescue ArgumentError %hr/ From ecd8c80e028ab572ea82546e386bce1d17ceb8ba Mon Sep 17 00:00:00 2001 From: f Date: Mon, 20 Mar 2023 12:13:51 -0300 Subject: [PATCH 339/453] =?UTF-8?q?fix:=20capturar=20la=20excepci=C3=B3n?= =?UTF-8?q?=20#10546?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_distributed_press.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 7f663a0b..9414abc6 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -120,7 +120,7 @@ class DeployDistributedPress < Deploy self.remote_site_id = created_site[:id] self.remote_info = created_site.to_h - rescue DistributedPress::V1::Error + rescue DistributedPress::V1::Error => e ExceptionNotifier.notify_exception(e, data: { site: site.name }) ensure nil From 3abd87e8e6ad18744d5b62a3386bdaeef31e258d Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 17:11:51 -0300 Subject: [PATCH 340/453] feat: guardar la api key de njalla en las credenciales --- app/models/deploy_distributed_press.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 9414abc6..6a6b1d64 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -160,7 +160,7 @@ class DeployDistributedPress < Deploy def njalla @njalla ||= begin - client = Njalla::V1::Client.new(token: ENV['NJALLA_TOKEN']) + client = Njalla::V1::Client.new(token: Rails.application.credentials.njalla) Njalla::V1::Domain.new(domain: Site.domain, client: client) end From 1ff48bf4589e8da1b73323c646af9d95d01524b0 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 18:02:43 -0300 Subject: [PATCH 341/453] fix: no intentar notificar si no hay sitio closes #12753 --- app/jobs/deploy_job.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 890f993a..530b69dd 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -69,11 +69,13 @@ class DeployJob < ApplicationJob rescue DeployTimedOutException => e notify_exception e ensure - @site&.update status: 'waiting' + if @site.present? + @site.update status: 'waiting' - notify_usuaries if notify + notify_usuaries if notify - puts "\a" if @output + puts "\a" if @output + end end end # rubocop:enable Metrics/MethodLength From 21dd6ffd55d7870eac6d682efa183a43aaf2deaa Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 18:25:55 -0300 Subject: [PATCH 342/453] =?UTF-8?q?fix:=20no=20fallar=20njalla=20si=20fall?= =?UTF-8?q?=C3=B3=20dp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #12410 --- app/models/deploy_distributed_press.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 6a6b1d64..679da09d 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -133,6 +133,7 @@ class DeployDistributedPress < Deploy # XXX: Esto depende de nuestro DNS actual, cuando lo migremos hay # que eliminarlo. unless site.name.end_with? '.' + 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']['ns'] = njalla.add_record(name: "_dnslink.#{site.name}", type: 'NS', content: "#{publisher.hostname}.").to_h From c53391b21cd881f4de246cf18eacd345d314c215 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 24 Mar 2023 13:30:14 -0300 Subject: [PATCH 343/453] =?UTF-8?q?fix:=20mostrar=20los=20metodos=20fallid?= =?UTF-8?q?os=20en=20el=20correo=20de=20notificaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit no salían porque la tabla se genera en base a expandir las urls y cuando las urls venían vacías no se generaba la fila. --- app/jobs/deploy_job.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 530b69dd..aeb0f4b6 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -44,7 +44,8 @@ class DeployJob < ApplicationJob status = false seconds ||= 0 size ||= 0 - urls ||= [] + # XXX: Hace que se vea la tabla + urls ||= [nil] notify_exception e, d end From da192ef14cf43ac136d22a9601073f3bd6f23682 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 24 Mar 2023 14:23:34 -0300 Subject: [PATCH 344/453] =?UTF-8?q?fix:=20sincronizar=20aunque=20algunos?= =?UTF-8?q?=20destinos=20todav=C3=ADa=20no=20existan?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit por ejemplo la dependencia en hidden service hace que no se sincronice el sitio principal. --- app/models/deploy_full_rsync.rb | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/app/models/deploy_full_rsync.rb b/app/models/deploy_full_rsync.rb index 5bdfeeff..a3c1840d 100644 --- a/app/models/deploy_full_rsync.rb +++ b/app/models/deploy_full_rsync.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class DeployFullRsync < DeployRsync - DEPENDENCIES = %i[ + SOFT_DEPENDENCIES = %i[ deploy_alternative_domain deploy_hidden_service deploy_local @@ -9,16 +9,24 @@ class DeployFullRsync < DeployRsync deploy_zip ] - # Sincroniza las ubicaciones alternativas también + # Sincroniza las ubicaciones alternativas también, ignorando las que + # todavía no se generaron. Solo falla si ningún sitio fue + # sincronizado o si alguna sincronización falló. # # @param :output [Boolean] # @return [Boolean] def rsync(output: false) - DEPENDENCIES.map(&:to_s).map(&:classify).map do |dependency| - site.deploys.where(type: dependency).find_each.map do |deploy| - run %(rsync -aviH --delete-after --timeout=5 #{Shellwords.escape deploy.destination} #{Shellwords.escape destination}), output: output - end - end.flatten.all? + result = + SOFT_DEPENDENCIES.map(&:to_s).map(&:classify).map do |dependency| + site.deploys.where(type: dependency).find_each.map do |deploy| + next unless File.exist? deploy.destination + + run %(rsync -aviH --delete-after --timeout=5 #{Shellwords.escape deploy.destination} #{Shellwords.escape destination}), output: output + rescue StandardError + end + end.flatten.compact + + result.present? && result.all? end def url From 57542c92a7fcf1548e93e87b0162e19497507037 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 27 Mar 2023 14:08:19 -0300 Subject: [PATCH 345/453] fix: typo --- app/models/deploy_local.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index d6dc6c28..5b48df29 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -123,15 +123,15 @@ class DeployLocal < Deploy run 'yarn install --production', output: output end - def bundle(output: false) - run %(bundle install --no-cache --path="#{gems_dir}" --clean --without test development), output: output - end - - def pnpm + def pnpm(output: false) return true unless pnpm_lock? - run %(pnpm config set store-dir "#{pnpm_cache_dir}") - run 'pnpm install --production' + run %(pnpm config set store-dir "#{pnpm_cache_dir}"), output: output + run 'pnpm install --production', output: output + end + + def bundle(output: false) + run %(bundle install --no-cache --path="#{gems_dir}" --clean --without test development), output: output end def jekyll_build(output: false) From 42c7e93ac96cff1681047cb9bfc9f4c5f9353945 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 27 Mar 2023 14:09:16 -0300 Subject: [PATCH 346/453] =?UTF-8?q?fix:=20crear=20un=20registro=20para=20w?= =?UTF-8?q?ww=20tambi=C3=A9n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_distributed_press.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 679da09d..f26a72b5 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -136,6 +136,7 @@ class DeployDistributedPress < Deploy 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 end rescue HTTParty::Error => e From bef171d3ace090d2afcca7be5ea7be91930baf26 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 27 Mar 2023 14:10:35 -0300 Subject: [PATCH 347/453] fix: intentar crear siempre los registros en njalla --- app/models/deploy_distributed_press.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index f26a72b5..a2e2e20a 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -30,7 +30,7 @@ class DeployDistributedPress < Deploy time_start create_remote_site! if remote_site_id.blank? - create_njalla_records! if remote_info['njalla'].blank? + create_njalla_records! save if remote_site_id.blank? || remote_info['njalla'].blank? @@ -134,10 +134,10 @@ class DeployDistributedPress < Deploy # que eliminarlo. unless site.name.end_with? '.' 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 + 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 end rescue HTTParty::Error => e ExceptionNotifier.notify_exception(e, data: { site: site.name }) From c774337fd325b421fd53c3873b6c9ae0aaef6582 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 27 Mar 2023 14:43:01 -0300 Subject: [PATCH 348/453] feat: sincronizar dominios por idioma --- app/models/deploy_full_rsync.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/deploy_full_rsync.rb b/app/models/deploy_full_rsync.rb index a3c1840d..7bc0e788 100644 --- a/app/models/deploy_full_rsync.rb +++ b/app/models/deploy_full_rsync.rb @@ -3,6 +3,7 @@ class DeployFullRsync < DeployRsync SOFT_DEPENDENCIES = %i[ deploy_alternative_domain + deploy_localized_domain deploy_hidden_service deploy_local deploy_www From b2c6d40b0f0dbdb7ff26b763db8865b24c4294b0 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 27 Mar 2023 14:44:22 -0300 Subject: [PATCH 349/453] fix: deprecar DeployLocal#extra_env --- app/models/deploy.rb | 1 + app/models/deploy_local.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 52031d87..33dc9f2b 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -13,6 +13,7 @@ class Deploy < ApplicationRecord has_many :build_stats, dependent: :destroy DEPENDENCIES = [] + SOFT_DEPENDENCIES = [] def deploy(**) raise NotImplementedError diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 5b48df29..d1d93fe5 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -152,6 +152,7 @@ class DeployLocal < Deploy # 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 ||= From ad0d7aac10736cc375a069e5172454c38950699a Mon Sep 17 00:00:00 2001 From: f Date: Mon, 27 Mar 2023 14:52:37 -0300 Subject: [PATCH 350/453] feat: tener en cuenta las dependencias suaves al armar el grafo --- app/models/deploy.rb | 7 +++++++ app/models/deploy_full_rsync.rb | 4 +--- app/models/site/deploy_dependencies.rb | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 33dc9f2b..a92708c0 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -100,6 +100,13 @@ class Deploy < ApplicationRecord @local_env ||= {} end + # Trae todas las dependencias + # + # @return [Array] + def self.all_dependencies + self::DEPENDENCIES | self::SOFT_DEPENDENCIES + end + private # @param [String] diff --git a/app/models/deploy_full_rsync.rb b/app/models/deploy_full_rsync.rb index 7bc0e788..b8c48eab 100644 --- a/app/models/deploy_full_rsync.rb +++ b/app/models/deploy_full_rsync.rb @@ -5,9 +5,7 @@ class DeployFullRsync < DeployRsync deploy_alternative_domain deploy_localized_domain deploy_hidden_service - deploy_local deploy_www - deploy_zip ] # Sincroniza las ubicaciones alternativas también, ignorando las que @@ -18,7 +16,7 @@ class DeployFullRsync < DeployRsync # @return [Boolean] def rsync(output: false) result = - SOFT_DEPENDENCIES.map(&:to_s).map(&:classify).map do |dependency| + self.class.all_dependencies.map(&:to_s).map(&:classify).map do |dependency| site.deploys.where(type: dependency).find_each.map do |deploy| next unless File.exist? deploy.destination diff --git a/app/models/site/deploy_dependencies.rb b/app/models/site/deploy_dependencies.rb index a01f99e7..ed80a8af 100644 --- a/app/models/site/deploy_dependencies.rb +++ b/app/models/site/deploy_dependencies.rb @@ -18,7 +18,7 @@ class Site end deploys.each do |deploy| - deploy.class::DEPENDENCIES.each do |dependency| + deploy.class.all_dependencies.each do |dependency| deploys.where(type: dependency.to_s.classify).each do |deploy_dependency| graph.add_edge deploy_dependency, deploy end From bee16538301b11a5b8c0bc3645ebe59a09816968 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 30 Mar 2023 14:45:49 -0300 Subject: [PATCH 351/453] =?UTF-8?q?fix:=20evitar=20m=C3=A9todos=20de=20pub?= =?UTF-8?q?licaci=C3=B3n=20duplicados=20#12276?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/sites_controller.rb | 2 -- app/services/site_service.rb | 1 + app/views/sites/_form.haml | 3 --- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/controllers/sites_controller.rb b/app/controllers/sites_controller.rb index f0eff0dc..8d49fd8a 100644 --- a/app/controllers/sites_controller.rb +++ b/app/controllers/sites_controller.rb @@ -28,8 +28,6 @@ class SitesController < ApplicationController @site = Site.new authorize @site - - @site.deploys.build type: 'DeployLocal' end def create diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 0ecccba4..bb76c6ac 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -14,6 +14,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do self.site = Site.new params add_role temporal: false, rol: 'usuarie' + site.deploys.build type: 'DeployLocal' sync_nodes I18n.with_locale(usuarie.lang.to_sym || I18n.default_locale) do diff --git a/app/views/sites/_form.haml b/app/views/sites/_form.haml index 757b8b48..48e30e0c 100644 --- a/app/views/sites/_form.haml +++ b/app/views/sites/_form.haml @@ -158,9 +158,6 @@ = f.fields_for :deploys do |deploy| = render "deploys/#{deploy.object.type.underscore}", deploy: deploy, site: site - - else - = f.fields_for :deploys do |deploy| - = deploy.hidden_field :type .form-group = f.submit submit, class: 'btn btn-lg btn-block' From 95198832c4791134df2c8f11fd682219e4684780 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 30 Mar 2023 14:53:34 -0300 Subject: [PATCH 352/453] feat: configurar la fuente de gemas del skel desde el panel --- app/models/deploy_local.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index d1d93fe5..39cd9622 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -84,7 +84,8 @@ class DeployLocal < Deploy 'AIRBRAKE_PROJECT_KEY' => site.airbrake_api_key, 'JEKYLL_ENV' => Rails.env, 'LANG' => ENV['LANG'], - 'YARN_CACHE_FOLDER' => yarn_cache_dir + 'YARN_CACHE_FOLDER' => yarn_cache_dir, + 'GEMS_SOURCE' => ENV['GEMS_SOURCE'] }) end From b759398a4ee15beaa52972840dfc29ac27557a55 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 12:01:00 -0300 Subject: [PATCH 353/453] =?UTF-8?q?BREAKING=20CHANGE:=20usar=20la=20=C3=BA?= =?UTF-8?q?ltima=20instancia=20de=20Distributed=20Press?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_distributed_press.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index a2e2e20a..64c66cfc 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -88,7 +88,7 @@ class DeployDistributedPress < Deploy # # @return [DistributedPressPublisher] def publisher - @publisher ||= DistributedPressPublisher.first + @publisher ||= DistributedPressPublisher.last end # El cliente para actualizar el sitio From b818408f3e7f5b2c9a4a0983e26102af9e428073 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 12:14:14 -0300 Subject: [PATCH 354/453] feat: indicarle a distributed press que elimine el sitio sutty/distributed-press-api-client#10 --- Gemfile | 2 +- Gemfile.lock | 2 +- app/models/deploy_distributed_press.rb | 11 ++++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 9d1b6d67..2ff1c68c 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.2' +gem 'distributed-press-api-client', '~> 0.2.3' gem 'njalla-api-client' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'exception_notification' diff --git a/Gemfile.lock b/Gemfile.lock index c2c29531..30619795 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -622,7 +622,7 @@ DEPENDENCIES devise devise-i18n devise_invitable - distributed-press-api-client (~> 0.2.2) + distributed-press-api-client (~> 0.2.3) dotenv-rails down ed25519 diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 64c66cfc..ca10218a 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -16,6 +16,7 @@ class DeployDistributedPress < Deploy store :values, accessors: %i[hostname remote_site_id remote_info], coder: JSON before_create :create_remote_site!, :create_njalla_records! + before_destroy :delete_remote_site! DEPENDENCIES = %i[deploy_local] @@ -120,9 +121,9 @@ class DeployDistributedPress < Deploy self.remote_site_id = created_site[:id] self.remote_info = created_site.to_h + nil rescue DistributedPress::V1::Error => e ExceptionNotifier.notify_exception(e, data: { site: site.name }) - ensure nil end @@ -156,6 +157,14 @@ class DeployDistributedPress < Deploy nil end + def delete_remote_site! + site_client.delete(publishing_site) + nil + rescue DistributedPress::V1::Error => e + ExceptionNotifier.notify_exception(e, data: { site: site.name }) + nil + end + # Actualizar registros en Njalla # # @return [Njalla::V1::Domain] From f6a08f1073c834d2201b7cbcb5d067fa28140cd7 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 13:35:42 -0300 Subject: [PATCH 355/453] feat: eliminar registros en njalla --- Gemfile | 2 +- Gemfile.lock | 2 +- app/models/deploy_distributed_press.rb | 10 +++++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 2ff1c68c..b2472035 100644 --- a/Gemfile +++ b/Gemfile @@ -40,7 +40,7 @@ gem 'devise' gem 'devise-i18n' gem 'devise_invitable' gem 'distributed-press-api-client', '~> 0.2.3' -gem 'njalla-api-client' +gem 'njalla-api-client', '~> 0.2.0' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'exception_notification' gem 'fast_blank' diff --git a/Gemfile.lock b/Gemfile.lock index 30619795..67ce13e2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -387,7 +387,7 @@ GEM nokogiri (1.12.5-x86_64-linux-musl) mini_portile2 (~> 2.6.1) racc (~> 1.4) - njalla-api-client (0.1.0) + njalla-api-client (0.2.0) dry-schema httparty (~> 0.18) orm_adapter (0.5.0) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index ca10218a..9f78ba28 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -16,7 +16,7 @@ class DeployDistributedPress < Deploy store :values, accessors: %i[hostname remote_site_id remote_info], coder: JSON before_create :create_remote_site!, :create_njalla_records! - before_destroy :delete_remote_site! + before_destroy :delete_remote_site!, :delete_njalla_records! DEPENDENCIES = %i[deploy_local] @@ -165,6 +165,14 @@ class DeployDistributedPress < Deploy nil end + def delete_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] From d2e4fe09646e7b337868bf6711e2a3e5062a426b Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 13:58:10 -0300 Subject: [PATCH 356/453] fix: los registros en njalla no siempre son necesarios --- app/models/deploy_distributed_press.rb | 36 ++++++++++++++++++-------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 9f78ba28..b77dfe19 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -34,8 +34,12 @@ class DeployDistributedPress < Deploy create_njalla_records! save - if remote_site_id.blank? || remote_info['njalla'].blank? - raise DeployJob::DeployException, '' + if remote_site_id.blank? + raise DeployJob::DeployException, 'El sitio no se creó en Distributed Press' + 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| @@ -129,17 +133,20 @@ class DeployDistributedPress < Deploy # Crea los registros en Njalla # + # XXX: Esto depende de nuestro DNS actual, cuando lo migremos hay + # que eliminarlo. + # # @return [nil] def create_njalla_records! - # XXX: Esto depende de nuestro DNS actual, cuando lo migremos hay - # que eliminarlo. - unless site.name.end_with? '.' - 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 - end + 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['njalla'] = nil @@ -166,6 +173,8 @@ class DeployDistributedPress < Deploy 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? @@ -184,4 +193,9 @@ class DeployDistributedPress < Deploy 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 From 943bf7b5bdafd2080736d8cdf4774ee6632d5b91 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 14:38:04 -0300 Subject: [PATCH 357/453] fix: no pisar las datos de njalla con los de distributed press --- app/models/deploy_distributed_press.rb | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index b77dfe19..081ceeb5 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -38,7 +38,7 @@ class DeployDistributedPress < Deploy raise DeployJob::DeployException, 'El sitio no se creó en Distributed Press' end - if create_njalla_records? && remote_info['njalla'].blank? + if create_njalla_records? && remote_info[:njalla].blank? raise DeployJob::DeployException, 'No se pudieron crear los registros necesarios en Njalla' end @@ -52,7 +52,8 @@ class DeployDistributedPress < Deploy end end - update remote_info: c.show(publishing_site).to_h + self.remote_info[:distributed_press] = c.show(publishing_site).to_h + save status = c.publish(publishing_site, deploy_local.destination) @@ -77,7 +78,7 @@ class DeployDistributedPress < Deploy # Devuelve las URLs de todos los protocolos def urls - remote_info[:links].values.map do |protocol| + remote_info.dig(:distributed_press, :links).values.map do |protocol| [ protocol[:link], protocol[:gateway] ] end.flatten.compact.select do |link| link.include? '://' @@ -124,7 +125,8 @@ class DeployDistributedPress < Deploy created_site = site_client.create(create_site) self.remote_site_id = created_site[:id] - self.remote_info = created_site.to_h + self.remote_info ||= {} + self.remote_info[:distributed_press] = created_site.to_h nil rescue DistributedPress::V1::Error => e ExceptionNotifier.notify_exception(e, data: { site: site.name }) @@ -141,15 +143,15 @@ class DeployDistributedPress < Deploy 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 + 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['njalla'] = nil + self.remote_info.delete :njalla ensure nil end From a56acfd6da2aec2c3e5b913c91bae4de229be5ec Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 14:44:48 -0300 Subject: [PATCH 358/453] =?UTF-8?q?fix:=20obtener=20los=20links=20luego=20?= =?UTF-8?q?de=20la=20publicaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_distributed_press.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 081ceeb5..d8fd3f61 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -52,11 +52,13 @@ class DeployDistributedPress < Deploy end end - self.remote_info[:distributed_press] = c.show(publishing_site).to_h - save - status = c.publish(publishing_site, deploy_local.destination) + if status + self.remote_info[:distributed_press] = c.show(publishing_site).to_h + save + end + publisher.logger.close stdout.join end From ab126038afe4a9352c82002d58687bb5074142bf Mon Sep 17 00:00:00 2001 From: f Date: Fri, 31 Mar 2023 14:49:17 -0300 Subject: [PATCH 359/453] feat: devolver las urls con protocolos --- app/models/deploy_distributed_press.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index d8fd3f61..32a3049e 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -80,6 +80,12 @@ class DeployDistributedPress < Deploy # Devuelve las URLs de todos los protocolos def urls + protocol_urls + gateway_urls + end + + private + + def gateway_urls remote_info.dig(:distributed_press, :links).values.map do |protocol| [ protocol[:link], protocol[:gateway] ] end.flatten.compact.select do |link| @@ -87,7 +93,13 @@ class DeployDistributedPress < Deploy end end - private + def protocol_urls + remote_info.dig(:distributed_press, :protocols).select do |_, enabled| + enabled + end.map do |protocol, _| + "#{protocol}://#{site.hostname}" + end + end # El cliente de la API # From 87d51e88562faf61eb81a3a3833a2799813d86a0 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 17:31:35 -0300 Subject: [PATCH 360/453] feat: pedir consentimiento #12795 --- app/views/bootstrap/_custom_checkbox.haml | 6 ++++++ app/views/devise/registrations/new.haml | 18 +++++++++++++++++- config/locales/devise.views.en.yml | 19 +++++++++++++++++++ config/locales/devise.views.es.yml | 18 ++++++++++++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 app/views/bootstrap/_custom_checkbox.haml diff --git a/app/views/bootstrap/_custom_checkbox.haml b/app/views/bootstrap/_custom_checkbox.haml new file mode 100644 index 00000000..0c3ff3a6 --- /dev/null +++ b/app/views/bootstrap/_custom_checkbox.haml @@ -0,0 +1,6 @@ +- help_id = "#{id}_help" + +.custom-control.custom-checkbox + %input.custom-control-input{ id: id, type: 'checkbox', name: name, value: value, required: required } + %label.custom-control-label{ for: id, aria: { describedby: help_id } }= content + %small.form-text.text-muted{ id: help_id }= yield diff --git a/app/views/devise/registrations/new.haml b/app/views/devise/registrations/new.haml index e6bda964..75015831 100644 --- a/app/views/devise/registrations/new.haml +++ b/app/views/devise/registrations/new.haml @@ -4,7 +4,7 @@ = render 'devise/shared/error_messages', resource: resource .row.align-items-center.justify-content-center.full-height - .col-md-5.align-self-center + .col-md-6.align-self-center %h2= t('.sign_up') %p= t('.help') @@ -39,6 +39,22 @@ min: @minimum_password_length, aria: { describedby: 'minimum-password-length' }, placeholder: t("#{password}_confirmation") + + - if params[:consent] + .form-group + - %i[privacy_policy_accepted terms_of_service_accepted code_of_conduct_accepted available_for_feedback_accepted].each do |field| + - required = t(".#{field}.required", default: '').present? + - id = "usuarie_#{field}" + - name = "usuarie[#{field}]" + - content = t(".#{field}.label") + - href = t(".#{field}.href", default: '') + - help_content = t(".#{field}.help") + = render 'bootstrap/custom_checkbox', id: id, name: name, content: content, required: required, value: "1" do + - if href.present? + = link_to help_content, href, target: '_blank', rel: 'noopener' + - else + = help_content + .actions = f.submit t('.sign_up'), class: 'btn btn-lg btn-block' diff --git a/config/locales/devise.views.en.yml b/config/locales/devise.views.en.yml index 793f3a0a..3dd666b1 100644 --- a/config/locales/devise.views.en.yml +++ b/config/locales/devise.views.en.yml @@ -104,6 +104,25 @@ en: new: sign_up: Sign up help: We only ask for an e-mail address and a password. The password is safely stored, no one else besides you knows it! You'll also receive an e-mail to confirm your account. + privacy_policy_accepted: + label: "I know about Sutty's privacy policy" + help: "Read privacy policy" + href: "https://sutty.nl/en/privacy-policy/" + required: true + terms_of_service_accepted: + label: "My sites won't promote hate towards minorities" + help: "Read terms of service" + href: "https://sutty.nl/en/terms-of-service/" + required: true + code_of_conduct_accepted: + label: "My sites are inclusive spaces" + help: "Read codes for sharing" + href: "https://sutty.nl/en/code-of-conduct/" + required: true + available_for_feedback_accepted: + label: "I'm available to provide feedback" + help: "We may contact you occasionaly" + required: false signed_up: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account." signed_up_but_inactive: You have signed up successfully. However, we could not sign you in because your account is not yet activated. signed_up_but_locked: You have signed up successfully. However, we could not sign you in because your account is locked. diff --git a/config/locales/devise.views.es.yml b/config/locales/devise.views.es.yml index b745fc5f..c955373f 100644 --- a/config/locales/devise.views.es.yml +++ b/config/locales/devise.views.es.yml @@ -104,6 +104,24 @@ es: new: sign_up: Registrarme help: Para registrarte solo pedimos una dirección de correo y una contraseña. La contraseña se almacena de forma segura, ¡nadie más que vos la sabe! Recibirás un correo de confirmación de cuenta. + privacy_policy_accepted: + label: "Conozco la política de privacidad de Sutty" + help: "Leer política de privacidad" + href: "https://sutty.nl/politica-de-privacidad/" + required: "true" + terms_of_service_accepted: + label: "Mis sitios no promueven el odio a minorías" + help: "Leer términos de servicio" + href: "https://sutty.nl/terminos-de-servicio/" + required: "true" + code_of_conduct_accepted: + label: "Mis sitios son espacios inclusivos" + help: "Leer códigos para compartir" + href: "https://sutty.nl/codigo-de-convivencia/" + required: "true" + available_for_feedback_accepted: + label: "Estoy disponible para ofrecer retroalimentación" + help: "Te contactaremos ocasionalmente" signed_up: "Hemos enviado un mensaje con un enlace de confirmación a tu correo electrónico. Por favor, abrí el enlace para terminar de activar tu cuenta." signed_up_but_inactive: Tu cuenta ha sido creada correctamente. Sin embargo, no hemos podido iniciar la sesión porque tu cuenta aún no está activada. signed_up_but_locked: Tu cuenta ha sido creada correctamente. Sin embargo, no hemos podido iniciar la sesión porque que tu cuenta está bloqueada. From 8f0f260a4f9bd345eddcf66ab079da054d9d2a00 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 18:18:53 -0300 Subject: [PATCH 361/453] feat: almacenar los campos --- app/models/concerns/usuarie/consent.rb | 26 +++++++++++++++++++ app/models/usuarie.rb | 2 ++ app/views/devise/registrations/new.haml | 2 +- .../20230328200129_add_consent_to_usuaries.rb | 12 +++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 app/models/concerns/usuarie/consent.rb create mode 100644 db/migrate/20230328200129_add_consent_to_usuaries.rb diff --git a/app/models/concerns/usuarie/consent.rb b/app/models/concerns/usuarie/consent.rb new file mode 100644 index 00000000..14e67fbc --- /dev/null +++ b/app/models/concerns/usuarie/consent.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class Usuarie + # Gestiona los campos de consentimiento + module Consent + extend ActiveSupport::Concern + + included do + CONSENT_FIELDS = %i[privacy_policy_accepted terms_of_service_accepted code_of_conduct_accepted available_for_feedback_accepted] + + CONSENT_FIELDS.each do |field| + attribute field, :boolean + end + + before_save :update_consent_fields! + + private + + def update_consent_fields! + CONSENT_FIELDS.each do |field| + send(:"#{field}_at=", Time.now) if send(field).present? + end + end + end + end +end diff --git a/app/models/usuarie.rb b/app/models/usuarie.rb index 7b83ee75..9b9fd4e6 100644 --- a/app/models/usuarie.rb +++ b/app/models/usuarie.rb @@ -2,6 +2,8 @@ # Usuarie de la plataforma class Usuarie < ApplicationRecord + include Usuarie::Consent + devise :invitable, :database_authenticatable, :recoverable, :rememberable, :validatable, :confirmable, :lockable, :registerable diff --git a/app/views/devise/registrations/new.haml b/app/views/devise/registrations/new.haml index 75015831..04e81917 100644 --- a/app/views/devise/registrations/new.haml +++ b/app/views/devise/registrations/new.haml @@ -42,7 +42,7 @@ - if params[:consent] .form-group - - %i[privacy_policy_accepted terms_of_service_accepted code_of_conduct_accepted available_for_feedback_accepted].each do |field| + - Usuarie::CONSENT_FIELDS.each do |field| - required = t(".#{field}.required", default: '').present? - id = "usuarie_#{field}" - name = "usuarie[#{field}]" diff --git a/db/migrate/20230328200129_add_consent_to_usuaries.rb b/db/migrate/20230328200129_add_consent_to_usuaries.rb new file mode 100644 index 00000000..1e85864d --- /dev/null +++ b/db/migrate/20230328200129_add_consent_to_usuaries.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +# Agrega consentimientos a les usuaries. No usamos un loop de +# Usuarie::CONSENT_FIELDS porque quizás agreguemos campos luego. +class AddConsentToUsuaries < ActiveRecord::Migration[6.1] + def change + add_column :usuaries, :privacy_policy_accepted_at, :datetime + add_column :usuaries, :terms_of_service_accepted_at, :datetime + add_column :usuaries, :code_of_conduct_accepted_at, :datetime + add_column :usuaries, :available_for_feedback_accepted_at, :datetime + end +end From 492d238f579b02f6a0ffdbe78e71f4b00c554ae8 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 18:33:19 -0300 Subject: [PATCH 362/453] =?UTF-8?q?BREAKING=20CHANGE:=20eliminar=20campo?= =?UTF-8?q?=20que=20no=20se=20us=C3=B3=20nunca?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...remove_acepta_politicas_de_privacidad_from_usuaries.rb | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 db/migrate/20230328213242_remove_acepta_politicas_de_privacidad_from_usuaries.rb diff --git a/db/migrate/20230328213242_remove_acepta_politicas_de_privacidad_from_usuaries.rb b/db/migrate/20230328213242_remove_acepta_politicas_de_privacidad_from_usuaries.rb new file mode 100644 index 00000000..7ca562bf --- /dev/null +++ b/db/migrate/20230328213242_remove_acepta_politicas_de_privacidad_from_usuaries.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# Elimina un campo que nunca se usó +class RemoveAceptaPoliticasDePrivacidadFromUsuaries < ActiveRecord::Migration[6.1] + def change + remove_column :usuaries, :acepta_politicas_de_privacidad, :boolean, default: false + end +end From c66d1f0f087310085da99f8e76fb7389d783cbdc Mon Sep 17 00:00:00 2001 From: f Date: Wed, 29 Mar 2023 15:50:45 -0300 Subject: [PATCH 363/453] =?UTF-8?q?fix:=20mejorar=20la=20redacci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/devise.views.en.yml | 6 +++--- config/locales/devise.views.es.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config/locales/devise.views.en.yml b/config/locales/devise.views.en.yml index 3dd666b1..a524cf7c 100644 --- a/config/locales/devise.views.en.yml +++ b/config/locales/devise.views.en.yml @@ -105,17 +105,17 @@ en: sign_up: Sign up help: We only ask for an e-mail address and a password. The password is safely stored, no one else besides you knows it! You'll also receive an e-mail to confirm your account. privacy_policy_accepted: - label: "I know about Sutty's privacy policy" + label: "I understand and accept the privacy policy" help: "Read privacy policy" href: "https://sutty.nl/en/privacy-policy/" required: true terms_of_service_accepted: - label: "My sites won't promote hate towards minorities" + label: "My sites won't promote hate speech" help: "Read terms of service" href: "https://sutty.nl/en/terms-of-service/" required: true code_of_conduct_accepted: - label: "My sites are inclusive spaces" + label: "I want a more inclusive Internet" help: "Read codes for sharing" href: "https://sutty.nl/en/code-of-conduct/" required: true diff --git a/config/locales/devise.views.es.yml b/config/locales/devise.views.es.yml index c955373f..4575c628 100644 --- a/config/locales/devise.views.es.yml +++ b/config/locales/devise.views.es.yml @@ -105,17 +105,17 @@ es: sign_up: Registrarme help: Para registrarte solo pedimos una dirección de correo y una contraseña. La contraseña se almacena de forma segura, ¡nadie más que vos la sabe! Recibirás un correo de confirmación de cuenta. privacy_policy_accepted: - label: "Conozco la política de privacidad de Sutty" + label: "Comprendo y acepto la política de privacidad" help: "Leer política de privacidad" href: "https://sutty.nl/politica-de-privacidad/" required: "true" terms_of_service_accepted: - label: "Mis sitios no promueven el odio a minorías" + label: "Mis sitios no promueven el discurso de odio" help: "Leer términos de servicio" href: "https://sutty.nl/terminos-de-servicio/" required: "true" code_of_conduct_accepted: - label: "Mis sitios son espacios inclusivos" + label: "Quiero una Internet más inclusiva" help: "Leer códigos para compartir" href: "https://sutty.nl/codigo-de-convivencia/" required: "true" From 414fd7348d7b5b3d9801ee7f8068c193b12d3df8 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 29 Mar 2023 15:51:10 -0300 Subject: [PATCH 364/453] fix: activarlo --- app/views/devise/registrations/new.haml | 27 ++++++++++++------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/app/views/devise/registrations/new.haml b/app/views/devise/registrations/new.haml index 04e81917..26fc8e18 100644 --- a/app/views/devise/registrations/new.haml +++ b/app/views/devise/registrations/new.haml @@ -40,20 +40,19 @@ aria: { describedby: 'minimum-password-length' }, placeholder: t("#{password}_confirmation") - - if params[:consent] - .form-group - - Usuarie::CONSENT_FIELDS.each do |field| - - required = t(".#{field}.required", default: '').present? - - id = "usuarie_#{field}" - - name = "usuarie[#{field}]" - - content = t(".#{field}.label") - - href = t(".#{field}.href", default: '') - - help_content = t(".#{field}.help") - = render 'bootstrap/custom_checkbox', id: id, name: name, content: content, required: required, value: "1" do - - if href.present? - = link_to help_content, href, target: '_blank', rel: 'noopener' - - else - = help_content + .form-group + - Usuarie::CONSENT_FIELDS.each do |field| + - required = t(".#{field}.required", default: '').present? + - id = "usuarie_#{field}" + - name = "usuarie[#{field}]" + - content = t(".#{field}.label") + - href = t(".#{field}.href", default: '') + - help_content = t(".#{field}.help") + = render 'bootstrap/custom_checkbox', id: id, name: name, content: content, required: required, value: "1" do + - if href.present? + = link_to help_content, href, target: '_blank', rel: 'noopener' + - else + = help_content .actions = f.submit t('.sign_up'), From 252652c94b2bff95ad0304422b73d7c19a6efa13 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 15 Mar 2022 16:03:16 -0300 Subject: [PATCH 365/453] poder ver la salida si lo ejecutamos desde la terminal --- app/models/deploy_local.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index 71c23b36..bfde29f7 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -117,14 +117,6 @@ class DeployLocal < Deploy run %(gem install bundler --no-document), output: output end - def pnpm_lock - File.join(site.path, 'pnpm-lock.yaml') - end - - def pnpm_lock? - File.exist? pnpm_lock - end - # Corre yarn dentro del repositorio def yarn(output: false) return true unless yarn_lock? From 718463f0eae2255e7cb33cddb72a6ab4364b6405 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 15:28:46 -0300 Subject: [PATCH 366/453] feat: generar direcciones tor a demanda #12773 --- app/lib/hidden_service_client.rb | 13 +++++++++++++ app/models/deploy_hidden_service.rb | 21 ++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 app/lib/hidden_service_client.rb diff --git a/app/lib/hidden_service_client.rb b/app/lib/hidden_service_client.rb new file mode 100644 index 00000000..5715a869 --- /dev/null +++ b/app/lib/hidden_service_client.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'httparty' + +class HiddenServiceClient + include HTTParty + + base_uri ENV.fetch('HIDDEN_SERVICE', 'http://tor:3000') + + def create(name) + self.class.get("/#{name}").body + end +end diff --git a/app/models/deploy_hidden_service.rb b/app/models/deploy_hidden_service.rb index 79ff1bae..aa495baf 100644 --- a/app/models/deploy_hidden_service.rb +++ b/app/models/deploy_hidden_service.rb @@ -2,8 +2,12 @@ # Genera una versión onion class DeployHiddenService < DeployWww + store :values, accessors: %i[onion], coder: JSON + + before_create :create_hidden_service! + def fqdn - values[:onion].tap do |onion| + onion.tap do |onion| raise ArgumentError, 'Aun no se generó la dirección .onion' if onion.blank? end end @@ -11,4 +15,19 @@ class DeployHiddenService < DeployWww def url "http://#{fqdn}" end + + private + + def create_hidden_service! + onion_address = HiddenServiceClient.new.create(site.name) + + if ONION_RE =~ onion_address + self.onion = onion_address + + usuarie = GitAuthor.new email: "tor@#{Site.domain}", name: 'Tor' + params = { onion: onion_address, deploy: self } + + SiteService.new(site: site, usuarie: usuarie, params: params).add_onion + end + end end From 487765f7d88356b4d33242ca95c4487bb6488917 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 16:21:29 -0300 Subject: [PATCH 367/453] =?UTF-8?q?feat:=20validar=20y=20agregar=20la=20di?= =?UTF-8?q?recci=C3=B3n=20a=20la=20configuraci=C3=B3n=20del=20sitio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_hidden_service.rb | 2 ++ app/services/site_service.rb | 7 ++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/models/deploy_hidden_service.rb b/app/models/deploy_hidden_service.rb index aa495baf..3356e815 100644 --- a/app/models/deploy_hidden_service.rb +++ b/app/models/deploy_hidden_service.rb @@ -6,6 +6,8 @@ class DeployHiddenService < DeployWww before_create :create_hidden_service! + ONION_RE = /\A[a-z0-9]{56}\.onion\z/.freeze + def fqdn onion.tap do |onion| raise ArgumentError, 'Aun no se generó la dirección .onion' if onion.blank? diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 848f3cfc..8ecc3f56 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -64,14 +64,11 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # Agregar una dirección oculta de Tor al DeployHiddenService y a la # configuración del Site. def add_onion - onion = params[:onion].strip - deploy = DeployHiddenService.find_by(site: site) + onion = params[:onion] + deploy = params[:deploy] return false unless !onion.blank? && deploy - deploy.values[:onion] = onion - deploy.save - site.config['onion-location'] = onion site.config.write From 0002ed53a940f69da649ab3ebe4c1b90bb8c3433 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 16:22:02 -0300 Subject: [PATCH 368/453] BREAKING CHANGE: deprecar la api de onion --- app/controllers/api/v1/sites_controller.rb | 25 ---------------------- config/routes.rb | 2 -- 2 files changed, 27 deletions(-) diff --git a/app/controllers/api/v1/sites_controller.rb b/app/controllers/api/v1/sites_controller.rb index 10a92907..ae64cf74 100644 --- a/app/controllers/api/v1/sites_controller.rb +++ b/app/controllers/api/v1/sites_controller.rb @@ -12,31 +12,6 @@ module Api render json: sites_names + alternative_names + api_names + www_names end - # Sitios con hidden service de Tor - # - # @return [Array] lista de nombres de sitios sin onion aun - def hidden_services - render json: DeployHiddenService.where(values: nil).includes(:site).pluck(:name) - end - - # Tor va a enviar el onion junto con el nombre del sitio y tenemos - # que guardarlo en su deploy_hidden_service. - # - # @params [String] name - # @params [String] onion - def add_onion - site = Site.find_by(name: params[:name]) - - if site - usuarie = GitAuthor.new email: "tor@#{Site.domain}", name: 'Tor' - service = SiteService.new site: site, usuarie: usuarie, - params: params - service.add_onion - end - - head :ok - end - private def canonicalize(name) diff --git a/config/routes.rb b/config/routes.rb index a132135a..511ca654 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -11,8 +11,6 @@ Rails.application.routes.draw do namespace :v1 do resources :csp_reports, only: %i[create] - get :'sites/hidden_services', to: 'sites#hidden_services' - post :'sites/add_onion', to: 'sites#add_onion' resources :sites, only: %i[index], constraints: { site_id: /[a-z0-9\-.]+/, id: /[a-z0-9\-.]+/ } do get :'invitades/cookie', to: 'invitades#cookie' post :'posts/:layout', to: 'posts#create', as: :posts From 2f745886f5240a7b4f524155f505900ef54932fd Mon Sep 17 00:00:00 2001 From: f Date: Tue, 28 Mar 2023 16:22:58 -0300 Subject: [PATCH 369/453] =?UTF-8?q?fix:=20reintentar=20si=20fall=C3=B3=20l?= =?UTF-8?q?a=20generaci=C3=B3n=20en=20el=20pasado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_hidden_service.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/deploy_hidden_service.rb b/app/models/deploy_hidden_service.rb index 3356e815..25c0c217 100644 --- a/app/models/deploy_hidden_service.rb +++ b/app/models/deploy_hidden_service.rb @@ -9,6 +9,8 @@ class DeployHiddenService < DeployWww ONION_RE = /\A[a-z0-9]{56}\.onion\z/.freeze def fqdn + create_hidden_service! if onion.blank? + onion.tap do |onion| raise ArgumentError, 'Aun no se generó la dirección .onion' if onion.blank? end From 20e8e83ab601168214974333e69a2968970a9c2a Mon Sep 17 00:00:00 2001 From: f Date: Mon, 10 Apr 2023 13:28:01 -0300 Subject: [PATCH 370/453] feat: notificar errores de que --- config/initializers/que.rb | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 config/initializers/que.rb diff --git a/config/initializers/que.rb b/config/initializers/que.rb new file mode 100644 index 00000000..d7abfeb5 --- /dev/null +++ b/config/initializers/que.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +ActiveJob::Serializers.add_serializers ActiveJob::Serializers::ExceptionSerializer + +# Notificar los errores +Que.error_notifier = proc do |error, job| + ExceptionNotifier.notify_exception(error, data: (job || {})) +end From a58936b22ecc2e70903c89d8dcf8e501d00f6642 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 10 Apr 2023 13:28:32 -0300 Subject: [PATCH 371/453] =?UTF-8?q?fix:=20retomar=20la=20publicaci=C3=B3n?= =?UTF-8?q?=20de=20cambios=20#12958?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/deploy_job.rb | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index aeb0f4b6..a7f59afb 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -4,9 +4,23 @@ class DeployJob < ApplicationJob class DeployException < StandardError; end class DeployTimedOutException < DeployException; end + class DeployAlreadyRunningException < DeployException; end discard_on ActiveRecord::RecordNotFound + # Lanzar lo antes posible + self.priority = 10 + # Intentar dentro de un minuto + self.retry_interval = 60 + + def handle_error(error) + case error + when DeployAlreadyRunningException then retry_in 1.minute + when DeployTimedOutException then expire + else super + end + end + # rubocop:disable Metrics/MethodLength def perform(site, notify: true, time: Time.now, output: false) @output = output @@ -20,14 +34,14 @@ class DeployJob < ApplicationJob # Como el trabajo actual se aplaza al siguiente, arrastrar la # hora original para poder ir haciendo timeouts. if @site.building? + notify = false + if 10.minutes.ago >= time - notify = false raise DeployTimedOutException, "#{@site.name} la tarea estuvo más de 10 minutos esperando, volviendo al estado original" + else + raise DeployAlreadyRunningException end - - DeployJob.perform_in(60, site, notify: notify, time: time, output: output) - return end @deployed = {} @@ -67,8 +81,6 @@ class DeployJob < ApplicationJob t << ([type.to_s] + row.values) end end) - rescue DeployTimedOutException => e - notify_exception e ensure if @site.present? @site.update status: 'waiting' From 79f3958a0697d16c59b079da86db601bdf1abf90 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 10 Apr 2023 16:53:35 -0300 Subject: [PATCH 372/453] fix: que no expone este metodo en activejob --- app/jobs/deploy_job.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index a7f59afb..a5cda360 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -10,8 +10,6 @@ class DeployJob < ApplicationJob # Lanzar lo antes posible self.priority = 10 - # Intentar dentro de un minuto - self.retry_interval = 60 def handle_error(error) case error From 6c1dcf5ded419363690844a3a66eda6047c9d0bd Mon Sep 17 00:00:00 2001 From: f Date: Mon, 10 Apr 2023 17:31:26 -0300 Subject: [PATCH 373/453] =?UTF-8?q?fix:=20evitar=20errores=20de=20serializ?= =?UTF-8?q?aci=C3=B3n=20#12998?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `que` falla silenciosamente cuando no puede serializar errores para enviar, que es la mayor parte de las veces. enviar los errores sincronicamente excepto los de airbrake --- app/lib/exception_notifier/gitlab_notifier.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/lib/exception_notifier/gitlab_notifier.rb b/app/lib/exception_notifier/gitlab_notifier.rb index 18bfc6d4..8152bb62 100644 --- a/app/lib/exception_notifier/gitlab_notifier.rb +++ b/app/lib/exception_notifier/gitlab_notifier.rb @@ -11,7 +11,12 @@ module ExceptionNotifier # @param [Exception] # @param [Hash] def call(exception, **options) - GitlabNotifierJob.perform_async(exception, **options) + case exception + when BacktraceJob::BacktraceException + GitlabNotifierJob.perform_later(exception, **options) + else + GitlabNotifierJob.perform_now(exception, **options) + end end end end From 482a63720793508f03e8756d575ea2d39021ff5d Mon Sep 17 00:00:00 2001 From: f Date: Mon, 10 Apr 2023 17:33:07 -0300 Subject: [PATCH 374/453] fix: perform_later --- app/controllers/api/v1/contact_controller.rb | 2 +- app/jobs/maintenance_job.rb | 2 +- app/models/log_entry.rb | 2 +- app/services/site_service.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/v1/contact_controller.rb b/app/controllers/api/v1/contact_controller.rb index deacf4a7..d949dc30 100644 --- a/app/controllers/api/v1/contact_controller.rb +++ b/app/controllers/api/v1/contact_controller.rb @@ -18,7 +18,7 @@ module Api # Si todo salió bien, enviar los correos y redirigir al sitio. # El sitio nos dice a dónde tenemos que ir. - ContactJob.perform_async site.id, + ContactJob.perform_later site.id, params[:form], contact_params.to_h.symbolize_keys, params[:redirect] diff --git a/app/jobs/maintenance_job.rb b/app/jobs/maintenance_job.rb index 4c411d0e..c7a962f9 100644 --- a/app/jobs/maintenance_job.rb +++ b/app/jobs/maintenance_job.rb @@ -10,7 +10,7 @@ # bundle exec rails c # m = Maintenance.create message_en: 'reason', message_es: 'razón', # estimated_from: Time.now, estimated_to: Time.now + 1.hour -# MaintenanceJob.perform_async(maintenance_id: m.id) +# MaintenanceJob.perform_later(maintenance_id: m.id) # # Lo mismo para salir de mantenimiento, agregando el atributo # are_we_back: true al crear el Maintenance. diff --git a/app/models/log_entry.rb b/app/models/log_entry.rb index 1824da55..9685e0d0 100644 --- a/app/models/log_entry.rb +++ b/app/models/log_entry.rb @@ -11,7 +11,7 @@ class LogEntry < ApplicationRecord def resend return if sent - ContactJob.perform_async site_id, params[:form], params + ContactJob.perform_later site_id, params[:form], params end def params diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 8ecc3f56..5d28bf91 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -5,7 +5,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do def deploy site.enqueue! - DeployJob.perform_async site.id + DeployJob.perform_later site.id end # Crea un sitio, agrega un rol nuevo y guarda los cambios a la From 1e79e2687295d8c12ded65c0ccb2e82f8f144346 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 10 Apr 2023 17:38:16 -0300 Subject: [PATCH 375/453] fix: ignorar las excepciones de publicaciones duplicadas --- config/environments/production.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/environments/production.rb b/config/environments/production.rb index d121bdbd..653ca8aa 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -147,7 +147,7 @@ Rails.application.configure do } config.action_mailer.default_options = { from: ENV.fetch('DEFAULT_FROM', "noreply@sutty.nl") } - config.middleware.use ExceptionNotification::Rack, gitlab: {} + config.middleware.use ExceptionNotification::Rack, gitlab: {}, ignore_exceptions: (['DeployJob::DeployAlreadyRunningException'] + ExceptionNotifier.ignored_exceptions) Rails.application.routes.default_url_options[:host] = "panel.#{ENV.fetch('SUTTY', 'sutty.nl')}" Rails.application.routes.default_url_options[:protocol] = 'https' From 2086ade1a7d4acf92b5a7df4e3fca9867c25aa3d Mon Sep 17 00:00:00 2001 From: f Date: Mon, 10 Apr 2023 18:21:33 -0300 Subject: [PATCH 376/453] =?UTF-8?q?fix:=20solo=20permitir=20subir=20im?= =?UTF-8?q?=C3=A1genes=20para=20web=20#13009?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/posts/attributes/_image.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/posts/attributes/_image.haml b/app/views/posts/attributes/_image.haml index f4d9bb3d..84fe56fd 100644 --- a/app/views/posts/attributes/_image.haml +++ b/app/views/posts/attributes/_image.haml @@ -22,7 +22,7 @@ = file_field(*field_name_for(base, attribute, :path), **field_options(attribute, metadata, required: (metadata.required && !metadata.path?)), class: "custom-file-input #{invalid(post, attribute)}", - accept: 'image/*', data: { preview: "#{attribute}-preview" }) + accept: ActiveStorage.web_image_content_types.join(','), data: { preview: "#{attribute}-preview" }) = label_tag "#{base}_#{attribute}_path", post_label_t(attribute, :path, post: post), class: 'custom-file-label' = render 'posts/attribute_feedback', From 563060e1132df7db6aa3e13a8323ed9144a80e8a Mon Sep 17 00:00:00 2001 From: f Date: Mon, 10 Apr 2023 18:22:49 -0300 Subject: [PATCH 377/453] feat: permitir subir webp --- config/application.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/config/application.rb b/config/application.rb index 97ab244c..941caa68 100644 --- a/config/application.rb +++ b/config/application.rb @@ -37,6 +37,7 @@ module Sutty .rescue_responses['Pundit::NotAuthorizedError'] = :forbidden config.active_storage.variant_processor = :vips + config.active_storage.web_image_content_types << 'image/webp' config.to_prepare do # Load application's model / class decorators From f2b6e2929c317c9ad1b216e7d3ae59fdba85c747 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 10 Apr 2023 18:29:13 -0300 Subject: [PATCH 378/453] =?UTF-8?q?fix:=20informar=20cu=C3=A1les=20formato?= =?UTF-8?q?s=20aceptamos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 3ddf681d..50392ed3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -50,7 +50,7 @@ en: cant_be_empty: 'This field cannot be empty' image: site_invalid: 'The image cannot be stored if the site configuration is not valid' - not_an_image: 'Not an image' + not_an_image: 'Not a web image. Accepted formats: PNG, JPEG, GIF, WEBP' path_required: 'Missing image for upload' no_file_for_description: "Description with no associated image" attachment_missing: "I couldn't save the image :(" diff --git a/config/locales/es.yml b/config/locales/es.yml index 01f1085c..340e3d6a 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -50,7 +50,7 @@ es: cant_be_empty: 'El campo no puede estar vacío' image: site_invalid: 'La imagen no se puede almacenar si la configuración del sitio no es válida' - not_an_image: 'No es una imagen' + not_an_image: 'No es una imagen en formato web. Formatos aceptados: PNG, JPEG, GIF, WEBP' path_required: 'Se necesita una imagen' no_file_for_description: 'Se envió una descripción sin imagen asociada' attachment_missing: 'no pude guardar el archivo :(' From 83a16c7b94b8336f10a547bc26e6200c75c5c728 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 10 Apr 2023 18:36:03 -0300 Subject: [PATCH 379/453] fix: typo #13008 --- config/locales/en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 3ddf681d..7befed7a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -516,7 +516,7 @@ en: file: destroy: Remove file image: - label: Imagen + label: Image destroy: Remove image belongs_to: empty: "(Empty)" From d84975a61ada0783edc82ed5f948b0355e1a6c5a Mon Sep 17 00:00:00 2001 From: f Date: Tue, 11 Apr 2023 10:42:07 -0300 Subject: [PATCH 380/453] feat: poder hacer git lfs checkout --- app/models/deploy_local.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index bfde29f7..ee06fa4e 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -14,6 +14,7 @@ class DeployLocal < Deploy # Sutty def deploy(output: false) return false unless mkdir + return false unless git_lfs(output: output) return false unless yarn(output: output) return false unless pnpm(output: output) return false unless bundle(output: output) @@ -113,6 +114,11 @@ class DeployLocal < Deploy File.exist? pnpm_lock end + def git_lfs(output: false) + run %(git lfs fetch), output: output + run %(git lfs checkout), output: output + end + def gem(output: false) run %(gem install bundler --no-document), output: output end From 1c5dd603e5890b32eaf864e11213206229d3f78a Mon Sep 17 00:00:00 2001 From: f Date: Tue, 11 Apr 2023 10:42:33 -0300 Subject: [PATCH 381/453] fix: hacer git lfs checkout despues de clonar el sitio #13022 --- app/models/site.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/site.rb b/app/models/site.rb index 3f2aa34e..9a6a3865 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -473,6 +473,8 @@ class Site < ApplicationRecord return if jekyll? Rugged::Repository.clone_at ENV['SKEL_SUTTY'], path + + deploys.find_by_type('DeployLocal').send(:git_lfs) end # Elimina el directorio del sitio From 9e177a2257db47eddaf7f70f90ce98d5b7e09bbe Mon Sep 17 00:00:00 2001 From: f Date: Tue, 11 Apr 2023 10:48:00 -0300 Subject: [PATCH 382/453] fix: correr lfs junto con las gemas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit esto es una solución temporal! --- app/models/site.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/site.rb b/app/models/site.rb index 9a6a3865..6ac10329 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -473,8 +473,6 @@ class Site < ApplicationRecord return if jekyll? Rugged::Repository.clone_at ENV['SKEL_SUTTY'], path - - deploys.find_by_type('DeployLocal').send(:git_lfs) end # Elimina el directorio del sitio @@ -566,6 +564,8 @@ class Site < ApplicationRecord def install_gems return unless persisted? + deploys.find_by_type('DeployLocal').send(:git_lfs) + if !gem_dir? || gemfile_updated? || gemfile_lock_updated? deploys.find_by_type('DeployLocal').send(:bundle) touch From 9aa99e27540fa4e6559cdc8bb3b340a1a3742891 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 11 Apr 2023 12:09:13 -0300 Subject: [PATCH 383/453] feat: establecer los metadatos para cambiar el idioma #12925 --- app/views/layouts/_link_rel_alternate.haml | 7 +++++++ app/views/layouts/application.html.haml | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 app/views/layouts/_link_rel_alternate.haml diff --git a/app/views/layouts/_link_rel_alternate.haml b/app/views/layouts/_link_rel_alternate.haml new file mode 100644 index 00000000..64a70977 --- /dev/null +++ b/app/views/layouts/_link_rel_alternate.haml @@ -0,0 +1,7 @@ +- unless current_usuarie + - params.permit! + - I18n.available_locales.each do |locale| + - url = url_for(**params.to_h.merge(change_locale_to: locale), only_path: false) + - if locale == I18n.default_locale + %link{ rel: 'alternate', hreflang: 'x-default', href: url } + %link{ rel: 'alternate', hreflang: locale, href: url } diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 965a856f..d2113398 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -4,7 +4,7 @@ %meta{ charset: 'UTF-8' }/ %meta{ content: 'text/html; charset=UTF-8', 'http-equiv': 'Content-Type' }/ - %meta{ name: 'color-scheme', content: 'light dark' }/ + %meta{ name: 'color-scheme', content: 'light' }/ %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1.0' }/ %meta{ name: 'referrer', content: 'same-origin' }/ @@ -17,6 +17,7 @@ = javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' = stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' = favicon_link_tag 'sutty_cuadrada.png', rel: 'apple-touch-icon', type: 'image/png' + = render 'layouts/link_rel_alternate' %body{ class: yield(:body) } .container-fluid#sutty From 556a0541a57ecd607716b22b39496e1ddf34abb1 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 11 Apr 2023 16:19:49 -0300 Subject: [PATCH 384/453] =?UTF-8?q?feat:=20agregar=20las=20columnas=20para?= =?UTF-8?q?=20la=20recolecci=C3=B3n=20de=20datos=20#13029?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...20230411185406_add_sustainability_to_access_logs.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 db/migrate/20230411185406_add_sustainability_to_access_logs.rb diff --git a/db/migrate/20230411185406_add_sustainability_to_access_logs.rb b/db/migrate/20230411185406_add_sustainability_to_access_logs.rb new file mode 100644 index 00000000..80f16fb5 --- /dev/null +++ b/db/migrate/20230411185406_add_sustainability_to_access_logs.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# Agrega las columnas de calculo de emisiones de CO2 +class AddSustainabilityToAccessLogs < ActiveRecord::Migration[6.1] + def change + %i[datacenter_co2 network_co2 consumer_device_co2 production_co2 total_co2].each do |column| + add_column :access_logs, column, :decimal, limit: 53 + end + end +end From 030a64a31cc88eda93d2149a2e86d55677b25be7 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 11 Apr 2023 16:37:24 -0300 Subject: [PATCH 385/453] fix: generar una imagen por rama --- .woodpecker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 2e775624..dfade89d 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -6,7 +6,7 @@ pipeline: username: "sutty" repo: "gitea.nulo.in/sutty/panel" tags: - - "${ALPINE_VERSION}-${RUBY_VERSION}.${RUBY_PATCH}" + - "${ALPINE_VERSION}-${RUBY_VERSION}.${RUBY_PATCH}-${CI_COMMIT_BRANCH}" - "latest" build_args: - "RUBY_VERSION=${RUBY_VERSION}" From 8f1c38b8fc770219cb4a0819a4c9ac7a9cf786ad Mon Sep 17 00:00:00 2001 From: f Date: Tue, 11 Apr 2023 16:39:10 -0300 Subject: [PATCH 386/453] fix: correr la ci cuando cambia --- .woodpecker.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.woodpecker.yml b/.woodpecker.yml index dfade89d..cdd99651 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -25,6 +25,7 @@ pipeline: include: - "Dockerfile" - ".dockerignore" + - ".woodpecker.yml" assets: image: "gitea.nulo.in/sutty/panel:${ALPINE_VERSION}-${RUBY_VERSION}.${RUBY_PATCH}" commands: From 991624b951f7ab2141e147f50e1165a709cb0701 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 11 Apr 2023 17:45:01 -0300 Subject: [PATCH 387/453] feat: no instalar otras gemas que las especificadas sutty/skel.sutty.nl#7 --- app/models/deploy_local.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_local.rb b/app/models/deploy_local.rb index bfde29f7..69f1c030 100644 --- a/app/models/deploy_local.rb +++ b/app/models/deploy_local.rb @@ -132,7 +132,7 @@ class DeployLocal < Deploy end def bundle(output: false) - run %(bundle install --no-cache --path="#{gems_dir}" --clean --without test development), output: output + run %(bundle install --deployment --no-cache --path="#{gems_dir}" --clean --without test development), output: output end def jekyll_build(output: false) From 8457a07664ea914f4d18ef0d1cf39fffcfc4d8a9 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 11 Apr 2023 17:49:45 -0300 Subject: [PATCH 388/453] fix: al usar alert tenemos que cambiar i18n #13034 --- app/views/posts/_submit.haml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/views/posts/_submit.haml b/app/views/posts/_submit.haml index cad43320..944694c1 100644 --- a/app/views/posts/_submit.haml +++ b/app/views/posts/_submit.haml @@ -1,6 +1,8 @@ +- invalid_help = site.config.fetch('invalid_help', t('.invalid_help')) +- sending_help = site.config.fetch('sending_help', t('.sending_help')) .form-group = submit_tag t('.save'), class: 'btn submit-post' = render 'bootstrap/alert', class: 'invalid-help d-none' do - = site.config.fetch('invalid_help', t('.invalid_help')) + = invalid_help = render 'bootstrap/alert', class: 'sending-help d-none' do - = site.config.fetch('sending_help', t('.sending_help')) + = sending_help From f5aae98b91d0b8c269f461a804674de0f4ae7af4 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 13 Apr 2023 14:25:56 -0300 Subject: [PATCH 389/453] =?UTF-8?q?feat:=20mover=20el=20bot=C3=B3n=20de=20?= =?UTF-8?q?publicaci=C3=B3n=20a=20una=20zona=20m=C3=A1s=20visible=20#13071?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/posts/index.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 4f814cda..49a55f55 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -5,6 +5,8 @@ - cache_if @usuarie, [@site, I18n.locale] do = render 'sites/status', site: @site + = render 'sites/build', site: @site + %h3= t('posts.new') %table.mb-3 - @site.layouts.sort_by(&:humanized_name).each do |layout| @@ -33,8 +35,6 @@ type: 'info', link: site_usuaries_path(@site) - = render 'sites/build', site: @site - - if @site.design.credits = render 'bootstrap/alert' do = sanitize_markdown @site.design.credits From 8aed1edaff81544ecfd6ac21559db5af5048229b Mon Sep 17 00:00:00 2001 From: f Date: Thu, 13 Apr 2023 14:27:51 -0300 Subject: [PATCH 390/453] feat: ocupar todo el ancho --- app/views/posts/index.haml | 2 +- app/views/sites/_build.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 49a55f55..591f5795 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -5,7 +5,7 @@ - cache_if @usuarie, [@site, I18n.locale] do = render 'sites/status', site: @site - = render 'sites/build', site: @site + = render 'sites/build', site: @site, class: 'btn-block' %h3= t('posts.new') %table.mb-3 diff --git a/app/views/sites/_build.haml b/app/views/sites/_build.haml index 6bc4d11b..5911e908 100644 --- a/app/views/sites/_build.haml +++ b/app/views/sites/_build.haml @@ -3,7 +3,7 @@ method: :post, class: 'form-inline inline' do = submit_tag site.enqueued? ? t('sites.enqueued') : t('sites.enqueue'), - class: 'btn no-border-radius', + class: "btn no-border-radius #{local_assigns[:class]}", title: site.enqueued? ? t('help.sites.enqueued') : t('help.sites.enqueue'), data: { disable_with: t('sites.enqueued') }, disabled: site.enqueued? From 6e567787681b5177e31e0ccef83b52e54635cb9b Mon Sep 17 00:00:00 2001 From: f Date: Sat, 15 Apr 2023 11:16:58 -0300 Subject: [PATCH 391/453] fix: renovar el token #13105 `touch` no corre `before_save`, con lo que el token nunca se renovaba --- app/jobs/renew_distributed_press_tokens_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/renew_distributed_press_tokens_job.rb b/app/jobs/renew_distributed_press_tokens_job.rb index 5664d9fa..86086ac7 100644 --- a/app/jobs/renew_distributed_press_tokens_job.rb +++ b/app/jobs/renew_distributed_press_tokens_job.rb @@ -7,7 +7,7 @@ class RenewDistributedPressTokensJob < ApplicationJob # detener la tarea si algo pasa. def perform DistributedPressPublisher.with_about_to_expire_tokens.find_each do |publisher| - publisher.touch + publisher.save rescue DistributedPress::V1::Error => e data = { instance: publisher.instance, expires_at: publisher.client.token.expires_at } From aa0cd9d6a301cc955632a42afe442093d3e97521 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 15 Apr 2023 12:23:43 -0300 Subject: [PATCH 392/453] =?UTF-8?q?ci:=20compilar=20assets=20tambi=C3=A9n?= =?UTF-8?q?=20en=20gitlab?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitlab-ci.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..41b504ac --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,33 @@ +image: "gitea.nulo.in/sutty/panel:3.14.10-2.7.8-panel.sutty.nl" +variables: + RAILS_ENV: "production" + LC_ALL: "C.UTF-8" +cache: + paths: + - "vendor/ruby" +assets: + stage: "assets" + rules: + - if: "$CI_COMMIT_BRANCH == panel.sutty.nl" + - if: "$CI_COMMIT_BRANCH" + changes: + compares_to: "refs/heads/rails" + paths: + - "package.json" + - "app/javascript/**/*" + - "app/assets/**/*" + before_script: + - "git config --global user.email \"${GIT_USER_EMAIL:-$GITLAB_USER_EMAIL}\"" + - "git config --global user.name \"${GIT_USER_NAME:-$GITLAB_USER_NAME}\"" + - "git remote set-url --push origin \"https://${GITLAB_USERNAME}:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git\"" + - "apk add python2 dotenv brotli" + - "mv config/credentials.yml.enc.ci config/credentials.yml.enc" + - "cp .env.example .env" + - "dotenv bundle install --path=vendor" + script: + - "dotenv RAILS_ENV=production bundle exec rails webpacker:clobber" + - "dotenv RAILS_ENV=production bundle exec rails assets:precompile" + - "dotenv RAILS_ENV=production bundle exec rails assets:clean" + after_script: + - "git add public && git commit -m \"ci: assets [skip ci]\"" + - "git push -o ci.skip" From e85ce7c883746dcb79c514814e45f50e8e5e481a Mon Sep 17 00:00:00 2001 From: f Date: Sat, 15 Apr 2023 12:28:37 -0300 Subject: [PATCH 393/453] ci: typo --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 41b504ac..7c09d65f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,7 +11,7 @@ assets: - if: "$CI_COMMIT_BRANCH == panel.sutty.nl" - if: "$CI_COMMIT_BRANCH" changes: - compares_to: "refs/heads/rails" + compare_to: "refs/heads/rails" paths: - "package.json" - "app/javascript/**/*" From 1231f3bdab0d608e258b2cd25f59e509a2106f4d Mon Sep 17 00:00:00 2001 From: f Date: Sat, 15 Apr 2023 12:31:12 -0300 Subject: [PATCH 394/453] ci: comillas --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7c09d65f..bd9a3903 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,7 +8,7 @@ cache: assets: stage: "assets" rules: - - if: "$CI_COMMIT_BRANCH == panel.sutty.nl" + - if: "$CI_COMMIT_BRANCH == \"panel.sutty.nl\"" - if: "$CI_COMMIT_BRANCH" changes: compare_to: "refs/heads/rails" From 29f4c7a847d191b66c249501d31546b6e7890d91 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 15 Apr 2023 12:31:52 -0300 Subject: [PATCH 395/453] =?UTF-8?q?ci:=20estad=C3=ADo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bd9a3903..f8994356 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,7 +6,7 @@ cache: paths: - "vendor/ruby" assets: - stage: "assets" + stage: "build" rules: - if: "$CI_COMMIT_BRANCH == \"panel.sutty.nl\"" - if: "$CI_COMMIT_BRANCH" From d59fa43082a119eb2f0a478d14539ba76436d29a Mon Sep 17 00:00:00 2001 From: jazzari Date: Sat, 15 Apr 2023 13:31:09 -0300 Subject: [PATCH 396/453] feat: reorder template designs according to complexity # 13091 --- app/views/sites/_form.haml | 2 +- .../20230415153231_add_priority_to_designs.rb | 5 + db/schema.rb | 222 +++++++++++++++++- db/seeds/designs.yml | 11 +- 4 files changed, 235 insertions(+), 5 deletions(-) create mode 100644 db/migrate/20230415153231_add_priority_to_designs.rb diff --git a/app/views/sites/_form.haml b/app/views/sites/_form.haml index 001f542e..50391871 100644 --- a/app/views/sites/_form.haml +++ b/app/views/sites/_form.haml @@ -55,7 +55,7 @@ layouts: site.incompatible_layouts.to_sentence) .row.row-cols-1.row-cols-md-2.designs -# Demasiado complejo para un f.collection_radio_buttons - - Design.all.find_each do |design| + - Design.all.order(priority: :desc).find_each do |design| .design.col.d-flex.flex-column .custom-control.custom-radio = f.radio_button :design_id, design.id, diff --git a/db/migrate/20230415153231_add_priority_to_designs.rb b/db/migrate/20230415153231_add_priority_to_designs.rb new file mode 100644 index 00000000..7fc45558 --- /dev/null +++ b/db/migrate/20230415153231_add_priority_to_designs.rb @@ -0,0 +1,5 @@ +class AddPriorityToDesigns < ActiveRecord::Migration[6.1] + def change + add_column :designs, :priority, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index a395329d..f659f11d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_10_22_225449) do +ActiveRecord::Schema.define(version: 2023_04_15_153231) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" @@ -65,6 +65,11 @@ ActiveRecord::Schema.define(version: 2021_10_22_225449) do t.boolean "crawler", default: false t.string "http_referer" t.datetime "created_at", precision: 6 + t.decimal "datacenter_co2" + t.decimal "network_co2" + t.decimal "consumer_device_co2" + t.decimal "production_co2" + t.decimal "total_co2" t.index ["geoip2_data_city_name"], name: "index_access_logs_on_geoip2_data_city_name" t.index ["geoip2_data_country_name"], name: "index_access_logs_on_geoip2_data_country_name" t.index ["host"], name: "index_access_logs_on_host" @@ -103,7 +108,7 @@ ActiveRecord::Schema.define(version: 2021_10_22_225449) do t.string "checksum", null: false t.datetime "created_at", null: false t.string "service_name", null: false - t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true + t.index ["key", "service_name"], name: "index_active_storage_blobs_on_key_and_service_name", unique: true end create_table "active_storage_variant_records", force: :cascade do |t| @@ -179,6 +184,14 @@ ActiveRecord::Schema.define(version: 2021_10_22_225449) do t.index ["deploy_id"], name: "index_build_stats_on_deploy_id" end + create_table "codes_of_conduct", force: :cascade do |t| + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.string "title" + t.text "description" + t.text "content" + end + create_table "csp_reports", id: :uuid, default: nil, force: :cascade do |t| t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false @@ -217,6 +230,15 @@ ActiveRecord::Schema.define(version: 2021_10_22_225449) do t.boolean "disabled", default: false t.text "credits" t.string "designer_url" + t.integer "priority" + end + + create_table "distributed_press_publishers", force: :cascade do |t| + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.string "instance" + t.text "token_ciphertext", null: false + t.datetime "expires_at" end create_table "indexed_posts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| @@ -232,6 +254,7 @@ ActiveRecord::Schema.define(version: 2021_10_22_225449) do t.tsvector "indexed_content" t.integer "order", default: 0 t.string "dictionary" + t.uuid "post_id" t.index ["front_matter"], name: "index_indexed_posts_on_front_matter", using: :gin t.index ["indexed_content"], name: "index_indexed_posts_on_indexed_content", using: :gin t.index ["layout"], name: "index_indexed_posts_on_layout" @@ -247,6 +270,7 @@ ActiveRecord::Schema.define(version: 2021_10_22_225449) do t.text "deed" t.string "url" t.string "icons" + t.string "short_description" end create_table "log_entries", force: :cascade do |t| @@ -292,6 +316,56 @@ ActiveRecord::Schema.define(version: 2021_10_22_225449) do t.index ["translatable_id", "translatable_type", "locale", "key"], name: "index_mobility_text_translations_on_keys", unique: true end + create_table "privacy_policies", force: :cascade do |t| + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.string "title" + t.text "description" + t.text "content" + end + + create_table "que_jobs", comment: "7", force: :cascade do |t| + t.integer "priority", limit: 2, default: 100, null: false + t.datetime "run_at", default: -> { "now()" }, null: false + t.text "job_class", null: false + t.integer "error_count", default: 0, null: false + t.text "last_error_message" + t.text "queue", default: "default", null: false + t.text "last_error_backtrace" + t.datetime "finished_at" + t.datetime "expired_at" + t.jsonb "args", default: [], null: false + t.jsonb "data", default: {}, null: false + t.integer "job_schema_version", null: false + t.jsonb "kwargs", default: {}, null: false + t.index ["args"], name: "que_jobs_args_gin_idx", opclass: :jsonb_path_ops, using: :gin + t.index ["data"], name: "que_jobs_data_gin_idx", opclass: :jsonb_path_ops, using: :gin + t.index ["job_schema_version", "queue", "priority", "run_at", "id"], name: "que_poll_idx", where: "((finished_at IS NULL) AND (expired_at IS NULL))" + t.index ["kwargs"], name: "que_jobs_kwargs_gin_idx", opclass: :jsonb_path_ops, using: :gin + t.check_constraint "(char_length(last_error_message) <= 500) AND (char_length(last_error_backtrace) <= 10000)", name: "error_length" + t.check_constraint "(jsonb_typeof(data) = 'object'::text) AND ((NOT (data ? 'tags'::text)) OR ((jsonb_typeof((data -> 'tags'::text)) = 'array'::text) AND (jsonb_array_length((data -> 'tags'::text)) <= 5) AND que_validate_tags((data -> 'tags'::text))))", name: "valid_data" + t.check_constraint "char_length(queue) <= 100", name: "queue_length" + t.check_constraint "jsonb_typeof(args) = 'array'::text", name: "valid_args" + t.check_constraint nil, name: "job_class_length" + end + + create_table "que_lockers", primary_key: "pid", id: :integer, default: nil, force: :cascade do |t| + t.integer "worker_count", null: false + t.integer "worker_priorities", null: false, array: true + t.integer "ruby_pid", null: false + t.text "ruby_hostname", null: false + t.text "queues", null: false, array: true + t.boolean "listening", null: false + t.integer "job_schema_version", default: 1 + t.check_constraint "(array_ndims(queues) = 1) AND (array_length(queues, 1) IS NOT NULL)", name: "valid_queues" + t.check_constraint "(array_ndims(worker_priorities) = 1) AND (array_length(worker_priorities, 1) IS NOT NULL)", name: "valid_worker_priorities" + end + + create_table "que_values", primary_key: "key", id: :text, force: :cascade do |t| + t.jsonb "value", default: {}, null: false + t.check_constraint "jsonb_typeof(value) = 'object'::text", name: "valid_value" + end + create_table "roles", force: :cascade do |t| t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -329,6 +403,7 @@ ActiveRecord::Schema.define(version: 2021_10_22_225449) do t.string "tienda_api_key_ciphertext", default: "" t.string "tienda_url", default: "" t.string "api_key_ciphertext" + t.string "slugify_mode", default: "default" t.index ["design_id"], name: "index_sites_on_design_id" t.index ["licencia_id"], name: "index_sites_on_licencia_id" t.index ["name"], name: "index_sites_on_name", unique: true @@ -358,7 +433,6 @@ ActiveRecord::Schema.define(version: 2021_10_22_225449) do t.integer "failed_attempts", default: 0, null: false t.string "unlock_token" t.datetime "locked_at" - t.boolean "acepta_politicas_de_privacidad", default: false t.string "invitation_token" t.datetime "invitation_created_at" t.datetime "invitation_sent_at" @@ -368,6 +442,10 @@ ActiveRecord::Schema.define(version: 2021_10_22_225449) do t.bigint "invited_by_id" t.integer "invitations_count", default: 0 t.string "lang", default: "es" + t.datetime "privacy_policy_accepted_at" + t.datetime "terms_of_service_accepted_at" + t.datetime "code_of_conduct_accepted_at" + t.datetime "available_for_feedback_accepted_at" t.index ["confirmation_token"], name: "index_usuaries_on_confirmation_token", unique: true t.index ["email"], name: "index_usuaries_on_email", unique: true t.index ["invitation_token"], name: "index_usuaries_on_invitation_token", unique: true @@ -380,6 +458,144 @@ ActiveRecord::Schema.define(version: 2021_10_22_225449) do add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" + # no candidate create_trigger statement could be found, creating an adapter-specific one + execute(<<-SQL) +CREATE OR REPLACE FUNCTION public.que_job_notify() + RETURNS trigger + LANGUAGE plpgsql +AS $function$ + DECLARE + locker_pid integer; + sort_key json; + BEGIN + -- Don't do anything if the job is scheduled for a future time. + IF NEW.run_at IS NOT NULL AND NEW.run_at > now() THEN + RETURN null; + END IF; + + -- Pick a locker to notify of the job's insertion, weighted by their number + -- of workers. Should bounce pseudorandomly between lockers on each + -- invocation, hence the md5-ordering, but still touch each one equally, + -- hence the modulo using the job_id. + SELECT pid + INTO locker_pid + FROM ( + SELECT *, last_value(row_number) OVER () + 1 AS count + FROM ( + SELECT *, row_number() OVER () - 1 AS row_number + FROM ( + SELECT * + FROM public.que_lockers ql, generate_series(1, ql.worker_count) AS id + WHERE + listening AND + queues @> ARRAY[NEW.queue] AND + ql.job_schema_version = NEW.job_schema_version + ORDER BY md5(pid::text || id::text) + ) t1 + ) t2 + ) t3 + WHERE NEW.id % count = row_number; + + IF locker_pid IS NOT NULL THEN + -- There's a size limit to what can be broadcast via LISTEN/NOTIFY, so + -- rather than throw errors when someone enqueues a big job, just + -- broadcast the most pertinent information, and let the locker query for + -- the record after it's taken the lock. The worker will have to hit the + -- DB in order to make sure the job is still visible anyway. + SELECT row_to_json(t) + INTO sort_key + FROM ( + SELECT + 'job_available' AS message_type, + NEW.queue AS queue, + NEW.priority AS priority, + NEW.id AS id, + -- Make sure we output timestamps as UTC ISO 8601 + to_char(NEW.run_at AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.US"Z"') AS run_at + ) t; + + PERFORM pg_notify('que_listener_' || locker_pid::text, sort_key::text); + END IF; + + RETURN null; + END +$function$ + SQL + + # no candidate create_trigger statement could be found, creating an adapter-specific one + execute("CREATE TRIGGER que_job_notify AFTER INSERT ON \"que_jobs\" FOR EACH ROW WHEN (NOT COALESCE(current_setting('que.skip_notify'::text, true), ''::text) = 'true'::text) EXECUTE FUNCTION que_job_notify()") + + # no candidate create_trigger statement could be found, creating an adapter-specific one + execute(<<-SQL) +CREATE OR REPLACE FUNCTION public.que_state_notify() + RETURNS trigger + LANGUAGE plpgsql +AS $function$ + DECLARE + row record; + message json; + previous_state text; + current_state text; + BEGIN + IF TG_OP = 'INSERT' THEN + previous_state := 'nonexistent'; + current_state := public.que_determine_job_state(NEW); + row := NEW; + ELSIF TG_OP = 'DELETE' THEN + previous_state := public.que_determine_job_state(OLD); + current_state := 'nonexistent'; + row := OLD; + ELSIF TG_OP = 'UPDATE' THEN + previous_state := public.que_determine_job_state(OLD); + current_state := public.que_determine_job_state(NEW); + + -- If the state didn't change, short-circuit. + IF previous_state = current_state THEN + RETURN null; + END IF; + + row := NEW; + ELSE + RAISE EXCEPTION 'Unrecognized TG_OP: %', TG_OP; + END IF; + + SELECT row_to_json(t) + INTO message + FROM ( + SELECT + 'job_change' AS message_type, + row.id AS id, + row.queue AS queue, + + coalesce(row.data->'tags', '[]'::jsonb) AS tags, + + to_char(row.run_at AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.US"Z"') AS run_at, + to_char(now() AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.US"Z"') AS time, + + CASE row.job_class + WHEN 'ActiveJob::QueueAdapters::QueAdapter::JobWrapper' THEN + coalesce( + row.args->0->>'job_class', + 'ActiveJob::QueueAdapters::QueAdapter::JobWrapper' + ) + ELSE + row.job_class + END AS job_class, + + previous_state AS previous_state, + current_state AS current_state + ) t; + + PERFORM pg_notify('que_state', message::text); + + RETURN null; + END +$function$ + SQL + + # no candidate create_trigger statement could be found, creating an adapter-specific one + execute("CREATE TRIGGER que_state_notify AFTER INSERT OR DELETE OR UPDATE ON \"que_jobs\" FOR EACH ROW WHEN (NOT COALESCE(current_setting('que.skip_notify'::text, true), ''::text) = 'true'::text) EXECUTE FUNCTION que_state_notify()") + create_trigger("indexed_posts_before_insert_update_row_tr", :compatibility => 1). on("indexed_posts"). before(:insert, :update) do diff --git a/db/seeds/designs.yml b/db/seeds/designs.yml index b1508b84..22615638 100644 --- a/db/seeds/designs.yml +++ b/db/seeds/designs.yml @@ -6,6 +6,7 @@ disabled: true description_en: "Upload your own theme. [This feature is in development, help us!](https://sutty.nl/en/#contact)" description_es: "Subir tu propio diseño. [Esta posibilidad está en desarrollo, ¡ayudanos!](https://sutty.nl/#contacto)" + priority: '8' - name_en: 'I want you to develop a site for me' name_es: 'Quiero que desarrollen mi sitio' gem: 'sutty-theme-custom' @@ -13,6 +14,7 @@ disabled: true description_en: "If you want us to develop your site, you're welcome to [contact us!](https://sutty.nl/en/#contact) :)" description_es: "Si querés que desarrollemos tu sitio, [escribinos](https://sutty.nl/#contacto) :)" + priority: '7' - name_en: 'Minima' name_es: 'Mínima' gem: 'sutty-minima' @@ -20,6 +22,7 @@ description_en: "Sutty Minima is based on [Minima](https://jekyll.github.io/minima/), a blog-focused theme for Jekyll." description_es: 'Sutty Mínima es una plantilla para blogs basada en [Mínima](https://jekyll.github.io/minima/).' license: 'https://0xacab.org/sutty/jekyll/minima/-/blob/master/LICENSE.txt' + priority: '1' - name_en: 'Sutty' name_es: 'Sutty' gem: 'sutty-jekyll-theme' @@ -29,6 +32,7 @@ license: 'https://0xacab.org/sutty/jekyll/sutty-jekyll-theme/-/blob/master/LICENSE.txt' credits_es: 'Sutty es parte de la economía solidaria :)' credits_en: 'Sutty is a solidarity economy project!' + priority: '2' - name_en: 'Self-managed Book Publisher' name_es: 'Editorial Autogestiva' gem: 'editorial-autogestiva-jekyll-theme' @@ -38,6 +42,7 @@ license: 'https://0xacab.org/sutty/jekyll/editorial-autogestiva-jekyll-theme/-/blob/master/LICENSE.txt' credits_es: 'Esta plantilla fue inspirada en el trabajo de las [editoriales autogestivas](https://sutty.nl/plantillas-para-crear-cat%C3%A1logos-de-editoriales-autogestivas/)' credits_en: 'This theme is inspired by [independent publishing projects](https://sutty.nl/en/new-template-for-publishing-projects/)' + priority: '6' - name_en: 'Donations' name_es: 'Donaciones' gem: 'sutty-donaciones-jekyll-theme' @@ -47,6 +52,7 @@ license: 'https://0xacab.org/sutty/jekyll/sutty-donaciones-jekyll-theme/-/blob/master/LICENSE.txt' credits_es: 'Diseñamos esta plantilla para [visibilizar campañas de donaciones](https://sutty.nl/plantilla-para-donaciones/) durante la cuarentena.' credits_en: 'We designed this theme to increase [visibility for donation requests](https://sutty.nl/template-for-donations/) during the quarantine.' + priority: '3' - name_en: 'Support campaign' name_es: 'Adhesiones' gem: 'adhesiones-jekyll-theme' @@ -57,6 +63,7 @@ credits_es: 'Desarrollamos esta plantilla junto con [Librenauta](https://sutty.nl/plantilla-para-campa%C3%B1as-de-adhesiones/)' credits_en: 'This template was made in collaboration with Librenauta' designer_url: 'https://copiona.com/donaunbit/' + priority: '5' - name_en: 'Community Radio' name_es: 'Radio comunitaria' gem: 'radios-comunitarias-jekyll-theme' @@ -67,6 +74,7 @@ credits_es: 'Desarrollamos esta plantilla junto con Librenauta en 15 horas :)' credits_en: 'This template was made in collaboration with Librenauta in 15 hours!' designer_url: 'https://copiona.com/donaunbit/' + priority: '4' - name_en: 'Resource toolkit' name_es: 'Recursero' gem: 'recursero-jekyll-theme' @@ -75,9 +83,10 @@ description_en: "We're working towards adding more themes for you to use. [Contact us!](https://sutty.nl/en/#contact)" description_es: "Estamos trabajando para que puedas tener más diseños. [¡Escribinos!](https://sutty.nl/#contacto)" - name_en: 'Other themes' - name_es: 'Mi propio diseño' + name_es: 'Otros temas' gem: 'sutty-theme-own' url: 'https://jekyllthemes.org' disabled: true description_en: "We're working towards adding more themes for you to use. [Contact us!](https://sutty.nl/en/#contact)" description_es: "Estamos trabajando para que puedas tener más diseños. [¡Escribinos!](https://sutty.nl/#contacto)" + priority: '9' \ No newline at end of file From bdac1fb0b834ac8b00025c754b6c03c455703bdb Mon Sep 17 00:00:00 2001 From: f Date: Sat, 15 Apr 2023 14:39:55 -0300 Subject: [PATCH 397/453] fix: estos cambios no pertenecen a esta rama --- db/schema.rb | 211 +-------------------------------------------------- 1 file changed, 1 insertion(+), 210 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index f659f11d..fd8e5b48 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -184,14 +184,6 @@ ActiveRecord::Schema.define(version: 2023_04_15_153231) do t.index ["deploy_id"], name: "index_build_stats_on_deploy_id" end - create_table "codes_of_conduct", force: :cascade do |t| - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false - t.string "title" - t.text "description" - t.text "content" - end - create_table "csp_reports", id: :uuid, default: nil, force: :cascade do |t| t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false @@ -233,14 +225,6 @@ ActiveRecord::Schema.define(version: 2023_04_15_153231) do t.integer "priority" end - create_table "distributed_press_publishers", force: :cascade do |t| - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false - t.string "instance" - t.text "token_ciphertext", null: false - t.datetime "expires_at" - end - create_table "indexed_posts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.bigint "site_id" t.datetime "created_at", precision: 6, null: false @@ -254,7 +238,6 @@ ActiveRecord::Schema.define(version: 2023_04_15_153231) do t.tsvector "indexed_content" t.integer "order", default: 0 t.string "dictionary" - t.uuid "post_id" t.index ["front_matter"], name: "index_indexed_posts_on_front_matter", using: :gin t.index ["indexed_content"], name: "index_indexed_posts_on_indexed_content", using: :gin t.index ["layout"], name: "index_indexed_posts_on_layout" @@ -270,7 +253,6 @@ ActiveRecord::Schema.define(version: 2023_04_15_153231) do t.text "deed" t.string "url" t.string "icons" - t.string "short_description" end create_table "log_entries", force: :cascade do |t| @@ -316,56 +298,6 @@ ActiveRecord::Schema.define(version: 2023_04_15_153231) do t.index ["translatable_id", "translatable_type", "locale", "key"], name: "index_mobility_text_translations_on_keys", unique: true end - create_table "privacy_policies", force: :cascade do |t| - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false - t.string "title" - t.text "description" - t.text "content" - end - - create_table "que_jobs", comment: "7", force: :cascade do |t| - t.integer "priority", limit: 2, default: 100, null: false - t.datetime "run_at", default: -> { "now()" }, null: false - t.text "job_class", null: false - t.integer "error_count", default: 0, null: false - t.text "last_error_message" - t.text "queue", default: "default", null: false - t.text "last_error_backtrace" - t.datetime "finished_at" - t.datetime "expired_at" - t.jsonb "args", default: [], null: false - t.jsonb "data", default: {}, null: false - t.integer "job_schema_version", null: false - t.jsonb "kwargs", default: {}, null: false - t.index ["args"], name: "que_jobs_args_gin_idx", opclass: :jsonb_path_ops, using: :gin - t.index ["data"], name: "que_jobs_data_gin_idx", opclass: :jsonb_path_ops, using: :gin - t.index ["job_schema_version", "queue", "priority", "run_at", "id"], name: "que_poll_idx", where: "((finished_at IS NULL) AND (expired_at IS NULL))" - t.index ["kwargs"], name: "que_jobs_kwargs_gin_idx", opclass: :jsonb_path_ops, using: :gin - t.check_constraint "(char_length(last_error_message) <= 500) AND (char_length(last_error_backtrace) <= 10000)", name: "error_length" - t.check_constraint "(jsonb_typeof(data) = 'object'::text) AND ((NOT (data ? 'tags'::text)) OR ((jsonb_typeof((data -> 'tags'::text)) = 'array'::text) AND (jsonb_array_length((data -> 'tags'::text)) <= 5) AND que_validate_tags((data -> 'tags'::text))))", name: "valid_data" - t.check_constraint "char_length(queue) <= 100", name: "queue_length" - t.check_constraint "jsonb_typeof(args) = 'array'::text", name: "valid_args" - t.check_constraint nil, name: "job_class_length" - end - - create_table "que_lockers", primary_key: "pid", id: :integer, default: nil, force: :cascade do |t| - t.integer "worker_count", null: false - t.integer "worker_priorities", null: false, array: true - t.integer "ruby_pid", null: false - t.text "ruby_hostname", null: false - t.text "queues", null: false, array: true - t.boolean "listening", null: false - t.integer "job_schema_version", default: 1 - t.check_constraint "(array_ndims(queues) = 1) AND (array_length(queues, 1) IS NOT NULL)", name: "valid_queues" - t.check_constraint "(array_ndims(worker_priorities) = 1) AND (array_length(worker_priorities, 1) IS NOT NULL)", name: "valid_worker_priorities" - end - - create_table "que_values", primary_key: "key", id: :text, force: :cascade do |t| - t.jsonb "value", default: {}, null: false - t.check_constraint "jsonb_typeof(value) = 'object'::text", name: "valid_value" - end - create_table "roles", force: :cascade do |t| t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -403,7 +335,6 @@ ActiveRecord::Schema.define(version: 2023_04_15_153231) do t.string "tienda_api_key_ciphertext", default: "" t.string "tienda_url", default: "" t.string "api_key_ciphertext" - t.string "slugify_mode", default: "default" t.index ["design_id"], name: "index_sites_on_design_id" t.index ["licencia_id"], name: "index_sites_on_licencia_id" t.index ["name"], name: "index_sites_on_name", unique: true @@ -433,6 +364,7 @@ ActiveRecord::Schema.define(version: 2023_04_15_153231) do t.integer "failed_attempts", default: 0, null: false t.string "unlock_token" t.datetime "locked_at" + t.boolean "acepta_politicas_de_privacidad", default: false t.string "invitation_token" t.datetime "invitation_created_at" t.datetime "invitation_sent_at" @@ -442,10 +374,6 @@ ActiveRecord::Schema.define(version: 2023_04_15_153231) do t.bigint "invited_by_id" t.integer "invitations_count", default: 0 t.string "lang", default: "es" - t.datetime "privacy_policy_accepted_at" - t.datetime "terms_of_service_accepted_at" - t.datetime "code_of_conduct_accepted_at" - t.datetime "available_for_feedback_accepted_at" t.index ["confirmation_token"], name: "index_usuaries_on_confirmation_token", unique: true t.index ["email"], name: "index_usuaries_on_email", unique: true t.index ["invitation_token"], name: "index_usuaries_on_invitation_token", unique: true @@ -458,143 +386,6 @@ ActiveRecord::Schema.define(version: 2023_04_15_153231) do add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" - # no candidate create_trigger statement could be found, creating an adapter-specific one - execute(<<-SQL) -CREATE OR REPLACE FUNCTION public.que_job_notify() - RETURNS trigger - LANGUAGE plpgsql -AS $function$ - DECLARE - locker_pid integer; - sort_key json; - BEGIN - -- Don't do anything if the job is scheduled for a future time. - IF NEW.run_at IS NOT NULL AND NEW.run_at > now() THEN - RETURN null; - END IF; - - -- Pick a locker to notify of the job's insertion, weighted by their number - -- of workers. Should bounce pseudorandomly between lockers on each - -- invocation, hence the md5-ordering, but still touch each one equally, - -- hence the modulo using the job_id. - SELECT pid - INTO locker_pid - FROM ( - SELECT *, last_value(row_number) OVER () + 1 AS count - FROM ( - SELECT *, row_number() OVER () - 1 AS row_number - FROM ( - SELECT * - FROM public.que_lockers ql, generate_series(1, ql.worker_count) AS id - WHERE - listening AND - queues @> ARRAY[NEW.queue] AND - ql.job_schema_version = NEW.job_schema_version - ORDER BY md5(pid::text || id::text) - ) t1 - ) t2 - ) t3 - WHERE NEW.id % count = row_number; - - IF locker_pid IS NOT NULL THEN - -- There's a size limit to what can be broadcast via LISTEN/NOTIFY, so - -- rather than throw errors when someone enqueues a big job, just - -- broadcast the most pertinent information, and let the locker query for - -- the record after it's taken the lock. The worker will have to hit the - -- DB in order to make sure the job is still visible anyway. - SELECT row_to_json(t) - INTO sort_key - FROM ( - SELECT - 'job_available' AS message_type, - NEW.queue AS queue, - NEW.priority AS priority, - NEW.id AS id, - -- Make sure we output timestamps as UTC ISO 8601 - to_char(NEW.run_at AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.US"Z"') AS run_at - ) t; - - PERFORM pg_notify('que_listener_' || locker_pid::text, sort_key::text); - END IF; - - RETURN null; - END -$function$ - SQL - - # no candidate create_trigger statement could be found, creating an adapter-specific one - execute("CREATE TRIGGER que_job_notify AFTER INSERT ON \"que_jobs\" FOR EACH ROW WHEN (NOT COALESCE(current_setting('que.skip_notify'::text, true), ''::text) = 'true'::text) EXECUTE FUNCTION que_job_notify()") - - # no candidate create_trigger statement could be found, creating an adapter-specific one - execute(<<-SQL) -CREATE OR REPLACE FUNCTION public.que_state_notify() - RETURNS trigger - LANGUAGE plpgsql -AS $function$ - DECLARE - row record; - message json; - previous_state text; - current_state text; - BEGIN - IF TG_OP = 'INSERT' THEN - previous_state := 'nonexistent'; - current_state := public.que_determine_job_state(NEW); - row := NEW; - ELSIF TG_OP = 'DELETE' THEN - previous_state := public.que_determine_job_state(OLD); - current_state := 'nonexistent'; - row := OLD; - ELSIF TG_OP = 'UPDATE' THEN - previous_state := public.que_determine_job_state(OLD); - current_state := public.que_determine_job_state(NEW); - - -- If the state didn't change, short-circuit. - IF previous_state = current_state THEN - RETURN null; - END IF; - - row := NEW; - ELSE - RAISE EXCEPTION 'Unrecognized TG_OP: %', TG_OP; - END IF; - - SELECT row_to_json(t) - INTO message - FROM ( - SELECT - 'job_change' AS message_type, - row.id AS id, - row.queue AS queue, - - coalesce(row.data->'tags', '[]'::jsonb) AS tags, - - to_char(row.run_at AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.US"Z"') AS run_at, - to_char(now() AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.US"Z"') AS time, - - CASE row.job_class - WHEN 'ActiveJob::QueueAdapters::QueAdapter::JobWrapper' THEN - coalesce( - row.args->0->>'job_class', - 'ActiveJob::QueueAdapters::QueAdapter::JobWrapper' - ) - ELSE - row.job_class - END AS job_class, - - previous_state AS previous_state, - current_state AS current_state - ) t; - - PERFORM pg_notify('que_state', message::text); - - RETURN null; - END -$function$ - SQL - - # no candidate create_trigger statement could be found, creating an adapter-specific one - execute("CREATE TRIGGER que_state_notify AFTER INSERT OR DELETE OR UPDATE ON \"que_jobs\" FOR EACH ROW WHEN (NOT COALESCE(current_setting('que.skip_notify'::text, true), ''::text) = 'true'::text) EXECUTE FUNCTION que_state_notify()") create_trigger("indexed_posts_before_insert_update_row_tr", :compatibility => 1). on("indexed_posts"). From bc74f85ba2c4b3b943cc1999b56de1032b302d08 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 15 Apr 2023 14:56:58 -0300 Subject: [PATCH 398/453] =?UTF-8?q?fix:=20mejorar=20el=20t=C3=ADtulo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/seeds/designs.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/db/seeds/designs.yml b/db/seeds/designs.yml index 22615638..67bccad3 100644 --- a/db/seeds/designs.yml +++ b/db/seeds/designs.yml @@ -82,11 +82,11 @@ disabled: true description_en: "We're working towards adding more themes for you to use. [Contact us!](https://sutty.nl/en/#contact)" description_es: "Estamos trabajando para que puedas tener más diseños. [¡Escribinos!](https://sutty.nl/#contacto)" -- name_en: 'Other themes' - name_es: 'Otros temas' +- name_en: 'More themes' + name_es: 'Más plantillas' gem: 'sutty-theme-own' url: 'https://jekyllthemes.org' disabled: true description_en: "We're working towards adding more themes for you to use. [Contact us!](https://sutty.nl/en/#contact)" description_es: "Estamos trabajando para que puedas tener más diseños. [¡Escribinos!](https://sutty.nl/#contacto)" - priority: '9' \ No newline at end of file + priority: '9' From fd41242985cf43912d0224444defb3f55963a9dc Mon Sep 17 00:00:00 2001 From: f Date: Sat, 15 Apr 2023 15:03:38 -0300 Subject: [PATCH 399/453] fix: el orden es de mayor a menor prioridad dejando espacio entre algunos para poder intercalar otras plantillas --- db/seeds/designs.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/db/seeds/designs.yml b/db/seeds/designs.yml index 67bccad3..a04c99c1 100644 --- a/db/seeds/designs.yml +++ b/db/seeds/designs.yml @@ -6,7 +6,7 @@ disabled: true description_en: "Upload your own theme. [This feature is in development, help us!](https://sutty.nl/en/#contact)" description_es: "Subir tu propio diseño. [Esta posibilidad está en desarrollo, ¡ayudanos!](https://sutty.nl/#contacto)" - priority: '8' + priority: '0' - name_en: 'I want you to develop a site for me' name_es: 'Quiero que desarrollen mi sitio' gem: 'sutty-theme-custom' @@ -14,7 +14,7 @@ disabled: true description_en: "If you want us to develop your site, you're welcome to [contact us!](https://sutty.nl/en/#contact) :)" description_es: "Si querés que desarrollemos tu sitio, [escribinos](https://sutty.nl/#contacto) :)" - priority: '7' + priority: '2' - name_en: 'Minima' name_es: 'Mínima' gem: 'sutty-minima' @@ -22,7 +22,7 @@ description_en: "Sutty Minima is based on [Minima](https://jekyll.github.io/minima/), a blog-focused theme for Jekyll." description_es: 'Sutty Mínima es una plantilla para blogs basada en [Mínima](https://jekyll.github.io/minima/).' license: 'https://0xacab.org/sutty/jekyll/minima/-/blob/master/LICENSE.txt' - priority: '1' + priority: '100' - name_en: 'Sutty' name_es: 'Sutty' gem: 'sutty-jekyll-theme' @@ -32,7 +32,7 @@ license: 'https://0xacab.org/sutty/jekyll/sutty-jekyll-theme/-/blob/master/LICENSE.txt' credits_es: 'Sutty es parte de la economía solidaria :)' credits_en: 'Sutty is a solidarity economy project!' - priority: '2' + priority: '90' - name_en: 'Self-managed Book Publisher' name_es: 'Editorial Autogestiva' gem: 'editorial-autogestiva-jekyll-theme' @@ -42,7 +42,7 @@ license: 'https://0xacab.org/sutty/jekyll/editorial-autogestiva-jekyll-theme/-/blob/master/LICENSE.txt' credits_es: 'Esta plantilla fue inspirada en el trabajo de las [editoriales autogestivas](https://sutty.nl/plantillas-para-crear-cat%C3%A1logos-de-editoriales-autogestivas/)' credits_en: 'This theme is inspired by [independent publishing projects](https://sutty.nl/en/new-template-for-publishing-projects/)' - priority: '6' + priority: '50' - name_en: 'Donations' name_es: 'Donaciones' gem: 'sutty-donaciones-jekyll-theme' @@ -52,7 +52,7 @@ license: 'https://0xacab.org/sutty/jekyll/sutty-donaciones-jekyll-theme/-/blob/master/LICENSE.txt' credits_es: 'Diseñamos esta plantilla para [visibilizar campañas de donaciones](https://sutty.nl/plantilla-para-donaciones/) durante la cuarentena.' credits_en: 'We designed this theme to increase [visibility for donation requests](https://sutty.nl/template-for-donations/) during the quarantine.' - priority: '3' + priority: '80' - name_en: 'Support campaign' name_es: 'Adhesiones' gem: 'adhesiones-jekyll-theme' @@ -63,7 +63,7 @@ credits_es: 'Desarrollamos esta plantilla junto con [Librenauta](https://sutty.nl/plantilla-para-campa%C3%B1as-de-adhesiones/)' credits_en: 'This template was made in collaboration with Librenauta' designer_url: 'https://copiona.com/donaunbit/' - priority: '5' + priority: '60' - name_en: 'Community Radio' name_es: 'Radio comunitaria' gem: 'radios-comunitarias-jekyll-theme' @@ -74,7 +74,7 @@ credits_es: 'Desarrollamos esta plantilla junto con Librenauta en 15 horas :)' credits_en: 'This template was made in collaboration with Librenauta in 15 hours!' designer_url: 'https://copiona.com/donaunbit/' - priority: '4' + priority: '70' - name_en: 'Resource toolkit' name_es: 'Recursero' gem: 'recursero-jekyll-theme' @@ -82,6 +82,7 @@ disabled: true description_en: "We're working towards adding more themes for you to use. [Contact us!](https://sutty.nl/en/#contact)" description_es: "Estamos trabajando para que puedas tener más diseños. [¡Escribinos!](https://sutty.nl/#contacto)" + priority: '3' - name_en: 'More themes' name_es: 'Más plantillas' gem: 'sutty-theme-own' @@ -89,4 +90,4 @@ disabled: true description_en: "We're working towards adding more themes for you to use. [Contact us!](https://sutty.nl/en/#contact)" description_es: "Estamos trabajando para que puedas tener más diseños. [¡Escribinos!](https://sutty.nl/#contacto)" - priority: '9' + priority: '1' From 020fb250b496112265407281be0b003837f13a50 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 15 Apr 2023 15:12:08 -0300 Subject: [PATCH 400/453] fix: #find_each no respeta el orden --- app/views/sites/_form.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/sites/_form.haml b/app/views/sites/_form.haml index 50391871..69997ffa 100644 --- a/app/views/sites/_form.haml +++ b/app/views/sites/_form.haml @@ -55,7 +55,7 @@ layouts: site.incompatible_layouts.to_sentence) .row.row-cols-1.row-cols-md-2.designs -# Demasiado complejo para un f.collection_radio_buttons - - Design.all.order(priority: :desc).find_each do |design| + - Design.all.order(priority: :desc).each do |design| .design.col.d-flex.flex-column .custom-control.custom-radio = f.radio_button :design_id, design.id, From 2d6e3443d7664a7440eaada0ae3ebfdffb773e9d Mon Sep 17 00:00:00 2001 From: f Date: Sat, 15 Apr 2023 15:16:31 -0300 Subject: [PATCH 401/453] fix: estos cambios tampoco --- db/schema.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index fd8e5b48..fd82d447 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -65,11 +65,6 @@ ActiveRecord::Schema.define(version: 2023_04_15_153231) do t.boolean "crawler", default: false t.string "http_referer" t.datetime "created_at", precision: 6 - t.decimal "datacenter_co2" - t.decimal "network_co2" - t.decimal "consumer_device_co2" - t.decimal "production_co2" - t.decimal "total_co2" t.index ["geoip2_data_city_name"], name: "index_access_logs_on_geoip2_data_city_name" t.index ["geoip2_data_country_name"], name: "index_access_logs_on_geoip2_data_country_name" t.index ["host"], name: "index_access_logs_on_host" @@ -108,7 +103,7 @@ ActiveRecord::Schema.define(version: 2023_04_15_153231) do t.string "checksum", null: false t.datetime "created_at", null: false t.string "service_name", null: false - t.index ["key", "service_name"], name: "index_active_storage_blobs_on_key_and_service_name", unique: true + t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true end create_table "active_storage_variant_records", force: :cascade do |t| From 4eb23a787bbdf66fbf9d26d1c44f4413fe0f4ab9 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 15 Apr 2023 18:36:56 -0300 Subject: [PATCH 402/453] feat: lista de links #13096 --- app/controllers/application_controller.rb | 4 +++ app/controllers/build_stats_controller.rb | 41 +++++++++++++++++++++++ app/controllers/posts_controller.rb | 4 --- app/policies/site_build_stat_policy.rb | 16 +++++++++ app/views/build_stats/index.haml | 21 ++++++++++++ config/locales/en.yml | 3 ++ config/locales/es.yml | 3 ++ config/routes.rb | 2 ++ 8 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 app/controllers/build_stats_controller.rb create mode 100644 app/policies/site_build_stat_policy.rb create mode 100644 app/views/build_stats/index.haml diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b4be5a97..ee153394 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -91,6 +91,10 @@ class ApplicationController < ActionController::Base breadcrumb 'stats.index', root_path, match: :exact end + def site + @site ||= find_site + end + protected def configure_permitted_parameters diff --git a/app/controllers/build_stats_controller.rb b/app/controllers/build_stats_controller.rb new file mode 100644 index 00000000..31a4c5d6 --- /dev/null +++ b/app/controllers/build_stats_controller.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +# La lista de estados de compilación, por ahora solo mostramos el último +# estado. +class BuildStatsController < ApplicationController + include ActionView::Helpers::NumberHelper + include ActionView::Helpers::DateHelper + + before_action :authenticate_usuarie! + + breadcrumb -> { current_usuarie.email }, :edit_usuarie_registration_path + breadcrumb 'sites.index', :sites_path, match: :exact + breadcrumb -> { site.title }, -> { site_posts_path(site, locale: locale) }, match: :exact + + def index + authorize SiteBuildStat.new(site) + breadcrumb I18n.t('build_stats.index.title'), '' + + @headers = %w[type url seconds size].map do |header| + t("deploy_mailer.deployed.th.#{header}") + end + + @table = site.deployment_list.map do |deploy| + type = deploy.class.name.underscore + urls = deploy.respond_to?(:urls) ? deploy.urls : [deploy.url].compact + urls = [nil] if urls.empty? + build_stat = deploy.build_stats.where(status: true).last + seconds = build_stat&.seconds || 0 + + { + title: t("deploy_mailer.deployed.#{type}.title"), + urls: urls, + seconds: { + human: distance_of_time_in_words(seconds), + machine: "PT#{seconds}S" + }, + size: number_to_human_size(build_stat&.bytes || 0, precision: 2) + } + end + end +end diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 3c529c24..9720fe13 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -159,10 +159,6 @@ class PostsController < ApplicationController end.transform_keys(&:to_sym) end - def site - @site ||= find_site - end - def post @post ||= site.posts(lang: locale).find(params[:post_id] || params[:id]) end diff --git a/app/policies/site_build_stat_policy.rb b/app/policies/site_build_stat_policy.rb new file mode 100644 index 00000000..03f09d21 --- /dev/null +++ b/app/policies/site_build_stat_policy.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Quiénes pueden ver estados de compilación de un sitio +class SiteBuildStatPolicy + attr_reader :site_build_stat, :usuarie + + def initialize(usuarie, site_build_stat) + @usuarie = usuarie + @site_build_stat = site_build_stat + end + + # Todes les usuaries e invitades de este sitio + def index? + site_build_stat.site.usuarie?(usuarie) || site_build_stat.site.invitade?(usuarie) + end +end diff --git a/app/views/build_stats/index.haml b/app/views/build_stats/index.haml new file mode 100644 index 00000000..dab5fc9a --- /dev/null +++ b/app/views/build_stats/index.haml @@ -0,0 +1,21 @@ +%main.row + %aside.menu.col-md-3 + %h1= @site.title + %p.lead= @site.description + .col + %h1= t('.title') + + %table.table + %thead + %tr + - @headers.each do |header| + %th{ scope: 'col' }= header + %tbody + - @table.each do |row| + - row[:urls].each do |url| + %tr + %th{ scope: 'row' }= row[:title] + %td= link_to_if url.present?, url, url + %td + %time{ datetime: row[:seconds][:machine] }= row[:seconds][:human] + %td= row[:size] diff --git a/config/locales/en.yml b/config/locales/en.yml index 3ddf681d..d92aa42a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -697,3 +697,6 @@ en: queries: show: empty: '(empty)' + build_stats: + index: + title: "Publications" diff --git a/config/locales/es.yml b/config/locales/es.yml index 01f1085c..db116e37 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -705,3 +705,6 @@ es: queries: show: empty: '(vacío)' + build_stats: + index: + title: "Publicaciones" diff --git a/config/routes.rb b/config/routes.rb index 511ca654..3828915c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -75,5 +75,7 @@ Rails.application.routes.draw do get :'stats/host', to: 'stats#host' get :'stats/uris', to: 'stats#uris' get :'stats/resources', to: 'stats#resources' + + resources :build_stats, only: %i[index] end end From 5d541ebee64c34885baba12f7a4370984138f257 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 15 Apr 2023 19:06:20 -0300 Subject: [PATCH 403/453] fixup! feat: lista de links #13096 --- app/models/site_build_stat.rb | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 app/models/site_build_stat.rb diff --git a/app/models/site_build_stat.rb b/app/models/site_build_stat.rb new file mode 100644 index 00000000..1a63a0bb --- /dev/null +++ b/app/models/site_build_stat.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +SiteBuildStat = Struct.new(:site) From 251dde865b534f93a2fd8a090d13676a34d0814f Mon Sep 17 00:00:00 2001 From: f Date: Sat, 15 Apr 2023 19:13:23 -0300 Subject: [PATCH 404/453] fix: siempre devolver un array --- app/models/deploy_distributed_press.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 32a3049e..ff2f7325 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -85,20 +85,22 @@ class DeployDistributedPress < Deploy private + # @return [Array] def gateway_urls - remote_info.dig(:distributed_press, :links).values.map do |protocol| + remote_info.dig(:distributed_press, :links)&.values&.map do |protocol| [ protocol[:link], protocol[:gateway] ] - end.flatten.compact.select do |link| + end&.flatten&.compact&.select do |link| link.include? '://' - end + end || [] end + # @return [Array] def protocol_urls - remote_info.dig(:distributed_press, :protocols).select do |_, enabled| + remote_info.dig(:distributed_press, :protocols)&.select do |_, enabled| enabled - end.map do |protocol, _| + end&.map do |protocol, _| "#{protocol}://#{site.hostname}" - end + end || [] end # El cliente de la API From 07d6b14b872d50c4bcca1b092a1599eee72a4199 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 15 Apr 2023 19:24:45 -0300 Subject: [PATCH 405/453] fix: cortar los links largos --- app/assets/stylesheets/application.scss | 4 ++++ app/views/build_stats/index.haml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index bba48558..fadbcbab 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -383,6 +383,8 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); } } +.word-break-all { word-break: break-all !important; } + /* * Modificadores de Bootstrap que no tienen versión responsive. */ @@ -405,6 +407,8 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); .text-#{$grid-breakpoint}-right { text-align: right !important; } .text-#{$grid-breakpoint}-center { text-align: center !important; } + .word-break-#{$grid-breakpoint}-all { word-break: break-all !important; } + // posición @each $position in $positions { .position-#{$grid-breakpoint}-#{$position} { position: $position !important; } diff --git a/app/views/build_stats/index.haml b/app/views/build_stats/index.haml index dab5fc9a..27dc20d1 100644 --- a/app/views/build_stats/index.haml +++ b/app/views/build_stats/index.haml @@ -15,7 +15,7 @@ - row[:urls].each do |url| %tr %th{ scope: 'row' }= row[:title] - %td= link_to_if url.present?, url, url + %td= link_to_if url.present?, url, url, class: 'word-break-all' %td %time{ datetime: row[:seconds][:machine] }= row[:seconds][:human] %td= row[:size] From 56d5ee3dfec628bd006cdbfb2de7f3230d313f1c Mon Sep 17 00:00:00 2001 From: jazzari Date: Sun, 16 Apr 2023 18:01:17 -0300 Subject: [PATCH 406/453] fix: change key in line 433 from licencia to license in en.yml #13092 --- config/locales/en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 3ddf681d..7059b79b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -430,7 +430,7 @@ en: title: 'Design' actions: 'Information about this design' url: 'Demo' - licencia: 'License' + license: 'License' licencia: title: 'License for the site and everything published on it' url: 'Read the license' From 6651781cac78f169cc220d16cc680748694dad72 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 17 Apr 2023 14:45:12 -0300 Subject: [PATCH 407/453] feat: poder ir a la lista de publicaciones del sitio --- app/views/sites/_status.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/sites/_status.haml b/app/views/sites/_status.haml index a731aa7d..4cf480df 100644 --- a/app/views/sites/_status.haml +++ b/app/views/sites/_status.haml @@ -16,4 +16,4 @@ - link = true = render 'bootstrap/alert' do - = link_to_if link, message.html_safe, site.url, class: 'alert-link' + = link_to_if link, message.html_safe, site_build_stats_path(site), class: 'alert-link' From 31b66373aec1073e1742f33585e568bddf6c7aff Mon Sep 17 00:00:00 2001 From: f Date: Mon, 17 Apr 2023 15:03:00 -0300 Subject: [PATCH 408/453] fix: mejorar el mensaje de espera, dando un accionable --- config/locales/en.yml | 4 ++-- config/locales/es.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index d92aa42a..76fc20ab 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -362,9 +362,9 @@ en: static_file_migration: 'File migration' find_and_replace: 'Search and replace' status: - building: "Your site is building, please wait to refresh this page..." + building: "Your site is building, refresh this page in ." not_published_yet: "Your site is being published for the first time, please wait up to 1 minute..." - available: "Your site is available! Click here to visit it." + available: "Your site is available! Click here to visit find all the different ways to visit it." index: title: 'My Sites' pull: 'Upgrade' diff --git a/config/locales/es.yml b/config/locales/es.yml index db116e37..f4c579f1 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -367,9 +367,9 @@ es: static_file_migration: 'Migración de archivos' find_and_replace: 'Búsqueda y reemplazo' status: - building: "Tu sitio se está publicando, por favor espera para recargar esta página..." + building: "Tu sitio se está publicando, recargá esta página en ." not_published_yet: "Tu sitio se está publicando por primera vez, por favor espera hasta un minuto..." - available: "¡Tu sitio está disponible! Cliquea aquí para visitarlo." + available: "¡Tu sitio está disponible! Cliqueá aquí para encontrar todas las formas en que podés visitarlo." index: title: 'Mis sitios' pull: 'Actualizar' From 6b9eead0abfe8b35fcd083d9f7270e2f668628b2 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 17 Apr 2023 15:13:37 -0300 Subject: [PATCH 409/453] fix: search placeholder in index.haml view #13095 --- app/views/posts/index.haml | 3 ++- config/locales/en.yml | 3 ++- config/locales/es.yml | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 4f814cda..1a12e405 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -49,7 +49,8 @@ - next if param == 'q' %input{ type: 'hidden', name: param, value: value } .form-group.flex-grow-0.m-0 - %input.form-control.border.border-magenta{ type: 'search', placeholder: 'Buscar', name: 'q', value: @filter_params[:q] } + .label.sr-only t('.search') + %input.form-control.border.border-magenta{ type: 'search', placeholder: t('.search'), name: 'q', value: @filter_params[:q] } %input.sr-only{ type: 'submit' } - if @site.locales.size > 1 diff --git a/config/locales/en.yml b/config/locales/en.yml index 3ddf681d..163d6021 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -544,7 +544,8 @@ en: remove_filter: 'Back' remove_filter_help: 'Remove the filter: %{filter}' categories: 'Everything' - index: 'Posts' + index: + search: 'search' edit: 'Edit' preview: btn: 'Preliminary version' diff --git a/config/locales/es.yml b/config/locales/es.yml index 01f1085c..b67db8ca 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -552,7 +552,8 @@ es: filter: 'Filtrar' remove_filter: 'Volver' remove_filter_help: 'Quitar este filtro: %{filter}' - index: 'Artículos' + index: + search: 'buscar' edit: 'Editar' preview: btn: 'Versión preliminar' From fcbed5003e28953a90d1ac317b5016dd012f74a9 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 17 Apr 2023 16:15:09 -0300 Subject: [PATCH 410/453] fix: add missing sign = in view #13095 --- app/views/posts/index.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 1a12e405..ac2932f8 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -49,7 +49,7 @@ - next if param == 'q' %input{ type: 'hidden', name: param, value: value } .form-group.flex-grow-0.m-0 - .label.sr-only t('.search') + .label.sr-only = t('.search') %input.form-control.border.border-magenta{ type: 'search', placeholder: t('.search'), name: 'q', value: @filter_params[:q] } %input.sr-only{ type: 'submit' } From 19bf8fb8bf682381db1815a8f8836cdd564ffae9 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 17 Apr 2023 16:37:10 -0300 Subject: [PATCH 411/453] fix: capitalization en yml & fix in view #13095 --- app/views/posts/index.haml | 2 +- config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index ac2932f8..bceb0a24 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -49,7 +49,7 @@ - next if param == 'q' %input{ type: 'hidden', name: param, value: value } .form-group.flex-grow-0.m-0 - .label.sr-only = t('.search') + .label.sr-only= t('.search') %input.form-control.border.border-magenta{ type: 'search', placeholder: t('.search'), name: 'q', value: @filter_params[:q] } %input.sr-only{ type: 'submit' } diff --git a/config/locales/en.yml b/config/locales/en.yml index 163d6021..64f596d7 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -545,7 +545,7 @@ en: remove_filter_help: 'Remove the filter: %{filter}' categories: 'Everything' index: - search: 'search' + search: 'Search' edit: 'Edit' preview: btn: 'Preliminary version' diff --git a/config/locales/es.yml b/config/locales/es.yml index b67db8ca..6ad61228 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -553,7 +553,7 @@ es: remove_filter: 'Volver' remove_filter_help: 'Quitar este filtro: %{filter}' index: - search: 'buscar' + search: 'Buscar' edit: 'Editar' preview: btn: 'Versión preliminar' From 219c0f4fb6837808e415cff5142cae5921bf2916 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 17 Apr 2023 16:47:09 -0300 Subject: [PATCH 412/453] fix: label tag in view #13095 --- app/views/posts/index.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index bceb0a24..62760e85 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -49,7 +49,7 @@ - next if param == 'q' %input{ type: 'hidden', name: param, value: value } .form-group.flex-grow-0.m-0 - .label.sr-only= t('.search') + %label.sr-only= t('.search') %input.form-control.border.border-magenta{ type: 'search', placeholder: t('.search'), name: 'q', value: @filter_params[:q] } %input.sr-only{ type: 'submit' } From 85f959071912af407bb707cf4956d6211b88f673 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 17 Apr 2023 17:49:39 -0300 Subject: [PATCH 413/453] fix label in view #13095 --- app/views/posts/index.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 62760e85..d1a4f84d 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -49,7 +49,7 @@ - next if param == 'q' %input{ type: 'hidden', name: param, value: value } .form-group.flex-grow-0.m-0 - %label.sr-only= t('.search') + %label{for: 'q'}.sr-only= t('.search') %input.form-control.border.border-magenta{ type: 'search', placeholder: t('.search'), name: 'q', value: @filter_params[:q] } %input.sr-only{ type: 'submit' } From 6921a33f61ecd38c6726f9af7f3371e5d4d6009c Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 17 Apr 2023 17:59:35 -0300 Subject: [PATCH 414/453] fix: add id to input in view #13095 --- app/views/posts/index.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index d1a4f84d..60cc6245 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -50,7 +50,7 @@ %input{ type: 'hidden', name: param, value: value } .form-group.flex-grow-0.m-0 %label{for: 'q'}.sr-only= t('.search') - %input.form-control.border.border-magenta{ type: 'search', placeholder: t('.search'), name: 'q', value: @filter_params[:q] } + %input#q.form-control.border.border-magenta{ type: 'search', placeholder: t('.search'), name: 'q', value: @filter_params[:q] } %input.sr-only{ type: 'submit' } - if @site.locales.size > 1 From 7d9b96980ad6c96bc0d7d48345a9ca0af4cf46c5 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 17 Apr 2023 18:29:01 -0300 Subject: [PATCH 415/453] fix: establecer el color por defecto de los botones MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit si lo establecemos después de bootstrap, pisamos los colores de los botones --- app/assets/stylesheets/application.scss | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index bba48558..0f848946 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -29,6 +29,11 @@ $sizes: ( "70ch": 70ch, ); +.btn { + background-color: var(--foreground); + color: var(--background); +} + @import "bootstrap"; @import "editor"; @@ -204,8 +209,6 @@ svg { } .btn { - background-color: var(--foreground); - color: var(--background); border: none; border-radius: 0; margin-right: 0.3rem; From 35b79ed9b463cdf555be626c49895e795b39509f Mon Sep 17 00:00:00 2001 From: f Date: Mon, 17 Apr 2023 18:30:21 -0300 Subject: [PATCH 416/453] feat: organizar layouts #13072 --- app/models/layout.rb | 7 ++++++ app/models/site.rb | 1 + app/models/site/layout_ordering.rb | 38 ++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 app/models/site/layout_ordering.rb diff --git a/app/models/layout.rb b/app/models/layout.rb index c70829fa..efca66ee 100644 --- a/app/models/layout.rb +++ b/app/models/layout.rb @@ -9,6 +9,13 @@ Layout = Struct.new(:site, :name, :meta, :metadata, keyword_init: true) do name.to_s end + # Obtiene todos los layouts (schemas) dependientes de este. + # + # @return [Array] + def schemas + @schemas ||= site.layouts.to_h.slice(*site.schema_organization[name]).values + end + def attributes @attributes ||= metadata.keys.map(&:to_sym) end diff --git a/app/models/site.rb b/app/models/site.rb index 3f2aa34e..521f298d 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -9,6 +9,7 @@ class Site < ApplicationRecord include Site::Api include Site::DeployDependencies include Site::BuildStats + include Site::LayoutOrdering include Tienda # Cifrar la llave privada que cifra y decifra campos ocultos. Sutty diff --git a/app/models/site/layout_ordering.rb b/app/models/site/layout_ordering.rb new file mode 100644 index 00000000..9fecbf21 --- /dev/null +++ b/app/models/site/layout_ordering.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +class Site + # Obtiene un listado de layouts (schemas) + module LayoutOrdering + extend ActiveSupport::Concern + + included do + + # Obtiene o genera un listado de layouts (schemas) con sus + # dependencias, para poder generar un árbol. + # + # Por defecto, si el sitio no lo soporta, se obtienen los layouts + # ordenados alfabéticamente por traducción. + # + # @return [Hash] + def schema_organization + @schema_organization ||= + begin + schema_organization = data.dig('schema', 'organization') + schema_organization&.symbolize_keys! + schema_organization&.transform_values! do |ary| + ary.map(&:to_sym) + end + + schema_organization || + begin + layouts = self.layouts.sort_by(&:humanized_name).map(&:name) + Hash[layouts.zip([].fill([], 0, layouts.size))] + end + end + end + + # TODO: Deprecar cuando renombremos layouts a schemas + alias layout_organization schema_organization + end + end +end From 5c976377387d62bf515bb6d4cbf103029984b780 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 17 Apr 2023 18:31:51 -0300 Subject: [PATCH 417/453] =?UTF-8?q?feat:=20mostrar=20la=20lista=20de=20art?= =?UTF-8?q?=C3=ADculos=20organizada=20#13072?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/posts/index.haml | 16 ++++++---------- app/views/schemas/_add.haml | 1 + app/views/schemas/_filter.haml | 4 ++++ app/views/schemas/_row.haml | 12 ++++++++++++ config/locales/en.yml | 8 +++++--- config/locales/es.yml | 9 ++++++--- 6 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 app/views/schemas/_add.haml create mode 100644 app/views/schemas/_filter.haml create mode 100644 app/views/schemas/_row.haml diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 4f814cda..cbc67a60 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -6,16 +6,12 @@ = render 'sites/status', site: @site %h3= t('posts.new') - %table.mb-3 - - @site.layouts.sort_by(&:humanized_name).each do |layout| - - next if layout.hidden? - %tr - %th= layout.humanized_name - %td.pl-3= link_to t('posts.add'), new_site_post_path(@site, layout: layout.value), class: 'btn btn-secondary btn-sm' - - if @filter_params[:layout] == layout.name.to_s - %td= link_to t('posts.remove_filter'), site_posts_path(@site, **@filter_params.merge(layout: nil)), class: 'btn btn-primary btn-sm' - - else - %td= link_to t('posts.filter'), site_posts_path(@site, **@filter_params.merge(layout: layout.value)), class: 'btn btn-secondary btn-sm' + %table.table.table-sm.mb-3 + %tbody + - @site.schema_organization.each do |schema, _| + - schema = @site.layouts[schema] + - next if schema.hidden? + = render 'schemas/row', site: @site, schema: schema, filter: @filter_params - if policy(@site_stat).index? = link_to t('stats.index.title'), site_stats_path(@site), class: 'btn' diff --git a/app/views/schemas/_add.haml b/app/views/schemas/_add.haml new file mode 100644 index 00000000..0131a6bb --- /dev/null +++ b/app/views/schemas/_add.haml @@ -0,0 +1 @@ += link_to t('.add'), new_site_post_path(site, layout: schema.value), class: 'btn btn-secondary btn-sm m-0' diff --git a/app/views/schemas/_filter.haml b/app/views/schemas/_filter.haml new file mode 100644 index 00000000..c422c5b8 --- /dev/null +++ b/app/views/schemas/_filter.haml @@ -0,0 +1,4 @@ +- if filter[:layout] == schema.name.to_s + = link_to t('.remove'), site_posts_path(site, **filter.merge(layout: nil)), class: 'btn btn-primary btn-sm m-0' +- else + = link_to t('.filter'), site_posts_path(site, **filter.merge(layout: schema.value)), class: 'btn btn-secondary btn-sm m-0' diff --git a/app/views/schemas/_row.haml b/app/views/schemas/_row.haml new file mode 100644 index 00000000..9a759fd9 --- /dev/null +++ b/app/views/schemas/_row.haml @@ -0,0 +1,12 @@ +%tr + %th{ scope: 'row' } + - if local_assigns[:parent_schema] + %span.text-muted — + = schema.humanized_name + %td.px-0= render 'schemas/add', **local_assigns + %td.px-0= render 'schemas/filter', **local_assigns + +-# XXX: Solo un nivel de recursividad +- unless local_assigns[:parent_schema] + - schema.schemas.each do |s| + = render 'schemas/row', schema: s, site: site, filter: filter, parent_schema: schema diff --git a/config/locales/en.yml b/config/locales/en.yml index 3ddf681d..5da5fe4f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -539,9 +539,6 @@ en: order: 'Order' content: 'Text' new: 'Post types' - add: 'Add' - filter: 'Filter' - remove_filter: 'Back' remove_filter_help: 'Remove the filter: %{filter}' categories: 'Everything' index: 'Posts' @@ -697,3 +694,8 @@ en: queries: show: empty: '(empty)' + schemas: + add: 'Add' + filter: + filter: 'Filter' + remove: 'Back' diff --git a/config/locales/es.yml b/config/locales/es.yml index 01f1085c..829e0ccc 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -548,9 +548,6 @@ es: content: 'Cuerpo del artículo' categories: 'Todos' new: 'Tipos de artículos' - add: 'Agregar' - filter: 'Filtrar' - remove_filter: 'Volver' remove_filter_help: 'Quitar este filtro: %{filter}' index: 'Artículos' edit: 'Editar' @@ -705,3 +702,9 @@ es: queries: show: empty: '(vacío)' + schemas: + add: + add: 'Agregar' + filter: + filter: 'Filtrar' + remove: 'Volver' From fbc822ba5ddda3d92a1b50f887756f75618819c6 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 17 Apr 2023 20:02:00 -0300 Subject: [PATCH 418/453] fix: attributes on label in view #13095 --- app/views/posts/index.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 60cc6245..9159d5e7 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -49,7 +49,7 @@ - next if param == 'q' %input{ type: 'hidden', name: param, value: value } .form-group.flex-grow-0.m-0 - %label{for: 'q'}.sr-only= t('.search') + %label.sr-only{for: 'q'}= t('.search') %input#q.form-control.border.border-magenta{ type: 'search', placeholder: t('.search'), name: 'q', value: @filter_params[:q] } %input.sr-only{ type: 'submit' } From 6e5fcc17ff25adedbbb9c5f5f4ad1a085cc6ef15 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 18 Apr 2023 17:38:45 -0300 Subject: [PATCH 419/453] fix: palabra sobrante --- config/locales/en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 76fc20ab..2423ab61 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -364,7 +364,7 @@ en: status: building: "Your site is building, refresh this page in ." not_published_yet: "Your site is being published for the first time, please wait up to 1 minute..." - available: "Your site is available! Click here to visit find all the different ways to visit it." + available: "Your site is available! Click here to find all the different ways to visit it." index: title: 'My Sites' pull: 'Upgrade' From bd48b8561cfbf9a01bde04e41d5a95b76ad63a2b Mon Sep 17 00:00:00 2001 From: f Date: Wed, 19 Apr 2023 18:04:22 -0300 Subject: [PATCH 420/453] fix: no generar urls a partir de los protocolos #13163 porque ipfs es ipns (!) --- app/models/deploy_distributed_press.rb | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 32a3049e..a9494658 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -80,7 +80,7 @@ class DeployDistributedPress < Deploy # Devuelve las URLs de todos los protocolos def urls - protocol_urls + gateway_urls + gateway_urls end private @@ -93,14 +93,6 @@ class DeployDistributedPress < Deploy end end - def protocol_urls - remote_info.dig(:distributed_press, :protocols).select do |_, enabled| - enabled - end.map do |protocol, _| - "#{protocol}://#{site.hostname}" - end - end - # El cliente de la API # # TODO: cuando soportemos más, tiene que haber una relación entre From 76ddbaf5ab90272daaad862e1e7488ffccc5834f Mon Sep 17 00:00:00 2001 From: f Date: Thu, 20 Apr 2023 18:14:48 -0300 Subject: [PATCH 421/453] =?UTF-8?q?fix:=20vincular=20a=20saber=20m=C3=A1s?= =?UTF-8?q?=20#10449?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 3ddf681d..941280c0 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -302,7 +302,7 @@ en: storage network may continue retaining copies of the data indefinitely. - [Learn more](https://ffdweb.org/building-distributed-press-a-publishing-tool-for-the-decentralized-web/) + [Learn more](https://sutty.nl/learn-more-about-publish-to-dweb-functionality/) stats: index: title: Statistics diff --git a/config/locales/es.yml b/config/locales/es.yml index 01f1085c..af84b474 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -307,7 +307,7 @@ es: nodos en la red de almacenamiento distribuida puedan retener copias de tu contenido indefinidamente. - [Saber más (en inglés)](https://ffdweb.org/building-distributed-press-a-publishing-tool-for-the-decentralized-web/) + [Saber más](https://sutty.nl/saber-mas-sobre-publicar-a-la-web-distribuida/) stats: index: title: Estadísticas From f35df41d1be8b0e699246a27091a499c8ff4a752 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 20 Apr 2023 18:17:41 -0300 Subject: [PATCH 422/453] =?UTF-8?q?fix:=20usar=20guionado=20en=20t=C3=ADtu?= =?UTF-8?q?lo=20y=20descripci=C3=B3n=20#13160?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/stylesheets/application.scss | 2 ++ app/views/posts/index.haml | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index bba48558..fa07a185 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -383,6 +383,8 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); } } +.hyphens { hyphens: auto; } + /* * Modificadores de Bootstrap que no tienen versión responsive. */ diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 4f814cda..ba8f3ee5 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -1,7 +1,9 @@ %main.row %aside.menu.col-md-3 - %h1= @site.title - %p.lead= @site.description + .hyphens{ lang: @site.default_locale } + %h1= @site.title + %p.lead= @site.description + - cache_if @usuarie, [@site, I18n.locale] do = render 'sites/status', site: @site From 7e8bcc55a11ab2fbdbf5dbba93e3cec6d072aafc Mon Sep 17 00:00:00 2001 From: f Date: Thu, 20 Apr 2023 18:22:00 -0300 Subject: [PATCH 423/453] feat: indicar que se puede publicar el sitio #13178 --- app/models/site/build_stats.rb | 7 +++++++ app/views/sites/_status.haml | 2 ++ config/locales/en.yml | 1 + config/locales/es.yml | 1 + 4 files changed, 11 insertions(+) diff --git a/app/models/site/build_stats.rb b/app/models/site/build_stats.rb index 6eebcc84..64e689b6 100644 --- a/app/models/site/build_stats.rb +++ b/app/models/site/build_stats.rb @@ -40,6 +40,13 @@ class Site def not_published_yet? build_stats.jekyll.where(status: true).count.zero? end + + # Hubo cambios desde la última publicación? + # + # @return [Boolean] + def awaiting_publication? + updated_at > (build_stats.jekyll.where(status: true).last&.created_at || updated_at) + end end end end diff --git a/app/views/sites/_status.haml b/app/views/sites/_status.haml index a731aa7d..2d0de7b9 100644 --- a/app/views/sites/_status.haml +++ b/app/views/sites/_status.haml @@ -1,6 +1,8 @@ - link = nil - if site.not_published_yet? - message = t('.not_published_yet') +- elsif site.awaiting_publication? + - message = t('.awaiting_publication') - if site.building? - if site.average_publication_time_calculable? - average_building_time = site.average_publication_time diff --git a/config/locales/en.yml b/config/locales/en.yml index 3ddf681d..afb470c8 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -365,6 +365,7 @@ en: building: "Your site is building, please wait to refresh this page..." not_published_yet: "Your site is being published for the first time, please wait up to 1 minute..." available: "Your site is available! Click here to visit it." + awaiting_publication: "There are unpublished changes. Click the button below and wait a moment to find them on your site." index: title: 'My Sites' pull: 'Upgrade' diff --git a/config/locales/es.yml b/config/locales/es.yml index 01f1085c..d80e2676 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -370,6 +370,7 @@ es: building: "Tu sitio se está publicando, por favor espera para recargar esta página..." not_published_yet: "Tu sitio se está publicando por primera vez, por favor espera hasta un minuto..." available: "¡Tu sitio está disponible! Cliquea aquí para visitarlo." + awaiting_publication: "Hay cambios sin publicar, cliqueá el botón debajo y espera un momento para encontrarlos en tu sitio." index: title: 'Mis sitios' pull: 'Actualizar' From 0567e491eedb6c7bf59718b4b684c8c7796b7a53 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 20 Apr 2023 18:22:21 -0300 Subject: [PATCH 424/453] fix: poder ver los mensajes en el orden correcto --- app/views/sites/_status.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/sites/_status.haml b/app/views/sites/_status.haml index 2d0de7b9..9a671d71 100644 --- a/app/views/sites/_status.haml +++ b/app/views/sites/_status.haml @@ -3,7 +3,7 @@ - message = t('.not_published_yet') - elsif site.awaiting_publication? - message = t('.awaiting_publication') -- if site.building? +- elsif site.building? - if site.average_publication_time_calculable? - average_building_time = site.average_publication_time - elsif !site.similar_sites? From 498c8cc5ad5653631b7d8b9d3133111eb4ce3832 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 20 Apr 2023 21:14:12 -0300 Subject: [PATCH 425/453] fix: usar los posts indexados para obtener la diferencia --- app/models/site/build_stats.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/site/build_stats.rb b/app/models/site/build_stats.rb index 64e689b6..63761bae 100644 --- a/app/models/site/build_stats.rb +++ b/app/models/site/build_stats.rb @@ -45,7 +45,7 @@ class Site # # @return [Boolean] def awaiting_publication? - updated_at > (build_stats.jekyll.where(status: true).last&.created_at || updated_at) + waiting? && updated_at >= (indexed_posts.order(updated_at: :desc).select(:updated_at).first&.updated_at || 1.second.ago) end end end From da873d2efe41ae63d5bb3f63eebfdf6e490a2b10 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 21 Apr 2023 12:10:03 -0300 Subject: [PATCH 426/453] =?UTF-8?q?fix:=20detectar=20si=20el=20sitio=20o?= =?UTF-8?q?=20los=20art=C3=ADculos=20fueron=20modificados=20luego=20de=20p?= =?UTF-8?q?ublicar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/site/build_stats.rb | 41 ++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/app/models/site/build_stats.rb b/app/models/site/build_stats.rb index 63761bae..23931140 100644 --- a/app/models/site/build_stats.rb +++ b/app/models/site/build_stats.rb @@ -41,11 +41,48 @@ class Site build_stats.jekyll.where(status: true).count.zero? end - # Hubo cambios desde la última publicación? + # Cambios posibles luego de la última publicación exitosa: + # + # * Artículos modificados + # * Configuración modificada + # * Métodos de publicación añadidos # # @return [Boolean] def awaiting_publication? - waiting? && updated_at >= (indexed_posts.order(updated_at: :desc).select(:updated_at).first&.updated_at || 1.second.ago) + waiting? && (post_publication_pending? || configuration_publication_pending?) + end + + # Se modificaron artículos después de publicar el sitio por última + # vez + # + # @return [Boolean] + def post_publication_pending? + last_indexed_post_time > last_publication_time + end + + # Se modificó el sitio después de publicarlo por última vez + # + # @return [Boolean] + def configuration_publication_pending? + updated_at > last_publication_time + end + + private + + # Encuentra el último artículo modificado. Si no hay ninguno, + # devuelve la fecha de modificación del sitio. + # + # @return [Time] + def last_indexed_post_time + indexed_posts.order(updated_at: :desc).select(:updated_at).first&.updated_at || updated_at + end + + # Encuentra la fecha de última publicación exitosa, si no hay + # ninguno, devuelve la fecha de modificación del sitio. + # + # @return [Time] + def last_publication_time + build_stats.jekyll.where(status: true).order(created_at: :desc).select(:created_at).first&.created_at || updated_at end end end From 04c9ff5319000c27f404682d712c2f1738886871 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 21 Apr 2023 12:15:22 -0300 Subject: [PATCH 427/453] =?UTF-8?q?fix:=20detectar=20cambios=20de=20config?= =?UTF-8?q?uraci=C3=B3n=20por=20separado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/site/build_stats.rb | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/app/models/site/build_stats.rb b/app/models/site/build_stats.rb index 23931140..0d1d5a57 100644 --- a/app/models/site/build_stats.rb +++ b/app/models/site/build_stats.rb @@ -49,34 +49,49 @@ class Site # # @return [Boolean] def awaiting_publication? - waiting? && (post_publication_pending? || configuration_publication_pending?) + waiting? && (post_pending? || deploy_pending? || configuration_pending?) end # Se modificaron artículos después de publicar el sitio por última # vez # # @return [Boolean] - def post_publication_pending? + def post_pending? last_indexed_post_time > last_publication_time end # Se modificó el sitio después de publicarlo por última vez # # @return [Boolean] - def configuration_publication_pending? - updated_at > last_publication_time + def deploy_pending? + last_deploy_time > last_publication_time + end + + # Se modificó la configuración del sitio + # + # @return [Boolean] + def configuration_pending? + last_configuration_time > last_publication_time end private - # Encuentra el último artículo modificado. Si no hay ninguno, - # devuelve la fecha de modificación del sitio. + # Encuentra la fecha del último artículo modificado. Si no hay + # ninguno, devuelve la fecha de modificación del sitio. # # @return [Time] def last_indexed_post_time indexed_posts.order(updated_at: :desc).select(:updated_at).first&.updated_at || updated_at end + # Encuentra la fecha de última modificación de los métodos de + # publicación. + # + # @return [Time] + def last_deploy_time + deploys.order(updated_at: :desc).select(:updated_at).first&.updated_at || updated_at + end + # Encuentra la fecha de última publicación exitosa, si no hay # ninguno, devuelve la fecha de modificación del sitio. # @@ -84,6 +99,13 @@ class Site def last_publication_time build_stats.jekyll.where(status: true).order(created_at: :desc).select(:created_at).first&.created_at || updated_at end + + # Fecha de última modificación de la configuración + # + # @return [Time] + def last_configuration_time + File.mtime(config.path) + end end end end From 8ed5aedf757db07da0cbfbabe156913886c1ea5f Mon Sep 17 00:00:00 2001 From: f Date: Fri, 21 Apr 2023 12:31:46 -0300 Subject: [PATCH 428/453] feat: componente de cabecera de sitio --- app/views/posts/index.haml | 4 +--- app/views/sites/_header.haml | 3 +++ 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 app/views/sites/_header.haml diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index ba8f3ee5..dd0bf052 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -1,8 +1,6 @@ %main.row %aside.menu.col-md-3 - .hyphens{ lang: @site.default_locale } - %h1= @site.title - %p.lead= @site.description + = render 'sites/header', site: @site - cache_if @usuarie, [@site, I18n.locale] do = render 'sites/status', site: @site diff --git a/app/views/sites/_header.haml b/app/views/sites/_header.haml new file mode 100644 index 00000000..c8931041 --- /dev/null +++ b/app/views/sites/_header.haml @@ -0,0 +1,3 @@ +.hyphens{ lang: site.default_locale } + %h1= site.title + %p.lead= site.description From f1aefbcb34526a02acdd41b9bba80bcb9de6c4d5 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 21 Apr 2023 12:36:40 -0300 Subject: [PATCH 429/453] fix: guionar titulo y descripciones largas #13096 --- app/views/build_stats/index.haml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/views/build_stats/index.haml b/app/views/build_stats/index.haml index 27dc20d1..27c063f9 100644 --- a/app/views/build_stats/index.haml +++ b/app/views/build_stats/index.haml @@ -1,7 +1,6 @@ %main.row %aside.menu.col-md-3 - %h1= @site.title - %p.lead= @site.description + = render 'sites/header', site: @site .col %h1= t('.title') From 3f4517b4272ee4a3cc10ef7602359f41dc4b79c7 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 21 Apr 2023 12:40:36 -0300 Subject: [PATCH 430/453] fix: no cachear el estado --- app/views/posts/index.haml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 4f814cda..2a0b92f8 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -2,8 +2,7 @@ %aside.menu.col-md-3 %h1= @site.title %p.lead= @site.description - - cache_if @usuarie, [@site, I18n.locale] do - = render 'sites/status', site: @site + = render 'sites/status', site: @site %h3= t('posts.new') %table.mb-3 From 04ad7e2324096378d1aa3ac0489b68e79d05b2ef Mon Sep 17 00:00:00 2001 From: f Date: Fri, 21 Apr 2023 13:47:02 -0300 Subject: [PATCH 431/453] =?UTF-8?q?fix:=20usar=20la=20fecha=20de=20creaci?= =?UTF-8?q?=C3=B3n=20del=20deploy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit para saber si hubo publicaciones después de su creación. no usamos la fecha de modificación porque la configuración manual solo los crea o los elimina y los métodos pueden automodificarse durante la publicación. --- app/models/site/build_stats.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/site/build_stats.rb b/app/models/site/build_stats.rb index 0d1d5a57..071b1eab 100644 --- a/app/models/site/build_stats.rb +++ b/app/models/site/build_stats.rb @@ -89,7 +89,7 @@ class Site # # @return [Time] def last_deploy_time - deploys.order(updated_at: :desc).select(:updated_at).first&.updated_at || updated_at + deploys.order(created_at: :desc).select(:created_at).first&.created_at || updated_at end # Encuentra la fecha de última publicación exitosa, si no hay From d8c432b71ad5c682d3cbde79c423d7a7c75e51db Mon Sep 17 00:00:00 2001 From: f Date: Fri, 21 Apr 2023 14:14:39 -0300 Subject: [PATCH 432/453] fix: ocupar menos espacio #13199 --- app/views/schemas/_row.haml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/views/schemas/_row.haml b/app/views/schemas/_row.haml index 9a759fd9..1d1fca87 100644 --- a/app/views/schemas/_row.haml +++ b/app/views/schemas/_row.haml @@ -1,10 +1,11 @@ %tr - %th{ scope: 'row' } + %th.w-100{ scope: 'row' } - if local_assigns[:parent_schema] %span.text-muted — = schema.humanized_name - %td.px-0= render 'schemas/add', **local_assigns - %td.px-0= render 'schemas/filter', **local_assigns + %td.px-0.text-nowrap + = render 'schemas/add', **local_assigns + = render 'schemas/filter', **local_assigns -# XXX: Solo un nivel de recursividad - unless local_assigns[:parent_schema] From 834715d559d8275210bc6c510b45a1d466c42d34 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 21 Apr 2023 14:17:09 -0300 Subject: [PATCH 433/453] =?UTF-8?q?fix:=20traducir=20el=20bot=C3=B3n=20de?= =?UTF-8?q?=20agregar=20#13177?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/en.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 5da5fe4f..05223ba3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -695,7 +695,8 @@ en: show: empty: '(empty)' schemas: - add: 'Add' + add: + add: 'Add' filter: filter: 'Filter' remove: 'Back' From 79fd1b7fbbc6e7fcc92c143e775a3490adde187d Mon Sep 17 00:00:00 2001 From: f Date: Fri, 21 Apr 2023 15:24:40 -0300 Subject: [PATCH 434/453] BREAKING CHANGE: usar rsyncd en lugar de ssh #13171 --- app/services/site_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 5d28bf91..d9c7783e 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -215,7 +215,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # 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: "sutty@#{node}:") + site.deploys.build(type: 'DeployFullRsync', destination: "rsync://#{node}/deploys/") end end From a6bba8c3cbb84051fd709fb45be3eb6ae7e3ce14 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 21 Apr 2023 15:42:16 -0300 Subject: [PATCH 435/453] =?UTF-8?q?fix:=20cambiar=20las=20direcciones=20de?= =?UTF-8?q?=20sincronizaci=C3=B3n=20a=20rsyncd?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...421182627_change_full_rsync_destination.rb | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 db/migrate/20230421182627_change_full_rsync_destination.rb diff --git a/db/migrate/20230421182627_change_full_rsync_destination.rb b/db/migrate/20230421182627_change_full_rsync_destination.rb new file mode 100644 index 00000000..47352139 --- /dev/null +++ b/db/migrate/20230421182627_change_full_rsync_destination.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +# Envía los cambios a través de rsyncd +class ChangeFullRsyncDestination < ActiveRecord::Migration[6.1] + def up + DeployFullRsync.find_each do |deploy| + Rails.application.nodes.each do |node| + deploy.destination = "rsync://#{node}/deploys/" + deploy.save + end + end + end + + def down + DeployFullRsync.find_each do |deploy| + Rails.application.nodes.each do |node| + deploy.destination = "sutty@#{node}:" + deploy.save + end + end + end +end From 79398d0448bd707906c2a15e719fc76acb72db98 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 21 Apr 2023 15:44:22 -0300 Subject: [PATCH 436/453] =?UTF-8?q?fixup!=20fix:=20cambiar=20las=20direcci?= =?UTF-8?q?ones=20de=20sincronizaci=C3=B3n=20a=20rsyncd?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/migrate/20230421182627_change_full_rsync_destination.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20230421182627_change_full_rsync_destination.rb b/db/migrate/20230421182627_change_full_rsync_destination.rb index 47352139..3a22aea6 100644 --- a/db/migrate/20230421182627_change_full_rsync_destination.rb +++ b/db/migrate/20230421182627_change_full_rsync_destination.rb @@ -5,7 +5,7 @@ class ChangeFullRsyncDestination < ActiveRecord::Migration[6.1] def up DeployFullRsync.find_each do |deploy| Rails.application.nodes.each do |node| - deploy.destination = "rsync://#{node}/deploys/" + deploy.destination = "rsync://rsyncd.#{node}/deploys/" deploy.save end end From 4f74c6f6cad3e62d2841e3811e9f31add3f8b566 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 21 Apr 2023 15:48:09 -0300 Subject: [PATCH 437/453] fix: no configurar ssh para rsyncd --- app/models/deploy_rsync.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/deploy_rsync.rb b/app/models/deploy_rsync.rb index 1dff2d99..fcc5a65d 100644 --- a/app/models/deploy_rsync.rb +++ b/app/models/deploy_rsync.rb @@ -38,6 +38,7 @@ class DeployRsync < Deploy # # @return [Boolean] def ssh? + return true if destination.start_with? 'rsync://' user, host = user_host ssh_available = false From f1e53c04db1a59d8f15f46e6d839eb21d586d946 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 22 Apr 2023 18:18:30 -0300 Subject: [PATCH 438/453] fix: ir al contenedor de rsyncd --- app/services/site_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index d9c7783e..5a2b7dde 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -215,7 +215,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # 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://#{node}/deploys/") + site.deploys.build(type: 'DeployFullRsync', destination: "rsync://rsyncd.#{node}/deploys/") end end From b78dd1661ad1a98be8fdbd535a157d6d16a61eb5 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 24 Apr 2023 14:41:45 -0300 Subject: [PATCH 439/453] fix: guardar el hostname --- app/services/site_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 5a2b7dde..696acd57 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -215,7 +215,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # 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/") + site.deploys.build(type: 'DeployFullRsync', destination: "rsync://rsyncd.#{node}/deploys/", hostname: node) end end From 3a99e1a8677e3a3ec13212394eac6d7418846efe Mon Sep 17 00:00:00 2001 From: f Date: Mon, 24 Apr 2023 14:42:02 -0300 Subject: [PATCH 440/453] fix: usar el hostname como url --- app/models/deploy_full_rsync.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/models/deploy_full_rsync.rb b/app/models/deploy_full_rsync.rb index b8c48eab..b417470a 100644 --- a/app/models/deploy_full_rsync.rb +++ b/app/models/deploy_full_rsync.rb @@ -27,8 +27,4 @@ class DeployFullRsync < DeployRsync result.present? && result.all? end - - def url - "https://#{user_host.last}/" - end end From 47969cc410c42fe912e5cd0634db54b0f58b26b7 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 24 Apr 2023 14:46:56 -0300 Subject: [PATCH 441/453] fix: no sincronizar los sitios de testeo --- app/services/site_service.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 696acd57..2c29538c 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -15,7 +15,8 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do add_role temporal: false, rol: 'usuarie' site.deploys.build type: 'DeployLocal' - sync_nodes + # 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 From 61bc23babec3e4b6ec4f265eccada5e8bd77a4a6 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 24 Apr 2023 14:55:46 -0300 Subject: [PATCH 442/453] feat: agregar nodo en los logs --- db/migrate/20230424174544_add_node_to_access_logs.rb | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 db/migrate/20230424174544_add_node_to_access_logs.rb diff --git a/db/migrate/20230424174544_add_node_to_access_logs.rb b/db/migrate/20230424174544_add_node_to_access_logs.rb new file mode 100644 index 00000000..805fbc27 --- /dev/null +++ b/db/migrate/20230424174544_add_node_to_access_logs.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# Agrega la columna de nodo a los logs +class AddNodeToAccessLogs < ActiveRecord::Migration[6.1] + def change + add_column :access_logs, :node, :string, index: true + end +end From 1cf5ca5953da4f54f18b2951a2781b325f77d05c Mon Sep 17 00:00:00 2001 From: f Date: Mon, 24 Apr 2023 17:03:38 -0300 Subject: [PATCH 443/453] =?UTF-8?q?fix:=20aceptar=20la=20invitaci=C3=B3n?= =?UTF-8?q?=20al=20confirmar=20la=20cuenta=20#13247?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/usuarie.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/models/usuarie.rb b/app/models/usuarie.rb index 9b9fd4e6..0dcf917d 100644 --- a/app/models/usuarie.rb +++ b/app/models/usuarie.rb @@ -12,6 +12,7 @@ class Usuarie < ApplicationRecord validates_with EmailAddress::ActiveRecordValidator, field: :email before_create :lang_from_locale! + before_update :accept_invitation_after_confirmation! has_many :roles has_many :sites, through: :roles @@ -54,4 +55,13 @@ class Usuarie < ApplicationRecord def lang_from_locale! self.lang = I18n.locale.to_s end + + # Si le usuarie (re)confirma su cuenta con una invitación pendiente, + # considerarla aceptada también. + def accept_invitation_after_confirmation! + if confirmed? + self.invitation_token = nil + self.invitation_accepted_at ||= Time.now.utc + end + end end From 5c467e08b88d3c0db22d496fee1c7591adfcd3ec Mon Sep 17 00:00:00 2001 From: f Date: Mon, 24 Apr 2023 17:21:24 -0300 Subject: [PATCH 444/453] =?UTF-8?q?fix:=20aceptar=20la=20invitaci=C3=B3n?= =?UTF-8?q?=20tambi=C3=A9n=20confirma=20el=20correo=20#13247?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit les usuaries que no confirmaron su correo quedaban en un loop si luego eran invitades a un sitio. --- app/models/usuarie.rb | 6 ++++++ app/views/devise/mailer/invitation_instructions.html.haml | 2 +- app/views/devise/mailer/invitation_instructions.text.haml | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/models/usuarie.rb b/app/models/usuarie.rb index 0dcf917d..ef13239b 100644 --- a/app/models/usuarie.rb +++ b/app/models/usuarie.rb @@ -50,6 +50,12 @@ class Usuarie < ApplicationRecord end end + # Les usuaries necesitan link de invitación si no tenían cuenta + # o todavía no la confirmaron + def needs_invitation_link? + (created_by_invite? && !invitation_accepted?) || !confirmed? + end + private def lang_from_locale! diff --git a/app/views/devise/mailer/invitation_instructions.html.haml b/app/views/devise/mailer/invitation_instructions.html.haml index b12cef64..1cdcb2a9 100644 --- a/app/views/devise/mailer/invitation_instructions.html.haml +++ b/app/views/devise/mailer/invitation_instructions.html.haml @@ -8,7 +8,7 @@ %h1= site.title %p= site.description -- if @resource.created_by_invite? && !@resource.invitation_accepted? +- if @resource.needs_invitation_link? %p= link_to t('devise.mailer.invitation_instructions.accept'), accept_invitation_url(@resource, invitation_token: @token, change_locale_to: @resource.lang) diff --git a/app/views/devise/mailer/invitation_instructions.text.haml b/app/views/devise/mailer/invitation_instructions.text.haml index bb496733..eab021ef 100644 --- a/app/views/devise/mailer/invitation_instructions.text.haml +++ b/app/views/devise/mailer/invitation_instructions.text.haml @@ -9,7 +9,7 @@ \ = site.description \ -- if @resource.created_by_invite? && !@resource.invitation_accepted? +- if @resource.needs_invitation_link? = accept_invitation_url(@resource, invitation_token: @token, change_locale_to: @resource.lang) \ - if @resource.invitation_due_at From 229914e8493a158192c5ee9bc10ede0516bbe0cc Mon Sep 17 00:00:00 2001 From: f Date: Mon, 24 Apr 2023 17:44:04 -0300 Subject: [PATCH 445/453] =?UTF-8?q?fix:=20confirmar=20usuaries=20en=20la?= =?UTF-8?q?=20invitaci=C3=B3n=20#13247?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/usuaries_controller.rb | 6 ++++++ app/models/usuarie.rb | 4 ++-- app/views/devise/mailer/invitation_instructions.html.haml | 4 ++++ app/views/devise/mailer/invitation_instructions.text.haml | 4 ++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index 9e9cac71..28513e63 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -96,6 +96,12 @@ class UsuariesController < ApplicationController # XXX: La invitación tiene que ser enviada luego de crear el rol if role.persisted? + # Si es una cuenta manual que no está confirmada aun, + # aprovechar para reconfirmarla. + if !usuarie.confirmed? && !usuarie.created_by_invite? + usuarie.generate_confirmation_token! + end + usuarie.deliver_invitation else raise ArgumentError, role.errors.full_messages diff --git a/app/models/usuarie.rb b/app/models/usuarie.rb index ef13239b..e25a6785 100644 --- a/app/models/usuarie.rb +++ b/app/models/usuarie.rb @@ -51,9 +51,9 @@ class Usuarie < ApplicationRecord end # Les usuaries necesitan link de invitación si no tenían cuenta - # o todavía no la confirmaron + # y todavía no aceptaron la invitación anterior. def needs_invitation_link? - (created_by_invite? && !invitation_accepted?) || !confirmed? + created_by_invite? && !invitation_accepted? end private diff --git a/app/views/devise/mailer/invitation_instructions.html.haml b/app/views/devise/mailer/invitation_instructions.html.haml index 1cdcb2a9..6370ed1a 100644 --- a/app/views/devise/mailer/invitation_instructions.html.haml +++ b/app/views/devise/mailer/invitation_instructions.html.haml @@ -18,5 +18,9 @@ format: :'devise.mailer.invitation_instructions.accept_until_format')) %p= t('devise.mailer.invitation_instructions.ignore') +- elsif !@resource.confirmed? && @resource.confirmation_token + = confirmation_url(@resource, confirmation_token: @token, change_locale_to: @resource.lang) + \ + = t('devise.mailer.invitation_instructions.ignore') - else %p= link_to t('devise.mailer.invitation_instructions.sign_in'), root_url diff --git a/app/views/devise/mailer/invitation_instructions.text.haml b/app/views/devise/mailer/invitation_instructions.text.haml index eab021ef..719c7cd2 100644 --- a/app/views/devise/mailer/invitation_instructions.text.haml +++ b/app/views/devise/mailer/invitation_instructions.text.haml @@ -18,6 +18,10 @@ format: :'devise.mailer.invitation_instructions.accept_until_format')) \ = t('devise.mailer.invitation_instructions.ignore') +- elsif !@resource.confirmed? && @resource.confirmation_token + = confirmation_url(@resource, confirmation_token: @token, change_locale_to: @resource.lang) + \ + = t('devise.mailer.invitation_instructions.ignore') - else = root_url(change_locale_to: @resource.lang) = t('devise.mailer.invitation_instructions.sign_in') From e35d09e343fa79232edeae617de849e958f64781 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 24 Apr 2023 18:07:57 -0300 Subject: [PATCH 446/453] fix: si le usuarie creo su cuenta manualmente no necesita ser invitade --- app/models/usuarie.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/models/usuarie.rb b/app/models/usuarie.rb index e25a6785..2bc7a1b5 100644 --- a/app/models/usuarie.rb +++ b/app/models/usuarie.rb @@ -12,6 +12,7 @@ class Usuarie < ApplicationRecord validates_with EmailAddress::ActiveRecordValidator, field: :email before_create :lang_from_locale! + before_update :remove_confirmation_invitation_inconsistencies! before_update :accept_invitation_after_confirmation! has_many :roles @@ -62,6 +63,13 @@ class Usuarie < ApplicationRecord self.lang = I18n.locale.to_s end + # El invitation_token solo es necesario cuando fue creade por otre + # usuarie. De lo contrario lo que queremos es un proceso de + # confirmación. + def remove_confirmation_invitation_inconsistencies! + self.invitation_token = nil unless created_by_invite? + end + # Si le usuarie (re)confirma su cuenta con una invitación pendiente, # considerarla aceptada también. def accept_invitation_after_confirmation! From 3a7c9c6b623f68a445441e58de8b98094401c357 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 24 Apr 2023 18:12:40 -0300 Subject: [PATCH 447/453] =?UTF-8?q?fixup!=20fix:=20confirmar=20usuaries=20?= =?UTF-8?q?en=20la=20invitaci=C3=B3n=20#13247?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/usuaries_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index 28513e63..76d17541 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -99,7 +99,7 @@ class UsuariesController < ApplicationController # Si es una cuenta manual que no está confirmada aun, # aprovechar para reconfirmarla. if !usuarie.confirmed? && !usuarie.created_by_invite? - usuarie.generate_confirmation_token! + usuarie.send :generate_confirmation_token! end usuarie.deliver_invitation From 838b398f289be22158ea81857d664cebc95398b7 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 24 Apr 2023 18:58:05 -0300 Subject: [PATCH 448/453] =?UTF-8?q?fix:=20cambiar=20el=20token=20de=20conf?= =?UTF-8?q?irmaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/usuaries_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/usuaries_controller.rb b/app/controllers/usuaries_controller.rb index 76d17541..6924c860 100644 --- a/app/controllers/usuaries_controller.rb +++ b/app/controllers/usuaries_controller.rb @@ -99,6 +99,7 @@ class UsuariesController < ApplicationController # Si es una cuenta manual que no está confirmada aun, # aprovechar para reconfirmarla. if !usuarie.confirmed? && !usuarie.created_by_invite? + usuarie.confirmation_token = nil usuarie.send :generate_confirmation_token! end From 18de36939f50266ba6b1707c41dc769bd51cd65d Mon Sep 17 00:00:00 2001 From: f Date: Mon, 24 Apr 2023 19:00:23 -0300 Subject: [PATCH 449/453] fix: usar el token correcto --- app/views/devise/mailer/invitation_instructions.html.haml | 2 +- app/views/devise/mailer/invitation_instructions.text.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/devise/mailer/invitation_instructions.html.haml b/app/views/devise/mailer/invitation_instructions.html.haml index 6370ed1a..5c10c433 100644 --- a/app/views/devise/mailer/invitation_instructions.html.haml +++ b/app/views/devise/mailer/invitation_instructions.html.haml @@ -19,7 +19,7 @@ %p= t('devise.mailer.invitation_instructions.ignore') - elsif !@resource.confirmed? && @resource.confirmation_token - = confirmation_url(@resource, confirmation_token: @token, change_locale_to: @resource.lang) + = confirmation_url(@resource, confirmation_token: @resource.confirmation_token, change_locale_to: @resource.lang) \ = t('devise.mailer.invitation_instructions.ignore') - else diff --git a/app/views/devise/mailer/invitation_instructions.text.haml b/app/views/devise/mailer/invitation_instructions.text.haml index 719c7cd2..ee0247a0 100644 --- a/app/views/devise/mailer/invitation_instructions.text.haml +++ b/app/views/devise/mailer/invitation_instructions.text.haml @@ -19,7 +19,7 @@ \ = t('devise.mailer.invitation_instructions.ignore') - elsif !@resource.confirmed? && @resource.confirmation_token - = confirmation_url(@resource, confirmation_token: @token, change_locale_to: @resource.lang) + = confirmation_url(@resource, confirmation_token: @resource.confirmation_token, change_locale_to: @resource.lang) \ = t('devise.mailer.invitation_instructions.ignore') - else From 34947ffd4e9069f787973cfc9fd009ec3f94c394 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 24 Apr 2023 19:01:02 -0300 Subject: [PATCH 450/453] fix: typo --- config/locales/devise_invitable.es.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/devise_invitable.es.yml b/config/locales/devise_invitable.es.yml index e83a703c..860ee4f8 100644 --- a/config/locales/devise_invitable.es.yml +++ b/config/locales/devise_invitable.es.yml @@ -22,7 +22,7 @@ es: someone_invited_you: "Alguien te ha invitado a colaborar en %{url}, podés aceptar la invitación con el enlace a continuación." accept: "Aceptar la invitación" accept_until: "La invitación vencerá el %{due_date}." - ignore: "Si no querés aceptar la invitación, por favor ignora este correo. Tu cuenta no será creada hasta que aceptes la invitación y configures una contraseña." + ignore: "Si no querés aceptar la invitación, por favor ignorá este correo. Tu cuenta no será creada hasta que aceptes la invitación y configures una contraseña." sign_in: "Iniciá sesión con tu cuenta para aceptar o rechazar la invitación." time: formats: From 5c44a4f15ee0a6af0fe14664c1d9f7bfe4a9a41c Mon Sep 17 00:00:00 2001 From: f Date: Mon, 24 Apr 2023 19:01:19 -0300 Subject: [PATCH 451/453] fix: el mensaje de ignorar no es el correcto --- app/views/devise/mailer/invitation_instructions.html.haml | 2 -- app/views/devise/mailer/invitation_instructions.text.haml | 2 -- 2 files changed, 4 deletions(-) diff --git a/app/views/devise/mailer/invitation_instructions.html.haml b/app/views/devise/mailer/invitation_instructions.html.haml index 5c10c433..e87d99d9 100644 --- a/app/views/devise/mailer/invitation_instructions.html.haml +++ b/app/views/devise/mailer/invitation_instructions.html.haml @@ -20,7 +20,5 @@ %p= t('devise.mailer.invitation_instructions.ignore') - elsif !@resource.confirmed? && @resource.confirmation_token = confirmation_url(@resource, confirmation_token: @resource.confirmation_token, change_locale_to: @resource.lang) - \ - = t('devise.mailer.invitation_instructions.ignore') - else %p= link_to t('devise.mailer.invitation_instructions.sign_in'), root_url diff --git a/app/views/devise/mailer/invitation_instructions.text.haml b/app/views/devise/mailer/invitation_instructions.text.haml index ee0247a0..5cb007de 100644 --- a/app/views/devise/mailer/invitation_instructions.text.haml +++ b/app/views/devise/mailer/invitation_instructions.text.haml @@ -20,8 +20,6 @@ = t('devise.mailer.invitation_instructions.ignore') - elsif !@resource.confirmed? && @resource.confirmation_token = confirmation_url(@resource, confirmation_token: @resource.confirmation_token, change_locale_to: @resource.lang) - \ - = t('devise.mailer.invitation_instructions.ignore') - else = root_url(change_locale_to: @resource.lang) = t('devise.mailer.invitation_instructions.sign_in') From fb7fb080d1628aaa6fd87eefccdb6dd8f6d48bea Mon Sep 17 00:00:00 2001 From: f Date: Tue, 25 Apr 2023 13:12:07 -0300 Subject: [PATCH 452/453] =?UTF-8?q?feat:=20vincular=20al=20formulario=20de?= =?UTF-8?q?=20contacto=20desde=20la=20p=C3=A1gina=20de=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/500.html | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/public/500.html b/public/500.html index 2d69baf6..9e8ea780 100644 --- a/public/500.html +++ b/public/500.html @@ -19,7 +19,11 @@

Gracias por ayudarnos a encontrar errores :)

-

Volver al panel

+

+ Volver al panel + | + Contáctanos +

@@ -31,7 +35,11 @@

Thanks for helping us in finding errors! :)

-

Go back to panel

+

+ Go back to panel + | + Contact us +

From 0b2cc38691356fcac3dc1cbf86c3aeada5417773 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 25 Apr 2023 13:14:29 -0300 Subject: [PATCH 453/453] =?UTF-8?q?feat:=20bot=C3=B3n=20de=20contacto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/layouts/_breadcrumb.haml | 4 ++++ config/locales/en.yml | 2 ++ config/locales/es.yml | 2 ++ 3 files changed, 8 insertions(+) diff --git a/app/views/layouts/_breadcrumb.haml b/app/views/layouts/_breadcrumb.haml index b1c42cb2..6281404a 100644 --- a/app/views/layouts/_breadcrumb.haml +++ b/app/views/layouts/_breadcrumb.haml @@ -19,6 +19,10 @@ = link_to t('.tienda'), @site.tienda_url, role: 'button', class: 'btn' + %li.nav-item + = link_to t('.contact_us'), t('.contact_us_href'), + class: 'btn', rel: 'me', target: '_blank' + %li.nav-item = link_to t('.logout'), main_app.destroy_usuarie_session_path, method: :delete, role: 'button', class: 'btn' diff --git a/config/locales/en.yml b/config/locales/en.yml index 941280c0..5b65f42e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -206,6 +206,8 @@ en: title: 'Your location in Sutty' logout: Log out mutual_aid: Mutual aid + contact_us: "Contact us" + contact_us_href: "https://sutty.nl/en/#contact" collaborations: collaborate: submit: Register diff --git a/config/locales/es.yml b/config/locales/es.yml index af84b474..bef67311 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -206,6 +206,8 @@ es: title: 'Tu ubicación en Sutty' logout: Cerrar sesión mutual_aid: Ayuda mutua + contact_us: "Contacto" + contact_us_href: "https://sutty.nl/#contacto" collaborations: collaborate: submit: Registrarme