Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow admins to invite other staff #251

Merged
merged 3 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ gem "bootstrap_form", "~> 5.3"
# Devise Authentication
gem "devise"

gem "devise_invitable", "~> 2.0.0"

# Use Sass to process CSS
gem "dartsass-rails"

Expand Down
4 changes: 4 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ GEM
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
devise_invitable (2.0.8)
actionmailer (>= 5.0)
devise (>= 4.6)
docile (1.4.0)
em-websocket (0.5.3)
eventmachine (>= 0.12.9)
Expand Down Expand Up @@ -476,6 +479,7 @@ DEPENDENCIES
dartsass-rails
debug
devise
devise_invitable (~> 2.0.0)
evil_systems (~> 1.1)
factory_bot_rails
faker
Expand Down
30 changes: 30 additions & 0 deletions app/controllers/organizations/invitations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
class Organizations::InvitationsController < Devise::InvitationsController
before_action :require_organization_admin, only: [:new, :create]
layout "dashboard", only: [:new, :create]

def new
@user = User.new
@staff = StaffAccount.new(user: @user)
end

def create
@user = User.new(user_params.merge(password: SecureRandom.hex(8)).except(:staff_account_attributes))
@user.staff_account = StaffAccount.new(verified: true)

if @user.save
@user.staff_account.add_role(user_params[:staff_account_attributes][:roles])
@user.invite!(current_user)
redirect_to staff_index_path, notice: "Staff saved successfully."
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we change the notice to something like "Invite sent!"?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think both make sense here. The staff account does get saved and the invitation is sent

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "Invite sent!" makes more sense from the user perspective. Fixed!

I also changed texts in a couple of other places from "Add staff" to "Invite staff".

else
render :new, status: :unprocessable_entity
end
end

private

def user_params
params.require(:user)
.permit(:first_name, :last_name, :email,
staff_account_attributes: [:roles])
end
end
25 changes: 0 additions & 25 deletions app/controllers/organizations/staff_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,4 @@ class Organizations::StaffController < Organizations::BaseController
def index
@staff_accounts = StaffAccount.all
end

def new
@user = User.new
@staff = StaffAccount.new(user: @user)
end

def create
@user = User.new(user_params.merge(password: SecureRandom.hex(8)).except(:staff_account_attributes))
@user.staff_account = StaffAccount.new

if @user.save
@user.staff_account.add_role(user_params[:staff_account_attributes][:roles])
redirect_to staff_index_path, notice: "Staff saved successfully."
else
render :new, status: :unprocessable_entity
end
end

private

def user_params
params.require(:user)
.permit(:first_name, :last_name, :email,
staff_account_attributes: [:roles])
end
end
1 change: 1 addition & 0 deletions app/models/pet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
# name :string
# pause_reason :integer default("not_paused")
# sex :string
# species :integer not null
# weight_from :integer not null
# weight_to :integer not null
# weight_unit :string not null
Expand Down
13 changes: 12 additions & 1 deletion app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,29 @@
# email :string default(""), not null
# encrypted_password :string default(""), not null
# first_name :string not null
# invitation_accepted_at :datetime
# invitation_created_at :datetime
# invitation_limit :integer
# invitation_sent_at :datetime
# invitation_token :string
# invitations_count :integer default(0)
# invited_by_type :string
# last_name :string not null
# remember_created_at :datetime
# reset_password_sent_at :datetime
# reset_password_token :string
# tos_agreement :boolean
# created_at :datetime not null
# updated_at :datetime not null
# invited_by_id :bigint
# organization_id :bigint
#
# Indexes
#
# index_users_on_email (email) UNIQUE
# index_users_on_invitation_token (invitation_token) UNIQUE
# index_users_on_invited_by (invited_by_type,invited_by_id)
# index_users_on_invited_by_id (invited_by_id)
# index_users_on_organization_id (organization_id)
# index_users_on_reset_password_token (reset_password_token) UNIQUE
#
Expand All @@ -35,7 +46,7 @@ class User < ApplicationRecord
end
end

devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable
devise :invitable, :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable

validates :first_name, presence: true
validates :last_name, presence: true
Expand Down
39 changes: 39 additions & 0 deletions app/views/organizations/invitations/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!-- form -->
<%= bootstrap_form_with model: user, url: invitation_path(user) do |form| %>

<div class="row gx-3">
<!-- form group -->
<div class="mb-3 col-md-6 col-12">
<div class="input-group me-3">
<%= form.text_field :first_name, class: 'form-control', required: true %>
</div>
</div>
<!-- form group -->
<div class="mb-3 col-md-6 col-12">
<div class="input-group me-3">
<%= form.text_field :last_name, class: 'form-control', required: true %>
</div>
</div>
<!-- form group -->
<div class="mb-3 col-12">
<div class="input-group">
<%= form.text_field :email, class: 'form-control', required: true %>
</div>
</div>

<!-- form group -->
<%= form.fields_for :staff_account do |staff_subform| %>
<div class="mb-3 col-md-6 col-12">
<div class="input-group me-3">
<%= staff_subform.select :roles, options_for_select([['Staff', :staff], ['Admin', :admin]]), class: 'form-control', required: true %>
</div>
</div>
<% end %>

