ver artículos como invitade

This commit is contained in:
f 2019-07-04 13:23:43 -03:00
parent 847b798a82
commit a125b388bb
No known key found for this signature in database
GPG key ID: 2AE5A13E321F953D
15 changed files with 243 additions and 18 deletions

View file

@ -23,6 +23,9 @@ class ApplicationController < ActionController::Base
# lugar de desperdiciar una consulta # lugar de desperdiciar una consulta
current_usuarie.sites.find_by_name(id) || current_usuarie.sites.find_by_name(id) ||
current_usuarie.sites_as_invitade.find_by_name(id) current_usuarie.sites_as_invitade.find_by_name(id)
# TODO: reenviar a un 403 si el sitio ya no está permitido para le
# usuarie
end end
def find_post(site) def find_post(site)

View file

@ -0,0 +1,54 @@
# frozen_string_literal: true
# Controlador de Usuaries
class UsuariesController < ApplicationController
include Pundit
before_action :authenticate_usuarie!
# Mostrar todes les usuaries e invitades de un sitio
def index
@site = find_site
site_usuarie = SiteUsuarie.new(@site, current_usuarie)
authorize site_usuarie
@policy = policy(site_usuarie)
end
# Desasociar une usuarie de un sitio
def destroy
@site = find_site
authorize SiteUsuarie.new(@site, current_usuarie)
@usuarie = Usuarie.find(params[:id])
@usuarie.sites.delete(@site)
redirect_to site_usuaries_path
end
# Convertir une usuarie en invitade
def demote
@site = find_site
authorize SiteUsuarie.new(@site, current_usuarie)
@usuarie = Usuarie.find(params[:usuarie_id])
@usuarie.sites.delete(@site)
@site.invitades << @usuarie
redirect_to site_usuaries_path
end
# Convertir invitade en usuarie
def promote
@site = find_site
authorize SiteUsuarie.new(@site, current_usuarie)
@usuarie = Usuarie.find(params[:usuarie_id])
@usuarie.sites_as_invitade.delete(@site)
@site.usuaries << @usuarie
redirect_to site_usuaries_path
end
end

View file

@ -0,0 +1,12 @@
# frozen_string_literal: true
# Clase genérica a través de la que podemos obtener la relación entre
# sitio y usuarie
class SiteUsuarie
attr_reader :site, :usuarie
def initialize(site, usuarie)
@site = site
@usuarie = usuarie
end
end

View file

@ -9,6 +9,7 @@ class Usuarie < ApplicationRecord
validates_uniqueness_of :email validates_uniqueness_of :email
has_and_belongs_to_many :sites has_and_belongs_to_many :sites
has_and_belongs_to_many :sites_as_invitade, class_name: 'Site', has_and_belongs_to_many :sites_as_invitade,
join_table: 'invitades_sites' class_name: 'Site',
join_table: 'invitades_sites'
end end

View file

