This commit is contained in:
f 2019-03-26 12:32:20 -03:00
parent 617619a493
commit fa90f7c21f
No known key found for this signature in database
GPG key ID: 2AE5A13E321F953D
76 changed files with 604 additions and 288 deletions

178
.rubocop_todo.yml Normal file
View file

@ -0,0 +1,178 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2019-03-26 12:32:08 -0300 using RuboCop version 0.66.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyleAlignWith, AutoCorrect, Severity.
# SupportedStylesAlignWith: keyword, variable, start_of_line
Layout/EndAlignment:
Exclude:
- 'app/models/post/image_uploader.rb'
# Offense count: 1
# Configuration parameters: AllowSafeAssignment.
Lint/AssignmentInCondition:
Exclude:
- 'app/controllers/invitadxs_controller.rb'
# Offense count: 4
Lint/DuplicateMethods:
Exclude:
- 'app/models/post.rb'
- 'app/models/site.rb'
# Offense count: 1
Lint/HandleExceptions:
Exclude:
- 'app/controllers/posts_controller.rb'
# Offense count: 1
Lint/NonLocalExitFromIterator:
Exclude:
- 'app/models/invitadx.rb'
# Offense count: 1
Lint/ShadowingOuterLocalVariable:
Exclude:
- 'app/models/post.rb'
# Offense count: 3
Lint/UnderscorePrefixedVariableName:
Exclude:
- 'app/models/post.rb'
- 'app/models/post/template_field.rb'
- 'app/models/site.rb'
# Offense count: 2
Lint/UselessAssignment:
Exclude:
- 'app/models/invitadx.rb'
- 'app/models/site.rb'
# Offense count: 19
Metrics/AbcSize:
Max: 58
# Offense count: 3
# Configuration parameters: CountComments, ExcludedMethods.
# ExcludedMethods: refine
Metrics/BlockLength:
Max: 31
# Offense count: 3
# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 379
# Offense count: 6
Metrics/CyclomaticComplexity:
Max: 18
# Offense count: 15
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/MethodLength:
Max: 34
# Offense count: 5
Metrics/PerceivedComplexity:
Max: 20
# Offense count: 1
# Configuration parameters: EnforcedStyleForLeadingUnderscores.
# SupportedStylesForLeadingUnderscores: disallowed, required, optional
Naming/MemoizedInstanceVariableName:
Exclude:
- 'app/models/post/image_uploader.rb'
# Offense count: 1
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist, MethodDefinitionMacros.
# NamePrefix: is_, has_, have_
# NamePrefixBlacklist: is_, has_, have_
# NameWhitelist: is_a?
# MethodDefinitionMacros: define_method, define_singleton_method
Naming/PredicateName:
Exclude:
- 'spec/**/*'
- 'app/models/post.rb'
# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect.
Performance/TimesMap:
Exclude:
- 'app/models/site.rb'
- 'test/models/site_test.rb'
# Offense count: 102
# Configuration parameters: AllowedChars.
Style/AsciiComments:
Exclude:
- 'app/controllers/application_controller.rb'
- 'app/controllers/i18n_controller.rb'
- 'app/controllers/posts_controller.rb'
- 'app/controllers/sites_controller.rb'
- 'app/models/invitadx.rb'
- 'app/models/jekyll_i18n.rb'
- 'app/models/post.rb'
- 'app/models/post/image_uploader.rb'
- 'app/models/post/template_field.rb'
- 'app/models/site.rb'
- 'app/models/usuaria.rb'
- 'app/policies/post_policy.rb'
- 'config/routes.rb'
- 'lib/warden/imap.rb'
# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle.
# SupportedStyles: nested, compact
Style/ClassAndModuleChildren:
Exclude:
- 'app/models/post/image_uploader.rb'
- 'config/initializers/commonmarker.rb'
- 'config/initializers/warden.rb'
- 'test/test_helper.rb'
# Offense count: 25
Style/Documentation:
Enabled: false
# Offense count: 5
# Configuration parameters: MinBodyLength.
Style/GuardClause:
Exclude:
- 'app/controllers/posts_controller.rb'
- 'app/models/invitadx.rb'
- 'app/models/post.rb'
- 'lib/warden/email_and_password.rb'
# Offense count: 7
# Cop supports --auto-correct.
Style/IfUnlessModifier:
Exclude:
- 'app/models/invitadx.rb'
- 'app/models/jekyll_i18n.rb'
- 'app/models/post.rb'
- 'bin/bundle'
# Offense count: 2
Style/MixinUsage:
Exclude:
- 'bin/setup'
- 'bin/update'
# Offense count: 1
Style/OptionalArguments:
Exclude:
- 'app/models/site.rb'
# Offense count: 66
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
Max: 190

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
# Load DSL and Setup Up Stages # Load DSL and Setup Up Stages
require 'capistrano/setup' require 'capistrano/setup'

29
Gemfile
View file

@ -1,7 +1,9 @@
# frozen_string_literal: true
source 'https://rubygems.org' source 'https://rubygems.org'
git_source(:github) do |repo_name| git_source(:github) do |repo_name|
repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?('/')
"https://github.com/#{repo_name}.git" "https://github.com/#{repo_name}.git"
end end
@ -30,21 +32,21 @@ gem 'bcrypt', '~> 3.1.7'
# Use Capistrano for deployment # Use Capistrano for deployment
# gem 'capistrano-rails', group: :development # gem 'capistrano-rails', group: :development
gem 'bootstrap', '~> 4.0.0'
gem 'carrierwave'
gem 'carrierwave-bombshelter'
gem 'carrierwave-i18n'
gem 'commonmarker' gem 'commonmarker'
gem 'email_address' gem 'email_address'
gem 'rails_warden' gem 'exception_notification'
gem 'font-awesome-rails'
gem 'haml-rails' gem 'haml-rails'
gem 'bootstrap', '~> 4.0.0'
gem 'jekyll' gem 'jekyll'
gem 'jquery-rails' gem 'jquery-rails'
gem 'font-awesome-rails'
gem 'exception_notification'
gem 'whenever', require: false
gem 'carrierwave'
gem 'carrierwave-i18n'
gem 'mini_magick' gem 'mini_magick'
gem 'carrierwave-bombshelter'
gem 'pundit' gem 'pundit'
gem 'rails_warden'
gem 'whenever', require: false
group :development, :test do group :development, :test do
gem 'pry' gem 'pry'
@ -55,17 +57,18 @@ end
group :development do group :development do
# Access an IRB console on exception pages or by using <%= console %> anywhere in the code. # Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
gem 'web-console', '>= 3.3.0'
gem 'listen', '>= 3.0.5', '< 3.2' 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 # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
gem 'bcrypt_pbkdf' gem 'bcrypt_pbkdf'
gem 'capistrano' gem 'capistrano'
gem 'capistrano-bundler' gem 'capistrano-bundler'
gem 'capistrano-passenger' gem 'capistrano-passenger'
gem 'capistrano-rails' gem 'capistrano-rails'
gem 'capistrano-rbenv' gem 'capistrano-rbenv'
gem 'rbnacl', '< 5.0'
gem 'letter_opener' gem 'letter_opener'
gem 'rbnacl', '< 5.0'
gem 'rubocop'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
end end

View file

