From 76f20b0ede0896d6eb71b04b36e87391c092483b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Gaya?= <sebastien.gaya@gmail.com>
Date: Wed, 26 Jan 2022 15:52:21 +0100
Subject: [PATCH] wip school roles

---
 .../school/role/people_controller.rb          | 56 +++++++++++++++++
 .../education/school/roles_controller.rb      | 62 +++++++++++++++++++
 .../admin/education/schools_controller.rb     |  1 +
 app/models/ability.rb                         |  4 ++
 app/models/education/school.rb                |  4 ++
 app/models/university/person/involvement.rb   | 12 +++-
 app/models/university/role.rb                 |  9 +++
 .../school/role/people/_form.html.erb         | 23 +++++++
 .../school/role/people/_list.html.erb         | 33 ++++++++++
 .../school/role/people/edit.html.erb          |  3 +
 .../education/school/role/people/new.html.erb |  3 +
 .../education/school/roles/_form.html.erb     | 17 +++++
 .../education/school/roles/_list.html.erb     | 35 +++++++++++
 .../education/school/roles/edit.html.erb      |  3 +
 .../education/school/roles/index.html.erb     |  3 +
 .../admin/education/school/roles/new.html.erb |  3 +
 .../education/school/roles/show.html.erb      |  4 ++
 .../admin/education/schools/show.html.erb     | 31 +++++++++-
 config/locales/university/en.yml              |  6 ++
 config/locales/university/fr.yml              |  6 ++
 config/routes/admin/education.rb              | 10 +++
 lib/tasks/app.rake                            |  2 +-
 22 files changed, 325 insertions(+), 5 deletions(-)
 create mode 100644 app/controllers/admin/education/school/role/people_controller.rb
 create mode 100644 app/controllers/admin/education/school/roles_controller.rb
 create mode 100644 app/views/admin/education/school/role/people/_form.html.erb
 create mode 100644 app/views/admin/education/school/role/people/_list.html.erb
 create mode 100644 app/views/admin/education/school/role/people/edit.html.erb
 create mode 100644 app/views/admin/education/school/role/people/new.html.erb
 create mode 100644 app/views/admin/education/school/roles/_form.html.erb
 create mode 100644 app/views/admin/education/school/roles/_list.html.erb
 create mode 100644 app/views/admin/education/school/roles/edit.html.erb
 create mode 100644 app/views/admin/education/school/roles/index.html.erb
 create mode 100644 app/views/admin/education/school/roles/new.html.erb
 create mode 100644 app/views/admin/education/school/roles/show.html.erb

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 000000000..d1929ee37
--- /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 000000000..f795f26cc
--- /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 e1368257c..7152bbd27 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 905dd2f6a..a193260c5 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 6f79e2f3b..c62ab123b 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 83c1b444a..d555cccbc 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 d63eb7041..2e4987077 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 000000000..81fb739c7
--- /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 000000000..5f10eb42c
--- /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 000000000..da924cd05
--- /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 000000000..f07ff39c1
--- /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 000000000..f09aa1ee3
--- /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 000000000..084f107a7
--- /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 000000000..ff1ec73bd
--- /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 000000000..d8dda13f8
--- /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 000000000..1e11d9157
--- /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 000000000..f4c18babf
--- /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 5367e4558..bb527954d 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 8d690dbb6..6d8df213d 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 d40b74e83..a47bf3c9b 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 c3ac5899e..125c44a9e 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 0e862f5d6..4899fc661 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
-- 
GitLab