mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-15 02:21:42 +00:00
pedir consentimiento para invitaciones
This commit is contained in:
parent
1bf3fc0128
commit
a9990397ba
12 changed files with 139 additions and 141 deletions
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue