Update sign up

This commit is contained in:
Stanko K.R.
2025-11-13 15:46:22 +01:00
committed by Mike Dalessio
parent edf837fed3
commit 8fa9566c07
26 changed files with 70 additions and 198 deletions
+3 -14
View File
@@ -1,24 +1,13 @@
class Sessions::MenusController < ApplicationController
disallow_account_scope
before_action(if: :render_as_menu_section?) { request.variant = :menu_section }
layout "public"
def show
@memberships = Current.identity.memberships
@accounts = Current.identity.accounts
if params[:without]
@memberships = @memberships.where.not(tenant: params[:without])
end
if @memberships.one? && !render_as_menu_section?
redirect_to root_url(script_name: "/#{@memberships.first.tenant}")
if @accounts.one?
redirect_to root_url(script_name: @accounts.first.slug)
end
end
private
def render_as_menu_section?
params[:menu_section]
end
end
+1 -1
View File
@@ -20,7 +20,7 @@ class SessionsController < ApplicationController
redirect_to session_magic_link_path
elsif signups_allowed?
Signup.new(email_address: email_address).create_identity
session[:return_to_after_authenticating] = saas.new_signup_membership_path
session[:return_to_after_authenticating] = saas.new_signup_completion_path
redirect_to session_magic_link_path
end
end
+1 -1
View File
@@ -2,6 +2,6 @@ module Account::Seedeable
extend ActiveSupport::Concern
def setup_customer_template
Account::Seeder.new(self, users.active.first).seed
Account::Seeder.new(self, users.active.where(role: :admin).first).seed
end
end
+4 -8
View File
@@ -7,7 +7,7 @@ class Account::Seeder
end
def seed
Current.set session: session do
Current.set(user: creator, account: account) do
populate
end
end
@@ -20,15 +20,11 @@ class Account::Seeder
end
private
def session
creator.identity.sessions.last
end
def populate
# ---------------
# Playground Board
# ---------------
playground = Board.create! name: "Playground", creator: creator, all_access: true
playground = account.boards.create! name: "Playground", creator: creator, all_access: true
# Cards
playground.cards.create! creator: creator, title: "Finally, watch this Fizzy orientation video", status: "published", description: <<~HTML
@@ -104,8 +100,8 @@ class Account::Seeder
end
def delete_everything
Current.set session: session do
Board.destroy_all
Current.set(user: creator, account: account) do
account.boards.destroy_all
end
end
end
+1 -1
View File
@@ -1,7 +1,7 @@
class Board < ApplicationRecord
include Accessible, AutoPostponing, Broadcastable, Cards, Entropic, Filterable, Publishable, Triageable
belongs_to :account, default: -> { Current.account }
belongs_to :account, default: -> { creator.account }
belongs_to :creator, class_name: "User", default: -> { Current.user }
has_rich_text :public_description
+1 -1
View File
@@ -1,7 +1,7 @@
class Column < ApplicationRecord
include Colored, Positioned
belongs_to :account, default: -> { Current.account }
belongs_to :account, default: -> { board.account }
belongs_to :board, touch: true
has_many :cards, dependent: :nullify
+1 -1
View File
@@ -1,7 +1,7 @@
class Comment < ApplicationRecord
include Attachments, Eventable, Mentions, Promptable, Searchable
belongs_to :account, default: -> { Current.account }
belongs_to :account, default: -> { card.account }
belongs_to :card, touch: true
belongs_to :creator, class_name: "User", default: -> { Current.user }
has_many :reactions, dependent: :delete_all
+1 -1
View File
@@ -1,7 +1,7 @@
class Event < ApplicationRecord
include Notifiable, Particulars, Promptable
belongs_to :account, default: -> { Current.account }
belongs_to :account, default: -> { board.account }
belongs_to :board
belongs_to :creator, class_name: "User"
belongs_to :eventable, polymorphic: true
+1 -1
View File
@@ -1,7 +1,7 @@
class Filter < ApplicationRecord
include Fields, Params, Resources, Summarized
belongs_to :account, default: -> { Current.account }
belongs_to :account, default: -> { creator.account }
belongs_to :creator, class_name: "User", default: -> { Current.user }
class << self
+4 -1
View File
@@ -1,9 +1,12 @@
class Identity < ApplicationRecord
include Joinable, Transferable
has_many :users, dependent: :nullify
has_many :magic_links, dependent: :destroy
has_many :sessions, dependent: :destroy
has_many :users, dependent: :nullify
has_many :accounts, through: :users
has_one_attached :avatar
before_destroy :deactivate_users
+1 -1
View File
@@ -1,5 +1,5 @@
class Push::Subscription < ApplicationRecord
belongs_to :account, default: -> { Current.account }
belongs_to :account, default: -> { user.account }
belongs_to :user
def notification(**params)
+1 -1
View File
@@ -1,5 +1,5 @@
class Step < ApplicationRecord
belongs_to :account, default: -> { Current.account }
belongs_to :account, default: -> { card.account }
belongs_to :card, touch: true
scope :completed, -> { where(completed: true) }
+1 -1
View File
@@ -5,7 +5,7 @@ class User < ApplicationRecord
has_one_attached :avatar
belongs_to :account, default: -> { Current.account }
belongs_to :account
belongs_to :identity, optional: true
has_many :comments, inverse_of: :creator, dependent: :destroy
+1 -1
View File
@@ -25,7 +25,7 @@ class Webhook < ApplicationRecord
has_many :deliveries, dependent: :delete_all
has_one :delinquency_tracker, dependent: :delete
belongs_to :account, default: -> { Current.account }
belongs_to :account, default: -> { board.account }
belongs_to :board
serialize :subscribed_actions, type: Array, coder: JSON
+10 -1
View File
@@ -61,7 +61,16 @@
<% end %>
<% end %>
<%= turbo_frame_tag Current.identity, :account_menu, src: session_menu_url(script_name: nil, menu_section: true, without: Current.account.id) %>
<% accounts = Current.identity.accounts.where.not(id: Current.account) %>
<% if accounts.any? %>
<% cache [ Current.identity, accounts ] do %>
<%= collapsible_nav_section "Accounts" do %>
<% accounts.each do |account| %>
<%= filter_place_menu_item landing_url(script_name: account.slug), account.name, "marker", new_window: true %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
<footer class="nav__footer">
+1 -1
View File
@@ -26,7 +26,7 @@
<% if signups_allowed? %>
<div class="margin-block-start">
<%= link_to saas.new_signup_membership_path, class: "btn btn--plain txt-link center txt-small", data: { turbo_prefetch: false } do %>
<%= link_to saas.new_signup_completion_path, class: "btn btn--plain txt-link center txt-small", data: { turbo_prefetch: false } do %>
<span>Sign up for a new Fizzy account</span>
<% end %>
</div>
@@ -4,14 +4,14 @@ class Signup::CompletionsController < ApplicationController
disallow_account_scope
def new
@signup = Signup.new(signup_params)
@signup = Signup.new(identity: Current.identity)
end
def create
@signup = Signup.new(signup_params)
if @signup.complete
redirect_to landing_url(script_name: "/#{@signup.tenant}")
redirect_to landing_url(script_name: @signup.account.slug)
else
render :new, status: :unprocessable_entity
end
@@ -19,6 +19,6 @@ class Signup::CompletionsController < ApplicationController
private
def signup_params
params.expect(signup: %i[ full_name account_name membership_id ]).with_defaults(identity: Current.identity)
params.expect(signup: %i[ full_name ]).with_defaults(identity: Current.identity)
end
end
@@ -1,30 +0,0 @@
class Signup::MembershipsController < ApplicationController
layout "public"
disallow_account_scope
def new
@signup = Signup.new
end
def create
@signup = Signup.new(signup_params)
if @signup.create_membership
redirect_to saas.new_signup_completion_path(
signup: {
membership_id: @signup.membership_id,
full_name: @signup.full_name,
account_name: @signup.account_name
}
)
else
render :new, status: :unprocessable_entity
end
end
private
def signup_params
params.expect(signup: %i[ full_name ]).with_defaults(identity: Current.identity)
end
end
+19 -64
View File
@@ -1,40 +1,26 @@
class Signup
MEMBERSHIP_PURPOSE = :account_creation
include ActiveModel::Model
include ActiveModel::Attributes
include ActiveModel::Validations
attr_accessor :full_name, :email_address, :identity, :membership_id, :account_name
attr_reader :queenbee_account, :account, :user, :tenant, :membership
with_options on: :membership_creation do
validates_presence_of :full_name, :identity
end
attr_accessor :full_name, :email_address, :identity
attr_reader :queenbee_account, :account, :user
with_options on: :completion do
validates_presence_of :full_name, :account_name, :identity, :membership
validates_presence_of :full_name, :identity
end
def initialize(...)
@full_name = nil
@email_address = nil
@tenant = nil
@account = nil
@user = nil
@queenbee_account = nil
@membership = nil
@membership_id = nil
@identity = nil
@account_name = nil
super
if @identity
@email_address = @identity.email_address
@membership = identity.memberships.find_signed(membership_id, purpose: MEMBERSHIP_PURPOSE)
@tenant = membership&.tenant
end
@email_address = @identity.email_address if @identity
end
def create_identity
@@ -42,41 +28,21 @@ class Signup
@identity.send_magic_link
end
def create_membership
if valid?(:membership_creation)
begin
create_queenbee_account
@membership = identity.memberships.create!(tenant: tenant)
@membership_id = @membership.signed_id(purpose: MEMBERSHIP_PURPOSE)
rescue => error
destroy_queenbee_account
@membership&.destroy
@membership = nil
@membership_id = nil
errors.add(:base, "Something went wrong, and we couldn't create your account. Please give it another try.")
Rails.error.report(error, severity: :error)
false
end
else
false
end
end
def complete
if valid?(:completion)
begin
create_tenant
create_queenbee_account
create_account
true
rescue => error
destroy_tenant
destroy_account
destroy_queenbee_account
errors.add(:base, "Something went wrong, and we couldn't create your account. Please give it another try.")
Rails.error.report(error, severity: :error)
Rails.logger.error error
Rails.logger.error error.backtrace.join("\n")
false
end
@@ -97,35 +63,24 @@ class Signup
@queenbee_account = nil
end
def create_tenant
def create_account
@account = Account.create_with_admin_user(
account: {
external_account_id: tenant,
name: account_name
external_account_id: @tenant,
name: @account_name
},
owner: {
name: full_name,
membership_id: membership.id
identity: identity,
}
)
@user = @account.users.find_by!(role: :admin)
# TODO:PLANB: remove this once board and other models have an account_id.
# this is needed because code will try to reference Account#entropy, previously
# that code used Account.sole.
old_account, Current.account = Current.account, @account
# TODO:PLANB: I'm not sure how to get around needing Current.user here (which requires Current.membership)
old_membership, Current.membership = Current.membership, @membership
begin
@account.setup_customer_template
ensure
Current.membership = old_membership
Current.account = old_account
end
@account.setup_customer_template
end
def destroy_tenant
# # TODO:PLANB: need to destroy the account/user records properly
def destroy_account
@account&.destroy!
@user = nil
@account = nil
@tenant = nil
@@ -134,7 +89,7 @@ class Signup
def queenbee_account_attributes
{}.tap do |attributes|
attributes[:product_name] = "fizzy"
attributes[:name] = account_name
attributes[:name] = @account_name
attributes[:owner_name] = full_name
attributes[:owner_email] = email_address
@@ -24,12 +24,10 @@ class Signup::AccountNameGenerator
end
def existing_indices
identity.memberships.filter_map do |membership|
if membership.account_name.blank?
nil
elsif membership.account_name.match?(first_account_name_regex)
identity.accounts.filter_map do |account|
if account.name.match?(first_account_name_regex)
1
elsif match = membership.account_name.match(nth_account_name_regex)
elsif match = account.name.match(nth_account_name_regex)
match[1].to_i
end
end
@@ -1,12 +1,12 @@
<% @page_title = "Creating your account…" %>
<% @page_title = "Complete your sign-up" %>
<div class="panel panel--centered flex flex-column gap-half <%= "shake" if flash[:alert] %>">
<h1 class="txt-x-large font-weight-black margin-block-end"><%= @page_title %></h1>
<%= form_with model: @signup, url: saas.signup_completion_url(script_name: "/#{@signup.tenant}"), scope: "signup", class: "flex flex-column gap", data: { turbo: false, controller: @signup.errors.blank? ? "form auto-submit" : "form" } do |form| %>
<%= form.hidden_field :membership_id %>
<%= form.hidden_field :full_name %>
<%= form.hidden_field :account_name %>
<%= form_with model: @signup, url: saas.signup_completion_path, scope: "signup", class: "flex flex-column gap", data: { controller: "form" } do |form| %>
<%= form.text_field :full_name, class: "input txt-large", autocomplete: "name", placeholder: "Enter your full name…", autofocus: true, required: true %>
<p>Youre one step away. Just enter your name to get your own Fizzy account.</p>
<% if @signup.errors.any? %>
<div class="margin-block-half">
@@ -19,7 +19,8 @@
<% end %>
<button type="submit" class="btn btn--link center" data-form-target="submit">
<span>Done</span>
<span>Continue</span>
<%= icon_tag "arrow-right" %>
</button>
<% end %>
</div>
@@ -1,33 +0,0 @@
<% @page_title = "Complete your sign-up" %>
<div class="panel panel--centered flex flex-column gap-half <%= "shake" if flash[:alert] %>">
<h1 class="txt-x-large font-weight-black margin-block-end"><%= @page_title %></h1>
<%= form_with model: @signup, url: saas.signup_membership_path, scope: "signup", class: "flex flex-column gap", data: { controller: "form" } do |form| %>
<%= form.hidden_field :new_user %>
<%= form.text_field :full_name, class: "input txt-large", autocomplete: "name", placeholder: "Enter your full name…", autofocus: true, required: true %>
<p>Youre one step away. Just enter your name to get your own Fizzy account.</p>
<% if @signup.errors.any? %>
<div class="margin-block-half">
<ul class="margin-block-none txt-negative txt-small">
<% @signup.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<button type="submit" class="btn btn--link center" data-form-target="submit">
<span>Continue</span>
<%= icon_tag "arrow-right" %>
</button>
<% end %>
</div>
<% content_for :footer do %>
<%= render "sessions/footer" %>
<% end %>
-1
View File
@@ -2,7 +2,6 @@ Fizzy::Saas::Engine.routes.draw do
get "/signup/new", to: redirect("/session/new")
namespace :signup do
resource :membership, only: %i[ new create ]
resource :completion, only: %i[ new create ]
end
+1 -1
View File
@@ -148,7 +148,7 @@ class Import
import.users.find_each do |old_user|
new_identity = nil
if old_user.membership_id
if old_user.membership_id && old_user.active?
membership = untenanted.memberships.find(old_user.membership_id)
new_identity = Identity.find_or_create_by!(email_address: membership.identity.email_address)
end
-15
View File
@@ -1,15 +0,0 @@
david_in_37signals:
identity: david
tenant: <%= ActiveRecord::FixtureSet.identify("37signals") %> # matches the external_account_id
jz_in_37signals:
identity: jz
tenant: <%= ActiveRecord::FixtureSet.identify("37signals") %> # matches the external_account_id
kevin_in_37signals:
identity: kevin
tenant: <%= ActiveRecord::FixtureSet.identify("37signals") %> # matches the external_account_id
mike_in_initech:
identity: mike
tenant: <%= ActiveRecord::FixtureSet.identify("initech") %>
+4 -4
View File
@@ -2,21 +2,21 @@ david:
id: <%= ActiveRecord::FixtureSet.identify("david", :uuid) %>
name: David
role: member
membership: david_in_37signals
identity: david
account: 37s_uuid
jz:
id: <%= ActiveRecord::FixtureSet.identify("jz", :uuid) %>
name: JZ
role: member
membership: jz_in_37signals
identity: jz
account: 37s_uuid
kevin:
id: <%= ActiveRecord::FixtureSet.identify("kevin", :uuid) %>
name: Kevin
role: admin
membership: kevin_in_37signals
identity: kevin
account: 37s_uuid
system:
@@ -29,5 +29,5 @@ mike:
id: <%= ActiveRecord::FixtureSet.identify("mike", :uuid) %>
name: Mike
role: admin
membership: mike_in_initech
identity: mike
account: initech_uuid