@ -43,6 +43,7 @@ GEM
airbrussh (1.3.1) airbrussh (1.3.1)
sshkit (>= 1.6.1, != 1.7.0) sshkit (>= 1.6.1, != 1.7.0)
arel (8.0.0) arel (8.0.0)
ast (2.4.0)
autoprefixer-rails (9.5.0) autoprefixer-rails (9.5.0)
execjs execjs
bcrypt (3.1.12) bcrypt (3.1.12)
@ -134,6 +135,7 @@ GEM
http_parser.rb (0.6.0) http_parser.rb (0.6.0)
i18n (0.9.5) i18n (0.9.5)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
jaro_winkler (1.5.2)
jbuilder (2.8.0) jbuilder (2.8.0)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
multi_json (>= 1.2) multi_json (>= 1.2)
@ -190,12 +192,16 @@ GEM
nio4r (2.3.1) nio4r (2.3.1)
nokogiri (1.10.2) nokogiri (1.10.2)
mini_portile2 (~> 2.4.0) mini_portile2 (~> 2.4.0)
parallel (1.15.0)
parser (2.6.2.0)
ast (~> 2.4.0)
pathutil (0.16.2) pathutil (0.16.2)
forwardable-extended (~> 2.6) forwardable-extended (~> 2.6)
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)
psych (3.1.0)
public_suffix (3.0.3) public_suffix (3.0.3)
puma (3.12.1) puma (3.12.1)
pundit (2.0.1) pundit (2.0.1)
@ -228,6 +234,7 @@ GEM
method_source method_source
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rainbow (3.0.0)
rake (12.3.2) rake (12.3.2)
rb-fsevent (0.10.3) rb-fsevent (0.10.3)
rb-inotify (0.10.0) rb-inotify (0.10.0)
@ -235,8 +242,17 @@ GEM
rbnacl (4.0.2) rbnacl (4.0.2)
ffi ffi
rouge (3.3.0) rouge (3.3.0)
rubocop (0.66.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.5, != 2.5.1.1)
psych (>= 3.1.0)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 1.6)
ruby-enum (0.7.2) ruby-enum (0.7.2)
i18n i18n
ruby-progressbar (1.10.0)
ruby_dep (1.5.0) ruby_dep (1.5.0)
ruby_parser (3.13.0) ruby_parser (3.13.0)
sexp_processor (~> 4.9) sexp_processor (~> 4.9)
@ -289,6 +305,7 @@ GEM
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.5) unf_ext (0.0.7.5)
unicode-display_width (1.5.0)
warden (1.2.8) warden (1.2.8)
rack (>= 2.0.6) rack (>= 2.0.6)
web-console (3.7.0) web-console (3.7.0)
@ -338,6 +355,7 @@ DEPENDENCIES
rails (~> 5.1.4) rails (~> 5.1.4)
rails_warden rails_warden
rbnacl (< 5.0) rbnacl (< 5.0)
rubocop
sass-rails (~> 5.0) sass-rails (~> 5.0)
selenium-webdriver selenium-webdriver
spring spring

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# Add your own tasks in files placed in lib/tasks ending in .rake, # Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# Forma de ingreso a Sutty # Forma de ingreso a Sutty
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
protect_from_forgery with: :exception protect_from_forgery with: :exception
@ -9,8 +11,7 @@ class ApplicationController < ActionController::Base
redirect_to sites_path redirect_to sites_path
end end
def markdown def markdown; end
end
private private

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class I18nController < ApplicationController class I18nController < ApplicationController
include Pundit include Pundit
before_action :authenticate! before_action :authenticate!
@ -15,7 +17,7 @@ class I18nController < ApplicationController
@lang_from = params.fetch(:from, I18n.locale.to_s) @lang_from = params.fetch(:from, I18n.locale.to_s)
@lang_to = params.fetch(:to, @lang_from) @lang_to = params.fetch(:to, @lang_from)
@options = I18n.available_locales.map do |lang| @options = I18n.available_locales.map do |lang|
[ t("i18n.#{lang.to_s}"), lang.to_s ] [t("i18n.#{lang}"), lang.to_s]
end end
end end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class InvitadxsController < ApplicationController class InvitadxsController < ApplicationController
include Pundit include Pundit
@ -53,6 +55,6 @@ class InvitadxsController < ApplicationController
def invitadx_params def invitadx_params
params.require(:invitadx).permit(:email, :password, params.require(:invitadx).permit(:email, :password,
:password_confirmation, :acepta_politicas_de_privacidad) :password_confirmation, :acepta_politicas_de_privacidad)
end end
end end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class LoginController < ApplicationController class LoginController < ApplicationController
protect_from_forgery with: :exception protect_from_forgery with: :exception
@ -15,7 +17,7 @@ class LoginController < ApplicationController
def create def create
authenticate authenticate
session[:lang] = params[:lang] session[:lang] = params[:lang]
referer = request.referer unless /\/login/ =~ request.referer referer = request.referer unless %r{/login} =~ request.referer
referer = params[:referer] if params[:referer].present? referer = params[:referer] if params[:referer].present?
if authenticated? if authenticated?

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class PostsController < ApplicationController class PostsController < ApplicationController
include Pundit include Pundit
before_action :authenticate! before_action :authenticate!
@ -32,9 +34,9 @@ class PostsController < ApplicationController
@lang = find_lang(@site) @lang = find_lang(@site)
@template = find_template(@site) @template = find_template(@site)
@post = Post.new(site: @site, @post = Post.new(site: @site,
front_matter: { date: Time.now }, front_matter: { date: Time.now },
lang: @lang, lang: @lang,
template: @template) template: @template)
end end
def create def create
@ -47,17 +49,17 @@ class PostsController < ApplicationController
# El post se guarda como incompleto si se envió con "guardar para # El post se guarda como incompleto si se envió con "guardar para
# después" # después"
@post.update_attributes({incomplete: params[:commit_incomplete].present?}) @post.update_attributes(incomplete: params[:commit_incomplete].present?)
# Las usuarias pueden especificar una autora, de la contrario por # Las usuarias pueden especificar una autora, de la contrario por
# defecto es la usuaria actual # defecto es la usuaria actual
if current_user.is_a? Usuaria if current_user.is_a? Usuaria
@post.update_attributes({author: params[:post][:author]}) @post.update_attributes(author: params[:post][:author])
else else
# Todo lo que crean lxs invitadxs es borrador # Todo lo que crean lxs invitadxs es borrador
@post.update_attributes({draft: true}) @post.update_attributes(draft: true)
end end
@post.update_attributes({author: current_user.username}) unless @post.author @post.update_attributes(author: current_user.username) unless @post.author
if @post.save if @post.save
flash[:success] = @site.config.dig('thanks') flash[:success] = @site.config.dig('thanks')
@ -87,11 +89,11 @@ class PostsController < ApplicationController
# Solo las usuarias pueden modificar la autoría # Solo las usuarias pueden modificar la autoría
if current_user.is_a? Usuaria if current_user.is_a? Usuaria
@post.update_attributes({author: params[:post][:author]}) if params[:post][:author].present? @post.update_attributes(author: params[:post][:author]) if params[:post][:author].present?
@post.update_attributes({draft: false}) @post.update_attributes(draft: false)
else else
# Todo lo que crean lxs invitadxs es borrador # Todo lo que crean lxs invitadxs es borrador
@post.update_attributes({draft: true}) @post.update_attributes(draft: true)
end end
if @post.save if @post.save
@ -114,11 +116,11 @@ class PostsController < ApplicationController
obj.each do |key, value| obj.each do |key, value|
if value.is_a?(ActionController::Parameters) || value.is_a?(Hash) if value.is_a?(ActionController::Parameters) || value.is_a?(Hash)
# If any non-integer keys # If any non-integer keys
if value.keys.find {|k, _| k =~ /\D/ } if value.keys.find { |k, _| k =~ /\D/ }
repair_nested_params(value) repair_nested_params(value)
else else
obj[key] = value.values obj[key] = value.values
obj[key].each {|h| repair_nested_params(h) } obj[key].each { |h| repair_nested_params(h) }
end end
end end
end end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# Controlador de sitios # Controlador de sitios
class SitesController < ApplicationController class SitesController < ApplicationController
include Pundit include Pundit
@ -25,7 +27,7 @@ class SitesController < ApplicationController
file = [params[:basename], params[:format]].join('.') file = [params[:basename], params[:format]].join('.')
path = Pathname.new(File.join(@site.path, 'public', params[:type], file)) path = Pathname.new(File.join(@site.path, 'public', params[:type], file))
# TODO Verificar que no nos estén sacando archivos del sistema, como # TODO: Verificar que no nos estén sacando archivos del sistema, como
# /etc/passwd # /etc/passwd
# #
# En sí el matcher de la ruta no admite .. así que estaríamos semi # En sí el matcher de la ruta no admite .. así que estaríamos semi
@ -50,10 +52,10 @@ class SitesController < ApplicationController
@site = find_site @site = find_site
authorize @site authorize @site
# TODO eliminar ANSI # TODO: eliminar ANSI
render file: @site.build_log, render file: @site.build_log,
layout: false, layout: false,
content_type: 'text/plain; charset=utf-8' content_type: 'text/plain; charset=utf-8'
end end
def reorder_posts def reorder_posts
@ -61,11 +63,11 @@ class SitesController < ApplicationController
authorize @site authorize @site
lang = params.require(:posts).require(:lang) lang = params.require(:posts).require(:lang)
if params[:posts][:force].present? result = if params[:posts][:force].present?
result = @site.reorder_collection! lang @site.reorder_collection! lang
else else
result = @site.reorder_collection(lang, params.require(:posts).require(:order)) @site.reorder_collection(lang, params.require(:posts).require(:order))
end end
if result if result
flash[:info] = I18n.t('info.posts.reorder') flash[:info] = I18n.t('info.posts.reorder')

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
module ApplicationHelper module ApplicationHelper
# Devuelve el atributo name de un campo posiblemente anidado # Devuelve el atributo name de un campo posiblemente anidado
def field_name_for_post(names) def field_name_for_post(names)

View file

