version privadas del sitio #180

se puede compilar una versión privada del sitio solo accesible a través
del panel, es decir con los mismos niveles de acceso.  en combinación
con el complemento de jekyll correspondiente, sería posible ver un sitio
con otros datos que no se publican.
This commit is contained in:
f 2020-08-22 21:04:46 -03:00
parent bcab506ff3
commit f77a907753
11 changed files with 160 additions and 5 deletions

1
.gitignore vendored
View file

@ -24,6 +24,7 @@
/_sites/*
/_deploy/*
/_private/*
/data/*
/_storage/*

View file

@ -103,6 +103,7 @@ RUN ln -s data/_storage /srv/http/_storage
RUN ln -s data/_sites /srv/http/_sites
RUN ln -s data/_deploy /srv/http/_deploy
RUN ln -s data/_public /srv/http/_public
RUN ln -s data/_private /srv/http/_private
# Volver a root para cerrar la compilación
USER root

View file

@ -0,0 +1,76 @@
# Gestiona las versiones privadas de los sitios. Solo se puede acceder
# con una cuenta
class PrivateController < ApplicationController
# XXX: Permite ejecutar JS
skip_forgery_protection
include Pundit
rescue_from Pundit::NilPolicyError, with: :page_not_found
# Enviar el archivo si existe, agregar una / al final siempre para no
# romper las direcciones relativas.
def show
authorize site
# Detectar si necesitamos una / al final
if needs_trailing_slash?
redirect_to request.url + '/'
return
end
if deploy_private
send_file path, disposition: 'inline'
else
head :not_found
end
end
private
# Detects if the URL should have a trailing slash
def needs_trailing_slash?
!trailing_slash? && params[:format].blank?
end
def trailing_slash?
request.env['REQUEST_URI'].ends_with?('/')
end
def site
@site ||= find_site
end
def deploy_private
@deploy_private ||= site.deploys.find_by(type: 'DeployPrivate')
end
# Devuelve la ruta completa del archivo
def path
return @path if @path
@path = Pathname.new(File.join(deploy_private.destination, file)).realpath.to_s
raise Errno::ENOENT unless @path.starts_with? deploy_private.destination
@path
rescue Errno::ENOENT
File.join(deploy_private.destination, '404.html')
end
# Devuelve la ruta del archivo, limpieza copiada desde Jekyll
#
# @see Jekyll::URL#sanitize_url
def file
return @file if @file
@file = params[:file] || '/'
@file += '/' if trailing_slash?
@file += if @file.ends_with? '/'
'index.html'
else
'.' + params[:format].to_s
end
@file = @file.gsub('..', '/').gsub('./', '').squeeze('/')
end
end

View file

@ -0,0 +1,23 @@
# frozen_string_literal: true
# Permite generar el sitio en una versión privada, mostrando información
# que no se vería públicamente (borradores, campos privados, etc.)
#
# XXX: La plantilla tiene que soportar esto con el plugin
# jekyll-private-data
class DeployPrivate < DeployLocal
# No es necesario volver a instalar dependencias
def deploy
jekyll_build
end
# Hacer el deploy a un directorio privado
def destination
File.join(Rails.root, '_private', site.name)
end
# No usar recursos en compresión y habilitar los datos privados
def env
@env ||= super.merge({ 'JEKYLL_ENV' => 'development', 'JEKYLL_PRIVATE' => 'true' })
end
end

View file

@ -15,7 +15,7 @@ class Site < ApplicationRecord
# TODO: Hacer que los diferentes tipos de deploy se auto registren
# @see app/services/site_service.rb
DEPLOYS = %i[local www zip hidden_service].freeze
DEPLOYS = %i[local private www zip hidden_service].freeze
validates :name, uniqueness: true, hostname: {
allow_root_label: true

View file

@ -14,6 +14,11 @@ class SitePolicy
true
end
# Puede ver la versión privada del sitio?
def private?
edit? && site.deploys.find_by_type('DeployPrivate')
end
# Todes les usuaries pueden ver el sitio si aceptaron la invitación
def show?
!current_role.temporal

View file

@ -0,0 +1,20 @@
-# Formulario para alojar una copia privada
.row
.col
= deploy.hidden_field :id
= deploy.hidden_field :type
.custom-control.custom-switch
-#
El checkbox invierte la lógica de destrucción porque queremos
crear el deploy si está activado y destruirlo si está
desactivado.
= deploy.check_box :_destroy,
{ checked: deploy.object.persisted?, class: 'custom-control-input' },
'0', '1'
= deploy.label :_destroy, class: 'custom-control-label' do
%h3= t('.title')
= sanitize_markdown t('.help'),
tags: %w[p strong em a]
%hr/

View file

@ -17,8 +17,10 @@
new_site_post_path(@site, layout: layout)
- if policy(@site).edit?
= link_to t('sites.edit.btn', site: @site.title),
edit_site_path(@site), class: 'btn'
= link_to t('sites.edit.btn', site: @site.title), edit_site_path(@site), class: 'btn'
- if policy(@site).private?
= link_to t('sites.private'), '../private/' + @site.name, class: 'btn', target: '_blank'
= render 'sites/build', site: @site

View file

@ -71,6 +71,10 @@ en:
title: Link to www
success: Success!
error: Error
deploy_private:
title: Private version
success: Success!
error: Error
deploy_zip:
title: Build ZIP file
success: Available for download
@ -255,6 +259,13 @@ en:
We're working out the details for allowing your own site
domains, you can help us!
ejemplo: 'example'
deploy_private:
title: 'Generate private version'
help: |
Some templates support gathering private information. By
enabling this option, when changes are published, you and your
collaborators will be able to access this information in a
private copy of the site.
deploy_www:
title: 'Add www to the address'
help: |
@ -337,6 +348,7 @@ en:
title: 'Sites'
enqueued: 'Waiting for build'
enqueue: 'Publish all changes'
private: 'Private version'
failed: 'Failed!'
build_log: 'Read log'
invitations:

View file

@ -79,6 +79,10 @@ es:
title: Alojar como servicio oculto de Tor
success: ¡Éxito!
error: Hubo un error
deploy_private:
title: Versión privada del sitio
success: ¡Éxito!
error: Hubo un error
help: Por cualquier duda, responde este correo para contactarte con nosotres.
maintenance_mailer:
notice:
@ -257,6 +261,13 @@ es:
Estamos desarrollando la posibilidad de agregar tus propios
dominios, ¡ayudanos!
ejemplo: 'ejemplo'
deploy_private:
title: 'Generar versión privada'
help: |
Algunas plantillas contienen información privada, activando esta
opción, al publicar los cambios podrás acceder a una versión
privada del sitio, que solo estará accesible para todes les
colaboradores del sitio.
deploy_www:
title: 'Agregar www a la dirección'
help: |
@ -339,6 +350,7 @@ es:
title: 'Sitios'
enqueued: 'Esperando publicación'
enqueue: 'Publicar todos los cambios'
private: 'Versión privada'
failed: '¡Falló!'
build_log: 'Ver registro'
invitations:

View file

@ -26,9 +26,12 @@ Rails.application.routes.draw do
end
end
resources :sites, constraints: { site_id: %r{[^/]+}, id: %r{[^/]+} } do
get 'public/:type/:basename', to: 'sites#send_public_file'
# Las rutas privadas empiezan con una ruta única para poder hacer un
# alias en nginx sin tener que usar expresiones regulares para
# detectar el nombre del sitio.
get '/sites/private/:site_id(*file)', to: 'private#show', constraints: { site_id: %r{[^/]+} }
resources :sites, constraints: { site_id: %r{[^/]+}, id: %r{[^/]+} } do
# Gestionar actualizaciones del sitio
get 'pull', to: 'sites#fetch'
post 'pull', to: 'sites#merge'