mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-26 01:06:21 +00:00
Merge branch 'panel.testing.sutty.nl' of 0xacab.org:sutty/sutty into panel.testing.sutty.nl
This commit is contained in:
commit
ffff78c0cb
90 changed files with 297 additions and 287 deletions
|
@ -1,3 +1,6 @@
|
|||
stages:
|
||||
- "test"
|
||||
- "deploy"
|
||||
.apk-add: &apk-add
|
||||
- "apk add go-task diffutils gitlab_ci_log_section"
|
||||
.disable-hainish: &disable-hainish
|
||||
|
@ -6,9 +9,15 @@
|
|||
- paths:
|
||||
- "vendor/ruby"
|
||||
- ".bundle"
|
||||
key:
|
||||
files:
|
||||
- "Gemfile.lock"
|
||||
.cache-node: &cache-node
|
||||
- paths:
|
||||
- "node_modules"
|
||||
key:
|
||||
files:
|
||||
- "yarn.lock"
|
||||
.cache-task: &cache-task
|
||||
- paths:
|
||||
- ".task"
|
||||
|
@ -18,11 +27,26 @@ variables:
|
|||
LC_ALL: "C.UTF-8"
|
||||
HAINISH: ""
|
||||
cache:
|
||||
push:
|
||||
stage: "test"
|
||||
only:
|
||||
- "rails"
|
||||
except:
|
||||
- "schedules"
|
||||
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_CI_PUSH_TOKEN:${GITLAB_CI_PUSH_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git\""
|
||||
script:
|
||||
- "git commit --allow-empty -m \"ci: test [skip ci]\""
|
||||
- "git push -o ci.skip origin HEAD:${CI_COMMIT_BRANCH}"
|
||||
assets:
|
||||
stage: "deploy"
|
||||
only:
|
||||
- "rails"
|
||||
- "17.3.alpine.panel.sutty.nl"
|
||||
- "production.panel.sutty.nl"
|
||||
- "panel.sutty.nl"
|
||||
- "panel.testing.sutty.nl"
|
||||
except:
|
||||
- "schedules"
|
||||
cache:
|
||||
|
@ -30,14 +54,14 @@ assets:
|
|||
- *cache-node
|
||||
- *cache-task
|
||||
before_script:
|
||||
- *apk-add
|
||||
- "gitlab_ci_log_section --name git --header=\"Configuring git\""
|
||||
- "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\""
|
||||
- "git remote set-url --push origin \"https://GITLAB_CI_PUSH_TOKEN:${GITLAB_CI_PUSH_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git\""
|
||||
- "gitlab_ci_log_section --name git --end"
|
||||
- "gitlab_ci_log_section --name apk --header=\"Installing dependencies\""
|
||||
- "apk add brotli"
|
||||
- *apk-add
|
||||
- *disable-hainish
|
||||
- "gitlab_ci_log_section --name apk --end"
|
||||
script:
|
||||
|
@ -45,7 +69,7 @@ assets:
|
|||
- "go-task assets"
|
||||
after_script:
|
||||
- "git add public && git commit -m \"ci: assets [skip ci]\""
|
||||
- "git push -o ci.skip"
|
||||
- "git push -o ci.skip origin HEAD:${CI_COMMIT_BRANCH}"
|
||||
gem-audit:
|
||||
stage: "test"
|
||||
only:
|
||||
|
|
1
Gemfile
1
Gemfile
|
@ -80,6 +80,7 @@ gem 'yaml_db', git: 'https://0xacab.org/sutty/yaml_db.git'
|
|||
gem 'kaminari'
|
||||
gem 'device_detector'
|
||||
gem 'htmlbeautifier'
|
||||
gem 'dry-schema'
|
||||
gem 'rubanok'
|
||||
|
||||
gem 'after_commit_everywhere', '~> 1.0'
|
||||
|
|
15
Gemfile.lock
15
Gemfile.lock
|
@ -118,10 +118,11 @@ GEM
|
|||
bundler-audit (0.9.1)
|
||||
bundler (>= 1.2.0, < 3)
|
||||
thor (~> 1.0)
|
||||
capybara (2.18.0)
|
||||
capybara (3.40.0)
|
||||
addressable
|
||||
matrix
|
||||
mini_mime (>= 0.1.3)
|
||||
nokogiri (~> 1.8)
|
||||
nokogiri (~> 1.11)
|
||||
rack (>= 1.6.0)
|
||||
rack-test (>= 0.6.3)
|
||||
regexp_parser (>= 1.5, < 3.0)
|
||||
|
@ -361,13 +362,14 @@ GEM
|
|||
net-pop
|
||||
net-smtp
|
||||
marcel (1.0.2)
|
||||
matrix (0.4.2)
|
||||
memory_profiler (1.0.1)
|
||||
mercenary (0.4.0)
|
||||
method_source (1.0.0)
|
||||
mini_histogram (0.3.1)
|
||||
mini_magick (4.12.0)
|
||||
mini_mime (1.1.5)
|
||||
mini_portile2 (2.8.5)
|
||||
mini_portile2 (2.8.6)
|
||||
minitest (5.21.1)
|
||||
mobility (1.2.9)
|
||||
i18n (>= 0.6.10, < 2)
|
||||
|
@ -387,7 +389,7 @@ GEM
|
|||
net-ssh (7.2.1)
|
||||
netaddr (2.0.6)
|
||||
nio4r (2.7.0-x86_64-linux-musl)
|
||||
nokogiri (1.16.0-x86_64-linux-musl)
|
||||
nokogiri (1.16.5-x86_64-linux-musl)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
orm_adapter (0.5.0)
|
||||
|
@ -408,7 +410,7 @@ GEM
|
|||
pry (0.14.2)
|
||||
coderay (~> 1.1)
|
||||
method_source (~> 1.0)
|
||||
public_suffix (5.0.4)
|
||||
public_suffix (5.0.5)
|
||||
puma (6.4.2-x86_64-linux-musl)
|
||||
nio4r (~> 2.0)
|
||||
pundit (2.3.1)
|
||||
|
@ -487,7 +489,7 @@ GEM
|
|||
redis-store (>= 1.2, < 2)
|
||||
redis-store (1.9.2)
|
||||
redis (>= 4, < 6)
|
||||
regexp_parser (2.9.0)
|
||||
regexp_parser (2.9.2)
|
||||
request_store (1.5.1)
|
||||
rack (>= 1.4)
|
||||
responders (3.1.1)
|
||||
|
@ -646,6 +648,7 @@ DEPENDENCIES
|
|||
distributed-press-api-client (~> 0.4.1)
|
||||
dotenv-rails
|
||||
down
|
||||
dry-schema
|
||||
ed25519
|
||||
email_address!
|
||||
exception_notification
|
||||
|
|
|
@ -185,9 +185,13 @@ tasks:
|
|||
- "test -f ../hain/usr/bin/bundler-audit"
|
||||
rubocop:
|
||||
desc: "Ruby linting"
|
||||
deps:
|
||||
- "gems"
|
||||
cmds:
|
||||
- "./bin/modified_files | ./bin/with_extension rb | xargs -r {{.HAINISH}} bundle exec rubocop {{.CLI_ARGS}}"
|
||||
haml-lint:
|
||||
desc: "HAML linting"
|
||||
deps:
|
||||
- "gems"
|
||||
cmds:
|
||||
- "./bin/modified_files | ./bin/with_extension haml | xargs -r {{.HAINISH}} bundle exec haml-lint {{.CLI_ARGS}}"
|
||||
|
|
|
@ -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_later site.id,
|
||||
ContactJob.perform_later site,
|
||||
params[:form],
|
||||
contact_params.to_h.symbolize_keys,
|
||||
params[:redirect]
|
||||
|
|
|
@ -11,7 +11,7 @@ module Api
|
|||
# respondemos con lo mismo.
|
||||
def create
|
||||
if (site&.airbrake_valid? airbrake_token) && !detected_device.bot?
|
||||
BacktraceJob.perform_later site_id: params[:site_id],
|
||||
BacktraceJob.perform_later site: site,
|
||||
params: airbrake_params.to_h
|
||||
end
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class ApplicationController < ActionController::Base
|
|||
after_action :store_location!
|
||||
|
||||
before_action do
|
||||
Rack::MiniProfiler.authorize_request if current_usuarie&.email&.ends_with?('@' + ENV.fetch('SUTTY', 'sutty.nl'))
|
||||
Rack::MiniProfiler.authorize_request if current_usuarie&.email&.ends_with?("@#{ENV.fetch('SUTTY', 'sutty.nl')}")
|
||||
end
|
||||
|
||||
# No tenemos índice de sutty, vamos directamente a ver el listado de
|
||||
|
@ -24,7 +24,7 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
private
|
||||
|
||||
|
||||
def notify_unconfirmed_email
|
||||
return unless current_usuarie
|
||||
return if current_usuarie.confirmed?
|
||||
|
@ -58,9 +58,7 @@ class ApplicationController < ActionController::Base
|
|||
def current_locale
|
||||
locale = params[:change_locale_to]
|
||||
|
||||
if locale.present? && I18n.locale_available?(locale)
|
||||
session[:locale] = params[:change_locale_to]
|
||||
end
|
||||
session[:locale] = params[:change_locale_to] if locale.present? && I18n.locale_available?(locale)
|
||||
|
||||
session[:locale] || current_usuarie&.lang || I18n.locale
|
||||
end
|
||||
|
@ -121,5 +119,4 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
session[:usuarie_return_to] = request.fullpath
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ class EnvController < ActionController::Base
|
|||
skip_before_action :verify_authenticity_token
|
||||
|
||||
def index
|
||||
@site = Site.find_by_name('panel')
|
||||
@site = Site.find_by_name('panel') || Site.first
|
||||
|
||||
stale? @site if @site
|
||||
end
|
||||
|
|
|
@ -13,7 +13,7 @@ module ApplicationHelper
|
|||
root = names.shift
|
||||
|
||||
names.each do |n|
|
||||
root += '[' + n.to_s + ']'
|
||||
root += "[#{n}]"
|
||||
end
|
||||
|
||||
[root, name]
|
||||
|
@ -41,7 +41,7 @@ module ApplicationHelper
|
|||
def plain_field_name_for(*names)
|
||||
root, name = field_name_for(*names)
|
||||
|
||||
root + '[' + name.to_s + ']'
|
||||
"#{root}[#{name}]"
|
||||
end
|
||||
|
||||
def distance_of_time_in_words_if_more_than_a_minute(seconds)
|
||||
|
|
|
@ -11,14 +11,33 @@ class ActivityPub
|
|||
class FetchJob < ApplicationJob
|
||||
self.priority = 50
|
||||
|
||||
attr_reader :object, :response
|
||||
|
||||
# Notificar errores de JSON con el contenido, tomar los errores de
|
||||
# validación y conexión como errores temporales y notificar todo lo
|
||||
# demás sin reintentar.
|
||||
#
|
||||
# @param error [Exception]
|
||||
# @return [Bool]
|
||||
discard_on(FastJsonparser::ParseError) do |error|
|
||||
ExceptionNotifier.notify_exception(error, data: { site: site.name, object: object.uri, body: response.body })
|
||||
end
|
||||
|
||||
retry_on ActiveRecord::RecordInvalid
|
||||
retry_on SocketError, wait: ApplicationJob.random_wait
|
||||
retry_on SystemCallError, wait: ApplicationJob.random_wait
|
||||
retry_on Net::OpenTimeout, wait: ApplicationJob.random_wait
|
||||
retry_on OpenSSL::OpenSSLError, wait: ApplicationJob.random_wait
|
||||
|
||||
def perform(site:, object_id:)
|
||||
ActivityPub::Object.transaction do
|
||||
object = ::ActivityPub::Object.find(object_id)
|
||||
@site = site
|
||||
@object = ::ActivityPub::Object.find(object_id)
|
||||
|
||||
return if object.blank?
|
||||
return if object.activity_pubs.where(aasm_state: 'removed').count.positive?
|
||||
|
||||
response = site.social_inbox.dereferencer.get(uri: object.uri)
|
||||
@response = site.social_inbox.dereferencer.get(uri: object.uri)
|
||||
|
||||
# @todo Fallar cuando la respuesta no funcione?
|
||||
# @todo Eliminar en 410 Gone
|
||||
|
@ -31,7 +50,8 @@ class ActivityPub
|
|||
content = FastJsonparser.parse(response.body)
|
||||
|
||||
# Modificar atómicamente
|
||||
::ActivityPub::Object.lock.find(object_id).update!(content: content, type: ActivityPub::Object.type_from(content).name)
|
||||
::ActivityPub::Object.lock.find(object_id).update!(content: content,
|
||||
type: ActivityPub::Object.type_from(content).name)
|
||||
|
||||
object = ::ActivityPub::Object.find(object_id)
|
||||
# Actualiza la mención
|
||||
|
@ -39,8 +59,6 @@ class ActivityPub
|
|||
|
||||
# Arreglar las relaciones con actividades también
|
||||
ActivityPub.where(object_id: object.id).update_all(object_type: object.type, updated_at: Time.now)
|
||||
rescue FastJsonparser::ParseError => e
|
||||
ExceptionNotifier.notify_exception(e, data: { site: site.name, object: object.uri, body: response.body })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
class ActivityPub
|
||||
# Procesar las actividades a medida que llegan
|
||||
class ProcessJob < ApplicationJob
|
||||
attr_reader :body, :initial_state
|
||||
attr_reader :body
|
||||
|
||||
retry_on ActiveRecord::RecordInvalid
|
||||
|
||||
# Procesa la actividad en segundo plano
|
||||
#
|
||||
|
@ -12,7 +14,6 @@ class ActivityPub
|
|||
def perform(site:, body:, initial_state: :paused)
|
||||
@site = site
|
||||
@body = body
|
||||
@initial_state = initial_state
|
||||
|
||||
ActiveRecord::Base.connection_pool.with_connection do
|
||||
::ActivityPub.transaction do
|
||||
|
@ -28,24 +29,6 @@ class ActivityPub
|
|||
end
|
||||
end
|
||||
|
||||
# Al generar una excepción, en lugar de seguir intentando, enviamos
|
||||
# el reporte.
|
||||
def handle_error(error)
|
||||
case error
|
||||
when ActiveRecord::RecordInvalid then retry_in(ApplicationJob.random_wait)
|
||||
else
|
||||
ExceptionNotifier.notify_exception(
|
||||
error,
|
||||
data: {
|
||||
site: site.name,
|
||||
body: body,
|
||||
initial_state: initial_state,
|
||||
activity: original_activity,
|
||||
message: 'Esta acción se canceló automáticamente, para regenerarla, volver a correr el proceso con los mismos parámetros.'
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Si el objeto ya viene incorporado en la actividad o lo tenemos
|
||||
|
|
|
@ -43,7 +43,9 @@ class ActivityPub
|
|||
# Si alguna falló, reintentar
|
||||
raise if logs.present?
|
||||
rescue Exception => e
|
||||
ExceptionNotifier.notify_exception(e, data: { site: site.name, logs: logs, blocklist: blocklist, allowlist: allowlist, pauselist: pauselist })
|
||||
ExceptionNotifier.notify_exception(e,
|
||||
data: { site: site.name, logs: logs, blocklist: blocklist,
|
||||
allowlist: allowlist, pauselist: pauselist })
|
||||
|
||||
raise
|
||||
end
|
||||
|
|
|
@ -8,16 +8,17 @@ class ApplicationJob < ActiveJob::Base
|
|||
# superpongan tareas
|
||||
#
|
||||
# @return [Array<Integer>]
|
||||
RANDOM_WAIT = [3, 5, 7, 11, 13]
|
||||
RANDOM_WAIT = [3, 5, 7, 11, 13].freeze
|
||||
|
||||
# @return [ActiveSupport::Duration]
|
||||
def self.random_wait
|
||||
RANDOM_WAIT.sample.seconds
|
||||
end
|
||||
|
||||
private
|
||||
attr_reader :site
|
||||
|
||||
def site
|
||||
@site ||= Site.find @params[:site_id]
|
||||
# Si falla por cualquier cosa informar y descartar
|
||||
discard_on(Exception) do |job, error|
|
||||
ExceptionNotifier.notify_exception(error, data: { job: job })
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,10 +6,10 @@ class BacktraceJob < ApplicationJob
|
|||
|
||||
EMPTY_SOURCEMAP = { 'mappings' => '' }.freeze
|
||||
|
||||
attr_reader :params, :site_id
|
||||
attr_reader :params
|
||||
|
||||
def perform(site_id:, params:)
|
||||
@site_id = site_id
|
||||
def perform(site:, params:)
|
||||
@site = site
|
||||
@params = params
|
||||
|
||||
unless sources.empty?
|
||||
|
@ -44,10 +44,6 @@ class BacktraceJob < ApplicationJob
|
|||
|
||||
private
|
||||
|
||||
def site
|
||||
@site ||= Site.find_by_id(site_id)
|
||||
end
|
||||
|
||||
# Obtiene todos los archivos del backtrace solo si los puede descargar
|
||||
# desde fuentes seguras.
|
||||
#
|
||||
|
@ -59,9 +55,7 @@ class BacktraceJob < ApplicationJob
|
|||
x['backtrace']
|
||||
end.flatten.map do |x|
|
||||
x['file'].split('@').last
|
||||
end.uniq.select do |x|
|
||||
%r{\Ahttps://} =~ x
|
||||
end
|
||||
end.uniq.grep(%r{\Ahttps://})
|
||||
end
|
||||
|
||||
# Descarga y devuelve los datos de un archivo
|
||||
|
|
|
@ -5,10 +5,8 @@ class ContactJob < ApplicationJob
|
|||
# @param [Integer]
|
||||
# @param [String]
|
||||
# @param [Hash]
|
||||
def perform(site_id, form_name, form, origin = nil)
|
||||
# Retrocompabilidad al actualizar a 2.7.1
|
||||
# @see ApplicationJob#site
|
||||
@params = { site_id: site_id }
|
||||
def perform(site, form_name, form, origin = nil)
|
||||
@site = site
|
||||
|
||||
# Sanitizar los valores
|
||||
form.each_key do |key|
|
||||
|
@ -23,7 +21,7 @@ class ContactJob < ApplicationJob
|
|||
usuaries.each_slice(10) do |u|
|
||||
ContactMailer.with(form_name: form_name,
|
||||
form: form,
|
||||
site_id: site_id,
|
||||
site: site,
|
||||
usuaries_emails: u,
|
||||
origin: origin)
|
||||
.notify_usuaries.deliver_now
|
||||
|
|
|
@ -11,44 +11,36 @@ class DeployJob < ApplicationJob
|
|||
# Lanzar lo antes posible
|
||||
self.priority = 10
|
||||
|
||||
def handle_error(error)
|
||||
case error
|
||||
when DeployAlreadyRunningException then retry_in 1.minute
|
||||
when DeployTimedOutException then expire
|
||||
else super
|
||||
end
|
||||
end
|
||||
retry_on DeployAlreadyRunningException, wait: 1.minute
|
||||
discard_on DeployTimedOutException
|
||||
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
def perform(site, notify: true, time: Time.now, output: false)
|
||||
@output = output
|
||||
@site = site
|
||||
|
||||
ActiveRecord::Base.connection_pool.with_connection do
|
||||
@site = Site.find(site)
|
||||
|
||||
# Si ya hay una tarea corriendo, aplazar esta. Si estuvo
|
||||
# esperando más de 10 minutos, recuperar el estado anterior.
|
||||
#
|
||||
# Como el trabajo actual se aplaza al siguiente, arrastrar la
|
||||
# hora original para poder ir haciendo timeouts.
|
||||
if @site.building?
|
||||
if site.building?
|
||||
notify = false
|
||||
|
||||
if 10.minutes.ago >= time
|
||||
raise DeployTimedOutException,
|
||||
"#{@site.name} la tarea estuvo más de 10 minutos esperando, volviendo al estado original"
|
||||
else
|
||||
raise DeployAlreadyRunningException
|
||||
end
|
||||
raise DeployAlreadyRunningException unless 10.minutes.ago >= time
|
||||
|
||||
raise DeployTimedOutException,
|
||||
"#{site.name} la tarea estuvo más de 10 minutos esperando, volviendo al estado original"
|
||||
|
||||
end
|
||||
|
||||
@deployed = {}
|
||||
@site.update status: 'building'
|
||||
@site.deployment_list.each do |d|
|
||||
site.update status: 'building'
|
||||
site.deployment_list.each do |d|
|
||||
begin
|
||||
raise DeployException, 'Una dependencia falló' if failed_dependencies? d
|
||||
|
||||
status = d.deploy(output: @output)
|
||||
status = d.deploy(output: output)
|
||||
seconds = d.build_stats.last.try(:seconds) || 0
|
||||
size = d.size
|
||||
urls = d.urls.map do |url|
|
||||
|
@ -57,9 +49,7 @@ class DeployJob < ApplicationJob
|
|||
nil
|
||||
end.compact
|
||||
|
||||
if d == @site.deployment_list.last && !status
|
||||
raise DeployException, 'Falló la compilación'
|
||||
end
|
||||
raise DeployException, 'Falló la compilación' if d == site.deployment_list.last && !status
|
||||
rescue StandardError => e
|
||||
status = false
|
||||
seconds ||= 0
|
||||
|
@ -78,9 +68,9 @@ class DeployJob < ApplicationJob
|
|||
}
|
||||
end
|
||||
|
||||
return unless @output
|
||||
return unless output
|
||||
|
||||
puts (Terminal::Table.new do |t|
|
||||
puts(Terminal::Table.new do |t|
|
||||
t << (%w[type] + @deployed.values.first.keys)
|
||||
t.add_separator
|
||||
@deployed.each do |type, row|
|
||||
|
@ -90,12 +80,12 @@ class DeployJob < ApplicationJob
|
|||
rescue DeployTimedOutException => e
|
||||
notify_exception e
|
||||
ensure
|
||||
if @site.present?
|
||||
@site.update status: 'waiting'
|
||||
if site.present?
|
||||
site.update status: 'waiting'
|
||||
|
||||
notify_usuaries if notify
|
||||
|
||||
puts "\a" if @output
|
||||
puts "\a" if output
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -125,7 +115,7 @@ class DeployJob < ApplicationJob
|
|||
# @param :deploy [Deploy]
|
||||
def notify_exception(exception, deploy = nil)
|
||||
data = {
|
||||
site: @site.id,
|
||||
site: site.name,
|
||||
deploy: deploy&.type,
|
||||
log: deploy&.build_stats&.last&.log,
|
||||
failed_dependencies: (failed_dependencies(deploy) if deploy)
|
||||
|
@ -135,8 +125,10 @@ class DeployJob < ApplicationJob
|
|||
end
|
||||
|
||||
def notify_usuaries
|
||||
@site.roles.where(rol: 'usuarie', temporal: false).pluck(:usuarie_id).each do |usuarie|
|
||||
DeployMailer.with(usuarie: usuarie, site: @site.id)
|
||||
usuarie_ids = site.roles.where(rol: 'usuarie', temporal: false).pluck(:usuarie_id)
|
||||
|
||||
Usuarie.where(id: usuarie_ids).find_each do |usuarie|
|
||||
DeployMailer.with(usuarie: usuarie, site: site)
|
||||
.deployed(@deployed)
|
||||
.deliver_now
|
||||
end
|
||||
|
|
|
@ -7,6 +7,8 @@ class GitPullJob < ApplicationJob
|
|||
# @param :message [String]
|
||||
# @return [nil]
|
||||
def perform(site, usuarie, message)
|
||||
@site = site
|
||||
|
||||
return unless site.repository.origin
|
||||
|
||||
site.repository.fetch
|
||||
|
|
|
@ -6,6 +6,8 @@ class GitPushJob < ApplicationJob
|
|||
# @param :site [Site]
|
||||
# @return [nil]
|
||||
def perform(site)
|
||||
site.repository.push if site.repository.origin
|
||||
@site = site
|
||||
|
||||
site.repository.push if site.repository.origin
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
# Lo mismo para salir de mantenimiento, agregando el atributo
|
||||
# are_we_back: true al crear el Maintenance.
|
||||
class MaintenanceJob < ApplicationJob
|
||||
def perform(maintenance_id:)
|
||||
maintenance = Maintenance.find(maintenance_id)
|
||||
def perform(maintenance:)
|
||||
# Decidir cuál vamos a enviar según el estado de Maintenance
|
||||
mailer = maintenance.are_we_back ? :were_back : :notice
|
||||
|
||||
|
|
|
@ -6,9 +6,6 @@ class PeriodicJob < ApplicationJob
|
|||
|
||||
STARTING_INTERVAL = Stat::INTERVALS.first
|
||||
|
||||
# Tener el sitio a mano
|
||||
attr_reader :site
|
||||
|
||||
# Descartar y notificar si pasó algo más.
|
||||
#
|
||||
# XXX: En realidad deberíamos seguir reintentando?
|
||||
|
|
|
@ -7,8 +7,8 @@ class StatCollectionJob < PeriodicJob
|
|||
|
||||
STAT_NAME = 'stat_collection_job'
|
||||
|
||||
def perform(site_id:, once: true)
|
||||
@site = Site.find site_id
|
||||
def perform(site:, once: true)
|
||||
@site = site
|
||||
beginning = beginning_of_interval
|
||||
stat = site.stats.create! name: STAT_NAME
|
||||
|
||||
|
@ -22,7 +22,7 @@ class StatCollectionJob < PeriodicJob
|
|||
rollup.average(:seconds)
|
||||
end
|
||||
|
||||
dimensions = { site_id: site_id }
|
||||
dimensions = { site_id: site.id }
|
||||
|
||||
reduce_rollup(name: 'builds', operation: :sum, dimensions: dimensions)
|
||||
reduce_rollup(name: 'space_used', operation: :average, dimensions: dimensions)
|
||||
|
|
|
@ -16,8 +16,8 @@ class UriCollectionJob < PeriodicJob
|
|||
IMAGES = %w[.png .jpg .jpeg .gif .webp .jfif].freeze
|
||||
STAT_NAME = 'uri_collection_job'
|
||||
|
||||
def perform(site_id:, once: true)
|
||||
@site = Site.find site_id
|
||||
def perform(site:, once: true)
|
||||
@site = site
|
||||
|
||||
# Obtener el principio del intervalo anterior
|
||||
beginning_of_interval
|
||||
|
|
|
@ -14,6 +14,8 @@ module Jekyll
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
DATA_EXTENSIONS = %w[.yaml .yml .json .csv .tsv].freeze
|
||||
|
||||
def read_data_to(dir, data)
|
||||
return unless File.directory?(dir) && !@entry_filter.symlink?(dir)
|
||||
|
||||
|
@ -24,7 +26,7 @@ module Jekyll
|
|||
|
||||
if File.directory?(path)
|
||||
read_data_to(path, data[sanitize_filename(entry)] = {})
|
||||
else
|
||||
elsif DATA_EXTENSIONS.include?(File.extname(entry))
|
||||
key = sanitize_filename(File.basename(entry, ".*"))
|
||||
data[key] = read_data_file(path)
|
||||
end
|
||||
|
|
|
@ -10,7 +10,7 @@ class ApplicationMailer < ActionMailer::Base
|
|||
private
|
||||
|
||||
def site
|
||||
@site ||= Site.find @params[:site_id]
|
||||
@site ||= @params[:site]
|
||||
end
|
||||
|
||||
def inline_logo!
|
||||
|
|
|
@ -13,8 +13,7 @@ class DeployMailer < ApplicationMailer
|
|||
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
def deployed(deploys = {})
|
||||
usuarie = Usuarie.find(params[:usuarie])
|
||||
site = usuarie.sites.find(params[:site])
|
||||
usuarie = params[:usuarie]
|
||||
hostname = site.hostname
|
||||
deploys ||= {}
|
||||
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class InvitadxMailer < ApplicationMailer
|
||||
def confirmation_required
|
||||
@invitadx = params[:invitadx]
|
||||
@site = params[:site]
|
||||
mail from: "#{@site.config.dig('title')} <#{ENV.fetch('DEFAULT_FROM', 'sutty@kefir.red')}>", to: @invitadx.email, subject: t('.subject')
|
||||
end
|
||||
end
|
|
@ -64,7 +64,7 @@ class ActivityPub < ApplicationRecord
|
|||
# Array<String> o mezcla y obtener el que más nos convenga o
|
||||
# adivinar uno.
|
||||
when Array
|
||||
links = object['url'].map.with_index do |link, i|
|
||||
links = object['url'].map.with_index do |link, _i|
|
||||
case link
|
||||
when Hash then link
|
||||
else { 'href' => link.to_s }
|
||||
|
@ -93,7 +93,8 @@ class ActivityPub < ApplicationRecord
|
|||
|
||||
# Gestionar todos los errores
|
||||
error_on_all_events do |e|
|
||||
ExceptionNotifier.notify_exception(e, data: { site: site.name, activity_pub: self.id, activity: activities.first.uri })
|
||||
ExceptionNotifier.notify_exception(e,
|
||||
data: { site: site.name, activity_pub: id, activity: activities.first.uri })
|
||||
end
|
||||
|
||||
# Se puede volver a pausa en caso de actualización remota, para
|
||||
|
|
|
@ -35,9 +35,9 @@ class ActivityPub
|
|||
validates_inclusion_of :format, in: %w[mastodon fediblock none]
|
||||
|
||||
HOSTNAME_HEADERS = {
|
||||
'mastodon' => '#domain',
|
||||
'mastodon' => '#domain',
|
||||
'fediblock' => 'domain'
|
||||
}
|
||||
}.freeze
|
||||
|
||||
def client
|
||||
@client ||= Client.new
|
||||
|
|
|
@ -39,13 +39,14 @@ class ActivityPub
|
|||
def referenced(site)
|
||||
require 'distributed_press/v1/social/referenced_object'
|
||||
|
||||
@referenced ||= DistributedPress::V1::Social::ReferencedObject.new(object: content, dereferencer: site.social_inbox.dereferencer)
|
||||
@referenced ||= DistributedPress::V1::Social::ReferencedObject.new(object: content,
|
||||
dereferencer: site.social_inbox.dereferencer)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def uri_is_content_id?
|
||||
return if self.uri == content['id']
|
||||
return if uri == content['id']
|
||||
|
||||
errors.add(:activity_pub_objects, 'El ID del objeto no coincide con su URI')
|
||||
end
|
||||
|
|
|
@ -40,7 +40,8 @@ class ActivityPub
|
|||
def content
|
||||
{
|
||||
'@context' => 'https://www.w3.org/ns/activitystreams',
|
||||
'id' => Rails.application.routes.url_helpers.v1_activity_pub_remote_flag_url(self, host: site.social_inbox_hostname),
|
||||
'id' => Rails.application.routes.url_helpers.v1_activity_pub_remote_flag_url(self,
|
||||
host: site.social_inbox_hostname),
|
||||
'type' => 'Flag',
|
||||
'actor' => main_site.social_inbox.actor_id,
|
||||
'content' => message.to_s,
|
||||
|
@ -53,7 +54,7 @@ class ActivityPub
|
|||
#
|
||||
# @return [Site]
|
||||
def main_site
|
||||
@main_site ||= Site.find(ENV.fetch('PANEL_ACTOR_SITE_ID') { 1 })
|
||||
@main_site ||= Site.find(ENV.fetch('PANEL_ACTOR_SITE_ID', 1))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,4 +2,28 @@
|
|||
|
||||
class ApplicationRecord < ActiveRecord::Base
|
||||
self.abstract_class = true
|
||||
|
||||
# Obtener una lista filtrada de atributos al momento de serializar
|
||||
#
|
||||
# @return [String]
|
||||
def to_yaml(options = {})
|
||||
pruned_attributes.to_yaml(options)
|
||||
end
|
||||
|
||||
# Devuelve todos los atributos menos los filtrados
|
||||
#
|
||||
# @return [Hash]
|
||||
def pruned_attributes
|
||||
self.class.inspection_filter.filter(serializable_hash)
|
||||
end
|
||||
|
||||
# @param coder [Psych::Coder]
|
||||
# @return nil
|
||||
def encode_with(coder)
|
||||
pruned_attributes.each_pair do |attr, value|
|
||||
coder[attr] = value
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,7 +17,7 @@ module Tienda
|
|||
|
||||
return t if new_record?
|
||||
|
||||
t.blank? ? 'https://' + name + '.' + ENV.fetch('TIENDA', 'tienda.sutty.nl') : t
|
||||
t.blank? ? "https://#{name}.#{ENV.fetch('TIENDA', 'tienda.sutty.nl')}" : t
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -45,7 +45,8 @@ class FediblockState < ApplicationRecord
|
|||
private
|
||||
|
||||
def block_instances!
|
||||
ActivityPub::InstanceModerationJob.perform_later(site: site, hostnames: fediblock.hostnames, perform_remotely: false)
|
||||
ActivityPub::InstanceModerationJob.perform_later(site: site, hostnames: fediblock.hostnames,
|
||||
perform_remotely: false)
|
||||
end
|
||||
|
||||
# Pausar todas las moderaciones de las instancias que no estén
|
||||
|
|
|
@ -16,7 +16,9 @@ class InstanceModeration < ApplicationRecord
|
|||
state :blocked
|
||||
|
||||
error_on_all_events do |e|
|
||||
ExceptionNotifier.notify_exception(e, data: { site: site.name, instance: instance.hostname, instance_moderation: id })
|
||||
ExceptionNotifier.notify_exception(e,
|
||||
data: { site: site.name, instance: instance.hostname,
|
||||
instance_moderation: id })
|
||||
end
|
||||
|
||||
after_all_events do
|
||||
|
|
|
@ -11,7 +11,7 @@ class LogEntry < ApplicationRecord
|
|||
def resend
|
||||
return if sent
|
||||
|
||||
ContactJob.perform_later site_id, params[:form], params
|
||||
ContactJob.perform_later site, params[:form], params
|
||||
end
|
||||
|
||||
def params
|
||||
|
|
|
@ -142,7 +142,7 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
|
|||
# En caso de que algún campo necesite realizar acciones antes de ser
|
||||
# guardado
|
||||
def save
|
||||
if !changed?
|
||||
unless changed?
|
||||
self[:value] = document_value if private?
|
||||
|
||||
return true
|
||||
|
|
|
@ -11,8 +11,11 @@ class Site < ApplicationRecord
|
|||
include Site::BuildStats
|
||||
include Site::LayoutOrdering
|
||||
include Site::SocialDistributedPress
|
||||
include Site::DefaultOptions
|
||||
include Tienda
|
||||
|
||||
self.filter_attributes += [/_key/, /_ciphertext\z/]
|
||||
|
||||
# Cifrar la llave privada que cifra y decifra campos ocultos. Sutty
|
||||
# tiene acceso pero los datos se guardan cifrados en el sitio. Esto
|
||||
# protege información privada en repositorios públicos, pero no la
|
||||
|
@ -235,11 +238,11 @@ class Site < ApplicationRecord
|
|||
# layouts. Si pasamos un layout que no existe, obtenemos un
|
||||
# NoMethodError
|
||||
@layouts_struct ||= Struct.new(*layout_keys, keyword_init: true)
|
||||
@layouts ||= @layouts_struct.new(**data['layouts'].map do |name, metadata|
|
||||
@layouts ||= @layouts_struct.new(**data['layouts'].to_h do |name, metadata|
|
||||
[name.to_sym,
|
||||
Layout.new(site: self, name: name.to_sym, meta: metadata.delete('meta')&.with_indifferent_access,
|
||||
metadata: metadata.with_indifferent_access)]
|
||||
end.to_h)
|
||||
end)
|
||||
end
|
||||
|
||||
# TODO: Si la estructura de datos no existe, vamos a producir una
|
||||
|
@ -314,7 +317,7 @@ class Site < ApplicationRecord
|
|||
end
|
||||
|
||||
def reload
|
||||
super.tap do |s|
|
||||
super.tap do |_s|
|
||||
reload_jekyll!
|
||||
end
|
||||
self
|
||||
|
@ -403,7 +406,7 @@ class Site < ApplicationRecord
|
|||
def clone_skel!
|
||||
return if jekyll?
|
||||
|
||||
Rugged::Repository.clone_at(ENV['SKEL_SUTTY'], path, checkout_branch: design.gem)
|
||||
Rugged::Repository.clone_at(ENV.fetch('SKEL_SUTTY', nil), path, checkout_branch: design.gem)
|
||||
|
||||
# Necesita un bloque
|
||||
repository.rugged.remotes.rename('origin', 'upstream') {}
|
||||
|
@ -497,11 +500,11 @@ class Site < ApplicationRecord
|
|||
deploy_local = deploys.find_by_type('DeployLocal')
|
||||
deploy_local.git_lfs
|
||||
|
||||
if !gems_installed? || gemfile_updated? || gemfile_lock_updated?
|
||||
deploy_local.bundle
|
||||
touch
|
||||
FileUtils.touch(gemfile_path)
|
||||
end
|
||||
return unless !gems_installed? || gemfile_updated? || gemfile_lock_updated?
|
||||
|
||||
deploy_local.bundle
|
||||
touch
|
||||
FileUtils.touch(gemfile_path)
|
||||
end
|
||||
|
||||
def gem_path
|
||||
|
|
44
app/models/site/default_options.rb
Normal file
44
app/models/site/default_options.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'dry-schema'
|
||||
|
||||
class Site
|
||||
# Las opciones por defecto se aplican durante la creación del sitio y
|
||||
# luego se permite a les usuaries modificarlas según quieran. Por el
|
||||
# momento las opciones nuevas que aparezcan no modifican un sitio que
|
||||
# ya existe.
|
||||
module DefaultOptions
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
Schema = Dry::Schema.Params do
|
||||
optional(:colaboracion_anonima).value(:bool)
|
||||
optional(:contact).value(:bool)
|
||||
optional(:acepta_invitades).value(:bool)
|
||||
optional(:slugify_mode).value(included_in?: Jekyll::Utils::SLUGIFY_MODES)
|
||||
optional(:pagination).value(:bool)
|
||||
end
|
||||
|
||||
included do
|
||||
validate :validate_options_from_theme!, if: :persisted?
|
||||
|
||||
# @return [Dry::Schema::Result]
|
||||
def options_from_theme
|
||||
@options_from_theme ||= Schema.call(data['sutty'])
|
||||
end
|
||||
|
||||
def update_options_from_theme
|
||||
return true if options_from_theme.to_h.blank?
|
||||
|
||||
update(**options_from_theme.to_h)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_options_from_theme!
|
||||
options_from_theme.errors.each do |error|
|
||||
errors.add(:default_options, "#{error.path.map(&:to_s).join('/')} #{error} (#{error.input})")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -45,7 +45,7 @@ class SocialInbox
|
|||
# @param url [String]
|
||||
# @return [DistributedPress::V1::Social::Client]
|
||||
def client_for(url)
|
||||
raise "Falló generar un cliente" if url.blank?
|
||||
raise 'Falló generar un cliente' if url.blank?
|
||||
|
||||
@client_for ||= {}
|
||||
@client_for[url] ||=
|
||||
|
@ -54,7 +54,7 @@ class SocialInbox
|
|||
public_key_url: public_key_url,
|
||||
private_key_pem: site.private_key_pem,
|
||||
logger: Rails.logger,
|
||||
cache_store: HTTParty::Cache::Store::Redis.new(redis_url: ENV['REDIS_SERVER'])
|
||||
cache_store: HTTParty::Cache::Store::Redis.new(redis_url: ENV.fetch('REDIS_SERVER', nil))
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ class Usuarie < ApplicationRecord
|
|||
has_many :blazer_audits, foreign_key: 'user_id', class_name: 'Blazer::Audit'
|
||||
has_many :blazer_queries, foreign_key: 'creator_id', class_name: 'Blazer::Query'
|
||||
|
||||
self.filter_attributes += [/\Aemail\z/, /\Aencrypted_password\z/]
|
||||
|
||||
def name
|
||||
email.split('@', 2).first
|
||||
end
|
||||
|
@ -74,10 +76,10 @@ class Usuarie < ApplicationRecord
|
|||
# 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
|
||||
return unless confirmed?
|
||||
|
||||
self.invitation_token = nil
|
||||
self.invitation_accepted_at ||= Time.now.utc
|
||||
end
|
||||
|
||||
# Muestra un error si el idioma no está disponible al cambiar el
|
||||
|
@ -85,7 +87,7 @@ class Usuarie < ApplicationRecord
|
|||
#
|
||||
# @return [nil]
|
||||
def locale_available!
|
||||
return if I18n.locale_available? self.lang
|
||||
return if I18n.locale_available? lang
|
||||
|
||||
errors.add(:lang, I18n.t('activerecord.errors.models.usuarie.attributes.lang.not_available'))
|
||||
nil
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do
|
||||
def deploy
|
||||
site.enqueue!
|
||||
DeployJob.perform_later site.id
|
||||
DeployJob.perform_later site
|
||||
end
|
||||
|
||||
# Crea un sitio, agrega un rol nuevo y guarda los cambios a la
|
||||
|
@ -31,6 +31,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do
|
|||
add_role_to_deploys! role
|
||||
|
||||
site.save &&
|
||||
site.update_options_from_theme &&
|
||||
site.config.write &&
|
||||
commit_config(action: :create) &&
|
||||
site.reset.nil? &&
|
||||
|
@ -236,8 +237,6 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do
|
|||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Asignar un rol a cada deploy si no lo tenía ya
|
||||
def add_role_to_deploys!(role = current_role)
|
||||
site.deploys.each do |deploy|
|
||||
|
@ -249,7 +248,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do
|
|||
@current_role ||= usuarie.rol_for_site(site)
|
||||
end
|
||||
|
||||
def with_all_locales(&block)
|
||||
def with_all_locales
|
||||
site.locales.map do |locale|
|
||||
next unless I18n.available_locales.include? locale
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
.d-flex.flex-row.w-100
|
||||
- local = { report: { class: 'ml-auto', data: { confirm: t('.confirm_report') } } }
|
||||
- ActorModeration.events.each do |actor_event|
|
||||
- possible = !actor_moderation.public_send(:"may_#{actor_event}?")
|
||||
- possible = actor_moderation.public_send(:"may_#{actor_event}?")
|
||||
%div{ class: local.dig(actor_event, :class) }
|
||||
= render 'components/btn_base',
|
||||
text: t(".text_#{actor_event}"),
|
||||
|
|
4
app/views/env/index.js.haml
vendored
4
app/views/env/index.js.haml
vendored
|
@ -2,7 +2,7 @@
|
|||
= cache @site do
|
||||
:plain
|
||||
window.env = {
|
||||
AIRBRAKE_SITE_ID: #{@site.id},
|
||||
AIRBRAKE_API_KEY: "#{@site.airbrake_api_key}",
|
||||
AIRBRAKE_PROJECT_ID: #{@site.id},
|
||||
AIRBRAKE_PROJECT_KEY: "#{@site.airbrake_api_key}",
|
||||
PANEL_URL: "#{ENV['PANEL_URL']}"
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
- else
|
||||
= link_to crumb.name, crumb.url, class: 'line-clamp-1'
|
||||
|
||||
%ul.navbar-nav.order-1.order-md-2
|
||||
- if @current_usuarie || current_usuarie
|
||||
- if @current_usuarie || current_usuarie
|
||||
%ul.navbar-nav.order-1.order-md-2
|
||||
- if @site&.tienda?
|
||||
%li.nav-item
|
||||
= link_to t('.tienda'), @site.tienda_url,
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
= csrf_meta_tags
|
||||
= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
|
||||
= stylesheet_link_tag 'dark', rel: 'alternate stylesheet', media: 'all', 'data-turbolinks-track': 'reload', title: t('dark')
|
||||
= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload'
|
||||
= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true
|
||||
= 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'
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
= 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 btn-secondary'
|
||||
|
||||
|
@ -136,15 +135,16 @@
|
|||
%span{ lang: post.locale, dir: dir }= category
|
||||
= '/' unless post.front_matter['categories'].last == category
|
||||
|
||||
%td.text-nowrap
|
||||
= post.created_at.strftime('%F')
|
||||
%br/
|
||||
= post.order
|
||||
%td.text-nowrap
|
||||
- if @usuarie || policy(post).edit?
|
||||
= link_to t('posts.edit'), edit_site_post_path(@site, post.path), class: 'btn btn-secondary btn-block'
|
||||
- if @usuarie || policy(post).destroy?
|
||||
= link_to t('posts.destroy'), site_post_path(@site, post.path), class: 'btn btn-secondary btn-block', method: :delete, data: { confirm: t('posts.confirm_destroy') }
|
||||
%td.text-nowrap
|
||||
= post.created_at.strftime('%F')
|
||||
%br/
|
||||
= post.order
|
||||
%td.text-nowrap
|
||||
.d-flex.flex-row.align-items-start
|
||||
- if @usuarie || policy(post).edit?
|
||||
= link_to t('posts.edit_post'), edit_site_post_path(@site, post.path), class: 'btn btn-secondary'
|
||||
- if @usuarie || policy(post).destroy?
|
||||
= link_to t('posts.destroy'), site_post_path(@site, post.path), class: 'btn btn-secondary', method: :delete, data: { confirm: t('posts.confirm_destroy') }
|
||||
-#
|
||||
Rescatar cualquier error en un post, notificarlo e
|
||||
ignorar su renderización.
|
||||
|
|
|
@ -62,7 +62,7 @@ Rails.application.configure do
|
|||
config.log_tags = %i[request_id]
|
||||
|
||||
# Use a different cache store in production.
|
||||
config.cache_store = :redis_cache_store, { url: ENV['REDIS_SERVER'] }
|
||||
config.cache_store = :redis_cache_store, { url: ENV.fetch('REDIS_SERVER', nil) }
|
||||
|
||||
config.action_mailer.perform_caching = false
|
||||
|
||||
|
@ -87,7 +87,7 @@ Rails.application.configure do
|
|||
config.lograge.enabled = true
|
||||
# Use default logging formatter so that PID and timestamp are not
|
||||
# suppressed.
|
||||
config.log_formatter = ::Logger::Formatter.new
|
||||
config.log_formatter = Logger::Formatter.new
|
||||
|
||||
# Use a different logger for distributed setups.
|
||||
require 'syslog/logger'
|
||||
|
@ -140,9 +140,10 @@ Rails.application.configure do
|
|||
domain: ENV.fetch('SUTTY', 'sutty.nl'),
|
||||
enable_starttls_auto: false
|
||||
}
|
||||
config.action_mailer.default_options = { from: ENV.fetch('DEFAULT_FROM', "noreply@sutty.nl") }
|
||||
config.action_mailer.default_options = { from: ENV.fetch('DEFAULT_FROM', 'noreply@sutty.nl') }
|
||||
|
||||
config.middleware.use ExceptionNotification::Rack, gitlab: {}, error_grouping: true, ignore_exceptions: ['DeployJob::DeployAlreadyRunningException']
|
||||
config.middleware.use ExceptionNotification::Rack, gitlab: {}, error_grouping: true,
|
||||
ignore_exceptions: ['DeployJob::DeployAlreadyRunningException']
|
||||
|
||||
Rails.application.routes.default_url_options[:host] = "panel.#{ENV.fetch('SUTTY', 'sutty.nl')}"
|
||||
Rails.application.routes.default_url_options[:protocol] = 'https'
|
||||
|
|
|
@ -5,4 +5,5 @@
|
|||
# Configure sensitive parameters which will be filtered from the log file.
|
||||
Rails.application.config.filter_parameters += %i[
|
||||
password passw secret token _key crypt salt certificate otp ssn key
|
||||
_pem _ciphertext email
|
||||
]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Que::Web.use(Rack::Auth::Basic) do |user, password|
|
||||
[user, password] == [ENV['HTTP_BASIC_USER'], ENV['HTTP_BASIC_PASSWORD']]
|
||||
[user, password] == [ENV.fetch('HTTP_BASIC_USER', nil), ENV.fetch('HTTP_BASIC_PASSWORD', nil)]
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ class AddDefaultToDistributedPressPublisher < ActiveRecord::Migration[6.1]
|
|||
def up
|
||||
add_column :distributed_press_publishers, :default, :boolean, default: false
|
||||
|
||||
DistributedPressPublisher.last.update(default: true)
|
||||
DistributedPressPublisher.last&.update(default: true)
|
||||
end
|
||||
|
||||
def down
|
||||
|
|
|
@ -16,9 +16,7 @@ class CreateFediblockStates < ActiveRecord::Migration[6.1]
|
|||
# Todas las listas están activas por defecto
|
||||
DeploySocialDistributedPress.find_each do |deploy|
|
||||
ActivityPub::Fediblock.find_each do |fediblock|
|
||||
FediblockState.create(site: deploy.site, fediblock: fediblock, aasm_state: 'disabled').tap do |f|
|
||||
f.enable!
|
||||
end
|
||||
FediblockState.create(site: deploy.site, fediblock: fediblock, aasm_state: 'disabled').tap(&:enable!)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
# decompresión
|
||||
class BrsDecompressorCorruptedSourceError < ActiveRecord::Migration[6.1]
|
||||
def up
|
||||
raise unless HTTParty.get("https://mas.to/api/v2/instance", headers: { "Accept-Encoding": "br;q=1.0,gzip;q=1.0,deflate;q=0.6,identity;q=0.3" }).ok?
|
||||
raise unless HTTParty.get('https://mas.to/api/v2/instance',
|
||||
headers: { 'Accept-Encoding': 'br;q=1.0,gzip;q=1.0,deflate;q=0.6,identity;q=0.3' }).ok?
|
||||
|
||||
QueJob.where("last_error_message like '%BRS::DecompressorCorruptedSourceError%'").update_all(error_count: 0, run_at: Time.now)
|
||||
QueJob.where("last_error_message like '%BRS::DecompressorCorruptedSourceError%'").update_all(error_count: 0,
|
||||
run_at: Time.now)
|
||||
end
|
||||
|
||||
def down; end
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
class FixActivityType < ActiveRecord::Migration[6.1]
|
||||
def up
|
||||
%w[Like Announce].each do |type|
|
||||
ActivityPub::Activity.where(Arel.sql("content->>'type' = '#{type}'")).update_all(type: "ActivityPub::Activity::#{type}", updated_at: Time.now)
|
||||
ActivityPub::Activity.where(Arel.sql("content->>'type' = '#{type}'")).update_all(
|
||||
type: "ActivityPub::Activity::#{type}", updated_at: Time.now
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# De alguna forma se guardaron objetos duplicados!
|
||||
class FixDuplicateObjects < ActiveRecord::Migration[6.1]
|
||||
def up
|
||||
ActivityPub::Object.group(:uri).count.select { |_, v| v > 1 }.keys.each do |uri|
|
||||
ActivityPub::Object.group(:uri).count.select { |_, v| v > 1 }.each_key do |uri|
|
||||
objects = ActivityPub::Object.where(uri: uri)
|
||||
deleted_ids = objects[1..].map(&:delete).map(&:id)
|
||||
|
||||
|
|
|
@ -14,9 +14,7 @@ class AddFedipactToFediblocks < ActiveRecord::Migration[6.1]
|
|||
)
|
||||
|
||||
DeploySocialDistributedPress.find_each do |deploy|
|
||||
FediblockState.create(site: deploy.site, fediblock: fedipact, aasm_state: 'disabled').tap do |f|
|
||||
f.enable!
|
||||
end
|
||||
FediblockState.create(site: deploy.site, fediblock: fedipact, aasm_state: 'disabled').tap(&:enable!)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
# no es válida y por eso teníamos objetos duplicados.
|
||||
class AddMissingUniqueIndexes < ActiveRecord::Migration[6.1]
|
||||
def up
|
||||
ActivityPub::Object.group(:uri).count.select { |_, v| v > 1 }.keys.each do |uri|
|
||||
ActivityPub::Object.group(:uri).count.select { |_, v| v > 1 }.each_key do |uri|
|
||||
objects = ActivityPub::Object.where(uri: uri)
|
||||
deleted_ids = objects[1..].map(&:delete).map(&:id)
|
||||
|
||||
ActivityPub.where(object_id: deleted_ids).update_all(object_id: objects.first.id, updated_at: Time.now)
|
||||
end
|
||||
|
||||
ActivityPub::Actor.group(:uri).count.select { |_, v| v > 1 }.keys.each do |uri|
|
||||
ActivityPub::Actor.group(:uri).count.select { |_, v| v > 1 }.each_key do |uri|
|
||||
objects = ActivityPub::Actor.where(uri: uri)
|
||||
deleted_ids = objects[1..].map(&:delete).map(&:id)
|
||||
|
||||
|
@ -21,7 +21,7 @@ class AddMissingUniqueIndexes < ActiveRecord::Migration[6.1]
|
|||
ActivityPub::RemoteFlag.where(actor_id: deleted_ids).update_all(actor_id: objects.first.id, updated_at: Time.now)
|
||||
end
|
||||
|
||||
ActivityPub::Instance.group(:hostname).count.select { |_, v| v > 1 }.keys.each do |hostname|
|
||||
ActivityPub::Instance.group(:hostname).count.select { |_, v| v > 1 }.each_key do |hostname|
|
||||
objects = ActivityPub::Instance.where(hostname: hostname)
|
||||
deleted_ids = objects[1..].map(&:delete).map(&:id)
|
||||
|
||||
|
|
|
@ -20,13 +20,13 @@ if CodeOfConduct.count.zero?
|
|||
YAML.safe_load(File.read('db/seeds/codes_of_conduct.yml')).each do |coc|
|
||||
CodeOfConduct.new(**coc).save!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if PrivacyPolicy.count.zero?
|
||||
YAML.safe_load(File.read('db/seeds/privacy_policies.yml')).each do |pp|
|
||||
PrivacyPolicy.new(**pp).save!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
YAML.safe_load(File.read('db/seeds/activity_pub/fediblocks.yml')).each do |fediblock|
|
||||
ActivityPub::Fediblock.find_or_create_by(id: fediblock['id']).tap do |f|
|
||||
|
|
|
@ -91,6 +91,14 @@
|
|||
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: 'Worker-recovered factory'
|
||||
name_es: 'Empresa recuperada'
|
||||
gem: 'empresa-recuperada-jekyll-theme'
|
||||
url: 'https://empresa-recuperada.sutty.nl/'
|
||||
disabled: true
|
||||
description_en: "A template for [empresas recuperadas](https://en.wikipedia.org/wiki/Workers%27_self-management#Empresas_recuperadas_movement). 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'
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
namespace :stats do
|
||||
desc 'Process stats'
|
||||
task process_all: :environment do
|
||||
Site.all.pluck(:id).each do |site_id|
|
||||
UriCollectionJob.perform_now site_id: site_id, once: true
|
||||
StatCollectionJob.perform_now site_id: site_id, once: true
|
||||
Site.all.find_each do |site|
|
||||
UriCollectionJob.perform_now site: site, once: true
|
||||
StatCollectionJob.perform_now site: site, once: true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"@rails/activestorage": "^6.1.3-1",
|
||||
"@rails/ujs": "^6.1.3-1",
|
||||
"@rails/webpacker": "5.4.4",
|
||||
"@suttyweb/editor": "^0.1.27",
|
||||
"@suttyweb/editor": "^0.1.29",
|
||||
"babel-loader": "^8.2.2",
|
||||
"bs-custom-file-input": "^1.3.4",
|
||||
"chart.js": "^3.5.1",
|
||||
|
|
BIN
public/packs/css/application-5688882d.css
(Stored with Git LFS)
BIN
public/packs/css/application-5688882d.css
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/css/application-5688882d.css.br
(Stored with Git LFS)
BIN
public/packs/css/application-5688882d.css.br
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/css/application-5688882d.css.gz
(Stored with Git LFS)
BIN
public/packs/css/application-5688882d.css.gz
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/js/application-32aa31c983405e239377.js
(Stored with Git LFS)
BIN
public/packs/js/application-32aa31c983405e239377.js
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/js/application-32aa31c983405e239377.js.LICENSE.txt
(Stored with Git LFS)
BIN
public/packs/js/application-32aa31c983405e239377.js.LICENSE.txt
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/js/application-32aa31c983405e239377.js.br
(Stored with Git LFS)
BIN
public/packs/js/application-32aa31c983405e239377.js.br
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/js/application-32aa31c983405e239377.js.gz
(Stored with Git LFS)
BIN
public/packs/js/application-32aa31c983405e239377.js.gz
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/js/application-32aa31c983405e239377.js.map
(Stored with Git LFS)
BIN
public/packs/js/application-32aa31c983405e239377.js.map
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/js/application-32aa31c983405e239377.js.map.br
(Stored with Git LFS)
BIN
public/packs/js/application-32aa31c983405e239377.js.map.br
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/js/application-32aa31c983405e239377.js.map.gz
(Stored with Git LFS)
BIN
public/packs/js/application-32aa31c983405e239377.js.map.gz
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/manifest.json
(Stored with Git LFS)
BIN
public/packs/manifest.json
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/manifest.json.br
(Stored with Git LFS)
BIN
public/packs/manifest.json.br
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/manifest.json.gz
(Stored with Git LFS)
BIN
public/packs/manifest.json.gz
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/fonts/forkawesome-webfont-2dfb5f36.woff
(Stored with Git LFS)
BIN
public/packs/media/fonts/forkawesome-webfont-2dfb5f36.woff
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/fonts/forkawesome-webfont-7c20758e.woff2
(Stored with Git LFS)
BIN
public/packs/media/fonts/forkawesome-webfont-7c20758e.woff2
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/fonts/forkawesome-webfont-86541105.svg
(Stored with Git LFS)
BIN
public/packs/media/fonts/forkawesome-webfont-86541105.svg
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/fonts/forkawesome-webfont-86541105.svg.br
(Stored with Git LFS)
BIN
public/packs/media/fonts/forkawesome-webfont-86541105.svg.br
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/fonts/forkawesome-webfont-86541105.svg.gz
(Stored with Git LFS)
BIN
public/packs/media/fonts/forkawesome-webfont-86541105.svg.gz
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/fonts/forkawesome-webfont-e182ad6d.eot
(Stored with Git LFS)
BIN
public/packs/media/fonts/forkawesome-webfont-e182ad6d.eot
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/fonts/forkawesome-webfont-e182ad6d.eot.br
(Stored with Git LFS)
BIN
public/packs/media/fonts/forkawesome-webfont-e182ad6d.eot.br
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/fonts/forkawesome-webfont-e182ad6d.eot.gz
(Stored with Git LFS)
BIN
public/packs/media/fonts/forkawesome-webfont-e182ad6d.eot.gz
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/fonts/forkawesome-webfont-ee4d8bfd.ttf
(Stored with Git LFS)
BIN
public/packs/media/fonts/forkawesome-webfont-ee4d8bfd.ttf
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/fonts/forkawesome-webfont-ee4d8bfd.ttf.br
(Stored with Git LFS)
BIN
public/packs/media/fonts/forkawesome-webfont-ee4d8bfd.ttf.br
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/fonts/forkawesome-webfont-ee4d8bfd.ttf.gz
(Stored with Git LFS)
BIN
public/packs/media/fonts/forkawesome-webfont-ee4d8bfd.ttf.gz
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/images/layers-2x-8f2c4d11.png
(Stored with Git LFS)
BIN
public/packs/media/images/layers-2x-8f2c4d11.png
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/images/layers-416d9136.png
(Stored with Git LFS)
BIN
public/packs/media/images/layers-416d9136.png
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/images/marker-icon-2b3e1faf.png
(Stored with Git LFS)
BIN
public/packs/media/images/marker-icon-2b3e1faf.png
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/images/marker-icon-2x-680f69f3.png
(Stored with Git LFS)
BIN
public/packs/media/images/marker-icon-2x-680f69f3.png
(Stored with Git LFS)
Binary file not shown.
BIN
public/packs/media/images/marker-shadow-a0c6cc14.png
(Stored with Git LFS)
BIN
public/packs/media/images/marker-shadow-a0c6cc14.png
(Stored with Git LFS)
Binary file not shown.
|
@ -1975,10 +1975,10 @@
|
|||
resolved "https://registry.npmjs.org/@stimulus/webpack-helpers/-/webpack-helpers-1.1.1.tgz"
|
||||
integrity sha512-XOkqSw53N9072FLHvpLM25PIwy+ndkSSbnTtjKuyzsv8K5yfkFB2rv68jU1pzqYa9FZLcvZWP4yazC0V38dx9A==
|
||||
|
||||
"@suttyweb/editor@^0.1.27":
|
||||
version "0.1.27"
|
||||
resolved "https://registry.yarnpkg.com/@suttyweb/editor/-/editor-0.1.27.tgz#9415a0b767e72dbe4fbf42ce87e62fb8f5125c31"
|
||||
integrity sha512-Ts9TZtGiRIaHm+ffVBRl+/nuVcANWZNtFsrGacoajgEsagaIyA1cq8qjiNpPoM5ne9vTba3cAaLP04V/uEIhBw==
|
||||
"@suttyweb/editor@^0.1.29":
|
||||
version "0.1.29"
|
||||
resolved "https://registry.yarnpkg.com/@suttyweb/editor/-/editor-0.1.29.tgz#8b5c6ae4e4d546002a96ecd65765d77d2a88d415"
|
||||
integrity sha512-GshI8wE5UqXge2RhwAUxUXTRLPoOX7US9xVu1aLqT/deT/hDyN9S3PxVn9cJBf7uPHEqBzYXGDKWWF79PLqGHw==
|
||||
dependencies:
|
||||
"@floating-ui/dom" "^1.5.1"
|
||||
linkifyjs "^4.1.1"
|
||||
|
|
Loading…
Reference in a new issue