@ -1,2 +1,4 @@
# frozen_string_literal: true
class ApplicationJob < ActiveJob::Base class ApplicationJob < ActiveJob::Base
end end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class ApplicationMailer < ActionMailer::Base class ApplicationMailer < ActionMailer::Base
default from: 'from@example.com' default from: 'from@example.com'
layout 'mailer' layout 'mailer'

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class InvitadxMailer < ApplicationMailer class InvitadxMailer < ApplicationMailer
def confirmation_required def confirmation_required
@invitadx = params[:invitadx] @invitadx = params[:invitadx]

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class ApplicationRecord < ActiveRecord::Base class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true self.abstract_class = true
end end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class Invitadx < ApplicationRecord class Invitadx < ApplicationRecord
has_secure_password has_secure_password
validates_uniqueness_of :email validates_uniqueness_of :email
@ -15,9 +17,10 @@ class Invitadx < ApplicationRecord
File.join(Rails.root, '_invitadxs', email) File.join(Rails.root, '_invitadxs', email)
end end
# TODO convertir el Pathname en un helper # TODO: convertir el Pathname en un helper
def site_dirs def site_dirs
return [] unless Dir.exists? path return [] unless Dir.exist? path
Pathname.new(path).children.map(&:expand_path).map(&:to_s) Pathname.new(path).children.map(&:expand_path).map(&:to_s)
end end
@ -32,7 +35,7 @@ class Invitadx < ApplicationRecord
def acepto_politicas_de_privacidad def acepto_politicas_de_privacidad
unless acepta_politicas_de_privacidad? unless acepta_politicas_de_privacidad?
errors.add(:acepta_politicas_de_privacidad, errors.add(:acepta_politicas_de_privacidad,
:no_acepta_politicas_de_privacidad) :no_acepta_politicas_de_privacidad)
end end
end end
@ -47,11 +50,11 @@ class Invitadx < ApplicationRecord
dir = File.join(path, site.name) dir = File.join(path, site.name)
file = site.invitadxs_file file = site.invitadxs_file
unless File.exists? dir unless File.exist? dir
FileUtils.ln_s File.join('..', '..', '_sites', site.name), dir FileUtils.ln_s File.join('..', '..', '_sites', site.name), dir
end end
if File.exists? file if File.exist? file
invitadxs = File.read(file).split("\n") invitadxs = File.read(file).split("\n")
invitadxs_orig = invitadxs.dup invitadxs_orig = invitadxs.dup
invitadxs << email unless invitadxs.include? email invitadxs << email unless invitadxs.include? email
@ -78,7 +81,6 @@ class Invitadx < ApplicationRecord
f.flush f.flush
f.truncate(f.pos) f.truncate(f.pos)
end end
end end
end end
end end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# Esta clase se encarga de guardan los archivos YAML de idiomas # Esta clase se encarga de guardan los archivos YAML de idiomas
# #
# TODO se podría convertir en una clase genérica de editor de YAML # TODO se podría convertir en una clase genérica de editor de YAML
@ -45,7 +47,7 @@ class JekyllI18n
# Obtiene la ruta a partir del sitio y el idioma # Obtiene la ruta a partir del sitio y el idioma
def path def path
File.join(@site.path, '_data', "#{@lang.to_s}.yml") File.join(@site.path, '_data', "#{@lang}.yml")
end end
def exist? def exist?
@ -79,6 +81,7 @@ class JekyllI18n
end end
return true if r.zero? return true if r.zero?
false false
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'jekyll/utils' 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
@ -16,7 +17,7 @@ require 'jekyll/utils'
class Post class Post
attr_accessor :content, :front_matter attr_accessor :content, :front_matter
attr_reader :post, :site, :errors, :old_post, :lang, :template, attr_reader :post, :site, :errors, :old_post, :lang, :template,
:template_fields :template_fields
REJECT_FROM_DATA = %w[excerpt].freeze REJECT_FROM_DATA = %w[excerpt].freeze
# datos que no tienen que terminar en el front matter # datos que no tienen que terminar en el front matter
@ -24,8 +25,8 @@ class Post
# datos que no traemos del template # datos que no traemos del template
REJECT_FROM_TEMPLATE = %w[draft categories layout title ext tags date slug post pre].freeze REJECT_FROM_TEMPLATE = %w[draft categories layout title ext tags date slug post pre].freeze
DEFAULT_PARAMS = [:title, :date, :content, :slug, :cover, DEFAULT_PARAMS = [:title, :date, :content, :slug, :cover,
:layout, :permalink, :dir, :layout, :permalink, :dir,
{ lang: {} }, { tags: [] }, { categories: [] }] { lang: {} }, { tags: [] }, { categories: [] }].freeze
def inspect def inspect
"#<Post @id=#{id} @site=#{site.name}>" "#<Post @id=#{id} @site=#{site.name}>"
@ -37,29 +38,29 @@ class Post
def initialize(site:, post: nil, front_matter: {}, lang: nil, template: nil) def initialize(site:, post: nil, front_matter: {}, lang: nil, template: nil)
unless site.is_a?(Site) unless site.is_a?(Site)
raise ArgumentError, raise ArgumentError,
I18n.t('errors.argument_error', argument: :site, class: Site) I18n.t('errors.argument_error', argument: :site, class: Site)
end end
unless post.nil? || post.is_a?(Jekyll::Document) unless post.nil? || post.is_a?(Jekyll::Document)
raise ArgumentError, raise ArgumentError,
I18n.t('errors.argument_error', argument: :post, I18n.t('errors.argument_error', argument: :post,
class: Jekyll::Document) class: Jekyll::Document)
end end
@site = site @site = site
@post = post @post = post
@template = template @template = template
# los errores tienen que ser un hash para que # los errores tienen que ser un hash para que
# ActiveModel pueda traer los errores normalmente # ActiveModel pueda traer los errores normalmente
@errors = {} @errors = {}
# Si el sitio está traducido, trabajamos con la colección del # Si el sitio está traducido, trabajamos con la colección del
# idioma, sino, con posts # idioma, sino, con posts
if @site.i18n? @collection = if @site.i18n?
@collection = @lang = lang || I18n.locale.to_s @lang = lang || I18n.locale.to_s
else else
@collection = 'posts' 'posts'
end end
# sincronizar los datos del document # sincronizar los datos del document
if new? if new?
@ -115,6 +116,7 @@ class Post
slugs.map do |lang, id| slugs.map do |lang, id|
next if lang == @lang next if lang == @lang
@site.posts_for(lang).find do |p| @site.posts_for(lang).find do |p|
p.id == id p.id == id
end end
@ -141,7 +143,7 @@ class Post
add_post_to_site! add_post_to_site!
true true
end end
alias :save! :save alias save! save
def title def title
get_front_matter 'title' get_front_matter 'title'
@ -166,7 +168,7 @@ class Post
def categories def categories
get_front_matter('categories') || [] get_front_matter('categories') || []
end end
alias :category :categories alias category categories
# Devuelve la ruta del post, si se cambió alguno de los datos, # Devuelve la ruta del post, si se cambió alguno de los datos,
# generamos una ruta nueva para tener siempre la ruta actualizada. # generamos una ruta nueva para tener siempre la ruta actualizada.
@ -178,13 +180,13 @@ class Post
end end
end end
# TODO los slugs se pueden repetir, el identificador real sería # TODO: los slugs se pueden repetir, el identificador real sería
# fecha+slug, pero se ve feo en las urls? # fecha+slug, pero se ve feo en las urls?
def id def id
get_front_matter 'slug' get_front_matter 'slug'
end end
alias :slug :id alias slug id
alias :to_s :id alias to_s id
def basename_changed? def basename_changed?
@post.try(:basename) != basename_from_front_matter @post.try(:basename) != basename_from_front_matter
@ -208,7 +210,7 @@ class Post
def has_field?(field) def has_field?(field)
if template if template
template.fetch_front_matter("has_#{field.to_s}", true) template.fetch_front_matter("has_#{field}", true)
else else
true true
end end
@ -225,7 +227,7 @@ class Post
# convertir los hashes en arrays si los campos son anidados # convertir los hashes en arrays si los campos son anidados
# usamos to_hash por todos lados porque sino son # usamos to_hash por todos lados porque sino son
# HashWithIndifferentAccess # HashWithIndifferentAccess
_attrs = attrs.to_hash.map do |k,v| _attrs = attrs.to_hash.map do |k, v|
t = template_fields.find { |t| t.key == k } t = template_fields.find { |t| t.key == k }
if t if t
# Subir la imagen! # Subir la imagen!
@ -257,7 +259,7 @@ class Post
else else
{ k => v } { k => v }
end end
end.reduce(Hash.new, :merge).stringify_keys end.reduce({}, :merge).stringify_keys
# el cuerpo se maneja por separado # el cuerpo se maneja por separado
@content = _attrs.delete('content') if _attrs.key? 'content' @content = _attrs.delete('content') if _attrs.key? 'content'
@ -275,6 +277,7 @@ class Post
# XXX este es un principio de validación de plantillas, aunque no es # XXX este es un principio de validación de plantillas, aunque no es
# recursivo # recursivo
return if fetch_front_matter('incomplete', false) return if fetch_front_matter('incomplete', false)
template_fields.each do |tf| template_fields.each do |tf|
errors = [get_front_matter(tf.key)].flatten.compact errors = [get_front_matter(tf.key)].flatten.compact
if tf.image? && errors.map { |i| File.exist?(File.join(site.path, i)) }.none? if tf.image? && errors.map { |i| File.exist?(File.join(site.path, i)) }.none?
@ -299,6 +302,7 @@ class Post
def url?(name) def url?(name)
path = get_front_matter(name) path = get_front_matter(name)
return false unless path.is_a?(String) || path.is_a?(Array) return false unless path.is_a?(String) || path.is_a?(Array)
# El primer valor es '' porque la URL empieza con / # El primer valor es '' porque la URL empieza con /
[path].flatten.map do |p| [path].flatten.map do |p|
p.split('/').second == 'public' p.split('/').second == 'public'
@ -308,20 +312,20 @@ class Post
def image?(name) def image?(name)
return false unless url? name return false unless url? name
# TODO no chequear por la extensión # TODO: no chequear por la extensión
%[gif jpg jpeg png].include? get_front_matter(name).gsub(/.*\./, '') %(gif jpg jpeg png).include? get_front_matter(name).gsub(/.*\./, '')
end end
# Obtiene metadatos de forma recursiva # Obtiene metadatos de forma recursiva
# TODO devolver un valor por defecto en base al template? # TODO devolver un valor por defecto en base al template?
def get_front_matter(name) def get_front_matter(name)
if name.is_a? Array name = if name.is_a? Array
# Convertir los indices numericos a integers # Convertir los indices numericos a integers
name = name.map { |i| i =~ /[0-9]+/ ? i.to_i : i } name.map { |i| /[0-9]+/.match?(i) ? i.to_i : i }
else else
# XXX retrocompatibilidad # XXX retrocompatibilidad
name = name.to_s name.to_s
end end
@front_matter.dig(*name) @front_matter.dig(*name)
end end
@ -341,9 +345,10 @@ class Post
end end
end end
# TODO convertir a hash para que sea más fácil buscar uno # TODO: convertir a hash para que sea más fácil buscar uno
def template_fields def template_fields
return [] unless template return [] unless template
@template_fields ||= template.front_matter.map do |key, contents| @template_fields ||= template.front_matter.map do |key, contents|
next if REJECT_FROM_TEMPLATE.include? key next if REJECT_FROM_TEMPLATE.include? key
next if key.start_with? 'has_' next if key.start_with? 'has_'
@ -355,9 +360,7 @@ class Post
# devuelve las plantillas como strong params, primero los valores # devuelve las plantillas como strong params, primero los valores
# simples, luego los arrays y al final los hashes # simples, luego los arrays y al final los hashes
def template_params def template_params
@template_params ||= (DEFAULT_PARAMS + template_fields.map do |k| @template_params ||= (DEFAULT_PARAMS + template_fields.map(&:to_param)).sort_by do |s|
k.to_param
end).sort_by do |s|
s.is_a?(Symbol) ? 0 : 1 s.is_a?(Symbol) ? 0 : 1
end end
end end
@ -375,7 +378,7 @@ class Post
# entramos en una race condition # entramos en una race condition
return {} unless @template return {} unless @template
ft = template_fields.map(&:to_front_matter).reduce(Hash.new, :merge) ft = template_fields.map(&:to_front_matter).reduce({}, :merge)
# Convertimos el slug en layout # Convertimos el slug en layout
ft['layout'] = template.slug ft['layout'] = template.slug
@ -430,7 +433,7 @@ class Post
# Obtiene el nombre del archivo a partir de los datos que le # Obtiene el nombre del archivo a partir de los datos que le
# pasemos # pasemos
def basename_from_front_matter def basename_from_front_matter
ext = get_front_matter('ext') || '.markdown' ext = get_front_matter('ext') || '.markdown'
"#{date_as_string}-#{slug}#{ext}" "#{date_as_string}-#{slug}#{ext}"
end end
@ -485,7 +488,7 @@ class Post
end end
def remove_empty_front_matter! def remove_empty_front_matter!
@front_matter.delete_if do |k,v| @front_matter.delete_if do |_k, v|
v.blank? v.blank?
end end
end end
@ -526,7 +529,7 @@ class Post
# obtener el contenido por defecto si es que no lo enviamos # obtener el contenido por defecto si es que no lo enviamos
# modificaciones, como en `update_translations!` # modificaciones, como en `update_translations!`
def full_content def full_content
yaml = @front_matter.reject do |k,_| yaml = @front_matter.reject do |k, _|
REJECT_FROM_FRONT_MATTER.include? k REJECT_FROM_FRONT_MATTER.include? k
end end
@ -534,12 +537,12 @@ class Post
end end
def add_error(hash) def add_error(hash)
hash.each_pair do |k,i| hash.each_pair do |k, i|
if @errors.key?(k) @errors[k] = if @errors.key?(k)
@errors[k] = [@errors[k], i] [@errors[k], i]
else else
@errors[k] = i i
end end
end end
@errors @errors
@ -557,18 +560,17 @@ class Post
# XXX es necesario ahora que tenemos select2? # XXX es necesario ahora que tenemos select2?
def things_to_arrays! def things_to_arrays!
[:tags,:categories].each do |c| %i[tags categories].each do |c|
thing = @front_matter.dig(c.to_s) thing = @front_matter.dig(c.to_s)
next if thing.blank? next if thing.blank?
next if thing.is_a? Array next if thing.is_a? Array
@front_matter[c.to_s] = thing.split(',').map(&:strip) @front_matter[c.to_s] = thing.split(',').map(&:strip)
end end
end end
def slugify_title! def slugify_title!
if slug.blank? @front_matter['slug'] = Jekyll::Utils.slugify(title) if slug.blank?
@front_matter['slug'] = Jekyll::Utils.slugify(title)
end
end end
# Agregar al final de la cola si no especificamos un orden # Agregar al final de la cola si no especificamos un orden
@ -585,20 +587,20 @@ class Post
def create_glossary! def create_glossary!
return unless site.glossary? return unless site.glossary?
[:tags,:categories].each do |i| %i[tags categories].each do |i|
self.send(i).each do |c| send(i).each do |c|
# TODO no hardcodear, hacer _configurable # TODO: no hardcodear, hacer _configurable
next if c == 'Glossary' next if c == 'Glossary'
next if site.posts.find do |p| next if site.posts.find do |p|
p.title == c p.title == c
end end
glossary = Post.new(site: site, lang: lang) glossary = Post.new(site: site, lang: lang)
glossary.update_attributes({ glossary.update_attributes(
title: c, title: c,
layout: 'glossary', layout: 'glossary',
categories: 'Glossary' categories: 'Glossary'
}) )
glossary.save! glossary.save!
end end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# Una clase que permite adjuntar imágenes a artículos # Una clase que permite adjuntar imágenes a artículos
class Post::ImageUploader < CarrierWave::Uploader::Base class Post::ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick include CarrierWave::MiniMagick
@ -9,7 +11,7 @@ class Post::ImageUploader < CarrierWave::Uploader::Base
version :thumb do version :thumb do
process :strip process :strip
process resize_to_fit: [200,200] process resize_to_fit: [200, 200]
end end
def strip def strip
@ -28,7 +30,7 @@ class Post::ImageUploader < CarrierWave::Uploader::Base
# Solo aceptamos imágenes # Solo aceptamos imágenes
def content_type_whitelist def content_type_whitelist
/\Aimage\// %r{\Aimage/}
end end
# Devuelve la ubicación del directorio dentro de Jekyll, para eso, # Devuelve la ubicación del directorio dentro de Jekyll, para eso,
@ -46,10 +48,10 @@ class Post::ImageUploader < CarrierWave::Uploader::Base
# están repetidos. # están repetidos.
def filename def filename
current_filename = parent_version.try(:filename) || file.try(:filename) current_filename = parent_version.try(:filename) || file.try(:filename)
@unique_filename ||= if /\A(thumb_)?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\..*\Z/ =~ current_filename @unique_filename ||= if /\A(thumb_)?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\..*\Z/.match?(current_filename)
current_filename current_filename
else else
[SecureRandom.uuid, '.', file.extension].join [SecureRandom.uuid, '.', file.extension].join
end end
end end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# Representa los distintos tipos de campos que pueden venir de una # Representa los distintos tipos de campos que pueden venir de una
# plantilla compleja # plantilla compleja
class Post class Post
@ -5,7 +7,7 @@ class Post
attr_reader :post, :contents, :key attr_reader :post, :contents, :key
STRING_VALUES = %w[string text url number email password date year STRING_VALUES = %w[string text url number email password date year
image video audio document].freeze image video audio document].freeze
# Tipo de valores que son archivos # Tipo de valores que son archivos
FILE_TYPES = %w[image video audio document].freeze FILE_TYPES = %w[image video audio document].freeze
@ -27,50 +29,51 @@ class Post
def max def max
return 0 if simple? return 0 if simple?
contents.fetch('max', 0) contents.fetch('max', 0)
end end
def min def min
return 0 if simple? return 0 if simple?
contents.fetch('min', 0) contents.fetch('min', 0)
end end
# TODO volver elegante! # TODO: volver elegante!
def type def type
return @type if @type return @type if @type
case if image?
when image?
@type = 'image' @type = 'image'
when email? elsif email?
@type = 'email' @type = 'email'
when url? elsif url?
@type = 'url' @type = 'url'
when number? elsif number?
@type = 'number' @type = 'number'
when password? elsif password?
@type = 'password' @type = 'password'
when date? elsif date?
@type = 'date' @type = 'date'
when year? elsif year?
@type = 'year' @type = 'year'
when text_area? elsif text_area?
@type = 'text_area' @type = 'text_area'
when check_box_group? elsif check_box_group?
@type = 'check_box_group' @type = 'check_box_group'
when radio_group? elsif radio_group?
@type = 'radio_group' @type = 'radio_group'
when string? elsif string?
@type = 'text' @type = 'text'
# TODO volver a hacer funcionar esto y ahorranos los multiple: # TODO: volver a hacer funcionar esto y ahorranos los multiple:
# false # false
when string? && contents.split('/', 2).count == 2 elsif string? && contents.split('/', 2).count == 2
@type = 'select' @type = 'select'
when nested? elsif nested?
@type = 'table' @type = 'table'
when array? elsif array?
@type = 'select' @type = 'select'
when boolean? elsif boolean?
@type = 'check_box' @type = 'check_box'
end end
@ -79,15 +82,14 @@ class Post
# Devuelve los valores vacíos según el tipo # Devuelve los valores vacíos según el tipo
def empty_value def empty_value
case if string?
when string?
'' ''
when nested? elsif nested?
# TODO devolver las keys también # TODO: devolver las keys también
{} {}
when array? elsif array?
[] []
when boolean? elsif boolean?
false false
end end
end end
@ -124,7 +126,7 @@ class Post
def email? def email?
value == 'email' || value == 'mail' value == 'email' || value == 'mail'
end end
alias :mail? :email? alias mail? email?
def date? def date?
value == 'date' value == 'date'
@ -192,7 +194,7 @@ class Post
value.is_a? Array value.is_a? Array
end end
# TODO detectar cuando es complejo y tomar el valor de :multiple # TODO: detectar cuando es complejo y tomar el valor de :multiple
def multiple? def multiple?
# si la plantilla es simple, es multiple cuando tenemos un array # si la plantilla es simple, es multiple cuando tenemos un array
return array? if simple? return array? if simple?
@ -211,6 +213,7 @@ class Post
# Todos los valores simples son abiertos # Todos los valores simples son abiertos
return true unless complex? return true unless complex?
return false unless array? return false unless array?
# La cosa se complejiza cuando tenemos valores complejos # La cosa se complejiza cuando tenemos valores complejos
# #
# Si tenemos una lista cerrada de valores, necesitamos saber si el # Si tenemos una lista cerrada de valores, necesitamos saber si el
@ -241,7 +244,7 @@ class Post
def human def human
h = key.humanize h = key.humanize
h = h + ' *' if required? h += ' *' if required?
h h
end end
@ -260,21 +263,21 @@ class Post
v = value v = value
v = value.first if array? v = value.first if array?
@nested_fields ||= v.map do |k,sv| @nested_fields ||= v.map do |k, sv|
Post::TemplateField.new post, k, sv Post::TemplateField.new post, k, sv
end end
end end
# Obtiene los valores posibles para el campo de la plantilla # Obtiene los valores posibles para el campo de la plantilla
def values def values
return 'false' if self.value == false return 'false' if value == false
return 'true' if self.value == true return 'true' if value == true
# XXX por alguna razón `value` no refiere a value() :/ # XXX por alguna razón `value` no refiere a value() :/
return '' if STRING_VALUES.include? self.value return '' if STRING_VALUES.include? value
# Las listas cerradas no necesitan mayor procesamiento # Las listas cerradas no necesitan mayor procesamiento
return self.value if array? && closed? && self.value.count > 1 return value if array? && closed? && value.count > 1
# Y las vacías tampoco # Y las vacías tampoco
return self.value if array? && self.value.empty? return value if array? && value.empty?
# Ahorrarnos el trabajo # Ahorrarnos el trabajo
return @values if @values return @values if @values
@ -301,7 +304,7 @@ class Post
collection, attr, subattr = v.split('/', 3) collection, attr, subattr = v.split('/', 3)
if collection == 'site' if collection == 'site'
# TODO puede ser peligroso permitir acceder a cualquier # TODO: puede ser peligroso permitir acceder a cualquier
# atributo de site? No estamos trayendo nada fuera de # atributo de site? No estamos trayendo nada fuera de
# lo normal # lo normal
post.site.send(attr.to_sym) post.site.send(attr.to_sym)
@ -311,11 +314,11 @@ class Post
# TODO volver recursivo! # TODO volver recursivo!
elsif subattr elsif subattr
post.site.everything_of(attr, lang: collection) post.site.everything_of(attr, lang: collection)
.compact .compact
.map { |sv| sv[subattr] } .map { |sv| sv[subattr] }
.flatten .flatten
.compact .compact
.uniq .uniq
else else
post.site.everything_of(attr, lang: collection).compact post.site.everything_of(attr, lang: collection).compact
end end
@ -331,7 +334,7 @@ class Post
if _value.count == 1 if _value.count == 1
_value = [(_value.first + value).uniq] _value = [(_value.first + value).uniq]
elsif _value.count == 2 elsif _value.count == 2
_value = _value.each_with_index.map do |v,i| _value = _value.each_with_index.map do |v, i|
v + value.fetch(i, []) v + value.fetch(i, [])
end end
end end

View file

@ -1,7 +1,8 @@
# frozen_string_literal: true
# Un sitio es un directorio dentro del directorio de sitios de cada # Un sitio es un directorio dentro del directorio de sitios de cada
# Usuaria # Usuaria
class Site class Site
attr_accessor :jekyll, :collections attr_accessor :jekyll, :collections
attr_reader :path attr_reader :path
@ -71,8 +72,8 @@ class Site
def name def name
@name ||= File.basename(@jekyll.config['source']) @name ||= File.basename(@jekyll.config['source'])
end end
alias :id :name alias id name
alias :to_s :name alias to_s name
def name_with_i18n(lang) def name_with_i18n(lang)
[name, lang].join('/') [name, lang].join('/')
@ -108,9 +109,7 @@ class Site
@jekyll.config @jekyll.config
end end
def collections attr_reader :collections
@collections
end
def collections_names def collections_names
@jekyll.config['collections'].keys @jekyll.config['collections'].keys
@ -132,6 +131,7 @@ class Site
# Devuelve nil si la colección no existe # Devuelve nil si la colección no existe
def posts_for(collection) def posts_for(collection)
return unless collections_names.include? collection return unless collections_names.include? collection
# Si pedimos 'posts' pero estamos en un sitio traducido, traemos el # Si pedimos 'posts' pero estamos en un sitio traducido, traemos el
# idioma actual # idioma actual
collection = default_lang if collection == 'posts' && i18n? collection = default_lang if collection == 'posts' && i18n?
@ -192,6 +192,7 @@ class Site
def invitadxs def invitadxs
return [] unless invitadxs? return [] unless invitadxs?
@invitadxs ||= File.read(invitadxs_file).split("\n").map do |i| @invitadxs ||= File.read(invitadxs_file).split("\n").map do |i|
Invitadx.find_by_email(i) Invitadx.find_by_email(i)
end end
@ -208,7 +209,7 @@ class Site
def defail def defail
FileUtils.rm failed_file if failed? FileUtils.rm failed_file if failed?
end end
alias :defail! :defail alias defail! defail
def build_log def build_log
File.join(path, 'build.log') File.join(path, 'build.log')
@ -225,13 +226,13 @@ class Site
def enqueued? def enqueued?
File.exist? queue_file File.exist? queue_file
end end
alias :queued? :enqueued? alias queued? enqueued?
# El sitio se genera cuando se coloca en una cola de generación, para # El sitio se genera cuando se coloca en una cola de generación, para
# que luego lo construya un cronjob # que luego lo construya un cronjob
def enqueue def enqueue
defail! defail!
# TODO ya van tres métodos donde usamos esta idea, convertir en un # TODO: ya van tres métodos donde usamos esta idea, convertir en un
# helper o algo # helper o algo
r = File.open(queue_file, File::RDWR | File::CREAT, 0o640) do |f| r = File.open(queue_file, File::RDWR | File::CREAT, 0o640) do |f|
# Bloquear el archivo para que no sea accedido por otro # Bloquear el archivo para que no sea accedido por otro
@ -249,19 +250,17 @@ class Site
f.truncate(f.pos) f.truncate(f.pos)
end end
end end
alias :enqueue! :enqueue alias enqueue! enqueue
# Eliminar de la cola # Eliminar de la cola
def dequeue def dequeue
FileUtils.rm(queue_file) if enqueued? FileUtils.rm(queue_file) if enqueued?
end end
alias :dequeue! :dequeue alias dequeue! dequeue
# Verifica si los posts están ordenados # Verifica si los posts están ordenados
def ordered?(collection = 'posts') def ordered?(collection = 'posts')
posts_for(collection).map do |p| posts_for(collection).map(&:order).all?
p.order
end.all?
end end
# Reordena la colección usando la posición informada # Reordena la colección usando la posición informada
@ -293,10 +292,10 @@ class Site
# Reordena la colección usando la posición actual de los artículos # Reordena la colección usando la posición actual de los artículos
def reorder_collection!(collection = 'posts') def reorder_collection!(collection = 'posts')
order = Hash[posts_for(collection).count.times.map { |i| [i.to_s,i.to_s] }] order = Hash[posts_for(collection).count.times.map { |i| [i.to_s, i.to_s] }]
reorder_collection collection, order reorder_collection collection, order
end end
alias :reorder_posts! :reorder_collection! alias reorder_posts! reorder_collection!
# Obtener una ruta disponible para Sutty # Obtener una ruta disponible para Sutty
def get_url_for_sutty(path) def get_url_for_sutty(path)
@ -336,9 +335,9 @@ class Site
# Especificamos `safe` para no cargar los _plugins, que interfieren # Especificamos `safe` para no cargar los _plugins, que interfieren
# entre sitios incluso # entre sitios incluso
config = ::Jekyll.configuration('source' => path, config = ::Jekyll.configuration('source' => path,
'destination' => File.join(path, '_site'), 'destination' => File.join(path, '_site'),
'safe' => true, 'safe' => true,
'watch' => false) 'watch' => false)
# No necesitamos cargar plugins en este momento # No necesitamos cargar plugins en este momento
%w[plugins gems theme].each do |unneeded| %w[plugins gems theme].each do |unneeded|
@ -348,10 +347,8 @@ class Site
# Si estamos usando nuestro propio plugin de i18n, los posts están # Si estamos usando nuestro propio plugin de i18n, los posts están
# en "colecciones" # en "colecciones"
i18n = config.dig('i18n') i18n = config.dig('i18n')
if i18n i18n&.each do |i|
i18n.each do |i| config['collections'][i] = {}
config['collections'][i] = {}
end
end end
Jekyll::Site.new(config) Jekyll::Site.new(config)

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# Un modelo para la usuaria que no se corresponde con una base de datos # Un modelo para la usuaria que no se corresponde con una base de datos
# porque vienen de IMAP # porque vienen de IMAP
# #

