pedir consentimiento para invitaciones

This commit is contained in:
f 2019-07-08 14:55:19 -03:00
parent 1bf3fc0128
commit a9990397ba
No known key found for this signature in database
GPG key ID: 2AE5A13E321F953D
12 changed files with 139 additions and 141 deletions

View file

@ -1,65 +0,0 @@
# frozen_string_literal: true
# Controlador de Invitadxs
#
# TODO: reemplazar
class InvitadxsController < ApplicationController
include Pundit
def index
authenticate_usuarie!
@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 site_invitadx_path(@site, @invitadx)
else
render 'new'
end
end
def show
@site = Site.find(params[:site_id])
@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
flash[:info] = t('.confirmed')
redirect_to site_invitadxs_login_new_path(@site)
else
redirect_to root_path
end
end
private
def invitadx_params
params.require(:invitadx).permit(:email, :password,
:password_confirmation,
:acepta_politicas_de_privacidad)
end
end

View file

@ -67,10 +67,13 @@ class UsuariesController < ApplicationController
authorize SiteUsuarie.new(@site, current_usuarie)
# Enviar la invitación si es necesario y agregar al sitio
#
# TODO: Pedir consentimiento para agregar a un sitio!
invitaciones.each do |invitacion|
# Si la cuenta no existe, envía una invitación por correo
# Si la cuenta no existe, envía una invitación por correo, sino,
# no se envía nada
#
# TODO: Enviar invitación igual! Podemos no usar el Mailer de
# DeviseInvitations y usar uno propio que contenga texto y se
# envíe de todas formas.
usuarie = Usuarie.invite! email: invitacion.address
# No invitar al sitio si ya estaba en la lista!
@ -83,6 +86,26 @@ class UsuariesController < ApplicationController
redirect_to site_usuaries_path(@site)
end
# Aceptar la invitación
def accept_invitation
@site = find_site
authorize SiteUsuarie.new(@site, current_usuarie)
current_usuarie.rol_for_site(@site).update_attribute :temporal, false
redirect_to sites_path
end
# Declinar la invitación
def reject_invitation
@site = find_site
authorize SiteUsuarie.new(@site, current_usuarie)
current_usuarie.rol_for_site(@site).destroy
redirect_to sites_path
end
private
# Traer todas las invitaciones que al menos tengan usuarie y dominio

View file

@ -11,4 +11,12 @@ class Rol < ApplicationRecord
belongs_to :site
validates_inclusion_of :rol, in: ROLES
def invitade?
rol == 'invitade'
end
def usuarie?
rol == 'usuarie'
end
end

View file

@ -10,4 +10,8 @@ class Usuarie < ApplicationRecord
has_many :roles
has_many :sites, through: :roles
def rol_for_site(site)
site.roles.merge(roles).first
end
end

View file

@ -35,9 +35,22 @@ class SiteUsuariePolicy
usuarie?
end
def accept_invitation?
su = site_usuarie
(usuarie? || invitade?) && su.usuarie.rol_for_site(su.site).temporal
end
def reject_invitation?
accept_invitation?
end
private
def usuarie?
site_usuarie.site.usuarie? usuarie
end
def invitade?
site_usuarie.site.invitade? usuarie
end
end

View file

@ -1,13 +0,0 @@
.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

View file

@ -1,2 +1,2 @@
= link_to text, link, class: "btn btn-#{type || secondary}",
data: { toggle: 'tooltip' }, title: tooltip
data: { toggle: 'tooltip' }, 'aria-role': 'button', title: tooltip

View file

