diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 5752c2c..4d9137d 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -1,71 +1,106 @@ class Admin::UsersController < Admin::BaseController + before_action :fetch_user, only: [:show, :edit, :update, :ban, :unban] + before_action :editable_users_only, only: [:edit, :update] + # GET /admin/users def index @baculized_host_names = Hash.new { |h, k| h[k] = [] } @non_baculized_host_names = Hash.new { |h, k| h[k] = [] } @unverified_host_names = Hash.new { |h, k| h[k] = [] } @users = User.all.includes(:hosts) @users = @users.admin if params[:type] == 'admin' @users = @users.vima if params[:type] == 'vima' + @users = @users.institutional if params[:type] == 'institutional' @users.each do |user| user.hosts.each do |host| if host.deployed? || host.updated? || host.dispatched? || host.for_removal? @baculized_host_names[user.id] << host.name else @non_baculized_host_names[user.id] << host.name @unverified_host_names[user.id] << host.name if !host.verified? end end end end # GET /admin/users/new def new - @user = User.new + @user = User.new(user_type: :admin) end # POST /admin/users def create @user = User.new(fetch_params) @user.user_type = :admin if @user.add_password(@user.password) flash[:success] = 'User created' redirect_to admin_users_path else flash[:error] = 'User was not created' render 'new' end end + # GET /admin/users/1 + def show + end + + # GET /admin/users/1/edit + def edit + end + + # PATCH /admin/users/1/update + def update + if @user.admin? && @user.update_attributes(fetch_params) + flash[:success] = 'User updated' + redirect_to admin_user_path(@user) + elsif @user.admin? + flash[:error] = 'User not updated' + redirect_to edit_admin_user_path(@user) + else + flash[:error] = "User is #{@user.user_type} and thus accepts no updates" + redirect_to admin_user_path(@user) + end + end + # PATCH /admin/users/1/ban def ban - @user = User.find(params[:id]) if @user.ban flash[:success] = 'User banned' else flash[:error] = 'User NOT banned' end redirect_to admin_users_path end # PATCH /admin/users/1/unban def unban - @user = User.find(params[:id]) if @user.unban flash[:success] = 'User enabled' else flash[:error] = 'User NOT enabled' end redirect_to admin_users_path end private def fetch_params params.require(:user).permit(:username, :email, :password, :retype_password) end + + def fetch_user + @user = User.find(params[:id]) + end + + def editable_users_only + return if @user.editable? + + flash[:error] = "User #{@user.username} is not editable" + redirect_to admin_users_path + end end diff --git a/app/models/user.rb b/app/models/user.rb index 7fc1c97..614d625 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,101 +1,109 @@ class User < ActiveRecord::Base attr_accessor :password, :retype_password has_many :ownerships has_many :hosts, through: :ownerships, inverse_of: :users enum user_type: { institutional: 0, vima: 1, okeanos: 2, admin: 3 } validates :user_type, presence: true validates :username, presence: true, uniqueness: { scope: :user_type } validates :email, presence: true, uniqueness: { scope: :user_type } before_create :confirm_passwords, if: :admin? # Returns an admin user with the given password # # @param username[String] username from user input # @param a_password[String] password from user input # # @return [User] the admin user or nil def self.fetch_admin_with_password(username, a_password) hashed_pass = Digest::SHA256.hexdigest(a_password + Rails.application.secrets.salt) admin = User.admin.find_by_username_and_password_hash(username, hashed_pass) admin end # Composes the user's display name from the user's username and email # # @return [String] def display_name "#{username} <#{email}>" end # Determines if the user must select hosts from a list or enter their # FQDN manually # # @return [Boolean] def needs_host_list? vima? || okeanos? end + # Determines if the user is editable or not. + # Editable users are only admin users, all others come from 3rd party authorization + # + # @return [Boolean] + def editable? + admin? + end + # Marks a user as not enabled def ban self.enabled = false save end # Marks a user as enabled def unban self.enabled = true save end # Stores a hashed password as a password_hash # # @param a_password[String] the user submitted password # # @return [Boolean] the save exit status def add_password(a_password) self.password_hash = Digest::SHA256.hexdigest(a_password + Rails.application.secrets.salt) self.save end # Fetches the user's unverified hosts # # @return [Array] of Strings containing the hosts' names def unverified_hosts hosts.unverified.pluck(:name) end # Fetches the user's hosts that are being backed up by bacula # # @return [Array] of Strings configuration the host's names def baculized_hosts hosts.in_bacula.pluck(:name) end # Fetches the user's hosts that are NOT being backed up by bacula # # @return [Array] of Strings configuration the host's names def non_baculized_hosts hosts.not_baculized.pluck(:name) end private def confirm_passwords if password.blank? self.errors.add(:password, 'Must give a password') return false end if password != retype_password self.errors.add(:password, 'Passwords mismatch') self.errors.add(:retype_password, 'Passwords mismatch') return false end true end end diff --git a/app/views/admin/users/_header.html.erb b/app/views/admin/users/_header.html.erb new file mode 100644 index 0000000..a332735 --- /dev/null +++ b/app/views/admin/users/_header.html.erb @@ -0,0 +1,5 @@ +<%= breadcrumb_with Admin: admin_path, + Users: admin_users_path, + @user.user_type.capitalize => admin_users_path(type: @user.user_type), + (@user.username || 'New') => @user.persisted? ? admin_user_path(@user):'' + %> diff --git a/app/views/admin/users/_user.html.erb b/app/views/admin/users/_user.html.erb index 20a857d..2ca9474 100644 --- a/app/views/admin/users/_user.html.erb +++ b/app/views/admin/users/_user.html.erb @@ -1,25 +1,35 @@ - #<%= user.id %> - <%= user.username %> + <%= link_to "##{user.id}", admin_user_path(user) %> + <%= link_to user.username, admin_user_path(user) %> <%= user.email %> <%= user.user_type %> <%= I18n.l(user.created_at, format: :short) %> <%= inline_list @baculized_host_names[user.id] %> <%= inline_list @unverified_host_names[user.id] %> <%= inline_list @non_baculized_host_names[user.id] %> + <%= link_to admin_user_path(user) do %> + + <% end %> + <% if user.editable? %> + <%= link_to edit_admin_user_path(user) do %> + + <% end %> + <% end %> + + <% if user.enabled? %> <%= link_to ban_admin_user_path(user), method: :patch, class: 'btn btn-default', - data: { confirm: 'User will be banned' } do %> - + data: { confirm: "User #{user.username} will be banned" } do %> + Ban <% end %> <% else %> <%= link_to unban_admin_user_path(user), method: :patch, class: 'btn btn-default', - data: { confirm: 'User will be unbanned' } do %> - + data: { confirm: "User #{user.username} will be unbanned" } do %> + Unban <% end %> <% end %> diff --git a/app/views/admin/users/new.html.erb b/app/views/admin/users/edit.html.erb similarity index 76% copy from app/views/admin/users/new.html.erb copy to app/views/admin/users/edit.html.erb index 010faa0..52f80b6 100644 --- a/app/views/admin/users/new.html.erb +++ b/app/views/admin/users/edit.html.erb @@ -1,11 +1,13 @@ +<%= render partial: 'header' %> +
-

New Admin

+

Edit Admin

<%= render partial: 'form' %>
diff --git a/app/views/admin/users/index.html.erb b/app/views/admin/users/index.html.erb index d0fa88c..1f06a17 100644 --- a/app/views/admin/users/index.html.erb +++ b/app/views/admin/users/index.html.erb @@ -1,34 +1,35 @@
<%= link_to new_admin_user_path, class: "btn btn-default", role: "button" do %> New Admin <% end %>

Users

- - - - - - - - + + + + + + + + + <%= render partial: 'user', collection: @users %>
idusernameemailuser typecreated atclientsunverified hostspending hostsactionsUsernameEmailUser typeCreated atClientsUnverified hostsPending hostsActionsBan
diff --git a/app/views/admin/users/new.html.erb b/app/views/admin/users/new.html.erb index 010faa0..5427af3 100644 --- a/app/views/admin/users/new.html.erb +++ b/app/views/admin/users/new.html.erb @@ -1,11 +1,13 @@ +<%= render partial: 'header' %> +

New Admin

<%= render partial: 'form' %>
diff --git a/app/views/admin/users/show.html.erb b/app/views/admin/users/show.html.erb new file mode 100644 index 0000000..6c637a6 --- /dev/null +++ b/app/views/admin/users/show.html.erb @@ -0,0 +1,71 @@ +<%= render partial: 'header' %> + +
+
+
+

