mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-24 09:06:21 +00:00
wip de invitadxs
This commit is contained in:
parent
2e4219ce07
commit
39b575ebfb
23 changed files with 368 additions and 19 deletions
2
Gemfile
2
Gemfile
|
@ -25,7 +25,7 @@ gem 'turbolinks', '~> 5'
|
||||||
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
|
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
|
||||||
gem 'jbuilder', '~> 2.5'
|
gem 'jbuilder', '~> 2.5'
|
||||||
# Use ActiveModel has_secure_password
|
# Use ActiveModel has_secure_password
|
||||||
# gem 'bcrypt', '~> 3.1.7'
|
gem 'bcrypt', '~> 3.1.7'
|
||||||
|
|
||||||
# Use Capistrano for deployment
|
# Use Capistrano for deployment
|
||||||
# gem 'capistrano-rails', group: :development
|
# gem 'capistrano-rails', group: :development
|
||||||
|
|
|
@ -45,6 +45,7 @@ GEM
|
||||||
arel (8.0.0)
|
arel (8.0.0)
|
||||||
autoprefixer-rails (9.1.4)
|
autoprefixer-rails (9.1.4)
|
||||||
execjs
|
execjs
|
||||||
|
bcrypt (3.1.12)
|
||||||
bcrypt_pbkdf (1.0.0)
|
bcrypt_pbkdf (1.0.0)
|
||||||
bindex (0.5.0)
|
bindex (0.5.0)
|
||||||
bootstrap (4.0.0)
|
bootstrap (4.0.0)
|
||||||
|
@ -302,6 +303,7 @@ PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
|
bcrypt (~> 3.1.7)
|
||||||
bcrypt_pbkdf
|
bcrypt_pbkdf
|
||||||
bootstrap (~> 4.0.0)
|
bootstrap (~> 4.0.0)
|
||||||
capistrano
|
capistrano
|
||||||
|
|
53
app/controllers/invitadxs_controller.rb
Normal file
53
app/controllers/invitadxs_controller.rb
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
class InvitadxsController < ApplicationController
|
||||||
|
include Pundit
|
||||||
|
|
||||||
|
def index
|
||||||
|
authenticate!
|
||||||
|
|
||||||
|
@site = find_site
|
||||||
|
@invitadxs = @site.invitadxs
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@site = Site.find(params[:site_id])
|
||||||
|
@has_cover = true
|
||||||
|
@invitadx = Invitadx.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@site = Site.find(params[:invitadx][:site])
|
||||||
|
@invitadx = Invitadx.new(invitadx_params)
|
||||||
|
@invitadx.confirmation_token = SecureRandom.hex(16)
|
||||||
|
@invitadx.sites << @site
|
||||||
|
|
||||||
|
if @invitadx.save
|
||||||
|
InvitadxMailer.with(site: @site, invitadx: @invitadx).confirmation_required.deliver
|
||||||
|
redirect_to invitadx_path(@invitadx)
|
||||||
|
else
|
||||||
|
render 'new'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
@has_cover = true
|
||||||
|
@invitadx = Invitadx.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def confirmation
|
||||||
|
@invitadx = Invitadx.find(params[:invitadx_id])
|
||||||
|
@site = @invitadx.sites.find do |site|
|
||||||
|
site.id == params[:site_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
if @invitadx.confirmation_token = params[:confirmation_token]
|
||||||
|
@invitadx.update_attribute :confirmed, true
|
||||||
|
redirect_to site_
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def invitadx_params
|
||||||
|
params.require(:invitadx).permit(:email, :password, :password_confirmation)
|
||||||
|
end
|
||||||
|
end
|
7
app/mailers/invitadx_mailer.rb
Normal file
7
app/mailers/invitadx_mailer.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
class InvitadxMailer < ApplicationMailer
|
||||||
|
def confirmation_required
|
||||||
|
@invitadx = params[:invitadx]
|
||||||
|
@site = params[:site]
|
||||||
|
mail to: @invitadx.email, subject: t('.subject')
|
||||||
|
end
|
||||||
|
end
|
76
app/models/invitadx.rb
Normal file
76
app/models/invitadx.rb
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
class Invitadx < ApplicationRecord
|
||||||
|
has_secure_password
|
||||||
|
validates_uniqueness_of :email
|
||||||
|
|
||||||
|
after_create :create_invitadx_directory!
|
||||||
|
after_save :add_sites!
|
||||||
|
|
||||||
|
# Para facilitar la serialización de Warden
|
||||||
|
def username
|
||||||
|
email
|
||||||
|
end
|
||||||
|
|
||||||
|
def path
|
||||||
|
File.join(Rails.root, '_invitadxs', email)
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO convertir el Pathname en un helper
|
||||||
|
def site_dirs
|
||||||
|
return [] unless Dir.exists? path
|
||||||
|
Pathname.new(path).children.map(&:expand_path).map(&:to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def sites
|
||||||
|
@sites ||= site_dirs.map do |site|
|
||||||
|
Site.find(File.basename(site))
|
||||||
|
end.compact
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Crea el directorio en _sites
|
||||||
|
def create_invitadx_directory!
|
||||||
|
FileUtils.mkdir_p(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Agrega el sitio a las invitadxs y viceversa
|
||||||
|
def add_sites!
|
||||||
|
sites.each do |site|
|
||||||
|
dir = File.join(path, site.name)
|
||||||
|
file = site.invitadxs_file
|
||||||
|
|
||||||
|
unless File.exists? dir
|
||||||
|
FileUtils.ln_s File.join('..', '..', '_sites', site.name), dir
|
||||||
|
end
|
||||||
|
|
||||||
|
if File.exists? file
|
||||||
|
invitadxs = File.read(file).split("\n")
|
||||||
|
invitadxs_orig = invitadxs.dup
|
||||||
|
invitadxs << email unless invitadxs.include? email
|
||||||
|
else
|
||||||
|
invitadxs_orig = []
|
||||||
|
invitadxs = [email]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Solo escribir los cambios si hubo cambios en la lista
|
||||||
|
return if invitadxs_orig == invitadxs
|
||||||
|
|
||||||
|
r = File.open(file, File::RDWR | File::CREAT, 0o640) do |f|
|
||||||
|
# Bloquear el archivo para que no sea accedido por otro
|
||||||
|
# proceso u otra editora
|
||||||
|
f.flock(File::LOCK_EX)
|
||||||
|
|
||||||
|
# Empezar por el principio
|
||||||
|
f.rewind
|
||||||
|
|
||||||
|
# Escribir la fecha de creación
|
||||||
|
f.write(invitadxs.join("\n"))
|
||||||
|
|
||||||
|
# Eliminar el resto
|
||||||
|
f.flush
|
||||||
|
f.truncate(f.pos)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,6 +11,15 @@ class Site
|
||||||
@collections = {}
|
@collections = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Este sitio acepta invitadxs?
|
||||||
|
def invitadxs?
|
||||||
|
jekyll.config.fetch('invitadxs', false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def cover
|
||||||
|
"/covers/#{name}.png"
|
||||||
|
end
|
||||||
|
|
||||||
# Determina si el sitio está en varios idiomas
|
# Determina si el sitio está en varios idiomas
|
||||||
def i18n?
|
def i18n?
|
||||||
!translations.empty?
|
!translations.empty?
|
||||||
|
@ -173,6 +182,16 @@ class Site
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def invitadxs_file
|
||||||
|
File.join(path, '.invitadxs')
|
||||||
|
end
|
||||||
|
|
||||||
|
def invitadxs
|
||||||
|
@invitadxs ||= File.read(invitadxs_file).split("\n").map do |i|
|
||||||
|
Invitadx.find_by_email(i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def failed_file
|
def failed_file
|
||||||
File.join(path, '.failed')
|
File.join(path, '.failed')
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
%h1= t('.hi')
|
||||||
|
|
||||||
|
%p= t('.body')
|
||||||
|
|
||||||
|
%code= site_invitadx_confirmation_url(@site, @invitadx, confirmation_token: @invitadx.confirmation_token)
|
5
app/views/invitadx_mailer/confirmation_required.txt.haml
Normal file
5
app/views/invitadx_mailer/confirmation_required.txt.haml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
= t('.hi')
|
||||||
|
|
||||||
|
= t('.body')
|
||||||
|
|
||||||
|
= site_invitadx_confirmation_url(@site, @invitadx, confirmation_token: @invitadx.confirmation_token)
|
13
app/views/invitadxs/index.haml
Normal file
13
app/views/invitadxs/index.haml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
.row
|
||||||
|
.col
|
||||||
|
= render 'layouts/breadcrumb', crumbs: [ t('sites.index'), t('.title') ]
|
||||||
|
.row
|
||||||
|
.col
|
||||||
|
%h1= t('.title')
|
||||||
|
|
||||||
|
%table.table.table-striped.table-condensed
|
||||||
|
%tbody
|
||||||
|
- @invitadxs.each do |invitadx|
|
||||||
|
%tr
|
||||||
|
%td= invitadx.email
|
||||||
|
%td= invitadx.created_at
|
31
app/views/invitadxs/new.haml
Normal file
31
app/views/invitadxs/new.haml
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
.row.align-items-center.justify-content-center.full-height
|
||||||
|
.col-md-6.align-self-center
|
||||||
|
- if @invitadx.errors.full_messages.empty?
|
||||||
|
.alert.alert-dismissible.alert-info.fade.show{role: 'alert'}
|
||||||
|
= @site.config.dig('welcome', 'message') || t('.welcome')
|
||||||
|
%button.close{type: 'button',
|
||||||
|
data: { dismiss: 'alert' },
|
||||||
|
'aria-label': t('help.close') }
|
||||||
|
%span{'aria-hidden': true} ×
|
||||||
|
- else
|
||||||
|
.alert.alert-dismissible.alert-info.fade.show{role: 'alert'}
|
||||||
|
%ul
|
||||||
|
- @invitadx.errors.full_messages.each do |message|
|
||||||
|
%li= message
|
||||||
|
%button.close{type: 'button',
|
||||||
|
data: { dismiss: 'alert' },
|
||||||
|
'aria-label': t('help.close') }
|
||||||
|
%span{'aria-hidden': true} ×
|
||||||
|
|
||||||
|
= form_for @invitadx do |f|
|
||||||
|
= f.hidden_field :site, value: @site.id
|
||||||
|
.form-group
|
||||||
|
= f.email_field :email, class: 'form-control', placeholder: t('.email')
|
||||||
|
.form-group
|
||||||
|
= f.password_field :password, class: 'form-control', placeholder: t('.password')
|
||||||
|
.form-group
|
||||||
|
= f.password_field :password_confirmation, class: 'form-control', placeholder: t('.password_confirmation')
|
||||||
|
|
||||||
|
.form-group
|
||||||
|
- button = @site.config.dig('welcome', 'button')
|
||||||
|
= f.submit t('.submit'), class: 'btn btn-lg btn-primary btn-block', style: (button) ? "background-color: #{button};" : ''
|
3
app/views/invitadxs/show.haml
Normal file
3
app/views/invitadxs/show.haml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.row.align-items-center.justify-content-center.full-height
|
||||||
|
.col-md-6.align-self-center
|
||||||
|
= t('.confirmation_sent')
|
|
@ -6,7 +6,7 @@
|
||||||
= csrf_meta_tags
|
= csrf_meta_tags
|
||||||
= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
|
= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
|
||||||
= javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
|
= javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
|
||||||
%body{class: @has_cover ? 'background-cover' : ''}
|
%body{class: @has_cover ? 'background-cover' : '', style: @has_cover ? "background-image: url(#{@site.try(:cover)})": ''}
|
||||||
.container-fluid
|
.container-fluid
|
||||||
= yield
|
= yield
|
||||||
%footer.footer
|
%footer.footer
|
||||||
|
|
3
app/views/layouts/mailer.html.haml
Normal file
3
app/views/layouts/mailer.html.haml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
%html
|
||||||
|
%body
|
||||||
|
= yield
|
1
app/views/layouts/mailer.text.haml
Normal file
1
app/views/layouts/mailer.text.haml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
= yield
|
|
@ -1,16 +1,9 @@
|
||||||
# Be sure to restart your server when you modify this file.
|
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
||||||
|
inflect.plural 'invitadx', 'invitadxs'
|
||||||
|
inflect.singular 'invitadxs', 'invitadx'
|
||||||
|
end
|
||||||
|
|
||||||
# Add new inflection rules using the following format. Inflections
|
ActiveSupport::Inflector.inflections(:es) do |inflect|
|
||||||
# are locale specific, and you may define rules for as many different
|
inflect.plural 'invitadx', 'invitadxs'
|
||||||
# locales as you wish. All of these examples are active by default:
|
inflect.singular 'invitadxs', 'invitadx'
|
||||||
# ActiveSupport::Inflector.inflections(:en) do |inflect|
|
end
|
||||||
# inflect.plural /^(ox)$/i, '\1en'
|
|
||||||
# inflect.singular /^(ox)en/i, '\1'
|
|
||||||
# inflect.irregular 'person', 'people'
|
|
||||||
# inflect.uncountable %w( fish sheep )
|
|
||||||
# end
|
|
||||||
|
|
||||||
# These inflection rules are supported but not enabled by default:
|
|
||||||
# ActiveSupport::Inflector.inflections(:en) do |inflect|
|
|
||||||
# inflect.acronym 'RESTful'
|
|
||||||
# end
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
require 'warden/imap'
|
require 'warden/imap'
|
||||||
|
require 'warden/email_and_password'
|
||||||
|
|
||||||
Rails.configuration.middleware.use RailsWarden::Manager do |manager|
|
Rails.configuration.middleware.use RailsWarden::Manager do |manager|
|
||||||
manager.default_strategies :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
|
||||||
|
|
||||||
|
@ -11,8 +12,9 @@ class Warden::SessionSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def deserialize(keys)
|
def deserialize(keys)
|
||||||
Usuaria.find(keys.first)
|
Invitadx.find_by_email(keys.first) || Usuaria.find(keys.first)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Warden::Strategies.add(:imap, Warden::IMAP::Strategy)
|
Warden::Strategies.add(:imap, Warden::IMAP::Strategy)
|
||||||
|
Warden::Strategies.add(:email, Warden::EmailAndPassword::Strategy)
|
||||||
|
|
|
@ -1,4 +1,13 @@
|
||||||
en:
|
en:
|
||||||
|
activerecord:
|
||||||
|
errors:
|
||||||
|
models:
|
||||||
|
invitadx:
|
||||||
|
attributes:
|
||||||
|
email:
|
||||||
|
taken: 'This e-mail address is already taken, please choose another'
|
||||||
|
password_confirmation:
|
||||||
|
confirmation: The passwords don't match
|
||||||
errors:
|
errors:
|
||||||
argument_error: 'Argument `%{argument}` must be an instance of %{class}'
|
argument_error: 'Argument `%{argument}` must be an instance of %{class}'
|
||||||
unknown_locale: 'Unknown %{locale} locale'
|
unknown_locale: 'Unknown %{locale} locale'
|
||||||
|
@ -6,6 +15,14 @@ en:
|
||||||
reorder: "We're sorry, we couldn't reorder the articles"
|
reorder: "We're sorry, we couldn't reorder the articles"
|
||||||
disordered: "The posts are disordered, this will prevent you from reordering them!"
|
disordered: "The posts are disordered, this will prevent you from reordering them!"
|
||||||
disordered_button: 'Reorder!'
|
disordered_button: 'Reorder!'
|
||||||
|
invitadxs:
|
||||||
|
index:
|
||||||
|
title: Guests
|
||||||
|
new:
|
||||||
|
email: E-Mail
|
||||||
|
password: Password
|
||||||
|
password_confirmation: Repeat password
|
||||||
|
submit: Register
|
||||||
info:
|
info:
|
||||||
posts:
|
posts:
|
||||||
reorder: "The articles have been reordered!"
|
reorder: "The articles have been reordered!"
|
||||||
|
|
|
@ -1,4 +1,13 @@
|
||||||
es:
|
es:
|
||||||
|
activerecord:
|
||||||
|
errors:
|
||||||
|
models:
|
||||||
|
invitadx:
|
||||||
|
attributes:
|
||||||
|
email:
|
||||||
|
taken: 'Esa cuenta ya está tomada, por favor elige otra.'
|
||||||
|
password_confirmation:
|
||||||
|
confirmation: Las contraseñas no coinciden
|
||||||
errors:
|
errors:
|
||||||
argument_error: 'El argumento `%{argument}` debe ser una instancia de %{class}'
|
argument_error: 'El argumento `%{argument}` debe ser una instancia de %{class}'
|
||||||
unknown_locale: 'El idioma %{locale} es desconocido'
|
unknown_locale: 'El idioma %{locale} es desconocido'
|
||||||
|
@ -6,6 +15,14 @@ es:
|
||||||
reorder: "Lo sentimos, no pudimos reordenar los artículos."
|
reorder: "Lo sentimos, no pudimos reordenar los artículos."
|
||||||
disordered: 'Los artículos no tienen número de orden, esto impedirá que los puedas reordenar'
|
disordered: 'Los artículos no tienen número de orden, esto impedirá que los puedas reordenar'
|
||||||
disordered_button: '¡Reordenar!'
|
disordered_button: '¡Reordenar!'
|
||||||
|
invitadxs:
|
||||||
|
index:
|
||||||
|
title: Invitadxs
|
||||||
|
new:
|
||||||
|
email: Correo electrónico
|
||||||
|
password: Contraseña
|
||||||
|
password_confirmation: Repite la contraseña
|
||||||
|
submit: Registrarme
|
||||||
info:
|
info:
|
||||||
posts:
|
posts:
|
||||||
reorder: "¡Los artículos fueron reordenados!"
|
reorder: "¡Los artículos fueron reordenados!"
|
||||||
|
|
|
@ -9,9 +9,15 @@ Rails.application.routes.draw do
|
||||||
|
|
||||||
get '/sites/:site_id/public/:type/:basename', to: 'sites#send_public_file'
|
get '/sites/:site_id/public/:type/:basename', to: 'sites#send_public_file'
|
||||||
|
|
||||||
|
resources :invitadxs, only: [:create, :show] do
|
||||||
|
end
|
||||||
|
|
||||||
resources :sites, only: [:index, :show], constraints: { site_id: /[^\/]+/, id: /[^\/]+/ } do
|
resources :sites, only: [:index, :show], constraints: { site_id: /[^\/]+/, id: /[^\/]+/ } do
|
||||||
resources :posts
|
resources :posts
|
||||||
resources :templates
|
resources :templates
|
||||||
|
resources :invitadxs, only: [:index, :new] do
|
||||||
|
get :confirmation, to: 'invitadxs#confirmation'
|
||||||
|
end
|
||||||
|
|
||||||
get 'i18n', to: 'i18n#index'
|
get 'i18n', to: 'i18n#index'
|
||||||
get 'i18n/edit', to: 'i18n#edit'
|
get 'i18n/edit', to: 'i18n#edit'
|
||||||
|
|
11
db/migrate/20180925183241_create_invitadxs.rb
Normal file
11
db/migrate/20180925183241_create_invitadxs.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
class CreateInvitadxs < ActiveRecord::Migration[5.1]
|
||||||
|
def change
|
||||||
|
create_table :invitadxs do |t|
|
||||||
|
t.timestamps
|
||||||
|
t.string :password_digest
|
||||||
|
t.string :email, unique: true, index: true
|
||||||
|
t.string :confirmation_token
|
||||||
|
t.boolean :confirmed
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
53
doc/invitadxs.md
Normal file
53
doc/invitadxs.md
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
# Gestión de usuarixs invitadxs
|
||||||
|
|
||||||
|
Lxs usuarixs invitadxs solo tienen cuenta en Sutty, no comparten cuenta
|
||||||
|
con el resto del sistema (Sutty está integrada a otras cuentas vía
|
||||||
|
IMAP).
|
||||||
|
|
||||||
|
Pueden cambiar su contraseña y recuperarla.
|
||||||
|
|
||||||
|
Cuando se loguean, solo pueden ver sus artículos y editarlos. También
|
||||||
|
pueden crear nuevos.
|
||||||
|
|
||||||
|
Cuando crean un artículo o cuando lo editan, los artículos pasan a
|
||||||
|
estado borrador. Solo las usuarias de Sutty pueden revisar el artículo
|
||||||
|
y publicarlo.
|
||||||
|
|
||||||
|
Cada invitadx está asociadx a uno o más sitios.
|
||||||
|
|
||||||
|
|
||||||
|
## Idea
|
||||||
|
|
||||||
|
Que cada sitio gestione sus propias cuentas usando un archivo en formato
|
||||||
|
`/etc/passwd` (ver `man 5 passwd`).
|
||||||
|
|
||||||
|
Con esto habría portabilidad de cuentas junto con los sitios, pero sería
|
||||||
|
un problema para poder gestionar varios sitios con cuentas compartidas.
|
||||||
|
|
||||||
|
## Temporal
|
||||||
|
|
||||||
|
Usar `devise` con una base de datos SQLite. La idea es descartarla más
|
||||||
|
adelante y tener un `passwd` + `shadow` de Sutty. Sino vamos a empezar
|
||||||
|
a poner cosas en una base de datos y no es la idea...
|
||||||
|
|
||||||
|
**No se puede usar devise porque toma el control de toda la gestión de
|
||||||
|
usuarias.**
|
||||||
|
|
||||||
|
## Implementación
|
||||||
|
|
||||||
|
Para poder separar la autenticación de usuarias de invitadxs, cada
|
||||||
|
controlador tiene su propio `namespace`, de forma que no se crucen
|
||||||
|
funcionalidades.
|
||||||
|
|
||||||
|
Lxs invitadxs se almacenan con email y contraseña en una base de datos
|
||||||
|
SQLite3.
|
||||||
|
|
||||||
|
La pertenencia a un sitio se almacena en el archivo `.invitadxs` de cada
|
||||||
|
sitio (como `.usuarias`).
|
||||||
|
|
||||||
|
Además, se vincula el sitio al directorio de invitadx para poder tener
|
||||||
|
acceso a varios sitios.
|
||||||
|
|
||||||
|
El directorio de lx invitadx es `_invitadxs/direccion@mail`.
|
||||||
|
|
||||||
|
El registro de cuentas se hace en base al sitio.
|
32
lib/warden/email_and_password.rb
Normal file
32
lib/warden/email_and_password.rb
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
require 'email_address'
|
||||||
|
module Warden
|
||||||
|
module EmailAndPassword
|
||||||
|
|
||||||
|
class Strategy < Warden::Strategies::Base
|
||||||
|
def valid?
|
||||||
|
return false unless params.include? 'username'
|
||||||
|
return false unless params.include? 'password'
|
||||||
|
username = params['username']
|
||||||
|
@email = EmailAddress.new(username, host_validation: :a)
|
||||||
|
|
||||||
|
Rails.logger.error [username, @email.error].join(': ') unless @email.valid?
|
||||||
|
|
||||||
|
@email.valid?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Autentica a una posible invitadx, no fallamos para que haya
|
||||||
|
# fallback con IMAP
|
||||||
|
def authenticate!
|
||||||
|
u = Invitadx.find_by_email(params['username'])
|
||||||
|
|
||||||
|
if u.try(:authenticate, params['password'])
|
||||||
|
if u.confirmed?
|
||||||
|
success! u
|
||||||
|
else
|
||||||
|
fail! 'unconfirmed'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
0
public/covers/.keep
Normal file
0
public/covers/.keep
Normal file
Loading…
Reference in a new issue