@ -21,46 +21,60 @@
= t('.invitade')
%br
.btn-group{role: 'group', 'aria-label': t('sites.actions')}
- if policy(site).show?
= render 'layouts/btn_with_tooltip',
tooltip: t('help.sites.edit_posts'),
type: 'success',
link: site_path(site),
text: t('sites.posts')
- if policy(SiteTranslation.new(site)).edit?
= render 'layouts/btn_with_tooltip',
tooltip: t('help.sites.edit_translations'),
text: t('i18n.edit'),
type: 'info',
link: site_i18n_edit_path(site)
- if policy(SiteUsuarie.new(site, current_usuarie)).index?
= render 'layouts/btn_with_tooltip',
tooltip: t('usuaries.index.help.self'),
text: t('usuaries.index.title'),
type: 'info',
link: site_usuaries_path(site)
- if policy(site).build?
- if site.enqueued?
- if current_usuarie.rol_for_site(site).temporal
= button_to t('sites.invitations.accept'),
site_usuaries_accept_invitation_path(site),
data: { toggle: 'tooltip' },
title: t('help.sites.invitations.accept'),
method: :patch,
class: 'btn btn-success'
= button_to t('sites.invitations.reject'),
site_usuaries_reject_invitation_path(site),
data: { toggle: 'tooltip' },
title: t('help.sites.invitations.reject'),
method: :patch,
class: 'btn btn-info'
- else
- if policy(site).show?
= render 'layouts/btn_with_tooltip',
tooltip: t('help.sites.enqueued'),
text: t('sites.enqueued'),
type: 'secondary',
link: nil
- else
= form_tag site_enqueue_path(site), method: :post, class: 'form-inline' do
= button_tag type: 'submit',
class: 'btn btn-success',
title: t('help.sites.enqueue'),
data: { toggle: 'tooltip' } do
= fa_icon 'building'
= t('sites.enqueue')
tooltip: t('help.sites.edit_posts'),
type: 'success',
link: site_path(site),
text: t('sites.posts')
- if policy(SiteTranslation.new(site)).edit?
= render 'layouts/btn_with_tooltip',
tooltip: t('help.sites.edit_translations'),
text: t('i18n.edit'),
type: 'info',
link: site_i18n_edit_path(site)
- if policy(SiteUsuarie.new(site, current_usuarie)).index?
= render 'layouts/btn_with_tooltip',
tooltip: t('usuaries.index.help.self'),
text: t('usuaries.index.title'),
type: 'info',
link: site_usuaries_path(site)
- if policy(site).build?
- if site.enqueued?
= render 'layouts/btn_with_tooltip',
tooltip: t('help.sites.enqueued'),
text: t('sites.enqueued'),
type: 'secondary',
link: nil
- else
= form_tag site_enqueue_path(site), method: :post, class: 'form-inline' do
= button_tag type: 'submit',
class: 'btn btn-success',
title: t('help.sites.enqueue'),
data: { toggle: 'tooltip' } do
= fa_icon 'building'
= t('sites.enqueue')
- if policy(site).build_log?
- if site.failed?
%button.btn.btn-danger= t('sites.failed')
- if site.build_log?
= render 'layouts/btn_with_tooltip',
tooltip: t('help.sites.build_log'),
text: t('sites.build_log'),
type: 'warning',
link: site_build_log_path(site)
- if policy(site).build_log?
- if site.failed?
%button.btn.btn-danger= t('sites.failed')
- if site.build_log?
= render 'layouts/btn_with_tooltip',
tooltip: t('help.sites.build_log'),
text: t('sites.build_log'),
type: 'warning',
link: site_build_log_path(site)

View file

@ -90,6 +90,9 @@ en:
build_log: "This is the log for what happened during site
generation. If there was an issue, you'll see it here."
invitade: "Invited users can only add and modify entries but can't publish until reviewed by a user"
invitations:
accept: 'Someone invited you to collaborate on their site. If you accept the invitation, you can access the site.'
reject: 'If you decline, nothing happens.'
close: 'Close help'
markdown:
intro: 'The text is formatted using a syntax called Markdown, a
@ -146,6 +149,9 @@ en:
enqueue: 'Build'
failed: 'Failed!'
build_log: 'Read log'
invitations:
accept: 'Accept invitation'
reject: 'No, thanks'
footer:
powered_by: 'is developed by'
templates:

View file

