From 131e3b00b10b982656ec0b0b30745c62ab9d7cfb Mon Sep 17 00:00:00 2001 From: Josep Egea Date: Mon, 21 Oct 2024 00:38:24 +0200 Subject: [PATCH 01/15] Add login with email --- .rubocop_todo.yml | 6 ---- app/controllers/concerns/with_email_auth.rb | 32 +++++++++++++++++ app/controllers/sessions_controller.rb | 2 ++ app/helpers/application_helper.rb | 8 ++++- app/lib/token.rb | 22 ++++++++++++ app/mailers/application_mailer.rb | 4 +++ app/mailers/user_mailer.rb | 17 +++++++++ app/mailers/usergroup_mailer.rb | 2 +- app/models/user.rb | 27 +++++++++++++- app/views/application/_nav.slim | 2 +- app/views/sessions/email.slim | 9 +++++ app/views/sessions/index.slim | 2 +- app/views/user_mailer/login_link.text.erb | 11 ++++++ app/views/users/edit.slim | 2 +- config/initializers/omniauth.rb | 3 ++ config/locales/en.yml | 14 ++++++++ config/locales/es.yml | 2 +- config/routes.rb | 7 +++- lib/omni_auth/strategies/email.rb | 39 +++++++++++++++++++++ 19 files changed, 197 insertions(+), 14 deletions(-) create mode 100644 app/controllers/concerns/with_email_auth.rb create mode 100644 app/lib/token.rb create mode 100644 app/mailers/application_mailer.rb create mode 100644 app/mailers/user_mailer.rb create mode 100644 app/views/sessions/email.slim create mode 100644 app/views/user_mailer/login_link.text.erb create mode 100644 lib/omni_auth/strategies/email.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 8b5afb7d1..aad92c0f2 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -186,12 +186,6 @@ Rails/ApplicationController: - 'app/controllers/images_controller.rb' - 'app/controllers/labels_controller.rb' -# Offense count: 1 -# Cop supports --auto-correct. -Rails/ApplicationMailer: - Exclude: - - 'app/mailers/usergroup_mailer.rb' - # Offense count: 7 # Configuration parameters: EnforcedStyle. # SupportedStyles: strict, flexible diff --git a/app/controllers/concerns/with_email_auth.rb b/app/controllers/concerns/with_email_auth.rb new file mode 100644 index 000000000..833e3eea6 --- /dev/null +++ b/app/controllers/concerns/with_email_auth.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +# Based on https://github.com/weg-li/weg-li/blob/master/app/controllers/sessions_controller.rb +# Original author: https://github.com/phoet + +module WithEmailAuth + def email; end + + def email_login + email = normalize_email(params[:email]) + if email.present? + token = Token.generate(email) + from = "do-not-reply@#{Whitelabel[:domains].first}" + label_name = t("label.#{Whitelabel[:label_id]}.name") + label_link = Whitelabel[:canonical_url] + UserMailer.login_link(email, token, from, I18n.locale, + label_name, label_link).deliver_later + + redirect_to root_path, notice: t('email_auth.email_sent', email:) + else + flash.now[:alert] = t('email_auth.invalid_email') + + render :email + end + end + + protected + + def normalize_email(email) + email.to_s.strip.downcase + end +end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index eedc5102b..bd23b37c6 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class SessionsController < ApplicationController + include WithEmailAuth + def offline_login user = User.find_by(nickname: params[:nickname]) sign_in(user) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 2ac053949..393bee93a 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -13,7 +13,13 @@ def cache_image_path(model) end def login_providers - %w[twitter github google_oauth2] + %w[twitter github google_oauth2 email] + end + + def icon_for_provider(provider) + return 'envelope' if provider == 'email' + + provider end def whitelabel_stylesheet_link_tag diff --git a/app/lib/token.rb b/app/lib/token.rb new file mode 100644 index 000000000..2b71c03bd --- /dev/null +++ b/app/lib/token.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +# Based on https://github.com/weg-li/weg-li/blob/master/app/lib/token.rb +# Original author: https://github.com/phoet + +class Token + def self.generate( + email, + expiration: 15.minutes, + secret: Rails.application.secrets.secret_key_base + ) + now_seconds = Time.now.to_i + payload = { iss: email, iat: now_seconds, exp: now_seconds + expiration } + token = ::JWT.encode(payload, secret, 'HS256') + Base64.encode64(token) + end + + def self.decode(string, secret: Rails.application.secrets.secret_key_base) + token = Base64.decode64(string) + JWT.decode(token, secret, true, algorithm: 'HS256').first + end +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 000000000..26148f2d6 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +class ApplicationMailer < ActionMailer::Base +end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb new file mode 100644 index 000000000..3ddfb94e9 --- /dev/null +++ b/app/mailers/user_mailer.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# Based on https://github.com/weg-li/weg-li/blob/master/app/mailers/user_mailer.rb +# Original author: https://github.com/phoet + +class UserMailer < ApplicationMailer + def login_link(email, token, from, locale, label_name, label_link) # rubocop:disable Metrics/ParameterLists + @token = token + @from = from + @label_name = label_name + @label_link = label_link + + I18n.with_locale(locale) do + mail from: @from, to: email, subject: t('email_auth.subject', label: label_name) + end + end +end diff --git a/app/mailers/usergroup_mailer.rb b/app/mailers/usergroup_mailer.rb index b57ca1e09..e04fdb8b5 100644 --- a/app/mailers/usergroup_mailer.rb +++ b/app/mailers/usergroup_mailer.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class UsergroupMailer < ActionMailer::Base +class UsergroupMailer < ApplicationMailer def invitation_mail(event) @event = event options = { diff --git a/app/models/user.rb b/app/models/user.rb index 0e7865dfb..462a93940 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class User < ApplicationRecord +class User < ApplicationRecord # rubocop:disable Metrics/ClassLength include Slug extend ApiHandling slugged_by(:nickname) @@ -84,6 +84,31 @@ def handle_google_oauth2_attributes(hash) self.image = hash['info']['image'] end + def handle_email_attributes(hash) + received_email = hash['info']['email'] + + self.nickname = nickname_from_email(received_email) unless nickname + self.name = name_from_email(received_email) unless name + self.image = image_from_email(received_email) unless image + self.email = received_email + end + + def hash_for_email(email) + Digest::SHA256.new.hexdigest(email) + end + + def nickname_from_email(email) + "email_#{hash_for_email(email)}" + end + + def name_from_email(email) + "Email User (#{hash_for_email(email)})" + end + + def image_from_email(email) + "https://www.gravatar.com/avatar/#{hash_for_email(email)}" + end + def with_provider?(provider) authorizations.map(&:provider).include?(provider) end diff --git a/app/views/application/_nav.slim b/app/views/application/_nav.slim index 889186c3d..4276d24f9 100644 --- a/app/views/application/_nav.slim +++ b/app/views/application/_nav.slim @@ -43,7 +43,7 @@ nav.navbar.sticky-top.navbar-expand-lg#nav .dropdown-menu.dropdown-menu-right(aria-labelledby="loginDropdown") - login_providers.each do |provider| = button_to(label_auth_url(provider), class: 'dropdown-item') do - = fa_icon(provider, class: 'fa-fw', text: t("login.#{provider}_login")) + = fa_icon(icon_for_provider(provider), class: 'fa-fw', text: t("login.#{provider}_login")) li.nav-item.dropdown.pr-4 diff --git a/app/views/sessions/email.slim b/app/views/sessions/email.slim new file mode 100644 index 000000000..51eaa5757 --- /dev/null +++ b/app/views/sessions/email.slim @@ -0,0 +1,9 @@ +section + h3= t("email_auth.header") + + .d-flex.justify-content-center + = form_tag email_login_path do |form| + legend= t('email_auth.enter_email') + - email = signed_in? ? current_user.email : params[:email] + = email_field_tag :email, email, placeholder: 'me@example.com', required: true + = submit_tag t('email_auth.submit'), class: 'btn-primary' diff --git a/app/views/sessions/index.slim b/app/views/sessions/index.slim index cf525383c..2b710e0a8 100644 --- a/app/views/sessions/index.slim +++ b/app/views/sessions/index.slim @@ -6,4 +6,4 @@ section - login_providers.each do |provider| li.list-group-item = button_to(label_auth_url(provider)) do - = fa_icon(provider, class: 'fa-fw dropdown-list-icon', text: t("login.#{provider}_login")) + = fa_icon(icon_for_provider(provider), class: 'fa-fw dropdown-list-icon', text: t("login.#{provider}_login")) diff --git a/app/views/user_mailer/login_link.text.erb b/app/views/user_mailer/login_link.text.erb new file mode 100644 index 000000000..6ed826a9c --- /dev/null +++ b/app/views/user_mailer/login_link.text.erb @@ -0,0 +1,11 @@ +<%= t("email_auth.body.salute") %>, + +<%= t("email_auth.body.intro", label: @label_name) %>, + +<%= provider_callback_url(provider: :email, token: @token, host: @label_link) %> + +<%= t("email_auth.body.final_details") %> + +-- +<%= @label_name %> +<%= @label_link %> diff --git a/app/views/users/edit.slim b/app/views/users/edit.slim index 158b8890f..bb1734e34 100644 --- a/app/views/users/edit.slim +++ b/app/views/users/edit.slim @@ -27,7 +27,7 @@ section - login_providers.each do |provider| li = button_to label_auth_url(provider), title: t("login.#{provider}_login"), class: "btn btn-#{existing_providers.include?(provider) ? 'disabled' : 'secondary'}", disabled: existing_providers.include?(provider) do - = fa_icon provider, class: 'fa-fw dropdown-list-icon' + = fa_icon icon_for_provider(provider), class: 'fa-fw dropdown-list-icon' => t("login.#{provider}_login") - if existing_providers.include? provider = fa_icon 'check', class: 'fa-fw dropdown-list-icon' diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 4558a7cae..c2740c8ef 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -1,3 +1,5 @@ +require_relative File.join(Rails.root, 'lib/omni_auth/strategies/email') + OmniAuth.config.logger = Rails.logger Rails.application.config.middleware.use OmniAuth::Builder do @@ -14,4 +16,5 @@ env['omniauth.strategy'].options[:client_secret] = ENV["#{name}_SECRET"] end, } + provider :email end diff --git a/config/locales/en.yml b/config/locales/en.yml index 4ff1bb6dd..cf3e0a73c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -172,3 +172,17 @@ en: previous: "<" next: ">" truncate: "..." + email_auth: + header: "Login with email" + enter_email: "Please, enter your email" + submit: "Authorize" + email_sent: "An email has been sent to %{email} with details for logging in" + invalid_email: "Please enter a valid email address" + subject: "Login to %{label}" + body: + salute: "Hi" + intro: "Use this link to log into %{label}" + good_bye: "Best" + final_details: >- + This link will be valid just for 15 minutes. + If you cannot click on the link, just copy and paste it into your browser address bar. diff --git a/config/locales/es.yml b/config/locales/es.yml index 10bd1737d..fdd274edf 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -57,7 +57,7 @@ es: route: "Mapa" material: "Material" description: "Infos" - no_location: "¡Estamos bustando sitio!" + no_location: "¡Estamos buscando sitio!" home: the_usergroup: "%{usergroup} es un grupo de usuarios, grupo de interés o simplemente de personas interesadas en Ruby. Contacta con nosotros en la siguiente reunión! Todo el mundo es bienvenido, incluso si no tienes mucha experiencia con Ruby." like_to_talk: "Quieres dar una charla en el grupo, o quieres proponer un tema para una?" diff --git a/config/routes.rb b/config/routes.rb index 0b718bf84..8a04b5b83 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -55,12 +55,17 @@ scope '/auth' do get '/', to: 'sessions#index', as: :login - get '/:provider/callback', to: 'sessions#create' + get '/:provider/callback', to: 'sessions#create', as: :provider_callback get '/failure', to: 'sessions#failure' get '/destroy_session', to: 'sessions#destroy', as: :destroy_session get '/offline_login/:nickname', to: 'sessions#offline_login' if Rails.env.development? end + scope "/sessions" do + get "/email", to: "sessions#email" + post "/email_login", to: "sessions#email_login" + end + constraints MainDomainConstraint.new do get '/', to: 'labels#index', as: :labels end diff --git a/lib/omni_auth/strategies/email.rb b/lib/omni_auth/strategies/email.rb new file mode 100644 index 000000000..86a15d743 --- /dev/null +++ b/lib/omni_auth/strategies/email.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +# Based on https://github.com/weg-li/weg-li/blob/master/app/lib/omni_auth/strategies/email.rb +# Original author: https://github.com/phoet + +require 'base64' +require 'English' + +module OmniAuth + module Strategies + class Email + include OmniAuth::Strategy + + def request_phase + redirect '/sessions/email' + end + + def callback_phase + token = request.params['token'] + fail!(:authenticity_error) if token.blank? + + begin + decoded_token = Token.decode(token) + rescue StandardError + fail!(:authenticity_error, $ERROR_INFO) + end + + @email = decoded_token['iss'].to_s.downcase + fail!(:authenticity_error) if @email.blank? + + super + end + + uid { Digest::SHA256.new.hexdigest(@email) } + + info { { 'email' => @email } } + end + end +end From 740639a4a287b3dda740e0aa9fb321c4c817ea69 Mon Sep 17 00:00:00 2001 From: Josep Egea Date: Mon, 21 Oct 2024 21:39:52 +0200 Subject: [PATCH 02/15] Improve name handling when signup is by email --- app/controllers/sessions_controller.rb | 9 ++++++++- app/controllers/users_controller.rb | 7 ++++++- app/models/user.rb | 12 +++++++++--- config/locales/en.yml | 1 + 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index bd23b37c6..0045ed1a6 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -21,7 +21,14 @@ def create options = { alert: t('flash.duplicate_nick', name: e.nickname) } end - redirect_to request.env['omniauth.origin'].presence || root_path, options + redirect_path = request.env['omniauth.origin'].presence || root_path + + if current_user&.missing_name? + options = { alert: t('flash.update_profile_details') } + redirect_path = edit_user_path(current_user) + end + + redirect_to redirect_path, options end def destroy diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 4625cd581..73b2e5e23 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -12,7 +12,12 @@ def index; end def show; end - def edit; end + def edit + return unless current_user.missing_name? + + user.name = nil + user.errors.add(:name, :required) + end def calendar respond_to do |format| diff --git a/app/models/user.rb b/app/models/user.rb index 462a93940..e50cb54fb 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -98,11 +98,13 @@ def hash_for_email(email) end def nickname_from_email(email) - "email_#{hash_for_email(email)}" + hash_for_email(email) end - def name_from_email(email) - "Email User (#{hash_for_email(email)})" + EMPTY_NAME = '********' + + def name_from_email(_email) + EMPTY_NAME end def image_from_email(email) @@ -113,6 +115,10 @@ def with_provider?(provider) authorizations.map(&:provider).include?(provider) end + def missing_name? + name == EMPTY_NAME + end + class DuplicateNickname < StandardError attr_reader :nickname diff --git a/config/locales/en.yml b/config/locales/en.yml index cf3e0a73c..f544408f6 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -160,6 +160,7 @@ en: topic_added: "Added new Topic." topic_updated: "Updated the Topic." add_email: "Please add an email address, so that we can get in contact!" + update_profile_details: "Please, fill in your name so that we can refer to you!" mobile: settings: "Settings" back: "Back" From ad4f0987b9bbb148708acdfc739f52a89b5193d6 Mon Sep 17 00:00:00 2001 From: Josep Egea Date: Mon, 21 Oct 2024 21:48:07 +0200 Subject: [PATCH 03/15] Hide nicknames when generated from email hashes --- app/models/user.rb | 4 ++++ app/views/users/show.slim | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/models/user.rb b/app/models/user.rb index e50cb54fb..de0e9bb07 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -101,6 +101,10 @@ def nickname_from_email(email) hash_for_email(email) end + def hide_nickname? + nickname == nickname_from_email(email) + end + EMPTY_NAME = '********' def name_from_email(_email) diff --git a/app/views/users/show.slim b/app/views/users/show.slim index 71c4cebf6..fffaa3163 100644 --- a/app/views/users/show.slim +++ b/app/views/users/show.slim @@ -22,7 +22,8 @@ .card-body h2.card-title = user_image(user) - = "#{user.name} (#{user.nickname})" + = "#{user.name}" + = " (#{user.nickname})" unless user.hide_nickname? small.text-muted span>= I18n.tw("profile.freelancer") if user.freelancer? span>= "(#{t("profile.available")})" if user.available? From 158233ed591a025d8e66a3d4d69b143186067c5b Mon Sep 17 00:00:00 2001 From: Josep Egea Date: Wed, 23 Oct 2024 23:08:20 +0200 Subject: [PATCH 04/15] Manage unnamed users and add specs --- app/controllers/concerns/with_email_auth.rb | 10 +++-- app/controllers/users_controller.rb | 1 + config/environments/test.rb | 3 ++ config/locales/es.yml | 14 +++++++ spec/controllers/sessions_controller_spec.rb | 38 ++++++++++++++++++- spec/controllers/users_controller_spec.rb | 16 ++++++++ spec/mailers/user_mailer_spec.rb | 39 ++++++++++++++++++++ spec/models/user_spec.rb | 12 ++++++ spec/support/factories/authorizations.rb | 8 ++++ 9 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 spec/mailers/user_mailer_spec.rb diff --git a/app/controllers/concerns/with_email_auth.rb b/app/controllers/concerns/with_email_auth.rb index 833e3eea6..d6b6099a2 100644 --- a/app/controllers/concerns/with_email_auth.rb +++ b/app/controllers/concerns/with_email_auth.rb @@ -8,9 +8,9 @@ def email; end def email_login email = normalize_email(params[:email]) - if email.present? + if email.present? && valid_looking_email?(email) token = Token.generate(email) - from = "do-not-reply@#{Whitelabel[:domains].first}" + from = Whitelabel[:email] label_name = t("label.#{Whitelabel[:label_id]}.name") label_link = Whitelabel[:canonical_url] UserMailer.login_link(email, token, from, I18n.locale, @@ -20,7 +20,7 @@ def email_login else flash.now[:alert] = t('email_auth.invalid_email') - render :email + render :email, status: :unprocessable_entity end end @@ -29,4 +29,8 @@ def email_login def normalize_email(email) email.to_s.strip.downcase end + + def valid_looking_email?(email) + email.match(/\A[\w+\-.]+@[a-z\d-]+(\.[a-z\d-]+)*\.[a-z]+\z/i) + end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 73b2e5e23..d6e01d3a8 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -17,6 +17,7 @@ def edit user.name = nil user.errors.add(:name, :required) + render :edit end def calendar diff --git a/config/environments/test.rb b/config/environments/test.rb index f70643207..31d6a198a 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -56,4 +56,7 @@ # Annotate rendered view with file names. # config.action_view.annotate_rendered_view_with_filenames = true + + # For testing async jobs + config.active_job.queue_adapter = :test end diff --git a/config/locales/es.yml b/config/locales/es.yml index fdd274edf..a2da8fe57 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -173,3 +173,17 @@ es: previous: "<" next: ">" truncate: "..." + email_auth: + header: "Acceder por Email" + enter_email: "Por favor, introduce tu email" + submit: "Autorizar" + email_sent: "Te hemos enviado un email a %{email} con los detalles para acceder" + invalid_email: "Por favor, asegúrate de que el email es correcto" + subject: "Accede a %{label}" + body: + salute: "Hola" + intro: "Usa este enlace para acceder a %{label}" + good_bye: "Saludos" + final_details: >- + Este enlace es válido sólo durante 15 minutos. + Si no puedes pulsar sobre el enlace, puedes copiarlo y pegarlo en la barra de tu navegador. diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index 76a6ca06a..e2d74d216 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -29,10 +29,46 @@ end context 'GET :destroy' do - it 'destroys a user session' do + it 'destroys a user session', :aggregate_failures do get :destroy expect(response).to redirect_to(root_path) expect(flash[:notice]).not_to be_nil end end + + context 'for email auth' do + before do + request.env['omniauth.auth'] = EMAIL_AUTH_HASH + request.host = 'hamburg.onruby.de' + end + + context 'POST :email_login' do + it 'sends the email and redirect to index', :aggregate_failures do + expect { post :email_login, params: { email: 'user@somewhere.org' } } + .to have_enqueued_job(ActionMailer::DeliveryJob) + + expect(response).to redirect_to(root_path) + end + + it 'does not send the email if param missing', :aggregate_failures do + expect { post :email_login } + .not_to have_enqueued_job(ActionMailer::DeliveryJob) + expect(response).to have_http_status(:unprocessable_entity) + end + + it 'does not send the email looks bad', :aggregate_failures do + expect { post :email_login, params: { email: 'user@org' } } + .not_to have_enqueued_job(ActionMailer::DeliveryJob) + expect(response).to have_http_status(:unprocessable_entity) + end + end + + context 'GET :create' do + it 'creates the user and redirects to edit', :aggregate_failures do + get :create, params: { provider: :email } + expect(controller.send(:signed_in?)).to be_truthy + expect(response).to redirect_to(edit_user_path(User.last)) + end + end + end end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 6b777eedf..0b161f7a0 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -34,6 +34,22 @@ expect(flash[:alert]).not_to be_nil expect(response).to redirect_to(root_path) end + + context 'if the user has an unfilled name' do + render_views + + it 'clears the name input and sets it to error' do + allow(@controller).to receive_messages(current_user: user) + user.update(name: User::EMPTY_NAME) + + get :edit, params: { id: user } + + doc = Nokogiri::HTML(response.body) + input = doc.at_css('.form-group.user_name.form-group-invalid input') + expect(input).not_to be_nil + expect(input[:value].to_s.strip).to eq('') + end + end end context 'GET :calendar' do diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb new file mode 100644 index 000000000..d15c0b891 --- /dev/null +++ b/spec/mailers/user_mailer_spec.rb @@ -0,0 +1,39 @@ +require 'spec_helper' + +describe UserMailer do + describe '#login_link' do + subject(:mail) do + described_class.login_link(email, token, from, locale, label_name, label_link).deliver_now + end + + let(:email) { 'user@example.com' } + let(:token) { '12345678' } + let(:from) { 'no-reply@example.com' } + let(:locale) { :en } + let(:label_name) { 'My RUG' } + let(:label_link) { 'http://rug.org' } + + it 'renders the headers' do + expect(mail.subject).to eq('Login to My RUG') + expect(mail.to).to eq([email]) + expect(mail.from).to eq([from]) + end + + it 'renders the body' do + link = provider_callback_url(provider: :email, + token:, host: label_link) + + expect(mail.body.encoded).to include(link) + expect(mail.body.encoded).to include(label_name) + expect(mail.body.encoded).to include(label_link) + end + + context 'when using different locale' do + let(:locale) { :es } + + it 'uses the correct locale for the subject' do + expect(mail.subject).to eq('Accede a My RUG') + end + end + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 636b6f876..9555e86ce 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -57,6 +57,12 @@ expect(user.email).to eql('phoetmail@googlemail.com') end + it 'sets email and empty name for users created by email' do + user = User.create_from_hash!(EMAIL_AUTH_HASH) + expect(user.email).to eql('user@somewhere.org') + expect(user.name).to eql(User::EMPTY_NAME) + end + it 'raises an error for same nickname but different auths' do User.create_from_hash!(TWITTER_AUTH_HASH) expect do @@ -85,6 +91,12 @@ expect(it.url).to eql('http://blog.nofail.de') end end + + it 'updates only the email from email-auth-hash', :aggregate_failures do + expect { user.update_from_auth!(EMAIL_AUTH_HASH) } + .not_to(change { user.attributes.slice(:name, :github, :image, :location, :description, :url) }) + expect(user.email).to eq('user@somewhere.org') + end end context 'finder' do diff --git a/spec/support/factories/authorizations.rb b/spec/support/factories/authorizations.rb index 053f10b85..07b832864 100644 --- a/spec/support/factories/authorizations.rb +++ b/spec/support/factories/authorizations.rb @@ -53,6 +53,14 @@ }, }.freeze +EMAIL_AUTH_HASH = { + 'provider' => 'email', + 'uid' => 'f8a846d3199e68bb5a7d9ba9dab54ddc9c28e382b5c4490b396214808d26aeb9', + 'info' => { + 'email' => 'user@somewhere.org', + }, +}.freeze + FactoryBot.define do factory :authorization do user From d5c3266ed757f076a01066ff8528c84ad98f9239 Mon Sep 17 00:00:00 2001 From: Josep Egea Date: Wed, 23 Oct 2024 23:14:17 +0200 Subject: [PATCH 05/15] Rename Token class --- app/controllers/concerns/with_email_auth.rb | 2 +- app/lib/{token.rb => email_auth_token.rb} | 2 +- lib/omni_auth/strategies/email.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename app/lib/{token.rb => email_auth_token.rb} (96%) diff --git a/app/controllers/concerns/with_email_auth.rb b/app/controllers/concerns/with_email_auth.rb index d6b6099a2..b49cd4e35 100644 --- a/app/controllers/concerns/with_email_auth.rb +++ b/app/controllers/concerns/with_email_auth.rb @@ -9,7 +9,7 @@ def email; end def email_login email = normalize_email(params[:email]) if email.present? && valid_looking_email?(email) - token = Token.generate(email) + token = EmailAuthToken.generate(email) from = Whitelabel[:email] label_name = t("label.#{Whitelabel[:label_id]}.name") label_link = Whitelabel[:canonical_url] diff --git a/app/lib/token.rb b/app/lib/email_auth_token.rb similarity index 96% rename from app/lib/token.rb rename to app/lib/email_auth_token.rb index 2b71c03bd..b82b9ae52 100644 --- a/app/lib/token.rb +++ b/app/lib/email_auth_token.rb @@ -3,7 +3,7 @@ # Based on https://github.com/weg-li/weg-li/blob/master/app/lib/token.rb # Original author: https://github.com/phoet -class Token +class EmailAuthToken def self.generate( email, expiration: 15.minutes, diff --git a/lib/omni_auth/strategies/email.rb b/lib/omni_auth/strategies/email.rb index 86a15d743..49f280794 100644 --- a/lib/omni_auth/strategies/email.rb +++ b/lib/omni_auth/strategies/email.rb @@ -20,7 +20,7 @@ def callback_phase fail!(:authenticity_error) if token.blank? begin - decoded_token = Token.decode(token) + decoded_token = EmailAuthToken.decode(token) rescue StandardError fail!(:authenticity_error, $ERROR_INFO) end From 96131789da2ff5bc614258cc0454d5ab43335922 Mon Sep 17 00:00:00 2001 From: Josep Egea Date: Wed, 23 Oct 2024 23:18:18 +0200 Subject: [PATCH 06/15] Remove redundant render --- app/controllers/users_controller.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index d6e01d3a8..73b2e5e23 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -17,7 +17,6 @@ def edit user.name = nil user.errors.add(:name, :required) - render :edit end def calendar From 7f96266d1f8df07b1dd9c20c99d31f1ee28f737f Mon Sep 17 00:00:00 2001 From: Josep Egea Date: Sat, 26 Oct 2024 18:15:55 +0200 Subject: [PATCH 07/15] Update readme with Email OAuth details --- readme.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/readme.md b/readme.md index ab4e03d5e..77f88f2f1 100644 --- a/readme.md +++ b/readme.md @@ -175,12 +175,36 @@ In order to register for events, users need to log in first. The app uses OAuth for that. At this point, it accepts Twitter [^1], GitHub and Google as valid OAuth providers. +It also accepts email as a method for registering and logging in, using a custom OAuth provider based on one time passwords (OTP) sent to that email. + When a user is not currently logged in, selecting one of the login providers creates an account for him/her, attaching this provider as a valid auth mechanism. When a user is already logged in, selecting another provider will add that auth mechanism to the existing user. [^1]: As of 2024 Twitter/X has deprecated API v1.1 and Twitter login is not working anymore +### Required used information + +At this point, the app marks `nickname`, `name` and `image` as required, not allowing a user to be created if any of those are empty. `email` is not required. + +For external OAuth sources, values for those 3 properties are obtained from the providers. + +- When a user is created through them, it gets these (and other) properties from that source. + +- When an existing user adds one of those providers, some of these values are overwritten (`name` and `image`), while `nickname` stays always the same. + +For users registered through email OTP, none of these values are available on creation. In order to deal with the validations, they're initialized as follows: + +- `nickname` is generated by hashing the email address. + +- `name` is filled in with a known marker for "missing name" declared in `User::EMPTY_NAME` (currently `"********"`). It doesn't use the email address as a placeholder in order to avoid exposing it, as the user name is displayed in several pages in the application. + +- `image` is set to the Gravatar URL for the email. + +In order to urge users registered through email to provide a name that can be used in the app, after log in, a user with such an "empty" name is redirected to the profile edit page and asked to provide one. + +As with any other source, if such a user later adds another provider, the `name` and `image` coming from those will take over the existing ones. + ### Recovering login for existing users who only had Twitter auth As a consequence of X deprecating API v1.1, Twitter authentication is not working anymore and registered users that only had defined Twitter as their auth method are left out in the cold. From e19870f09154503d5d34ebe30cd44bb37a61f895 Mon Sep 17 00:00:00 2001 From: Josep Egea Date: Sat, 26 Oct 2024 18:23:01 +0200 Subject: [PATCH 08/15] Update :de and :pl locales --- config/locales/de.yml | 14 ++++++++++++++ config/locales/pl.yml | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/config/locales/de.yml b/config/locales/de.yml index 79f2ac77e..119fe9fff 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -172,3 +172,17 @@ de: previous: "<" next: ">" truncate: "..." + email_auth: + header: "Mit E-Mail anmelden" + enter_email: "Bitte geben Sie Ihre E-Mail-Adresse ein" + submit: "Autorisieren" + email_sent: "Eine E-Mail wurde an %{email} mit Details zum Einloggen gesendet" + invalid_email: "Bitte geben Sie eine gültige E-Mail-Adresse ein" + subject: "Anmeldung zu %{label}" + body: + salute: "Hallo" + intro: "Verwenden Sie diesen Link, um sich bei %{label} anzumelden" + good_bye: "Mit freundlichen Grüßen" + final_details: >- + Dieser Link ist nur 15 Minuten gültig. + Wenn Sie nicht auf den Link klicken können, kopieren Sie ihn einfach und fügen Sie ihn in die Adresszeile Ihres Browsers ein. diff --git a/config/locales/pl.yml b/config/locales/pl.yml index c41cdae23..de5a89a67 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -181,3 +181,17 @@ pl: - czwartek - piątek - sobotę + email_auth: + header: "Zaloguj się przez email" + enter_email: "Proszę, wprowadź swój email" + submit: "Autoryzuj" + email_sent: "Email został wysłany na adres %{email} z detalami do logowania" + invalid_email: "Proszę wprowadzić prawidłowy adres e-mail" + subject: "Logowanie do %{label}" + body: + salute: "Cześć" + intro: "Użyj tego linku, aby zalogować się do %{label}" + good_bye: "Najlepsze życzenia" + final_details: >- + Ten link będzie ważny tylko przez 15 minut. + Jeśli nie możesz kliknąć na link, skopiuj go i wklej w pasek adresu przeglądarki. From d2d2e3a1ee0324b73bdb1ae632a52b566ebecce1 Mon Sep 17 00:00:00 2001 From: Josep Egea Date: Sat, 26 Oct 2024 19:08:07 +0200 Subject: [PATCH 09/15] Hide name for users without it --- app/helpers/application_helper.rb | 4 ++++ app/helpers/link_helper.rb | 6 +++--- app/views/users/show.slim | 2 +- spec/views/users/show.html_spec.rb | 24 +++++++++++++++++++++--- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 393bee93a..c6b24a9e0 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -87,6 +87,10 @@ def hint(close = true) end end + def user_name(user) + user.missing_name? ? '-' : user.name + end + private def markdown_parser diff --git a/app/helpers/link_helper.rb b/app/helpers/link_helper.rb index 15983d934..97f59a8ac 100644 --- a/app/helpers/link_helper.rb +++ b/app/helpers/link_helper.rb @@ -2,14 +2,14 @@ module LinkHelper def link_to_user(user, image: false, image_class: nil) - link_to(user, title: user.name) do - image ? user_image(user, image_class:) + user.name : user.name + link_to(user, title: user_name(user)) do + image ? user_image(user, image_class:) + user_name(user) : user_name(user) end end def user_image(user, image_class: nil) image_class ||= 'small-user-image' - image_tag(cache_image_path(user), title: user.name, class: image_class) + image_tag(cache_image_path(user), title: user_name(user), class: image_class) end def link_to_job(job) diff --git a/app/views/users/show.slim b/app/views/users/show.slim index fffaa3163..0f18ec0da 100644 --- a/app/views/users/show.slim +++ b/app/views/users/show.slim @@ -22,7 +22,7 @@ .card-body h2.card-title = user_image(user) - = "#{user.name}" + = "#{user_name(user)}" = " (#{user.nickname})" unless user.hide_nickname? small.text-muted span>= I18n.tw("profile.freelancer") if user.freelancer? diff --git a/spec/views/users/show.html_spec.rb b/spec/views/users/show.html_spec.rb index cdc87ebcb..648a0dd0a 100644 --- a/spec/views/users/show.html_spec.rb +++ b/spec/views/users/show.html_spec.rb @@ -2,12 +2,30 @@ describe 'users/show' do let(:user) { build(:user, id: 123) } + let(:dom) { Nokogiri::HTML(rendered) } - it 'renders successfully' do - allow(view).to receive_messages(current_user: user, user:) + before { allow(view).to receive_messages(current_user: user, user:) } + it 'renders successfully' do render - expect(rendered).to include(user.nickname) + expect(dom.at_css('.card .card-body .card-title').inner_text).to include(user.nickname) + end + + context 'when user was just created through email OTP' do + let(:user) { User.create_from_hash!(EMAIL_AUTH_HASH) } + + it 'hides nickname' do + render + + expect(dom.at_css('.card .card-body .card-title').inner_text).not_to include(user.nickname) + end + + it 'shows name placeholder', :aggregate_failures do + render + + expect(dom.at_css('.card .card-body .card-title').inner_text).not_to include(user.name) + expect(dom.at_css('.card .card-body .card-title').inner_text).to include('-') + end end end From a0009dde276dff97aa33742f82295248ea7792d3 Mon Sep 17 00:00:00 2001 From: Josep Egea Date: Tue, 29 Oct 2024 14:18:15 +0100 Subject: [PATCH 10/15] Update config/locales/de.yml Co-authored-by: Ben Rexin --- config/locales/de.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/de.yml b/config/locales/de.yml index 119fe9fff..95c8e5d35 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -178,7 +178,7 @@ de: submit: "Autorisieren" email_sent: "Eine E-Mail wurde an %{email} mit Details zum Einloggen gesendet" invalid_email: "Bitte geben Sie eine gültige E-Mail-Adresse ein" - subject: "Anmeldung zu %{label}" + subject: "Anmeldung bei %{label}" body: salute: "Hallo" intro: "Verwenden Sie diesen Link, um sich bei %{label} anzumelden" From aabad1ad308e7574fc22ee1a8562e91f5b4a1cf9 Mon Sep 17 00:00:00 2001 From: Josep Egea Date: Tue, 29 Oct 2024 14:26:09 +0100 Subject: [PATCH 11/15] Apply review suggestions --- lib/omni_auth/strategies/email.rb | 5 ++--- spec/controllers/sessions_controller_spec.rb | 2 +- spec/models/user_spec.rb | 4 ++-- spec/support/factories/authorizations.rb | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/omni_auth/strategies/email.rb b/lib/omni_auth/strategies/email.rb index 49f280794..7954acc1c 100644 --- a/lib/omni_auth/strategies/email.rb +++ b/lib/omni_auth/strategies/email.rb @@ -4,7 +4,6 @@ # Original author: https://github.com/phoet require 'base64' -require 'English' module OmniAuth module Strategies @@ -21,8 +20,8 @@ def callback_phase begin decoded_token = EmailAuthToken.decode(token) - rescue StandardError - fail!(:authenticity_error, $ERROR_INFO) + rescue StandardError => e + fail!(:authenticity_error, e) end @email = decoded_token['iss'].to_s.downcase diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index e2d74d216..b86d95189 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -44,7 +44,7 @@ context 'POST :email_login' do it 'sends the email and redirect to index', :aggregate_failures do - expect { post :email_login, params: { email: 'user@somewhere.org' } } + expect { post :email_login, params: { email: 'user@example.org' } } .to have_enqueued_job(ActionMailer::DeliveryJob) expect(response).to redirect_to(root_path) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 9555e86ce..d218f666c 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -59,7 +59,7 @@ it 'sets email and empty name for users created by email' do user = User.create_from_hash!(EMAIL_AUTH_HASH) - expect(user.email).to eql('user@somewhere.org') + expect(user.email).to eql('user@example.org') expect(user.name).to eql(User::EMPTY_NAME) end @@ -95,7 +95,7 @@ it 'updates only the email from email-auth-hash', :aggregate_failures do expect { user.update_from_auth!(EMAIL_AUTH_HASH) } .not_to(change { user.attributes.slice(:name, :github, :image, :location, :description, :url) }) - expect(user.email).to eq('user@somewhere.org') + expect(user.email).to eq('user@example.org') end end diff --git a/spec/support/factories/authorizations.rb b/spec/support/factories/authorizations.rb index 07b832864..a5110c672 100644 --- a/spec/support/factories/authorizations.rb +++ b/spec/support/factories/authorizations.rb @@ -57,7 +57,7 @@ 'provider' => 'email', 'uid' => 'f8a846d3199e68bb5a7d9ba9dab54ddc9c28e382b5c4490b396214808d26aeb9', 'info' => { - 'email' => 'user@somewhere.org', + 'email' => 'user@example.org', }, }.freeze From 9fae30df99ab5eeacf441da928b8f6ec5a82e956 Mon Sep 17 00:00:00 2001 From: Josep Egea Date: Wed, 30 Oct 2024 17:40:14 +0100 Subject: [PATCH 12/15] Use relative path for require_relative --- config/initializers/omniauth.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index c2740c8ef..7b7e6061d 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -1,4 +1,4 @@ -require_relative File.join(Rails.root, 'lib/omni_auth/strategies/email') +require_relative '../../lib/omni_auth/strategies/email' OmniAuth.config.logger = Rails.logger From 60e0fafbe75a635cf618fb0119877f20596b0f80 Mon Sep 17 00:00:00 2001 From: Josep Egea Date: Wed, 30 Oct 2024 17:49:17 +0100 Subject: [PATCH 13/15] Use informal language for German locale --- config/locales/de.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/locales/de.yml b/config/locales/de.yml index 95c8e5d35..20f985c01 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -174,15 +174,15 @@ de: truncate: "..." email_auth: header: "Mit E-Mail anmelden" - enter_email: "Bitte geben Sie Ihre E-Mail-Adresse ein" + enter_email: "Bitte gib eine gültige E-Mail-Adresse ein" submit: "Autorisieren" email_sent: "Eine E-Mail wurde an %{email} mit Details zum Einloggen gesendet" - invalid_email: "Bitte geben Sie eine gültige E-Mail-Adresse ein" + invalid_email: "Bitte gib eine gültige E-Mail-Adresse ein" subject: "Anmeldung bei %{label}" body: salute: "Hallo" - intro: "Verwenden Sie diesen Link, um sich bei %{label} anzumelden" + intro: "Verwende diesen Link, um dich bei %{label} anzumelden" good_bye: "Mit freundlichen Grüßen" final_details: >- Dieser Link ist nur 15 Minuten gültig. - Wenn Sie nicht auf den Link klicken können, kopieren Sie ihn einfach und fügen Sie ihn in die Adresszeile Ihres Browsers ein. + Wenn du nicht auf den Link klicken kannst, kopiere ihn einfach und füge ihn in die Adresszeile deines Browsers ein. From c4bc48967734b4426b4ae81c88b7964bbb7b928b Mon Sep 17 00:00:00 2001 From: Josep Egea Date: Wed, 30 Oct 2024 18:01:18 +0100 Subject: [PATCH 14/15] Disable exception catching for bad tokens --- lib/omni_auth/strategies/email.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/omni_auth/strategies/email.rb b/lib/omni_auth/strategies/email.rb index 7954acc1c..9e55e930c 100644 --- a/lib/omni_auth/strategies/email.rb +++ b/lib/omni_auth/strategies/email.rb @@ -18,11 +18,9 @@ def callback_phase token = request.params['token'] fail!(:authenticity_error) if token.blank? - begin - decoded_token = EmailAuthToken.decode(token) - rescue StandardError => e - fail!(:authenticity_error, e) - end + # Not catching the exception until this is more tested + # This way we'll get it reported in AppSignal for diagnosing + decoded_token = EmailAuthToken.decode(token) @email = decoded_token['iss'].to_s.downcase fail!(:authenticity_error) if @email.blank? From 1f386f6f8636cfaf4acb616713a9e180afc16bf6 Mon Sep 17 00:00:00 2001 From: Josep Egea Date: Wed, 30 Oct 2024 19:21:13 +0100 Subject: [PATCH 15/15] Move asking for user name to hint partial --- app/controllers/sessions_controller.rb | 12 +++--------- app/helpers/application_helper.rb | 2 +- app/models/user.rb | 4 ++++ app/views/application/_hint.slim | 8 ++++++++ spec/controllers/sessions_controller_spec.rb | 8 -------- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 0045ed1a6..87105b75d 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -16,19 +16,13 @@ def create begin authorization = Authorization.handle_authorization(current_user, request.env['omniauth.auth']) sign_in(authorization.user) - options = { notice: t('flash.logged_in', name: current_user.name) } + user_name = current_user.missing_name? ? '' : current_user.name + options = { notice: t('flash.logged_in', name: user_name) } rescue User::DuplicateNickname => e options = { alert: t('flash.duplicate_nick', name: e.nickname) } end - redirect_path = request.env['omniauth.origin'].presence || root_path - - if current_user&.missing_name? - options = { alert: t('flash.update_profile_details') } - redirect_path = edit_user_path(current_user) - end - - redirect_to redirect_path, options + redirect_to request.env['omniauth.origin'].presence || root_path, options end def destroy diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c6b24a9e0..588bb83f9 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -88,7 +88,7 @@ def hint(close = true) end def user_name(user) - user.missing_name? ? '-' : user.name + user.display_name end private diff --git a/app/models/user.rb b/app/models/user.rb index de0e9bb07..f425c6189 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -123,6 +123,10 @@ def missing_name? name == EMPTY_NAME end + def display_name + missing_name? ? '-' : name + end + class DuplicateNickname < StandardError attr_reader :nickname diff --git a/app/views/application/_hint.slim b/app/views/application/_hint.slim index 175a13570..6544c5f62 100644 --- a/app/views/application/_hint.slim +++ b/app/views/application/_hint.slim @@ -25,3 +25,11 @@ li.mb-4 span.job-toggle= link_to fa_icon("chevron-up"), '#', title: t("hint.click_to_refresh") if index == 0 .job.ml-4== job_description(job) + +- if current_user&.missing_name? + = hint(false) do + .highlights + => fa_icon("exclamation-triangle") + strong=> t("flash.update_profile_details") + - unless current_page?(edit_user_path(current_user)) + = link_to t("login.edit_profile"), edit_user_path(current_user) diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index b86d95189..5cb69a294 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -62,13 +62,5 @@ expect(response).to have_http_status(:unprocessable_entity) end end - - context 'GET :create' do - it 'creates the user and redirects to edit', :aggregate_failures do - get :create, params: { provider: :email } - expect(controller.send(:signed_in?)).to be_truthy - expect(response).to redirect_to(edit_user_path(User.last)) - end - end end end