From 067a6144e4dccf19f0dbf6f79e40db04f910efe3 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 8 Jul 2019 17:58:14 -0300 Subject: [PATCH] aceptar colaboraciones publicas --- .rubocop.yml | 3 + app/controllers/collaborations_controller.rb | 71 ++++++++++++++++++++ app/models/collaboration.rb | 4 ++ app/models/usuarie.rb | 16 +++++ app/policies/collaboration_policy.rb | 12 ++++ app/views/collaborations/collaborate.haml | 24 +++++++ config/initializers/devise.rb | 2 +- config/locales/devise.views.es.yml | 2 +- config/locales/en.yml | 10 +-- config/locales/es.yml | 28 +++----- config/routes.rb | 3 + 11 files changed, 151 insertions(+), 24 deletions(-) create mode 100644 app/controllers/collaborations_controller.rb create mode 100644 app/models/collaboration.rb create mode 100644 app/policies/collaboration_policy.rb create mode 100644 app/views/collaborations/collaborate.haml diff --git a/.rubocop.yml b/.rubocop.yml index 2b20bbb..1e38f2f 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -20,6 +20,7 @@ Metrics/AbcSize: - 'app/controllers/invitadxs_controller.rb' - 'app/controllers/i18n_controller.rb' - 'app/controllers/usuaries_controller.rb' + - 'app/controllers/collaborations_controller.rb' Metrics/MethodLength: Exclude: @@ -30,6 +31,8 @@ Metrics/MethodLength: - 'app/controllers/posts_controller.rb' - 'app/controllers/invitadxs_controller.rb' - 'app/controllers/i18n_controller.rb' + - 'app/controllers/collaborations_controller.rb' + Metrics/BlockLength: Exclude: diff --git a/app/controllers/collaborations_controller.rb b/app/controllers/collaborations_controller.rb new file mode 100644 index 0000000..fecb99a --- /dev/null +++ b/app/controllers/collaborations_controller.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +# Controlador para gestionar colaboraciones abiertas +# +# No necesitamos autenticación aun +class CollaborationsController < ApplicationController + include Pundit + + def collaborate + @site = Site.find_by_name(params[:site_id]) + authorize Collaboration.new(@site) + + @has_cover = true + @invitade = current_usuarie || @site.usuaries.build + end + + # Aceptar una colaboración tiene varios pasos + # + # * Si le usuarie no existe, hay que crearle + # + # * Si le usuarie existe, hay que darle un rol si no lo tiene + # + # * Si le usuarie existe y no está logueade, pedirle la contraseña + def accept_collaboration + @site = Site.find_by_name(params[:site_id]) + authorize Collaboration.new(@site) + + @invitade = current_usuarie + @invitade ||= logged_out_invitade + + # Salir si no se pudo validar le invitade + return if @invitade == false + + Usuarie.transaction do + # Si la cuenta no existe, crearla + @invitade ||= Usuarie.create(invitade_params) + # Y asignar un rol si no existe + unless @invitade.rol_for_site(@site) + @site.roles << Rol.create(site: @site, usuarie: @invitade, + temporal: false, rol: 'invitade') + end + + sign_in :usuarie, @invitade unless current_usuarie + + redirect_to site_path(@site) + end + end + + private + + def invitade_params + params.require(:usuarie).permit(:email, :password) + end + + def logged_out_invitade + invitade = Usuarie.find_by_email(invitade_params[:email]) + return unless invitade + + # Si la contraseña no es válida, volver atrás + if invitade.can_sign_in? invitade_params[:password] + invitade + else + invitade.increment_and_lock! + + flash[:warning] = I18n.t('collaborations.password.incorrect') + redirect_to site_collaborate_path(@site) + + false + end + end +end diff --git a/app/models/collaboration.rb b/app/models/collaboration.rb new file mode 100644 index 0000000..cb99117 --- /dev/null +++ b/app/models/collaboration.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +# Una clase que contiene el sitio con el que se va a colaborar +Collaboration = Struct.new(:site) diff --git a/app/models/usuarie.rb b/app/models/usuarie.rb index 4467a4b..a1a2be7 100644 --- a/app/models/usuarie.rb +++ b/app/models/usuarie.rb @@ -14,4 +14,20 @@ class Usuarie < ApplicationRecord def rol_for_site(site) site.roles.merge(roles).first end + + # XXX: Ver increment_and_lock + def can_sign_in?(password) + active_for_authentication? && valid_password?(password) + end + + # XXX: Estamos duplicando la forma en que Devise bloquea acceso + # por intentos fallidos porque no tenemos forma de correr + # validate() desde la estrategia DatabaseAuthenticatable sin + # generar una redirección. + # + # lib/devise/models/lockable.rb + def increment_and_lock! + increment_failed_attempts + lock_access! if attempts_exceeded? && !access_locked? + end end diff --git a/app/policies/collaboration_policy.rb b/app/policies/collaboration_policy.rb new file mode 100644 index 0000000..2a43247 --- /dev/null +++ b/app/policies/collaboration_policy.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +# Política de aceptación de colaboradorxs +CollaborationPolicy = Struct.new(:usuarie, :collaboration) do + def collaborate? + collaboration.site.invitadxs? + end + + def accept_collaboration? + collaboration.site.invitadxs? + end +end diff --git a/app/views/collaborations/collaborate.haml b/app/views/collaborations/collaborate.haml new file mode 100644 index 0000000..f19cdef --- /dev/null +++ b/app/views/collaborations/collaborate.haml @@ -0,0 +1,24 @@ +.row.align-items-center.justify-content-center.full-height + .col-md-10.align-self-center + = raw CommonMarker.render_doc(@site.config.dig('welcome', 'message') || t('.welcome')).to_html + + .col-md-6.align-self-center + -# Copiado y pegado de app/views/devise/registrations/new.haml + - resource = resource_name = @invitade + = form_for(resource, as: resource_name, url: site_collaborate_path(@site), method: :post) do |f| + - unless current_usuarie + = render 'layouts/flash' + .form-group + = f.label :email + = f.email_field :email, autofocus: true, autocomplete: 'email', + class: 'form-control' + .form-group + = f.label :password + - if @minimum_password_length + %em= t('devise.shared.minimum_password_length', count: @minimum_password_length) + = f.password_field :password, autocomplete: 'new-password', + class: 'form-control' + + .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};" : '' diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index a963058..f7e7acd 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -197,7 +197,7 @@ Devise.setup do |config| # website without confirming their account. # Default is 0.days, meaning the user cannot access the website # without confirming their account. - config.allow_unconfirmed_access_for = 2.days + # config.allow_unconfirmed_access_for = 2.days # A period that the user is allowed to confirm their account before # their token becomes invalid. For example, if set to 3.days, the user diff --git a/config/locales/devise.views.es.yml b/config/locales/devise.views.es.yml index b70d6aa..0db4db7 100644 --- a/config/locales/devise.views.es.yml +++ b/config/locales/devise.views.es.yml @@ -45,7 +45,7 @@ es: not_found_in_database: "%{authentication_keys} o contraseña inválidos." timeout: Tu sesión expiró. Por favor, inicia sesión nuevamente para continuar. unauthenticated: Tienes que iniciar sesión o registrarte para poder continuar. - unconfirmed: Tienes que confirmar tu cuenta para poder continuar. + unconfirmed: Te enviamos un correo electrónico para confirmar tu cuenta, por favor acéptalo para poder continuar. mailer: confirmation_instructions: action: Confirmar mi cuenta diff --git a/config/locales/en.yml b/config/locales/en.yml index 4011ecd..d4d2e27 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -20,11 +20,11 @@ en: layouts: breadcrumb: help: Help - invitadx_mailer: - confirmation_required: - subject: "Confirm your e-mail address" - hi: "Hi!" - body: "Please open this link to confirm your e-mail address." + collaborations: + collaborate: + submit: Register + password: + incorrect: 'Wrong password, please try again.' invitadxs: index: title: 'Guests' diff --git a/config/locales/es.yml b/config/locales/es.yml index ee2a406..9e958df 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1,5 +1,12 @@ es: activerecord: + models: + usuarie: Usuarie + attributes: + usuarie: + email: 'Correo electrónico' + password: 'Contraseña' + password_confirmation: 'Confirmación de contraseña' errors: models: invitadx: @@ -20,24 +27,11 @@ es: layouts: breadcrumb: help: Ayuda - invitadx_mailer: - confirmation_required: - subject: "Confirma tu dirección de correo" - hi: "¡Hola!" - body: "Por favor abre esta dirección para confirmar tu cuenta de correo." - invitadxs: - index: - title: Invitadxs - new: - email: Correo electrónico - password: Contraseña - password_confirmation: Repite la contraseña + collaborations: + collaborate: submit: Registrarme - acepta_politicas_de_privacidad: 'Acepto las Políticas de privacidad.' - confirmation: - confirmed: 'Tu cuenta está confirmada, ahora puedes ingresar' - show: - confirmation_sent: "Te hemos enviado un correo de confirmación a tu casilla, por favor confirma tu cuenta antes de continuar." + password: + incorrect: 'Contraseña incorrecta, intenta nuevamente.' info: posts: reorder: "¡Los artículos fueron reordenados!" diff --git a/config/routes.rb b/config/routes.rb index 664a4bb..35bdd76 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -26,6 +26,9 @@ Rails.application.routes.draw do patch 'promote', to: 'usuaries#promote' end + get 'collaborate', to: 'collaborations#collaborate' + post 'collaborate', to: 'collaborations#accept_collaboration' + # Gestionar artículos resources :posts