@ -100,6 +100,9 @@ es:
build_log: 'Este es el registro de lo que sucedió mientras se
generaba el sitio. Si hubo algún problema, saldrá aquí.'
invitade: 'Les invitades a un sitio solo pueden crear y modificar entradas propias y no pueden publicar sin la revisión de une usuarie'
invitations:
accept: 'Alguien te invitó a colaborar en su sitio. Si aceptas la invitación, tendrás acceso a este sitio.'
reject: 'Si rechazas la invitación, no pasa nada.'
close: 'Cerrar ayuda'
markdown:
intro: 'El formato del texto se llama Markdown. Es un formato
@ -155,6 +158,9 @@ es:
enqueue: 'Compilar'
failed: '¡Falló!'
build_log: 'Ver registro'
invitations:
accept: 'Aceptar la invitación'
reject: 'No, gracias'
footer:
powered_by: 'es desarrollada por'
i18n:

View file

@ -19,6 +19,8 @@ Rails.application.routes.draw do
# Gestionar usuaries
get 'usuaries/invite', to: 'usuaries#invite'
post 'usuaries/invite', to: 'usuaries#send_invitations'
patch 'usuaries/accept_invitation', to: 'usuaries#accept_invitation'
patch 'usuaries/reject_invitation', to: 'usuaries#reject_invitation'
resources :usuaries do
patch 'demote', to: 'usuaries#demote'
patch 'promote', to: 'usuaries#promote'

View file

@ -12,7 +12,7 @@ artículos y modificar los propios).
No nos gusta la idea de implementar todo un sistema de privilegios,
primero porque queremos que Sutty sea una plataforma democrática y
segundo porque en nuestra experiencia nadie los usa y prefieren usar una
cuenta de administración.
cuenta de administración para todo.
La migración a Devise nos va a permitir tener recuperación de
contraseñas, registro independiente, correos de bienvenida y varias
@ -27,21 +27,17 @@ integrarla con otras plataformas comunitarias
Los Sitios tienen una contraparte física, de archivos, pero también se
crean en la base de datos para establecer relaciones con Usuaries.
Une Usuarie puede tener muchos Sitios y viceversa. En Rails esto se
llama "tiene y pertenece a muchos" (HABTM en inglés).
Une Usuarie puede tener muchos Sitios y viceversa.
Sin embargo también queremos saber qué rol tienen, con lo que
necesitamos dos tablas de HABTM, una de Invitades y otra de Usuaries.
De lo contrario necesitamos establecer roles y ya entramos en las
dificultades que decíamos más arriba.
No podemos saber desde cuándo se creo la relación, a menos que tengamos
una tabla de actividades por separado.
También queremos saber qué rol tienen, con lo que tenemos una tabla de
roles que establece el rol que une usuarie tiene en un sitio. De lo
contrario necesitamos establecer roles y ya entramos en las dificultades
que decíamos más arriba.
Podemos saber quién es invitade ingresando a un sitio y fijándonos si
está en su lista de invitade. Lo mismo para usuaries.
Les usuaries pueden bloquear invitades y a otres usuaries, y sumar
Les usuaries pueden bloquear invitades y a otres usuaries y sumar
usuaries e invitades a su sitio (via correo de invitación).
## Invitaciones a sitios
@ -56,15 +52,19 @@ participación.
Si no tienen cuenta, tienen que registrarse completando los datos en el
momento, sino se pueden loguear normalmente.
Si ya están logueades, se acepta la invitación inmediatamente.
Para poder hacer una invitación con consentimiento, se guarda el rol
como temporal. Cuando la usuaria acepta la invitación el rol se vuelve
definitivo.
Para poder hacer una invitación con consentimiento, se guarda la
relación en una tabla aparte. Cuando la usuaria acepta la invitación
esa relación se borra y se aplican los cambios.
### Aceptar invitación
En el futuro cambiaríamos el sistema de permisos separados que tenemos
ahora por una tabla de roles (por qué no la hicimos desde el principio!)
con un campo binario que indique si ya se aceptó la invitación o no.
Al ingresar, le usuarie ve su listado de sitios y en la lista ve a
cuales está invitade. Usa el botón de aceptar invitación para poder
acceder al sitio. Si rechaza la invitación, el rol se elimina de la
base de datos.
Eventualmente queremos pasar a un modelo de estados del rol donde
podamos saber si fue rechazado, aceptado, etc.
### Invitades desde la web