mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-17 06:36:22 +00:00
Merge branch 'rails' into prosemirror
This commit is contained in:
commit
97bf535e24
35 changed files with 679 additions and 173 deletions
|
@ -1 +1,2 @@
|
||||||
*/**/*.rb
|
*/**/*.rb
|
||||||
|
*/**/*.yml
|
||||||
|
|
9
Gemfile
9
Gemfile
|
@ -52,6 +52,8 @@ gem 'hiredis'
|
||||||
gem 'image_processing'
|
gem 'image_processing'
|
||||||
gem 'inline_svg'
|
gem 'inline_svg'
|
||||||
gem 'jekyll'
|
gem 'jekyll'
|
||||||
|
gem 'jekyll-data', require: 'jekyll-data',
|
||||||
|
git: 'https://0xacab.org/sutty/jekyll/jekyll-data.git'
|
||||||
gem 'mini_magick'
|
gem 'mini_magick'
|
||||||
gem 'mobility'
|
gem 'mobility'
|
||||||
gem 'pg'
|
gem 'pg'
|
||||||
|
@ -60,7 +62,6 @@ gem 'rails-i18n'
|
||||||
gem 'rails_warden'
|
gem 'rails_warden'
|
||||||
gem 'redis', require: %w[redis redis/connection/hiredis]
|
gem 'redis', require: %w[redis redis/connection/hiredis]
|
||||||
gem 'redis-rails'
|
gem 'redis-rails'
|
||||||
gem 'reverse_markdown', git: 'https://0xacab.org/sutty/reverse_markdown.git'
|
|
||||||
gem 'rubyzip'
|
gem 'rubyzip'
|
||||||
gem 'rugged'
|
gem 'rugged'
|
||||||
gem 'sucker_punch'
|
gem 'sucker_punch'
|
||||||
|
@ -69,6 +70,12 @@ gem 'validates_hostname'
|
||||||
gem 'webpacker'
|
gem 'webpacker'
|
||||||
gem 'yaml_db', git: 'https://0xacab.org/sutty/yaml_db.git'
|
gem 'yaml_db', git: 'https://0xacab.org/sutty/yaml_db.git'
|
||||||
|
|
||||||
|
group :themes do
|
||||||
|
gem 'editorial-autogestiva-jekyll-theme', require: false
|
||||||
|
gem 'minima', require: false
|
||||||
|
gem 'sutty-jekyll-theme', require: false
|
||||||
|
end
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
gem 'pry'
|
gem 'pry'
|
||||||
# Adds support for Capybara system testing and selenium driver
|
# Adds support for Capybara system testing and selenium driver
|
||||||
|
|
236
Gemfile.lock
236
Gemfile.lock
|
@ -1,9 +1,9 @@
|
||||||
GIT
|
GIT
|
||||||
remote: https://0xacab.org/sutty/reverse_markdown.git
|
remote: https://0xacab.org/sutty/jekyll/jekyll-data.git
|
||||||
revision: 5c243096669aa77e0dc173dec8006b4c5fe07683
|
revision: 1ad9c175be6bbb31ae6d19cbb8dde18828af90d9
|
||||||
specs:
|
specs:
|
||||||
reverse_markdown (1.2.0)
|
jekyll-data (1.1.0)
|
||||||
nokogiri
|
jekyll (>= 3.3, < 5.0.0)
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
remote: https://0xacab.org/sutty/yaml_db.git
|
remote: https://0xacab.org/sutty/yaml_db.git
|
||||||
|
@ -16,56 +16,56 @@ GIT
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (6.0.2.1)
|
actioncable (6.0.2.2)
|
||||||
actionpack (= 6.0.2.1)
|
actionpack (= 6.0.2.2)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
actionmailbox (6.0.2.1)
|
actionmailbox (6.0.2.2)
|
||||||
actionpack (= 6.0.2.1)
|
actionpack (= 6.0.2.2)
|
||||||
activejob (= 6.0.2.1)
|
activejob (= 6.0.2.2)
|
||||||
activerecord (= 6.0.2.1)
|
activerecord (= 6.0.2.2)
|
||||||
activestorage (= 6.0.2.1)
|
activestorage (= 6.0.2.2)
|
||||||
activesupport (= 6.0.2.1)
|
activesupport (= 6.0.2.2)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.7.1)
|
||||||
actionmailer (6.0.2.1)
|
actionmailer (6.0.2.2)
|
||||||
actionpack (= 6.0.2.1)
|
actionpack (= 6.0.2.2)
|
||||||
actionview (= 6.0.2.1)
|
actionview (= 6.0.2.2)
|
||||||
activejob (= 6.0.2.1)
|
activejob (= 6.0.2.2)
|
||||||
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.2.1)
|
actionpack (6.0.2.2)
|
||||||
actionview (= 6.0.2.1)
|
actionview (= 6.0.2.2)
|
||||||
activesupport (= 6.0.2.1)
|
activesupport (= 6.0.2.2)
|
||||||
rack (~> 2.0, >= 2.0.8)
|
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.2.1)
|
actiontext (6.0.2.2)
|
||||||
actionpack (= 6.0.2.1)
|
actionpack (= 6.0.2.2)
|
||||||
activerecord (= 6.0.2.1)
|
activerecord (= 6.0.2.2)
|
||||||
activestorage (= 6.0.2.1)
|
activestorage (= 6.0.2.2)
|
||||||
activesupport (= 6.0.2.1)
|
activesupport (= 6.0.2.2)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (6.0.2.1)
|
actionview (6.0.2.2)
|
||||||
activesupport (= 6.0.2.1)
|
activesupport (= 6.0.2.2)
|
||||||
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.2.1)
|
activejob (6.0.2.2)
|
||||||
activesupport (= 6.0.2.1)
|
activesupport (= 6.0.2.2)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (6.0.2.1)
|
activemodel (6.0.2.2)
|
||||||
activesupport (= 6.0.2.1)
|
activesupport (= 6.0.2.2)
|
||||||
activerecord (6.0.2.1)
|
activerecord (6.0.2.2)
|
||||||
activemodel (= 6.0.2.1)
|
activemodel (= 6.0.2.2)
|
||||||
activesupport (= 6.0.2.1)
|
activesupport (= 6.0.2.2)
|
||||||
activestorage (6.0.2.1)
|
activestorage (6.0.2.2)
|
||||||
actionpack (= 6.0.2.1)
|
actionpack (= 6.0.2.2)
|
||||||
activejob (= 6.0.2.1)
|
activejob (= 6.0.2.2)
|
||||||
activerecord (= 6.0.2.1)
|
activerecord (= 6.0.2.2)
|
||||||
marcel (~> 0.3.1)
|
marcel (~> 0.3.1)
|
||||||
activesupport (6.0.2.1)
|
activesupport (6.0.2.2)
|
||||||
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)
|
||||||
|
@ -74,7 +74,7 @@ GEM
|
||||||
addressable (2.7.0)
|
addressable (2.7.0)
|
||||||
public_suffix (>= 2.0.2, < 5.0)
|
public_suffix (>= 2.0.2, < 5.0)
|
||||||
ast (2.4.0)
|
ast (2.4.0)
|
||||||
autoprefixer-rails (9.7.3)
|
autoprefixer-rails (9.7.4)
|
||||||
execjs
|
execjs
|
||||||
bcrypt (3.1.13)
|
bcrypt (3.1.13)
|
||||||
bcrypt_pbkdf (1.0.1)
|
bcrypt_pbkdf (1.0.1)
|
||||||
|
@ -88,7 +88,7 @@ GEM
|
||||||
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)
|
||||||
brakeman (4.7.2)
|
brakeman (4.8.0)
|
||||||
builder (3.2.4)
|
builder (3.2.4)
|
||||||
capybara (2.18.0)
|
capybara (2.18.0)
|
||||||
addressable
|
addressable
|
||||||
|
@ -101,11 +101,11 @@ GEM
|
||||||
childprocess (3.0.0)
|
childprocess (3.0.0)
|
||||||
coderay (1.1.2)
|
coderay (1.1.2)
|
||||||
colorator (1.1.0)
|
colorator (1.1.0)
|
||||||
commonmarker (0.20.2)
|
commonmarker (0.21.0)
|
||||||
ruby-enum (~> 0.5)
|
ruby-enum (~> 0.5)
|
||||||
concurrent-ruby (1.1.5)
|
concurrent-ruby (1.1.6)
|
||||||
crass (1.0.5)
|
crass (1.0.6)
|
||||||
database_cleaner (1.7.0)
|
database_cleaner (1.8.3)
|
||||||
devise (4.7.1)
|
devise (4.7.1)
|
||||||
bcrypt (~> 3.0)
|
bcrypt (~> 3.0)
|
||||||
orm_adapter (~> 0.1)
|
orm_adapter (~> 0.1)
|
||||||
|
@ -122,10 +122,19 @@ GEM
|
||||||
dotenv (= 2.7.5)
|
dotenv (= 2.7.5)
|
||||||
railties (>= 3.2, < 6.1)
|
railties (>= 3.2, < 6.1)
|
||||||
ed25519 (1.2.4)
|
ed25519 (1.2.4)
|
||||||
|
editorial-autogestiva-jekyll-theme (0.2.2)
|
||||||
|
jekyll (~> 4.0)
|
||||||
|
jekyll-data (~> 1.1)
|
||||||
|
jekyll-feed (~> 0.9)
|
||||||
|
jekyll-images (~> 0.2)
|
||||||
|
jekyll-include-cache (~> 0)
|
||||||
|
jekyll-locales (~> 0.1)
|
||||||
|
jekyll-relative-urls (~> 0.0)
|
||||||
|
jekyll-seo-tag (~> 2.1)
|
||||||
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.12)
|
email_address (0.1.15)
|
||||||
netaddr (>= 2.0.4, < 3)
|
netaddr (>= 2.0.4, < 3)
|
||||||
simpleidn
|
simpleidn
|
||||||
errbase (0.2.0)
|
errbase (0.2.0)
|
||||||
|
@ -140,7 +149,7 @@ GEM
|
||||||
factory_bot_rails (5.1.1)
|
factory_bot_rails (5.1.1)
|
||||||
factory_bot (~> 5.1.0)
|
factory_bot (~> 5.1.0)
|
||||||
railties (>= 4.2.0)
|
railties (>= 4.2.0)
|
||||||
ffi (1.11.3)
|
ffi (1.12.2)
|
||||||
forwardable-extended (2.6.0)
|
forwardable-extended (2.6.0)
|
||||||
friendly_id (5.3.0)
|
friendly_id (5.3.0)
|
||||||
activerecord (>= 4.0.0)
|
activerecord (>= 4.0.0)
|
||||||
|
@ -151,7 +160,7 @@ GEM
|
||||||
tilt
|
tilt
|
||||||
haml-lint (0.999.999)
|
haml-lint (0.999.999)
|
||||||
haml_lint
|
haml_lint
|
||||||
haml_lint (0.34.1)
|
haml_lint (0.35.0)
|
||||||
haml (>= 4.0, < 5.2)
|
haml (>= 4.0, < 5.2)
|
||||||
rainbow
|
rainbow
|
||||||
rubocop (>= 0.50.0)
|
rubocop (>= 0.50.0)
|
||||||
|
@ -167,17 +176,17 @@ GEM
|
||||||
railties (>= 4.0.1)
|
railties (>= 4.0.1)
|
||||||
hiredis (0.6.3)
|
hiredis (0.6.3)
|
||||||
http_parser.rb (0.6.0)
|
http_parser.rb (0.6.0)
|
||||||
i18n (1.7.0)
|
i18n (1.8.2)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
image_processing (1.10.0)
|
image_processing (1.10.3)
|
||||||
mini_magick (>= 4.9.5, < 5)
|
mini_magick (>= 4.9.5, < 5)
|
||||||
ruby-vips (>= 2.0.13, < 3)
|
ruby-vips (>= 2.0.17, < 3)
|
||||||
inline_svg (1.6.0)
|
inline_svg (1.7.1)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
nokogiri (>= 1.6)
|
nokogiri (>= 1.6)
|
||||||
jaro_winkler (1.5.4)
|
jaro_winkler (1.5.4)
|
||||||
jbuilder (2.9.1)
|
jbuilder (2.10.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 5.0.0)
|
||||||
jekyll (4.0.0)
|
jekyll (4.0.0)
|
||||||
addressable (~> 2.4)
|
addressable (~> 2.4)
|
||||||
colorator (~> 1.0)
|
colorator (~> 1.0)
|
||||||
|
@ -193,15 +202,27 @@ 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.1)
|
jekyll-feed (0.13.0)
|
||||||
|
jekyll (>= 3.7, < 5.0)
|
||||||
|
jekyll-images (0.2.3)
|
||||||
|
ruby-filemagic (~> 0.7)
|
||||||
|
ruby-vips (~> 2)
|
||||||
|
jekyll-include-cache (0.2.0)
|
||||||
|
jekyll (>= 3.7, < 5.0)
|
||||||
|
jekyll-locales (0.1.7)
|
||||||
|
jekyll-relative-urls (0.0.5)
|
||||||
|
jekyll (>= 3.8, < 5)
|
||||||
|
jekyll-sass-converter (2.1.0)
|
||||||
sassc (> 2.0.1, < 3.0)
|
sassc (> 2.0.1, < 3.0)
|
||||||
|
jekyll-seo-tag (2.6.1)
|
||||||
|
jekyll (>= 3.3, < 5.0)
|
||||||
jekyll-watch (2.2.1)
|
jekyll-watch (2.2.1)
|
||||||
listen (~> 3.0)
|
listen (~> 3.0)
|
||||||
kramdown (2.1.0)
|
kramdown (2.1.0)
|
||||||
kramdown-parser-gfm (1.1.0)
|
kramdown-parser-gfm (1.1.0)
|
||||||
kramdown (~> 2.0)
|
kramdown (~> 2.0)
|
||||||
launchy (2.4.3)
|
launchy (2.5.0)
|
||||||
addressable (~> 2.3)
|
addressable (~> 2.7)
|
||||||
letter_opener (1.7.0)
|
letter_opener (1.7.0)
|
||||||
launchy (~> 2.2)
|
launchy (~> 2.2)
|
||||||
liquid (4.0.3)
|
liquid (4.0.3)
|
||||||
|
@ -218,31 +239,35 @@ GEM
|
||||||
mimemagic (~> 0.3.2)
|
mimemagic (~> 0.3.2)
|
||||||
mercenary (0.3.6)
|
mercenary (0.3.6)
|
||||||
method_source (0.9.2)
|
method_source (0.9.2)
|
||||||
mimemagic (0.3.3)
|
mimemagic (0.3.4)
|
||||||
mini_magick (4.9.5)
|
mini_magick (4.10.1)
|
||||||
mini_mime (1.0.2)
|
mini_mime (1.0.2)
|
||||||
mini_portile2 (2.4.0)
|
mini_portile2 (2.4.0)
|
||||||
minitest (5.13.0)
|
minima (2.5.1)
|
||||||
mobility (0.8.9)
|
jekyll (>= 3.5, < 5.0)
|
||||||
|
jekyll-feed (~> 0.9)
|
||||||
|
jekyll-seo-tag (~> 2.1)
|
||||||
|
minitest (5.14.0)
|
||||||
|
mobility (0.8.10)
|
||||||
i18n (>= 0.6.10, < 2)
|
i18n (>= 0.6.10, < 2)
|
||||||
request_store (~> 1.0)
|
request_store (~> 1.0)
|
||||||
netaddr (2.0.4)
|
netaddr (2.0.4)
|
||||||
nio4r (2.5.2)
|
nio4r (2.5.2)
|
||||||
nokogiri (1.10.7)
|
nokogiri (1.10.9)
|
||||||
mini_portile2 (~> 2.4.0)
|
mini_portile2 (~> 2.4.0)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
parallel (1.19.1)
|
parallel (1.19.1)
|
||||||
parser (2.7.0.1)
|
parser (2.7.0.4)
|
||||||
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.2.0)
|
pg (1.2.3)
|
||||||
popper_js (1.14.5)
|
popper_js (1.16.0)
|
||||||
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.2)
|
public_suffix (4.0.3)
|
||||||
puma (4.3.1)
|
puma (4.3.3)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
pundit (2.1.0)
|
pundit (2.1.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
|
@ -251,20 +276,20 @@ GEM
|
||||||
rack
|
rack
|
||||||
rack-test (1.1.0)
|
rack-test (1.1.0)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rails (6.0.2.1)
|
rails (6.0.2.2)
|
||||||
actioncable (= 6.0.2.1)
|
actioncable (= 6.0.2.2)
|
||||||
actionmailbox (= 6.0.2.1)
|
actionmailbox (= 6.0.2.2)
|
||||||
actionmailer (= 6.0.2.1)
|
actionmailer (= 6.0.2.2)
|
||||||
actionpack (= 6.0.2.1)
|
actionpack (= 6.0.2.2)
|
||||||
actiontext (= 6.0.2.1)
|
actiontext (= 6.0.2.2)
|
||||||
actionview (= 6.0.2.1)
|
actionview (= 6.0.2.2)
|
||||||
activejob (= 6.0.2.1)
|
activejob (= 6.0.2.2)
|
||||||
activemodel (= 6.0.2.1)
|
activemodel (= 6.0.2.2)
|
||||||
activerecord (= 6.0.2.1)
|
activerecord (= 6.0.2.2)
|
||||||
activestorage (= 6.0.2.1)
|
activestorage (= 6.0.2.2)
|
||||||
activesupport (= 6.0.2.1)
|
activesupport (= 6.0.2.2)
|
||||||
bundler (>= 1.3.0)
|
bundler (>= 1.3.0)
|
||||||
railties (= 6.0.2.1)
|
railties (= 6.0.2.2)
|
||||||
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)
|
||||||
|
@ -276,9 +301,9 @@ 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.2.1)
|
railties (6.0.2.2)
|
||||||
actionpack (= 6.0.2.1)
|
actionpack (= 6.0.2.2)
|
||||||
activesupport (= 6.0.2.1)
|
activesupport (= 6.0.2.2)
|
||||||
method_source
|
method_source
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.8.7)
|
||||||
thor (>= 0.20.3, < 2.0)
|
thor (>= 0.20.3, < 2.0)
|
||||||
|
@ -290,46 +315,49 @@ GEM
|
||||||
rbnacl (4.0.2)
|
rbnacl (4.0.2)
|
||||||
ffi
|
ffi
|
||||||
redis (4.1.3)
|
redis (4.1.3)
|
||||||
redis-actionpack (5.1.0)
|
redis-actionpack (5.2.0)
|
||||||
actionpack (>= 4.0, < 7)
|
actionpack (>= 5, < 7)
|
||||||
redis-rack (>= 1, < 3)
|
redis-rack (>= 2.1.0, < 3)
|
||||||
redis-store (>= 1.1.0, < 2)
|
redis-store (>= 1.1.0, < 2)
|
||||||
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.6)
|
redis-rack (2.1.2)
|
||||||
rack (>= 1.5, < 3)
|
rack (>= 2.0.8, < 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.8.1)
|
redis-store (1.8.2)
|
||||||
redis (>= 4, < 5)
|
redis (>= 4, < 5)
|
||||||
request_store (1.5.0)
|
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.14.0)
|
rexml (3.2.4)
|
||||||
rubocop (0.78.0)
|
rouge (3.17.0)
|
||||||
|
rubocop (0.80.1)
|
||||||
jaro_winkler (~> 1.5.1)
|
jaro_winkler (~> 1.5.1)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 2.6)
|
parser (>= 2.7.0.1)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
|
rexml
|
||||||
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.4.1)
|
rubocop-rails (2.4.2)
|
||||||
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-filemagic (0.7.2)
|
||||||
ruby-progressbar (1.10.1)
|
ruby-progressbar (1.10.1)
|
||||||
ruby-vips (2.0.16)
|
ruby-vips (2.0.17)
|
||||||
ffi (~> 1.9)
|
ffi (~> 1.9)
|
||||||
ruby_dep (1.5.0)
|
ruby_dep (1.5.0)
|
||||||
rubyzip (2.0.0)
|
rubyzip (2.3.0)
|
||||||
rugged (0.28.4.1)
|
rugged (0.99.0)
|
||||||
safe_yaml (1.0.5)
|
safe_yaml (1.0.5)
|
||||||
safely_block (0.3.0)
|
safely_block (0.3.0)
|
||||||
errbase (>= 0.1.1)
|
errbase (>= 0.1.1)
|
||||||
|
@ -360,6 +388,13 @@ GEM
|
||||||
sqlite3 (1.4.2)
|
sqlite3 (1.4.2)
|
||||||
sucker_punch (2.1.2)
|
sucker_punch (2.1.2)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
|
sutty-jekyll-theme (0.1.0)
|
||||||
|
jekyll (~> 4.0)
|
||||||
|
jekyll-feed (~> 0.9)
|
||||||
|
jekyll-images (~> 0.2)
|
||||||
|
jekyll-include-cache (~> 0)
|
||||||
|
jekyll-relative-urls (~> 0.0)
|
||||||
|
jekyll-seo-tag (~> 2.1)
|
||||||
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)
|
||||||
|
@ -378,8 +413,8 @@ GEM
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
unf_ext (0.0.7.6)
|
unf_ext (0.0.7.6)
|
||||||
unicode-display_width (1.6.0)
|
unicode-display_width (1.6.1)
|
||||||
validates_hostname (1.0.8)
|
validates_hostname (1.0.10)
|
||||||
activerecord (>= 3.0)
|
activerecord (>= 3.0)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
warden (1.2.8)
|
warden (1.2.8)
|
||||||
|
@ -398,7 +433,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.2)
|
zeitwerk (2.3.0)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
@ -417,6 +452,7 @@ DEPENDENCIES
|
||||||
devise_invitable
|
devise_invitable
|
||||||
dotenv-rails
|
dotenv-rails
|
||||||
ed25519
|
ed25519
|
||||||
|
editorial-autogestiva-jekyll-theme
|
||||||
email_address
|
email_address
|
||||||
exception_notification
|
exception_notification
|
||||||
factory_bot_rails
|
factory_bot_rails
|
||||||
|
@ -428,9 +464,11 @@ DEPENDENCIES
|
||||||
inline_svg
|
inline_svg
|
||||||
jbuilder (~> 2.5)
|
jbuilder (~> 2.5)
|
||||||
jekyll
|
jekyll
|
||||||
|
jekyll-data!
|
||||||
letter_opener
|
letter_opener
|
||||||
listen (>= 3.0.5, < 3.2)
|
listen (>= 3.0.5, < 3.2)
|
||||||
mini_magick
|
mini_magick
|
||||||
|
minima
|
||||||
mobility
|
mobility
|
||||||
pg
|
pg
|
||||||
pry
|
pry
|
||||||
|
@ -442,7 +480,6 @@ DEPENDENCIES
|
||||||
rbnacl (< 5.0)
|
rbnacl (< 5.0)
|
||||||
redis
|
redis
|
||||||
redis-rails
|
redis-rails
|
||||||
reverse_markdown!
|
|
||||||
rubocop-rails
|
rubocop-rails
|
||||||
rubyzip
|
rubyzip
|
||||||
rugged
|
rugged
|
||||||
|
@ -452,6 +489,7 @@ DEPENDENCIES
|
||||||
spring-watcher-listen (~> 2.0.0)
|
spring-watcher-listen (~> 2.0.0)
|
||||||
sqlite3
|
sqlite3
|
||||||
sucker_punch
|
sucker_punch
|
||||||
|
sutty-jekyll-theme
|
||||||
terminal-table
|
terminal-table
|
||||||
timecop
|
timecop
|
||||||
turbolinks (~> 5)
|
turbolinks (~> 5)
|
||||||
|
|
|
@ -308,3 +308,13 @@ svg {
|
||||||
background-color: $cyan;
|
background-color: $cyan;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.custom-control-label {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.designs {
|
||||||
|
.design {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,12 @@ module Api
|
||||||
class BaseController < ActionController::Base
|
class BaseController < ActionController::Base
|
||||||
protect_from_forgery with: :null_session
|
protect_from_forgery with: :null_session
|
||||||
respond_to :json
|
respond_to :json
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def origin
|
||||||
|
request.headers['Origin']
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
102
app/controllers/api/v1/contact_controller.rb
Normal file
102
app/controllers/api/v1/contact_controller.rb
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
# API para formulario de contacto
|
||||||
|
class ContactController < BaseController
|
||||||
|
# Aplicar algunos chequeos básicos. Deberíamos registrar de
|
||||||
|
# alguna forma los errores pero tampoco queremos que nos usen
|
||||||
|
# recursos.
|
||||||
|
#
|
||||||
|
# TODO: Agregar los mismos chequeos que en PostsController
|
||||||
|
before_action :site_exists?, unless: :performed?
|
||||||
|
before_action :site_is_origin?, unless: :performed?
|
||||||
|
before_action :from_is_address?, unless: :performed?
|
||||||
|
before_action :gave_consent?, unless: :performed?
|
||||||
|
|
||||||
|
# Recibe un mensaje a través del formulario de contacto y lo envía
|
||||||
|
# a les usuaries del sitio.
|
||||||
|
#
|
||||||
|
# Tenemos que verificar que el sitio exista y que algunos campos
|
||||||
|
# estén llenos para detener spambots o DDOS. También nos vamos a
|
||||||
|
# estar apoyando en la limitación de peticiones en el servidor web.
|
||||||
|
def receive
|
||||||
|
# No hacer nada si no se pasaron los chequeos
|
||||||
|
return if performed?
|
||||||
|
|
||||||
|
# Si todo salió bien, enviar los correos y redirigir al sitio.
|
||||||
|
# El sitio nos dice a dónde tenemos que ir.
|
||||||
|
ContactJob.perform_async site_id: site.id,
|
||||||
|
**contact_params.to_h.symbolize_keys
|
||||||
|
|
||||||
|
redirect_to contact_params[:redirect] || site.url
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Comprueba que el sitio existe
|
||||||
|
#
|
||||||
|
# TODO: Responder con una zip bomb!
|
||||||
|
def site_exists?
|
||||||
|
render html: body(:site_exists), status: status unless site
|
||||||
|
end
|
||||||
|
|
||||||
|
# Comprueba que el mensaje vino fue enviado desde el sitio
|
||||||
|
def site_is_origin?
|
||||||
|
return if origin.to_s == site.url
|
||||||
|
|
||||||
|
render html: body(:site_is_origin), status: status
|
||||||
|
end
|
||||||
|
|
||||||
|
# Detecta si la dirección de contacto es válida. Además es
|
||||||
|
# opcional.
|
||||||
|
def from_is_address?
|
||||||
|
return unless contact_params[:from]
|
||||||
|
return if EmailAddress.valid? contact_params[:from]
|
||||||
|
|
||||||
|
render html: body(:from_is_address), status: status
|
||||||
|
end
|
||||||
|
|
||||||
|
# No aceptar nada si no dió su consentimiento
|
||||||
|
def gave_consent?
|
||||||
|
return if contact_params[:gdpr].present?
|
||||||
|
|
||||||
|
render html: body(:gave_consent), status: status
|
||||||
|
end
|
||||||
|
|
||||||
|
# Realiza la inversa de Site#hostname
|
||||||
|
def site_id
|
||||||
|
@site_id ||= if params[:site_id].end_with? Site.domain
|
||||||
|
params[:site_id].gsub(/\.#{Site.domain}\z/, '')
|
||||||
|
else
|
||||||
|
"#{params[:site_id]}."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Encuentra el sitio
|
||||||
|
def site
|
||||||
|
@site ||= Site.find_by(name: site_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parámetros limpios
|
||||||
|
def contact_params
|
||||||
|
@contact_params ||= params.permit(:gdpr, :name, :pronouns, :from,
|
||||||
|
:contact, :body, :redirect)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Para poder testear, enviamos un mensaje en el cuerpo de la
|
||||||
|
# respuesta
|
||||||
|
#
|
||||||
|
# @param [Any] el mensaje
|
||||||
|
def body(message)
|
||||||
|
return message.to_s if Rails.env.test?
|
||||||
|
end
|
||||||
|
|
||||||
|
# No queremos informar nada a los spammers, pero en testeo
|
||||||
|
# queremos saber por qué. :no_content oculta el cuerpo.
|
||||||
|
def status
|
||||||
|
Rails.env.test? ? :unprocessable_entity : :no_content
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,21 +11,21 @@ class PostsController < ApplicationController
|
||||||
@category = session[:category] = params.dig(:category)
|
@category = session[:category] = params.dig(:category)
|
||||||
@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: lang)
|
||||||
@posts.sort_by!(:order, :date).reverse!
|
@posts.sort_by!(:order, :date).reverse!
|
||||||
@usuarie = @site.usuarie? current_usuarie
|
@usuarie = @site.usuarie? current_usuarie
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@site = find_site
|
@site = find_site
|
||||||
@post = @site.posts.find params[:id]
|
@post = @site.posts(lang: lang).find params[:id]
|
||||||
authorize @post
|
authorize @post
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
authorize Post
|
authorize Post
|
||||||
@site = find_site
|
@site = find_site
|
||||||
@post = @site.posts.build(lang: I18n.locale, layout: params[:layout])
|
@post = @site.posts.build(lang: lang, layout: params[:layout])
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
@ -44,14 +44,14 @@ class PostsController < ApplicationController
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
@site = find_site
|
@site = find_site
|
||||||
@post = @site.posts.find params[:id]
|
@post = @site.posts(lang: lang).find params[:id]
|
||||||
|
|
||||||
authorize @post
|
authorize @post
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@site = find_site
|
@site = find_site
|
||||||
@post = @site.posts.find params[:id]
|
@post = @site.posts(lang: lang).find params[:id]
|
||||||
|
|
||||||
authorize @post
|
authorize @post
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ class PostsController < ApplicationController
|
||||||
# Eliminar artículos
|
# Eliminar artículos
|
||||||
def destroy
|
def destroy
|
||||||
@site = find_site
|
@site = find_site
|
||||||
@post = @site.posts.find params[:id]
|
@post = @site.posts(lang: lang).find params[:id]
|
||||||
|
|
||||||
authorize @post
|
authorize @post
|
||||||
|
|
||||||
|
@ -96,4 +96,13 @@ class PostsController < ApplicationController
|
||||||
service.reorder
|
service.reorder
|
||||||
redirect_to site_posts_path(@site)
|
redirect_to site_posts_path(@site)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Devuelve el idioma solicitado a través de un parámetro, validando
|
||||||
|
# que el sitio soporte ese idioma
|
||||||
|
def lang
|
||||||
|
return unless params[:lang]
|
||||||
|
return unless @site.try(:locales).try(:include?, params[:lang])
|
||||||
|
|
||||||
|
params[:lang]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
34
app/jobs/contact_job.rb
Normal file
34
app/jobs/contact_job.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Envía los mensajes de contacto
|
||||||
|
class ContactJob < ApplicationJob
|
||||||
|
def perform(**args)
|
||||||
|
@params = args
|
||||||
|
|
||||||
|
# Enviar de a 10 usuaries para minimizar el riesgo que nos
|
||||||
|
# consideren spammers.
|
||||||
|
#
|
||||||
|
# TODO: #i18n. Agrupar usuaries por su idioma
|
||||||
|
|
||||||
|
usuaries.each_slice(10) do |u|
|
||||||
|
ContactMailer.with(**args.merge(usuaries: u, title: site.title))
|
||||||
|
.notify_usuaries.deliver_now
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def site
|
||||||
|
@site ||= Site.find @params[:site_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Trae solo les usuaries definitives para eliminar un vector de ataque
|
||||||
|
# donde alguien crea un sitio, agrega a muches usuaries y les envía
|
||||||
|
# correos.
|
||||||
|
#
|
||||||
|
# TODO: Mover a Site#usuaries
|
||||||
|
def usuaries
|
||||||
|
site.roles.where(rol: 'usuarie', temporal: false).includes(:usuarie)
|
||||||
|
.pluck(:email)
|
||||||
|
end
|
||||||
|
end
|
|
@ -45,9 +45,8 @@ class DeployJob < ApplicationJob
|
||||||
end
|
end
|
||||||
|
|
||||||
def notify_usuaries
|
def notify_usuaries
|
||||||
# TODO: existe site.usuaries_ids?
|
@site.roles.where(rol: 'usuarie', temporal: false).pluck(:usuaries_id).each do |usuarie|
|
||||||
@site.usuaries.find_each do |usuarie|
|
DeployMailer.with(usuarie: usuarie, site: @site.id)
|
||||||
DeployMailer.with(usuarie: usuarie.id, site: @site.id)
|
|
||||||
.deployed(@deployed)
|
.deployed(@deployed)
|
||||||
.deliver_now
|
.deliver_now
|
||||||
end
|
end
|
||||||
|
|
11
app/mailers/contact_mailer.rb
Normal file
11
app/mailers/contact_mailer.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Formulario de contacto
|
||||||
|
class ContactMailer < ApplicationMailer
|
||||||
|
# Enviar el formulario de contacto a les usuaries
|
||||||
|
def notify_usuaries
|
||||||
|
mail to: params[:usuaries],
|
||||||
|
reply_to: params[:from],
|
||||||
|
subject: I18n.t('contact_mailer.subject', site: params[:title])
|
||||||
|
end
|
||||||
|
end
|
|
@ -15,14 +15,14 @@ class MetadataBoolean < MetadataTemplate
|
||||||
# En este caso, queremos priorizar el dato enviado por le usuarie
|
# En este caso, queremos priorizar el dato enviado por le usuarie
|
||||||
# antes que el generado internamente.
|
# antes que el generado internamente.
|
||||||
def value
|
def value
|
||||||
return false if false?
|
return false if self[:value] == '0'
|
||||||
|
return self[:value] unless self[:value].nil?
|
||||||
|
|
||||||
self[:value].present? || document.data.fetch(name.to_s, default_value)
|
document.data.fetch(name.to_s, default_value)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
def save
|
||||||
|
self[:value] = !%w[0 false].include?(self[:value])
|
||||||
def false?
|
true
|
||||||
self[:value] == '0'
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
15
app/models/metadata_number.rb
Normal file
15
app/models/metadata_number.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Un campo numérico
|
||||||
|
class MetadataNumber < MetadataTemplate
|
||||||
|
# Nada
|
||||||
|
def default_value
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def save
|
||||||
|
self[:value] = value.to_i
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
|
@ -21,6 +21,9 @@ class MetadataPath < MetadataTemplate
|
||||||
File.basename(value, ext)
|
File.basename(value, ext)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# No lo aceptamos en los parámetros
|
||||||
|
def to_param; end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def ext
|
def ext
|
||||||
|
|
10
app/models/metadata_predefined_array.rb
Normal file
10
app/models/metadata_predefined_array.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Una lista de valores predefinidos
|
||||||
|
class MetadataPredefinedArray < MetadataArray
|
||||||
|
def values
|
||||||
|
@values ||= layout[:metadata][name]['values'].map do |k, v|
|
||||||
|
{ v[I18n.locale.to_s] => k }
|
||||||
|
end.inject(&:merge)
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,7 +5,7 @@
|
||||||
class MetadataRelatedPosts < MetadataArray
|
class MetadataRelatedPosts < MetadataArray
|
||||||
# Genera un Hash de { title | slug => uuid }
|
# Genera un Hash de { title | slug => uuid }
|
||||||
def values
|
def values
|
||||||
site.posts(lang: lang).map do |p|
|
@values ||= site.posts(lang: lang).map do |p|
|
||||||
{ title(p) => p.uuid.value }
|
{ title(p) => p.uuid.value }
|
||||||
end.inject(:merge)
|
end.inject(:merge)
|
||||||
end
|
end
|
||||||
|
|
|
@ -69,6 +69,7 @@ class Site < ApplicationRecord
|
||||||
|
|
||||||
def hostname
|
def hostname
|
||||||
sub = name || I18n.t('deploys.deploy_local.ejemplo')
|
sub = name || I18n.t('deploys.deploy_local.ejemplo')
|
||||||
|
|
||||||
if sub.ends_with? '.'
|
if sub.ends_with? '.'
|
||||||
sub.gsub(/\.\Z/, '')
|
sub.gsub(/\.\Z/, '')
|
||||||
else
|
else
|
||||||
|
@ -123,6 +124,11 @@ class Site < ApplicationRecord
|
||||||
config.fetch('locales', I18n.available_locales.map(&:to_s))
|
config.fetch('locales', I18n.available_locales.map(&:to_s))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Similar a site.i18n en jekyll-locales
|
||||||
|
def i18n
|
||||||
|
data[I18n.locale.to_s]
|
||||||
|
end
|
||||||
|
|
||||||
# Devuelve el idioma por defecto del sitio, el primero de la lista.
|
# Devuelve el idioma por defecto del sitio, el primero de la lista.
|
||||||
def default_locale
|
def default_locale
|
||||||
locales.first
|
locales.first
|
||||||
|
@ -259,6 +265,8 @@ class Site < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def reload_jekyll!
|
def reload_jekyll!
|
||||||
|
reset
|
||||||
|
|
||||||
Dir.chdir(path) do
|
Dir.chdir(path) do
|
||||||
@jekyll = Jekyll::Site.new(jekyll_config)
|
@jekyll = Jekyll::Site.new(jekyll_config)
|
||||||
end
|
end
|
||||||
|
@ -285,10 +293,13 @@ class Site < ApplicationRecord
|
||||||
'quiet' => true, 'excerpt_separator' => '')
|
'quiet' => true, 'excerpt_separator' => '')
|
||||||
|
|
||||||
# No necesitamos cargar plugins en este momento
|
# No necesitamos cargar plugins en este momento
|
||||||
%w[plugins gems theme].each do |unneeded|
|
%w[plugins gems].each do |unneeded|
|
||||||
configuration[unneeded] = [] if configuration.key? unneeded
|
configuration[unneeded] = [] if configuration.key? unneeded
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Eliminar el theme si no es una gema válida
|
||||||
|
configuration.delete 'theme' unless theme_available?
|
||||||
|
|
||||||
# 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"
|
||||||
locales.each do |i|
|
locales.each do |i|
|
||||||
|
@ -298,6 +309,20 @@ class Site < ApplicationRecord
|
||||||
configuration
|
configuration
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Lista los nombres de las plantillas disponibles como gemas,
|
||||||
|
# tomándolas dinámicamente de las que agreguemos en el grupo :themes
|
||||||
|
# del Gemfile.
|
||||||
|
def available_themes
|
||||||
|
@available_themes ||= Bundler.load.current_dependencies.select do |gem|
|
||||||
|
gem.groups.include? :themes
|
||||||
|
end.map(&:name)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Detecta si el tema actual es una gema
|
||||||
|
def theme_available?
|
||||||
|
available_themes.include? design.gem
|
||||||
|
end
|
||||||
|
|
||||||
# Devuelve el dominio actual
|
# Devuelve el dominio actual
|
||||||
def self.domain
|
def self.domain
|
||||||
ENV.fetch('SUTTY', 'sutty.nl')
|
ENV.fetch('SUTTY', 'sutty.nl')
|
||||||
|
@ -308,6 +333,12 @@ class Site < ApplicationRecord
|
||||||
File.join(Rails.root, '_sites')
|
File.join(Rails.root, '_sites')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reset
|
||||||
|
@read = false
|
||||||
|
@layouts = nil
|
||||||
|
@layouts_struct = nil
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Clona el esqueleto de Sutty para crear el sitio nuevo, no pasa nada
|
# Clona el esqueleto de Sutty para crear el sitio nuevo, no pasa nada
|
||||||
|
@ -340,6 +371,7 @@ class Site < ApplicationRecord
|
||||||
config.description = description
|
config.description = description
|
||||||
config.title = title
|
config.title = title
|
||||||
config.url = url
|
config.url = url
|
||||||
|
config.hostname = hostname
|
||||||
end
|
end
|
||||||
|
|
||||||
# Migra los archivos a Sutty
|
# Migra los archivos a Sutty
|
||||||
|
|
|
@ -102,8 +102,19 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Devuelve el idioma solicitado a través de un parámetro, validando
|
||||||
|
# que el sitio soporte ese idioma
|
||||||
|
#
|
||||||
|
# TODO: DRY
|
||||||
def lang
|
def lang
|
||||||
params[:post][:lang] || I18n.locale
|
return unless params[:lang]
|
||||||
|
return unless site.try(:locales).try(:include?, params[:lang])
|
||||||
|
|
||||||
|
params[:lang]
|
||||||
|
end
|
||||||
|
|
||||||
|
def layout
|
||||||
|
params.dig(:post, :layout) || params[:layout]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/BlockLength
|
# rubocop:enable Metrics/BlockLength
|
||||||
|
|
11
app/views/contact_mailer/notify_usuaries.html.haml
Normal file
11
app/views/contact_mailer/notify_usuaries.html.haml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
-#
|
||||||
|
Solo enviamos versión de texto para no aceptar HTML en el formulario
|
||||||
|
de contacto
|
||||||
|
|
||||||
|
%p
|
||||||
|
%strong= I18n.t('contact_mailer.name', name: sanitize(@params[:name]),
|
||||||
|
pronouns: sanitize(@params[:pronouns]))
|
||||||
|
%strong= I18n.t('contact_mailer.contact', contact: sanitize(@params[:contact]))
|
||||||
|
%strong= I18n.t('contact_mailer.gdpr', gdpr: sanitize(@params[:gdpr]))
|
||||||
|
|
||||||
|
%div= sanitize @params[:body]
|
11
app/views/contact_mailer/notify_usuaries.text.haml
Normal file
11
app/views/contact_mailer/notify_usuaries.text.haml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
-#
|
||||||
|
Solo enviamos versión de texto para no aceptar HTML en el formulario
|
||||||
|
de contacto
|
||||||
|
|
||||||
|
= I18n.t('contact_mailer.name',
|
||||||
|
name: sanitize(@params[:name]),
|
||||||
|
pronouns: sanitize(@params[:pronouns]))
|
||||||
|
= I18n.t('contact_mailer.contact', contact: sanitize(@params[:contact]))
|
||||||
|
= I18n.t('contact_mailer.gdpr', gdpr: sanitize(@params[:gdpr]))
|
||||||
|
\
|
||||||
|
= sanitize @params[:body]
|
3
app/views/posts/attribute_ro/_number.haml
Normal file
3
app/views/posts/attribute_ro/_number.haml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
%tr{ id: attribute }
|
||||||
|
%th= post_label_t(attribute, post: post)
|
||||||
|
%td= metadata.value
|
5
app/views/posts/attribute_ro/_predefined_array.haml
Normal file
5
app/views/posts/attribute_ro/_predefined_array.haml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
%tr{ id: attribute }
|
||||||
|
%th= post_label_t(attribute, post: post)
|
||||||
|
%td
|
||||||
|
- metadata.value.each do |v|
|
||||||
|
%span.badge.badge-primary= metadata.values.key v
|
|
@ -1,6 +1,6 @@
|
||||||
.form-check
|
.form-check
|
||||||
= hidden_field_tag "post[#{attribute}]", '0'
|
= hidden_field_tag "post[#{attribute}]", '0'
|
||||||
= check_box_tag "post[#{attribute}]", metadata.value, metadata.value,
|
= check_box_tag "post[#{attribute}]", '1', metadata.value,
|
||||||
class: "form-check-input #{invalid(post, attribute)}",
|
class: "form-check-input #{invalid(post, attribute)}",
|
||||||
aria: { describedby: id_for_help(attribute) },
|
aria: { describedby: id_for_help(attribute) },
|
||||||
autofocus: autofocus
|
autofocus: autofocus
|
||||||
|
|
|
@ -16,4 +16,4 @@
|
||||||
value: metadata.value['lng'],
|
value: metadata.value['lng'],
|
||||||
**field_options(attribute, metadata))
|
**field_options(attribute, metadata))
|
||||||
= render 'posts/attribute_feedback',
|
= render 'posts/attribute_feedback',
|
||||||
post: post, attribute: [attribute, :lat], metadata: metadata
|
post: post, attribute: [attribute, :lng], metadata: metadata
|
||||||
|
|
6
app/views/posts/attributes/_number.haml
Normal file
6
app/views/posts/attributes/_number.haml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
.form-group
|
||||||
|
= label_tag "post_#{attribute}", post_label_t(attribute, post: post)
|
||||||
|
= number_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/_predefined_array.haml
Normal file
19
app/views/posts/attributes/_predefined_array.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 }
|
|
@ -14,7 +14,7 @@
|
||||||
%h3= t('posts.new')
|
%h3= t('posts.new')
|
||||||
%ul
|
%ul
|
||||||
- @site.layouts.to_h.keys.each do |layout|
|
- @site.layouts.to_h.keys.each do |layout|
|
||||||
%li= link_to layout.to_s.humanize,
|
%li= link_to @site.i18n.dig('layouts', layout.to_s) || layout.to_s.humanize,
|
||||||
new_site_post_path(@site, layout: layout)
|
new_site_post_path(@site, layout: layout)
|
||||||
|
|
||||||
- if policy(@site).edit?
|
- if policy(@site).edit?
|
||||||
|
|
|
@ -36,18 +36,20 @@
|
||||||
.form-group
|
.form-group
|
||||||
%h2= t('.design.title')
|
%h2= t('.design.title')
|
||||||
%p.lead= t('.help.design')
|
%p.lead= t('.help.design')
|
||||||
.row
|
.row.designs
|
||||||
-# Demasiado complejo para un f.collection_radio_buttons
|
-# Demasiado complejo para un f.collection_radio_buttons
|
||||||
- Design.all.each do |design|
|
- Design.all.find_each do |design|
|
||||||
.col
|
.design.col-md-4.d-flex.flex-column
|
||||||
%h3
|
.custom-control.custom-radio
|
||||||
= f.radio_button :design_id, design.id,
|
= f.radio_button :design_id, design.id,
|
||||||
checked: design.id == site.design_id,
|
checked: design.id == site.design_id,
|
||||||
disabled: design.disabled,
|
disabled: design.disabled,
|
||||||
required: true
|
required: true, class: 'custom-control-input'
|
||||||
= f.label "design_id_#{design.id}", design.name
|
= f.label "design_id_#{design.id}", design.name,
|
||||||
= sanitize_markdown design.description,
|
class: 'custom-control-label'
|
||||||
tags: %w[p a strong em]
|
.flex-fill
|
||||||
|
= sanitize_markdown design.description,
|
||||||
|
tags: %w[p a strong em]
|
||||||
|
|
||||||
.btn-group{ role: 'group', 'aria-label': t('.design.actions') }
|
.btn-group{ role: 'group', 'aria-label': t('.design.actions') }
|
||||||
- if design.url
|
- if design.url
|
||||||
|
@ -58,25 +60,26 @@
|
||||||
target: '_blank', class: 'btn'
|
target: '_blank', class: 'btn'
|
||||||
%hr/
|
%hr/
|
||||||
|
|
||||||
.form-group
|
.form-group.licenses
|
||||||
%h2= t('.licencia.title')
|
%h2= t('.licencia.title')
|
||||||
%p.lead= t('.help.licencia')
|
%p.lead= t('.help.licencia')
|
||||||
- Licencia.all.each do |licencia|
|
- Licencia.all.find_each do |licencia|
|
||||||
.row
|
.row.license
|
||||||
.col
|
.col
|
||||||
%h3
|
.media.mt-1
|
||||||
= f.radio_button :licencia_id, licencia.id,
|
= image_tag licencia.icons, alt: licencia.name, class: 'mr-3 mt-4'
|
||||||
checked: licencia.id == site.licencia_id,
|
.media-body
|
||||||
required: true
|
.custom-control.custom-radio
|
||||||
= f.label "licencia_id_#{licencia.id}" do
|
= f.radio_button :licencia_id, licencia.id,
|
||||||
= image_tag licencia.icons, alt: licencia.name
|
checked: licencia.id == site.licencia_id,
|
||||||
= licencia.name
|
required: true, class: 'custom-control-input'
|
||||||
= sanitize_markdown licencia.description,
|
= f.label "licencia_id_#{licencia.id}", class: 'custom-control-label' do
|
||||||
tags: %w[p a strong em ul ol li h1 h2 h3 h4 h5 h6]
|
= licencia.name
|
||||||
|
= sanitize_markdown licencia.description,
|
||||||
|
tags: %w[p a strong em ul ol li h1 h2 h3 h4 h5 h6]
|
||||||
|
|
||||||
.btn-group{ role: 'group', 'aria-label': t('.licencia.actions') }
|
= link_to t('.licencia.url'), licencia.url,
|
||||||
= link_to t('.licencia.url'), licencia.url,
|
target: '_blank', class: 'btn'
|
||||||
target: '_blank', class: 'btn'
|
|
||||||
|
|
||||||
%hr/
|
%hr/
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ Rails.application.configure do
|
||||||
# routes, locales, etc. This feature depends on the listen gem.
|
# routes, locales, etc. This feature depends on the listen gem.
|
||||||
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
|
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
|
||||||
|
|
||||||
|
config.action_mailer.default_options = { from: ENV['DEFAULT_FROM'] }
|
||||||
config.action_mailer.perform_caching = false
|
config.action_mailer.perform_caching = false
|
||||||
config.action_mailer.delivery_method = :letter_opener
|
config.action_mailer.delivery_method = :letter_opener
|
||||||
config.action_mailer.perform_deliveries = true
|
config.action_mailer.perform_deliveries = true
|
||||||
|
|
|
@ -44,6 +44,7 @@ Rails.application.configure do
|
||||||
# The :test delivery method accumulates sent emails in the
|
# The :test delivery method accumulates sent emails in the
|
||||||
# ActionMailer::Base.deliveries array.
|
# ActionMailer::Base.deliveries array.
|
||||||
config.action_mailer.delivery_method = :test
|
config.action_mailer.delivery_method = :test
|
||||||
|
config.action_mailer.default_options = { from: ENV['DEFAULT_FROM'] }
|
||||||
config.action_mailer.default_url_options = { host: 'localhost',
|
config.action_mailer.default_url_options = { host: 'localhost',
|
||||||
port: 3000 }
|
port: 3000 }
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,11 @@ en:
|
||||||
es: Castillian Spanish
|
es: Castillian Spanish
|
||||||
en: English
|
en: English
|
||||||
seconds: '%{seconds} seconds'
|
seconds: '%{seconds} seconds'
|
||||||
|
contact_mailer:
|
||||||
|
subject: '[%site] Contact form'
|
||||||
|
name: 'Name: %{name} (%{pronouns})'
|
||||||
|
contact: 'Contact: %{contact}'
|
||||||
|
gdpr: 'Consent: %{gdpr}'
|
||||||
deploy_mailer:
|
deploy_mailer:
|
||||||
deployed:
|
deployed:
|
||||||
subject: "[Sutty] The site %{site} has been built"
|
subject: "[Sutty] The site %{site} has been built"
|
||||||
|
@ -312,7 +317,7 @@ en:
|
||||||
title: 'Design'
|
title: 'Design'
|
||||||
actions: 'Information about this design'
|
actions: 'Information about this design'
|
||||||
url: 'Demo'
|
url: 'Demo'
|
||||||
licencia: 'Read the license'
|
licencia: 'License'
|
||||||
licencia:
|
licencia:
|
||||||
title: 'License for the site and everything published on it'
|
title: 'License for the site and everything published on it'
|
||||||
url: 'Read the license'
|
url: 'Read the license'
|
||||||
|
@ -382,7 +387,7 @@ en:
|
||||||
date: 'date'
|
date: 'date'
|
||||||
order: 'Order'
|
order: 'Order'
|
||||||
content: 'Text'
|
content: 'Text'
|
||||||
new: 'New post as'
|
new: 'Add:'
|
||||||
dropdown: 'Toggle dropdown'
|
dropdown: 'Toggle dropdown'
|
||||||
categories: 'Everything'
|
categories: 'Everything'
|
||||||
index: 'Posts'
|
index: 'Posts'
|
||||||
|
|
|
@ -38,6 +38,11 @@ es:
|
||||||
es: Castellano
|
es: Castellano
|
||||||
en: Inglés
|
en: Inglés
|
||||||
seconds: '%{seconds} segundos'
|
seconds: '%{seconds} segundos'
|
||||||
|
contact_mailer:
|
||||||
|
subject: '[%{site}] Formulario de contacto'
|
||||||
|
name: 'Nombre: %{name} (%{pronouns})'
|
||||||
|
contact: 'Contacto: %{contact}'
|
||||||
|
gdpr: 'Consentimiento: %{gdpr}'
|
||||||
deploy_mailer:
|
deploy_mailer:
|
||||||
deployed:
|
deployed:
|
||||||
subject: "[Sutty] El sitio %{site} ha sido generado"
|
subject: "[Sutty] El sitio %{site} ha sido generado"
|
||||||
|
@ -320,7 +325,7 @@ es:
|
||||||
title: 'Diseño'
|
title: 'Diseño'
|
||||||
actions: 'Información sobre este diseño'
|
actions: 'Información sobre este diseño'
|
||||||
url: 'Demostración'
|
url: 'Demostración'
|
||||||
license: 'Leer la licencia'
|
license: 'Licencia'
|
||||||
licencia:
|
licencia:
|
||||||
title: 'Licencia del sitio y todo lo publicado'
|
title: 'Licencia del sitio y todo lo publicado'
|
||||||
url: 'Leer la licencia'
|
url: 'Leer la licencia'
|
||||||
|
@ -392,7 +397,7 @@ es:
|
||||||
content: 'Cuerpo del artículo'
|
content: 'Cuerpo del artículo'
|
||||||
categories: 'Todos'
|
categories: 'Todos'
|
||||||
dropdown: 'Desplegar el menú'
|
dropdown: 'Desplegar el menú'
|
||||||
new: 'Crear artículo en:'
|
new: 'Agregar:'
|
||||||
index: 'Artículos'
|
index: 'Artículos'
|
||||||
edit: 'Editar'
|
edit: 'Editar'
|
||||||
open: 'Nota: Puedes agregar más opciones a medida que las escribes y presionas Entrar'
|
open: 'Nota: Puedes agregar más opciones a medida que las escribes y presionas Entrar'
|
||||||
|
|
|
@ -24,6 +24,7 @@ Rails.application.routes.draw do
|
||||||
resources :sites, only: %i[index], constraints: { site_id: /[a-z0-9\-\.]+/, id: /[a-z0-9\-\.]+/ } do
|
resources :sites, only: %i[index], constraints: { site_id: /[a-z0-9\-\.]+/, id: /[a-z0-9\-\.]+/ } do
|
||||||
get 'invitades/cookie', to: 'invitades#cookie'
|
get 'invitades/cookie', to: 'invitades#cookie'
|
||||||
resources :posts, only: %i[create]
|
resources :posts, only: %i[create]
|
||||||
|
post :contact, to: 'contact#receive'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,6 +27,13 @@
|
||||||
description_en: "A design with Sutty's look & feel"
|
description_en: "A design with Sutty's look & feel"
|
||||||
description_es: 'El diseño de Sutty'
|
description_es: 'El diseño de Sutty'
|
||||||
license: 'https://0xacab.org/sutty/jekyll/sutty-jekyll-theme/-/blob/master/LICENSE.txt'
|
license: 'https://0xacab.org/sutty/jekyll/sutty-jekyll-theme/-/blob/master/LICENSE.txt'
|
||||||
|
- name_en: 'Self-managed Book Publisher'
|
||||||
|
name_es: 'Editorial Autogestiva'
|
||||||
|
gem: 'editorial-autogestiva-jekyll-theme'
|
||||||
|
url: 'https://subelamarea.sutty.nl/'
|
||||||
|
description_en: "A theme for self-managed book publishers."
|
||||||
|
description_es: 'Una plantilla para catálogos de editoriales autogestivas.'
|
||||||
|
license: 'https://0xacab.org/sutty/jekyll/editorial-autogestiva-jekyll-theme/-/blob/master/LICENSE.txt'
|
||||||
- name_en: 'Other themes'
|
- name_en: 'Other themes'
|
||||||
name_es: 'Mi propio diseño'
|
name_es: 'Mi propio diseño'
|
||||||
gem: 'sutty-theme-own'
|
gem: 'sutty-theme-own'
|
||||||
|
|
124
test/controllers/api/v1/contact_controller_test.rb
Normal file
124
test/controllers/api/v1/contact_controller_test.rb
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class ContactControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
setup do
|
||||||
|
@rol = create :rol
|
||||||
|
@site = @rol.site
|
||||||
|
@usuarie = @rol.usuarie
|
||||||
|
end
|
||||||
|
|
||||||
|
teardown do
|
||||||
|
@site&.destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'el sitio tiene que existir' do
|
||||||
|
@site.destroy
|
||||||
|
|
||||||
|
post v1_site_contact_url(site_id: @site.hostname),
|
||||||
|
params: {
|
||||||
|
name: SecureRandom.hex,
|
||||||
|
pronouns: SecureRandom.hex,
|
||||||
|
contact: SecureRandom.hex,
|
||||||
|
from: "#{SecureRandom.hex}@sutty.nl",
|
||||||
|
body: SecureRandom.hex,
|
||||||
|
gdpr: true
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_response :unprocessable_entity, response.status
|
||||||
|
assert_equal 'site_exists', response.body
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'hay que enviar desde el sitio principal' do
|
||||||
|
post v1_site_contact_url(site_id: @site.hostname),
|
||||||
|
params: {
|
||||||
|
name: SecureRandom.hex,
|
||||||
|
pronouns: SecureRandom.hex,
|
||||||
|
contact: SecureRandom.hex,
|
||||||
|
from: "#{SecureRandom.hex}@sutty.nl",
|
||||||
|
body: SecureRandom.hex,
|
||||||
|
gdpr: true
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_response :unprocessable_entity, response.status
|
||||||
|
assert_equal 'site_is_origin', response.body
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'hay que dar consentimiento' do
|
||||||
|
post v1_site_contact_url(site_id: @site.hostname),
|
||||||
|
headers: {
|
||||||
|
Origin: @site.url
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
name: SecureRandom.hex,
|
||||||
|
pronouns: SecureRandom.hex,
|
||||||
|
contact: SecureRandom.hex,
|
||||||
|
from: "#{SecureRandom.hex}@sutty.nl",
|
||||||
|
body: SecureRandom.hex
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_response :unprocessable_entity, response.status
|
||||||
|
assert_equal 'gave_consent', response.body
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'enviar un mensaje genera correos' do
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
|
||||||
|
redirect = "#{@site.url}/?thanks"
|
||||||
|
|
||||||
|
10.times do
|
||||||
|
create :rol, site: @site
|
||||||
|
end
|
||||||
|
|
||||||
|
post v1_site_contact_url(site_id: @site.hostname),
|
||||||
|
headers: {
|
||||||
|
Origin: @site.url
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
name: SecureRandom.hex,
|
||||||
|
pronouns: SecureRandom.hex,
|
||||||
|
contact: SecureRandom.hex,
|
||||||
|
from: "#{SecureRandom.hex}@sutty.nl",
|
||||||
|
body: SecureRandom.hex,
|
||||||
|
gdpr: true,
|
||||||
|
redirect: redirect
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal redirect, response.headers['Location']
|
||||||
|
assert_equal 2, ActionMailer::Base.deliveries.size
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'se puede enviar mensajes a dominios propios' do
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
|
||||||
|
@site.update name: 'example.org.'
|
||||||
|
|
||||||
|
redirect = "#{@site.url}?thanks"
|
||||||
|
|
||||||
|
10.times do
|
||||||
|
create :rol, site: @site
|
||||||
|
end
|
||||||
|
|
||||||
|
post v1_site_contact_url(site_id: @site.hostname),
|
||||||
|
headers: {
|
||||||
|
Origin: @site.url
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
name: SecureRandom.hex,
|
||||||
|
pronouns: SecureRandom.hex,
|
||||||
|
contact: SecureRandom.hex,
|
||||||
|
from: "#{SecureRandom.hex}@sutty.nl",
|
||||||
|
body: SecureRandom.hex,
|
||||||
|
gdpr: true,
|
||||||
|
redirect: redirect
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal redirect, response.headers['Location']
|
||||||
|
assert_equal 2, ActionMailer::Base.deliveries.size
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,14 +3,16 @@
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class SiteTest < ActiveSupport::TestCase
|
class SiteTest < ActiveSupport::TestCase
|
||||||
|
def site
|
||||||
|
@site ||= create :site
|
||||||
|
end
|
||||||
|
|
||||||
# Asegurarse que el sitio se destruye al terminar de usarlo
|
# Asegurarse que el sitio se destruye al terminar de usarlo
|
||||||
teardown do
|
teardown do
|
||||||
@site&.destroy
|
site&.destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'se puede crear un sitio' do
|
test 'se puede crear un sitio' do
|
||||||
site = create :site
|
|
||||||
|
|
||||||
assert site.valid?
|
assert site.valid?
|
||||||
# TODO: Mover a la validación del sitio o hacer algo similar
|
# TODO: Mover a la validación del sitio o hacer algo similar
|
||||||
assert File.directory?(site.path)
|
assert File.directory?(site.path)
|
||||||
|
@ -19,78 +21,92 @@ class SiteTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'el nombre tiene que ser único' do
|
test 'el nombre tiene que ser único' do
|
||||||
@site = create :site
|
site2 = build :site, name: site.name
|
||||||
site2 = build :site, name: @site.name
|
|
||||||
|
|
||||||
assert_not site2.valid?
|
assert_not site2.valid?
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'el nombre del sitio puede contener subdominios' do
|
test 'el nombre del sitio puede contener subdominios' do
|
||||||
site = build :site, name: 'hola.chau'
|
@site = build :site, name: 'hola.chau'
|
||||||
site.validate
|
site.validate
|
||||||
|
|
||||||
assert_not site.errors.messages[:name].present?
|
assert_not site.errors.messages[:name].present?
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'el nombre del sitio puede terminar con punto' do
|
test 'el nombre del sitio puede terminar con punto' do
|
||||||
site = build :site, name: 'hola.chau.'
|
@site = build :site, name: 'hola.chau.'
|
||||||
site.validate
|
site.validate
|
||||||
|
|
||||||
assert_not site.errors.messages[:name].present?
|
assert_not site.errors.messages[:name].present?
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'el nombre del sitio no puede contener wildcard' do
|
test 'el nombre del sitio no puede contener wildcard' do
|
||||||
site = build :site, name: '*.chau'
|
@site = build :site, name: '*.chau'
|
||||||
site.validate
|
site.validate
|
||||||
|
|
||||||
assert site.errors.messages[:name].present?
|
assert site.errors.messages[:name].present?
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'el nombre del sitio solo tiene letras, numeros y guiones' do
|
test 'el nombre del sitio solo tiene letras, numeros y guiones' do
|
||||||
site = build :site, name: 'A_Z!'
|
@site = build :site, name: 'A_Z!'
|
||||||
site.validate
|
site.validate
|
||||||
|
|
||||||
assert site.errors.messages[:name].present?
|
assert site.errors.messages[:name].present?
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'al destruir un sitio se eliminan los archivos' do
|
test 'al destruir un sitio se eliminan los archivos' do
|
||||||
site = create :site
|
@site = create :site
|
||||||
assert site.destroy
|
assert site.destroy
|
||||||
assert !File.directory?(site.path)
|
assert !File.directory?(site.path)
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'se puede leer un sitio' do
|
test 'se puede leer un sitio' do
|
||||||
site = create :site
|
|
||||||
|
|
||||||
assert site.valid?
|
assert site.valid?
|
||||||
assert !site.posts.empty?
|
assert !site.posts.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'se pueden renombrar' do
|
test 'se pueden renombrar' do
|
||||||
@site = create :site
|
path = site.path
|
||||||
path = @site.path
|
|
||||||
|
|
||||||
@site.update_attribute :name, SecureRandom.hex
|
site.update_attribute :name, SecureRandom.hex
|
||||||
|
|
||||||
assert_not_equal path, @site.path
|
assert_not_equal path, site.path
|
||||||
assert File.directory?(@site.path)
|
assert File.directory?(site.path)
|
||||||
assert_not File.directory?(path)
|
assert_not File.directory?(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'no se puede guardar html en title y description' do
|
test 'no se puede guardar html en title y description' do
|
||||||
site = build :site
|
_site = build :site
|
||||||
site.description = "<a href='hola'>hola</a><script>alert('pwned')</script>"
|
_site.description = "<a href='hola'>hola</a><script>alert('pwned')</script>"
|
||||||
site.title = "<a href='hola'>hola</a><script>alert('pwned')</script>"
|
_site.title = "<a href='hola'>hola</a><script>alert('pwned')</script>"
|
||||||
|
|
||||||
assert_equal 'hola', site.description
|
assert_equal 'hola', _site.description
|
||||||
assert_equal 'hola', site.title
|
assert_equal 'hola', _site.title
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'el sitio tiene artículos en distintos idiomas' do
|
test 'el sitio tiene artículos en distintos idiomas' do
|
||||||
@site = create :site
|
|
||||||
|
|
||||||
I18n.available_locales.each do |locale|
|
I18n.available_locales.each do |locale|
|
||||||
assert @site.posts(lang: locale).size.positive?
|
assert site.posts(lang: locale).size.positive?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test 'tienen un hostname que puede cambiar' do
|
||||||
|
assert_equal "#{site.name}.#{Site.domain}", site.hostname
|
||||||
|
|
||||||
|
site.name = name = SecureRandom.hex
|
||||||
|
|
||||||
|
assert_equal "#{name}.#{Site.domain}", site.hostname
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'se pueden traer los datos de una plantilla' do
|
||||||
|
@site = create :site, design: Design.find_by(gem: 'editorial-autogestiva-jekyll-theme')
|
||||||
|
|
||||||
|
assert_equal %i[post], site.layouts.to_h.keys
|
||||||
|
|
||||||
|
site.config.write
|
||||||
|
site.reload
|
||||||
|
|
||||||
|
assert_equal %w[book editorial post], site.data['layouts'].keys
|
||||||
|
assert_equal %i[book editorial post], site.layouts.to_h.keys
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue