From 018004ce0eae0eae8988e1647c5f3da07e96529e Mon Sep 17 00:00:00 2001 From: Yanick Minder <79108296+kcinay055679@users.noreply.github.com> Date: Fri, 7 Jun 2024 13:57:45 +0200 Subject: [PATCH] Feature/553 admin panel (#721) * Squash branch * Secure admin route * Remove unnecessary comment --------- Co-authored-by: Robin Steiner --- app/controllers/admin/companies_controller.rb | 5 +++++ app/controllers/admin/departments_controller.rb | 5 +++++ app/controllers/admin/roles_controller.rb | 5 +++++ app/controllers/admin_controller.rb | 7 +++++++ app/controllers/application_controller.rb | 16 ++++++++++++---- app/controllers/skills_controller.rb | 2 +- app/helpers/auth_helper.rb | 4 ++++ app/models/auth_user.rb | 7 ++++--- app/models/company.rb | 4 ++++ app/models/department.rb | 4 ++++ app/models/role.rb | 7 ++++++- app/views/admin/companies/index.html.haml | 3 +++ app/views/admin/departments/index.html.haml | 3 +++ app/views/admin/index.html.haml | 3 +++ app/views/admin/roles/index.html.haml | 3 +++ app/views/layouts/application.html.haml | 7 +++++++ config/auth.yml | 1 + config/initializers/active_record.rb | 3 ++- config/locales/de.yml | 12 ++++++++++++ config/locales/en.yml | 12 ++++++++++++ config/routes.rb | 7 +++++++ ...0240603085509_add_conf_admin_to_auth_users.rb | 5 +++++ db/schema.rb | 3 ++- db/seeds/development/01_auth_users.rb | 7 +++++-- db/seeds/support/auth_user_seeder.rb | 3 ++- lib/auth_config.rb | 4 ++++ 26 files changed, 128 insertions(+), 14 deletions(-) create mode 100644 app/controllers/admin/companies_controller.rb create mode 100644 app/controllers/admin/departments_controller.rb create mode 100644 app/controllers/admin/roles_controller.rb create mode 100644 app/controllers/admin_controller.rb create mode 100644 app/views/admin/companies/index.html.haml create mode 100644 app/views/admin/departments/index.html.haml create mode 100644 app/views/admin/index.html.haml create mode 100644 app/views/admin/roles/index.html.haml create mode 100644 db/migrate/20240603085509_add_conf_admin_to_auth_users.rb diff --git a/app/controllers/admin/companies_controller.rb b/app/controllers/admin/companies_controller.rb new file mode 100644 index 000000000..f97e29bd2 --- /dev/null +++ b/app/controllers/admin/companies_controller.rb @@ -0,0 +1,5 @@ +class Admin::CompaniesController < CrudController + self.nesting = :admin + self.permitted_attrs = %i[name] + before_action :render_unauthorized_not_conf_admin +end diff --git a/app/controllers/admin/departments_controller.rb b/app/controllers/admin/departments_controller.rb new file mode 100644 index 000000000..21e05ae28 --- /dev/null +++ b/app/controllers/admin/departments_controller.rb @@ -0,0 +1,5 @@ +class Admin::DepartmentsController < CrudController + self.nesting = :admin + self.permitted_attrs = %i[name] + before_action :render_unauthorized_not_conf_admin +end diff --git a/app/controllers/admin/roles_controller.rb b/app/controllers/admin/roles_controller.rb new file mode 100644 index 000000000..9b2a09ded --- /dev/null +++ b/app/controllers/admin/roles_controller.rb @@ -0,0 +1,5 @@ +class Admin::RolesController < CrudController + self.nesting = :admin + self.permitted_attrs = %i[name] + before_action :render_unauthorized_not_conf_admin +end diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb new file mode 100644 index 000000000..c65507fa1 --- /dev/null +++ b/app/controllers/admin_controller.rb @@ -0,0 +1,7 @@ +class AdminController < CrudController + before_action :render_unauthorized_not_conf_admin + + def model_class + AuthUser + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9fa587dc7..190a52559 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -4,12 +4,11 @@ class ApplicationController < ActionController::Base before_action :authenticate_auth_user! before_action :set_first_path! - helper_method :find_profile_by_keycloak_user def authenticate_auth_user! return super if helpers.devise? - admin = AuthUser.find_by(email: 'admin@skills.ch') + admin = AuthUser.find_by(email: 'conf_admin@skills.ch') raise 'User not found. This is highly likely due to a non-seeded database.' unless admin request.env['warden'].set_user(admin, :scope => :auth_user) @@ -19,9 +18,18 @@ def set_first_path! @first_path = Pathname(request.path).each_filename.to_a.map { |e| "/#{e}" }.first end - def render_unauthorized - return false if helpers.admin? + def render_unauthorized_not_admin + render_unauthorized(helpers.admin?) + end + + def render_unauthorized_not_conf_admin + render_unauthorized(helpers.conf_admin?) + end + + def render_unauthorized(unauthorized) + return false if unauthorized + redirect_to root_path if request.referer.nil? render_error('unauthorized', 'unauthorized', :unauthorized) end diff --git a/app/controllers/skills_controller.rb b/app/controllers/skills_controller.rb index 6ec3f23f2..66459ee14 100644 --- a/app/controllers/skills_controller.rb +++ b/app/controllers/skills_controller.rb @@ -3,7 +3,7 @@ class SkillsController < CrudController include ExportController before_action :update_category_parent, only: [:update] - before_action :render_unauthorized, except: %i[index show unrated_by_person] + before_action :render_unauthorized_not_admin, except: %i[index show unrated_by_person] helper_method :filter_by_rated, :compare_default_set diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb index 0cd2a1a9c..2d98e159f 100644 --- a/app/helpers/auth_helper.rb +++ b/app/helpers/auth_helper.rb @@ -9,6 +9,10 @@ def admin? current_auth_user&.is_admin end + def conf_admin? + current_auth_user&.is_conf_admin || false + end + def find_person_by_auth_user Person.find_by(name: current_auth_user&.name) end diff --git a/app/models/auth_user.rb b/app/models/auth_user.rb index 4d115b5ab..47b94b4c3 100644 --- a/app/models/auth_user.rb +++ b/app/models/auth_user.rb @@ -17,13 +17,14 @@ def from_omniauth(auth) private def set_admin(person, auth) - person.is_admin = admin?(auth) + person.is_admin = role?(auth, AuthConfig.admin_role) + person.is_conf_admin = role?(auth, AuthConfig.conf_admin_role) person.save person end - def admin?(auth) - client_roles(auth).include? AuthConfig.admin_role + def role?(auth, role) + client_roles(auth).include? role end def client_roles(auth) diff --git a/app/models/company.rb b/app/models/company.rb index 9296884b4..e1c3757f4 100644 --- a/app/models/company.rb +++ b/app/models/company.rb @@ -17,4 +17,8 @@ class Company < ApplicationRecord validates :name, length: { maximum: 100 } scope :list, -> { order('name asc') } + + def to_s + name + end end diff --git a/app/models/department.rb b/app/models/department.rb index 9b8e3db58..7582ddf62 100644 --- a/app/models/department.rb +++ b/app/models/department.rb @@ -5,4 +5,8 @@ class Department < ApplicationRecord validates :name, presence: true, length: { maximum: 100 } scope :list, -> { order('name asc') } + + def to_s + name + end end diff --git a/app/models/role.rb b/app/models/role.rb index 5b32b0faa..5f5f3af73 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -11,8 +11,13 @@ # class Role < ApplicationRecord - has_and_belongs_to_many :people, dependent: :restrict + has_and_belongs_to_many :people, dependent: :restrict_with_error, + join_table: 'person_roles' validates :name, length: { maximum: 100 } scope :list, -> { order(:name) } + + def to_s + name + end end diff --git a/app/views/admin/companies/index.html.haml b/app/views/admin/companies/index.html.haml new file mode 100644 index 000000000..706117f13 --- /dev/null +++ b/app/views/admin/companies/index.html.haml @@ -0,0 +1,3 @@ += link_to t("admin.panel.title"), admin_index_path += render 'list' += render 'actions_index' \ No newline at end of file diff --git a/app/views/admin/departments/index.html.haml b/app/views/admin/departments/index.html.haml new file mode 100644 index 000000000..706117f13 --- /dev/null +++ b/app/views/admin/departments/index.html.haml @@ -0,0 +1,3 @@ += link_to t("admin.panel.title"), admin_index_path += render 'list' += render 'actions_index' \ No newline at end of file diff --git a/app/views/admin/index.html.haml b/app/views/admin/index.html.haml new file mode 100644 index 000000000..5552cb899 --- /dev/null +++ b/app/views/admin/index.html.haml @@ -0,0 +1,3 @@ += link_to Department.model_name.human , admin_departments_path += link_to Role.model_name.human , admin_roles_path += link_to Company.model_name.human , admin_companies_path \ No newline at end of file diff --git a/app/views/admin/roles/index.html.haml b/app/views/admin/roles/index.html.haml new file mode 100644 index 000000000..706117f13 --- /dev/null +++ b/app/views/admin/roles/index.html.haml @@ -0,0 +1,3 @@ += link_to t("admin.panel.title"), admin_index_path += render 'list' += render 'actions_index' \ No newline at end of file diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 92a50e68a..d70e6108a 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -21,6 +21,7 @@ %img{:src=> "/assets/logo.svg",:height=>"32"} %text.d-flex.align-items-end.ms-2.small= "5.0.0" %ul.navbar.text-gray + -# Devise/Mockdata - if Rails.env.development? %li.d-flex.align-items-center.cursor-pointer.ps-2.pe-2.border-start.border-end.h-100 %span#username @@ -28,6 +29,10 @@ Devise - else Mockdata + -# Admin panel + - if conf_admin? + %li.d-flex.align-items-center.cursor-pointer.ps-2.pe-2.border-start.border-end.h-100 + = link_to "Admin panel", admin_index_path -# Username - if auth_user_signed_in? %li.d-flex.align-items-center.cursor-pointer.ps-2.pe-2.border-start.border-end.h-100 @@ -65,5 +70,7 @@ %div.container-fluid %div.row.d-flex.justify-content-center #flash= render partial: 'layouts/flash', collection: [:notice, :alert], as: :level + %span + = yield :actions = content_for?(:content) ? yield(:content) : yield = turbo_frame_tag "remote_modal", target: "_top" \ No newline at end of file diff --git a/config/auth.yml b/config/auth.yml index dc9300966..630783b78 100644 --- a/config/auth.yml +++ b/config/auth.yml @@ -1,4 +1,5 @@ admin_role: ADMIN +conf_admin_role: CONF_ADMIN host_url: realm: client_id: diff --git a/config/initializers/active_record.rb b/config/initializers/active_record.rb index 20c00fece..cb5586163 100644 --- a/config/initializers/active_record.rb +++ b/config/initializers/active_record.rb @@ -4,7 +4,8 @@ def destroyable? [ %i[restrict_with_error restrict_with_exception].exclude?(assoc.options[:dependent]), (assoc.macro == :has_one && send(assoc.name).nil?), - (assoc.macro == :has_many && send(assoc.name).empty?) + (assoc.macro == :has_many && send(assoc.name).empty?), + (assoc.macro == :has_and_belongs_to_many && send(assoc.name).empty?) ].any? end end diff --git a/config/locales/de.yml b/config/locales/de.yml index 90ebd0b2d..cfe68e0b4 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -33,6 +33,15 @@ de: project: Projekt skill: Skill people_skill: Skill + role: + one: Rolle + other: Rollen + company: + one: Firma + other: Firmen + department: + one: Organisationseinheit + other: Organisationseinheiten attributes: person: picture: Bild @@ -49,6 +58,9 @@ de: description: Beschreibung role: Rolle und Aufgaben technology: Eingesetzte Technologien + admin: + panel: + title: Admin Panel skills: header: all: Alle diff --git a/config/locales/en.yml b/config/locales/en.yml index 466e51b3b..908b5fad7 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -13,6 +13,18 @@ en: models: skill: Skill people_skill: Skill + role: + one: Role + other: Roles + company: + one: Company + other: Companies + department: + one: Department + other: Departments + admin: + panel: + title: Admin panel profile: personal-data: Personal data core-competences: Core competences diff --git a/config/routes.rb b/config/routes.rb index db4456527..e4a65bd60 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -31,6 +31,13 @@ resources :cv_search + resources :admin, only: :index + namespace :admin do + resources :departments + resources :roles + resources :companies + end + resources :people do resources :advanced_trainings resources :educations diff --git a/db/migrate/20240603085509_add_conf_admin_to_auth_users.rb b/db/migrate/20240603085509_add_conf_admin_to_auth_users.rb new file mode 100644 index 000000000..6f661d38e --- /dev/null +++ b/db/migrate/20240603085509_add_conf_admin_to_auth_users.rb @@ -0,0 +1,5 @@ +class AddConfAdminToAuthUsers < ActiveRecord::Migration[7.0] + def change + add_column :auth_users, :is_conf_admin, :boolean, default: false, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 6cb1c07d4..32c1c3b2a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2024_03_01_124103) do +ActiveRecord::Schema[7.0].define(version: 2024_06_03_085509) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -49,6 +49,7 @@ t.boolean "is_admin", default: false, null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.boolean "is_conf_admin", default: false, null: false t.index ["uid"], name: "index_auth_users_on_uid", unique: true end diff --git a/db/seeds/development/01_auth_users.rb b/db/seeds/development/01_auth_users.rb index 29868cdc1..a90686242 100644 --- a/db/seeds/development/01_auth_users.rb +++ b/db/seeds/development/01_auth_users.rb @@ -6,10 +6,13 @@ auth_users = [ { - first_name: 'Andreas', last_name: 'Admin', admin: true + first_name: 'Carl Albrecht', last_name: 'Conf Admin', conf_admin: true, admin: true }, { - first_name: 'Ursula', last_name: 'User', admin: false + first_name: 'Andreas', last_name: 'Admin', admin: true, conf_admin: false + }, + { + first_name: 'Ursula', last_name: 'User', admin: false, conf_admin: false } ] diff --git a/db/seeds/support/auth_user_seeder.rb b/db/seeds/support/auth_user_seeder.rb index 8d0fe88f7..3f9fa5f1e 100644 --- a/db/seeds/support/auth_user_seeder.rb +++ b/db/seeds/support/auth_user_seeder.rb @@ -12,8 +12,9 @@ def seed_auth_user(auth_user_information) AuthUser.seed_once(:email) do |user| user.uid = rand(36**20).to_s(36) user.name = auth_user_information[:first_name] + ' ' + auth_user_information[:last_name] - user.email = auth_user_information[:last_name].downcase + '@skills.ch' + user.email = auth_user_information[:last_name].parameterize.underscore. + '@skills.ch' user.is_admin = auth_user_information[:admin] + user.is_conf_admin = auth_user_information[:conf_admin] end end end diff --git a/lib/auth_config.rb b/lib/auth_config.rb index 79ec2fe14..5fb312843 100644 --- a/lib/auth_config.rb +++ b/lib/auth_config.rb @@ -29,6 +29,10 @@ def admin_role get_var_from_environment(:admin_role, required: false) end + def conf_admin_role + get_var_from_environment(:conf_admin_role, required: false) + end + def keycloak? to_boolean(get_var_from_environment(:keycloak, required: false, default: false)) end