diff --git a/app/controllers/profile_controller.rb b/app/controllers/profile_controller.rb
index b7f73c50..f0807995 100644
--- a/app/controllers/profile_controller.rb
+++ b/app/controllers/profile_controller.rb
@@ -1,23 +1,42 @@
# frozen_string_literal: true
class ProfileController < ApplicationController
- def index
- @user = current_user
+ def update_contact
+ if current_user.update(contact_params)
+ redirect_to contact_settings_profile_index_path, notice: 'Contact information successfully updated'
+ else
+ render :contact, status: :unprocessable_entity
+ end
end
- def update
- @user = current_user
+ def update_password
+ if current_user.update_with_password(password_params)
+ bypass_sign_in(current_user)
+ redirect_to password_settings_profile_index_path, notice: 'Password successfully changed'
+ else
+ render :password, status: :unprocessable_entity
+ end
+ end
- if @user.update(user_params)
- redirect_to settings_profile_path, notice: 'Profile updated'
+ def update_email
+ if current_user.update_with_password(email_params)
+ redirect_to email_settings_profile_index_path, notice: 'Email successfully updated. Please check your new email for confirmation instructions.'
else
- render :index
+ render :email, status: :unprocessable_entity
end
end
private
- def user_params
- params.require(:user).permit(:first_name, :last_name)
+ def contact_params
+ params.require(:user).permit(:first_name, :last_name, account_attributes: %i[name])
+ end
+
+ def password_params
+ params.require(:user).permit(:current_password, :password, :password_confirmation)
+ end
+
+ def email_params
+ params.require(:user).permit(:current_password, :email)
end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 0aaf3d97..a53fe09f 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -5,6 +5,9 @@
# Table name: users
#
# id :bigint not null, primary key
+# confirmation_sent_at :datetime
+# confirmation_token :string
+# confirmed_at :datetime
# current_sign_in_at :datetime
# current_sign_in_ip :string
# deleted_at :datetime
@@ -21,6 +24,7 @@
# reset_password_token :string
# role :string not null
# sign_in_count :integer default(0), not null
+# unconfirmed_email :string
# unlock_token :string
# created_at :datetime not null
# updated_at :datetime not null
@@ -45,13 +49,15 @@ class User < ApplicationRecord
belongs_to :account
- devise :database_authenticatable, :recoverable, :rememberable, :validatable, :trackable
+ devise :database_authenticatable, :recoverable, :rememberable, :validatable, :trackable, :confirmable
devise :registerable # if ENV['APP_MULTITENANT']
attribute :role, :string, default: 'admin'
scope :active, -> { where(deleted_at: nil) }
+ accepts_nested_attributes_for :account, update_only: true
+
def active_for_authentication?
!deleted_at?
end
diff --git a/app/views/devise/confirmations/new.html.erb b/app/views/devise/confirmations/new.html.erb
new file mode 100644
index 00000000..e37dd597
--- /dev/null
+++ b/app/views/devise/confirmations/new.html.erb
@@ -0,0 +1,14 @@
+
+
Resend confirmation instructions
+ <%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post, class: 'space-y-6' }) do |f| %>
+ <%= render "devise/shared/error_messages", resource: resource %>
+
+ <%= f.label :email, class: 'label' %>
+ <%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email), class: 'base-input' %>
+
+
+ <%= f.submit "Resend confirmation instructions", class: 'base-button' %>
+
+ <% end %>
+ <%= render "devise/shared/links" %>
+
diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb
new file mode 100644
index 00000000..57193aa7
--- /dev/null
+++ b/app/views/devise/mailer/confirmation_instructions.html.erb
@@ -0,0 +1,3 @@
+Welcome <%= @email %>!
+You can confirm your account email through the link below:
+<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>
diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb
index cc73180b..d6c10878 100644
--- a/app/views/devise/shared/_links.html.erb
+++ b/app/views/devise/shared/_links.html.erb
@@ -1,22 +1,22 @@
-
+
<%- if controller_name != 'sessions' %>
- <%= link_to 'Log in', new_session_path(resource_name), class: 'link link-hover' %>
+ <%= link_to 'Log in', new_session_path(resource_name), class: 'badge badge-outline my-1' %>
<% end %>
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
- <%= link_to 'Sign up', new_registration_path, class: 'link link-hover' %>
+ <%= link_to 'Sign up', new_registration_path, class: 'badge badge-outline my-1' %>
<% end %>
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
- <%= link_to 'Forgot your password?', new_password_path(resource_name), class: 'link link-hover' %>
+ <%= link_to 'Forgot your password?', new_password_path(resource_name), class: 'badge badge-outline my-1' %>
<% end %>
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
- <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: 'link link-hover' %>
+ <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: 'badge badge-outline my-1' %>
<% end %>
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
- <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name), class: 'link link-hover' %>
+ <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name), class: 'badge badge-outline my-1' %>
<% end %>
<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
- <%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), class: 'link link-hover', data: { turbo: false } %>
+ <%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), class: 'badge badge-outline my-1', data: { turbo: false } %>
<% end %>
<% end %>
diff --git a/app/views/profile/_navigation.html.erb b/app/views/profile/_navigation.html.erb
new file mode 100644
index 00000000..39db35ea
--- /dev/null
+++ b/app/views/profile/_navigation.html.erb
@@ -0,0 +1,36 @@
+
+
+
diff --git a/app/views/profile/index.html.erb b/app/views/profile/contact.html.erb
similarity index 64%
rename from app/views/profile/index.html.erb
rename to app/views/profile/contact.html.erb
index 78538561..5c686b9c 100644
--- a/app/views/profile/index.html.erb
+++ b/app/views/profile/contact.html.erb
@@ -2,7 +2,8 @@
<%= render 'shared/settings_nav' %>
Profile
- <%= form_for @user, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
+ <%= render 'navigation' %>
+ <%= form_for current_user, url: update_contact_settings_profile_index_path, method: :patch, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
<%= f.label :first_name, class: 'label' %>
@@ -13,6 +14,12 @@
<%= f.text_field :last_name, required: true, class: 'base-input' %>
+ <%= f.fields_for :account do |ff| %>
+
+ <%= ff.label :name, 'Company Name', class: 'label' %>
+ <%= ff.text_field :name, required: true, class: 'base-input' %>
+
+ <% end %>
<%= f.button button_title, class: 'base-button' %>
diff --git a/app/views/profile/email.html.erb b/app/views/profile/email.html.erb
new file mode 100644
index 00000000..cb40c857
--- /dev/null
+++ b/app/views/profile/email.html.erb
@@ -0,0 +1,30 @@
+
+ <%= render 'shared/settings_nav' %>
+
+
Profile
+ <%= render 'navigation' %>
+ <%= form_for current_user, url: update_email_settings_profile_index_path, method: :patch, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
+ <% if current_user.pending_reconfirmation? %>
+
+
+
+
Currently waiting confirmation
+
Unconfirmed email: <%= current_user.unconfirmed_email %>
+
+
+ <% end %>
+
+ <%= f.label :email, 'New email', class: 'label' %>
+ <%= f.email_field :email, autocomplete: 'off', class: 'base-input' %>
+
+
+ <%= f.label :current_password, 'Current password', class: 'label' %>
+ <%= f.password_field :current_password, autocomplete: 'off', class: 'base-input' %>
+
+
+ <%= f.button button_title, class: 'base-button' %>
+
+ <% end %>
+
+
+
diff --git a/app/views/profile/password.html.erb b/app/views/profile/password.html.erb
new file mode 100644
index 00000000..8a54cb03
--- /dev/null
+++ b/app/views/profile/password.html.erb
@@ -0,0 +1,25 @@
+
+ <%= render 'shared/settings_nav' %>
+
+
Profile
+ <%= render 'navigation' %>
+ <%= form_for current_user, url: update_password_settings_profile_index_path, method: :patch, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
+
+ <%= f.label :current_password, 'Current password', class: 'label' %>
+ <%= f.password_field :current_password, autocomplete: 'off', class: 'base-input' %>
+
+
+ <%= f.label :password, 'New password', class: 'label' %>
+ <%= f.password_field :password, autocomplete: 'off', class: 'base-input' %>
+
+
+ <%= f.label :password_confirmation, 'Confirm new password', class: 'label' %>
+ <%= f.password_field :password_confirmation, autocomplete: 'off', class: 'base-input' %>
+
+
+ <%= f.button button_title, class: 'base-button' %>
+
+ <% end %>
+
+
+
diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb
index 6716731e..27b8a588 100644
--- a/app/views/shared/_navbar.html.erb
+++ b/app/views/shared/_navbar.html.erb
@@ -12,7 +12,7 @@
-
- <%= link_to 'Profile', settings_profile_index_path, class: 'text-right' %>
+ <%= link_to 'Profile Settings', contact_settings_profile_index_path, class: 'text-right' %>
-
<%= link_to 'Sign out', destroy_user_session_path, data: { turbo_method: :delete } %>
diff --git a/app/views/shared/_settings_nav.html.erb b/app/views/shared/_settings_nav.html.erb
index 8d5df4b0..4291c141 100644
--- a/app/views/shared/_settings_nav.html.erb
+++ b/app/views/shared/_settings_nav.html.erb
@@ -4,7 +4,7 @@
-
- <%= link_to 'Profile', settings_profile_index_path, class: "text-base hover:bg-base-300" %>
+ <%= link_to 'Profile', contact_settings_profile_index_path, class: "text-base hover:bg-base-300" %>
-
<%= link_to 'Email', settings_email_index_path, class: "text-base hover:bg-base-300" %>
diff --git a/app/views/storage_settings/index.html.erb b/app/views/storage_settings/index.html.erb
index 87298ec3..841bac56 100644
--- a/app/views/storage_settings/index.html.erb
+++ b/app/views/storage_settings/index.html.erb
@@ -11,7 +11,7 @@
<% options = [['Disk', 'disk'], ['AWS S3', 'aws_s3'], ['Google Cloud', 'google']] %>
- <% [['Disk', 'disk'], ['AWS S3', 'aws_s3'], ['Google Cloud', 'google']].each do |(label, val)| %>
+ <% options.each do |(label, val)| %>
<%= f.label :selected, value: val, class: 'w-full flex flex-1 items-center space-x-2 btn btn-outline rounded-xl' do %>
<%= f.radio_button :selected, val, checked: value['service'] == val, data: { action: 'change:toggle-visible#trigger' }, class: 'base-radio' %>
<%= label %>
diff --git a/config/routes.rb b/config/routes.rb
index d7d71738..741ba2e3 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -5,7 +5,7 @@ Rails.application.routes.draw do
root 'dashboard#index'
- devise_for :users, path: '/', only: %i[sessions passwords]
+ devise_for :users, path: '/', only: %i[sessions passwords confirmations]
devise_scope :user do
if User.devise_modules.include?(:registerable)
@@ -55,7 +55,16 @@ Rails.application.routes.draw do
resources :storage, only: %i[index create], controller: 'storage_settings'
resources :email, only: %i[index create], controller: 'email_settings'
resources :esign, only: %i[index create], controller: 'esign_settings'
- resources :profile, only: %i[index update]
resources :users, only: %i[index]
+ resources :profile, only: %i[] do
+ collection do
+ get :contact
+ get :password
+ get :email
+ patch :contact, :update_contact
+ patch :password, :update_password
+ patch :email, :update_email
+ end
+ end
end
end
diff --git a/db/migrate/20230606210549_add_confirmation_to_users.rb b/db/migrate/20230606210549_add_confirmation_to_users.rb
new file mode 100644
index 00000000..4ea5a8c2
--- /dev/null
+++ b/db/migrate/20230606210549_add_confirmation_to_users.rb
@@ -0,0 +1,8 @@
+class AddConfirmationToUsers < ActiveRecord::Migration[7.0]
+ def change
+ add_column :users, :confirmation_token, :string, unique: true
+ add_column :users, :confirmed_at, :datetime
+ add_column :users, :confirmation_sent_at, :datetime
+ add_column :users, :unconfirmed_email, :string, unique: true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index da90df29..6b2f5449 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.0].define(version: 2023_05_19_144036) do
+ActiveRecord::Schema[7.0].define(version: 2023_06_06_210549) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -115,6 +115,10 @@ ActiveRecord::Schema[7.0].define(version: 2023_05_19_144036) do
t.datetime "deleted_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
+ t.string "confirmation_token"
+ t.datetime "confirmed_at"
+ t.datetime "confirmation_sent_at"
+ t.string "unconfirmed_email"
t.index ["account_id"], name: "index_users_on_account_id"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true