mirror of
https://0xacab.org/sutty/sutty
synced 2025-02-23 14:11:50 +00:00
Merge branch 'rails' into prosemirror
This commit is contained in:
commit
2d492538db
107 changed files with 1166 additions and 498 deletions
12
.env.example
12
.env.example
|
@ -1,7 +1,15 @@
|
||||||
RAILS_ENV=production
|
RAILS_ENV=
|
||||||
IMAP_SERVER=
|
IMAP_SERVER=
|
||||||
DEFAULT_FROM=
|
DEFAULT_FROM=
|
||||||
SKEL_SUTTY=https://0xacab.org/sutty/skel.sutty.nl
|
SKEL_SUTTY=https://0xacab.org/sutty/skel.sutty.nl
|
||||||
SUTTY=sutty.nl
|
SUTTY=sutty.local
|
||||||
|
SUTTY_WITH_PORT=sutty.local:3000
|
||||||
REDIS_SERVER=
|
REDIS_SERVER=
|
||||||
REDIS_CLIENT=
|
REDIS_CLIENT=
|
||||||
|
# API authentication
|
||||||
|
HTTP_BASIC_USER=
|
||||||
|
HTTP_BASIC_PASSWORD=
|
||||||
|
BLAZER_DATABASE_URL=
|
||||||
|
BLAZER_SLACK_WEBHOOK_URL=
|
||||||
|
BLAZER_USERNAME=
|
||||||
|
BLAZER_PASSWORD=
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -39,3 +39,6 @@
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
.yarn-integrity
|
.yarn-integrity
|
||||||
/vendor
|
/vendor
|
||||||
|
|
||||||
|
*.key
|
||||||
|
*.crt
|
||||||
|
|
58
.rubocop.yml
58
.rubocop.yml
|
@ -1,61 +1,5 @@
|
||||||
AllCops:
|
AllCops:
|
||||||
TargetRubyVersion: '2.5'
|
TargetRubyVersion: '2.6'
|
||||||
|
|
||||||
Style/AsciiComments:
|
Style/AsciiComments:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Sólo existe para molestarnos (?)
|
|
||||||
Metrics/AbcSize:
|
|
||||||
Enabled: false
|
|
||||||
|
|
||||||
Metrics/LineLength:
|
|
||||||
Exclude:
|
|
||||||
- 'db/schema.rb'
|
|
||||||
- 'db/migrate/*.rb'
|
|
||||||
- 'app/models/site.rb'
|
|
||||||
|
|
||||||
Metrics/MethodLength:
|
|
||||||
Exclude:
|
|
||||||
- 'db/schema.rb'
|
|
||||||
- 'db/migrate/*.rb'
|
|
||||||
- 'app/models/site.rb'
|
|
||||||
- 'app/controllers/sites_controller.rb'
|
|
||||||
- 'app/controllers/posts_controller.rb'
|
|
||||||
- 'app/controllers/invitadxs_controller.rb'
|
|
||||||
- 'app/controllers/i18n_controller.rb'
|
|
||||||
- 'app/controllers/collaborations_controller.rb'
|
|
||||||
- 'app/controllers/usuaries_controller.rb'
|
|
||||||
- 'app/models/post.rb'
|
|
||||||
|
|
||||||
Metrics/BlockLength:
|
|
||||||
Exclude:
|
|
||||||
- 'config/environments/development.rb'
|
|
||||||
- 'config/environments/production.rb'
|
|
||||||
- 'config/initializers/devise.rb'
|
|
||||||
- 'db/schema.rb'
|
|
||||||
- 'config/routes.rb'
|
|
||||||
- 'test/controllers/sites_controller_test.rb'
|
|
||||||
|
|
||||||
Metrics/ClassLength:
|
|
||||||
Exclude:
|
|
||||||
- 'app/models/site.rb'
|
|
||||||
- 'app/controllers/posts_controller.rb'
|
|
||||||
- 'app/controllers/sites_controller.rb'
|
|
||||||
- 'test/models/post_test.rb'
|
|
||||||
- 'test/controllers/sites_controller_test.rb'
|
|
||||||
|
|
||||||
Lint/HandleExceptions:
|
|
||||||
Exclude:
|
|
||||||
- 'app/controllers/posts_controller.rb'
|
|
||||||
|
|
||||||
Style/GuardClause:
|
|
||||||
Exclude:
|
|
||||||
- 'app/controllers/posts_controller.rb'
|
|
||||||
|
|
||||||
Metrics/PerceivedComplexity:
|
|
||||||
Exclude:
|
|
||||||
- 'app/controllers/posts_controller.rb'
|
|
||||||
|
|
||||||
Lint/UnreachableCode:
|
|
||||||
Exclude:
|
|
||||||
- 'app/policies/post_policy.rb'
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2.5.7
|
2.6.5
|
||||||
|
|
98
Dockerfile
98
Dockerfile
|
@ -2,7 +2,8 @@
|
||||||
# el mismo repositorio de trabajo. Cuando tengamos CI/CD algunas cosas
|
# el mismo repositorio de trabajo. Cuando tengamos CI/CD algunas cosas
|
||||||
# como el tarball van a tener que cambiar porque ya vamos a haber hecho
|
# como el tarball van a tener que cambiar porque ya vamos a haber hecho
|
||||||
# un clone/pull limpio.
|
# un clone/pull limpio.
|
||||||
FROM sutty/sdk-ruby:latest as build
|
FROM sutty/oxipng:latest as oxipng
|
||||||
|
FROM alpine:3.11 as build
|
||||||
MAINTAINER "f <f@sutty.nl>"
|
MAINTAINER "f <f@sutty.nl>"
|
||||||
|
|
||||||
ARG RAILS_MASTER_KEY
|
ARG RAILS_MASTER_KEY
|
||||||
|
@ -13,10 +14,21 @@ ENV SECRET_KEY_BASE solo_es_necesaria_para_correr_rake
|
||||||
ENV RAILS_ENV production
|
ENV RAILS_ENV production
|
||||||
ENV RAILS_MASTER_KEY=$RAILS_MASTER_KEY
|
ENV RAILS_MASTER_KEY=$RAILS_MASTER_KEY
|
||||||
|
|
||||||
# Para compilar los assets en brotli
|
RUN apk add --no-cache libxslt libxml2 tzdata ruby ruby-bundler ruby-json ruby-bigdecimal ruby-rake
|
||||||
RUN apk add --no-cache brotli libssh2
|
RUN apk add --no-cache postgresql-libs git yarn brotli libssh2 python
|
||||||
|
|
||||||
# Empezamos con la usuaria app creada por sdk-ruby
|
# https://github.com/rubygems/rubygems/issues/2918
|
||||||
|
# https://gitlab.alpinelinux.org/alpine/aports/issues/10808
|
||||||
|
COPY ./rubygems-platform-musl.patch /tmp/
|
||||||
|
RUN cd /usr/lib/ruby/2.6.0 && patch -Np 0 -i /tmp/rubygems-platform-musl.patch
|
||||||
|
|
||||||
|
# Agregar el usuario
|
||||||
|
RUN addgroup -g 82 -S www-data
|
||||||
|
RUN adduser -s /bin/sh -G www-data -h /home/app -D app
|
||||||
|
RUN install -dm750 -o app -g www-data /home/app/sutty
|
||||||
|
RUN gem install --no-document bundler:2.0.2
|
||||||
|
|
||||||
|
# Empezamos con la usuaria app
|
||||||
USER app
|
USER app
|
||||||
# Vamos a trabajar dentro de este directorio
|
# Vamos a trabajar dentro de este directorio
|
||||||
WORKDIR /home/app/sutty
|
WORKDIR /home/app/sutty
|
||||||
|
@ -24,25 +36,23 @@ WORKDIR /home/app/sutty
|
||||||
# Copiamos solo el Gemfile para poder instalar las gemas necesarias
|
# Copiamos solo el Gemfile para poder instalar las gemas necesarias
|
||||||
COPY --chown=app:www-data ./Gemfile .
|
COPY --chown=app:www-data ./Gemfile .
|
||||||
COPY --chown=app:www-data ./Gemfile.lock .
|
COPY --chown=app:www-data ./Gemfile.lock .
|
||||||
# XXX: No usamos la flag --production porque luego no nos deja
|
|
||||||
# desinstalar las gemas de los assets
|
|
||||||
# RUN --mount=type=cache,target=/home/app/.ccache \
|
|
||||||
RUN bundle install --no-cache --path=./vendor --without='test development'
|
RUN bundle install --no-cache --path=./vendor --without='test development'
|
||||||
# Vaciar la caché
|
# Vaciar la caché
|
||||||
RUN rm vendor/ruby/2.5.0/cache/*.gem
|
RUN rm vendor/ruby/2.6.0/cache/*.gem
|
||||||
# Limpiar las librerías nativas, esto ahorra más espacio y uso de
|
|
||||||
# memoria ya que no hay que cargar símbolos que no se van a usar.
|
|
||||||
RUN find vendor -name "*.so" | xargs -rn 1 strip --strip-unneeded
|
|
||||||
|
|
||||||
# Copiar el repositorio git
|
# Copiar el repositorio git
|
||||||
COPY --chown=app:www-data ./.git/ ./.git/
|
COPY --chown=app:www-data ./.git/ ./.git/
|
||||||
# Hacer un tarball de los archivos desde el repositorio
|
# Hacer un clon limpio del repositorio en lugar de copiar todos los
|
||||||
RUN git archive -o ../sutty.tar.gz HEAD
|
# archivos
|
||||||
|
RUN cd .. && git clone sutty checkout
|
||||||
|
|
||||||
|
WORKDIR /home/app/checkout
|
||||||
|
# Traer las gemas:
|
||||||
|
RUN mv ../sutty/vendor ./vendor
|
||||||
|
RUN mv ../sutty/.bundle ./.bundle
|
||||||
|
|
||||||
# Extraer archivos necesarios para compilar los assets
|
|
||||||
RUN tar xf ../sutty.tar.gz Rakefile config app bin yarn.lock package.json
|
|
||||||
# Instalar secretos
|
# Instalar secretos
|
||||||
COPY --chown=app:www-data ./config/credentials.yml.enc ./config/
|
COPY --chown=app:root ./config/credentials.yml.enc ./config/
|
||||||
# Pre-compilar los assets
|
# Pre-compilar los assets
|
||||||
RUN bundle exec rake assets:precompile
|
RUN bundle exec rake assets:precompile
|
||||||
# Comprimirlos usando brotli
|
# Comprimirlos usando brotli
|
||||||
|
@ -52,71 +62,51 @@ RUN find public -type f -name "*.gz" | sed -re "s/\.gz$//" | xargs -r brotli -k
|
||||||
# assets ya están pre-compilados.
|
# assets ya están pre-compilados.
|
||||||
RUN sed -re "/(uglifier|bootstrap|coffee-rails)/d" -i Gemfile
|
RUN sed -re "/(uglifier|bootstrap|coffee-rails)/d" -i Gemfile
|
||||||
RUN bundle clean
|
RUN bundle clean
|
||||||
|
RUN rm -rf ./node_modules ./tmp/cache ./.git
|
||||||
|
|
||||||
# Contenedor final
|
# Contenedor final
|
||||||
FROM sutty/monit:latest
|
FROM sutty/monit:latest
|
||||||
ENV RAILS_ENV production
|
ENV RAILS_ENV production
|
||||||
|
|
||||||
|
# Instalar oxipng
|
||||||
|
COPY --from=oxipng --chown=root:root /root/.cargo/bin/oxipng /usr/bin/oxipng
|
||||||
|
RUN chmod 755 /usr/bin/oxipng
|
||||||
|
|
||||||
# Instalar las dependencias, separamos la librería de base de datos para
|
# Instalar las dependencias, separamos la librería de base de datos para
|
||||||
# poder reutilizar este primer paso desde otros contenedores
|
# poder reutilizar este primer paso desde otros contenedores
|
||||||
RUN apk add --no-cache libxslt libxml2 tzdata ruby ruby-bundler ruby-json ruby-bigdecimal ruby-rake
|
RUN apk add --no-cache libxslt libxml2 tzdata ruby ruby-bundler ruby-json ruby-bigdecimal ruby-rake
|
||||||
|
RUN apk add --no-cache postgresql-libs libssh2 file rsync git jpegoptim vips
|
||||||
|
|
||||||
# Chequear que la versión de ruby sea la correcta
|
# Chequear que la versión de ruby sea la correcta
|
||||||
RUN test "2.5.7" = `ruby -e 'puts RUBY_VERSION'`
|
RUN test "2.6.5" = `ruby -e 'puts RUBY_VERSION'`
|
||||||
|
|
||||||
|
# https://github.com/rubygems/rubygems/issues/2918
|
||||||
|
# https://gitlab.alpinelinux.org/alpine/aports/issues/10808
|
||||||
|
COPY ./rubygems-platform-musl.patch /tmp/
|
||||||
|
RUN cd /usr/lib/ruby/2.6.0 && patch -Np 0 -i /tmp/rubygems-platform-musl.patch
|
||||||
|
|
||||||
RUN apk add --no-cache postgresql-libs libssh2
|
|
||||||
# Necesitamos yarn para que Jekyll pueda generar los sitios
|
# Necesitamos yarn para que Jekyll pueda generar los sitios
|
||||||
# XXX: Eliminarlo cuando extraigamos la generación de sitios del proceso
|
# XXX: Eliminarlo cuando extraigamos la generación de sitios del proceso
|
||||||
# principal
|
# principal
|
||||||
RUN apk add --no-cache yarn
|
RUN apk add --no-cache yarn
|
||||||
# Instalar foreman para poder correr los servicios
|
# Instalar foreman para poder correr los servicios
|
||||||
RUN gem install --no-document --no-user-install foreman
|
RUN gem install --no-document --no-user-install bundler foreman
|
||||||
RUN apk add --no-cache file
|
|
||||||
|
|
||||||
# Agregar el grupo del servidor web
|
# Agregar el grupo del servidor web y la usuaria
|
||||||
RUN addgroup -g 82 -S www-data
|
RUN addgroup -g 82 -S www-data
|
||||||
# Agregar la usuaria
|
|
||||||
RUN adduser -s /bin/sh -G www-data -h /srv/http -D app
|
RUN adduser -s /bin/sh -G www-data -h /srv/http -D app
|
||||||
|
|
||||||
# https://github.com/rubygems/rubygems/issues/2918
|
|
||||||
# https://gitlab.alpinelinux.org/alpine/aports/issues/10808
|
|
||||||
COPY ./rubygems-platform-musl.patch /tmp/
|
|
||||||
RUN cd /usr/lib/ruby/2.5.0 && patch -Np 0 -i /tmp/rubygems-platform-musl.patch
|
|
||||||
|
|
||||||
# Convertirse en app para instalar
|
# Convertirse en app para instalar
|
||||||
USER app
|
USER app
|
||||||
WORKDIR /srv/http
|
COPY --from=build --chown=app:www-data /home/app/checkout /srv/http
|
||||||
|
|
||||||
# Traer los archivos y colocarlos donde van definitivamente
|
|
||||||
COPY --from=build --chown=app:www-data /home/app/sutty.tar.gz /tmp/
|
|
||||||
RUN tar xf /tmp/sutty.tar.gz
|
|
||||||
# Publicar el código!
|
|
||||||
RUN mv /tmp/sutty.tar.gz ./public/
|
|
||||||
|
|
||||||
# Traer los assets compilados y las gemas
|
|
||||||
COPY --from=build /home/app/sutty/public/assets public/assets
|
|
||||||
COPY --from=build /home/app/sutty/public/packs public/packs
|
|
||||||
COPY --from=build /home/app/sutty/vendor vendor
|
|
||||||
COPY --from=build /home/app/sutty/.bundle .bundle
|
|
||||||
COPY --from=build /home/app/sutty/Gemfile Gemfile
|
|
||||||
COPY --from=build /home/app/sutty/Gemfile.lock Gemfile.lock
|
|
||||||
|
|
||||||
# Volver a root para cerrar la compilación
|
# Volver a root para cerrar la compilación
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
# Convertir la aplicación en solo lectura
|
|
||||||
#RUN chown -R root:root /srv/http
|
|
||||||
#RUN chmod -R o=g /srv/http
|
|
||||||
#RUN chown -R app:www-data _deploy _sites
|
|
||||||
|
|
||||||
# Sincronizar los assets a un directorio compartido
|
# Sincronizar los assets a un directorio compartido
|
||||||
RUN apk add --no-cache rsync
|
RUN install -m 755 /srv/http/sync_assets.sh /usr/local/bin/sync_assets
|
||||||
COPY ./sync_assets.sh /usr/local/bin/sync_assets
|
# Instalar la configuración de monit
|
||||||
RUN chmod 755 /usr/local/bin/sync_assets
|
RUN install -m 640 -o root -g root /srv/http/monit.conf /etc/monit.d/sutty.conf
|
||||||
# Instalar la configuración de monit y comprobarla
|
|
||||||
RUN install -m 640 -o root -g root ./monit.conf /etc/monit.d/sutty.conf
|
|
||||||
RUN monit -t
|
|
||||||
RUN apk add --no-cache git
|
|
||||||
|
|
||||||
# Mantener estos directorios!
|
# Mantener estos directorios!
|
||||||
VOLUME "/srv/http/_deploy"
|
VOLUME "/srv/http/_deploy"
|
||||||
|
|
21
Gemfile
21
Gemfile
|
@ -15,7 +15,7 @@ git_source(:github) do |repo_name|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Cambiar en Dockerfile también
|
# Cambiar en Dockerfile también
|
||||||
ruby '2.5.7'
|
ruby '2.6.5'
|
||||||
|
|
||||||
gem 'dotenv-rails', require: 'dotenv/rails-now'
|
gem 'dotenv-rails', require: 'dotenv/rails-now'
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ gem 'rails', '~> 6'
|
||||||
# Use Puma as the app server
|
# Use Puma as the app server
|
||||||
gem 'puma'
|
gem 'puma'
|
||||||
# Use SCSS for stylesheets
|
# Use SCSS for stylesheets
|
||||||
gem 'sass-rails', '~> 5.0'
|
gem 'sassc-rails'
|
||||||
# Use Uglifier as compressor for JavaScript assets
|
# Use Uglifier as compressor for JavaScript assets
|
||||||
gem 'uglifier', '>= 1.3.0'
|
gem 'uglifier', '>= 1.3.0'
|
||||||
# See https://github.com/rails/execjs#readme for more supported runtimes
|
# See https://github.com/rails/execjs#readme for more supported runtimes
|
||||||
|
@ -38,10 +38,7 @@ gem 'turbolinks', '~> 5'
|
||||||
gem 'jbuilder', '~> 2.5'
|
gem 'jbuilder', '~> 2.5'
|
||||||
# Use ActiveModel has_secure_password
|
# Use ActiveModel has_secure_password
|
||||||
gem 'bcrypt', '~> 3.1.7'
|
gem 'bcrypt', '~> 3.1.7'
|
||||||
|
gem 'blazer'
|
||||||
# Use Capistrano for deployment
|
|
||||||
# gem 'capistrano-rails', group: :development
|
|
||||||
|
|
||||||
gem 'bootstrap', '~> 4'
|
gem 'bootstrap', '~> 4'
|
||||||
gem 'commonmarker'
|
gem 'commonmarker'
|
||||||
gem 'devise'
|
gem 'devise'
|
||||||
|
@ -83,23 +80,17 @@ end
|
||||||
group :development do
|
group :development do
|
||||||
# Access an IRB console on exception pages or by using <%= console %>
|
# Access an IRB console on exception pages or by using <%= console %>
|
||||||
# anywhere in the code.
|
# anywhere in the code.
|
||||||
gem 'listen', '>= 3.0.5', '< 3.2'
|
|
||||||
gem 'web-console', '>= 3.3.0'
|
|
||||||
# Spring speeds up development by keeping your application running in
|
|
||||||
# the background. Read more: https://github.com/rails/spring
|
|
||||||
gem 'bcrypt_pbkdf'
|
gem 'bcrypt_pbkdf'
|
||||||
gem 'capistrano'
|
gem 'brakeman'
|
||||||
gem 'capistrano-bundler'
|
|
||||||
gem 'capistrano-passenger'
|
|
||||||
gem 'capistrano-rails'
|
|
||||||
gem 'capistrano-rbenv'
|
|
||||||
gem 'ed25519'
|
gem 'ed25519'
|
||||||
gem 'haml-lint', require: false
|
gem 'haml-lint', require: false
|
||||||
gem 'letter_opener'
|
gem 'letter_opener'
|
||||||
|
gem 'listen', '>= 3.0.5', '< 3.2'
|
||||||
gem 'rbnacl', '< 5.0'
|
gem 'rbnacl', '< 5.0'
|
||||||
gem 'rubocop-rails'
|
gem 'rubocop-rails'
|
||||||
gem 'spring'
|
gem 'spring'
|
||||||
gem 'spring-watcher-listen', '~> 2.0.0'
|
gem 'spring-watcher-listen', '~> 2.0.0'
|
||||||
|
gem 'web-console', '>= 3.3.0'
|
||||||
end
|
end
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
|
|
269
Gemfile.lock
269
Gemfile.lock
|
@ -16,56 +16,56 @@ GIT
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (6.0.1)
|
actioncable (6.0.2.1)
|
||||||
actionpack (= 6.0.1)
|
actionpack (= 6.0.2.1)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
actionmailbox (6.0.1)
|
actionmailbox (6.0.2.1)
|
||||||
actionpack (= 6.0.1)
|
actionpack (= 6.0.2.1)
|
||||||
activejob (= 6.0.1)
|
activejob (= 6.0.2.1)
|
||||||
activerecord (= 6.0.1)
|
activerecord (= 6.0.2.1)
|
||||||
activestorage (= 6.0.1)
|
activestorage (= 6.0.2.1)
|
||||||
activesupport (= 6.0.1)
|
activesupport (= 6.0.2.1)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.7.1)
|
||||||
actionmailer (6.0.1)
|
actionmailer (6.0.2.1)
|
||||||
actionpack (= 6.0.1)
|
actionpack (= 6.0.2.1)
|
||||||
actionview (= 6.0.1)
|
actionview (= 6.0.2.1)
|
||||||
activejob (= 6.0.1)
|
activejob (= 6.0.2.1)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
actionpack (6.0.1)
|
actionpack (6.0.2.1)
|
||||||
actionview (= 6.0.1)
|
actionview (= 6.0.2.1)
|
||||||
activesupport (= 6.0.1)
|
activesupport (= 6.0.2.1)
|
||||||
rack (~> 2.0)
|
rack (~> 2.0, >= 2.0.8)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||||
actiontext (6.0.1)
|
actiontext (6.0.2.1)
|
||||||
actionpack (= 6.0.1)
|
actionpack (= 6.0.2.1)
|
||||||
activerecord (= 6.0.1)
|
activerecord (= 6.0.2.1)
|
||||||
activestorage (= 6.0.1)
|
activestorage (= 6.0.2.1)
|
||||||
activesupport (= 6.0.1)
|
activesupport (= 6.0.2.1)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (6.0.1)
|
actionview (6.0.2.1)
|
||||||
activesupport (= 6.0.1)
|
activesupport (= 6.0.2.1)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||||
activejob (6.0.1)
|
activejob (6.0.2.1)
|
||||||
activesupport (= 6.0.1)
|
activesupport (= 6.0.2.1)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (6.0.1)
|
activemodel (6.0.2.1)
|
||||||
activesupport (= 6.0.1)
|
activesupport (= 6.0.2.1)
|
||||||
activerecord (6.0.1)
|
activerecord (6.0.2.1)
|
||||||
activemodel (= 6.0.1)
|
activemodel (= 6.0.2.1)
|
||||||
activesupport (= 6.0.1)
|
activesupport (= 6.0.2.1)
|
||||||
activestorage (6.0.1)
|
activestorage (6.0.2.1)
|
||||||
actionpack (= 6.0.1)
|
actionpack (= 6.0.2.1)
|
||||||
activejob (= 6.0.1)
|
activejob (= 6.0.2.1)
|
||||||
activerecord (= 6.0.1)
|
activerecord (= 6.0.2.1)
|
||||||
marcel (~> 0.3.1)
|
marcel (~> 0.3.1)
|
||||||
activesupport (6.0.1)
|
activesupport (6.0.2.1)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (>= 0.7, < 2)
|
i18n (>= 0.7, < 2)
|
||||||
minitest (~> 5.1)
|
minitest (~> 5.1)
|
||||||
|
@ -73,34 +73,23 @@ GEM
|
||||||
zeitwerk (~> 2.2)
|
zeitwerk (~> 2.2)
|
||||||
addressable (2.7.0)
|
addressable (2.7.0)
|
||||||
public_suffix (>= 2.0.2, < 5.0)
|
public_suffix (>= 2.0.2, < 5.0)
|
||||||
airbrussh (1.3.4)
|
|
||||||
sshkit (>= 1.6.1, != 1.7.0)
|
|
||||||
ast (2.4.0)
|
ast (2.4.0)
|
||||||
autoprefixer-rails (9.6.1.1)
|
autoprefixer-rails (9.7.3)
|
||||||
execjs
|
execjs
|
||||||
bcrypt (3.1.13)
|
bcrypt (3.1.13)
|
||||||
bcrypt_pbkdf (1.0.1)
|
bcrypt_pbkdf (1.0.1)
|
||||||
bindex (0.8.1)
|
bindex (0.8.1)
|
||||||
bootstrap (4.3.1)
|
blazer (2.2.1)
|
||||||
|
activerecord (>= 5)
|
||||||
|
chartkick (>= 3.2)
|
||||||
|
railties (>= 5)
|
||||||
|
safely_block (>= 0.1.1)
|
||||||
|
bootstrap (4.4.1)
|
||||||
autoprefixer-rails (>= 9.1.0)
|
autoprefixer-rails (>= 9.1.0)
|
||||||
popper_js (>= 1.14.3, < 2)
|
popper_js (>= 1.14.3, < 2)
|
||||||
sassc-rails (>= 2.0.0)
|
sassc-rails (>= 2.0.0)
|
||||||
builder (3.2.3)
|
brakeman (4.7.2)
|
||||||
capistrano (3.11.1)
|
builder (3.2.4)
|
||||||
airbrussh (>= 1.0.0)
|
|
||||||
i18n
|
|
||||||
rake (>= 10.0.0)
|
|
||||||
sshkit (>= 1.9.0)
|
|
||||||
capistrano-bundler (1.6.0)
|
|
||||||
capistrano (~> 3.1)
|
|
||||||
capistrano-passenger (0.2.0)
|
|
||||||
capistrano (~> 3.0)
|
|
||||||
capistrano-rails (1.4.0)
|
|
||||||
capistrano (~> 3.1)
|
|
||||||
capistrano-bundler (~> 1.1)
|
|
||||||
capistrano-rbenv (2.1.4)
|
|
||||||
capistrano (~> 3.1)
|
|
||||||
sshkit (~> 1.3)
|
|
||||||
capybara (2.18.0)
|
capybara (2.18.0)
|
||||||
addressable
|
addressable
|
||||||
mini_mime (>= 0.1.3)
|
mini_mime (>= 0.1.3)
|
||||||
|
@ -108,11 +97,11 @@ GEM
|
||||||
rack (>= 1.0.0)
|
rack (>= 1.0.0)
|
||||||
rack-test (>= 0.5.4)
|
rack-test (>= 0.5.4)
|
||||||
xpath (>= 2.0, < 4.0)
|
xpath (>= 2.0, < 4.0)
|
||||||
childprocess (2.0.0)
|
chartkick (3.3.1)
|
||||||
rake (< 13.0)
|
childprocess (3.0.0)
|
||||||
coderay (1.1.2)
|
coderay (1.1.2)
|
||||||
colorator (1.1.0)
|
colorator (1.1.0)
|
||||||
commonmarker (0.20.1)
|
commonmarker (0.20.2)
|
||||||
ruby-enum (~> 0.5)
|
ruby-enum (~> 0.5)
|
||||||
concurrent-ruby (1.1.5)
|
concurrent-ruby (1.1.5)
|
||||||
crass (1.0.5)
|
crass (1.0.5)
|
||||||
|
@ -123,8 +112,8 @@ GEM
|
||||||
railties (>= 4.1.0)
|
railties (>= 4.1.0)
|
||||||
responders
|
responders
|
||||||
warden (~> 1.2.3)
|
warden (~> 1.2.3)
|
||||||
devise-i18n (1.8.2)
|
devise-i18n (1.9.0)
|
||||||
devise (>= 4.6)
|
devise (>= 4.7.1)
|
||||||
devise_invitable (2.0.1)
|
devise_invitable (2.0.1)
|
||||||
actionmailer (>= 5.0)
|
actionmailer (>= 5.0)
|
||||||
devise (>= 4.6)
|
devise (>= 4.6)
|
||||||
|
@ -136,23 +125,24 @@ GEM
|
||||||
em-websocket (0.5.1)
|
em-websocket (0.5.1)
|
||||||
eventmachine (>= 0.12.9)
|
eventmachine (>= 0.12.9)
|
||||||
http_parser.rb (~> 0.6.0)
|
http_parser.rb (~> 0.6.0)
|
||||||
email_address (0.1.11)
|
email_address (0.1.12)
|
||||||
netaddr (~> 2.0)
|
netaddr (>= 2.0.4, < 3)
|
||||||
simpleidn
|
simpleidn
|
||||||
|
errbase (0.2.0)
|
||||||
erubi (1.9.0)
|
erubi (1.9.0)
|
||||||
eventmachine (1.2.7)
|
eventmachine (1.2.7)
|
||||||
exception_notification (4.4.0)
|
exception_notification (4.4.0)
|
||||||
actionmailer (>= 4.0, < 7)
|
actionmailer (>= 4.0, < 7)
|
||||||
activesupport (>= 4.0, < 7)
|
activesupport (>= 4.0, < 7)
|
||||||
execjs (2.7.0)
|
execjs (2.7.0)
|
||||||
factory_bot (5.0.2)
|
factory_bot (5.1.1)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
factory_bot_rails (5.0.2)
|
factory_bot_rails (5.1.1)
|
||||||
factory_bot (~> 5.0.2)
|
factory_bot (~> 5.1.0)
|
||||||
railties (>= 4.2.0)
|
railties (>= 4.2.0)
|
||||||
ffi (1.11.1)
|
ffi (1.11.3)
|
||||||
forwardable-extended (2.6.0)
|
forwardable-extended (2.6.0)
|
||||||
friendly_id (5.2.5)
|
friendly_id (5.3.0)
|
||||||
activerecord (>= 4.0.0)
|
activerecord (>= 4.0.0)
|
||||||
globalid (0.4.2)
|
globalid (0.4.2)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
|
@ -161,13 +151,12 @@ GEM
|
||||||
tilt
|
tilt
|
||||||
haml-lint (0.999.999)
|
haml-lint (0.999.999)
|
||||||
haml_lint
|
haml_lint
|
||||||
haml_lint (0.33.0)
|
haml_lint (0.34.1)
|
||||||
haml (>= 4.0, < 5.2)
|
haml (>= 4.0, < 5.2)
|
||||||
rainbow
|
rainbow
|
||||||
rake (>= 10, < 13)
|
|
||||||
rubocop (>= 0.50.0)
|
rubocop (>= 0.50.0)
|
||||||
sysexits (~> 1.1)
|
sysexits (~> 1.1)
|
||||||
hamlit (2.10.0)
|
hamlit (2.11.0)
|
||||||
temple (>= 0.8.2)
|
temple (>= 0.8.2)
|
||||||
thor
|
thor
|
||||||
tilt
|
tilt
|
||||||
|
@ -180,13 +169,13 @@ GEM
|
||||||
http_parser.rb (0.6.0)
|
http_parser.rb (0.6.0)
|
||||||
i18n (1.7.0)
|
i18n (1.7.0)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
image_processing (1.9.3)
|
image_processing (1.10.0)
|
||||||
mini_magick (>= 4.9.5, < 5)
|
mini_magick (>= 4.9.5, < 5)
|
||||||
ruby-vips (>= 2.0.13, < 3)
|
ruby-vips (>= 2.0.13, < 3)
|
||||||
inline_svg (1.5.2)
|
inline_svg (1.6.0)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
nokogiri (>= 1.6)
|
nokogiri (>= 1.6)
|
||||||
jaro_winkler (1.5.3)
|
jaro_winkler (1.5.4)
|
||||||
jbuilder (2.9.1)
|
jbuilder (2.9.1)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
jekyll (4.0.0)
|
jekyll (4.0.0)
|
||||||
|
@ -204,7 +193,7 @@ GEM
|
||||||
rouge (~> 3.0)
|
rouge (~> 3.0)
|
||||||
safe_yaml (~> 1.0)
|
safe_yaml (~> 1.0)
|
||||||
terminal-table (~> 1.8)
|
terminal-table (~> 1.8)
|
||||||
jekyll-sass-converter (2.0.0)
|
jekyll-sass-converter (2.0.1)
|
||||||
sassc (> 2.0.1, < 3.0)
|
sassc (> 2.0.1, < 3.0)
|
||||||
jekyll-watch (2.2.1)
|
jekyll-watch (2.2.1)
|
||||||
listen (~> 3.0)
|
listen (~> 3.0)
|
||||||
|
@ -220,7 +209,7 @@ GEM
|
||||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||||
rb-inotify (~> 0.9, >= 0.9.7)
|
rb-inotify (~> 0.9, >= 0.9.7)
|
||||||
ruby_dep (~> 1.2)
|
ruby_dep (~> 1.2)
|
||||||
loofah (2.3.1)
|
loofah (2.4.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.5.9)
|
||||||
mail (2.7.1)
|
mail (2.7.1)
|
||||||
|
@ -237,48 +226,45 @@ GEM
|
||||||
mobility (0.8.9)
|
mobility (0.8.9)
|
||||||
i18n (>= 0.6.10, < 2)
|
i18n (>= 0.6.10, < 2)
|
||||||
request_store (~> 1.0)
|
request_store (~> 1.0)
|
||||||
net-scp (2.0.0)
|
netaddr (2.0.4)
|
||||||
net-ssh (>= 2.6.5, < 6.0.0)
|
|
||||||
net-ssh (5.2.0)
|
|
||||||
netaddr (2.0.3)
|
|
||||||
nio4r (2.5.2)
|
nio4r (2.5.2)
|
||||||
nokogiri (1.10.5)
|
nokogiri (1.10.7)
|
||||||
mini_portile2 (~> 2.4.0)
|
mini_portile2 (~> 2.4.0)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
parallel (1.17.0)
|
parallel (1.19.1)
|
||||||
parser (2.6.4.1)
|
parser (2.7.0.1)
|
||||||
ast (~> 2.4.0)
|
ast (~> 2.4.0)
|
||||||
pathutil (0.16.2)
|
pathutil (0.16.2)
|
||||||
forwardable-extended (~> 2.6)
|
forwardable-extended (~> 2.6)
|
||||||
pg (1.1.4)
|
pg (1.2.0)
|
||||||
popper_js (1.14.5)
|
popper_js (1.14.5)
|
||||||
pry (0.12.2)
|
pry (0.12.2)
|
||||||
coderay (~> 1.1.0)
|
coderay (~> 1.1.0)
|
||||||
method_source (~> 0.9.0)
|
method_source (~> 0.9.0)
|
||||||
public_suffix (4.0.1)
|
public_suffix (4.0.2)
|
||||||
puma (4.3.0)
|
puma (4.3.1)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
pundit (2.1.0)
|
pundit (2.1.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
rack (2.0.7)
|
rack (2.0.8)
|
||||||
rack-proxy (0.6.5)
|
rack-proxy (0.6.5)
|
||||||
rack
|
rack
|
||||||
rack-test (1.1.0)
|
rack-test (1.1.0)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rails (6.0.1)
|
rails (6.0.2.1)
|
||||||
actioncable (= 6.0.1)
|
actioncable (= 6.0.2.1)
|
||||||
actionmailbox (= 6.0.1)
|
actionmailbox (= 6.0.2.1)
|
||||||
actionmailer (= 6.0.1)
|
actionmailer (= 6.0.2.1)
|
||||||
actionpack (= 6.0.1)
|
actionpack (= 6.0.2.1)
|
||||||
actiontext (= 6.0.1)
|
actiontext (= 6.0.2.1)
|
||||||
actionview (= 6.0.1)
|
actionview (= 6.0.2.1)
|
||||||
activejob (= 6.0.1)
|
activejob (= 6.0.2.1)
|
||||||
activemodel (= 6.0.1)
|
activemodel (= 6.0.2.1)
|
||||||
activerecord (= 6.0.1)
|
activerecord (= 6.0.2.1)
|
||||||
activestorage (= 6.0.1)
|
activestorage (= 6.0.2.1)
|
||||||
activesupport (= 6.0.1)
|
activesupport (= 6.0.2.1)
|
||||||
bundler (>= 1.3.0)
|
bundler (>= 1.3.0)
|
||||||
railties (= 6.0.1)
|
railties (= 6.0.2.1)
|
||||||
sprockets-rails (>= 2.0.0)
|
sprockets-rails (>= 2.0.0)
|
||||||
rails-dom-testing (2.0.3)
|
rails-dom-testing (2.0.3)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
|
@ -290,16 +276,16 @@ GEM
|
||||||
railties (>= 6.0.0, < 7)
|
railties (>= 6.0.0, < 7)
|
||||||
rails_warden (0.6.0)
|
rails_warden (0.6.0)
|
||||||
warden (>= 1.2.0)
|
warden (>= 1.2.0)
|
||||||
railties (6.0.1)
|
railties (6.0.2.1)
|
||||||
actionpack (= 6.0.1)
|
actionpack (= 6.0.2.1)
|
||||||
activesupport (= 6.0.1)
|
activesupport (= 6.0.2.1)
|
||||||
method_source
|
method_source
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.8.7)
|
||||||
thor (>= 0.20.3, < 2.0)
|
thor (>= 0.20.3, < 2.0)
|
||||||
rainbow (3.0.0)
|
rainbow (3.0.0)
|
||||||
rake (12.3.3)
|
rake (13.0.1)
|
||||||
rb-fsevent (0.10.3)
|
rb-fsevent (0.10.3)
|
||||||
rb-inotify (0.10.0)
|
rb-inotify (0.10.1)
|
||||||
ffi (~> 1.0)
|
ffi (~> 1.0)
|
||||||
rbnacl (4.0.2)
|
rbnacl (4.0.2)
|
||||||
ffi
|
ffi
|
||||||
|
@ -311,52 +297,43 @@ GEM
|
||||||
redis-activesupport (5.2.0)
|
redis-activesupport (5.2.0)
|
||||||
activesupport (>= 3, < 7)
|
activesupport (>= 3, < 7)
|
||||||
redis-store (>= 1.3, < 2)
|
redis-store (>= 1.3, < 2)
|
||||||
redis-rack (2.0.5)
|
redis-rack (2.0.6)
|
||||||
rack (>= 1.5, < 3)
|
rack (>= 1.5, < 3)
|
||||||
redis-store (>= 1.2, < 2)
|
redis-store (>= 1.2, < 2)
|
||||||
redis-rails (5.0.2)
|
redis-rails (5.0.2)
|
||||||
redis-actionpack (>= 5.0, < 6)
|
redis-actionpack (>= 5.0, < 6)
|
||||||
redis-activesupport (>= 5.0, < 6)
|
redis-activesupport (>= 5.0, < 6)
|
||||||
redis-store (>= 1.2, < 2)
|
redis-store (>= 1.2, < 2)
|
||||||
redis-store (1.6.0)
|
redis-store (1.8.1)
|
||||||
redis (>= 2.2, < 5)
|
redis (>= 4, < 5)
|
||||||
request_store (1.4.1)
|
request_store (1.5.0)
|
||||||
rack (>= 1.4)
|
rack (>= 1.4)
|
||||||
responders (3.0.0)
|
responders (3.0.0)
|
||||||
actionpack (>= 5.0)
|
actionpack (>= 5.0)
|
||||||
railties (>= 5.0)
|
railties (>= 5.0)
|
||||||
rouge (3.11.0)
|
rouge (3.14.0)
|
||||||
rubocop (0.74.0)
|
rubocop (0.78.0)
|
||||||
jaro_winkler (~> 1.5.1)
|
jaro_winkler (~> 1.5.1)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 2.6)
|
parser (>= 2.6)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 1.4.0, < 1.7)
|
unicode-display_width (>= 1.4.0, < 1.7)
|
||||||
rubocop-rails (2.3.2)
|
rubocop-rails (2.4.1)
|
||||||
rack (>= 1.1)
|
rack (>= 1.1)
|
||||||
rubocop (>= 0.72.0)
|
rubocop (>= 0.72.0)
|
||||||
ruby-enum (0.7.2)
|
ruby-enum (0.7.2)
|
||||||
i18n
|
i18n
|
||||||
ruby-progressbar (1.10.1)
|
ruby-progressbar (1.10.1)
|
||||||
ruby-vips (2.0.15)
|
ruby-vips (2.0.16)
|
||||||
ffi (~> 1.9)
|
ffi (~> 1.9)
|
||||||
ruby_dep (1.5.0)
|
ruby_dep (1.5.0)
|
||||||
rubyzip (1.3.0)
|
rubyzip (2.0.0)
|
||||||
rugged (0.28.3.1)
|
rugged (0.28.4.1)
|
||||||
safe_yaml (1.0.5)
|
safe_yaml (1.0.5)
|
||||||
sass (3.7.4)
|
safely_block (0.3.0)
|
||||||
sass-listen (~> 4.0.0)
|
errbase (>= 0.1.1)
|
||||||
sass-listen (4.0.0)
|
sassc (2.2.1)
|
||||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
|
||||||
rb-inotify (~> 0.9, >= 0.9.7)
|
|
||||||
sass-rails (5.1.0)
|
|
||||||
railties (>= 5.2.0)
|
|
||||||
sass (~> 3.1)
|
|
||||||
sprockets (>= 2.8, < 4.0)
|
|
||||||
sprockets-rails (>= 2.0, < 4.0)
|
|
||||||
tilt (>= 1.1, < 3)
|
|
||||||
sassc (2.2.0)
|
|
||||||
ffi (~> 1.9)
|
ffi (~> 1.9)
|
||||||
sassc-rails (2.1.2)
|
sassc-rails (2.1.2)
|
||||||
railties (>= 4.0.0)
|
railties (>= 4.0.0)
|
||||||
|
@ -364,41 +341,38 @@ GEM
|
||||||
sprockets (> 3.0)
|
sprockets (> 3.0)
|
||||||
sprockets-rails
|
sprockets-rails
|
||||||
tilt
|
tilt
|
||||||
selenium-webdriver (3.142.4)
|
selenium-webdriver (3.142.7)
|
||||||
childprocess (>= 0.5, < 3.0)
|
childprocess (>= 0.5, < 4.0)
|
||||||
rubyzip (~> 1.2, >= 1.2.2)
|
rubyzip (>= 1.2.2)
|
||||||
simpleidn (0.1.1)
|
simpleidn (0.1.1)
|
||||||
unf (~> 0.1.4)
|
unf (~> 0.1.4)
|
||||||
spring (2.1.0)
|
spring (2.1.0)
|
||||||
spring-watcher-listen (2.0.1)
|
spring-watcher-listen (2.0.1)
|
||||||
listen (>= 2.7, < 4.0)
|
listen (>= 2.7, < 4.0)
|
||||||
spring (>= 1.2, < 3.0)
|
spring (>= 1.2, < 3.0)
|
||||||
sprockets (3.7.2)
|
sprockets (4.0.0)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
rack (> 1, < 3)
|
rack (> 1, < 3)
|
||||||
sprockets-rails (3.2.1)
|
sprockets-rails (3.2.1)
|
||||||
actionpack (>= 4.0)
|
actionpack (>= 4.0)
|
||||||
activesupport (>= 4.0)
|
activesupport (>= 4.0)
|
||||||
sprockets (>= 3.0.0)
|
sprockets (>= 3.0.0)
|
||||||
sqlite3 (1.4.1)
|
sqlite3 (1.4.2)
|
||||||
sshkit (1.20.0)
|
|
||||||
net-scp (>= 1.1.2)
|
|
||||||
net-ssh (>= 2.8.0)
|
|
||||||
sucker_punch (2.1.2)
|
sucker_punch (2.1.2)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
sysexits (1.2.0)
|
sysexits (1.2.0)
|
||||||
temple (0.8.2)
|
temple (0.8.2)
|
||||||
terminal-table (1.8.0)
|
terminal-table (1.8.0)
|
||||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||||
thor (0.20.3)
|
thor (1.0.1)
|
||||||
thread_safe (0.3.6)
|
thread_safe (0.3.6)
|
||||||
tilt (2.0.9)
|
tilt (2.0.10)
|
||||||
turbolinks (5.2.0)
|
turbolinks (5.2.1)
|
||||||
turbolinks-source (~> 5.2)
|
turbolinks-source (~> 5.2)
|
||||||
turbolinks-source (5.2.0)
|
turbolinks-source (5.2.0)
|
||||||
tzinfo (1.2.5)
|
tzinfo (1.2.6)
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
uglifier (4.1.20)
|
uglifier (4.2.0)
|
||||||
execjs (>= 0.3.0, < 3)
|
execjs (>= 0.3.0, < 3)
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
|
@ -414,7 +388,7 @@ GEM
|
||||||
activemodel (>= 6.0.0)
|
activemodel (>= 6.0.0)
|
||||||
bindex (>= 0.4.0)
|
bindex (>= 0.4.0)
|
||||||
railties (>= 6.0.0)
|
railties (>= 6.0.0)
|
||||||
webpacker (4.0.7)
|
webpacker (4.2.2)
|
||||||
activesupport (>= 4.2)
|
activesupport (>= 4.2)
|
||||||
rack-proxy (>= 0.6.1)
|
rack-proxy (>= 0.6.1)
|
||||||
railties (>= 4.2)
|
railties (>= 4.2)
|
||||||
|
@ -423,7 +397,7 @@ GEM
|
||||||
websocket-extensions (0.1.4)
|
websocket-extensions (0.1.4)
|
||||||
xpath (3.2.0)
|
xpath (3.2.0)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
zeitwerk (2.2.1)
|
zeitwerk (2.2.2)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
@ -431,12 +405,9 @@ PLATFORMS
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
bcrypt (~> 3.1.7)
|
bcrypt (~> 3.1.7)
|
||||||
bcrypt_pbkdf
|
bcrypt_pbkdf
|
||||||
|
blazer
|
||||||
bootstrap (~> 4)
|
bootstrap (~> 4)
|
||||||
capistrano
|
brakeman
|
||||||
capistrano-bundler
|
|
||||||
capistrano-passenger
|
|
||||||
capistrano-rails
|
|
||||||
capistrano-rbenv
|
|
||||||
capybara (~> 2.13)
|
capybara (~> 2.13)
|
||||||
commonmarker
|
commonmarker
|
||||||
database_cleaner
|
database_cleaner
|
||||||
|
@ -474,7 +445,7 @@ DEPENDENCIES
|
||||||
rubocop-rails
|
rubocop-rails
|
||||||
rubyzip
|
rubyzip
|
||||||
rugged
|
rugged
|
||||||
sass-rails (~> 5.0)
|
sassc-rails
|
||||||
selenium-webdriver
|
selenium-webdriver
|
||||||
spring
|
spring
|
||||||
spring-watcher-listen (~> 2.0.0)
|
spring-watcher-listen (~> 2.0.0)
|
||||||
|
@ -489,7 +460,7 @@ DEPENDENCIES
|
||||||
yaml_db!
|
yaml_db!
|
||||||
|
|
||||||
RUBY VERSION
|
RUBY VERSION
|
||||||
ruby 2.5.7p206
|
ruby 2.6.5p114
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.0.2
|
2.1.4
|
||||||
|
|
18
Makefile
18
Makefile
|
@ -3,6 +3,9 @@ mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||||
root_dir := $(patsubst %/,%,$(dir $(mkfile_path)))
|
root_dir := $(patsubst %/,%,$(dir $(mkfile_path)))
|
||||||
include $(root_dir)/.env
|
include $(root_dir)/.env
|
||||||
|
|
||||||
|
serve:
|
||||||
|
bundle exec rails s -b "ssl://0.0.0.0:3000?key=config/sutty.local.key&cert=config/sutty.local.crt"
|
||||||
|
|
||||||
# Limpiar los archivos de testeo
|
# Limpiar los archivos de testeo
|
||||||
clean:
|
clean:
|
||||||
rm -rf _sites/test-* _deploy/test-*
|
rm -rf _sites/test-* _deploy/test-*
|
||||||
|
@ -11,13 +14,22 @@ clean:
|
||||||
build:
|
build:
|
||||||
docker build --build-arg="RAILS_MASTER_KEY=`cat config/master.key`" -t sutty/sutty .
|
docker build --build-arg="RAILS_MASTER_KEY=`cat config/master.key`" -t sutty/sutty .
|
||||||
|
|
||||||
|
save:
|
||||||
|
docker save sutty/sutty:latest | gzip | ssh root@sutty.nl docker load
|
||||||
|
|
||||||
|
load:
|
||||||
|
ssh root@sutty.nl sh -c "gunzip -c sutty.latest.gz | docker load"
|
||||||
|
|
||||||
# Crear el directorio donde se almacenan las gemas binarias
|
# Crear el directorio donde se almacenan las gemas binarias
|
||||||
../gems/:
|
../gems/:
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
|
|
||||||
|
ifeq ($(MAKECMDGOALS),convert-gems)
|
||||||
gem_dir := $(shell readlink -f ../gems)
|
gem_dir := $(shell readlink -f ../gems)
|
||||||
gems := $(shell bundle show --paths | xargs -I {} sh -c 'test -d {}/ext && basename {}')
|
gems := $(shell bundle show --paths | xargs -I {} sh -c 'test -f {}/ext/*/extconf.rb && basename {}')
|
||||||
|
gems += $(shell bundle show --paths | xargs -I {} sh -c 'test -f {}/ext/extconf.rb && basename {}')
|
||||||
gems_musl := $(patsubst %,$(gem_dir)/%-x86_64-linux-musl.gem,$(gems))
|
gems_musl := $(patsubst %,$(gem_dir)/%-x86_64-linux-musl.gem,$(gems))
|
||||||
|
endif
|
||||||
|
|
||||||
$(gem_dir)/%-x86_64-linux-musl.gem:
|
$(gem_dir)/%-x86_64-linux-musl.gem:
|
||||||
docker run \
|
docker run \
|
||||||
|
@ -45,8 +57,8 @@ test-container: $(dirs)
|
||||||
-v $(PWD)/root/public:/srv/http/_public \
|
-v $(PWD)/root/public:/srv/http/_public \
|
||||||
-v $(PWD)/config/credentials.yml.enc:/srv/http/config/credentials.yml.enc \
|
-v $(PWD)/config/credentials.yml.enc:/srv/http/config/credentials.yml.enc \
|
||||||
-e RAILS_MASTER_KEY=`cat config/master.key` \
|
-e RAILS_MASTER_KEY=`cat config/master.key` \
|
||||||
|
-e RAILS_ENV=production \
|
||||||
-it \
|
-it \
|
||||||
--rm \
|
--rm \
|
||||||
--name=sutty \
|
--name=sutty \
|
||||||
sutty/sutty \
|
sutty/sutty /bin/sh
|
||||||
/bin/sh
|
|
||||||
|
|
BIN
app/assets/fonts/saira/v3/Saira-subset.woff2
Normal file
BIN
app/assets/fonts/saira/v3/Saira-subset.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/saira/v3/Saira-subset.zopfli.woff
Normal file
BIN
app/assets/fonts/saira/v3/Saira-subset.zopfli.woff
Normal file
Binary file not shown.
BIN
app/assets/fonts/saira/v3/SairaBold-subset.woff2
Normal file
BIN
app/assets/fonts/saira/v3/SairaBold-subset.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/saira/v3/SairaBold-subset.zopfli.woff
Normal file
BIN
app/assets/fonts/saira/v3/SairaBold-subset.zopfli.woff
Normal file
Binary file not shown.
BIN
app/assets/fonts/saira/v3/SairaMedium-subset.woff2
Normal file
BIN
app/assets/fonts/saira/v3/SairaMedium-subset.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/saira/v3/SairaMedium-subset.zopfli.woff
Normal file
BIN
app/assets/fonts/saira/v3/SairaMedium-subset.zopfli.woff
Normal file
Binary file not shown.
|
@ -1,5 +1,6 @@
|
||||||
//= require rails-ujs
|
//= require rails-ujs
|
||||||
//= require turbolinks
|
//= require turbolinks
|
||||||
//= require input-tag/input-tag.js
|
//= require input-tag/input-tag.js
|
||||||
|
//= require input-map/input-map.js
|
||||||
//= require zepto/dist/zepto.min.js
|
//= require zepto/dist/zepto.min.js
|
||||||
//= require_tree .
|
//= require_tree .
|
||||||
|
|
|
@ -7,4 +7,13 @@ $(document).on('turbolinks:load', function() {
|
||||||
props: { ...this.dataset }
|
props: { ...this.dataset }
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('.mapable').each(function() {
|
||||||
|
this.innerHTML = '';
|
||||||
|
|
||||||
|
new InputMap({
|
||||||
|
target: this,
|
||||||
|
props: { ...this.dataset }
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,6 +20,18 @@ $magenta: #f206f9;
|
||||||
--background: #{$black};
|
--background: #{$black};
|
||||||
--color: #{$cyan};
|
--color: #{$cyan};
|
||||||
}
|
}
|
||||||
|
trix-toolbar {
|
||||||
|
.trix-button--icon {
|
||||||
|
background-color: var(--color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trix-toolbar {
|
||||||
|
background-color: var(--background);
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Encontrar la forma de generar esto desde los locales de Rails
|
// TODO: Encontrar la forma de generar esto desde los locales de Rails
|
||||||
|
@ -34,7 +46,8 @@ $custom-file-text: (
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-display: optional;
|
font-display: optional;
|
||||||
src: local('Saira Medium'), local('Saira-Medium'),
|
src: local('Saira Medium'), local('Saira-Medium'),
|
||||||
font-url('saira/v3/SairaMedium.ttf') format('truetype');
|
font-url('saira/v3/SairaMedium-subset.woff2') format('woff2'),
|
||||||
|
font-url('saira/v3/SairaMedium-subset.zopfli.woff') format('woff');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
@ -43,7 +56,8 @@ $custom-file-text: (
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-display: optional;
|
font-display: optional;
|
||||||
src: local('Saira Bold'), local('Saira-Bold'),
|
src: local('Saira Bold'), local('Saira-Bold'),
|
||||||
font-url('saira/v3/SairaBold.ttf') format('truetype');
|
font-url('saira/v3/SairaBold-subset.woff2') format('woff2'),
|
||||||
|
font-url('saira/v3/SairaBold-subset.zopfli.woff') format('woff');
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
@ -128,7 +142,9 @@ ol.breadcrumb {
|
||||||
transition: all 3s;
|
transition: all 3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mapable,
|
||||||
.taggable {
|
.taggable {
|
||||||
|
.input-map,
|
||||||
.input-tag {
|
.input-tag {
|
||||||
legend {
|
legend {
|
||||||
@extend .sr-only
|
@extend .sr-only
|
||||||
|
@ -144,7 +160,7 @@ ol.breadcrumb {
|
||||||
&[type=text] {
|
&[type=text] {
|
||||||
@extend .form-control;
|
@extend .form-control;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: calc(100% - 90px);
|
width: calc(100% - 93px);
|
||||||
}
|
}
|
||||||
|
|
||||||
&[type=checkbox] {
|
&[type=checkbox] {
|
||||||
|
@ -169,6 +185,8 @@ svg {
|
||||||
color: var(--background);
|
color: var(--background);
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
margin-right: 0.3rem;
|
||||||
|
margin-bottom: 0.3rem;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: var(--background);
|
color: var(--background);
|
||||||
|
|
|
@ -4,9 +4,6 @@ module Api
|
||||||
module V1
|
module V1
|
||||||
# API
|
# API
|
||||||
class BaseController < ActionController::Base
|
class BaseController < ActionController::Base
|
||||||
http_basic_authenticate_with name: ENV['HTTP_BASIC_USER'],
|
|
||||||
password: ENV['HTTP_BASIC_PASSWORD']
|
|
||||||
|
|
||||||
protect_from_forgery with: :null_session
|
protect_from_forgery with: :null_session
|
||||||
respond_to :json
|
respond_to :json
|
||||||
end
|
end
|
||||||
|
|
42
app/controllers/api/v1/csp_reports_controller.rb
Normal file
42
app/controllers/api/v1/csp_reports_controller.rb
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
# Recibe los reportes de Content Security Policy
|
||||||
|
class CspReportsController < BaseController
|
||||||
|
# Crea un reporte de CSP intercambiando los guiones medios por
|
||||||
|
# bajos
|
||||||
|
#
|
||||||
|
# TODO: Aplicar rate_limit
|
||||||
|
def create
|
||||||
|
csp = CspReport.new(csp_report_params.to_h.map do |k, v|
|
||||||
|
{ k.tr('-', '_') => v }
|
||||||
|
end.inject(&:merge))
|
||||||
|
|
||||||
|
csp.id = SecureRandom.uuid
|
||||||
|
csp.save
|
||||||
|
|
||||||
|
render json: {}, status: :created
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only#Violation_report_syntax
|
||||||
|
def csp_report_params
|
||||||
|
params.require(:'csp-report')
|
||||||
|
.permit(:disposition,
|
||||||
|
:referrer,
|
||||||
|
:'blocked-uri',
|
||||||
|
:'document-uri',
|
||||||
|
:'effective-directive',
|
||||||
|
:'original-policy',
|
||||||
|
:'script-sample',
|
||||||
|
:'status-code',
|
||||||
|
:'violated-directive',
|
||||||
|
:'line-number',
|
||||||
|
:'column-number',
|
||||||
|
:'source-file')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -4,8 +4,12 @@ module Api
|
||||||
module V1
|
module V1
|
||||||
# API para sitios
|
# API para sitios
|
||||||
class SitesController < BaseController
|
class SitesController < BaseController
|
||||||
|
http_basic_authenticate_with name: ENV['HTTP_BASIC_USER'],
|
||||||
|
password: ENV['HTTP_BASIC_PASSWORD']
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render json: Site.all.order(:name).pluck(:name)
|
render json: Site.all.order(:name).pluck(:name) +
|
||||||
|
DeployAlternativeDomain.all.map(&:hostname)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Detecta si se puede generar un certificado
|
# Detecta si se puede generar un certificado
|
||||||
|
|
|
@ -12,7 +12,8 @@ class PostsController < ApplicationController
|
||||||
@layout = params.dig(:layout).try :to_sym
|
@layout = params.dig(:layout).try :to_sym
|
||||||
# TODO: Aplicar policy_scope
|
# TODO: Aplicar policy_scope
|
||||||
@posts = @site.posts(lang: I18n.locale)
|
@posts = @site.posts(lang: I18n.locale)
|
||||||
@posts.sort_by! :order, :date
|
@posts.sort_by!(:order, :date).reverse!
|
||||||
|
@usuarie = @site.usuarie? current_usuarie
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
@ -34,7 +35,7 @@ class PostsController < ApplicationController
|
||||||
usuarie: current_usuarie,
|
usuarie: current_usuarie,
|
||||||
params: params)
|
params: params)
|
||||||
|
|
||||||
if service.create.persisted?
|
if (@post = service.create.persisted?)
|
||||||
redirect_to site_posts_path(@site)
|
redirect_to site_posts_path(@site)
|
||||||
else
|
else
|
||||||
render 'posts/new'
|
render 'posts/new'
|
||||||
|
|
|
@ -8,7 +8,7 @@ class SitesController < ApplicationController
|
||||||
# Ver un listado de sitios
|
# Ver un listado de sitios
|
||||||
def index
|
def index
|
||||||
authorize Site
|
authorize Site
|
||||||
@sites = current_usuarie.sites
|
@sites = current_usuarie.sites.order(:title)
|
||||||
end
|
end
|
||||||
|
|
||||||
# No tenemos propiedades de un sitio aún, así que vamos al listado de
|
# No tenemos propiedades de un sitio aún, así que vamos al listado de
|
||||||
|
|
|
@ -186,7 +186,11 @@ document.addEventListener('turbolinks:load', e => {
|
||||||
onlyBody: true,
|
onlyBody: true,
|
||||||
dragHandler: '.handle',
|
dragHandler: '.handle',
|
||||||
}).on('drop', (from, to, el, mode) => {
|
}).on('drop', (from, to, el, mode) => {
|
||||||
$('.reorder').val((i, v) => i)
|
Array.from(document.querySelectorAll('.reorder'))
|
||||||
$('.submit-reorder').removeClass('d-none')
|
.reverse()
|
||||||
|
.map((o,i) => o.value = i)
|
||||||
|
|
||||||
|
Array.from(document.querySelectorAll('.submit-reorder'))
|
||||||
|
.map(s => s.classList.remove('d-none'))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -15,6 +15,9 @@ class DeployJob < ApplicationJob
|
||||||
# No es opcional
|
# No es opcional
|
||||||
unless @deployed[:deploy_local]
|
unless @deployed[:deploy_local]
|
||||||
@site.update_attribute :status, 'waiting'
|
@site.update_attribute :status, 'waiting'
|
||||||
|
notify_usuaries
|
||||||
|
|
||||||
|
# Hacer fallar la tarea
|
||||||
raise DeployException, deploy_local.build_stats.last.log
|
raise DeployException, deploy_local.build_stats.last.log
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
4
app/models/csp_report.rb
Normal file
4
app/models/csp_report.rb
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Almacena un reporte de CSP
|
||||||
|
class CspReport < ApplicationRecord; end
|
23
app/models/deploy_alternative_domain.rb
Normal file
23
app/models/deploy_alternative_domain.rb
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Soportar dominios alternativos
|
||||||
|
class DeployAlternativeDomain < Deploy
|
||||||
|
store :values, accessors: %i[hostname], coder: JSON
|
||||||
|
|
||||||
|
# Generar un link simbólico del sitio principal al alternativo
|
||||||
|
def deploy
|
||||||
|
File.symlink?(destination) ||
|
||||||
|
File.symlink(site.hostname, destination).zero?
|
||||||
|
end
|
||||||
|
|
||||||
|
# No hay límite para los dominios alternativos
|
||||||
|
def limit; end
|
||||||
|
|
||||||
|
def size
|
||||||
|
File.size destination
|
||||||
|
end
|
||||||
|
|
||||||
|
def destination
|
||||||
|
File.join(Rails.root, '_deploy', hostname.gsub(/\.\z/, ''))
|
||||||
|
end
|
||||||
|
end
|
|
@ -13,7 +13,11 @@ class DeployLocal < Deploy
|
||||||
# Pasamos variables de entorno mínimas para no filtrar secretos de
|
# Pasamos variables de entorno mínimas para no filtrar secretos de
|
||||||
# Sutty
|
# Sutty
|
||||||
def deploy
|
def deploy
|
||||||
mkdir && yarn && bundle && jekyll_build
|
return false unless mkdir
|
||||||
|
return false unless yarn
|
||||||
|
return false unless bundle
|
||||||
|
|
||||||
|
jekyll_build
|
||||||
end
|
end
|
||||||
|
|
||||||
# Sólo permitimos un deploy local
|
# Sólo permitimos un deploy local
|
||||||
|
@ -49,7 +53,8 @@ class DeployLocal < Deploy
|
||||||
{
|
{
|
||||||
'HOME' => home_dir,
|
'HOME' => home_dir,
|
||||||
'PATH' => paths.join(':'),
|
'PATH' => paths.join(':'),
|
||||||
'JEKYLL_ENV' => Rails.env
|
'JEKYLL_ENV' => Rails.env,
|
||||||
|
'LANG' => ENV['LANG']
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -61,6 +66,10 @@ class DeployLocal < Deploy
|
||||||
File.exist? yarn_lock
|
File.exist? yarn_lock
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def gem
|
||||||
|
run %(gem install bundler --no-document)
|
||||||
|
end
|
||||||
|
|
||||||
# Corre yarn dentro del repositorio
|
# Corre yarn dentro del repositorio
|
||||||
def yarn
|
def yarn
|
||||||
return unless yarn_lock?
|
return unless yarn_lock?
|
||||||
|
|
4
app/models/metadata_color.rb
Normal file
4
app/models/metadata_color.rb
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Un campo de correo
|
||||||
|
class MetadataColor < MetadataString; end
|
5
app/models/metadata_email.rb
Normal file
5
app/models/metadata_email.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Un campo de correo
|
||||||
|
# TODO: Validar que tenga un formato correo
|
||||||
|
class MetadataEmail < MetadataString; end
|
23
app/models/metadata_geo.rb
Normal file
23
app/models/metadata_geo.rb
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Define un campo de coordenadas geográficas
|
||||||
|
class MetadataGeo < MetadataTemplate
|
||||||
|
def default_value
|
||||||
|
{ 'lat' => nil, 'lng' => nil }
|
||||||
|
end
|
||||||
|
|
||||||
|
def empty?
|
||||||
|
value == default_value
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_param
|
||||||
|
{ name => %i[lat lng] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def save
|
||||||
|
self[:value] = {
|
||||||
|
'lat' => self[:value]['lat'].to_f,
|
||||||
|
'lng' => self[:value]['lng'].to_f
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
# Un campo de orden
|
# Un campo de orden
|
||||||
class MetadataOrder < MetadataTemplate
|
class MetadataOrder < MetadataTemplate
|
||||||
# El valor según la posición del post en la relación, siguiendo el
|
# El valor según la posición del post en la relación ordenada por
|
||||||
# orden cronológico inverso
|
# fecha, a fecha más alta, posición más alta
|
||||||
def default_value
|
def default_value
|
||||||
site.posts(lang: post.lang.value).index(post)
|
site.posts(lang: post.lang.value).sort_by(:date).index(post)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
23
app/models/metadata_related_posts.rb
Normal file
23
app/models/metadata_related_posts.rb
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Devuelve una lista de títulos y UUID de todos los posts del mismo
|
||||||
|
# idioma que el actual, para usar con input-map.js
|
||||||
|
class MetadataRelatedPosts < MetadataArray
|
||||||
|
# Genera un Hash de { title | slug => uuid }
|
||||||
|
def values
|
||||||
|
site.posts(lang: lang).map do |p|
|
||||||
|
{ title(p) => p.uuid.value }
|
||||||
|
end.inject(:merge)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def title(post)
|
||||||
|
post.try(:title).try(:value) || post.try(:slug).try(:value)
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO: Traer el idioma actual de otra forma
|
||||||
|
def lang
|
||||||
|
post.try(:lang).try(:value) || I18n.locale
|
||||||
|
end
|
||||||
|
end
|
|
@ -15,6 +15,8 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
|
||||||
|
|
||||||
# Valores posibles, busca todos los valores actuales en otros
|
# Valores posibles, busca todos los valores actuales en otros
|
||||||
# artículos del mismo sitio
|
# artículos del mismo sitio
|
||||||
|
#
|
||||||
|
# TODO: Implementar lang!
|
||||||
def values
|
def values
|
||||||
site.everything_of(name)
|
site.everything_of(name)
|
||||||
end
|
end
|
||||||
|
|
8
app/models/metadata_uuid.rb
Normal file
8
app/models/metadata_uuid.rb
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Asigna un identificador único al artículo
|
||||||
|
class MetadataUuid < MetadataTemplate
|
||||||
|
def default_value
|
||||||
|
SecureRandom.uuid
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,7 +1,5 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'jekyll/utils'
|
|
||||||
|
|
||||||
# Esta clase representa un post en un sitio jekyll e incluye métodos
|
# Esta clase representa un post en un sitio jekyll e incluye métodos
|
||||||
# para modificarlos y crear nuevos.
|
# para modificarlos y crear nuevos.
|
||||||
#
|
#
|
||||||
|
@ -13,7 +11,16 @@ class Post < OpenStruct
|
||||||
DEFAULT_ATTRIBUTES = %i[site document layout].freeze
|
DEFAULT_ATTRIBUTES = %i[site document layout].freeze
|
||||||
# Otros atributos que no vienen en los metadatos
|
# Otros atributos que no vienen en los metadatos
|
||||||
PRIVATE_ATTRIBUTES = %i[path slug attributes errors].freeze
|
PRIVATE_ATTRIBUTES = %i[path slug attributes errors].freeze
|
||||||
PUBLIC_ATTRIBUTES = %i[lang date].freeze
|
PUBLIC_ATTRIBUTES = %i[lang date uuid].freeze
|
||||||
|
|
||||||
|
class << self
|
||||||
|
# Obtiene el layout sin leer el Document
|
||||||
|
def find_layout(doc)
|
||||||
|
SafeYAML.load(IO.foreach(doc.path).lazy.grep(/^layout: /).take(1).first)
|
||||||
|
.try(:[], 'layout')
|
||||||
|
.try(:to_sym)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Redefinir el inicializador de OpenStruct
|
# Redefinir el inicializador de OpenStruct
|
||||||
#
|
#
|
||||||
|
@ -33,6 +40,10 @@ class Post < OpenStruct
|
||||||
# MetadataFactory devuelve un tipo de campo por cada campo. A
|
# MetadataFactory devuelve un tipo de campo por cada campo. A
|
||||||
# partir de ahí se pueden obtener los valores actuales y una lista
|
# partir de ahí se pueden obtener los valores actuales y una lista
|
||||||
# de valores por defecto.
|
# de valores por defecto.
|
||||||
|
#
|
||||||
|
# XXX: En el primer intento de hacerlo más óptimo, movimos esta
|
||||||
|
# lógica a instanciación bajo demanda, pero no solo no logramos
|
||||||
|
# optimizar sino que aumentamos el tiempo de carga :/
|
||||||
layout.metadata.each_pair do |name, template|
|
layout.metadata.each_pair do |name, template|
|
||||||
send "#{name}=".to_sym,
|
send "#{name}=".to_sym,
|
||||||
MetadataFactory.build(document: document,
|
MetadataFactory.build(document: document,
|
||||||
|
@ -47,31 +58,27 @@ class Post < OpenStruct
|
||||||
required: template['required'])
|
required: template['required'])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO: Llamar dinámicamente
|
||||||
load_lang!
|
load_lang!
|
||||||
load_slug!
|
load_slug!
|
||||||
load_date!
|
load_date!
|
||||||
load_path!
|
load_path!
|
||||||
|
load_uuid!
|
||||||
|
|
||||||
# Leer el documento
|
# XXX: No usamos Post#read porque a esta altura todavía no sabemos
|
||||||
read
|
# nada del Document
|
||||||
|
document.read! if File.exist? document.path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO: Convertir a UUID?
|
||||||
def id
|
def id
|
||||||
path.basename
|
path.basename
|
||||||
end
|
end
|
||||||
|
|
||||||
def sha1
|
def updated_at
|
||||||
Digest::SHA1.hexdigest id
|
File.mtime(path.absolute)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Levanta un error si al construir el artículo no pasamos un atributo.
|
|
||||||
def default_attributes_missing(**args)
|
|
||||||
DEFAULT_ATTRIBUTES.each do |attr|
|
|
||||||
i18n = I18n.t("exceptions.post.#{attr}_missing")
|
|
||||||
|
|
||||||
raise ArgumentError, i18n unless args[attr].present?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Solo ejecuta la magia de OpenStruct si el campo existe en la
|
# Solo ejecuta la magia de OpenStruct si el campo existe en la
|
||||||
# plantilla
|
# plantilla
|
||||||
|
@ -82,14 +89,18 @@ class Post < OpenStruct
|
||||||
# XXX: rubocop dice que tenemos que usar super cuando ya lo estamos
|
# XXX: rubocop dice que tenemos que usar super cuando ya lo estamos
|
||||||
# usando...
|
# usando...
|
||||||
def method_missing(mid, *args)
|
def method_missing(mid, *args)
|
||||||
unless attribute? mid
|
# Limpiar el nombre del atributo, para que todos los ayudantes
|
||||||
|
# reciban el método en limpio
|
||||||
|
name = attribute_name mid
|
||||||
|
|
||||||
|
unless attribute? name
|
||||||
raise NoMethodError, I18n.t('exceptions.post.no_method',
|
raise NoMethodError, I18n.t('exceptions.post.no_method',
|
||||||
method: mid)
|
method: mid)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Definir los attribute_*
|
# Definir los attribute_*
|
||||||
new_attribute_was(mid)
|
new_attribute_was(name)
|
||||||
new_attribute_changed(mid)
|
new_attribute_changed(name)
|
||||||
|
|
||||||
# OpenStruct
|
# OpenStruct
|
||||||
super(mid, *args)
|
super(mid, *args)
|
||||||
|
@ -101,12 +112,15 @@ class Post < OpenStruct
|
||||||
# Detecta si es un atributo válido o no, a partir de la tabla de la
|
# Detecta si es un atributo válido o no, a partir de la tabla de la
|
||||||
# plantilla
|
# plantilla
|
||||||
def attribute?(mid)
|
def attribute?(mid)
|
||||||
attrs = DEFAULT_ATTRIBUTES + PRIVATE_ATTRIBUTES + PUBLIC_ATTRIBUTES
|
included = DEFAULT_ATTRIBUTES.include?(mid) ||
|
||||||
if singleton_class.method_defined? :attributes
|
PRIVATE_ATTRIBUTES.include?(mid) ||
|
||||||
(attrs + attributes).include? attribute_name(mid)
|
PUBLIC_ATTRIBUTES.include?(mid)
|
||||||
else
|
|
||||||
attrs.include? attribute_name(mid)
|
if !included && singleton_class.method_defined?(:attributes)
|
||||||
|
included = attributes.include? mid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
included
|
||||||
end
|
end
|
||||||
|
|
||||||
# Devuelve los strong params para el layout
|
# Devuelve los strong params para el layout
|
||||||
|
@ -133,8 +147,10 @@ class Post < OpenStruct
|
||||||
{ metadata.to_s => template.value }
|
{ metadata.to_s => template.value }
|
||||||
end.compact.inject(:merge)
|
end.compact.inject(:merge)
|
||||||
|
|
||||||
|
# TODO: Convertir a Metadata?
|
||||||
# Asegurarse que haya un layout
|
# Asegurarse que haya un layout
|
||||||
yaml['layout'] = layout.name.to_s
|
yaml['layout'] = layout.name.to_s
|
||||||
|
yaml['uuid'] = uuid.value
|
||||||
# Y que no se procese liquid
|
# Y que no se procese liquid
|
||||||
yaml['liquid'] = false
|
yaml['liquid'] = false
|
||||||
yaml['usuaries'] = usuaries.map(&:id).uniq
|
yaml['usuaries'] = usuaries.map(&:id).uniq
|
||||||
|
@ -156,8 +172,8 @@ class Post < OpenStruct
|
||||||
|
|
||||||
# Guarda los cambios
|
# Guarda los cambios
|
||||||
# rubocop:disable Metrics/CyclomaticComplexity
|
# rubocop:disable Metrics/CyclomaticComplexity
|
||||||
def save(validation = true)
|
def save(validate: true)
|
||||||
return false if validation && !valid?
|
return false if validate && !valid?
|
||||||
# Salir si tenemos que cambiar el nombre del archivo y no pudimos
|
# Salir si tenemos que cambiar el nombre del archivo y no pudimos
|
||||||
return false if !new? && path_changed? && !update_path!
|
return false if !new? && path_changed? && !update_path!
|
||||||
return false unless save_attributes!
|
return false unless save_attributes!
|
||||||
|
@ -176,7 +192,7 @@ class Post < OpenStruct
|
||||||
return unless written?
|
return unless written?
|
||||||
|
|
||||||
document.path = path.absolute
|
document.path = path.absolute
|
||||||
document.read
|
document.read!
|
||||||
end
|
end
|
||||||
|
|
||||||
def new?
|
def new?
|
||||||
|
@ -197,12 +213,6 @@ class Post < OpenStruct
|
||||||
|
|
||||||
# Detecta si el artículo es válido para guardar
|
# Detecta si el artículo es válido para guardar
|
||||||
def valid?
|
def valid?
|
||||||
validate
|
|
||||||
errors.blank?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Requisitos para que el post sea válido
|
|
||||||
def validate
|
|
||||||
self.errors = {}
|
self.errors = {}
|
||||||
|
|
||||||
layout.metadata.keys.map(&:to_sym).each do |metadata|
|
layout.metadata.keys.map(&:to_sym).each do |metadata|
|
||||||
|
@ -210,8 +220,9 @@ class Post < OpenStruct
|
||||||
|
|
||||||
errors[metadata] = template.errors unless template.valid?
|
errors[metadata] = template.errors unless template.valid?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
errors.blank?
|
||||||
end
|
end
|
||||||
alias validate! validate
|
|
||||||
|
|
||||||
# Guarda los cambios en el archivo destino
|
# Guarda los cambios en el archivo destino
|
||||||
def write
|
def write
|
||||||
|
@ -239,18 +250,35 @@ class Post < OpenStruct
|
||||||
end
|
end
|
||||||
alias update update_attributes
|
alias update update_attributes
|
||||||
|
|
||||||
|
# El Document guarda un Array de los ids de Usuarie. Si está vacío,
|
||||||
|
# no hacemos una consulta vacía. Si no, traemos todes les Usuaries
|
||||||
|
# por su id y convertimos a Array para poder agregar o quitar luego
|
||||||
|
# sin pasar por ActiveRecord.
|
||||||
def usuaries
|
def usuaries
|
||||||
@usuaries ||= Usuarie.where(id: document_usuaries).to_a
|
@usuaries ||= if (d = document_usuaries).empty?
|
||||||
|
[]
|
||||||
|
else
|
||||||
|
Usuarie.where(id: d).to_a
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
# Levanta un error si al construir el artículo no pasamos un atributo.
|
||||||
|
def default_attributes_missing(**args)
|
||||||
|
DEFAULT_ATTRIBUTES.each do |attr|
|
||||||
|
i18n = I18n.t("exceptions.post.#{attr}_missing")
|
||||||
|
|
||||||
|
raise ArgumentError, i18n unless args[attr].present?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def document_usuaries
|
def document_usuaries
|
||||||
document.data.fetch('usuaries', [])
|
document.data.fetch('usuaries', [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def new_attribute_was(method)
|
def new_attribute_was(method)
|
||||||
attr_was = (attribute_name(method).to_s + '_was').to_sym
|
attr_was = "#{method}_was".to_sym
|
||||||
return attr_was if singleton_class.method_defined? attr_was
|
return attr_was if singleton_class.method_defined? attr_was
|
||||||
|
|
||||||
define_singleton_method(attr_was) do
|
define_singleton_method(attr_was) do
|
||||||
|
@ -265,7 +293,7 @@ class Post < OpenStruct
|
||||||
|
|
||||||
# Pregunta si el atributo cambió
|
# Pregunta si el atributo cambió
|
||||||
def new_attribute_changed(method)
|
def new_attribute_changed(method)
|
||||||
attr_changed = (attribute_name(method).to_s + '_changed?').to_sym
|
attr_changed = "#{method}_changed?".to_sym
|
||||||
|
|
||||||
return attr_changed if singleton_class.method_defined? attr_changed
|
return attr_changed if singleton_class.method_defined? attr_changed
|
||||||
|
|
||||||
|
@ -314,6 +342,13 @@ class Post < OpenStruct
|
||||||
required: true)
|
required: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def load_uuid!
|
||||||
|
self.uuid = MetadataUuid.new(document: document, site: site,
|
||||||
|
layout: layout, name: :uuid,
|
||||||
|
type: :uuid, post: self,
|
||||||
|
required: true)
|
||||||
|
end
|
||||||
|
|
||||||
# Ejecuta la acción de guardado en cada atributo
|
# Ejecuta la acción de guardado en cada atributo
|
||||||
def save_attributes!
|
def save_attributes!
|
||||||
attributes.map do |attr|
|
attributes.map do |attr|
|
||||||
|
|
|
@ -31,15 +31,18 @@ class PostRelation < Array
|
||||||
post
|
post
|
||||||
end
|
end
|
||||||
|
|
||||||
|
alias sort_by_generic sort_by
|
||||||
alias sort_by_generic! sort_by!
|
alias sort_by_generic! sort_by!
|
||||||
|
|
||||||
# Permite ordenar los artículos por sus atributos
|
# Permite ordenar los artículos por sus atributos
|
||||||
#
|
#
|
||||||
# XXX: Prestar atención cuando estamos mezclando artículos con
|
# XXX: Prestar atención cuando estamos mezclando artículos con
|
||||||
# diferentes tipos de atributos.
|
# diferentes tipos de atributos.
|
||||||
def sort_by!(*attrs)
|
def sort_by(*attrs)
|
||||||
sort_by_generic! do |post|
|
sort_by_generic do |post|
|
||||||
attrs.map do |attr|
|
attrs.map do |attr|
|
||||||
|
# TODO: detectar el tipo de atributo faltante y obtener el valor
|
||||||
|
# por defecto para hacer la comparación
|
||||||
return 0 unless post.attributes.include? attr
|
return 0 unless post.attributes.include? attr
|
||||||
|
|
||||||
post.public_send(attr).value
|
post.public_send(attr).value
|
||||||
|
@ -47,12 +50,20 @@ class PostRelation < Array
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def sort_by!(*attrs)
|
||||||
|
replace sort_by(*attrs)
|
||||||
|
end
|
||||||
|
|
||||||
alias find_generic find
|
alias find_generic find
|
||||||
|
|
||||||
# Encontra un post por su id convertido a SHA1
|
# Encontrar un post por su UUID
|
||||||
def find(id, sha1: false)
|
def find(id, uuid: false)
|
||||||
find_generic do |p|
|
find_generic do |p|
|
||||||
p.sha1 == (sha1 ? id : Digest::SHA1.hexdigest(id))
|
if uuid
|
||||||
|
p.uuid.value == id
|
||||||
|
else
|
||||||
|
p.id == id
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -65,8 +76,10 @@ class PostRelation < Array
|
||||||
end
|
end
|
||||||
|
|
||||||
# Intenta guardar todos y devuelve true si pudo
|
# Intenta guardar todos y devuelve true si pudo
|
||||||
def save_all
|
def save_all(validate: true)
|
||||||
map(&:save).all?
|
map do |post|
|
||||||
|
post.save(validate: validate)
|
||||||
|
end.all?
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -9,7 +9,10 @@ class Site < ApplicationRecord
|
||||||
# @see app/services/site_service.rb
|
# @see app/services/site_service.rb
|
||||||
DEPLOYS = %i[local www zip].freeze
|
DEPLOYS = %i[local www zip].freeze
|
||||||
|
|
||||||
validates :name, uniqueness: true, hostname: true
|
validates :name, uniqueness: true, hostname: {
|
||||||
|
allow_root_label: true
|
||||||
|
}
|
||||||
|
|
||||||
validates :design_id, presence: true
|
validates :design_id, presence: true
|
||||||
validate :deploy_local_presence
|
validate :deploy_local_presence
|
||||||
validates_inclusion_of :status, in: %w[waiting enqueued building]
|
validates_inclusion_of :status, in: %w[waiting enqueued building]
|
||||||
|
@ -173,14 +176,10 @@ class Site < ApplicationRecord
|
||||||
|
|
||||||
@posts[lang] = PostRelation.new site: self
|
@posts[lang] = PostRelation.new site: self
|
||||||
|
|
||||||
# Jekyll lee los documentos en orden cronológico pero los invierte
|
|
||||||
# durante la renderización. Usamos el orden cronológico inverso por
|
|
||||||
# defecto para mostrar los artículos más nuevos primero.
|
|
||||||
docs = collections[lang.to_s].try(:docs).try(:sort) { |a, b| b <=> a }
|
|
||||||
# No fallar si no existe colección para este idioma
|
# No fallar si no existe colección para este idioma
|
||||||
# XXX: queremos fallar silenciosamente?
|
# XXX: queremos fallar silenciosamente?
|
||||||
(docs || []).each do |doc|
|
(collections[lang.to_s].try(:docs) || []).each do |doc|
|
||||||
layout = layouts[doc.data['layout'].to_sym]
|
layout = layouts[Post.find_layout(doc)]
|
||||||
|
|
||||||
@posts[lang].build(document: doc, layout: layout, lang: lang)
|
@posts[lang].build(document: doc, layout: layout, lang: lang)
|
||||||
end
|
end
|
||||||
|
|
|
@ -79,7 +79,7 @@ class Site
|
||||||
end
|
end
|
||||||
|
|
||||||
# Guardamos los cambios
|
# Guardamos los cambios
|
||||||
unless doc.save(false)
|
unless doc.save(validate: false)
|
||||||
log.write "#{doc.path.relative} no se pudo guardar\n"
|
log.write "#{doc.path.relative} no se pudo guardar\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
|
||||||
#
|
#
|
||||||
# @return Post
|
# @return Post
|
||||||
def create
|
def create
|
||||||
# TODO: Implementar layout
|
self.post = site.posts(lang: params[:post][:lang] || I18n.locale)
|
||||||
self.post = site.posts(lang: params[:post][:lang] || I18n.locale).build
|
.build(layout: params[:post][:layout])
|
||||||
post.usuaries << usuarie
|
post.usuaries << usuarie
|
||||||
params[:post][:draft] = true if site.invitade? usuarie
|
params[:post][:draft] = true if site.invitade? usuarie
|
||||||
|
|
||||||
|
@ -40,25 +40,31 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
|
||||||
end
|
end
|
||||||
|
|
||||||
# Reordena todos los posts que soporten orden de acuerdo a un hash de
|
# Reordena todos los posts que soporten orden de acuerdo a un hash de
|
||||||
# ids y nuevas posiciones. La posición actual la da la posición en
|
# uuids y nuevas posiciones. La posición actual la da la posición en
|
||||||
# el array.
|
# el array.
|
||||||
#
|
#
|
||||||
# { sha1 => 2, sha1 => 1, sha1 => 0 }
|
# { uuid => 2, uuid => 1, uuid => 0 }
|
||||||
def reorder
|
def reorder
|
||||||
posts = site.posts(lang: lang)
|
posts = site.posts(lang: lang)
|
||||||
reorder = params.require(:post).permit(reorder: {}).try(:[], :reorder)
|
reorder = params.require(:post).permit(reorder: {}).try(:[], :reorder)
|
||||||
|
modified = PostRelation.new(site: site)
|
||||||
|
|
||||||
files = reorder.keys.map do |id|
|
files = reorder.keys.map do |uuid|
|
||||||
post = posts.find(id, sha1: true)
|
post = posts.find(uuid, uuid: true)
|
||||||
|
order = reorder[uuid].to_i
|
||||||
|
|
||||||
|
next unless post
|
||||||
next unless post.attributes.include? :order
|
next unless post.attributes.include? :order
|
||||||
|
next if post.order.value == order
|
||||||
|
|
||||||
post.usuaries << usuarie
|
modified << post
|
||||||
post.order.value = reorder[id].to_i
|
post.order.value = order
|
||||||
post.path.absolute
|
post.path.absolute
|
||||||
end.compact
|
end.compact
|
||||||
|
|
||||||
# TODO: Implementar transacciones!
|
# TODO: Implementar transacciones!
|
||||||
posts.save_all && commit(action: :reorder, file: files)
|
modified.save_all(validate: false) &&
|
||||||
|
commit(action: :reorder, file: files)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
= t('.greeting', recipient: @email)
|
||||||
|
\
|
||||||
|
= t('.instruction')
|
||||||
|
\
|
||||||
|
= confirmation_url(@resource, confirmation_token: @token)
|
6
app/views/devise/mailer/email_changed.text.haml
Normal file
6
app/views/devise/mailer/email_changed.text.haml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
= t('.greeting', recipient: @email)
|
||||||
|
\
|
||||||
|
- if @resource.try(:unconfirmed_email?)
|
||||||
|
= t('.message', email: @resource.unconfirmed_email)
|
||||||
|
- else
|
||||||
|
= t('.message', email: @resource.email)
|
3
app/views/devise/mailer/password_change.text.haml
Normal file
3
app/views/devise/mailer/password_change.text.haml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
= t('.greeting', recipient: @resource.email)
|
||||||
|
\
|
||||||
|
= t('.message')
|
|
@ -0,0 +1,9 @@
|
||||||
|
= t('.greeting', recipient: @resource.email)
|
||||||
|
\
|
||||||
|
= t('.instruction')
|
||||||
|
\
|
||||||
|
= edit_password_url(@resource, reset_password_token: @token)
|
||||||
|
\
|
||||||
|
= t('.instruction_2')
|
||||||
|
\
|
||||||
|
= t('.instruction_3')
|
7
app/views/devise/mailer/unlock_instructions.text.haml
Normal file
7
app/views/devise/mailer/unlock_instructions.text.haml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
= t('.greeting', recipient: @resource.email)
|
||||||
|
\
|
||||||
|
= t('.message')
|
||||||
|
\
|
||||||
|
= t('.instruction')
|
||||||
|
\
|
||||||
|
= unlock_url(@resource, unlock_token: @token)
|
|
@ -5,9 +5,8 @@
|
||||||
|
|
||||||
.row.align-items-center.justify-content-center.full-height
|
.row.align-items-center.justify-content-center.full-height
|
||||||
.col-md-5.align-self-center
|
.col-md-5.align-self-center
|
||||||
.sr-only
|
%h2= t('.sign_up')
|
||||||
%h2= t('.sign_up')
|
%p= t('.help')
|
||||||
%p= t('.help')
|
|
||||||
|
|
||||||
= form_for(resource,
|
= form_for(resource,
|
||||||
as: resource_name,
|
as: resource_name,
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
%br/
|
%br/
|
||||||
|
|
||||||
- if devise_mapping.registerable? && controller_name != 'registrations'
|
- 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),
|
||||||
|
class: 'btn btn-lg btn-block btn-success'
|
||||||
%br/
|
%br/
|
||||||
|
|
||||||
- if devise_mapping.recoverable?
|
- if devise_mapping.recoverable?
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
%nav.navbar
|
%nav.navbar
|
||||||
%a.navbar-brand.d-none.d-sm-block{ href: '/' }
|
%a.navbar-brand.d-none.d-sm-block{ href: '/' }
|
||||||
= inline_svg 'sutty.svg', class: 'black', aria: true,
|
= inline_svg_tag 'sutty.svg', class: 'black', aria: true,
|
||||||
title: t('svg.sutty.title'), desc: t('svg.sutty.desc')
|
title: t('svg.sutty.title'), desc: t('svg.sutty.desc')
|
||||||
|
|
||||||
- if crumbs
|
- if crumbs
|
||||||
|
@ -21,9 +21,6 @@
|
||||||
|
|
||||||
- if current_usuarie
|
- if current_usuarie
|
||||||
%ul.navbar-nav
|
%ul.navbar-nav
|
||||||
%li.nav-item
|
|
||||||
= link_to t('.mutual_aid'), mutual_aid_url(local_channel),
|
|
||||||
class: 'btn'
|
|
||||||
%li.nav-item
|
%li.nav-item
|
||||||
= link_to t('.logout'), destroy_usuarie_session_path,
|
= link_to t('.logout'), destroy_usuarie_session_path,
|
||||||
method: :delete, role: 'button', class: 'btn'
|
method: :delete, role: 'button', class: 'btn'
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
= yield
|
= yield
|
||||||
|
\
|
||||||
|
= '-- '
|
||||||
= t('.signature')
|
= t('.signature')
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
-# Botones de guardado
|
-# Botones de guardado
|
||||||
= render 'posts/submit', site: site, post: post
|
= render 'posts/submit', site: site, post: post
|
||||||
|
|
||||||
|
= hidden_field_tag 'post[layout]', params[:layout] || 'post'
|
||||||
|
|
||||||
-# Dibuja cada atributo
|
-# Dibuja cada atributo
|
||||||
- post.attributes.each do |attribute|
|
- post.attributes.each do |attribute|
|
||||||
- metadata = post.send(attribute)
|
- metadata = post.send(attribute)
|
||||||
|
|
3
app/views/posts/attribute_ro/_color.haml
Normal file
3
app/views/posts/attribute_ro/_color.haml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
%tr{ id: attribute }
|
||||||
|
%th= post_label_t(attribute, post: post)
|
||||||
|
%td{ style: "background-color: #{metadata.value}" } = metadata.value
|
|
@ -1,3 +1,3 @@
|
||||||
%tr{ id: attribute }
|
%tr{ id: attribute }
|
||||||
%th= post_label_t(attribute, post: post)
|
%th= post_label_t(attribute, post: post)
|
||||||
%td= sanitize_markdown metadata.value, tags: tags
|
%td= metadata.value
|
||||||
|
|
4
app/views/posts/attribute_ro/_email.haml
Normal file
4
app/views/posts/attribute_ro/_email.haml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
%tr{ id: attribute }
|
||||||
|
%th= post_label_t(attribute, post: post)
|
||||||
|
%td
|
||||||
|
%a{ href: "mailto:#{metadata.value}" }= metadata.value
|
|
@ -2,6 +2,5 @@
|
||||||
%th= post_label_t(attribute, :path, post: post)
|
%th= post_label_t(attribute, :path, post: post)
|
||||||
%td
|
%td
|
||||||
- if metadata.value['path'].present?
|
- if metadata.value['path'].present?
|
||||||
%figure
|
= link_to t('.download'), url_for(metadata.static_file)
|
||||||
= link_to url_for(metadata.static_file)
|
%p= metadata.value['description']
|
||||||
%figcaption= metadata.value['description']
|
|
||||||
|
|
9
app/views/posts/attribute_ro/_geo.haml
Normal file
9
app/views/posts/attribute_ro/_geo.haml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
- lat = metadata.value['lat']
|
||||||
|
- lng = metadata.value['lng']
|
||||||
|
%tr{ id: attribute }
|
||||||
|
%th= post_label_t(attribute, post: post)
|
||||||
|
%td
|
||||||
|
= link_to t('posts.attributes.geo.uri'), "geo:#{lat},#{lng}"
|
||||||
|
%br/
|
||||||
|
= link_to t('posts.attributes.geo.osm'),
|
||||||
|
"https://www.openstreetmap.org/?mlat=#{lat}&mlon=#{lng}#map=9/#{lat}/#{lng}"
|
11
app/views/posts/attribute_ro/_related_posts.haml
Normal file
11
app/views/posts/attribute_ro/_related_posts.haml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
%tr{ id: attribute }
|
||||||
|
%th= post_label_t(attribute, post: post)
|
||||||
|
%td
|
||||||
|
%ul
|
||||||
|
- metadata.value.each do |v|
|
||||||
|
- p = site.posts(lang: post.lang.value).find(v, uuid: true)
|
||||||
|
-#
|
||||||
|
XXX: Ignorar todos los posts no encontrados (ej: fueron
|
||||||
|
borrados o el uuid cambió)
|
||||||
|
- next unless p
|
||||||
|
%li= link_to p.title.value, site_post_path(site, p.id)
|
3
app/views/posts/attribute_ro/_uuid.haml
Normal file
3
app/views/posts/attribute_ro/_uuid.haml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
%tr{ id: attribute }
|
||||||
|
%th= post_label_t(attribute, post: post)
|
||||||
|
%td= metadata.value
|
6
app/views/posts/attributes/_color.haml
Normal file
6
app/views/posts/attributes/_color.haml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
.form-group
|
||||||
|
= label_tag "post_#{attribute}", post_label_t(attribute, post: post)
|
||||||
|
= color_field 'post', attribute, value: metadata.value,
|
||||||
|
**field_options(attribute, metadata)
|
||||||
|
= render 'posts/attribute_feedback',
|
||||||
|
post: post, attribute: attribute, metadata: metadata
|
|
@ -1,6 +1,6 @@
|
||||||
.form-group
|
.form-group
|
||||||
= label_tag "post_#{attribute}", post_label_t(attribute, post: post)
|
= label_tag "post_#{attribute}", post_label_t(attribute, post: post)
|
||||||
= date_field 'post', attribute, value: metadata.value.strftime('%F'),
|
= date_field 'post', attribute, value: metadata.value.to_date.strftime('%F'),
|
||||||
**field_options(attribute, metadata)
|
**field_options(attribute, metadata)
|
||||||
= render 'posts/attribute_feedback',
|
= render 'posts/attribute_feedback',
|
||||||
post: post, attribute: attribute, metadata: metadata
|
post: post, attribute: attribute, metadata: metadata
|
||||||
|
|
6
app/views/posts/attributes/_email.haml
Normal file
6
app/views/posts/attributes/_email.haml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
.form-group
|
||||||
|
= label_tag "post_#{attribute}", post_label_t(attribute, post: post)
|
||||||
|
= email_field 'post', attribute, value: metadata.value,
|
||||||
|
**field_options(attribute, metadata)
|
||||||
|
= render 'posts/attribute_feedback',
|
||||||
|
post: post, attribute: attribute, metadata: metadata
|
19
app/views/posts/attributes/_geo.haml
Normal file
19
app/views/posts/attributes/_geo.haml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
.row
|
||||||
|
.col
|
||||||
|
.form-group
|
||||||
|
= label_tag "post_#{attribute}_lat",
|
||||||
|
post_label_t(attribute, :lat, post: post)
|
||||||
|
= text_field(*field_name_for('post', attribute, :lat),
|
||||||
|
value: metadata.value['lat'],
|
||||||
|
**field_options(attribute, metadata))
|
||||||
|
= render 'posts/attribute_feedback',
|
||||||
|
post: post, attribute: [attribute, :lat], metadata: metadata
|
||||||
|
.col
|
||||||
|
.form-group
|
||||||
|
= label_tag "post_#{attribute}_lng",
|
||||||
|
post_label_t(attribute, :lng, post: post)
|
||||||
|
= text_field(*field_name_for('post', attribute, :lng),
|
||||||
|
value: metadata.value['lng'],
|
||||||
|
**field_options(attribute, metadata))
|
||||||
|
= render 'posts/attribute_feedback',
|
||||||
|
post: post, attribute: [attribute, :lat], metadata: metadata
|
19
app/views/posts/attributes/_related_posts.haml
Normal file
19
app/views/posts/attributes/_related_posts.haml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
.form-group
|
||||||
|
= label_tag "post_#{attribute}", post_label_t(attribute, post: post)
|
||||||
|
|
||||||
|
.mapable{ data: { values: metadata.value.to_json,
|
||||||
|
'default-values': metadata.values.to_json,
|
||||||
|
name: "post[#{attribute}][]", list: id_for_datalist(attribute),
|
||||||
|
remove: 'false', legend: post_label_t(attribute, post: post),
|
||||||
|
described: id_for_help(attribute) } }
|
||||||
|
|
||||||
|
= text_field(*field_name_for('post', attribute, '[]'),
|
||||||
|
value: metadata.value.join(', '),
|
||||||
|
**field_options(attribute, metadata))
|
||||||
|
|
||||||
|
= render 'posts/attribute_feedback',
|
||||||
|
post: post, attribute: attribute, metadata: metadata
|
||||||
|
|
||||||
|
%datalist{ id: id_for_datalist(attribute) }
|
||||||
|
- metadata.values.keys.each do |value|
|
||||||
|
%option{ value: value }
|
1
app/views/posts/attributes/_uuid.haml
Normal file
1
app/views/posts/attributes/_uuid.haml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
-# nada
|
|
@ -25,62 +25,61 @@
|
||||||
|
|
||||||
%section.col
|
%section.col
|
||||||
= render 'layouts/flash'
|
= render 'layouts/flash'
|
||||||
- if @posts.present?
|
- if @posts.empty?
|
||||||
.row
|
|
||||||
.col
|
|
||||||
= form_tag site_posts_reorder_path, method: :post do
|
|
||||||
= submit_tag t('posts.reorder'), class: 'btn submit-reorder d-none'
|
|
||||||
-# TODO: Permitir cambiar el idioma
|
|
||||||
%table.table.table-condensed.table-draggable
|
|
||||||
%tbody
|
|
||||||
- @posts.each_with_index do |post, i|
|
|
||||||
-#
|
|
||||||
saltearse el post a menos que esté en la categoría por
|
|
||||||
la que estamos filtrando
|
|
||||||
- if @category
|
|
||||||
- next unless post.attributes.include? :categories
|
|
||||||
- next unless post.categories.value.include?(@category)
|
|
||||||
- if @layout
|
|
||||||
- next unless post.layout.name == @layout
|
|
||||||
- next unless policy(post).show?
|
|
||||||
%tr
|
|
||||||
%td
|
|
||||||
.handle
|
|
||||||
= image_tag 'arrows-alt-v.svg'
|
|
||||||
= hidden_field 'post[reorder]', post.sha1,
|
|
||||||
value: i, class: 'reorder'
|
|
||||||
%td
|
|
||||||
%small
|
|
||||||
= link_to post.layout.name.to_s.humanize,
|
|
||||||
site_posts_path(@site, layout: post.layout.name)
|
|
||||||
%br/
|
|
||||||
= link_to post.title.value,
|
|
||||||
site_post_path(@site, post.id)
|
|
||||||
- if post.attributes.include? :draft
|
|
||||||
- if post.draft.value
|
|
||||||
%span.badge.badge-primary
|
|
||||||
= post_label_t(:draft, post: post)
|
|
||||||
- if post.attributes.include? :categories
|
|
||||||
- unless post.categories.value.empty?
|
|
||||||
%br
|
|
||||||
%small
|
|
||||||
- post.categories.value.each do |c|
|
|
||||||
= link_to c, site_posts_path(@site, category: c)
|
|
||||||
|
|
||||||
%td
|
|
||||||
= post.date.value.strftime('%F')
|
|
||||||
%br/
|
|
||||||
= post.try(:order).try(:value)
|
|
||||||
%td
|
|
||||||
- if policy(post).edit?
|
|
||||||
= link_to t('posts.edit'),
|
|
||||||
edit_site_post_path(@site, post.id),
|
|
||||||
class: 'btn'
|
|
||||||
- if policy(post).destroy?
|
|
||||||
= link_to t('posts.destroy'),
|
|
||||||
site_post_path(@site, post.id),
|
|
||||||
class: 'btn',
|
|
||||||
method: :delete,
|
|
||||||
data: { confirm: t('posts.confirm_destroy') }
|
|
||||||
- else
|
|
||||||
%h2= t('posts.none')
|
%h2= t('posts.none')
|
||||||
|
- else
|
||||||
|
= form_tag site_posts_reorder_path, method: :post do
|
||||||
|
= submit_tag t('posts.reorder'), class: 'btn submit-reorder'
|
||||||
|
-# TODO: Permitir cambiar el idioma
|
||||||
|
%table.table.table-condensed.table-draggable
|
||||||
|
%tbody
|
||||||
|
- @posts.each_with_index do |post, i|
|
||||||
|
-#
|
||||||
|
saltearse el post a menos que esté en la categoría por
|
||||||
|
la que estamos filtrando
|
||||||
|
- if @category
|
||||||
|
- next unless post.attributes.include? :categories
|
||||||
|
- next unless post.categories.value.include?(@category)
|
||||||
|
- if @layout
|
||||||
|
- next unless post.layout.name == @layout
|
||||||
|
- next unless @usuarie || policy(post).show?
|
||||||
|
%tr
|
||||||
|
%td
|
||||||
|
.handle
|
||||||
|
= image_tag 'arrows-alt-v.svg'
|
||||||
|
-# Orden más alto es mayor prioridad
|
||||||
|
= hidden_field 'post[reorder]', post.uuid.value,
|
||||||
|
value: @posts.length - i, class: 'reorder'
|
||||||
|
%td
|
||||||
|
%small
|
||||||
|
= link_to post.layout.name.to_s.humanize,
|
||||||
|
site_posts_path(@site, layout: post.layout.name)
|
||||||
|
%br/
|
||||||
|
= link_to post.title.value,
|
||||||
|
site_post_path(@site, post.id)
|
||||||
|
- if post.attributes.include? :draft
|
||||||
|
- if post.draft.value
|
||||||
|
%span.badge.badge-primary
|
||||||
|
= post_label_t(:draft, post: post)
|
||||||
|
- if post.attributes.include? :categories
|
||||||
|
- unless post.categories.value.empty?
|
||||||
|
%br
|
||||||
|
%small
|
||||||
|
- post.categories.value.each do |c|
|
||||||
|
= link_to c, site_posts_path(@site, category: c)
|
||||||
|
|
||||||
|
%td
|
||||||
|
= post.date.value.strftime('%F')
|
||||||
|
%br/
|
||||||
|
= post.try(:order).try(:value)
|
||||||
|
%td
|
||||||
|
- if @usuarie || policy(post).edit?
|
||||||
|
= link_to t('posts.edit'),
|
||||||
|
edit_site_post_path(@site, post.id),
|
||||||
|
class: 'btn'
|
||||||
|
- if @usuarie || policy(post).destroy?
|
||||||
|
= link_to t('posts.destroy'),
|
||||||
|
site_post_path(@site, post.id),
|
||||||
|
class: 'btn',
|
||||||
|
method: :delete,
|
||||||
|
data: { confirm: t('posts.confirm_destroy') }
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
= render("posts/attribute_ro/#{metadata.type}",
|
= render("posts/attribute_ro/#{metadata.type}",
|
||||||
post: @post, attribute: attr,
|
post: @post, attribute: attr,
|
||||||
metadata: metadata,
|
metadata: metadata,
|
||||||
|
site: @site,
|
||||||
tags: all_html_tags)
|
tags: all_html_tags)
|
||||||
|
|
||||||
-# Mostrar todo lo que no va en el front_matter (el contenido)
|
-# Mostrar todo lo que no va en el front_matter (el contenido)
|
||||||
|
@ -33,4 +34,4 @@
|
||||||
- next if @post.send(attr).front_matter?
|
- next if @post.send(attr).front_matter?
|
||||||
|
|
||||||
%section{ id: attr }
|
%section{ id: attr }
|
||||||
= sanitize_markdown @post.send(attr).value, tags: all_html_tags
|
= raw @post.send(attr).value
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
link: nil
|
link: nil
|
||||||
- else
|
- else
|
||||||
= form_tag site_enqueue_path(site),
|
= form_tag site_enqueue_path(site),
|
||||||
method: :post, class: 'form-inline' do
|
method: :post, class: 'form-inline inline' do
|
||||||
= button_tag type: 'submit',
|
= button_tag type: 'submit',
|
||||||
class: 'btn no-border-radius',
|
class: 'btn no-border-radius',
|
||||||
title: t('help.sites.enqueue'),
|
title: t('help.sites.enqueue'),
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
= f.text_field :name,
|
= f.text_field :name,
|
||||||
class: form_control(site, :name),
|
class: form_control(site, :name),
|
||||||
required: true,
|
required: true,
|
||||||
pattern: '^([a-z0-9][a-z0-9\-]*)?[a-z0-9]$',
|
pattern: '^([a-z0-9][a-z0-9\-]*)?[a-z0-9\.]$',
|
||||||
minlength: 1,
|
minlength: 1,
|
||||||
maxlength: 63
|
maxlength: 63
|
||||||
- if invalid? site, :name
|
- if invalid? site, :name
|
||||||
|
@ -86,14 +86,20 @@
|
||||||
|
|
||||||
%hr/
|
%hr/
|
||||||
|
|
||||||
.form-group
|
- if site.persisted?
|
||||||
%h2= t('.deploys.title')
|
.form-group
|
||||||
%p.lead= t('.help.deploys')
|
%h2= t('.deploys.title')
|
||||||
|
%p.lead= t('.help.deploys')
|
||||||
|
|
||||||
|
= f.fields_for :deploys do |deploy|
|
||||||
|
= render "deploys/#{deploy.object.type.underscore}",
|
||||||
|
deploy: deploy, site: site
|
||||||
|
%hr/
|
||||||
|
- else
|
||||||
= f.fields_for :deploys do |deploy|
|
= f.fields_for :deploys do |deploy|
|
||||||
= render "deploys/#{deploy.object.type.underscore}",
|
- next unless deploy.object.is_a? DeployLocal
|
||||||
deploy: deploy, site: site
|
|
||||||
%hr/
|
= deploy.hidden_field :type
|
||||||
|
|
||||||
.form-group
|
.form-group
|
||||||
= f.submit submit, class: 'btn btn-lg btn-block'
|
= f.submit submit, class: 'btn btn-lg btn-block'
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
= render 'layouts/breadcrumb',
|
= render 'layouts/breadcrumb',
|
||||||
crumbs: [link_to(t('sites.index.title'), sites_path),
|
crumbs: [link_to(t('sites.index.title'), sites_path),
|
||||||
t('.title', site: @site.name)]
|
t('.title', site: @site.name)]
|
||||||
.row
|
.row.justify-content-center
|
||||||
.col
|
.col-md-8
|
||||||
%h1= t('.title', site: @site.name)
|
%h1= t('.title', site: @site.name)
|
||||||
|
|
||||||
= render 'form', site: @site, submit: t('.submit')
|
= render 'form', site: @site, submit: t('.submit')
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
class: 'btn'
|
class: 'btn'
|
||||||
|
|
||||||
%section.col
|
%section.col
|
||||||
|
- if @sites.empty?
|
||||||
|
:markdown
|
||||||
|
#{t('.welcome')}
|
||||||
%table.table.table-condensed
|
%table.table.table-condensed
|
||||||
%tbody
|
%tbody
|
||||||
- @sites.each do |site|
|
- @sites.each do |site|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
= render 'layouts/breadcrumb',
|
= render 'layouts/breadcrumb',
|
||||||
crumbs: [link_to(t('sites.index.title'), sites_path), t('.title')]
|
crumbs: [link_to(t('sites.index.title'), sites_path), t('.title')]
|
||||||
|
|
||||||
.row
|
.row.justify-content-center
|
||||||
.col
|
.col-md-8
|
||||||
%h1= t('.title')
|
%h1= t('.title')
|
||||||
|
%p.lead= t('.help')
|
||||||
|
|
||||||
= render 'form', site: @site, submit: t('.submit')
|
= render 'form', site: @site, submit: t('.submit')
|
||||||
|
|
77
config/blazer.yml
Normal file
77
config/blazer.yml
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
# see https://github.com/ankane/blazer for more info
|
||||||
|
|
||||||
|
data_sources:
|
||||||
|
main:
|
||||||
|
url: <%= ENV["BLAZER_DATABASE_URL"] %>
|
||||||
|
|
||||||
|
# statement timeout, in seconds
|
||||||
|
# none by default
|
||||||
|
# timeout: 15
|
||||||
|
|
||||||
|
# caching settings
|
||||||
|
# can greatly improve speed
|
||||||
|
# off by default
|
||||||
|
# cache:
|
||||||
|
# mode: slow # or all
|
||||||
|
# expires_in: 60 # min
|
||||||
|
# slow_threshold: 15 # sec, only used in slow mode
|
||||||
|
|
||||||
|
# wrap queries in a transaction for safety
|
||||||
|
# not necessary if you use a read-only user
|
||||||
|
# true by default
|
||||||
|
# use_transaction: false
|
||||||
|
|
||||||
|
smart_variables:
|
||||||
|
site_id: 'select id, name from sites order by name asc'
|
||||||
|
# zone_id: "SELECT id, name FROM zones ORDER BY name ASC"
|
||||||
|
# period: ["day", "week", "month"]
|
||||||
|
# status: {0: "Active", 1: "Archived"}
|
||||||
|
|
||||||
|
linked_columns:
|
||||||
|
# user_id: "/admin/users/{value}"
|
||||||
|
|
||||||
|
smart_columns:
|
||||||
|
site_id: 'select id, name from sites where id in {value}'
|
||||||
|
# user_id: "SELECT id, name FROM users WHERE id IN {value}"
|
||||||
|
|
||||||
|
# create audits
|
||||||
|
audit: true
|
||||||
|
|
||||||
|
# change the time zone
|
||||||
|
# time_zone: "Pacific Time (US & Canada)"
|
||||||
|
|
||||||
|
# class name of the user model
|
||||||
|
user_class: Usuarie
|
||||||
|
|
||||||
|
# method name for the current user
|
||||||
|
user_method: current_usuarie
|
||||||
|
|
||||||
|
# method name for the display name
|
||||||
|
user_name: email
|
||||||
|
|
||||||
|
# custom before_action to use for auth
|
||||||
|
# before_action_method: require_admin
|
||||||
|
|
||||||
|
# email to send checks from
|
||||||
|
from_email: blazer@<%= ENV.fetch('SUTTY', 'sutty.nl') %>
|
||||||
|
|
||||||
|
# webhook for Slack
|
||||||
|
# slack_webhook_url: <%= ENV["BLAZER_SLACK_WEBHOOK_URL"] %>
|
||||||
|
|
||||||
|
check_schedules:
|
||||||
|
- "1 day"
|
||||||
|
- "1 hour"
|
||||||
|
- "5 minutes"
|
||||||
|
|
||||||
|
override_csp: true
|
||||||
|
|
||||||
|
# enable anomaly detection
|
||||||
|
# note: with trend, time series are sent to https://trendapi.org
|
||||||
|
# anomaly_checks: trend / r
|
||||||
|
|
||||||
|
# enable forecasting
|
||||||
|
# note: with trend, time series are sent to https://trendapi.org
|
||||||
|
# forecasting: trend
|
||||||
|
|
||||||
|
# enable map
|
||||||
|
# mapbox_access_token: <%= ENV["MAPBOX_ACCESS_TOKEN"] %>
|
|
@ -6,31 +6,35 @@
|
||||||
# For further information see the following documentation
|
# For further information see the following documentation
|
||||||
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
|
||||||
|
|
||||||
# Rails.application.config.content_security_policy do |policy|
|
Rails.application.config.content_security_policy do |policy|
|
||||||
# policy.default_src :self, :https
|
policy.default_src :self
|
||||||
# policy.font_src :self, :https, :data
|
# XXX: Varios scripts generan estilos en línea
|
||||||
# policy.img_src :self, :https, :data
|
policy.style_src :self, :unsafe_inline
|
||||||
# policy.object_src :none
|
# Repetimos la default para poder saber cuál es la política en falta
|
||||||
# policy.script_src :self, :https
|
policy.script_src :self
|
||||||
# policy.style_src :self, :https
|
policy.font_src :self
|
||||||
# # If you are using webpack-dev-server then specify
|
# TODO: Permitimos cargar imágenes remotas?
|
||||||
# # webpack-dev-server host
|
# XXX: Los íconos de Trix se cargan vía data:
|
||||||
# policy.connect_src :self, :https, "http://localhost:3035",
|
policy.img_src :self, :data
|
||||||
# "ws://localhost:3035" if Rails.env.development?
|
# Ya no usamos applets!
|
||||||
|
policy.object_src :none
|
||||||
|
if Rails.env.development?
|
||||||
|
policy.connect_src :self,
|
||||||
|
'http://localhost:3035',
|
||||||
|
'ws://localhost:3035'
|
||||||
|
end
|
||||||
|
|
||||||
# # Specify URI for violation reports
|
# Specify URI for violation reports
|
||||||
# # policy.report_uri "/csp-violation-report-endpoint"
|
policy.report_uri "https://api.#{ENV.fetch('SUTTY_WITH_PORT', 'sutty.nl')}/v1/csp_reports.json"
|
||||||
# end
|
end
|
||||||
|
|
||||||
# If you are using UJS then enable automatic nonce generation
|
# If you are using UJS then enable automatic nonce generation
|
||||||
# Rails.application.config.content_security_policy_nonce_generator =
|
# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
|
||||||
# -> request { SecureRandom.base64(16) }
|
|
||||||
|
|
||||||
# Set the nonce only to specific directives
|
# Set the nonce only to specific directives
|
||||||
# Rails.application.config.content_security_policy_nonce_directives =
|
# Rails.application.config.content_security_policy_nonce_directives = %w(script-src)
|
||||||
# %w(script-src)
|
|
||||||
|
|
||||||
# Report CSP violations to a specified URI
|
# Report CSP violations to a specified URI
|
||||||
# For further information see the following documentation:
|
# For further information see the following documentation:
|
||||||
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
|
||||||
# Rails.application.config.content_security_policy_report_only = true
|
Rails.application.config.content_security_policy_report_only = false
|
||||||
|
|
|
@ -1,6 +1,36 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'jekyll/document'
|
|
||||||
|
|
||||||
String.include CoreExtensions::String::StripTags
|
String.include CoreExtensions::String::StripTags
|
||||||
Jekyll::Document.include CoreExtensions::Jekyll::Document::Path
|
Jekyll::Document.include CoreExtensions::Jekyll::Document::Path
|
||||||
|
|
||||||
|
# Lazy Loading de Jekyll, deshabilitando la instanciación de elementos
|
||||||
|
# que no necesitamos
|
||||||
|
#
|
||||||
|
# TODO: Aplicar monkey patches en otro lado...
|
||||||
|
module Jekyll
|
||||||
|
Site.class_eval do
|
||||||
|
def setup
|
||||||
|
ensure_not_in_dest
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Reader.class_eval do
|
||||||
|
def retrieve_posts(_); end
|
||||||
|
|
||||||
|
def retrieve_dirs(_, _, _); end
|
||||||
|
|
||||||
|
def retrieve_pages(_, _); end
|
||||||
|
|
||||||
|
def retrieve_static_files(_, _); end
|
||||||
|
end
|
||||||
|
|
||||||
|
ThemeAssetsReader.class_eval do
|
||||||
|
def read; end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Prevenir la lectura del documento
|
||||||
|
Document.class_eval do
|
||||||
|
alias_method :read!, :read
|
||||||
|
def read; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -24,7 +24,7 @@ Devise.setup do |config|
|
||||||
# config.mailer = 'Devise::Mailer'
|
# config.mailer = 'Devise::Mailer'
|
||||||
|
|
||||||
# Configure the parent class responsible to send e-mails.
|
# Configure the parent class responsible to send e-mails.
|
||||||
# config.parent_mailer = 'ActionMailer::Base'
|
config.parent_mailer = 'ApplicationMailer'
|
||||||
|
|
||||||
# ==> ORM configuration
|
# ==> ORM configuration
|
||||||
# Load and configure the ORM. Supports :active_record (default) and
|
# Load and configure the ORM. Supports :active_record (default) and
|
||||||
|
@ -197,7 +197,7 @@ Devise.setup do |config|
|
||||||
# website without confirming their account.
|
# website without confirming their account.
|
||||||
# Default is 0.days, meaning the user cannot access the website
|
# Default is 0.days, meaning the user cannot access the website
|
||||||
# without confirming their account.
|
# without confirming their account.
|
||||||
# config.allow_unconfirmed_access_for = 2.days
|
config.allow_unconfirmed_access_for = 2.days
|
||||||
|
|
||||||
# A period that the user is allowed to confirm their account before
|
# A period that the user is allowed to confirm their account before
|
||||||
# their token becomes invalid. For example, if set to 3.days, the user
|
# their token becomes invalid. For example, if set to 3.days, the user
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
Rails.application.configure do
|
Rails.application.configure do
|
||||||
next if ENV['RAILS_ENV'] == 'test'
|
next unless ENV['RAILS_ENV'] == 'development'
|
||||||
|
|
||||||
domain = ENV.fetch('SUTTY', 'sutty.nl')
|
domain = ENV.fetch('SUTTY', 'sutty.nl')
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Be sure to restart your server when you modify this file.
|
Mime::Type.register 'application/csp-report', :json
|
||||||
|
|
||||||
# Add new mime types for use in respond_to blocks:
|
|
||||||
# Mime::Type.register "text/richtext", :rtf
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ en:
|
||||||
locked: Your account is locked.
|
locked: Your account is locked.
|
||||||
not_found_in_database: Invalid %{authentication_keys} or password.
|
not_found_in_database: Invalid %{authentication_keys} or password.
|
||||||
timeout: Your session expired. Please sign in again to continue.
|
timeout: Your session expired. Please sign in again to continue.
|
||||||
unauthenticated: You need to sign in or sign up before continuing.
|
unauthenticated: Hi! You need to sign in or sign up before managing your sites.
|
||||||
unconfirmed: You have to confirm your email address before continuing.
|
unconfirmed: You have to confirm your email address before continuing.
|
||||||
mailer:
|
mailer:
|
||||||
confirmation_instructions:
|
confirmation_instructions:
|
||||||
|
@ -103,6 +103,7 @@ en:
|
||||||
we_need_your_current_password_to_confirm_your_changes: We need your current password to confirm your changes
|
we_need_your_current_password_to_confirm_your_changes: We need your current password to confirm your changes
|
||||||
new:
|
new:
|
||||||
sign_up: Sign up
|
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: Welcome! You have signed up successfully.
|
||||||
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_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_locked: You have signed up successfully. However, we could not sign you in because your account is locked.
|
||||||
|
|
|
@ -16,7 +16,7 @@ es:
|
||||||
last_sign_in_ip: IP del último inicio
|
last_sign_in_ip: IP del último inicio
|
||||||
locked_at: Fecha de bloqueo
|
locked_at: Fecha de bloqueo
|
||||||
password: Contraseña
|
password: Contraseña
|
||||||
password_confirmation: Confirmación de la contraseña
|
password_confirmation: Confirma tu contraseña
|
||||||
remember_created_at: Fecha de 'Recordarme'
|
remember_created_at: Fecha de 'Recordarme'
|
||||||
remember_me: Recordarme
|
remember_me: Recordarme
|
||||||
reset_password_sent_at: Fecha de envío de código para contraseña
|
reset_password_sent_at: Fecha de envío de código para contraseña
|
||||||
|
@ -44,7 +44,7 @@ es:
|
||||||
locked: Tu cuenta está bloqueada.
|
locked: Tu cuenta está bloqueada.
|
||||||
not_found_in_database: "%{authentication_keys} o contraseña inválidos."
|
not_found_in_database: "%{authentication_keys} o contraseña inválidos."
|
||||||
timeout: Tu sesión expiró. Por favor, inicia sesión nuevamente para continuar.
|
timeout: Tu sesión expiró. Por favor, inicia sesión nuevamente para continuar.
|
||||||
unauthenticated: Tienes que iniciar sesión o registrarte para poder continuar.
|
unauthenticated: "¡Hola! Tienes que iniciar sesión o registrarte para poder gestionar tus sitios."
|
||||||
unconfirmed: Te enviamos un correo electrónico para confirmar tu cuenta, por favor acéptalo para poder continuar.
|
unconfirmed: Te enviamos un correo electrónico para confirmar tu cuenta, por favor acéptalo para poder continuar.
|
||||||
mailer:
|
mailer:
|
||||||
confirmation_instructions:
|
confirmation_instructions:
|
||||||
|
@ -80,7 +80,7 @@ es:
|
||||||
edit:
|
edit:
|
||||||
change_my_password: Cambiar mi contraseña
|
change_my_password: Cambiar mi contraseña
|
||||||
change_your_password: Cambia tu contraseña
|
change_your_password: Cambia tu contraseña
|
||||||
confirm_new_password: Confirme la nueva contraseña
|
confirm_new_password: Confirma la nueva contraseña
|
||||||
new_password: Nueva contraseña
|
new_password: Nueva contraseña
|
||||||
new:
|
new:
|
||||||
forgot_your_password: "¿Has olvidado tu contraseña?"
|
forgot_your_password: "¿Has olvidado tu contraseña?"
|
||||||
|
@ -103,7 +103,7 @@ es:
|
||||||
we_need_your_current_password_to_confirm_your_changes: Necesitamos tu contraseña actual para confirmar los cambios.
|
we_need_your_current_password_to_confirm_your_changes: Necesitamos tu contraseña actual para confirmar los cambios.
|
||||||
new:
|
new:
|
||||||
sign_up: Registrarme por primera vez
|
sign_up: Registrarme por primera vez
|
||||||
email: O simplemente continuar con tu dirección de correo y contraseña
|
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: Bienvenide. Tu cuenta fue creada.
|
||||||
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_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_locked: Tu cuenta ha sido creada correctamente. Sin embargo, no hemos podido iniciar la sesión porque que tu cuenta está bloqueada.
|
||||||
|
|
|
@ -148,7 +148,6 @@ en:
|
||||||
anexo: 'Appendix'
|
anexo: 'Appendix'
|
||||||
simple: 'Simple'
|
simple: 'Simple'
|
||||||
sites:
|
sites:
|
||||||
static_file_migration: 'File migration'
|
|
||||||
index: 'This is the list of sites you can edit.'
|
index: 'This is the list of sites you can edit.'
|
||||||
edit_translations: "You can edit texts from your site other than
|
edit_translations: "You can edit texts from your site other than
|
||||||
posts', and you can also translate them to other languages."
|
posts', and you can also translate them to other languages."
|
||||||
|
@ -247,11 +246,27 @@ en:
|
||||||
average: 'Average building time'
|
average: 'Average building time'
|
||||||
maximum: 'Maximum building time'
|
maximum: 'Maximum building time'
|
||||||
sites:
|
sites:
|
||||||
|
static_file_migration: 'File migration'
|
||||||
index:
|
index:
|
||||||
title: 'Sites'
|
title: 'Sites'
|
||||||
pull: 'Upgrade'
|
pull: 'Upgrade'
|
||||||
help: 'This is the list of sites you can edit'
|
help: 'This is the list of sites you can edit'
|
||||||
visit: 'Visitar el sitio'
|
visit: 'Visit the site'
|
||||||
|
welcome: |
|
||||||
|
# Welcome!
|
||||||
|
|
||||||
|
You have no sites yet. You can generate all the sites you want
|
||||||
|
with the **Create site** button.
|
||||||
|
|
||||||
|
Para ver los cambios, usa el botón **Publicar cambios** en cada
|
||||||
|
sitio y espera unos segundos. También recibirás un correo de
|
||||||
|
notificación.
|
||||||
|
|
||||||
|
To see your changes, use the **Publish changes** button on each
|
||||||
|
site and wait a few seconds. You'll also receive an e-mail
|
||||||
|
notification.
|
||||||
|
|
||||||
|
[Create my first site](/sites/new)
|
||||||
repository:
|
repository:
|
||||||
config: 'Changes in config'
|
config: 'Changes in config'
|
||||||
actions: 'Actions'
|
actions: 'Actions'
|
||||||
|
@ -332,6 +347,9 @@ en:
|
||||||
en: 'English'
|
en: 'English'
|
||||||
ar: 'Arabic'
|
ar: 'Arabic'
|
||||||
posts:
|
posts:
|
||||||
|
attribute_ro:
|
||||||
|
file:
|
||||||
|
download: Download file
|
||||||
show:
|
show:
|
||||||
front_matter: Post metadata
|
front_matter: Post metadata
|
||||||
submit:
|
submit:
|
||||||
|
@ -348,6 +366,11 @@ en:
|
||||||
required:
|
required:
|
||||||
label: ' (required)'
|
label: ' (required)'
|
||||||
feedback: 'This field cannot be empty!'
|
feedback: 'This field cannot be empty!'
|
||||||
|
uuid:
|
||||||
|
label: 'Unique identifier'
|
||||||
|
geo:
|
||||||
|
uri: 'Open in app'
|
||||||
|
osm: 'Open in web map'
|
||||||
reorder: 'Reorder posts'
|
reorder: 'Reorder posts'
|
||||||
sort:
|
sort:
|
||||||
by: 'Sort by'
|
by: 'Sort by'
|
||||||
|
|
|
@ -71,7 +71,7 @@ es:
|
||||||
usuarie:
|
usuarie:
|
||||||
email: 'Correo electrónico'
|
email: 'Correo electrónico'
|
||||||
password: 'Contraseña'
|
password: 'Contraseña'
|
||||||
password_confirmation: 'Confirmación de contraseña'
|
password_confirmation: 'Confirma tu contraseña'
|
||||||
current_password: 'Contraseña actual'
|
current_password: 'Contraseña actual'
|
||||||
lang: Idioma principal
|
lang: Idioma principal
|
||||||
remember_me: Recordarme
|
remember_me: Recordarme
|
||||||
|
@ -149,7 +149,6 @@ es:
|
||||||
anexo: 'Anexo'
|
anexo: 'Anexo'
|
||||||
simple: 'Simple'
|
simple: 'Simple'
|
||||||
sites:
|
sites:
|
||||||
static_file_migration: 'Migración de archivos'
|
|
||||||
index: 'Este es el listado de sitios que puedes editar.'
|
index: 'Este es el listado de sitios que puedes editar.'
|
||||||
edit_translations: 'Puedes editar los textos que salen en tu sitio
|
edit_translations: 'Puedes editar los textos que salen en tu sitio
|
||||||
que no corresponden a artículos aquí, además de traducirlos a
|
que no corresponden a artículos aquí, además de traducirlos a
|
||||||
|
@ -252,11 +251,24 @@ es:
|
||||||
average: 'Tiempo promedio de generación'
|
average: 'Tiempo promedio de generación'
|
||||||
maximum: 'Tiempo máximo de generación'
|
maximum: 'Tiempo máximo de generación'
|
||||||
sites:
|
sites:
|
||||||
|
static_file_migration: 'Migración de archivos'
|
||||||
index:
|
index:
|
||||||
title: 'Sitios'
|
title: 'Sitios'
|
||||||
pull: 'Actualizar'
|
pull: 'Actualizar'
|
||||||
help: 'Este es el listado de sitios que puedes editar'
|
help: 'Este es el listado de sitios que puedes editar'
|
||||||
visit: 'Visitar el sitio'
|
visit: 'Visitar el sitio'
|
||||||
|
welcome: |
|
||||||
|
# ¡Bienvenide!
|
||||||
|
|
||||||
|
Todavía no tienes ningún sitio. Puedes crear todos los sitios
|
||||||
|
que quieras usando el botón **Crear sitio**.
|
||||||
|
|
||||||
|
Para ver los cambios, usa el botón **Publicar cambios** en cada
|
||||||
|
sitio y espera unos segundos. También recibirás un correo de
|
||||||
|
notificación.
|
||||||
|
|
||||||
|
[Crear mi primer sitio](/sites/new)
|
||||||
|
|
||||||
repository:
|
repository:
|
||||||
config: 'Cambios en la configuración'
|
config: 'Cambios en la configuración'
|
||||||
actions: 'Acciones'
|
actions: 'Acciones'
|
||||||
|
@ -272,6 +284,7 @@ es:
|
||||||
new:
|
new:
|
||||||
title: 'Crear un sitio'
|
title: 'Crear un sitio'
|
||||||
submit: 'Crear sitio'
|
submit: 'Crear sitio'
|
||||||
|
help: 'Podrás editar estas opciones más adelante en la configuración del sitio.'
|
||||||
edit:
|
edit:
|
||||||
title: 'Editar %{site}'
|
title: 'Editar %{site}'
|
||||||
submit: 'Guardar cambios'
|
submit: 'Guardar cambios'
|
||||||
|
@ -342,6 +355,9 @@ es:
|
||||||
en: 'inglés'
|
en: 'inglés'
|
||||||
ar: 'árabe'
|
ar: 'árabe'
|
||||||
posts:
|
posts:
|
||||||
|
attribute_ro:
|
||||||
|
file:
|
||||||
|
download: Descargar archivo
|
||||||
show:
|
show:
|
||||||
front_matter: Metadatos del artículo
|
front_matter: Metadatos del artículo
|
||||||
submit:
|
submit:
|
||||||
|
@ -358,6 +374,11 @@ es:
|
||||||
required:
|
required:
|
||||||
label: ' (requerido)'
|
label: ' (requerido)'
|
||||||
feedback: '¡Este campo no puede estar vacío!'
|
feedback: '¡Este campo no puede estar vacío!'
|
||||||
|
uuid:
|
||||||
|
label: 'Identificador único'
|
||||||
|
geo:
|
||||||
|
uri: 'Abrir en aplicación'
|
||||||
|
osm: 'Abrir en mapa web'
|
||||||
reorder: 'Reordenar artículos'
|
reorder: 'Reordenar artículos'
|
||||||
sort:
|
sort:
|
||||||
by: 'Ordenar por'
|
by: 'Ordenar por'
|
||||||
|
|
|
@ -38,3 +38,22 @@ preload_app!
|
||||||
plugin :tmp_restart
|
plugin :tmp_restart
|
||||||
|
|
||||||
pidfile 'tmp/puma.pid'
|
pidfile 'tmp/puma.pid'
|
||||||
|
|
||||||
|
# If you are preloading your application and using Active Record, it's
|
||||||
|
# recommended that you close any connections to the database before workers
|
||||||
|
# are forked to prevent connection leakage.
|
||||||
|
#
|
||||||
|
before_fork do
|
||||||
|
ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord)
|
||||||
|
end
|
||||||
|
|
||||||
|
# The code in the `on_worker_boot` will be called if you are using
|
||||||
|
# clustered mode by specifying a number of `workers`. After each worker
|
||||||
|
# process is booted, this block will be run. If you are using the `preload_app!`
|
||||||
|
# option, you will want to use this block to reconnect to any threads
|
||||||
|
# or connections that may have been created at application boot, as Ruby
|
||||||
|
# cannot share connections between processes.
|
||||||
|
#
|
||||||
|
on_worker_boot do
|
||||||
|
ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
|
||||||
|
end
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
Rails.application.routes.draw do
|
Rails.application.routes.draw do
|
||||||
devise_for :usuaries
|
devise_for :usuaries
|
||||||
|
mount Blazer::Engine, at: 'blazer'
|
||||||
|
|
||||||
root 'application#index'
|
root 'application#index'
|
||||||
|
|
||||||
|
@ -18,6 +19,7 @@ Rails.application.routes.draw do
|
||||||
constraints subdomain: 'api' do
|
constraints subdomain: 'api' do
|
||||||
scope module: 'api' do
|
scope module: 'api' do
|
||||||
namespace :v1 do
|
namespace :v1 do
|
||||||
|
resources :csp_reports, only: %i[create]
|
||||||
get 'sites/allowed', to: 'sites#allowed'
|
get 'sites/allowed', to: 'sites#allowed'
|
||||||
resources :sites, only: %i[index]
|
resources :sites, only: %i[index]
|
||||||
end
|
end
|
||||||
|
|
|
@ -57,10 +57,10 @@ development:
|
||||||
|
|
||||||
# Reference: https://webpack.js.org/configuration/dev-server/
|
# Reference: https://webpack.js.org/configuration/dev-server/
|
||||||
dev_server:
|
dev_server:
|
||||||
https: false
|
https: true
|
||||||
host: localhost
|
host: <%= ENV.fetch('SUTTY', 'localhost') %>
|
||||||
port: 3035
|
port: 3035
|
||||||
public: localhost:3035
|
public: <%= ENV.fetch('SUTTY', 'localhost') %>:3035
|
||||||
hmr: false
|
hmr: false
|
||||||
# Inline should be set to true if using HMR
|
# Inline should be set to true if using HMR
|
||||||
inline: true
|
inline: true
|
||||||
|
|
65
db/migrate/20200118155319_create_access_log.rb
Normal file
65
db/migrate/20200118155319_create_access_log.rb
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class CreateAccessLog < ActiveRecord::Migration[6.0]
|
||||||
|
def change
|
||||||
|
create_table :access_logs, id: :uuid do |t|
|
||||||
|
t.string :host, index: true
|
||||||
|
|
||||||
|
t.float :msec
|
||||||
|
|
||||||
|
t.string :server_protocol
|
||||||
|
t.string :request_method
|
||||||
|
t.string :request_completion
|
||||||
|
|
||||||
|
t.string :uri, index: true
|
||||||
|
t.string :query_string
|
||||||
|
t.integer :status, index: true
|
||||||
|
|
||||||
|
t.string :sent_http_content_type
|
||||||
|
t.string :sent_http_content_encoding
|
||||||
|
t.string :sent_http_etag
|
||||||
|
t.datetime :sent_http_last_modified
|
||||||
|
|
||||||
|
t.string :http_accept
|
||||||
|
t.string :http_accept_encoding
|
||||||
|
t.string :http_accept_language
|
||||||
|
|
||||||
|
t.string :http_pragma
|
||||||
|
t.string :http_cache_control
|
||||||
|
t.string :http_if_none_match
|
||||||
|
|
||||||
|
t.string :http_dnt
|
||||||
|
t.string :http_user_agent, index: true
|
||||||
|
t.string :http_referer, index: true
|
||||||
|
|
||||||
|
t.float :request_time
|
||||||
|
|
||||||
|
t.integer :bytes_sent
|
||||||
|
t.integer :body_bytes_sent
|
||||||
|
t.integer :request_length
|
||||||
|
|
||||||
|
t.string :http_connection
|
||||||
|
t.string :pipe
|
||||||
|
t.integer :connection_requests
|
||||||
|
|
||||||
|
t.string :geoip2_data_country_name, index: true
|
||||||
|
t.string :geoip2_data_city_name, index: true
|
||||||
|
|
||||||
|
t.string :ssl_server_name
|
||||||
|
t.string :ssl_protocol
|
||||||
|
t.string :ssl_early_data
|
||||||
|
t.string :ssl_session_reused
|
||||||
|
t.string :ssl_curves
|
||||||
|
t.string :ssl_ciphers
|
||||||
|
t.string :ssl_cipher
|
||||||
|
|
||||||
|
t.string :sent_http_x_xss_protection
|
||||||
|
t.string :sent_http_x_frame_options
|
||||||
|
t.string :sent_http_x_content_type_options
|
||||||
|
t.string :sent_http_strict_transport_security
|
||||||
|
|
||||||
|
t.string :nginx_version
|
||||||
|
t.integer :pid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
7
db/migrate/20200126175158_change_last_modified.rb
Normal file
7
db/migrate/20200126175158_change_last_modified.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ChangeLastModified < ActiveRecord::Migration[6.0]
|
||||||
|
def change
|
||||||
|
change_column :access_logs, :sent_http_last_modified, :string
|
||||||
|
end
|
||||||
|
end
|
17
db/migrate/20200205173039_create_csp_reports.rb
Normal file
17
db/migrate/20200205173039_create_csp_reports.rb
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
class CreateCspReports < ActiveRecord::Migration[6.0]
|
||||||
|
def change
|
||||||
|
create_table :csp_reports, id: :uuid do |t|
|
||||||
|
t.timestamps
|
||||||
|
|
||||||
|
t.string :disposition
|
||||||
|
t.string :referrer
|
||||||
|
t.string :blocked_uri
|
||||||
|
t.string :document_uri
|
||||||
|
t.string :effective_directive
|
||||||
|
t.string :original_policy
|
||||||
|
t.string :script_sample
|
||||||
|
t.string :status_code
|
||||||
|
t.string :violated_directive
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
7
db/migrate/20200206151057_add_source_to_csp_reports.rb
Normal file
7
db/migrate/20200206151057_add_source_to_csp_reports.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
class AddSourceToCspReports < ActiveRecord::Migration[6.0]
|
||||||
|
def change
|
||||||
|
add_column :csp_reports, :column_number, :integer
|
||||||
|
add_column :csp_reports, :line_number, :integer
|
||||||
|
add_column :csp_reports, :source_file, :string
|
||||||
|
end
|
||||||
|
end
|
51
db/migrate/20200206163257_install_blazer.rb
Normal file
51
db/migrate/20200206163257_install_blazer.rb
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Blazer
|
||||||
|
class InstallBlazer < ActiveRecord::Migration[6.0]
|
||||||
|
def change
|
||||||
|
return unless Rails.env.production?
|
||||||
|
|
||||||
|
create_table :blazer_queries do |t|
|
||||||
|
t.references :creator
|
||||||
|
t.string :name
|
||||||
|
t.text :description
|
||||||
|
t.text :statement
|
||||||
|
t.string :data_source
|
||||||
|
t.timestamps null: false
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table :blazer_audits do |t|
|
||||||
|
t.references :user
|
||||||
|
t.references :query
|
||||||
|
t.text :statement
|
||||||
|
t.string :data_source
|
||||||
|
t.timestamp :created_at
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table :blazer_dashboards do |t|
|
||||||
|
t.references :creator
|
||||||
|
t.text :name
|
||||||
|
t.timestamps null: false
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table :blazer_dashboard_queries do |t|
|
||||||
|
t.references :dashboard
|
||||||
|
t.references :query
|
||||||
|
t.integer :position
|
||||||
|
t.timestamps null: false
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table :blazer_checks do |t|
|
||||||
|
t.references :creator
|
||||||
|
t.references :query
|
||||||
|
t.string :state
|
||||||
|
t.string :schedule
|
||||||
|
t.text :emails
|
||||||
|
t.text :slack_channels
|
||||||
|
t.string :check_type
|
||||||
|
t.text :message
|
||||||
|
t.timestamp :last_run_at
|
||||||
|
t.timestamps null: false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -12,7 +12,10 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20_190_829_180_743) do
|
ActiveRecord::Schema.define(version: 20_200_206_151_057) do
|
||||||
|
# Could not dump table "access_logs" because of following StandardError
|
||||||
|
# Unknown type '' for column 'id'
|
||||||
|
|
||||||
create_table 'action_text_rich_texts', force: :cascade do |t|
|
create_table 'action_text_rich_texts', force: :cascade do |t|
|
||||||
t.string 'name', null: false
|
t.string 'name', null: false
|
||||||
t.text 'body'
|
t.text 'body'
|
||||||
|
@ -55,6 +58,9 @@ ActiveRecord::Schema.define(version: 20_190_829_180_743) do
|
||||||
t.index ['deploy_id'], name: 'index_build_stats_on_deploy_id'
|
t.index ['deploy_id'], name: 'index_build_stats_on_deploy_id'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Could not dump table "csp_reports" because of following StandardError
|
||||||
|
# Unknown type 'uuid' for column 'id'
|
||||||
|
|
||||||
create_table 'deploys', force: :cascade do |t|
|
create_table 'deploys', force: :cascade do |t|
|
||||||
t.datetime 'created_at', null: false
|
t.datetime 'created_at', null: false
|
||||||
t.datetime 'updated_at', null: false
|
t.datetime 'updated_at', null: false
|
||||||
|
@ -132,6 +138,7 @@ ActiveRecord::Schema.define(version: 20_190_829_180_743) do
|
||||||
t.string 'status', default: 'waiting'
|
t.string 'status', default: 'waiting'
|
||||||
t.text 'description'
|
t.text 'description'
|
||||||
t.string 'title'
|
t.string 'title'
|
||||||
|
t.boolean 'colaboracion_anonima', default: false
|
||||||
t.index ['design_id'], name: 'index_sites_on_design_id'
|
t.index ['design_id'], name: 'index_sites_on_design_id'
|
||||||
t.index ['licencia_id'], name: 'index_sites_on_licencia_id'
|
t.index ['licencia_id'], name: 'index_sites_on_licencia_id'
|
||||||
t.index ['name'], name: 'index_sites_on_name', unique: true
|
t.index ['name'], name: 'index_sites_on_name', unique: true
|
||||||
|
|
|
@ -4,15 +4,15 @@
|
||||||
gem: 'sutty-theme-none'
|
gem: 'sutty-theme-none'
|
||||||
url: 'https://sutty.nl'
|
url: 'https://sutty.nl'
|
||||||
disabled: true
|
disabled: true
|
||||||
description_en: "Upload your own theme. [This feature is in development, help us!](https://sutty.neocities.org/en/#contact)"
|
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.neocities.org/es/#contacto)"
|
description_es: "Subir tu propio diseño. [Esta posibilidad está en desarrollo, ¡ayudanos!](https://sutty.nl/#contacto)"
|
||||||
- name_en: 'I want you to create a site for me'
|
- name_en: 'I want you to create a site for me'
|
||||||
name_es: 'Quiero que desarrollen mi sitio'
|
name_es: 'Quiero que desarrollen mi sitio'
|
||||||
gem: 'sutty-theme-custom'
|
gem: 'sutty-theme-custom'
|
||||||
url: 'https://sutty.nl'
|
url: 'https://sutty.nl'
|
||||||
disabled: true
|
disabled: true
|
||||||
description_en: "If you want us to create your site, you're welcome to [contact us!](https://sutty.neocities.org/en/#contact) :)"
|
description_en: "If you want us to create 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.neocities.org/es/#contacto) :)"
|
description_es: "Si querés que desarrollemos tu sitio, [escribinos](https://sutty.nl/#contacto) :)"
|
||||||
- name_en: 'Minima'
|
- name_en: 'Minima'
|
||||||
name_es: 'Mínima'
|
name_es: 'Mínima'
|
||||||
gem: 'minima'
|
gem: 'minima'
|
||||||
|
@ -25,5 +25,5 @@
|
||||||
gem: 'sutty-theme-own'
|
gem: 'sutty-theme-own'
|
||||||
url: 'https://jekyllthemes.org'
|
url: 'https://jekyllthemes.org'
|
||||||
disabled: true
|
disabled: true
|
||||||
description_en: "We're working to add more themes for you to use. [Contact us!](https://sutty.neocities.org/en/#contact)"
|
description_en: "We're working to add 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.neocities.org/es/#contacto)"
|
description_es: "Estamos trabajando para que puedas tener más diseños. [¡Escribinos!](https://sutty.nl/#contacto)"
|
||||||
|
|
|
@ -17,3 +17,4 @@
|
||||||
- name: mail
|
- name: mail
|
||||||
- name: email
|
- name: email
|
||||||
- name: xmpp
|
- name: xmpp
|
||||||
|
- name: radicale
|
||||||
|
|
|
@ -23,3 +23,11 @@ otra vez.
|
||||||
|
|
||||||
Lo más controlado sería enviar exactamente el id del post con su nueva
|
Lo más controlado sería enviar exactamente el id del post con su nueva
|
||||||
ubicación en el orden. Esta es la implementación anterior.
|
ubicación en el orden. Esta es la implementación anterior.
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
El orden es descendiente (fechas más nuevas primero), pero el orden que
|
||||||
|
estuvimos usando es ascendientes (números más bajos primero). Es más
|
||||||
|
simple invertir la lógica y hacer todo el orden descendiente. Para eso
|
||||||
|
los artículos más nuevos tienen que tener el número de orden
|
||||||
|
correspondiente a la posición en el array ordenado por fecha.
|
||||||
|
|
28
doc/uuid.md
Normal file
28
doc/uuid.md
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# Identificadores para los artículos
|
||||||
|
|
||||||
|
Para poder vincular artículos entre sí y para otros usos, necesitamos
|
||||||
|
identificarlos únicamente. Un identificador incremental es problemático
|
||||||
|
porque tendríamos que mantener el estado y poder responder preguntas
|
||||||
|
como ¿cuál es el último identificador que asignamos?
|
||||||
|
|
||||||
|
Para poder identificar artículos sin mantener estado, usamos
|
||||||
|
[UUIDs](https://en.wikipedia.org/wiki/Universally_unique_identifier),
|
||||||
|
que son cadenas aleatorias que se pueden asignar adhoc. Así, en lugar
|
||||||
|
de un ID numérico que va incrementando, podemos asociar cadenas al
|
||||||
|
estilo `fb4a5048-5fa1-4b85-b70e-6c502feecdb9` (generada con la
|
||||||
|
herramienta `uuidgen`).
|
||||||
|
|
||||||
|
## MetadataUUID
|
||||||
|
|
||||||
|
Cada artículo se crea con un metadato `uuid` cuyo valor por defecto es
|
||||||
|
un UUID autogenerado utilizando `SecureRandom.uuid`. Este valor no
|
||||||
|
cambia (a menos que se lo vacíe intencionalmente).
|
||||||
|
|
||||||
|
## Migración
|
||||||
|
|
||||||
|
Para todos los artículos que existen, hay que escribir una migración que
|
||||||
|
se los agregue.
|
||||||
|
|
||||||
|
Para esto hay que cargar sitio por sitio, recorrer los artículos
|
||||||
|
asignando un UUID y guardando todos los cambios como un solo commit de
|
||||||
|
git.
|
|
@ -1,5 +1,6 @@
|
||||||
check process sutty with pidfile /srv/http/tmp/puma.pid
|
check process sutty with pidfile /srv/http/tmp/puma.pid
|
||||||
start program = "/bin/sh -c 'cd /srv/http && foreman start migrate && foreman start sutty'" as uid app
|
start program = "/bin/sh -c 'cd /srv/http && foreman start migrate && foreman start sutty'"
|
||||||
|
as uid "app" and gid "www-data"
|
||||||
stop program = "/bin/sh -c 'cat /srv/http/tmp/puma.pid | xargs kill'"
|
stop program = "/bin/sh -c 'cat /srv/http/tmp/puma.pid | xargs kill'"
|
||||||
|
|
||||||
check program sync_assets
|
check program sync_assets
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
"@rails/activestorage": "^6.0.0",
|
"@rails/activestorage": "^6.0.0",
|
||||||
"@rails/webpacker": "^4.0.7",
|
"@rails/webpacker": "^4.0.7",
|
||||||
"commonmark": "^0.29.0",
|
"commonmark": "^0.29.0",
|
||||||
|
"input-map": "https://0xacab.org/sutty/input-map.git",
|
||||||
"input-tag": "https://0xacab.org/sutty/input-tag.git",
|
"input-tag": "https://0xacab.org/sutty/input-tag.git",
|
||||||
"prosemirror-commands": "^1.0.8",
|
"prosemirror-commands": "^1.0.8",
|
||||||
"prosemirror-gapcursor": "^1.0.4",
|
"prosemirror-gapcursor": "^1.0.4",
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue