Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions app/controllers/onboardings_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ class OnboardingsController < ApplicationController

before_action :set_user
before_action :load_invitation
before_action :skip_setup_step_if_complete, only: :show

def show
end
Expand All @@ -21,4 +22,13 @@ def set_user
def load_invitation
@invitation = Current.family.invitations.accepted.find_by(email: Current.user.email)
end

def skip_setup_step_if_complete
return if performed?
return if @invitation.present?

if @user&.first_name.present? && @user&.last_name.present?
redirect_to preferences_onboarding_path
end
end
end
71 changes: 70 additions & 1 deletion app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,24 @@ def destroy

def openid_connect
auth = request.env["omniauth.auth"]
if auth && (user = User.find_by(email: auth.info.email))
flow = request.env.fetch("omniauth.params", {})&.[]("flow")

if auth.blank?
return redirect_to(flow == "signup" ? new_registration_path : new_session_path, alert: t(flow == "signup" ? ".signup_failed" : ".failed"))
end

if (user = User.find_by(email: auth.info.email))
@session = create_session_for(user)
redirect_to root_path
elsif flow == "signup"
user = create_user_from_openid(auth)

if user&.persisted?
@session = create_session_for(user)
redirect_to preferences_onboarding_path
else
redirect_to new_registration_path, alert: t(".signup_failed")
end
else
redirect_to new_session_path, alert: t(".failed")
end
Expand All @@ -45,4 +60,58 @@ def failure
def set_session
@session = Current.user.sessions.find(params[:id])
end

def create_user_from_openid(auth)
info = auth.info
email = info.email.to_s.strip.downcase
return nil if email.blank?

first_name, last_name = extract_name_parts(info)
fallback_name = fallback_name_from_email(email) || "User"
first_name ||= fallback_name
last_name ||= fallback_name
family_name = determine_family_name(last_name, first_name, email)

ActiveRecord::Base.transaction do
family = Family.create!(
name: family_name,
locale: "en",
currency: "USD",
country: "US",
date_format: "%Y-%m-%d"
)

family.users.create!(
email: email,
password: SecureRandom.base58(24),
role: :admin,
first_name: first_name,
last_name: last_name
)
end
rescue ActiveRecord::RecordInvalid => error
Rails.logger.error("OpenID Connect sign up failed: #{error.message}")
nil
end

def extract_name_parts(info)
first = info.first_name.to_s.strip.presence
last = info.last_name.to_s.strip.presence

if first.blank? || last.blank?
name_parts = info.name.to_s.strip.split
first ||= name_parts.first
last ||= name_parts.last if name_parts.size > 1
end

[ first, last ]
end

def determine_family_name(last_name, first_name, email)
last_name.presence || first_name.presence || fallback_name_from_email(email) || "Household"
end

def fallback_name_from_email(email)
email.to_s.split("@").first.to_s.gsub(/[._-]+/, " ").squeeze(" ").strip.titleize.presence
end
end
23 changes: 23 additions & 0 deletions app/views/registrations/new.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,26 @@

<%= form.submit t(".submit") %>
<% end %>

<div class="mt-6 text-center">
<%= button_to "/auth/openid_connect",
params: { flow: "signup" },
method: :post,
form: { data: { turbo: false } },
class: "gsi-material-button" do %>
<div class="gsi-material-button-state"></div>
<div class="gsi-material-button-content-wrapper">
<div class="gsi-material-button-icon">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" xmlns:xlink="http://www.w3.org/1999/xlink" style="display: block;">
<path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"></path>
<path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"></path>
<path fill="#FBBC05" d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"></path>
<path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"></path>
<path fill="none" d="M0 0h48v48H0z"></path>
</svg>
</div>
<span class="gsi-material-button-contents"><%= t(".google_auth_connect") %></span>
<span style="display: none;"><%= t(".google_auth_connect") %></span>
</div>
<% end %>
</div>
1 change: 1 addition & 0 deletions config/locales/views/registrations/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ en:
role_member: member
submit: Create account
title: Create your account
google_auth_connect: Sign up with Google
welcome_body: To get started, you must sign up for a new account. You will
then be able to configure additional settings within the app.
welcome_title: Welcome to Self Hosted Maybe!
Expand Down
51 changes: 26 additions & 25 deletions config/locales/views/registrations/nb.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
---
nb:
helpers:
label:
user:
invite_code: Invitasjonskode
submit:
user:
create: Fortsett
registrations:
create:
failure: Det oppsto et problem med registreringen.
invalid_invite_code: Ugyldig invitasjonskode, vennligst prøv igjen.
success: Du har blitt registrert.
new:
invitation_message: "%{inviter} har invitert deg til å bli med som %{role}"
join_family_title: Bli med i %{family}
role_admin: administrator
role_member: medlem
submit: Opprett konto
title: Opprett kontoen din
welcome_body: For å komme i gang må du registrere deg for en ny konto. Du vil
da kunne konfigurere flere innstillinger i appen.
welcome_title: Velkommen til Self Hosted Sure!
password_placeholder: Angi passordet ditt
---
nb:
helpers:
label:
user:
invite_code: Invitasjonskode
submit:
user:
create: Fortsett
registrations:
create:
failure: Det oppsto et problem med registreringen.
invalid_invite_code: Ugyldig invitasjonskode, vennligst prøv igjen.
success: Du har blitt registrert.
new:
invitation_message: "%{inviter} har invitert deg til å bli med som %{role}"
join_family_title: Bli med i %{family}
role_admin: administrator
role_member: medlem
submit: Opprett konto
title: Opprett kontoen din
google_auth_connect: Registrer deg med Google
welcome_body: For å komme i gang må du registrere deg for en ny konto. Du vil
da kunne konfigurere flere innstillinger i appen.
welcome_title: Velkommen til Self Hosted Sure!
password_placeholder: Angi passordet ditt
3 changes: 2 additions & 1 deletion config/locales/views/registrations/tr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ tr:
role_member: üye
submit: Hesap oluştur
title: Hesabınızı oluşturun
google_auth_connect: Google ile kayıt ol
welcome_body: Başlamak için yeni bir hesap oluşturmalısınız. Daha sonra uygulama içinde ek ayarları yapılandırabileceksiniz.
welcome_title: Self Hosted Maybe'ye Hoş Geldiniz!
password_placeholder: Şifrenizi girin
password_placeholder: Şifrenizi girin
1 change: 1 addition & 0 deletions config/locales/views/sessions/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ en:
logout_successful: You have signed out successfully.
openid_connect:
failed: Could not authenticate via OpenID Connect.
signup_failed: Could not complete sign up with Google.
failure:
failed: Could not authenticate.
new:
Expand Down
1 change: 1 addition & 0 deletions config/locales/views/sessions/nb.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ nb:
logout_successful: Du har blitt logget ut.
openid_connect:
failed: Kunne ikke autentisere via OpenID Connect.
signup_failed: Klarte ikke å registrere deg med Google.
new:
email: E-postadresse
email_placeholder: [email protected]
Expand Down
1 change: 1 addition & 0 deletions config/locales/views/sessions/tr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ tr:
logout_successful: Başarıyla çıkış yaptınız.
openid_connect:
failed: OpenID Connect ile kimlik doğrulaması yapılamadı.
signup_failed: Google ile kayıt tamamlanamadı.
new:
email: E-posta adresi
email_placeholder: [email protected]
Expand Down
47 changes: 47 additions & 0 deletions test/controllers/sessions_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,51 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
assert_equal @user.id, session[:mfa_user_id]
assert_not Session.exists?(user_id: @user.id)
end

test "can sign up with openid connect" do
OmniAuth.config.test_mode = true

auth_hash = OmniAuth::AuthHash.new(
provider: "openid_connect",
uid: "oidc-123",
info: OmniAuth::AuthHash.new(
email: "[email protected]",
first_name: "Jane",
last_name: "Doe",
name: "Jane Doe"
)
)

Rails.application.env_config["omniauth.auth"] = auth_hash
Rails.application.env_config["omniauth.params"] = { "flow" => "signup" }

assert_difference -> { Family.count }, 1 do
assert_difference -> { User.count }, 1 do
assert_difference -> { Session.count }, 1 do
post "/auth/openid_connect/callback"
end
end
end

assert_redirected_to preferences_onboarding_url

user = User.find_by(email: "[email protected]")
assert_not_nil user
assert_equal "Jane", user.first_name
assert_equal "Doe", user.last_name
assert_equal "Doe", user.family.name
assert_equal "US", user.family.country
assert_equal "en", user.family.locale
assert_equal "USD", user.family.currency
assert_equal "%Y-%m-%d", user.family.date_format
assert user.sessions.exists?

get onboarding_url
assert_redirected_to preferences_onboarding_url
ensure
Rails.application.env_config.delete("omniauth.auth")
Rails.application.env_config.delete("omniauth.params")
OmniAuth.config.mock_auth[:openid_connect] = nil if OmniAuth.config.respond_to?(:mock_auth)
OmniAuth.config.test_mode = false
end
end
Loading