@ -4,7 +4,7 @@
# #
# TODO: Implementar Invitadx # TODO: Implementar Invitadx
class PostPolicy class PostPolicy
attr_reader :post attr_reader :post, :usuarie
def initialize(usuarie, post) def initialize(usuarie, post)
@usuarie = usuarie @usuarie = usuarie
@ -17,7 +17,7 @@ class PostPolicy
# Lxs invitadxs solo pueden ver sus propios posts # Lxs invitadxs solo pueden ver sus propios posts
def show? def show?
true || post.author == usuarix.email post.site.usuarie?(usuarie) || post.author == usuarie.email
end end
def new? def new?
@ -34,7 +34,7 @@ class PostPolicy
# Lxs invitadxs solo pueden modificar sus propios artículos # Lxs invitadxs solo pueden modificar sus propios artículos
def update? def update?
true || post.author == usuarix.email post.site.usuarie?(usuarie) || post.author == usuarie.email
end end
# Solo las usuarias pueden eliminar artículos. Lxs invitadxs pueden # Solo las usuarias pueden eliminar artículos. Lxs invitadxs pueden
@ -58,8 +58,8 @@ class PostPolicy
# #
# Lxs invitadxs solo pueden ver sus propios posts # Lxs invitadxs solo pueden ver sus propios posts
def resolve def resolve
# TODO: filtrar por invitade return scope if scope.try(:first).try(:site).try(:usuarie?, usuarie)
return scope
# Asegurarse que al menos devolvemos [] # Asegurarse que al menos devolvemos []
[scope.find do |post| [scope.find do |post|
post.author == usuarie.email post.author == usuarie.email

View file

@ -0,0 +1,35 @@
# frozen_string_literal: true
# Gestiona la relación entre sitios y usuaries
class SiteUsuariePolicy
attr_reader :usuarie, :site_usuarie
def initialize(usuarie, site_usuarie)
@usuarie = usuarie
@site_usuarie = site_usuarie
end
def index?
usuarie?
end
# Les usuaries pueden remover a otres usuaries e invitades del sitio
def destroy?
usuarie?
end
# Les usuaries pueden convertir a otres usuaries en invitades
def demote?
usuarie?
end
def promote?
usuarie?
end
private
def usuarie?
site_usuarie.site.usuarie? usuarie
end
end

View file

@ -17,7 +17,7 @@
= link_to t('posts.new_with_template', template: @site.templates.first.id.humanize), = link_to t('posts.new_with_template', template: @site.templates.first.id.humanize),
new_site_post_path(@site, lang: @lang, template: @site.templates.first.id), new_site_post_path(@site, lang: @lang, template: @site.templates.first.id),
class: 'btn btn-success' class: 'btn btn-success'
- if policy(Post).usuaria? - if @site.usuarie? current_usuarie
%button.btn.btn-success.dropdown-toggle.dropdown-toggle-split{data: { toggle: 'split' }, %button.btn.btn-success.dropdown-toggle.dropdown-toggle-split{data: { toggle: 'split' },
aria: { haspopup: 'true', expanded: 'false' }} aria: { haspopup: 'true', expanded: 'false' }}
%span.sr-only= t('posts.dropdown') %span.sr-only= t('posts.dropdown')

View file

@ -33,6 +33,12 @@
text: t('i18n.edit'), text: t('i18n.edit'),
type: 'info', type: 'info',
link: site_i18n_edit_path(site) 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 policy(site).build?
- if site.enqueued? - if site.enqueued?
= render 'layouts/btn_with_tooltip', = render 'layouts/btn_with_tooltip',

View file

@ -0,0 +1,50 @@
.row
.col
= render 'layouts/breadcrumb',
crumbs: [ link_to(t('sites.index'), sites_path),
@site.name,
link_to(t('posts.index'),
site_usuaries_path(@site)) ]
= render 'layouts/help', help: t('help.breadcrumbs')
.row
.col
%h1= t('.title')
.row
.col
-# Una tabla de usuaries y otra de invitades, con acciones
- %i[usuaries invitades].each do |u|
%h2= t(".#{u.to_s}")
%p= t(".help.#{u.to_s}")
%table.table.table-striped.table-condensed
%tbody
- @site.send(u).each do |cuenta|
%tr
-# TODO: avatares
%td= cuenta.email
%td
.btn-group{role: 'group', 'aria-label': t('.actions')}
- if @policy.demote? && @site.usuarie?(cuenta)
= link_to t('.demote.text'),
site_usuarie_demote_path(@site, cuenta),
class: 'btn btn-warning',
data: { toggle: 'tooltip',
confirm: t('.demote.confirm')},
title: t('.help.demote'),
method: :patch
- if @policy.promote? && @site.invitade?(cuenta)
= link_to t('.promote.text'),
site_usuarie_promote_path(@site, cuenta),
class: 'btn btn-success',
data: { toggle: 'tooltip',
confirm: t('.promote.confirm')},
title: t('.help.promote'),
method: :patch
- if @policy.destroy?
= link_to t('.destroy.text'),
site_usuarie_path(@site, cuenta),
class: 'btn btn-danger',
data: { toggle: 'tooltip',
confirm: t('.destroy.confirm')},
title: t('.help.destroy'),
method: :delete

View file

@ -258,3 +258,24 @@ en:
blank: Nothing blank: Nothing
destroy: Delete destroy: Delete
confirm_destroy: Are you sure? confirm_destroy: Are you sure?
usuaries:
index:
help:
self: Self-manage who has access to this site
destroy: Remove access to this site
usuaries: 'Users can self-manage every section and option of this site, posts, review and approve posts from guests, publish changes, etc.'
invitades: 'Guests can only create new posts and edit those authored by them. Any change needs review and approval by a user.'
demote: Removes privileges for this user
promote: Gives privileges to this guest
title: Users and Guests
usuaries: Users
invitades: Guests
destroy:
text: 'Remove access'
confirm: "Remove access to this site? The account itself is not deleted, but it won't be able to make changes to this site."
demote:
text: 'Convert to guest'
confirm: 'Convert to guest? They can only edit their own posts and will need approval from other user to publish them.'
promote:
text: 'Convert to user'
confirm: 'Convert to user? They will gain full access to self-manage this site.'

View file

@ -265,3 +265,24 @@ es:
blank: En blanco blank: En blanco
destroy: Borrar destroy: Borrar
confirm_destroy: ¿Estás segurx? confirm_destroy: ¿Estás segurx?
usuaries:
index:
help:
self: Gestionar quiénes tienen acceso a este sitio
destroy: Impide el acceso a la gestión del sitio
usuaries: 'Les usuaries pueden gestionar todas las secciones del sitio, crear artículos, revisar y aprobar artículos de invitades, publicar los cambios, etc.'
invitades: 'Les invitades sólo pueden crear artículos nuevos y modificar los que cargaron. Todos los cambios que hagan necesitan la revisión y aprobación de une usuarie.'
demote: Quita privilegios a este usuarie
promote: Otorga privilegios a este invitade
title: Usuaries e invitades
usuaries: Usuaries
invitades: Invitades
destroy:
text: 'Quitar acceso'
confirm: '¿Quitar acceso a este sitio? La cuenta no será modificada, solo no podrá hacer cambios en este sitio.'
demote:
text: 'Convertir en invitade'
confirm: '¿Convertir en invitade? Solo tendrá acceso a sus propios artículos y necesitará la aprobación de otre usuarie para publicarlos.'
promote:
text: 'Convertir en usuarie'
confirm: '¿Convertir en usuarie? Ganará acceso a la gestión completa del sitio.'

View file

@ -16,16 +16,21 @@ Rails.application.routes.draw do
get 'public/:type/:basename', to: 'sites#send_public_file' get 'public/:type/:basename', to: 'sites#send_public_file'
resources :posts # Gestionar usuaries
resources :templates resources :usuaries do
resources :invitadxs, only: %i[index new show] do patch 'demote', to: 'usuaries#demote'
get :confirmation, to: 'invitadxs#confirmation' patch 'promote', to: 'usuaries#promote'
end end
# Gestionar artículos
resources :posts
# Gestionar traducciones
get 'i18n', to: 'i18n#index' get 'i18n', to: 'i18n#index'
get 'i18n/edit', to: 'i18n#edit' get 'i18n/edit', to: 'i18n#edit'
post 'i18n', to: 'i18n#update' post 'i18n', to: 'i18n#update'
# Compilar el sitio
post 'enqueue', to: 'sites#enqueue' post 'enqueue', to: 'sites#enqueue'
get 'build_log', to: 'sites#build_log' get 'build_log', to: 'sites#build_log'
post 'reorder_posts', to: 'sites#reorder_posts' post 'reorder_posts', to: 'sites#reorder_posts'

View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
# Agrega índices únicos a la combinación de Usuarie y Site para no tener
# accesos duplicados.
class AddUniqueToInvitadesAndUsuaries < ActiveRecord::Migration[5.2]
def change
%i[invitades_sites sites_usuaries].each do |t|
remove_index t, :site_id
remove_index t, :usuarie_id
add_index t, %i[site_id usuarie_id], unique: true
end
end
end

View file

@ -12,12 +12,11 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20_190_703_200_455) do ActiveRecord::Schema.define(version: 20_190_705_195_758) do
create_table 'invitades_sites', id: false, force: :cascade do |t| create_table 'invitades_sites', id: false, force: :cascade do |t|
t.integer 'site_id' t.integer 'site_id'
t.integer 'usuarie_id' t.integer 'usuarie_id'
t.index ['site_id'], name: 'index_invitades_sites_on_site_id' t.index %w[site_id usuarie_id], name: 'index_invitades_sites_on_site_id_and_usuarie_id', unique: true
t.index ['usuarie_id'], name: 'index_invitades_sites_on_usuarie_id'
end end
create_table 'sites', force: :cascade do |t| create_table 'sites', force: :cascade do |t|
@ -30,8 +29,7 @@ ActiveRecord::Schema.define(version: 20_190_703_200_455) do
create_table 'sites_usuaries', id: false, force: :cascade do |t| create_table 'sites_usuaries', id: false, force: :cascade do |t|
t.integer 'site_id' t.integer 'site_id'
t.integer 'usuarie_id' t.integer 'usuarie_id'
t.index ['site_id'], name: 'index_sites_usuaries_on_site_id' t.index %w[site_id usuarie_id], name: 'index_sites_usuaries_on_site_id_and_usuarie_id', unique: true
t.index ['usuarie_id'], name: 'index_sites_usuaries_on_usuarie_id'
end end
create_table 'usuaries', force: :cascade do |t| create_table 'usuaries', force: :cascade do |t|

View file

@ -36,4 +36,10 @@ De lo contrario necesitamos establecer roles y ya entramos en las
dificultades que decíamos más arriba. dificultades que decíamos más arriba.
No podemos saber desde cuándo se creo la relación, a menos que tengamos No podemos saber desde cuándo se creo la relación, a menos que tengamos
una tabla de actividades. una tabla de actividades por separado.
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
usuaries e invitades a su sitio (via correo de invitación).