Added the ability to log multiple access periods to each User and the ability to not only display these access periods but also remove them if accidentally entered.

This commit is contained in:
Ben 2024-04-12 02:40:09 -05:00
parent e7abc0fa50
commit b4cd83c2e7
7 changed files with 98 additions and 44 deletions

View File

@ -1,6 +1,6 @@
class AdminController < ApplicationController class AdminController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
load_and_authorize_resource class: User before_action :check_admin
def new_user def new_user
@user = User.new @user = User.new
@ -9,7 +9,7 @@ class AdminController < ApplicationController
def create_user def create_user
@user = User.new(user_params) @user = User.new(user_params)
if @user.save if @user.save
redirect_to some_admin_path, notice: 'User was successfully created.' # Update the redirect path as needed redirect_to users_path, notice: 'User was successfully created.'
else else
render :new_user render :new_user
end end
@ -18,7 +18,13 @@ class AdminController < ApplicationController
private private
def user_params def user_params
params.require(:user).permit(:email, :password, :password_confirmation) params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :phone, :company)
# Ensure you permit the right parameters
end end
def check_admin
unless current_user.admin?
redirect_to root_path, alert: 'Not authorized'
end
end
end end

View File

@ -10,14 +10,24 @@ class UsersController < ApplicationController
def new def new
@user = User.new @user = User.new
@user.access_periods.build unless @user.access_periods.any?
end end
def edit def edit
@user = User.find(params[:id])
@user.access_periods.build if @user.access_periods.empty?
end end
def create def create
@user = User.new(user_params.except(:roles)) @user = User.new(user_params)
# Ensure an access period is built if none exist and no start_date is provided
if @user.access_periods.empty?
@user.access_periods.build(start_date: Date.today) # Set start date automatically
end
if @user.save if @user.save
update_user_roles(@user, params[:user][:roles] || ['user']) update_user_roles(@user, params[:user][:roles] || ['user'])
redirect_to users_path, notice: 'User was successfully created.' redirect_to users_path, notice: 'User was successfully created.'
@ -25,16 +35,29 @@ class UsersController < ApplicationController
render :new render :new
end end
end end
def update def update
# Assumes @user is already set from a before_action callback @user = User.find(params[:id]) # Assumes @user is already set from a before_action callback, so this line could be redundant if such a callback exists.
if @user.update(user_params.except(:roles)) if @user.update(user_params.except(:roles))
# Check and update the access revoked status and end date
if params[:user][:access_revoked] == "1"
# This assumes that you always want to update the latest access period.
# Consider the logic if multiple access periods can exist and which one should be updated.
last_access_period = @user.access_periods.order(:created_at).last
last_access_period.update(end_date: Date.today) unless last_access_period.end_date.present?
end
# Update user roles if they are part of the form submission
update_user_roles(@user, user_params[:roles]) update_user_roles(@user, user_params[:roles])
handle_access_revocation
redirect_to users_path, notice: 'User was successfully updated.' redirect_to users_path, notice: 'User was successfully updated.'
else else
render :edit render :edit
end end
end end
def show def show
@user = User.includes(:access_periods).find(params[:id]) @user = User.includes(:access_periods).find(params[:id])
@ -57,7 +80,7 @@ class UsersController < ApplicationController
:email, :password, :password_confirmation, :remember_me, :email, :password, :password_confirmation, :remember_me,
:first_name, :last_name, :phone, :company, :first_name, :last_name, :phone, :company,
:access_revoked, :access_start_date, :access_end_date, :access_revoked, :access_start_date, :access_end_date,
access_periods_attributes: [:id, :start_date, :end_date, :destroy], access_periods_attributes: [:id, :start_date, :end_date, :_destroy],
roles: [] roles: []
) )
end end
@ -79,12 +102,19 @@ class UsersController < ApplicationController
def update_user_roles(user, roles_names) def update_user_roles(user, roles_names)
return if roles_names.blank? # Do nothing if no roles provided return if roles_names.blank? # Do nothing if no roles provided
user.roles.delete_all # Consider keeping this if role reset is truly intended
roles_names.each do |role_name| roles_names.each do |role_name|
user.add_role(role_name) unless role_name.blank? user.add_role(role_name) unless role_name.blank?
end end
end end
def handle_access_revocation
if params[:user][:access_revoked] == "1"
current_period = @user.access_periods.find_or_initialize_by(end_date: nil)
current_period.update(end_date: Date.today) unless current_period.end_date.present?
elsif params[:user][:access_revoked] == "0" && @user.access_periods.last&.end_date.present?
@user.access_periods.build(start_date: Date.today)
end
end