View file

@ -1,6 +1,7 @@
class I18nPolicy < SuttyPolicy # frozen_string_literal: true
def initialize(usuarix, i18n) class I18nPolicy < SuttyPolicy
def initialize(usuarix, _i18n)
@usuarix = usuarix @usuarix = usuarix
end end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class InvitadxPolicy class InvitadxPolicy
attr_reader :usuarix, :model attr_reader :usuarix, :model

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class PostPolicy < SuttyPolicy class PostPolicy < SuttyPolicy
attr_reader :post attr_reader :post

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class SitePolicy < SuttyPolicy class SitePolicy < SuttyPolicy
attr_reader :site attr_reader :site

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class SuttyPolicy class SuttyPolicy
attr_reader :usuarix attr_reader :usuarix

View file

@ -117,7 +117,7 @@
- @post.template_fields.each do |template| - @post.template_fields.each do |template|
- next unless type = template.type - next unless type = template.type
- if template.title.present? - if template.title.present?
%h1= template.title %h1{id: template.title.tr(' ', '_').titleize}= template.title
- value = @post.new? ? template.values : @post.get_front_matter(template.key) - value = @post.new? ? template.values : @post.get_front_matter(template.key)
.form-group .form-group
= label_tag "post_#{template}", id: template do = label_tag "post_#{template}", id: template do

