Compare commits
32 commits
Author | SHA1 | Date | |
---|---|---|---|
1b099cf96b | |||
3a170c191b | |||
360eec5c2c | |||
05a38f5b7e | |||
ffa2c80bf1 | |||
06a9b78eee | |||
a64f554f0e | |||
7e0600779e | |||
583a5c0ebc | |||
985ee40aa7 | |||
1fd9524150 | |||
99e9ec2659 | |||
316c04e86a | |||
0ffa7feb29 | |||
0b9d178d90 | |||
134535cb1c | |||
5ab754ff5d | |||
d087c3bb09 | |||
c6b6a1f74e | |||
908a0a90a8 | |||
3bae282d8b | |||
43927d78e7 | |||
f192c14947 | |||
11bbbe3b06 | |||
db8ed8d776 | |||
4bc163a2fb | |||
464ac4df8d | |||
bc1566735d | |||
9473fa7b93 | |||
d6c41d468b | |||
0f92cf193f | |||
8b9fddc171 |
|
@ -1,5 +1,3 @@
|
||||||
DELEGATE=athshe.sutty.nl
|
|
||||||
HAINISH=../haini.sh/haini.sh
|
|
||||||
DATABASE=
|
DATABASE=
|
||||||
RAILS_ENV=
|
RAILS_ENV=
|
||||||
IMAP_SERVER=
|
IMAP_SERVER=
|
||||||
|
|
184
Makefile
184
Makefile
|
@ -1,112 +1,135 @@
|
||||||
SHELL := /bin/bash
|
.SHELL := /bin/bash
|
||||||
.DEFAULT_GOAL := help
|
# Incluir las variables de entorno
|
||||||
|
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||||
|
root_dir := $(patsubst %/,%,$(dir $(mkfile_path)))
|
||||||
|
include $(root_dir)/.env
|
||||||
|
|
||||||
# Copiar el archivo de configuración y avisar cuando hay que
|
delegate := athshe
|
||||||
# actualizarlo.
|
|
||||||
.env: .env.example
|
|
||||||
@test -f $@ || cp -v $< $@
|
|
||||||
@test -f $@ && echo "Revisa $@ para actualizarlo con respecto a $<"
|
|
||||||
@test -f $@ && diff -auN --color $@ $<
|
|
||||||
|
|
||||||
include .env
|
assets := package.json yarn.lock $(shell find app/assets/ app/javascript/ -type f)
|
||||||
|
|
||||||
export
|
alpine_version := 3.13
|
||||||
|
hain ?= ../haini.sh/haini.sh
|
||||||
|
|
||||||
# XXX: El espacio antes del comentario cuenta como espacio
|
env ?= staging
|
||||||
args ?=## Argumentos para Hain
|
|
||||||
commit ?= origin/rails## Commit desde el que actualizar
|
|
||||||
env ?= staging## Entorno del nodo delegado
|
|
||||||
sutty ?= $(SUTTY)## Dirección local
|
|
||||||
delegate ?= $(DELEGATE)## Cambia el nodo delegado
|
|
||||||
hain ?= $(HAINISH)## Ubicación de Hainish
|
|
||||||
|
|
||||||
# El nodo delegado tiene dos entornos, production y staging.
|
|
||||||
# Dependiendo del entorno que elijamos, se van a generar los assets y el
|
|
||||||
# contenedor y subirse a un servidor u otro. No utilizamos CI/CD (aún).
|
|
||||||
#
|
|
||||||
# Production es el entorno de panel.sutty.nl
|
|
||||||
ifeq ($(env),production)
|
ifeq ($(env),production)
|
||||||
container ?= sutty
|
container ?= sutty
|
||||||
## TODO: Cambiar a otra cosa
|
|
||||||
branch ?= rails
|
branch ?= rails
|
||||||
public ?= public
|
public ?= public
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Staging es el entorno de panel.staging.sutty.nl
|
|
||||||
ifeq ($(env),staging)
|
ifeq ($(env),staging)
|
||||||
container := staging
|
container := staging
|
||||||
branch := staging
|
branch := staging
|
||||||
public := staging
|
public := staging
|
||||||
endif
|
endif
|
||||||
|
|
||||||
help: always ## Ayuda
|
export
|
||||||
@echo -e "Sutty\n" | sed -re "s/^.*/\x1B[38;5;197m&\x1B[0m/"
|
|
||||||
@echo -e "Servidor: https://panel.$(SUTTY_WITH_PORT)/\n"
|
|
||||||
@echo -e "Uso: make TAREA args=\"ARGUMENTOS\"\n"
|
|
||||||
@echo -e "Tareas:\n"
|
|
||||||
@grep -E "^[a-z\-]+:.*##" Makefile | sed -re "s/(.*):.*##(.*)/\1;\2/" | column -s ";" -t | sed -re "s/^([^ ]+) /\x1B[38;5;197m\1\x1B[0m/"
|
|
||||||
@echo -e "\nArgumentos:\n"
|
|
||||||
@grep -E "^[a-z\-]+ \?=.*##" Makefile | sed -re "s/(.*) \?=.*##(.*)/\1;\2/" | column -s ";" -t | sed -re "s/^([^ ]+) /\x1B[38;5;197m\1\x1B[0m/"
|
|
||||||
|
|
||||||
assets: node_modules public/packs/manifest.json.br ## Compilar los assets
|
public/packs/manifest.json.br: $(assets)
|
||||||
|
$(hain) 'cd /Sutty/sutty; PANEL_URL=https://panel.sutty.nl RAILS_ENV=production NODE_ENV=production bundle exec rake assets:precompile assets:clean'
|
||||||
|
|
||||||
test: always ## Ejecutar los tests
|
assets: public/packs/manifest.json.br
|
||||||
$(MAKE) rake args="test RAILS_ENV=test $(args)"
|
|
||||||
|
|
||||||
postgresql: /etc/hosts ## Iniciar la base de datos
|
tests := $(shell find test/ -name "*_test.rb")
|
||||||
|
$(tests): always
|
||||||
|
$(hain) 'cd /Sutty/sutty; bundle exec rake test TEST="$@" RAILS_ENV=test'
|
||||||
|
|
||||||
|
test: always
|
||||||
|
$(hain) 'cd /Sutty/sutty; RAILS_ENV=test bundle exec rake test'
|
||||||
|
|
||||||
|
postgresql: /etc/hosts
|
||||||
pgrep postgres >/dev/null || $(hain) postgresql
|
pgrep postgres >/dev/null || $(hain) postgresql
|
||||||
|
|
||||||
serve-js: /etc/hosts node_modules ## Iniciar el servidor de desarrollo de Javascript
|
serve: /etc/hosts postgresql
|
||||||
$(hain) 'bundle exec ./bin/webpack-dev-server'
|
|
||||||
|
|
||||||
serve: /etc/hosts postgresql Gemfile.lock ## Iniciar el servidor de desarrollo de Rails
|
|
||||||
$(MAKE) rails args=server
|
$(MAKE) rails args=server
|
||||||
|
|
||||||
rails: ## Corre rails dentro del entorno de desarrollo (pasar argumentos con args=).
|
# make rails args="db:migrate"
|
||||||
|
rails:
|
||||||
$(MAKE) bundle args="exec rails $(args)"
|
$(MAKE) bundle args="exec rails $(args)"
|
||||||
|
|
||||||
rake: ## Corre rake dentro del entorno de desarrollo (pasar argumentos con args=).
|
rake:
|
||||||
$(MAKE) bundle args="exec rake $(args)"
|
$(MAKE) bundle args="exec rake $(args)"
|
||||||
|
|
||||||
bundle: ## Corre bundle dentro del entorno de desarrollo (pasar argumentos con args=).
|
bundle:
|
||||||
$(hain) 'bundle $(args)'
|
$(hain) 'cd /Sutty/sutty; bundle $(args)'
|
||||||
|
|
||||||
rubocop: ## Yutea el código que está por ser commiteado
|
yarn:
|
||||||
git status --porcelain \
|
|
||||||
| grep -E "^(A|M)" \
|
|
||||||
| sed "s/^...//" \
|
|
||||||
| grep ".rb$$" \
|
|
||||||
| ../haini.sh/haini.sh "xargs -r ./bin/rubocop --auto-correct"
|
|
||||||
|
|
||||||
audit: ## Encuentra dependencias con vulnerabilidades
|
|
||||||
$(hain) 'gem install bundler-audit'
|
|
||||||
$(hain) 'bundle audit --update'
|
|
||||||
|
|
||||||
brakeman: ## Busca posibles vulnerabilidades en Sutty
|
|
||||||
$(MAKE) bundle args='exec brakeman'
|
|
||||||
|
|
||||||
yarn: ## Tareas de yarn
|
|
||||||
$(hain) 'yarn $(args)'
|
$(hain) 'yarn $(args)'
|
||||||
|
|
||||||
clean: ## Limpieza
|
# Servir JS con el dev server.
|
||||||
rm -rf _sites/test-* _deploy/test-* log/*.log tmp/cache tmp/letter_opener tmp/miniprofiler tmp/storage
|
# Esto acelera la compilación del javascript, tiene que correrse por separado
|
||||||
|
# de serve.
|
||||||
|
serve-js: /etc/hosts
|
||||||
|
$(hain) 'cd /Sutty/sutty; bundle exec ./bin/webpack-dev-server'
|
||||||
|
|
||||||
build: Gemfile.lock ## Generar la imagen Docker
|
# Limpiar los archivos de testeo
|
||||||
|
clean:
|
||||||
|
rm -rf _sites/test-* _deploy/test-*
|
||||||
|
|
||||||
|
# Generar la imagen Docker
|
||||||
|
build: assets
|
||||||
time docker build --build-arg="BRANCH=$(branch)" --build-arg="RAILS_MASTER_KEY=`cat config/master.key`" -t sutty/$(container) .
|
time docker build --build-arg="BRANCH=$(branch)" --build-arg="RAILS_MASTER_KEY=`cat config/master.key`" -t sutty/$(container) .
|
||||||
docker tag sutty/$(container):latest sutty:keep
|
docker tag sutty/$(container):latest sutty:keep
|
||||||
@echo -e "\a"
|
|
||||||
|
|
||||||
save: ## Subir la imagen Docker al nodo delegado
|
save:
|
||||||
time docker save sutty/$(container):latest | ssh root@$(delegate) docker load
|
time docker save sutty/$(container):latest | ssh root@$(delegate).sutty.nl docker load
|
||||||
date +%F | xargs -I {} git tag -f $(container)-{}
|
date +%F | xargs -I {} git tag -f $(container)-{}
|
||||||
@echo -e "\a"
|
@echo -e "\a"
|
||||||
|
|
||||||
ota-js: assets ## Actualizar Javascript en el nodo delegado
|
# proyectos.
|
||||||
sudo chgrp -R 82 public/
|
../gems/:
|
||||||
rsync -avi --delete-after public/ root@$(delegate):/srv/sutty/srv/http/data/_$(public)/
|
mkdir -p $@
|
||||||
ssh root@$(delegate) docker exec $(container) sh -c "cat /srv/http/tmp/puma.pid | xargs -r kill -USR2"
|
|
||||||
|
|
||||||
ota: ## Actualizar Rails en el nodo delegado
|
# Crear el directorio donde se almacenan las gemas binarias
|
||||||
|
# TODO: Mover a un proyecto propio, porque lo utilizamos en todos los
|
||||||
|
gem_dir := $(shell readlink -f ../gems)
|
||||||
|
gem_cache_dir := $(gem_dir)/cache
|
||||||
|
gem_binary_dir := $(gem_dir)/$(alpine_version)
|
||||||
|
ifeq ($(MAKECMDGOALS),build-gems)
|
||||||
|
gems := $(shell bundle show --paths | xargs -I {} sh -c 'find {}/ext/ -name extconf.rb &>/dev/null && basename {}')
|
||||||
|
gems := $(patsubst %-x86_64-linux,%,$(gems))
|
||||||
|
gems := $(patsubst %,$(gem_cache_dir)/%.gem,$(gems))
|
||||||
|
gems_musl := $(patsubst $(gem_cache_dir)/%.gem,$(gem_binary_dir)/%-x86_64-linux-musl.gem,$(gems))
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(gem_binary_dir)/%-x86_64-linux-musl.gem:
|
||||||
|
@docker run \
|
||||||
|
-v $(gem_dir):/srv/gems \
|
||||||
|
-v `readlink -f ~/.ccache`:/home/builder/.ccache \
|
||||||
|
-e HTTP_BASIC_USER=$(HTTP_BASIC_USER) \
|
||||||
|
-e HTTP_BASIC_PASSWORD=$(HTTP_BASIC_PASSWORD) \
|
||||||
|
-e GEM=`echo $(notdir $*) | sed -re "s/-[^-]+$$//"` \
|
||||||
|
-e VERSION=`echo $(notdir $*) | sed -re "s/.*-([^-]+)$$/\1/"` \
|
||||||
|
-e JOBS=2 \
|
||||||
|
--rm -it \
|
||||||
|
sutty/gem-compiler:latest || echo "No se pudo compilar $*"
|
||||||
|
|
||||||
|
# Compilar todas las gemas binarias y subirlas a gems.sutty.nl para que
|
||||||
|
# al crear el contenedor no tengamos que compilarlas cada vez
|
||||||
|
build-gems: $(gems_musl)
|
||||||
|
|
||||||
|
cached_gems = $(wildcard $(gem_dir)/cache/*.gem)
|
||||||
|
rebuild_gems = $(patsubst $(gem_dir)/cache/%.gem,$(gem_dir)/$(alpine_version)/%-x86_64-linux-musl.gem,$(cached_gems))
|
||||||
|
rebuild-gems: $(rebuild_gems)
|
||||||
|
|
||||||
|
dirs := $(patsubst %,root/%,data sites deploy public)
|
||||||
|
|
||||||
|
$(dirs):
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
ota: assets
|
||||||
|
sudo chgrp -R 82 public/
|
||||||
|
rsync -avi --delete-after public/ $(delegate):/srv/sutty/srv/http/data/_$(public)/
|
||||||
|
rsync -avi --delete-after public/ $(delegate):/srv/sutty/srv/http/data/_public/_staging/
|
||||||
|
ssh $(delegate) docker exec $(container) sh -c "cat /srv/http/tmp/puma.pid | xargs -r kill -USR2"
|
||||||
|
|
||||||
|
# Hotfixes
|
||||||
|
#
|
||||||
|
# TODO: Reemplazar esto por git pull en el contenedor
|
||||||
|
commit ?= origin/rails
|
||||||
|
ota-rb:
|
||||||
umask 022; git format-patch $(commit)
|
umask 022; git format-patch $(commit)
|
||||||
scp ./0*.patch $(delegate):/tmp/
|
scp ./0*.patch $(delegate):/tmp/
|
||||||
ssh $(delegate) mkdir -p /tmp/patches-$(commit)/
|
ssh $(delegate) mkdir -p /tmp/patches-$(commit)/
|
||||||
|
@ -118,19 +141,6 @@ ota: ## Actualizar Rails en el nodo delegado
|
||||||
ssh $(delegate) docker exec $(container) ota $(commit)
|
ssh $(delegate) docker exec $(container) ota $(commit)
|
||||||
rm ./0*.patch
|
rm ./0*.patch
|
||||||
|
|
||||||
# Todos los archivos de assets. Si alguno cambia, se van a recompilar
|
|
||||||
# los assets que luego se suben al nodo delegado.
|
|
||||||
assets := package.json yarn.lock $(shell find app/assets/ app/javascript/ -type f)
|
|
||||||
public/packs/manifest.json.br: $(assets)
|
|
||||||
$(hain) 'PANEL_URL=https://panel.sutty.nl RAILS_ENV=production NODE_ENV=production bundle exec rake assets:precompile assets:clean'
|
|
||||||
|
|
||||||
# Correr un test en particular por ejemplo
|
|
||||||
# `make test/models/usuarie_test.rb`
|
|
||||||
tests := $(shell find test/ -name "*_test.rb")
|
|
||||||
$(tests): always
|
|
||||||
$(MAKE) test args="TEST=$@"
|
|
||||||
|
|
||||||
# Agrega las direcciones locales al sistema
|
|
||||||
/etc/hosts: always
|
/etc/hosts: always
|
||||||
@echo "Chequeando si es necesario agregar el dominio local $(SUTTY)"
|
@echo "Chequeando si es necesario agregar el dominio local $(SUTTY)"
|
||||||
@grep -q " $(SUTTY)$$" $@ || echo -e "127.0.0.1 $(SUTTY)\n::1 $(SUTTY)" | sudo tee -a $@
|
@grep -q " $(SUTTY)$$" $@ || echo -e "127.0.0.1 $(SUTTY)\n::1 $(SUTTY)" | sudo tee -a $@
|
||||||
|
@ -138,12 +148,4 @@ $(tests): always
|
||||||
@grep -q " panel.$(SUTTY)$$" $@ || echo -e "127.0.0.1 panel.$(SUTTY)\n::1 panel.$(SUTTY)" | sudo tee -a $@
|
@grep -q " panel.$(SUTTY)$$" $@ || echo -e "127.0.0.1 panel.$(SUTTY)\n::1 panel.$(SUTTY)" | sudo tee -a $@
|
||||||
@grep -q " postgresql.$(SUTTY)$$" $@ || echo -e "127.0.0.1 postgresql.$(SUTTY)\n::1 postgresql.$(SUTTY)" | sudo tee -a $@
|
@grep -q " postgresql.$(SUTTY)$$" $@ || echo -e "127.0.0.1 postgresql.$(SUTTY)\n::1 postgresql.$(SUTTY)" | sudo tee -a $@
|
||||||
|
|
||||||
# Instala las dependencias de Javascript
|
|
||||||
node_modules: package.json
|
|
||||||
$(MAKE) yarn
|
|
||||||
|
|
||||||
# Instala las dependencias de Rails
|
|
||||||
Gemfile.lock: Gemfile
|
|
||||||
$(MAKE) bundle args=install
|
|
||||||
|
|
||||||
.PHONY: always
|
.PHONY: always
|
||||||
|
|
21
README.md
21
README.md
|
@ -15,17 +15,6 @@ Este repositorio es la plataforma _Ruby on Rails_ para alojar el
|
||||||
|
|
||||||
Para más información visita el [sitio de Sutty](https://sutty.nl/).
|
Para más información visita el [sitio de Sutty](https://sutty.nl/).
|
||||||
|
|
||||||
### Desarrollar
|
|
||||||
|
|
||||||
Todas las tareas se gestionan con `make`, por favor instala GNU Make
|
|
||||||
antes de comenzar.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make help
|
|
||||||
```
|
|
||||||
|
|
||||||
[Leer la documentación](https://docs.sutty.nl/)
|
|
||||||
|
|
||||||
## English
|
## English
|
||||||
|
|
||||||
Sutty is a platform for hosting safer, faster and more resilient
|
Sutty is a platform for hosting safer, faster and more resilient
|
||||||
|
@ -36,13 +25,3 @@ This repository is the Ruby on Rails platform that hosts the
|
||||||
self-managed [panel](https://panel.sutty.nl/).
|
self-managed [panel](https://panel.sutty.nl/).
|
||||||
|
|
||||||
For more information, visit [Sutty's website](https://sutty.nl/en/).
|
For more information, visit [Sutty's website](https://sutty.nl/en/).
|
||||||
|
|
||||||
### Development
|
|
||||||
|
|
||||||
Every task is run via `make`, please install GNU Make before developing.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make help
|
|
||||||
```
|
|
||||||
|
|
||||||
[Read the documentation](https://docs.sutty.nl/en/)
|
|
||||||
|
|
|
@ -19,6 +19,10 @@ import {
|
||||||
} from "editor/types/multimedia";
|
} from "editor/types/multimedia";
|
||||||
import { setupAuxiliaryToolbar as setupMarkAuxiliaryToolbar } from "editor/types/mark";
|
import { setupAuxiliaryToolbar as setupMarkAuxiliaryToolbar } from "editor/types/mark";
|
||||||
|
|
||||||
|
/// @ts-ignore
|
||||||
|
import SuttyEditor from "@suttyweb/editor";
|
||||||
|
import "@suttyweb/editor/dist/style.css";
|
||||||
|
|
||||||
// Esta funcion corrije errores que pueden haber como:
|
// Esta funcion corrije errores que pueden haber como:
|
||||||
// * que un nodo que no tiene 'text' permitido no tenga children (se les
|
// * que un nodo que no tiene 'text' permitido no tenga children (se les
|
||||||
// inserta un allowedChildren[0])
|
// inserta un allowedChildren[0])
|
||||||
|
@ -330,10 +334,15 @@ document.addEventListener("turbolinks:load", () => {
|
||||||
".editor[data-editor]"
|
".editor[data-editor]"
|
||||||
)) {
|
)) {
|
||||||
try {
|
try {
|
||||||
setupEditor(editorEl);
|
new SuttyEditor({
|
||||||
|
target: editorEl,
|
||||||
|
props: {
|
||||||
|
textareaEl: editorEl.parentElement!.querySelector("textarea"),
|
||||||
|
},
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// TODO: mostrar error
|
console.error(error);
|
||||||
console.error("no se pudo iniciar el editor, error completo", error);
|
alert(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,23 +5,13 @@ class DeployJob < ApplicationJob
|
||||||
class DeployException < StandardError; end
|
class DeployException < StandardError; end
|
||||||
|
|
||||||
# rubocop:disable Metrics/MethodLength
|
# rubocop:disable Metrics/MethodLength
|
||||||
def perform(site, notify = true, time = Time.now)
|
def perform(site, notify = true)
|
||||||
ActiveRecord::Base.connection_pool.with_connection do
|
ActiveRecord::Base.connection_pool.with_connection do
|
||||||
@site = Site.find(site)
|
@site = Site.find(site)
|
||||||
|
|
||||||
# Si ya hay una tarea corriendo, aplazar esta. Si estuvo
|
# Si ya hay una tarea corriendo, aplazar esta
|
||||||
# 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?
|
||||||
if 10.minutes.ago >= time
|
DeployJob.perform_in(60, site, notify)
|
||||||
@site.update status: 'waiting'
|
|
||||||
raise DeployException,
|
|
||||||
"#{@site.name} la tarea estuvo más de 10 minutos esperando, volviendo al estado original"
|
|
||||||
end
|
|
||||||
|
|
||||||
DeployJob.perform_in(60, site, notify, time)
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -39,11 +29,8 @@ class DeployJob < ApplicationJob
|
||||||
end
|
end
|
||||||
|
|
||||||
deploy_others
|
deploy_others
|
||||||
|
|
||||||
# Volver a la espera
|
|
||||||
@site.update status: 'waiting'
|
|
||||||
|
|
||||||
notify_usuaries if notify
|
notify_usuaries if notify
|
||||||
|
@site.update status: 'waiting'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/MethodLength
|
# rubocop:enable Metrics/MethodLength
|
||||||
|
|
|
@ -80,7 +80,7 @@ class DeployLocal < Deploy
|
||||||
|
|
||||||
# Corre yarn dentro del repositorio
|
# Corre yarn dentro del repositorio
|
||||||
def yarn
|
def yarn
|
||||||
return true unless yarn_lock?
|
return unless yarn_lock?
|
||||||
|
|
||||||
run 'yarn'
|
run 'yarn'
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,119 +9,6 @@
|
||||||
.alert.alert-info
|
.alert.alert-info
|
||||||
:markdown
|
:markdown
|
||||||
#{t('editor.alert')}
|
#{t('editor.alert')}
|
||||||
= text_area_tag "#{base}[#{attribute}]", '',
|
= text_area_tag "#{base}[#{attribute}]", metadata.value.html_safe,
|
||||||
dir: dir, lang: locale,
|
dir: dir, lang: locale,
|
||||||
**field_options(attribute, metadata), class: 'd-none'
|
**field_options(attribute, metadata)
|
||||||
|
|
||||||
-#
|
|
||||||
el > se come el salto de línea y hace que los botones no tengan
|
|
||||||
espacio adicional
|
|
||||||
|
|
||||||
TODO: Eliminar todo el espacio en blanco para minificar HTML
|
|
||||||
.editor-toolbar{ style: 'z-index: 1' }
|
|
||||||
.editor-primary-toolbar.scrollbar-black
|
|
||||||
%button.btn{ type: 'button', title: t('editor.multimedia'), data: { editor_button: 'multimedia' } }>
|
|
||||||
%i.fa.fa-fw.fa-upload>
|
|
||||||
%span.sr-only>= t('editor.multimedia')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.bold'), data: { editor_button: 'mark-bold' } }>
|
|
||||||
%i.fa.fa-fw.fa-bold>
|
|
||||||
%span.sr-only>= t('editor.bold')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.italic'), data: { editor_button: 'mark-italic' } }>
|
|
||||||
%i.fa.fa-fw.fa-italic>
|
|
||||||
%span.sr-only>= t('editor.italic')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.mark'), data: { editor_button: 'mark-mark' } }>
|
|
||||||
%i.fa.fa-fw.fa-tint>
|
|
||||||
%span.sr-only>= t('editor.mark')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.link'), data: { editor_button: 'mark-link' } }>
|
|
||||||
%i.fa.fa-fw.fa-link>
|
|
||||||
%span.sr-only>= t('editor.link')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.deleted'), data: { editor_button: 'mark-deleted' } }>
|
|
||||||
%i.fa.fa-fw.fa-strikethrough>
|
|
||||||
%span.sr-only>= t('editor.deleted')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.underline'), data: { editor_button: 'mark-underline' } }>
|
|
||||||
%i.fa.fa-fw.fa-underline>
|
|
||||||
%span.sr-only>= t('editor.underline')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.super'), data: { editor_button: 'mark-super' } }>
|
|
||||||
%i.fa.fa-fw.fa-superscript>
|
|
||||||
%span.sr-only>= t('editor.super')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.sub'), data: { editor_button: 'mark-sub' } }>
|
|
||||||
%i.fa.fa-fw.fa-subscript>
|
|
||||||
%span.sr-only>= t('editor.sub')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.small'), data: { editor_button: 'mark-small' } }>
|
|
||||||
%i.fa.fa-fw.fa-subscript>
|
|
||||||
%span.sr-only>= t('editor.small')
|
|
||||||
%button.btn.mr-0{ type: 'button', title: t('editor.h1'), data: { editor_button: 'block-h1' } }>
|
|
||||||
%i.fa.fa-fw.fa-heading>
|
|
||||||
1
|
|
||||||
%span.sr-only>= t('editor.h1')
|
|
||||||
%details.d-inline>
|
|
||||||
%summary.d-inline>
|
|
||||||
%span.btn.ml-0{ role: 'button', title: t('editor.more') }>
|
|
||||||
%i.fa.fa-caret-right>
|
|
||||||
%span.sr-only= t('editor.more')
|
|
||||||
.d-inline>
|
|
||||||
%button.btn{ type: 'button', title: t('editor.h2'), data: { editor_button: 'block-h2' } }>
|
|
||||||
%i.fa.fa-fw.fa-heading>
|
|
||||||
2
|
|
||||||
%span.sr-only>= t('editor.h2')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.h3'), data: { editor_button: 'block-h3' } }>
|
|
||||||
%i.fa.fa-fw.fa-heading>
|
|
||||||
3
|
|
||||||
%span.sr-only>= t('editor.h3')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.h4'), data: { editor_button: 'block-h4' } }>
|
|
||||||
%i.fa.fa-fw.fa-heading>
|
|
||||||
4
|
|
||||||
%span.sr-only>= t('editor.h4')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.h5'), data: { editor_button: 'block-h5' } }>
|
|
||||||
%i.fa.fa-fw.fa-heading>
|
|
||||||
5
|
|
||||||
%span.sr-only>= t('editor.h5')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.h6'), data: { editor_button: 'block-h6' } }>
|
|
||||||
%i.fa.fa-fw.fa-heading>
|
|
||||||
6
|
|
||||||
%span.sr-only>= t('editor.h6')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.ul'), data: { editor_button: 'block-unordered_list' } }>
|
|
||||||
%i.fa.fa-fw.fa-list-ul>
|
|
||||||
%span.sr-only>= t('editor.ul')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.ol'), data: { editor_button: 'block-ordered_list' } }>
|
|
||||||
%i.fa.fa-fw.fa-list-ol>
|
|
||||||
%span.sr-only>= t('editor.ol')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.left'), data: { editor_button: 'parentBlock-left' } }>
|
|
||||||
%i.fa.fa-fw.fa-align-left>
|
|
||||||
%span.sr-only>= t('editor.left')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.center'), data: { editor_button: 'parentBlock-center' } }>
|
|
||||||
%i.fa.fa-fw.fa-align-center>
|
|
||||||
%span.sr-only>= t('editor.center')
|
|
||||||
%button.btn{ type: 'button', title: t('editor.right'), data: { editor_button: 'parentBlock-right' } }>
|
|
||||||
%i.fa.fa-fw.fa-align-right>
|
|
||||||
%span.sr-only>= t('editor.right')
|
|
||||||
|
|
||||||
-# HAML cringe
|
|
||||||
.editor-auxiliary-toolbar.mt-1.scrollbar-black{ data: { editor_auxiliary_toolbar: '' } }
|
|
||||||
.form-group{ data: { editor_auxiliary: 'mark' } }
|
|
||||||
%label{ for: 'mark-color' }= t('editor.color')
|
|
||||||
%input.form-control{ type: 'color', name: 'mark-color' }/
|
|
||||||
%label{ for: 'mark-text-color' }= t('editor.text-color')
|
|
||||||
%input.form-control{ type: 'color', name: 'mark-text-color' }/
|
|
||||||
|
|
||||||
%div{ data: { editor_auxiliary: 'multimedia' } }
|
|
||||||
.form-group
|
|
||||||
.custom-file
|
|
||||||
%input.custom-file-input{ type: 'file', id: 'multimedia-file', name: 'multimedia-file' }/
|
|
||||||
%label.custom-file-label{ for: 'multimedia-file' }= t('editor.multimedia-select')
|
|
||||||
.form-group
|
|
||||||
%label{ for: 'multimedia-alt' }= t('editor.description')
|
|
||||||
%input.form-control{ type: 'text', id: 'multimedia-alt', name: 'multimedia-alt' }/
|
|
||||||
.form-group
|
|
||||||
%button.btn{ type: 'button', id: 'multimedia-file-upload', name: 'multimedia-file-upload' }= t('editor.multimedia-upload')
|
|
||||||
%button.btn{ type: 'button', id: 'multimedia-remove', name: 'multimedia-remove' }= t('editor.multimedia-remove')
|
|
||||||
|
|
||||||
.form-group{ data: { editor_auxiliary: 'link' } }
|
|
||||||
%label{ for: 'link-url' }= t('editor.url')
|
|
||||||
%input.form-control{ type: 'url', id: 'link-url', name: 'link-url' }/
|
|
||||||
|
|
||||||
.editor-aviso-word.alert.alert-info
|
|
||||||
%p= t('editor.word')
|
|
||||||
|
|
||||||
.editor-content.form-control.h-auto.mt-1{ contenteditable: 'true' }
|
|
||||||
= metadata.value.html_safe
|
|
||||||
|
|
|
@ -26,8 +26,7 @@ test:
|
||||||
user: <%= ENV['USER'] %>
|
user: <%= ENV['USER'] %>
|
||||||
|
|
||||||
production:
|
production:
|
||||||
adapter: postgresql
|
<<: *default
|
||||||
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
|
|
||||||
database: <%= ENV.fetch('DATABASE') { 'sutty' } %>
|
database: <%= ENV.fetch('DATABASE') { 'sutty' } %>
|
||||||
user: sutty
|
user: sutty
|
||||||
host: postgresql
|
host: postgresql
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
# Agrega la columna de request_uri a la tabla de logs
|
|
||||||
class AddRequestUriToAccessLogs < ActiveRecord::Migration[6.1]
|
|
||||||
def change
|
|
||||||
return unless Rails.env.production?
|
|
||||||
|
|
||||||
add_column :access_logs, :request_uri, :string, default: ''
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -12,6 +12,7 @@
|
||||||
"@rails/activestorage": "^6.1.3-1",
|
"@rails/activestorage": "^6.1.3-1",
|
||||||
"@rails/ujs": "^6.1.3-1",
|
"@rails/ujs": "^6.1.3-1",
|
||||||
"@rails/webpacker": "5.2.1",
|
"@rails/webpacker": "5.2.1",
|
||||||
|
"@suttyweb/editor": "0.0.7",
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.2.2",
|
||||||
"circular-dependency-plugin": "^5.2.2",
|
"circular-dependency-plugin": "^5.2.2",
|
||||||
"commonmark": "^0.29.0",
|
"commonmark": "^0.29.0",
|
||||||
|
|
|
@ -1171,6 +1171,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@stimulus/webpack-helpers/-/webpack-helpers-1.1.1.tgz#eff60cd4e58b921d1a2764dc5215f5141510f2c2"
|
resolved "https://registry.yarnpkg.com/@stimulus/webpack-helpers/-/webpack-helpers-1.1.1.tgz#eff60cd4e58b921d1a2764dc5215f5141510f2c2"
|
||||||
integrity sha512-XOkqSw53N9072FLHvpLM25PIwy+ndkSSbnTtjKuyzsv8K5yfkFB2rv68jU1pzqYa9FZLcvZWP4yazC0V38dx9A==
|
integrity sha512-XOkqSw53N9072FLHvpLM25PIwy+ndkSSbnTtjKuyzsv8K5yfkFB2rv68jU1pzqYa9FZLcvZWP4yazC0V38dx9A==
|
||||||
|
|
||||||
|
"@suttyweb/editor@0.0.7":
|
||||||
|
version "0.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@suttyweb/editor/-/editor-0.0.7.tgz#019c1ab2d43e6a6fb7d4ebf44c44f79ebd5a6896"
|
||||||
|
integrity sha512-fZepXH1pRTdDQWxKSF10lYVlYjoczkqGi00vTaSWDRTL/rnZrgOEakcdFyutcJzYnZWdWsWsF6AUidKvQvd1dw==
|
||||||
|
|
||||||
"@types/caseless@*":
|
"@types/caseless@*":
|
||||||
version "0.12.2"
|
version "0.12.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8"
|
resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8"
|
||||||
|
|
Loading…
Reference in a new issue