User details

+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <% if @user.institutional? %> + + + + + <% end %> +
Username<%= @user.username %>
Email<%= @user.email %>
User Type<%= @user.user_type %>
Created At<%= I18n.l(@user.created_at, format: :short) rescue '-' %>
Login At<%= I18n.l(@user.login_at, format: :short) rescue '-' %>
Clients<%= inline_list @user.baculized_hosts %>
Pending Hosts<%= inline_list @user.non_baculized_hosts %>
Unverified Hosts<%= inline_list @user.unverified_hosts %>
+
+
+ <% if @user.editable? %> + <%= link_to edit_admin_user_path(@user), class: 'btn btn-primary' do %> + + Edit User + <% end %> + <% end %> + <% if @user.enabled? %> + <%= link_to ban_admin_user_path(@user), method: :patch, class: 'btn btn-default', + data: { confirm: "User #{@user.username} will be banned" } do %> + + Ban User + <% end %> + <% else %> + <%= link_to unban_admin_user_path(@user), method: :patch, class: 'btn btn-default', + data: { confirm: "User #{@user.username} will be unbanned" } do %> + + Unban User + <% end %> + <% end %> + + <%= link_to 'Back to users', admin_users_path, class: 'right' %> +
diff --git a/app/views/shared/_nav.html.erb b/app/views/shared/_nav.html.erb index ca41736..bfacf33 100644 --- a/app/views/shared/_nav.html.erb +++ b/app/views/shared/_nav.html.erb @@ -1,73 +1,76 @@ diff --git a/config/routes.rb b/config/routes.rb index 7da6c85..91eb988 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,82 +1,82 @@ Rails.application.routes.draw do root 'application#index' post 'grnet' => 'application#grnet' get 'institutional' => 'application#institutional' match 'vima', to: 'application#vima', :via => [:get, :post] get 'logout' => 'application#logout' resources :clients, only: [:index, :show] do member do get :jobs get :logs get :stats post :stats get :users get :restore post :run_restore end collection do post :index end end resources :hosts, only: [:new, :create, :show, :edit, :update, :destroy] do member do post :submit_config post :disable delete :revoke end resources :jobs, only: [:new, :create, :show, :edit, :update, :destroy] do member do patch :toggle_enable post :backup_now end end resources :filesets, only: [:show, :new, :create, :destroy] resources :schedules, only: [:show, :new, :edit, :create, :update, :destroy] end namespace :admin do match '/', to: 'base#index', via: [:get, :post] get '/login' => 'base#login', as: :login resources :settings, only: [:index, :new, :create, :edit, :update] do member do delete :reset end end resources :clients, only: [:index, :show] do member do get :jobs get :logs get :stats post :stats get :configuration post :disable delete :revoke end end resources :hosts, only: [:show] do collection do get :unverified end member do post :verify end end - resources :users, only: [:index, :new, :create] do + resources :users, only: [:index, :new, :create, :show, :edit, :update] do member do patch :ban patch :unban end end end end