View file

@ -8,22 +8,23 @@
# this file is here to facilitate running it. # this file is here to facilitate running it.
# #
require "rubygems" require 'rubygems'
m = Module.new do m = Module.new do
module_function module_function
def invoked_as_script? def invoked_as_script?
File.expand_path($0) == File.expand_path(__FILE__) File.expand_path($PROGRAM_NAME) == File.expand_path(__FILE__)
end end
def env_var_version def env_var_version
ENV["BUNDLER_VERSION"] ENV['BUNDLER_VERSION']
end end
def cli_arg_version def cli_arg_version
return unless invoked_as_script? # don't want to hijack other binstubs return unless invoked_as_script? # don't want to hijack other binstubs
return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` return unless 'update'.start_with?(ARGV.first || ' ') # must be running `bundle update`
bundler_version = nil bundler_version = nil
update_index = nil update_index = nil
ARGV.each_with_index do |a, i| ARGV.each_with_index do |a, i|
@ -31,23 +32,24 @@ m = Module.new do
bundler_version = a bundler_version = a
end end
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
bundler_version = $1 || ">= 0.a"
bundler_version = Regexp.last_match(1) || '>= 0.a'
update_index = i update_index = i
end end
bundler_version bundler_version
end end
def gemfile def gemfile
gemfile = ENV["BUNDLE_GEMFILE"] gemfile = ENV['BUNDLE_GEMFILE']
return gemfile if gemfile && !gemfile.empty? return gemfile if gemfile && !gemfile.empty?
File.expand_path("../../Gemfile", __FILE__) File.expand_path('../Gemfile', __dir__)
end end
def lockfile def lockfile
lockfile = lockfile =
case File.basename(gemfile) case File.basename(gemfile)
when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) when 'gems.rb' then gemfile.sub(/\.rb$/, gemfile)
else "#{gemfile}.lock" else "#{gemfile}.lock"
end end
File.expand_path(lockfile) File.expand_path(lockfile)
@ -55,8 +57,10 @@ m = Module.new do
def lockfile_version def lockfile_version
return unless File.file?(lockfile) return unless File.file?(lockfile)
lockfile_contents = File.read(lockfile) lockfile_contents = File.read(lockfile)
return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
Regexp.last_match(1) Regexp.last_match(1)
end end
@ -68,24 +72,26 @@ m = Module.new do
end end
def load_bundler! def load_bundler!
ENV["BUNDLE_GEMFILE"] ||= gemfile ENV['BUNDLE_GEMFILE'] ||= gemfile
# must dup string for RG < 1.8 compatibility # must dup string for RG < 1.8 compatibility
activate_bundler(bundler_version.dup) activate_bundler(bundler_version.dup)
end end
def activate_bundler(bundler_version) def activate_bundler(bundler_version)
if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0") if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new('2.0')
bundler_version = "< 2" bundler_version = '< 2'
end end
gem_error = activation_error_handling do gem_error = activation_error_handling do
gem "bundler", bundler_version gem 'bundler', bundler_version
end end
return if gem_error.nil? return if gem_error.nil?
require_error = activation_error_handling do require_error = activation_error_handling do
require "bundler/version" require 'bundler/version'
end end
return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION)) return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION))
warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`" warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`"
exit 42 exit 42
end end
@ -100,6 +106,4 @@ end
m.load_bundler! m.load_bundler!
if m.invoked_as_script? load Gem.bin_path('bundler', 'bundle') if m.invoked_as_script?
load Gem.bin_path("bundler", "bundle")
end

16
bin/cap
View file

@ -8,14 +8,14 @@
# this file is here to facilitate running it. # this file is here to facilitate running it.
# #
require "pathname" require 'pathname'
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
Pathname.new(__FILE__).realpath) Pathname.new(__FILE__).realpath)
bundle_binstub = File.expand_path("../bundle", __FILE__) bundle_binstub = File.expand_path('bundle', __dir__)
if File.file?(bundle_binstub) if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ if /This file was generated by Bundler/.match?(File.read(bundle_binstub, 300))
load(bundle_binstub) load(bundle_binstub)
else else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
@ -23,7 +23,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
end end
end end
require "rubygems" require 'rubygems'
require "bundler/setup" require 'bundler/setup'
load Gem.bin_path("capistrano", "cap") load Gem.bin_path('capistrano', 'cap')

View file

@ -8,14 +8,14 @@
# this file is here to facilitate running it. # this file is here to facilitate running it.
# #
require "pathname" require 'pathname'
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
Pathname.new(__FILE__).realpath) Pathname.new(__FILE__).realpath)
bundle_binstub = File.expand_path("../bundle", __FILE__) bundle_binstub = File.expand_path('bundle', __dir__)
if File.file?(bundle_binstub) if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ if /This file was generated by Bundler/.match?(File.read(bundle_binstub, 300))
load(bundle_binstub) load(bundle_binstub)
else else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
@ -23,7 +23,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
end end
end end
require "rubygems" require 'rubygems'
require "bundler/setup" require 'bundler/setup'
load Gem.bin_path("capistrano", "capify") load Gem.bin_path('capistrano', 'capify')

View file

@ -1,6 +1,8 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# frozen_string_literal: true
begin begin
load File.expand_path('../spring', __FILE__) load File.expand_path('spring', __dir__)
rescue LoadError => e rescue LoadError => e
raise unless e.message.include?('spring') raise unless e.message.include?('spring')
end end

View file

@ -1,6 +1,8 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# frozen_string_literal: true
begin begin
load File.expand_path('../spring', __FILE__) load File.expand_path('spring', __dir__)
rescue LoadError => e rescue LoadError => e
raise unless e.message.include?('spring') raise unless e.message.include?('spring')
end end

View file

@ -1,10 +1,12 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# frozen_string_literal: true
require 'pathname' require 'pathname'
require 'fileutils' require 'fileutils'
include FileUtils include FileUtils
# path to your application root. # path to your application root.
APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) APP_ROOT = Pathname.new File.expand_path('..', __dir__)
def system!(*args) def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==") system(*args) || abort("\n== Command #{args} failed ==")
@ -21,7 +23,6 @@ chdir APP_ROOT do
# Install JavaScript dependencies if using Yarn # Install JavaScript dependencies if using Yarn
# system('bin/yarn') # system('bin/yarn')
# puts "\n== Copying sample files ==" # puts "\n== Copying sample files =="
# unless File.exist?('config/database.yml') # unless File.exist?('config/database.yml')
# cp 'config/database.yml.sample', 'config/database.yml' # cp 'config/database.yml.sample', 'config/database.yml'

View file

@ -1,4 +1,5 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# frozen_string_literal: true
# This file loads spring without using Bundler, in order to be fast. # This file loads spring without using Bundler, in order to be fast.
# It gets overwritten when you run the `spring binstub` command. # It gets overwritten when you run the `spring binstub` command.
@ -8,7 +9,7 @@ unless defined?(Spring)
require 'bundler' require 'bundler'
lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read) lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read)
spring = lockfile.specs.detect { |spec| spec.name == "spring" } spring = lockfile.specs.detect { |spec| spec.name == 'spring' }
if spring if spring
Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path
gem 'spring', spring.version gem 'spring', spring.version

View file

@ -1,10 +1,12 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# frozen_string_literal: true
require 'pathname' require 'pathname'
require 'fileutils' require 'fileutils'
include FileUtils include FileUtils
# path to your application root. # path to your application root.
APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) APP_ROOT = Pathname.new File.expand_path('..', __dir__)
def system!(*args) def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==") system(*args) || abort("\n== Command #{args} failed ==")

View file

@ -8,14 +8,14 @@
# this file is here to facilitate running it. # this file is here to facilitate running it.
# #
bundle_binstub = File.expand_path("../bundle", __FILE__) bundle_binstub = File.expand_path('bundle', __dir__)
load(bundle_binstub) if File.file?(bundle_binstub) load(bundle_binstub) if File.file?(bundle_binstub)
require "pathname" require 'pathname'
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
Pathname.new(__FILE__).realpath) Pathname.new(__FILE__).realpath)
require "rubygems" require 'rubygems'
require "bundler/setup" require 'bundler/setup'
load Gem.bin_path("whenever", "whenever") load Gem.bin_path('whenever', 'whenever')

View file

@ -8,14 +8,14 @@
# this file is here to facilitate running it. # this file is here to facilitate running it.
# #
bundle_binstub = File.expand_path("../bundle", __FILE__) bundle_binstub = File.expand_path('bundle', __dir__)
load(bundle_binstub) if File.file?(bundle_binstub) load(bundle_binstub) if File.file?(bundle_binstub)
require "pathname" require 'pathname'
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
Pathname.new(__FILE__).realpath) Pathname.new(__FILE__).realpath)
require "rubygems" require 'rubygems'
require "bundler/setup" require 'bundler/setup'
load Gem.bin_path("whenever", "wheneverize") load Gem.bin_path('whenever', 'wheneverize')

View file

@ -1,11 +1,11 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# frozen_string_literal: true
VENDOR_PATH = File.expand_path('..', __dir__) VENDOR_PATH = File.expand_path('..', __dir__)
Dir.chdir(VENDOR_PATH) do Dir.chdir(VENDOR_PATH) do
begin exec "yarnpkg #{ARGV.join(' ')}"
exec "yarnpkg #{ARGV.join(" ")}" rescue Errno::ENOENT
rescue Errno::ENOENT warn 'Yarn executable was not detected in the system.'
$stderr.puts "Yarn executable was not detected in the system." warn 'Download Yarn at https://yarnpkg.com/en/docs/install'
$stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" exit 1
exit 1
end
end end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# This file is used by Rack-based servers to start the application. # This file is used by Rack-based servers to start the application.
require_relative 'config/environment' require_relative 'config/environment'

