mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-14 22:51:41 +00:00
WIP: elegir el diseño del sitio
This commit is contained in:
parent
cff18bf861
commit
1cc4c4de64
25 changed files with 348 additions and 19 deletions
1
Gemfile
1
Gemfile
|
@ -50,6 +50,7 @@ gem 'hamlit-rails'
|
|||
gem 'jekyll'
|
||||
gem 'jquery-rails'
|
||||
gem 'mini_magick'
|
||||
gem 'mobility'
|
||||
gem 'pundit'
|
||||
gem 'rails-i18n'
|
||||
gem 'rails_warden'
|
||||
|
|
|
@ -212,10 +212,13 @@ GEM
|
|||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2018.0812)
|
||||
mimemagic (0.3.3)
|
||||
mini_magick (4.9.3)
|
||||
mini_magick (4.9.4)
|
||||
mini_mime (1.0.1)
|
||||
mini_portile2 (2.4.0)
|
||||
minitest (5.11.3)
|
||||
mobility (0.8.7)
|
||||
i18n (>= 0.6.10, < 2)
|
||||
request_store (~> 1.0)
|
||||
multi_json (1.13.1)
|
||||
net-scp (2.0.0)
|
||||
net-ssh (>= 2.6.5, < 6.0.0)
|
||||
|
@ -277,6 +280,8 @@ GEM
|
|||
ffi (~> 1.0)
|
||||
rbnacl (4.0.2)
|
||||
ffi
|
||||
request_store (1.4.1)
|
||||
rack (>= 1.4)
|
||||
responders (3.0.0)
|
||||
actionpack (>= 5.0)
|
||||
railties (>= 5.0)
|
||||
|
@ -409,6 +414,7 @@ DEPENDENCIES
|
|||
letter_opener
|
||||
listen (>= 3.0.5, < 3.2)
|
||||
mini_magick
|
||||
mobility
|
||||
pry
|
||||
puma (~> 3.7)
|
||||
pundit
|
||||
|
|
|
@ -137,6 +137,6 @@ class SitesController < ApplicationController
|
|||
private
|
||||
|
||||
def site_params
|
||||
params.require(:site).permit(:name)
|
||||
params.require(:site).permit(:name, :design_id)
|
||||
end
|
||||
end
|
||||
|
|
19
app/models/design.rb
Normal file
19
app/models/design.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# El diseño de un sitio es la plantilla/tema. En este modelo cargamos
|
||||
# las propiedades para poder verlas desde el panel y elegir un diseño
|
||||
# para el sitio.
|
||||
#
|
||||
# TODO: Agregar captura de pantalla con ActiveStorage
|
||||
class Design < ApplicationRecord
|
||||
extend Mobility
|
||||
|
||||
translates :name, type: :string, locale_accessors: true
|
||||
translates :description, type: :text, locale_accessors: true
|
||||
|
||||
has_many :sites
|
||||
|
||||
validates :name, presence: true, uniqueness: true
|
||||
validates :gem, presence: true, uniqueness: true
|
||||
validates :description, presence: true
|
||||
end
|
|
@ -6,9 +6,12 @@ class Site < ApplicationRecord
|
|||
include FriendlyId
|
||||
|
||||
validates :name, uniqueness: true, hostname: true
|
||||
validates :design_id, presence: true
|
||||
|
||||
friendly_id :name, use: %i[finders]
|
||||
|
||||
belongs_to :design
|
||||
|
||||
has_many :roles
|
||||
has_many :usuaries, -> { where('roles.rol = ?', 'usuarie') },
|
||||
through: :roles
|
||||
|
|
|
@ -1,6 +1,29 @@
|
|||
= form_for @site do |f|
|
||||
= form_for site do |f|
|
||||
.form-group
|
||||
= f.label :name
|
||||
%h2= f.label :name
|
||||
%p.lead= t('.help.name')
|
||||
= f.text_field :name, class: 'form-control'
|
||||
.form-group
|
||||
%h2= t('.design.title')
|
||||
%p.lead= t('.help.design')
|
||||
.row
|
||||
-# Demasiado complejo para un f.collection_radio_buttons
|
||||
- Design.all.each do |design|
|
||||
.col
|
||||
%h3
|
||||
= f.radio_button :design_id, design.id,
|
||||
checked: design.id == site.design_id,
|
||||
disabled: design.disabled
|
||||
= f.label "design_id_#{design.id}", design.name
|
||||
= sanitize_markdown design.description,
|
||||
tags: %w[p a strong em]
|
||||
|
||||
.btn-group{ role: 'group', 'aria-label': t('.design.actions') }
|
||||
- if design.url
|
||||
= link_to t('.design.url'), design.url,
|
||||
target: '_blank', class: 'btn btn-info'
|
||||
- if design.license
|
||||
= link_to t('.design.license'), design.license,
|
||||
target: '_blank', class: 'btn btn-info'
|
||||
.form-group
|
||||
= f.submit submit, class: 'btn btn-success'
|
||||
|
|
|
@ -7,4 +7,4 @@
|
|||
.col
|
||||
%h1= t('.title', site: @site.name)
|
||||
|
||||
= render 'form', submit: t('.submit')
|
||||
= render 'form', site: @site, submit: t('.submit')
|
||||
|
|
|
@ -6,4 +6,4 @@
|
|||
.col
|
||||
%h1= t('.title')
|
||||
|
||||
= render 'form', submit: t('.submit')
|
||||
= render 'form', site: @site, submit: t('.submit')
|
||||
|
|
97
config/initializers/mobility.rb
Normal file
97
config/initializers/mobility.rb
Normal file
|
@ -0,0 +1,97 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Mobility.configure do |config|
|
||||
# Sets the default backend to use in models. This can be overridden in
|
||||
# models by passing +backend: ...+ to +translates+.
|
||||
config.default_backend = :key_value
|
||||
|
||||
# By default, Mobility uses the +translates+ class method in models to
|
||||
# describe translated attributes, but you can configure this method to
|
||||
# be whatever you like. This may be useful if using Mobility alongside
|
||||
# another translation gem which uses the same method name.
|
||||
config.accessor_method = :translates
|
||||
|
||||
# To query on translated attributes, you need to append a scope to
|
||||
# your model. The name of this scope is +i18n+ by default, but this
|
||||
# can be changed to something else.
|
||||
config.query_method = :i18n
|
||||
|
||||
# Uncomment and remove (or add) items to (from) this list to
|
||||
# completely disable/enable plugins globally (so they cannot be used
|
||||
# and are never even loaded). Note that if you remove an item from the
|
||||
# list, you will not be able to use the plugin at all, and any options
|
||||
# for the plugin will be ignored by models. (In most cases, you
|
||||
# probably don't want to change this.)
|
||||
#
|
||||
# config.plugins = %i[
|
||||
# query
|
||||
# cache
|
||||
# dirty
|
||||
# fallbacks
|
||||
# presence
|
||||
# default
|
||||
# attribute_methods
|
||||
# fallthrough_accessors
|
||||
# locale_accessors
|
||||
# ]
|
||||
|
||||
# The translation cache is on by default, but you can turn it off by
|
||||
# uncommenting this line. (This may be helpful in debugging.)
|
||||
#
|
||||
# config.default_options[:cache] = false
|
||||
|
||||
# Dirty tracking is disabled by default. Uncomment this line to enable
|
||||
# it. If you enable this, you should also enable +locale_accessors+
|
||||
# by default (see below).
|
||||
#
|
||||
# config.default_options[:dirty] = true
|
||||
|
||||
# No fallbacks are used by default. To define default fallbacks,
|
||||
# uncomment and set the default fallback option value here. A "true"
|
||||
# value will use whatever is defined by +I18n.fallbacks+ (if defined),
|
||||
# or alternatively will fallback to your +I18n.default_locale+.
|
||||
#
|
||||
config.default_options[:fallbacks] = true
|
||||
|
||||
# The Presence plugin converts empty strings to nil when fetching and
|
||||
# setting translations. By default it is on, uncomment this line to
|
||||
# turn it off.
|
||||
#
|
||||
# config.default_options[:presence] = false
|
||||
|
||||
# Set a default value to use if the translation is nil. By default
|
||||
# this is off, uncomment and set a default to use it across all models
|
||||
# (you probably don't want to do that).
|
||||
#
|
||||
# config.default_options[:default] = ...
|
||||
|
||||
# Uncomment to enable locale_accessors by default on models. A true
|
||||
# value will use the locales defined either in
|
||||
# Rails.application.config.i18n.available_locales or
|
||||
# I18n.available_locales. If you want something else, pass an array
|
||||
# of locales instead.
|
||||
#
|
||||
# config.default_options[:locale_accessors] = true
|
||||
|
||||
# Uncomment to enable fallthrough accessors by default on models. This
|
||||
# will allow you to call any method with a suffix like _en or _pt_br,
|
||||
# and Mobility will catch the suffix and convert it into a locale in
|
||||
# +method_missing+. If you don't need this kind of open-ended
|
||||
# fallthrough behavior, it's better to use locale_accessors instead
|
||||
# (which define methods) since method_missing is very slow. (You can
|
||||
# use both fallthrough and locale accessor plugins together without
|
||||
# conflict.)
|
||||
#
|
||||
# Note: The dirty plugin enables fallthrough_accessors by default.
|
||||
#
|
||||
# config.default_options[:fallthrough_accessors] = true
|
||||
|
||||
# You can also include backend-specific default options. For example,
|
||||
# if you want to default to using the text-type translation table with
|
||||
# the KeyValue backend, you can set that as a default by uncommenting
|
||||
# this line, or change it to :string to default to the string-type
|
||||
# translation table instead. (For other backends, this option is
|
||||
# ignored.)
|
||||
#
|
||||
# config.default_options[:type] = :text
|
||||
end
|
|
@ -158,6 +158,15 @@ en:
|
|||
edit:
|
||||
title: 'Edit %{site}'
|
||||
submit: 'Save changes'
|
||||
form:
|
||||
help:
|
||||
name: "Your site's name. It can only contain numbers and letters."
|
||||
design: 'Select the design for your site. You can change it later. We add more designs from time to time.'
|
||||
design:
|
||||
title: 'Design'
|
||||
actions: 'Information about this design'
|
||||
url: 'Preview'
|
||||
licencia: 'Read the license'
|
||||
fetch:
|
||||
title: 'Upgrade the site'
|
||||
help:
|
||||
|
|
|
@ -163,6 +163,15 @@ es:
|
|||
edit:
|
||||
title: 'Editar %{site}'
|
||||
submit: 'Guardar cambios'
|
||||
form:
|
||||
help:
|
||||
name: 'El nombre de tu sitio. Solo puede contener letras y números.'
|
||||
design: 'Elegí el diseño que va a tener tu sitio aquí. Podés cambiarlo luego. De tanto en tanto vamos sumando diseños nuevos.'
|
||||
design:
|
||||
title: 'Diseño'
|
||||
actions: 'Información sobre este diseño'
|
||||
url: 'Vista previa'
|
||||
licencia: 'Leer la licencia'
|
||||
fetch:
|
||||
title: 'Actualizar el sitio'
|
||||
help:
|
||||
|
|
15
db/migrate/20190716195155_create_designs.rb
Normal file
15
db/migrate/20190716195155_create_designs.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Crea la tabla de diseños
|
||||
class CreateDesigns < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
create_table :designs do |t|
|
||||
t.timestamps
|
||||
t.string :name, unique: true
|
||||
t.text :description
|
||||
t.string :gem, unique: true
|
||||
t.string :url
|
||||
t.string :license
|
||||
end
|
||||
end
|
||||
end
|
9
db/migrate/20190716195449_add_lang_to_usuaries.rb
Normal file
9
db/migrate/20190716195449_add_lang_to_usuaries.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Agrega la columna de idioma a cada usuarie para que pueda ver el sitio
|
||||
# y escribir artículos en su idioma.
|
||||
class AddLangToUsuaries < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_column :usuaries, :lang, :string, default: 'es'
|
||||
end
|
||||
end
|
16
db/migrate/20190716195811_create_text_translations.rb
Normal file
16
db/migrate/20190716195811_create_text_translations.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Tabla de traducción de textos utilizada por Mobility
|
||||
class CreateTextTranslations < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
create_table :mobility_text_translations do |t|
|
||||
t.string :locale, null: false
|
||||
t.string :key, null: false
|
||||
t.text :value
|
||||
t.references :translatable, polymorphic: true, index: false
|
||||
t.timestamps null: false
|
||||
end
|
||||
add_index :mobility_text_translations, %i[translatable_id translatable_type locale key], unique: true, name: :index_mobility_text_translations_on_keys
|
||||
add_index :mobility_text_translations, %i[translatable_id translatable_type key], name: :index_mobility_text_translations_on_translatable_attribute
|
||||
end
|
||||
end
|
17
db/migrate/20190716195812_create_string_translations.rb
Normal file
17
db/migrate/20190716195812_create_string_translations.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Tabla de traducción de cadenas usada por Mobility
|
||||
class CreateStringTranslations < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
create_table :mobility_string_translations do |t|
|
||||
t.string :locale, null: false
|
||||
t.string :key, null: false
|
||||
t.string :value
|
||||
t.references :translatable, polymorphic: true, index: false
|
||||
t.timestamps null: false
|
||||
end
|
||||
add_index :mobility_string_translations, %i[translatable_id translatable_type locale key], unique: true, name: :index_mobility_string_translations_on_keys
|
||||
add_index :mobility_string_translations, %i[translatable_id translatable_type key], name: :index_mobility_string_translations_on_translatable_attribute
|
||||
add_index :mobility_string_translations, %i[translatable_type key value locale], name: :index_mobility_string_translations_on_query_keys
|
||||
end
|
||||
end
|
8
db/migrate/20190716202024_add_design_to_sites.rb
Normal file
8
db/migrate/20190716202024_add_design_to_sites.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Los sitios tienen un diseño
|
||||
class AddDesignToSites < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_belongs_to :sites, :design, index: true
|
||||
end
|
||||
end
|
8
db/migrate/20190717214308_add_disabled_to_designs.rb
Normal file
8
db/migrate/20190717214308_add_disabled_to_designs.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Algunos diseños están deshabilitados
|
||||
class AddDisabledToDesigns < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_column :designs, :disabled, :boolean, default: false
|
||||
end
|
||||
end
|
41
db/schema.rb
41
db/schema.rb
|
@ -12,7 +12,43 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20_190_712_165_059) do
|
||||
ActiveRecord::Schema.define(version: 20_190_717_214_308) do
|
||||
create_table 'designs', force: :cascade do |t|
|
||||
t.datetime 'created_at', null: false
|
||||
t.datetime 'updated_at', null: false
|
||||
t.string 'name'
|
||||
t.text 'description'
|
||||
t.string 'gem'
|
||||
t.string 'url'
|
||||
t.string 'license'
|
||||
t.boolean 'disabled', default: false
|
||||
end
|
||||
|
||||
create_table 'mobility_string_translations', force: :cascade do |t|
|
||||
t.string 'locale', null: false
|
||||
t.string 'key', null: false
|
||||
t.string 'value'
|
||||
t.string 'translatable_type'
|
||||
t.integer 'translatable_id'
|
||||
t.datetime 'created_at', null: false
|
||||
t.datetime 'updated_at', null: false
|
||||
t.index %w[translatable_id translatable_type key], name: 'index_mobility_string_translations_on_translatable_attribute'
|
||||
t.index %w[translatable_id translatable_type locale key], name: 'index_mobility_string_translations_on_keys', unique: true
|
||||
t.index %w[translatable_type key value locale], name: 'index_mobility_string_translations_on_query_keys'
|
||||
end
|
||||
|
||||
create_table 'mobility_text_translations', force: :cascade do |t|
|
||||
t.string 'locale', null: false
|
||||
t.string 'key', null: false
|
||||
t.text 'value'
|
||||
t.string 'translatable_type'
|
||||
t.integer 'translatable_id'
|
||||
t.datetime 'created_at', null: false
|
||||
t.datetime 'updated_at', null: false
|
||||
t.index %w[translatable_id translatable_type key], name: 'index_mobility_text_translations_on_translatable_attribute'
|
||||
t.index %w[translatable_id translatable_type locale key], name: 'index_mobility_text_translations_on_keys', unique: true
|
||||
end
|
||||
|
||||
create_table 'roles', force: :cascade do |t|
|
||||
t.datetime 'created_at', null: false
|
||||
t.datetime 'updated_at', null: false
|
||||
|
@ -29,6 +65,8 @@ ActiveRecord::Schema.define(version: 20_190_712_165_059) do
|
|||
t.datetime 'created_at', null: false
|
||||
t.datetime 'updated_at', null: false
|
||||
t.string 'name'
|
||||
t.integer 'design_id'
|
||||
t.index ['design_id'], name: 'index_sites_on_design_id'
|
||||
t.index ['name'], name: 'index_sites_on_name', unique: true
|
||||
end
|
||||
|
||||
|
@ -56,6 +94,7 @@ ActiveRecord::Schema.define(version: 20_190_712_165_059) do
|
|||
t.string 'invited_by_type'
|
||||
t.integer 'invited_by_id'
|
||||
t.integer 'invitations_count', default: 0
|
||||
t.string 'lang', default: 'es'
|
||||
t.index ['confirmation_token'], name: 'index_usuaries_on_confirmation_token', unique: true
|
||||
t.index ['email'], name: 'index_usuaries_on_email', unique: true
|
||||
t.index ['invitation_token'], name: 'index_usuaries_on_invitation_token', unique: true
|
||||
|
|
14
db/seeds.rb
14
db/seeds.rb
|
@ -1,9 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# 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).
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
|
||||
# Character.create(name: 'Luke', movie: movies.first)
|
||||
designs = YAML.safe_load(File.read('db/seeds/designs.yml'))
|
||||
|
||||
designs.each do |d|
|
||||
design = Design.find_or_create_by(gem: d['gem'])
|
||||
|
||||
design.update_attributes d
|
||||
end
|
||||
|
|
22
db/seeds/designs.yml
Normal file
22
db/seeds/designs.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
- name_en: 'My own design'
|
||||
name_es: 'Mi propio diseño'
|
||||
gem: 'sutty-theme-none'
|
||||
url: 'https://sutty.nl'
|
||||
disabled: true
|
||||
description_en: "Your own design. [This feature is in development, help us!]()"
|
||||
description_es: "Tu propio diseño. [Esta posibilidad está en desarrollo, ¡ayudanos!]()"
|
||||
- name_en: 'Minima'
|
||||
name_es: 'Mínima'
|
||||
gem: 'minima'
|
||||
url: 'https://jekyll.github.io/minima/'
|
||||
description_en: "Minima is the default design for Jekyll sites. It's made for general-purpose writing."
|
||||
description_es: 'Mínima es el diseño oficial de los sitios Jekyll, hecho para escritura de propósitos generales.'
|
||||
license: 'https://github.com/jekyll/minima/blob/master/LICENSE.txt'
|
||||
- name_en: 'EDSL'
|
||||
name_es: 'EDSL'
|
||||
gem: 'sutty-theme-edsl'
|
||||
url: 'https://endefensadelsl.org/'
|
||||
description_en: "_En defensa del software libre_'s design"
|
||||
description_es: 'El diseño de En defensa del software libre'
|
||||
license: 'https://endefensadelsl.org/ppl_deed_es.html'
|
|
@ -33,7 +33,8 @@ class SitesControllerTest < ActionDispatch::IntegrationTest
|
|||
|
||||
post sites_url, headers: @authorization, params: {
|
||||
site: {
|
||||
name: name
|
||||
name: name,
|
||||
design_id: create(:design).id
|
||||
}
|
||||
}
|
||||
|
||||
|
|
12
test/factories/design.rb
Normal file
12
test/factories/design.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :design do
|
||||
name { SecureRandom.hex }
|
||||
description { SecureRandom.hex }
|
||||
license { SecureRandom.hex }
|
||||
gem { SecureRandom.hex }
|
||||
url { SecureRandom.hex }
|
||||
disabled { false }
|
||||
end
|
||||
end
|
|
@ -3,5 +3,6 @@
|
|||
FactoryBot.define do
|
||||
factory :site do
|
||||
name { "test-#{SecureRandom.hex}" }
|
||||
design
|
||||
end
|
||||
end
|
||||
|
|
10
test/models/design_test.rb
Normal file
10
test/models/design_test.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DesignTest < ActiveSupport::TestCase
|
||||
test 'se pueden crear' do
|
||||
design = create :design
|
||||
|
||||
assert design.valid?
|
||||
assert design.persisted?
|
||||
end
|
||||
end
|
|
@ -27,26 +27,30 @@ class SiteTest < ActiveSupport::TestCase
|
|||
|
||||
test 'el nombre del sitio puede contener subdominios' do
|
||||
site = build :site, name: 'hola.chau'
|
||||
site.validate
|
||||
|
||||
assert site.valid?
|
||||
assert_not site.errors.messages[:name].present?
|
||||
end
|
||||
|
||||
test 'el nombre del sitio no puede terminar con punto' do
|
||||
site = build :site, name: 'hola.chau.'
|
||||
site.validate
|
||||
|
||||
assert_not site.valid?
|
||||
assert site.errors.messages[:name].present?
|
||||
end
|
||||
|
||||
test 'el nombre del sitio no puede contener wildcard' do
|
||||
site = build :site, name: '*.chau'
|
||||
site.validate
|
||||
|
||||
assert_not site.valid?
|
||||
assert site.errors.messages[:name].present?
|
||||
end
|
||||
|
||||
test 'el nombre del sitio solo tiene letras, numeros y guiones' do
|
||||
site = build :site, name: 'A_Z!'
|
||||
site.validate
|
||||
|
||||
assert_not site.valid?
|
||||
assert site.errors.messages[:name].present?
|
||||
end
|
||||
|
||||
test 'al destruir un sitio se eliminan los archivos' do
|
||||
|
|
Loading…
Reference in a new issue