<!-- button -->
<div class="col-12 mt-3">
<%= form.submit 'Save profile', class: 'btn btn-primary' %>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we change button to 'Send Invite' ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thanks!

</div>
</div>

<% end %>
21 changes: 21 additions & 0 deletions app/views/organizations/invitations/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<h2><%= t "devise.invitations.edit.header" %></h2>

<%= form_for(resource, as: resource_name, url: invitation_path(resource_name), html: { method: :put }) do |f| %>
<%= f.hidden_field :invitation_token, readonly: true %>

<% if f.object.class.require_password_on_accepting %>
<div class="field">
<%= f.label :password %><br />
<%= f.password_field :password %>
</div>

<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %>
</div>
<% end %>

<div class="actions">
<%= f.submit t("devise.invitations.edit.submit_button") %>
</div>
<% end %>
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@
</div>
</div>
</div>
</section>
</section>
11 changes: 11 additions & 0 deletions app/views/organizations/mailer/invitation_instructions.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<p><%= t("devise.mailer.invitation_instructions.hello", email: @resource.email) %></p>

<p><%= t("devise.mailer.invitation_instructions.someone_invited_you", url: root_url) %></p>

<p><%= link_to t("devise.mailer.invitation_instructions.accept"), accept_invitation_url(@resource, invitation_token: @token) %></p>

<% if @resource.invitation_due_at %>
<p><%= t("devise.mailer.invitation_instructions.accept_until", due_date: l(@resource.invitation_due_at, format: :'devise.mailer.invitation_instructions.accept_until_format')) %></p>
<% end %>

<p><%= t("devise.mailer.invitation_instructions.ignore") %></p>
11 changes: 11 additions & 0 deletions app/views/organizations/mailer/invitation_instructions.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<%= t("devise.mailer.invitation_instructions.hello", email: @resource.email) %>

<%= t("devise.mailer.invitation_instructions.someone_invited_you", url: root_url) %>

<%= accept_invitation_url(@resource, invitation_token: @token) %>

<% if @resource.invitation_due_at %>
<%= t("devise.mailer.invitation_instructions.accept_until", due_date: l(@resource.invitation_due_at, format: :'devise.mailer.invitation_instructions.accept_until_format')) %>
<% end %>

<%= t("devise.mailer.invitation_instructions.ignore") %>
68 changes: 0 additions & 68 deletions app/views/organizations/staff/_form.html.erb

This file was deleted.

4 changes: 2 additions & 2 deletions app/views/organizations/staff/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<!--create staff button-->
<%= content_for :button do %>
<%= link_to "New Staff", new_staff_path, class: "btn btn-primary" %><br>
<%= link_to "New Staff", new_user_invitation_path, class: "btn btn-primary" %><br>
<% end %>

<section class="container-fluid p-4">
Expand Down Expand Up @@ -140,4 +140,4 @@
</div>
</div>
</div>
</section>
</section>
49 changes: 49 additions & 0 deletions config/initializers/devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,55 @@
# Send a notification email when the user's password is changed.
# config.send_password_change_notification = false

# ==> Configuration for :invitable
# The period the generated invitation token is valid.
# After this period, the invited resource won't be able to accept the invitation.
# When invite_for is 0 (the default), the invitation won't expire.
# config.invite_for = 2.weeks

# Number of invitations users can send.
# - If invitation_limit is nil, there is no limit for invitations, users can
# send unlimited invitations, invitation_limit column is not used.
# - If invitation_limit is 0, users can't send invitations by default.
# - If invitation_limit n > 0, users can send n invitations.
# You can change invitation_limit column for some users so they can send more
# or less invitations, even with global invitation_limit = 0
# Default: nil
# config.invitation_limit = 5

# The key to be used to check existing users when sending an invitation
# and the regexp used to test it when validate_on_invite is not set.
# config.invite_key = { email: /\A[^@]+@[^@]+\z/ }
# config.invite_key = { email: /\A[^@]+@[^@]+\z/, username: nil }

# Ensure that invited record is valid.
# The invitation won't be sent if this check fails.
# Default: false
# config.validate_on_invite = true

# Resend invitation if user with invited status is invited again
# Default: true
# config.resend_invitation = false

# The class name of the inviting model. If this is nil,
# the #invited_by association is declared to be polymorphic.
# Default: nil
# config.invited_by_class_name = 'User'

# The foreign key to the inviting model (if invited_by_class_name is set)
# Default: :invited_by_id
# config.invited_by_foreign_key = :invited_by_id

# The column name used for counter_cache column. If this is nil,
# the #invited_by association is declared without counter_cache.
# Default: nil
# config.invited_by_counter_cache = :invitations_count

# Auto-login after the user accepts the invite. If this is false,
# the user will need to manually log in after accepting the invite.
# Default: true
# config.allow_insecure_sign_in_after_accept = false

# ==> Configuration for :confirmable
# A period that the user is allowed to access the website even without
# confirming their account. For instance, if set to 2.days, the user will be
Expand Down