diff --git a/app/controllers/admin/education/school/role/people_controller.rb b/app/controllers/admin/education/school/role/people_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..d1929ee372dcd7a4edfcf5fac4ed3b470479cb7c --- /dev/null +++ b/app/controllers/admin/education/school/role/people_controller.rb @@ -0,0 +1,56 @@ +class Admin::Education::School::Role::PeopleController < Admin::Education::School::ApplicationController + load_and_authorize_resource :role, class: University::Role, through: :school, param: :role_id, through_association: :university_roles + load_and_authorize_resource :involvement, class: University::Person::Involvement, through: :role, parent: false + + def new + breadcrumb + end + + def edit + breadcrumb + add_breadcrumb t('edit') + end + + def create + if @involvement.save + redirect_to admin_education_school_role_path(@role, { school_id: @school.id }), notice: t('admin.successfully_created_html', model: @involvement.to_s) + else + breadcrumb + render :new, status: :unprocessable_entity + end + end + + def update + if @involvement.update(involvement_params) + redirect_to admin_education_school_role_path(@role, { school_id: @school.id }), notice: t('admin.successfully_updated_html', model: @involvement.to_s) + else + breadcrumb + render :edit, status: :unprocessable_entity + add_breadcrumb t('edit') + end + end + + def destroy + @involvement.destroy + redirect_to admin_education_school_role_path(@role, { school_id: @school.id }), notice: t('admin.successfully_destroyed_html', model: @involvement.to_s) + end + + protected + + def breadcrumb + super + add_breadcrumb University::Role.model_name.human(count: 2), admin_education_school_roles_path(@school) + @role.persisted? ? add_breadcrumb(@role, admin_education_school_role_path(@role, { school_id: @school.id })) + : add_breadcrumb(t('create')) + if @involvement + @involvement.persisted? ? add_breadcrumb(@involvement, admin_education_school_role_person_path(@involvement, { school_id: @school.id, role_id: @role.id })) + : add_breadcrumb(t('create')) + end + end + + def involvement_params + params.require(:university_person_involvement) + .permit(:description, :position, :person_id) + .merge(university_id: @school.university_id) + end +end diff --git a/app/controllers/admin/education/school/roles_controller.rb b/app/controllers/admin/education/school/roles_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..f795f26cc454e78a325ecb2ad2f2fbd36a58dedf --- /dev/null +++ b/app/controllers/admin/education/school/roles_controller.rb @@ -0,0 +1,62 @@ +class Admin::Education::School::RolesController < Admin::Education::School::ApplicationController + load_and_authorize_resource class: University::Role, through: :school, through_association: :university_roles + + def index + breadcrumb + end + + def show + @involvements = @role.involvements.ordered + breadcrumb + end + + def new + breadcrumb + end + + def edit + breadcrumb + add_breadcrumb t('edit') + end + + def create + if @role.save + redirect_to admin_education_school_role_path(@role), notice: t('admin.successfully_created_html', model: @role.to_s) + else + breadcrumb + render :new, status: :unprocessable_entity + end + end + + def update + if @role.update(role_params) + redirect_to admin_education_school_role_path(@role), notice: t('admin.successfully_updated_html', model: @role.to_s) + else + breadcrumb + render :edit, status: :unprocessable_entity + add_breadcrumb t('edit') + end + end + + def destroy + @role.destroy + redirect_to admin_education_school_role_path(@role), notice: t('admin.successfully_destroyed_html', model: @role.to_s) + end + + protected + + def breadcrumb + super + add_breadcrumb University::Role.model_name.human(count: 2), admin_education_school_roles_path(@school) + if @role + @role.persisted? ? add_breadcrumb(@role, admin_education_school_role_path(@role, { school_id: @school.id })) + : add_breadcrumb(t('create')) + end + end + + def role_params + params.require(:university_role) + .permit(:description, :position) + .merge(target: @school, university_id: @school.university_id) + end +end diff --git a/app/controllers/admin/education/schools_controller.rb b/app/controllers/admin/education/schools_controller.rb index e1368257c8d1520570065c6c0a9817a75a720f91..7152bbd2748ae5a6622823a90566cf1fea61c082 100644 --- a/app/controllers/admin/education/schools_controller.rb +++ b/app/controllers/admin/education/schools_controller.rb @@ -8,6 +8,7 @@ class Admin::Education::SchoolsController < Admin::Education::ApplicationControl end def show + @roles = @school.university_roles.ordered breadcrumb end diff --git a/app/models/ability.rb b/app/models/ability.rb index 905dd2f6a0db3038439066dcc1c2fec1f76f2273..a193260c541486260a98a86d914a28d86f99d151 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -36,6 +36,8 @@ class Ability can :manage, Education::Program::Teacher, person_id: @user.person&.id can :read, Education::Program::Role, university_id: @user.university_id can :manage, Education::Program::Role::Person, person_id: @user.person&.id + can :read, University::Role, university_id: @user.university_id + can :manage, University::Person::Involvement, person_id: @user.person&.id end def program_manager @@ -66,6 +68,8 @@ class Ability can :manage, Research::Journal::Article, university_id: @user.university_id can :manage, Research::Journal::Volume, university_id: @user.university_id can :manage, Research::Laboratory, university_id: @user.university_id + can :manage, University::Role, university_id: @user.university_id + can :manage, University::Person::Involvement, university_id: @user.university_id can :read, User, university_id: @user.university_id can :manage, User, university_id: @user.university_id, role: @user.managed_roles end diff --git a/app/models/education/school.rb b/app/models/education/school.rb index 6f79e2f3beb978ade47e0fe8d554ec8fcb5824c6..c62ab123bddf850dd8e24b5e55e2ca4a39f767fb 100644 --- a/app/models/education/school.rb +++ b/app/models/education/school.rb @@ -32,6 +32,10 @@ class Education::School < ApplicationRecord has_many :university_people_through_administrators, through: :administrators, source: :person + has_many :university_roles, class_name: 'University::Role', as: :target, dependent: :destroy + has_many :university_people_through_roles, + through: :university_roles, + source: :person has_and_belongs_to_many :programs, class_name: 'Education::Program', join_table: 'education_programs_schools', diff --git a/app/models/university/person/involvement.rb b/app/models/university/person/involvement.rb index 83c1b444a5dc914519773f8f35a3c593cf96ea18..d555cccbc012d2f623fa4e27be461cfd32c7dd47 100644 --- a/app/models/university/person/involvement.rb +++ b/app/models/university/person/involvement.rb @@ -27,15 +27,25 @@ class University::Person::Involvement < ApplicationRecord include WithPosition + enum kind: { administrator: 10, researcher: 20, teacher: 30 } + belongs_to :university belongs_to :person belongs_to :target, polymorphic: true - enum kind: { administrator: 10, researcher: 20, teacher: 30 } + after_commit :sync_target + + def to_s + "#{person}" + end protected def last_ordered_element self.class.unscoped.where(university_id: university_id, target: target).ordered.last end + + def sync_target + target.sync_with_git + end end diff --git a/app/models/university/role.rb b/app/models/university/role.rb index d63eb7041925492af796c72c6b8585b4f7140ce6..2e4987077a6a12d1636514fb28a83ea95a7fdd3b 100644 --- a/app/models/university/role.rb +++ b/app/models/university/role.rb @@ -25,6 +25,15 @@ class University::Role < ApplicationRecord belongs_to :university belongs_to :target, polymorphic: true, optional: true + has_many :involvements, class_name: 'University::Person::Involvement', as: :target + + def to_s + "#{description}" + end + + def sync_with_git + target.sync_with_git + end protected diff --git a/app/views/admin/education/school/role/people/_form.html.erb b/app/views/admin/education/school/role/people/_form.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..81fb739c7ed7bc375864537be8b2f930b576a61a --- /dev/null +++ b/app/views/admin/education/school/role/people/_form.html.erb @@ -0,0 +1,23 @@ +<%= simple_form_for [:admin, involvement], + url: involvement.new_record? ? admin_education_school_role_people_path(@role, { school_id: @school.id }) + : admin_education_school_role_person_path(involvement, { school_id: @school.id, role_id: @role.id }) do |f| %> + <div class="card flex-fill w-100"> + <div class="card-header"> + <h5 class="card-title mb-0"><%= t('admin.infos') %></h5> + </div> + <div class="card-body"> + <div class="row"> + <div class="col-md-6"> + <% used_person_ids = @role.involvements.where.not(id: involvement.id).pluck(:person_id) %> + <%= f.association :person, collection: current_university.people.administration.where.not(id: used_person_ids).ordered %> + </div> + <div class="col-md-6"> + <%= f.input :description %> + </div> + </div> + </div> + </div> + <% content_for :action_bar_right do %> + <%= submit f %> + <% end %> +<% end %> diff --git a/app/views/admin/education/school/role/people/_list.html.erb b/app/views/admin/education/school/role/people/_list.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..5f10eb42cbab4105f2846d69ae881574bedaba5a --- /dev/null +++ b/app/views/admin/education/school/role/people/_list.html.erb @@ -0,0 +1,33 @@ +<% if involvements.any? %> + <table class="table table-sortable"> + <thead> + <tr> + <th class="ps-0"><%= University::Person.model_name.human %></th> + <th><%= University::Person::Involvement.human_attribute_name("description") %></th> + <th></th> + </tr> + </thead> + <tbody data-reorder-url="<%= reorder_admin_education_school_role_people_path(@role, { school_id: @school.id }) %>"> + <% involvements.each do |involvement| %> + <tr class="handle" data-id="<%= involvement.id %>"> + <td class="ps-0"> + <%= involvement %> + </td> + <td><%= involvement.description %></td> + <td class="text-end pe-0"> + <div class="btn-group" role="group"> + <%= link_to t('edit'), + edit_admin_education_school_role_person_path(involvement, { school_id: @school.id, role_id: @role.id }), + class: button_classes if can?(:edit, involvement) %> + <%= link_to t('delete'), + admin_education_school_role_person_path(involvement, { school_id: @school.id, role_id: @role.id }), + method: :delete, + data: { confirm: t('please_confirm') }, + class: button_classes_danger if can?(:destroy, involvement) %> + </div> + </td> + </tr> + <% end %> + </tbody> + </table> +<% end %> diff --git a/app/views/admin/education/school/role/people/edit.html.erb b/app/views/admin/education/school/role/people/edit.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..da924cd052e14cfa55c1f75b9fe56ee8d15a1b8a --- /dev/null +++ b/app/views/admin/education/school/role/people/edit.html.erb @@ -0,0 +1,3 @@ +<% content_for :title, @involvement %> + +<%= render 'form', involvement: @involvement %> diff --git a/app/views/admin/education/school/role/people/new.html.erb b/app/views/admin/education/school/role/people/new.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..f07ff39c18ffb7d9e598688bb41a9361413d804f --- /dev/null +++ b/app/views/admin/education/school/role/people/new.html.erb @@ -0,0 +1,3 @@ +<% content_for :title, University::Person.model_name.human %> + +<%= render 'form', involvement: @involvement %> diff --git a/app/views/admin/education/school/roles/_form.html.erb b/app/views/admin/education/school/roles/_form.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..f09aa1ee30ec84c1949af714a645c5764944507e --- /dev/null +++ b/app/views/admin/education/school/roles/_form.html.erb @@ -0,0 +1,17 @@ +<%= simple_form_for [:admin, role], + url: role.new_record? ? admin_education_school_roles_path(@school) + : admin_education_school_role_path(role, { school_id: @school.id }) do |f| %> + <div class="card flex-fill w-100"> + <div class="card-header"> + <h5 class="card-title mb-0"><%= t('admin.infos') %></h5> + </div> + <div class="card-body"> + <div class="row"> + <%= f.input :description %> + </div> + </div> + </div> + <% content_for :action_bar_right do %> + <%= submit f %> + <% end %> +<% end %> diff --git a/app/views/admin/education/school/roles/_list.html.erb b/app/views/admin/education/school/roles/_list.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..084f107a7b852baeb73d305aa13de692e8eb4f04 --- /dev/null +++ b/app/views/admin/education/school/roles/_list.html.erb @@ -0,0 +1,35 @@ +<% if roles.any? %> + <table class="table table-sortable"> + <thead> + <tr> + <th class="ps-0"><%= University::Role.model_name.human %></th> + <th><%= University::Role.human_attribute_name('people') %></th> + <th></th> + </tr> + </thead> + <tbody data-reorder-url="<%= reorder_admin_education_school_roles_path(school_id: @school.id) %>"> + <% roles.each do |role| %> + <tr class="handle" data-id="<%= role.id %>"> + <td class="ps-0"> + <%= link_to_if can?(:read, role), + role, + admin_education_school_role_path(role, { school_id: @school.id }) %> + </td> + <td><%= role.involvements.includes(:person).ordered.map { |involvement| involvement.person.to_s }.to_sentence %></td> + <td class="text-end pe-0"> + <div class="btn-group" role="group"> + <%= link_to t('edit'), + edit_admin_education_school_role_path(role, { school_id: @school.id }), + class: button_classes if can?(:edit, role) %> + <%= link_to t('delete'), + admin_education_school_role_path(role, { school_id: @school.id }), + method: :delete, + data: { confirm: t('please_confirm') }, + class: button_classes_danger if can?(:destroy, role) %> + </div> + </td> + </tr> + <% end %> + </tbody> + </table> +<% end %> diff --git a/app/views/admin/education/school/roles/edit.html.erb b/app/views/admin/education/school/roles/edit.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..ff1ec73bd6f1465a96497606080d481b6fd6ca51 --- /dev/null +++ b/app/views/admin/education/school/roles/edit.html.erb @@ -0,0 +1,3 @@ +<% content_for :title, @role %> + +<%= render 'form', role: @role %> diff --git a/app/views/admin/education/school/roles/index.html.erb b/app/views/admin/education/school/roles/index.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..d8dda13f8f93992acd13d167d6f47bc7f15b2b94 --- /dev/null +++ b/app/views/admin/education/school/roles/index.html.erb @@ -0,0 +1,3 @@ +<% content_for :title, University::Role.model_name.human(count: 2) %> +<%= link_to t('create'), new_admin_education_school_role_path(school_id: @school.id), class: button_classes %> +<%= render 'admin/education/school/roles/list', roles: @roles %> diff --git a/app/views/admin/education/school/roles/new.html.erb b/app/views/admin/education/school/roles/new.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..1e11d9157b4247984613930c39a66a5f5287ec23 --- /dev/null +++ b/app/views/admin/education/school/roles/new.html.erb @@ -0,0 +1,3 @@ +<% content_for :title, University::Role.model_name.human %> + +<%= render 'form', role: @role %> diff --git a/app/views/admin/education/school/roles/show.html.erb b/app/views/admin/education/school/roles/show.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..f4c18babfa4490bf24910f2b1bae4923db9ca539 --- /dev/null +++ b/app/views/admin/education/school/roles/show.html.erb @@ -0,0 +1,4 @@ +<% content_for :title, @role %> + +<%= link_to t('create'), new_admin_education_school_role_person_path(school_id: @school.id, role_id: @role.id), class: button_classes %> +<%= render 'admin/education/school/role/people/list', involvements: @involvements %> diff --git a/app/views/admin/education/schools/show.html.erb b/app/views/admin/education/schools/show.html.erb index 5367e4558ab1221f8c894ae179fcc1a437f85a94..bb527954dd006e6011623b753ae77b0737abe5cb 100644 --- a/app/views/admin/education/schools/show.html.erb +++ b/app/views/admin/education/schools/show.html.erb @@ -58,11 +58,36 @@ <div class="card flex-fill w-100"> <div class="card-header"> - <h2 class="card-title mb-0 h5"><%= Education::School.human_attribute_name('administrators') %></h2> + <div class="float-end"> + <%= link_to "Gérer les rôles", + admin_education_school_roles_path(school_id: @school.id), + class: button_classes if can?(:update, University::Role) %> + </div> + <h2 class="card-title mb-0 h5">Rôles</h2> </div> <div class="card-body"> - <%= render 'admin/education/school/administrators/list', administrators: @school.administrators.includes(:person).ordered %> - <%= link_to t('create'), new_admin_education_school_administrator_path(school_id: @school.id), class: button_classes %> + <% if @roles.any? %> + <table class="table"> + <thead> + <tr> + <th class="ps-0"><%= University::Role.model_name.human %></th> + <th><%= University::Role.human_attribute_name('people') %></th> + </tr> + </thead> + <tbody> + <% @roles.each do |role| %> + <tr> + <td class="ps-0"> + <%= link_to_if can?(:read, role), + role, + admin_education_school_role_path(role, { school_id: @school.id }) %> + </td> + <td><%= role.involvements.includes(:person).ordered.map { |involvement| involvement.person.to_s }.to_sentence %></td> + </tr> + <% end %> + </tbody> + </table> + <% end %> </div> </div> diff --git a/config/locales/university/en.yml b/config/locales/university/en.yml index 8d690dbb687aa5dd1691327ed3ba5c9e9de97061..6d8df213d4338944fbe5161cd3b46ed5c0f5945b 100644 --- a/config/locales/university/en.yml +++ b/config/locales/university/en.yml @@ -42,6 +42,12 @@ en: university/person: one: Person other: People + university/person/involvement: + one: Involvement + other: Involvements + university/role: + one: Role + other: Roles simple_form: hints: university: diff --git a/config/locales/university/fr.yml b/config/locales/university/fr.yml index d40b74e837c1e021fdc7e0d26fce0c6da9046248..a47bf3c9b2fb881b33ce7f26f90d6118d379cd50 100644 --- a/config/locales/university/fr.yml +++ b/config/locales/university/fr.yml @@ -42,6 +42,12 @@ fr: university/person: one: Personne other: Personnes + university/person/involvement: + one: Involvement + other: Involvements + university/role: + one: Rôle + other: Rôles simple_form: hints: university: diff --git a/config/routes/admin/education.rb b/config/routes/admin/education.rb index c3ac5899ec1bdaae385534f3d240cf8716955689..125c44a9e158ce0a19657879bc68b3146097921b 100644 --- a/config/routes/admin/education.rb +++ b/config/routes/admin/education.rb @@ -1,6 +1,16 @@ namespace :education do resources :teachers, only: [:index, :show] resources :schools do + resources :roles, controller: 'school/roles' do + resources :people, controller: 'school/role/people', except: [:index, :show] do + collection do + post :reorder + end + end + collection do + post :reorder + end + end resources :administrators, controller: 'school/administrators', except: [:index, :show] end resources :programs do diff --git a/lib/tasks/app.rake b/lib/tasks/app.rake index 0e862f5d679e6e5f6ed78b930a645e03915d1316..4899fc6617b6d82b6d9d51fe5bc970b0181ec9dd 100644 --- a/lib/tasks/app.rake +++ b/lib/tasks/app.rake @@ -53,7 +53,7 @@ namespace :app do Education::Program::Role.find_each { |program_role| university_role = University::Role.where( - description: program_role.description, + description: program_role.title, target: program_role.program, position: program_role.position, university_id: program_role.university_id