button toggle for ip address role active
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# typed: true
|
||||
class State::IpAddressRolesController < ApplicationController
|
||||
before_action :set_ip_address_role, only: %i[edit update destroy]
|
||||
before_action :set_ip_address_role, only: %i[edit update destroy toggle]
|
||||
before_action :authorize_ip_address_roles
|
||||
|
||||
# GET /state/ip_address_roles
|
||||
@@ -46,6 +46,14 @@ class State::IpAddressRolesController < ApplicationController
|
||||
notice: "IP address role was successfully deleted."
|
||||
end
|
||||
|
||||
def toggle
|
||||
@ip_address_role.update!(active: !@ip_address_role.active)
|
||||
redirect_to state_ip_address_roles_path
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
redirect_to state_ip_address_roles_path,
|
||||
alert: "Failed to update status: #{e.message}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Use callbacks to share common setup or constraints between actions
|
||||
@@ -70,7 +78,7 @@ class State::IpAddressRolesController < ApplicationController
|
||||
authorize IpAddressRole, policy_class: State::IpAddressRolePolicy
|
||||
when :create
|
||||
authorize IpAddressRole, policy_class: State::IpAddressRolePolicy
|
||||
when :update, :destroy
|
||||
when :update, :destroy, :toggle
|
||||
authorize @ip_address_role, policy_class: State::IpAddressRolePolicy
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
class IpAddressRole < ReduxApplicationRecord
|
||||
extend T::Sig
|
||||
|
||||
# Use the same role enum as User for consistency
|
||||
enum :role, User.roles, default: :user
|
||||
# Only roles that exist in the User model are allowed
|
||||
# Only allow 'user' role for now, as it is the least privileged
|
||||
enum :role, { user: "user" }, default: :user
|
||||
|
||||
validates :ip_address, presence: true, uniqueness: true
|
||||
validates :role, presence: true
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
class State::IpAddressRolePolicy < ApplicationPolicy
|
||||
extend T::Sig
|
||||
|
||||
@@ -32,6 +32,11 @@ class State::IpAddressRolePolicy < ApplicationPolicy
|
||||
is_role_admin?
|
||||
end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def toggle?
|
||||
update?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
class Scope
|
||||
|
||||
@@ -51,23 +51,24 @@
|
||||
<%= ip_role.description %>
|
||||
</td>
|
||||
<td class="py-2 pr-4 text-sm">
|
||||
<% if ip_role.active? %>
|
||||
<span class="text-emerald-600 font-medium">Active</span>
|
||||
<% else %>
|
||||
<span class="text-slate-500 font-medium">Inactive</span>
|
||||
<%= button_to toggle_state_ip_address_role_path(ip_role),
|
||||
method: :patch,
|
||||
class: "#{ip_role.active? ? 'bg-emerald-100 hover:bg-emerald-200 text-emerald-700' : 'bg-slate-100 hover:bg-slate-200 text-slate-700'} font-medium py-1 px-3 rounded inline-flex items-center w-24 justify-center" do %>
|
||||
<i class="fa-solid <%= ip_role.active? ? 'fa-check-circle' : 'fa-circle-xmark' %> mr-1.5"></i>
|
||||
<%= ip_role.active? ? 'Active' : 'Inactive' %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="py-2 pr-4 text-sm text-slate-500">
|
||||
<%= ip_role.created_at.strftime('%Y-%m-%d %H:%M') %>
|
||||
</td>
|
||||
<td class="py-2 text-right text-sm font-medium">
|
||||
<td class="py-2 text-right text-sm font-medium space-x-2">
|
||||
<%= link_to 'Edit',
|
||||
edit_state_ip_address_role_path(ip_role),
|
||||
class: "text-blue-600 hover:text-blue-900 mr-3" %>
|
||||
class: "bg-blue-100 hover:bg-blue-200 text-blue-700 font-medium py-1 px-3 rounded inline-block" %>
|
||||
<%= button_to 'Delete',
|
||||
state_ip_address_role_path(ip_role),
|
||||
method: :delete,
|
||||
class: "text-red-600 hover:text-red-900 inline",
|
||||
class: "bg-rose-100 hover:bg-rose-200 text-rose-700 font-medium py-1 px-3 rounded inline-block",
|
||||
form: {
|
||||
class: "inline",
|
||||
data: {
|
||||
|
||||
@@ -60,7 +60,9 @@ Rails.application.routes.draw do
|
||||
authenticate :user, ->(user) { user.admin? } do
|
||||
# IP address roles management
|
||||
namespace :state do
|
||||
resources :ip_address_roles, except: [:show]
|
||||
resources :ip_address_roles, except: [:show] do
|
||||
patch :toggle, on: :member
|
||||
end
|
||||
end
|
||||
|
||||
resources :global_states, path: "state" do
|
||||
|
||||
@@ -3,7 +3,7 @@ require "rails_helper"
|
||||
|
||||
RSpec.describe State::IpAddressRolesController, type: :controller do
|
||||
let(:user) { create(:user, :admin) }
|
||||
let(:ip_address_role) { create(:ip_address_role) }
|
||||
let(:ip_address_role) { create(:ip_address_role, active: true) }
|
||||
|
||||
before { sign_in user }
|
||||
|
||||
@@ -41,7 +41,7 @@ RSpec.describe State::IpAddressRolesController, type: :controller do
|
||||
let(:valid_attributes) do
|
||||
{
|
||||
ip_address: "192.168.1.0/24",
|
||||
role: "admin",
|
||||
role: "user",
|
||||
description: "Test role",
|
||||
active: true,
|
||||
}
|
||||
@@ -60,7 +60,7 @@ RSpec.describe State::IpAddressRolesController, type: :controller do
|
||||
end
|
||||
|
||||
context "with invalid params" do
|
||||
let(:invalid_attributes) { { ip_address: "", role: "admin" } }
|
||||
let(:invalid_attributes) { { ip_address: "", role: "user" } }
|
||||
|
||||
it "returns a success response (i.e. to display the 'new' template)" do
|
||||
post :create, params: { ip_address_role: invalid_attributes }
|
||||
@@ -245,4 +245,47 @@ RSpec.describe State::IpAddressRolesController, type: :controller do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "PATCH #toggle" do
|
||||
context "when user is authorized" do
|
||||
before { sign_in user }
|
||||
|
||||
it "toggles the active state" do
|
||||
expect { patch :toggle, params: { id: ip_address_role.id } }.to change {
|
||||
ip_address_role.reload.active
|
||||
}.from(true).to(false)
|
||||
|
||||
expect(response).to redirect_to(state_ip_address_roles_path)
|
||||
expect(flash[:notice]).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "when user is not authorized" do
|
||||
let(:regular_user) { create(:user, :user) }
|
||||
before { sign_in regular_user }
|
||||
|
||||
it "prevents toggling the active state" do
|
||||
patch :toggle, params: { id: ip_address_role.id }
|
||||
expect(response).to redirect_to(root_path)
|
||||
expect(flash[:alert]).to eq(
|
||||
"You are not authorized to perform this action.",
|
||||
)
|
||||
end
|
||||
|
||||
it "does not update the active state" do
|
||||
expect {
|
||||
patch :toggle, params: { id: ip_address_role.id }
|
||||
}.not_to change { ip_address_role.reload.active }
|
||||
end
|
||||
end
|
||||
|
||||
context "when user is not authenticated" do
|
||||
before { sign_out :user }
|
||||
|
||||
it "redirects to login" do
|
||||
patch :toggle, params: { id: ip_address_role.id }
|
||||
expect(response).to redirect_to(new_user_session_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,7 +14,7 @@ RSpec.describe IpAddressRole, type: :model do
|
||||
)
|
||||
|
||||
# Now test if creating another with the same IP fails
|
||||
new_role = IpAddressRole.new(ip_address: "192.168.1.1", role: "admin")
|
||||
new_role = IpAddressRole.new(ip_address: "192.168.1.1", role: "user")
|
||||
expect(new_role).not_to be_valid
|
||||
expect(new_role.errors[:ip_address]).to include("has already been taken")
|
||||
end
|
||||
@@ -25,7 +25,7 @@ RSpec.describe IpAddressRole, type: :model do
|
||||
@existing_role =
|
||||
IpAddressRole.create!(
|
||||
ip_address: "192.168.0.0/16", # This covers 192.168.0.0 to 192.168.255.255
|
||||
role: "moderator",
|
||||
role: "user",
|
||||
active: true,
|
||||
)
|
||||
end
|
||||
@@ -35,12 +35,10 @@ RSpec.describe IpAddressRole, type: :model do
|
||||
new_role =
|
||||
IpAddressRole.new(
|
||||
ip_address: "192.168.1.0/24",
|
||||
role: "admin",
|
||||
role: "user",
|
||||
active: true,
|
||||
)
|
||||
|
||||
# If we have a validation for overlapping ranges, this should fail
|
||||
# Note: This test might need to be updated if this validation doesn't exist yet
|
||||
expect(new_role).not_to be_valid
|
||||
expect(new_role.errors[:ip_address]).to include(
|
||||
"overlaps with an existing IP range",
|
||||
@@ -56,8 +54,6 @@ RSpec.describe IpAddressRole, type: :model do
|
||||
active: true,
|
||||
)
|
||||
|
||||
# If we have a validation for overlapping IPs, this should fail
|
||||
# Note: This test might need to be updated if this validation doesn't exist yet
|
||||
expect(new_role).not_to be_valid
|
||||
expect(new_role.errors[:ip_address]).to include(
|
||||
"overlaps with an existing IP range",
|
||||
@@ -69,7 +65,7 @@ RSpec.describe IpAddressRole, type: :model do
|
||||
new_role =
|
||||
IpAddressRole.new(
|
||||
ip_address: "10.0.0.0/8",
|
||||
role: "admin",
|
||||
role: "user",
|
||||
active: true,
|
||||
)
|
||||
|
||||
@@ -81,9 +77,9 @@ RSpec.describe IpAddressRole, type: :model do
|
||||
it { is_expected.to validate_presence_of(:role) }
|
||||
end
|
||||
|
||||
describe "role enum" do
|
||||
it "defines expected roles" do
|
||||
expect(IpAddressRole.roles.keys).to match_array(%w[user admin moderator])
|
||||
describe "role" do
|
||||
it "only allows user role" do
|
||||
expect(IpAddressRole.roles.keys).to match_array(%w[user])
|
||||
end
|
||||
|
||||
it "defaults to user role" do
|
||||
|
||||
Reference in New Issue
Block a user