View file

@ -1,16 +1,18 @@
# frozen_string_literal: true
require_relative 'boot' require_relative 'boot'
require "rails" require 'rails'
# Pick the frameworks you want: # Pick the frameworks you want:
require "active_model/railtie" require 'active_model/railtie'
require "active_job/railtie" require 'active_job/railtie'
require "active_record/railtie" require 'active_record/railtie'
require "action_controller/railtie" require 'action_controller/railtie'
require "action_mailer/railtie" require 'action_mailer/railtie'
require "action_view/railtie" require 'action_view/railtie'
# require "action_cable/engine" # require "action_cable/engine"
require "sprockets/railtie" require 'sprockets/railtie'
require "rails/test_unit/railtie" require 'rails/test_unit/railtie'
# Require the gems listed in Gemfile, including any gems # Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production. # you've limited to :test, :development, or :production.

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require 'bundler/setup' # Set up gems listed in the Gemfile. require 'bundler/setup' # Set up gems listed in the Gemfile.

View file

@ -1,11 +1,12 @@
# frozen_string_literal: true # frozen_string_literal: true
set :application, 'sutty' set :application, 'sutty'
set :repo_url, 'git@0xacab.org:itacate-kefir/sutty.git' set :repo_url, 'git@0xacab.org:itacate-kefir/sutty.git'
set :bundle_flags, '--deployment' set :bundle_flags, '--deployment'
set :default_env, path: '/usr/lib/passenger/bin:$PATH' set :default_env, path: '/usr/lib/passenger/bin:$PATH'
set :linked_dirs, %w{_sites _deploy _usuarias _invitadxs public/covers} set :linked_dirs, %w[_sites _deploy _usuarias _invitadxs public/covers]
set :linked_files, %w{.env db/production.sqlite3} set :linked_files, %w[.env db/production.sqlite3]
set :keep_releases, 1 set :keep_releases, 1

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
set :deploy_user, 'DEPLOY_USER' set :deploy_user, 'DEPLOY_USER'
set :deploy_to, '/srv/http/sutty.kefir.red' set :deploy_to, '/srv/http/sutty.kefir.red'
set :branch, 'rails' set :branch, 'rails'
@ -11,7 +12,7 @@ set :rbenv_type, :user
set :rbenv_ruby, '2.3.6' set :rbenv_ruby, '2.3.6'
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec" set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
set :rbenv_map_bins, %w(rake gem bundle ruby rails) set :rbenv_map_bins, %w[rake gem bundle ruby rails]
set :rbenv_roles, :all # default value set :rbenv_roles, :all # default value
# Evitar compilar nokogiri # Evitar compilar nokogiri
@ -19,4 +20,4 @@ set :bundle_env_variables, nokogiri_use_system_libraries: 1
server 'DEPLOY_SERVER', server 'DEPLOY_SERVER',
user: fetch(:deploy_user), user: fetch(:deploy_user),
roles: %w(app web db) roles: %w[app web db]

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
set :deploy_user, 'app' set :deploy_user, 'app'
set :deploy_to, '/srv/http/sutty.kefir.red' set :deploy_to, '/srv/http/sutty.kefir.red'
set :branch, 'rails' set :branch, 'rails'
@ -11,7 +12,7 @@ set :rbenv_type, :user
set :rbenv_ruby, '2.3.6' set :rbenv_ruby, '2.3.6'
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec" set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
set :rbenv_map_bins, %w(rake gem bundle ruby rails) set :rbenv_map_bins, %w[rake gem bundle ruby rails]
set :rbenv_roles, :all # default value set :rbenv_roles, :all # default value
# Evitar compilar nokogiri # Evitar compilar nokogiri
@ -19,4 +20,4 @@ set :bundle_env_variables, nokogiri_use_system_libraries: 1
server 'miso', server 'miso',
user: fetch(:deploy_user), user: fetch(:deploy_user),
roles: %w(app web db) roles: %w[app web db]

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# Load the Rails application. # Load the Rails application.
require_relative 'application' require_relative 'application'

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
Rails.application.configure do Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb. # Settings specified here will take precedence over those in config/application.rb.

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
Rails.application.configure do Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb. # Settings specified here will take precedence over those in config/application.rb.
@ -39,7 +41,6 @@ Rails.application.configure do
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true # config.force_ssl = true
@ -48,7 +49,7 @@ Rails.application.configure do
config.log_level = :debug config.log_level = :debug
# Prepend all log lines with the following tags. # Prepend all log lines with the following tags.
config.log_tags = [ :request_id ] config.log_tags = [:request_id]
# Use a different cache store in production. # Use a different cache store in production.
# config.cache_store = :mem_cache_store # config.cache_store = :mem_cache_store
@ -76,7 +77,7 @@ Rails.application.configure do
# require 'syslog/logger' # require 'syslog/logger'
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
if ENV["RAILS_LOG_TO_STDOUT"].present? if ENV['RAILS_LOG_TO_STDOUT'].present?
logger = ActiveSupport::Logger.new(STDOUT) logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = config.log_formatter logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger) config.logger = ActiveSupport::TaggedLogging.new(logger)
@ -93,9 +94,9 @@ Rails.application.configure do
config.action_mailer.default_options = { from: ENV.fetch('DEFAULT_FROM', 'sutty@kefir.red') } config.action_mailer.default_options = { from: ENV.fetch('DEFAULT_FROM', 'sutty@kefir.red') }
config.middleware.use ExceptionNotification::Rack, config.middleware.use ExceptionNotification::Rack,
email: { email: {
email_prefix: '[ERROR]', email_prefix: '[ERROR]',
sender_address: %(sutty@kefir.red), sender_address: %(sutty@kefir.red),
exception_recipients: 'sysadmin@kefir.red' exception_recipients: 'sysadmin@kefir.red'
} }
end end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
Rails.application.configure do Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb. # Settings specified here will take precedence over those in config/application.rb.

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file. # Be sure to restart your server when you modify this file.
# ActiveSupport::Reloader.to_prepare do # ActiveSupport::Reloader.to_prepare do

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file. # Be sure to restart your server when you modify this file.
# Version of your assets, change this if you want to expire all your assets. # Version of your assets, change this if you want to expire all your assets.

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file. # Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.

View file

@ -1,5 +1,7 @@
# frozen_string_literal: true
CarrierWave.configure do |config| CarrierWave.configure do |config|
config.permissions = 0640 config.permissions = 0o640
config.directory_permissions = 0750 config.directory_permissions = 0o750
config.storage = :file config.storage = :file
end end

View file

@ -1,18 +1,17 @@
# frozen_string_literal: true
require 'commonmarker' require 'commonmarker'
module Haml::Filters module Haml::Filters
remove_filter('Markdown') # remove the existing Markdown filter
remove_filter("Markdown") #remove the existing Markdown filter
module Markdown module Markdown
include Haml::Filters::Base include Haml::Filters::Base
def render(text) def render(text)
CommonMarker.render_html(text, CommonMarker.render_html(text,
[:TABLE_PREFER_STYLE_ATTRIBUTES], [:TABLE_PREFER_STYLE_ATTRIBUTES],
[:table,:strikethrough,:autolink,:tagfilter]) %i[table strikethrough autolink tagfilter])
end end
end end
end end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file. # Be sure to restart your server when you modify this file.
# Specify a serializer for the signed and encrypted cookie jars. # Specify a serializer for the signed and encrypted cookie jars.

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file. # Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file. # Configure sensitive parameters which will be filtered from the log file.

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
ActiveSupport::Inflector.inflections(:en) do |inflect| ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.plural 'invitadx', 'invitadxs' inflect.plural 'invitadx', 'invitadxs'
inflect.singular 'invitadxs', 'invitadx' inflect.singular 'invitadxs', 'invitadx'

View file

@ -1,4 +1,6 @@
# frozen_string_literal: true
Rails.application.configure do Rails.application.configure do
config.i18n.available_locales = [:es, :en, :ar] config.i18n.available_locales = %i[es en ar]
config.i18n.default_locale = :es config.i18n.default_locale = :es
end end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file. # Be sure to restart your server when you modify this file.
# Add new mime types for use in respond_to blocks: # Add new mime types for use in respond_to blocks:

View file

@ -1,9 +1,11 @@
# frozen_string_literal: true
require 'warden/imap' require 'warden/imap'
require 'warden/email_and_password' require 'warden/email_and_password'
Rails.configuration.middleware.use RailsWarden::Manager do |manager| Rails.configuration.middleware.use RailsWarden::Manager do |manager|
manager.default_strategies :email, :imap manager.default_strategies :email, :imap
manager.failure_app = -> (env) { LoginController.action(:new).call(env) } manager.failure_app = ->(env) { LoginController.action(:new).call(env) }
end end
class Warden::SessionSerializer class Warden::SessionSerializer

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file. # Be sure to restart your server when you modify this file.
# This file contains settings for ActionController::ParamsWrapper which # This file contains settings for ActionController::ParamsWrapper which

View file

