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

110 Better manage user roles #200

Merged
merged 11 commits into from
Dec 29, 2018
11 changes: 10 additions & 1 deletion app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# frozen_string_literal: true

class UsersController < ApplicationController
include UsersHelper

before_action :authenticate_current_user, only: [:edit]
before_action :authenticate_admin, only: [:update_role]

mlichtblau marked this conversation as resolved.
Show resolved Hide resolved
def index
@users = User.all
Expand All @@ -21,10 +24,16 @@ def update
if @user.update(user_params)
redirect_to @user
else
render 'edit'
render :edit
end
end

def update_role
@user = User.find(params[:id])
@user.update(role: params[:role])
redirect_to users_path
end

private

def user_params
Expand Down
12 changes: 12 additions & 0 deletions app/helpers/users_helper.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
# frozen_string_literal: true

module UsersHelper
def last_admin?(user)
user.admin? &&
only_one_admin?
end

def only_one_admin?
User.all.select(&:admin?).size == 1
end

def current_user?(user)
user == current_user
end
end
2 changes: 1 addition & 1 deletion app/views/users/edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<td>Name</td>
<td><%= @user.name %></td>
</tr>
<% if @user == current_user %>
<% if current_user?(@user) %>
<tr>
<td><%= User.human_attribute_name('ssh_key') %></td>
<td><%= f.text_area :ssh_key, class: 'form-control', rows: '8', id: 'sshKeyField' %></td>
Expand Down
31 changes: 28 additions & 3 deletions app/views/users/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,40 @@

<table class="table">
<thead>
<th>Name</th>
<th>Email</th>
<th>Last sign in</th>
<th><%= User.human_attribute_name('name') %></th>
<th><%= User.human_attribute_name('email') %></th>
<% if current_user.admin? %>
<th><%= User.human_attribute_name('role') %></th>
<% end %>
<th><%= User.human_attribute_name('last_sign_in_at') %></th>
<th></th>
</thead>
<tbody>
<% @users.each do |user| %>
<tr>
<td><%= link_to user.name, user_path(user) %></td>
<td><%= user.email %></td>
<% if current_user.admin? %>
<td>
<div class="btn-group" role="group">
<% User.roles.map(&:first).each do |role| %>
<% if last_admin?(user) && current_user?(user) %>
<button class="btn btn-secondary disabled <%= 'active' if user.role == role %>"
id= "btn-<%= role %>-<%= user.id %>",
>
<%= role.capitalize %>
</button>
<% else %>
<%= link_to role.capitalize,
update_role_user_path(user, role: role),
method: :patch,
id: "btn-#{role}-#{user.id}",
class: "btn btn-primary #{'active' if user.role == role}"
%>
<% end %>
<% end %>
</div>
<% end %>
<td><%= user.current_sign_in_at %></td>
</tr>
<% end %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/users/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<td><%= @user.email %></td>
</tr>
<tr>
<td>Name</td>
<td><%= User.human_attribute_name('name') %></td>
<td><%= @user.name %></td>
</tr>
<% if @user == current_user %>
Expand Down
6 changes: 5 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@
}

resources :vms, :hosts
resources :users, only: %i[show index edit update]
resources :users do
member do
patch :update_role
end
end

root 'landing#index'
end
10 changes: 9 additions & 1 deletion spec/factories/users.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@
factory :user do
# https://github.com/stympy/faker/blob/master/doc/v1.9.1/internet.md#fakerinternet
email { Faker::Internet.safe_email }
password { Faker::Internet.password(min_length = 10, max_length = 20, mix_case = true, special_chars = true) }
password { Faker::Internet.password(10, 20, true, true) }
password_confirmation { password }
first_name { 'Max' }
last_name { 'Mustermann' }
ssh_key { SSHKey.generate.ssh_public_key }
end

factory :admin, parent: :user do
role { :admin }
end

factory :employee, parent: :user do
role { :employee }
end
mlichtblau marked this conversation as resolved.
Show resolved Hide resolved
end
214 changes: 214 additions & 0 deletions spec/features/users/index.html.erb_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe 'users/index.html.erb', type: :feature do
let(:user) { FactoryBot.create :user }
let(:admin) { FactoryBot.create :admin }
let(:employee) { FactoryBot.create :employee }

context 'when the current_user is an admin' do
before do
user
employee
sign_in admin
visit users_path
end

context 'looking at a normal user' do
before do
@button_user = page.find(id: "btn-user-#{user.id}")
@button_employee = page.find(id: "btn-employee-#{user.id}")
@button_admin = page.find(id: "btn-admin-#{user.id}")
end

it 'shows that the role is user' do
expect(@button_user[:class]).to include 'active'
expect(@button_employee[:class]).not_to include 'active'
expect(@button_admin[:class]).not_to include 'active'
end

context 'clicking the employee button' do
before do
@button_employee.click
user.reload
@button_employee = page.find(id: "btn-employee-#{user.id}")
end

it 'updates the users role to employee' do
expect(user.role).to eq 'employee'
end

it 'shows that users role is now employee' do
expect(@button_employee[:class]).to include 'active'
end
end

context 'clicking the admin button' do
before do
@button_admin.click
user.reload
@button_admin = page.find(id: "btn-admin-#{user.id}")
end

it 'updates the users role to admin' do
expect(user.role).to eq 'admin'
end

it 'shows that users role is now admin' do
expect(@button_admin[:class]).to include 'active'
end
end
end

context 'looking at an employee' do
before do
@button_user = page.find(id: "btn-user-#{employee.id}")
@button_employee = page.find(id: "btn-employee-#{employee.id}")
@button_admin = page.find(id: "btn-admin-#{employee.id}")
end

it 'shows that the role is employee' do
expect(@button_user[:class]).not_to include 'active'
expect(@button_employee[:class]).to include 'active'
expect(@button_admin[:class]).not_to include 'active'
end

context 'clicking the user button' do
before do
@button_user.click
employee.reload
@button_user = page.find(id: "btn-user-#{employee.id}")
end

it 'updates the employees role to user' do
expect(employee.role).to eq 'user'
end

it 'shows that employees role is now role' do
expect(@button_user[:class]).to include 'active'
end
end

context 'clicking the admin button' do
before do
@button_admin.click
employee.reload
@button_admin = page.find(id: "btn-admin-#{employee.id}")
end

it 'updates the users role to admin' do
expect(employee.role).to eq 'admin'
end

it 'shows that users role is now admin' do
expect(@button_admin[:class]).to include 'active'
end
end
end

context 'looking at an admin' do
before do
@button_user = page.find(id: "btn-user-#{admin.id}")
@button_employee = page.find(id: "btn-employee-#{admin.id}")
@button_admin = page.find(id: "btn-admin-#{admin.id}")
end

it 'shows that the role is admin' do
expect(@button_user[:class]).not_to include 'active'
expect(@button_employee[:class]).not_to include 'active'
expect(@button_admin[:class]).to include 'active'
end

context 'when there is only one admin' do
before do
assert User.all.select(&:admin?).size == 1
end

it 'disables all buttons' do
expect(@button_user[:class]).to include 'disabled'
expect(@button_employee[:class]).to include 'disabled'
expect(@button_admin[:class]).to include 'disabled'
end

context 'clicking the user button' do
before do
@button_user.click
admin.reload
@button_admin = page.find(id: "btn-admin-#{admin.id}")
end

it 'does not update the admins role' do
expect(admin.role).to eq 'admin'
end

it 'shows that admins role is still admin' do
expect(@button_admin[:class]).to include 'active'
end
end

context 'clicking the employee button' do
before do
@button_employee.click
admin.reload
@button_admin = page.find(id: "btn-admin-#{admin.id}")
end

it 'does not update the admins role' do
expect(admin.role).to eq 'admin'
end

it 'shows that admins role is still admin' do
expect(@button_admin[:class]).to include 'active'
end
end
end

context 'when there are multiple admins' do
before do
FactoryBot.create :admin
visit users_path
@button_user = page.find(id: "btn-user-#{admin.id}")
@button_employee = page.find(id: "btn-employee-#{admin.id}")
@button_admin = page.find(id: "btn-admin-#{admin.id}")
end

it 'disables no button' do
expect(@button_user[:class]).not_to include 'disabled'
expect(@button_employee[:class]).not_to include 'disabled'
expect(@button_admin[:class]).not_to include 'disabled'
end

context 'clicking the user button' do
before do
@button_user.click
admin.reload
end

it 'does update the admins role to user' do
expect(admin.role).to eq 'user'
end

it 'hides the role columns' do
expect(page).not_to have_content 'Role'
end
end

context 'clicking the employee button' do
before do
@button_employee.click
admin.reload
end

it 'does update the admins role to employee' do
expect(admin.role).to eq 'employee'
end

it 'hides the role columns' do
expect(page).not_to have_content 'Role'
end
end
end
end
end
end
23 changes: 22 additions & 1 deletion spec/views/users/index.html.erb_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@
require 'rails_helper'

RSpec.describe 'users/index.html.erb', type: :view do
let(:current_user) do
FactoryBot.create(:user)
end

let(:users) do
[
FactoryBot.create(:user),
FactoryBot.create(:user, email: Faker::Internet.safe_email('joe'))
FactoryBot.create(:admin, email: Faker::Internet.safe_email('joe'))
]
end

before do
allow(view).to receive(:current_user).and_return(current_user)
assign(:users, users)
render
end
Expand All @@ -24,4 +29,20 @@
expect(rendered).to include users[0].email
expect(rendered).to include users[1].email
end

context 'when the user is an admin' do
let(:current_user) do
FactoryBot.create(:admin)
end

it 'shows a role column' do
expect(rendered).to include 'Role'
end
end

context 'when the user is not an admin' do
it 'does not show a role column' do
expect(rendered).not_to include 'Role'
end
end
end
Loading