View File

@ -1,3 +1,12 @@
class AccessPeriod < ApplicationRecord class AccessPeriod < ApplicationRecord
belongs_to :user belongs_to :user
before_validation :set_default_start_date, on: :create
validates :end_date, presence: true, if: -> { user&.access_revoked? }
private
def set_default_start_date
self.start_date ||= Date.today if self.new_record? && self.start_date.blank?
end
end end

View File

@ -3,7 +3,7 @@
<div class="col-md-6"> <div class="col-md-6">
<h2 class="mb-3 text-center">Create New User</h2> <h2 class="mb-3 text-center">Create New User</h2>
<%= form_for(@user, url: users_path, html: { class: 'needs-validation', novalidate: true }) do |f| %> <%= form_for(@user, url: admin_users_path, html: { class: 'needs-validation', novalidate: true }) do |f| %>
<div class="mb-3"> <div class="mb-3">
<%= f.label :first_name, 'First Name', class: 'form-label' %> <%= f.label :first_name, 'First Name', class: 'form-label' %>
<%= f.text_field :first_name, class: 'form-control', placeholder: 'Enter first name', required: true %> <%= f.text_field :first_name, class: 'form-control', placeholder: 'Enter first name', required: true %>
@ -16,7 +16,7 @@
<div class="mb-3"> <div class="mb-3">
<%= f.label :email, class: 'form-label' %> <%= f.label :email, class: 'form-label' %>
<%= f.email_field :email, class: 'form-control', placeholder: 'Enter email', required: true, autocomplete: "new-password" %> <%= f.email_field :email, class: 'form-control', placeholder: 'Enter email', required: true, autocomplete: "new-email" %>
</div> </div>
<div class="mb-3"> <div class="mb-3">

View File