@ -1,19 +1,21 @@
# frozen_string_literal: true
# Puma can serve each request in a thread from an internal thread pool. # Puma can serve each request in a thread from an internal thread pool.
# The `threads` method setting takes two numbers: a minimum and maximum. # The `threads` method setting takes two numbers: a minimum and maximum.
# Any libraries that use thread pools should be configured to match # Any libraries that use thread pools should be configured to match
# the maximum value specified for Puma. Default is set to 5 threads for minimum # the maximum value specified for Puma. Default is set to 5 threads for minimum
# and maximum; this matches the default thread size of Active Record. # and maximum; this matches the default thread size of Active Record.
# #
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } threads_count = ENV.fetch('RAILS_MAX_THREADS') { 1 }
threads threads_count, threads_count threads threads_count, threads_count
# Specifies the `port` that Puma will listen on to receive requests; default is 3000. # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
# #
port ENV.fetch("PORT") { 3000 } port ENV.fetch('PORT') { 3000 }
# Specifies the `environment` that Puma will run in. # Specifies the `environment` that Puma will run in.
# #
environment ENV.fetch("RAILS_ENV") { "development" } environment ENV.fetch('RAILS_ENV') { 'development' }
# Specifies the number of `workers` to boot in clustered mode. # Specifies the number of `workers` to boot in clustered mode.
# Workers are forked webserver processes. If using threads and workers together # Workers are forked webserver processes. If using threads and workers together

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
Rails.application.routes.draw do Rails.application.routes.draw do
root 'application#index' root 'application#index'
@ -7,16 +9,15 @@ Rails.application.routes.draw do
get 'markdown', to: 'application#markdown' get 'markdown', to: 'application#markdown'
# XXX Mantenemos solo esta ruta acá porque form_for no reconoce @site # XXX Mantenemos solo esta ruta acá porque form_for no reconoce @site
# como un objeto válido # como un objeto válido
resources :invitadxs, only: [:create] resources :invitadxs, only: [:create]
resources :sites, only: [:index, :show], constraints: { site_id: /[^\/]+/, id: /[^\/]+/ } do resources :sites, only: %i[index show], constraints: { site_id: %r{[^/]+}, id: %r{[^/]+} } do
get 'public/:type/:basename', to: 'sites#send_public_file' get 'public/:type/:basename', to: 'sites#send_public_file'
resources :posts resources :posts
resources :templates resources :templates
resources :invitadxs, only: [:index, :new, :show] do resources :invitadxs, only: %i[index new show] do
get :confirmation, to: 'invitadxs#confirmation' get :confirmation, to: 'invitadxs#confirmation'
end end
get :'invitadxs/login/new', to: 'login#new' get :'invitadxs/login/new', to: 'login#new'

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
env 'MAILTO', 'sysadmin@kefir.red' env 'MAILTO', 'sysadmin@kefir.red'
job_type :bash, 'cd :path && ./bin/:task' job_type :bash, 'cd :path && ./bin/:task'

View file

@ -1,14 +1,16 @@
# frozen_string_literal: true
# https://github.com/thoughtbot/ember-cli-rails/issues/479#issuecomment-241302961 # https://github.com/thoughtbot/ember-cli-rails/issues/479#issuecomment-241302961
Spring::Watcher::Listen.class_eval do Spring::Watcher::Listen.class_eval do
def base_directories def base_directories
%w(app config db lib test vendor) %w[app config db lib test vendor]
.uniq.map { |path| Pathname.new(File.join(root, path)) } .uniq.map { |path| Pathname.new(File.join(root, path)) }
end end
end end
%w( %w[
.ruby-version .ruby-version
.rbenv-vars .rbenv-vars
tmp/restart.txt tmp/restart.txt
tmp/caching-dev.txt tmp/caching-dev.txt
).each { |path| Spring.watch(path) } ].each { |path| Spring.watch(path) }

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class CreateInvitadxs < ActiveRecord::Migration[5.1] class CreateInvitadxs < ActiveRecord::Migration[5.1]
def change def change
create_table :invitadxs do |t| create_table :invitadxs do |t|

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class AddAceptaPoliticasDePrivacidadToInvitadx < ActiveRecord::Migration[5.1] class AddAceptaPoliticasDePrivacidadToInvitadx < ActiveRecord::Migration[5.1]
def change def change
add_column :invitadxs, :acepta_politicas_de_privacidad, :boolean, default: false add_column :invitadxs, :acepta_politicas_de_privacidad, :boolean, default: false

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
# This file should contain all the record creation needed to seed the database with its default values. # This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup). # The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
# #

View file

@ -1,11 +1,13 @@
# frozen_string_literal: true
require 'email_address' require 'email_address'
module Warden module Warden
module EmailAndPassword module EmailAndPassword
class Strategy < Warden::Strategies::Base class Strategy < Warden::Strategies::Base
def valid? def valid?
return false unless params.include? 'username' return false unless params.include? 'username'
return false unless params.include? 'password' return false unless params.include? 'password'
username = params['username'] username = params['username']
@email = EmailAddress.new(username, host_validation: :a) @email = EmailAddress.new(username, host_validation: :a)

View file

@ -55,4 +55,3 @@ module Warden
end end
end end
end end

View file

@ -1,4 +1,6 @@
require "test_helper" # frozen_string_literal: true
require 'test_helper'
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driven_by :selenium, using: :chrome, screen_size: [1400, 1400] driven_by :selenium, using: :chrome, screen_size: [1400, 1400]

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'test_helper' require 'test_helper'
class PostTest < ActiveSupport::TestCase class PostTest < ActiveSupport::TestCase

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'test_helper' require 'test_helper'
class SiteTest < ActiveSupport::TestCase class SiteTest < ActiveSupport::TestCase
@ -9,7 +11,7 @@ class SiteTest < ActiveSupport::TestCase
@site.read @site.read
end end
test "El directorio es un sitio jekyll" do test 'El directorio es un sitio jekyll' do
assert Site.jekyll?(@path) assert Site.jekyll?(@path)
end end
@ -27,21 +29,21 @@ class SiteTest < ActiveSupport::TestCase
test 'No podemos poner órdenes arbitrarios' do test 'No podemos poner órdenes arbitrarios' do
total = @site.posts.count total = @site.posts.count
new_order = Hash[total.times.map { |i| [i.to_s,rand(total)] }] new_order = Hash[total.times.map { |i| [i.to_s, rand(total)] }]
assert_not @site.reorder_collection('posts', new_order) assert_not @site.reorder_collection('posts', new_order)
end end
test 'Si les damos un orden alternativo los reordenamos' do test 'Si les damos un orden alternativo los reordenamos' do
total = @site.posts.count total = @site.posts.count
order = total.times.map { |i| i.to_s } order = total.times.map(&:to_s)
new_order = Hash[order.zip(order.shuffle)] new_order = Hash[order.zip(order.shuffle)]
assert @site.reorder_collection('posts', new_order) assert @site.reorder_collection('posts', new_order)
# podemos hacer este test porque reordenar los posts no ordena el # podemos hacer este test porque reordenar los posts no ordena el
# array # array
new_order.each do |k,v| new_order.each do |k, v|
v = v.to_i v = v.to_i
k = k.to_i k = k.to_i
assert_equal v, @site.posts[k].order assert_equal v, @site.posts[k].order
@ -50,14 +52,14 @@ class SiteTest < ActiveSupport::TestCase
test 'Podemos reordenar solo una parte de los artículos' do test 'Podemos reordenar solo una parte de los artículos' do
total = @site.posts.count total = @site.posts.count
order = (total - rand(total - 1)).times.map { |i| i.to_s } order = (total - rand(total - 1)).times.map(&:to_s)
new_order = Hash[order.zip(order.shuffle)] new_order = Hash[order.zip(order.shuffle)]
assert @site.reorder_collection('posts', new_order) assert @site.reorder_collection('posts', new_order)
# podemos hacer este test porque reordenar los posts no ordena el # podemos hacer este test porque reordenar los posts no ordena el
# array # array
new_order.each do |k,v| new_order.each do |k, v|
v = v.to_i v = v.to_i
k = k.to_i k = k.to_i
assert_equal v, @site.posts[k].order assert_equal v, @site.posts[k].order
@ -75,7 +77,7 @@ class SiteTest < ActiveSupport::TestCase
test 'El sitio tiene layouts' do test 'El sitio tiene layouts' do
assert_equal %w[anexo archive default feed header.ar header.en assert_equal %w[anexo archive default feed header.ar header.en
header.es header license.ar license.en license.es license pandoc header.es header license.ar license.en license.es license pandoc
politicas sesion simple style ].sort, @site.layouts politicas sesion simple style ].sort, @site.layouts
end end
end end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'test_helper' require 'test_helper'
class UsuariaTest < ActiveSupport::TestCase class UsuariaTest < ActiveSupport::TestCase
@ -6,11 +8,11 @@ class UsuariaTest < ActiveSupport::TestCase
@usuaria = Usuaria.find(@mail) @usuaria = Usuaria.find(@mail)
end end
test "La usuaria puede encontrarse por su mail" do test 'La usuaria puede encontrarse por su mail' do
assert_equal @mail, @usuaria.username assert_equal @mail, @usuaria.username
end end
test "La usuaria tiene sitios" do test 'La usuaria tiene sitios' do
@usuaria.sites.each do |s| @usuaria.sites.each do |s|
assert_equal Site, s.class assert_equal Site, s.class
end end

View file

@ -1,4 +1,6 @@
require File.expand_path('../../config/environment', __FILE__) # frozen_string_literal: true
require File.expand_path('../config/environment', __dir__)
require 'rails/test_help' require 'rails/test_help'
require 'open3' require 'open3'
@ -6,7 +8,7 @@ class ActiveSupport::TestCase
# Resetear el repositorio a su estado original antes de leerlo # Resetear el repositorio a su estado original antes de leerlo
def reset_git_repo(path) def reset_git_repo(path)
Dir.chdir(path) do Dir.chdir(path) do
Open3::popen3('git reset --hard') do |_, _, _, thread| Open3.popen3('git reset --hard') do |_, _, _, thread|
# Wait for the process to finish # Wait for the process to finish
thread.value thread.value
end end