@ -2,66 +2,53 @@
<%# Display validation errors, if any %> <%# Display validation errors, if any %>
<% if user.errors.any? %> <% if user.errors.any? %>
<%# Error messages display block %> <div class="alert alert-danger">
<strong>Please correct the following errors:</strong>
<ul>
<% user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %> <% end %>
<%# User attributes fields %> <%# User attributes fields %>
<%# First Name %>
<div class="mb-3"> <div class="mb-3">
<%= form.label :first_name, class: 'form-label' %> <%= form.label :first_name, class: 'form-label' %>
<%= form.text_field :first_name, id: :user_first_name, class: 'form-control' %> <%= form.text_field :first_name, id: :user_first_name, class: 'form-control' %>
</div> </div>
<%# Last Name %>
<div class="mb-3"> <div class="mb-3">
<%= form.label :last_name, class: 'form-label' %> <%= form.label :last_name, class: 'form-label' %>
<%= form.text_field :last_name, id: :user_last_name, class: 'form-control' %> <%= form.text_field :last_name, id: :user_last_name, class: 'form-control' %>
</div> </div>
<%# Email field %>
<div class="mb-3"> <div class="mb-3">
<%= form.label :email, class: 'form-label' %> <%= form.label :email, class: 'form-label' %>
<%= form.email_field :email, id: :user_email, class: 'form-control' %> <%= form.email_field :email, id: :user_email, class: 'form-control' %>
</div> </div>
<%# Phone Number %>
<div class="mb-3"> <div class="mb-3">
<%= form.label :phone, class: 'form-label' %> <%= form.label :phone, class: 'form-label' %>
<%= form.telephone_field :phone, id: :user_phone, class: 'form-control' %> <%= form.telephone_field :phone, id: :user_phone, class: 'form-control' %>
</div> </div>
<%# Company %>
<div class="mb-3"> <div class="mb-3">
<%= form.label :company, class: 'form-label' %> <%= form.label :company, class: 'form-label' %>
<%= form.text_field :company, id: :user_company, class: 'form-control' %> <%= form.text_field :company, id: :user_company, class: 'form-control' %>
</div> </div>
<%# Assuming roles are assigned via checkboxes or a select dropdown %>
<div class="mb-3"> <div class="mb-3">
<%= form.label :roles, 'Assign Role(s)', class: 'form-label' %> <%= form.label :roles, 'Assign Role(s)', class: 'form-label' %>
<%# Adjust this to your roles setup %>
<%= form.collection_select :roles, Role.all, :name, :name, {}, { multiple: true, class: 'form-select' } %> <%= form.collection_select :roles, Role.all, :name, :name, {}, { multiple: true, class: 'form-select' } %>
</div> </div>
<%# Access control fields %>
<div class="mb-3"> <div class="mb-3">
<%= form.check_box :access_revoked, class: 'form-check-input' %> <%= form.check_box :access_revoked, class: 'form-check-input' %>
<%= form.label :access_revoked, 'Access Revoked', class: 'form-check-label' %> <%= form.label :access_revoked, 'Access Revoked', class: 'form-check-label' %>
</div> </div>
<%# Date fields for access control %> <h3>Access Periods</h3>
<%= form.fields_for :access_periods do |period_form| %>
<div class="mb-3">
<%= period_form.label :start_date, 'Access Start Date', class: 'form-label' %>
<%= period_form.date_field :start_date, class: 'form-control' %>
</div>
<div class="mb-3">
<%= period_form.label :end_date, 'Access End Date', class: 'form-label' %>
<%= period_form.date_field :end_date, class: 'form-control' %>
</div>
<% end %>
<h3>Access Periods</h3>
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
@ -70,17 +57,37 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<% @user.access_periods.each do |period| %> <% @user.access_periods.order(:start_date).each do |period| %>
<tr> <tr>
<td><%= period.start_date %></td> <td><%= period.start_date ? period.start_date.strftime("%B %d, %Y") : 'Not set' %></td>
<td><%= period.end_date || 'Currently has access' %></td> <td><%= period.end_date ? period.end_date.strftime("%B %d, %Y") : 'Currently has access' %></td>
</tr> </tr>
<% end %> <% end %>
</tbody> </tbody>
</table> </table>
<%# Date fields for access control %>
<%= form.fields_for :access_periods do |period_form| %>
<div class="row">
<div class="col-md-5">
<%= period_form.label :start_date, 'Access Start Date' %>
<%= period_form.date_field :start_date, class: 'form-control' %>
</div>
<div class="col-md-5">
<%= period_form.label :end_date, 'Access End Date' %>
<%= period_form.date_field :end_date, class: 'form-control' %>
</div>
<% if period_form.object.persisted? %>
<div class="col-md-2">
<%= period_form.check_box :_destroy %>
<%= period_form.label :_destroy, 'Remove' %>
</div>
<% end %>
</div>
<% end %>
<%# Submit button %> <%# Submit button %>
<div class="actions"> <div class="actions mt-3">
<%= form.submit 'Save', class: 'btn btn-dark' %> <%= form.submit 'Save', class: 'btn btn-dark' %>
</div> </div>

View File

@ -41,7 +41,7 @@
<div class="col-12 d-flex justify-content-between mb-4"> <div class="col-12 d-flex justify-content-between mb-4">
<!-- Button for Admins to add a new user --> <!-- Button for Admins to add a new user -->
<% if can?(:create, User) %> <!-- Checks if the current user has the permission to create new users --> <% if can?(:create, User) %> <!-- Checks if the current user has the permission to create new users -->
<%= link_to 'Add New User', new_user_admin_path, class: "btn btn-dark" %> <%= link_to 'Add New User', new_admin_user_path, class: "btn btn-dark" %>
<% end %> <% end %>
<%= link_to 'Back to Home', root_path, class: "btn btn-secondary" %> <!-- Adjust as needed --> <%= link_to 'Back to Home', root_path, class: "btn btn-secondary" %> <!-- Adjust as needed -->

View File

@ -85,13 +85,15 @@ Rails.application.routes.draw do
resources :forms resources :forms
resources :users resources :users
resource :admin, controller: 'admin', only: [] do # Setup the routes under a scope to mimic namespace-like behavior without actual namespacing
get 'users/new', to: 'admin#new_user', as: 'new_user' scope '/admin', controller: :admin do
post 'users', to: 'admin#create_user', as: 'create_user' get 'users/new', as: 'new_admin_user', action: :new_user # for displaying the new user form
# Define other routes as needed post 'users', as: 'admin_users', action: :create_user # for submitting the new user form
# You can add more admin routes here as needed
end end
get 'home/index' get 'home/index'
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html