From 130522812d12224dadbef2b144ba8318e1c4296a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Gaya?= <sebastien.gaya@gmail.com>
Date: Fri, 7 Jan 2022 14:33:52 +0100
Subject: [PATCH] school admins

---
 .../school/administrators_controller.rb       | 50 +++++++++++++++++++
 .../school/application_controller.rb          | 20 ++++++++
 app/models/communication/website.rb           |  2 +-
 app/models/concerns/with_git.rb               |  4 +-
 app/models/education/program.rb               |  8 +--
 app/models/education/school.rb                |  1 +
 app/models/education/school/administrator.rb  | 33 ++++++++++++
 .../school/administrators/_form.html.erb      | 21 ++++++++
 .../school/administrators/_list.html.erb      | 35 +++++++++++++
 .../school/administrators/edit.html.erb       |  3 ++
 .../school/administrators/new.html.erb        |  3 ++
 .../admin/education/schools/show.html.erb     | 10 ++++
 config/locales/education/en.yml               |  7 +++
 config/locales/education/fr.yml               |  7 +++
 config/routes/admin/education.rb              |  4 +-
 ..._create_education_school_administrators.rb | 11 ++++
 db/schema.rb                                  | 14 +++++-
 .../education/school/administrators.yml       | 32 ++++++++++++
 .../education/school/administrator_test.rb    | 28 +++++++++++
 19 files changed, 284 insertions(+), 9 deletions(-)
 create mode 100644 app/controllers/admin/education/school/administrators_controller.rb
 create mode 100644 app/controllers/admin/education/school/application_controller.rb
 create mode 100644 app/models/education/school/administrator.rb
 create mode 100644 app/views/admin/education/school/administrators/_form.html.erb
 create mode 100644 app/views/admin/education/school/administrators/_list.html.erb
 create mode 100644 app/views/admin/education/school/administrators/edit.html.erb
 create mode 100644 app/views/admin/education/school/administrators/new.html.erb
 create mode 100644 db/migrate/20220107111002_create_education_school_administrators.rb
 create mode 100644 test/fixtures/education/school/administrators.yml
 create mode 100644 test/models/education/school/administrator_test.rb

diff --git a/app/controllers/admin/education/school/administrators_controller.rb b/app/controllers/admin/education/school/administrators_controller.rb
new file mode 100644
index 000000000..d7788a8b4
--- /dev/null
+++ b/app/controllers/admin/education/school/administrators_controller.rb
@@ -0,0 +1,50 @@
+class Admin::Education::School::AdministratorsController < Admin::Education::School::ApplicationController
+  load_and_authorize_resource class: Education::School::Administrator, through: :school
+
+  def new
+    breadcrumb
+  end
+
+  def edit
+    breadcrumb
+    add_breadcrumb t('edit')
+  end
+
+  def create
+    if @administrator.save
+      redirect_to admin_education_school_path(@school), notice: t('admin.successfully_created_html', model: @administrator.to_s)
+    else
+      breadcrumb
+      render :new, status: :unprocessable_entity
+    end
+  end
+
+  def update
+    if @administrator.update(administrator_params)
+      redirect_to admin_education_school_path(@school), notice: t('admin.successfully_updated_html', model: @administrator.to_s)
+    else
+      breadcrumb
+      render :edit, status: :unprocessable_entity
+      add_breadcrumb t('edit')
+    end
+  end
+
+  def destroy
+    @administrator.destroy
+    redirect_to admin_education_school_path(@school), notice: t('admin.successfully_destroyed_html', model: @administrator.to_s)
+  end
+
+  protected
+
+  def breadcrumb
+    super
+    add_breadcrumb Education::School::Administrator.model_name.human(count: 2)
+    breadcrumb_for @administrator
+  end
+
+  def administrator_params
+    params.require(:education_school_administrator)
+          .permit(:description, :person_id)
+          .merge(school_id: @school.id)
+  end
+end
diff --git a/app/controllers/admin/education/school/application_controller.rb b/app/controllers/admin/education/school/application_controller.rb
new file mode 100644
index 000000000..56a79f714
--- /dev/null
+++ b/app/controllers/admin/education/school/application_controller.rb
@@ -0,0 +1,20 @@
+class Admin::Education::School::ApplicationController < Admin::Education::ApplicationController
+  load_and_authorize_resource :school,
+                              class: Education::School,
+                              through: :current_university,
+                              through_association: :education_schools
+
+  protected
+
+  def breadcrumb
+    super
+    add_breadcrumb @school, [:admin, @school]
+  end
+
+  def default_url_options
+    return {} unless params.has_key? :school_id
+    {
+      school_id: params[:school_id]
+    }
+  end
+end
diff --git a/app/models/communication/website.rb b/app/models/communication/website.rb
index 6749b6482..b7a4d67ae 100644
--- a/app/models/communication/website.rb
+++ b/app/models/communication/website.rb
@@ -59,6 +59,6 @@ class Communication::Website < ApplicationRecord
       dependencies.concat [about.articles, about.volumes]
     end
 
-    dependencies.flatten.uniq.compact
+    dependencies
   end
 end
diff --git a/app/models/concerns/with_git.rb b/app/models/concerns/with_git.rb
index 981a0b102..2bbe7cc57 100644
--- a/app/models/concerns/with_git.rb
+++ b/app/models/concerns/with_git.rb
@@ -39,7 +39,7 @@ module WithGit
     websites_for_self.each do |website|
       identifiers(website: website).each do |identifier|
         Communication::Website::GitFile.sync website, self, identifier
-        dependencies = send "git_dependencies_#{identifier}"
+        dependencies = send("git_dependencies_#{identifier}").flatten.uniq.compact
         dependencies.each do |object|
           Communication::Website::GitFile.sync website, object, identifier
         end
@@ -53,7 +53,7 @@ module WithGit
     websites_for_self.each do |website|
       identifiers(website: website).each do |identifier|
         Communication::Website::GitFile.sync website, self, identifier, destroy: true
-        dependencies = send "git_destroy_dependencies_#{identifier}"
+        dependencies = send("git_destroy_dependencies_#{identifier}").flatten.uniq.compact
         dependencies.each do |object|
           Communication::Website::GitFile.sync website, object, identifier, destroy: true
         end
diff --git a/app/models/education/program.rb b/app/models/education/program.rb
index ba085aa57..ebf7b7d8b 100644
--- a/app/models/education/program.rb
+++ b/app/models/education/program.rb
@@ -121,11 +121,11 @@ class Education::Program < ApplicationRecord
   end
 
   def git_dependencies_static
-    [
-      active_storage_blobs,
-      university_people_through_teachers,
+    (
+      active_storage_blobs +
+      university_people_through_teachers +
       university_people_through_roles
-    ].flatten.uniq.compact
+    )
   end
 
   def git_destroy_dependencies_static
diff --git a/app/models/education/school.rb b/app/models/education/school.rb
index c6be33604..ad5acb370 100644
--- a/app/models/education/school.rb
+++ b/app/models/education/school.rb
@@ -28,6 +28,7 @@ class Education::School < ApplicationRecord
 
   belongs_to :university
   has_many :websites, class_name: 'Communication::Website', as: :about, dependent: :nullify
+  has_many :administrators, dependent: :destroy
   has_and_belongs_to_many :programs,
                           class_name: 'Education::Program',
                           join_table: 'education_programs_schools',
diff --git a/app/models/education/school/administrator.rb b/app/models/education/school/administrator.rb
new file mode 100644
index 000000000..42c86f05d
--- /dev/null
+++ b/app/models/education/school/administrator.rb
@@ -0,0 +1,33 @@
+# == Schema Information
+#
+# Table name: education_school_administrators
+#
+#  id          :uuid             not null, primary key
+#  description :text
+#  created_at  :datetime         not null
+#  updated_at  :datetime         not null
+#  person_id   :uuid             not null
+#  school_id   :uuid             not null
+#
+# Indexes
+#
+#  index_education_school_administrators_on_person_id  (person_id)
+#  index_education_school_administrators_on_school_id  (school_id)
+#
+# Foreign Keys
+#
+#  fk_rails_...  (person_id => university_people.id)
+#  fk_rails_...  (school_id => education_schools.id)
+#
+class Education::School::Administrator < ApplicationRecord
+  belongs_to :school
+  belongs_to :person, class_name: "University::Person"
+
+  validates :person_id, uniqueness: { scope: :school_id }
+
+  scope :ordered, -> { joins(:person).order('university_people.last_name, university_people.first_name') }
+
+  def to_s
+    person.to_s
+  end
+end
diff --git a/app/views/admin/education/school/administrators/_form.html.erb b/app/views/admin/education/school/administrators/_form.html.erb
new file mode 100644
index 000000000..b5bedea8c
--- /dev/null
+++ b/app/views/admin/education/school/administrators/_form.html.erb
@@ -0,0 +1,21 @@
+<%= simple_form_for [:admin, administrator] 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_administrator_ids = @school.administrators.where.not(id: administrator.id).pluck(:person_id) %>
+          <%= f.association :person, collection: current_university.people.administratives.where.not(id: used_administrator_ids).ordered %>
+        </div>
+        <div class="col-md-6">
+          <%= f.input :description, as: :string %>
+        </div>
+      </div>
+    </div>
+  </div>
+  <% content_for :action_bar_right do %>
+    <%= submit f %>
+  <% end %>
+<% end %>
diff --git a/app/views/admin/education/school/administrators/_list.html.erb b/app/views/admin/education/school/administrators/_list.html.erb
new file mode 100644
index 000000000..569c595ec
--- /dev/null
+++ b/app/views/admin/education/school/administrators/_list.html.erb
@@ -0,0 +1,35 @@
+<% if administrators.any? %>
+  <table class="table">
+    <thead>
+      <tr>
+        <th class="ps-0"><%= Education::School::Administrator.model_name.human %></th>
+        <th><%= Education::School::Administrator.human_attribute_name('description') %></th>
+        <th></th>
+      </tr>
+    </thead>
+    <tbody>
+      <% administrators.each do |administrator| %>
+        <tr>
+          <td class="ps-0">
+            <%= link_to_if  can?(:read, administrator.person),
+                            administrator.person,
+                            admin_university_person_path(administrator.person) %>
+          </td>
+          <td><%= administrator.description %></td>
+          <td class="text-end pe-0">
+            <div class="btn-group" role="group">
+              <%= link_to t('edit'),
+                          edit_admin_education_school_administrator_path(administrator, { school_id: @school.id }),
+                          class: button_classes %>
+              <%= link_to t('delete'),
+                          admin_education_school_administrator_path(administrator, { school_id: @school.id }),
+                          method: :delete,
+                          data: { confirm: t('please_confirm') },
+                          class: button_classes_danger %>
+            </div>
+          </td>
+        </tr>
+      <% end %>
+    </tbody>
+  </table>
+<% end %>
diff --git a/app/views/admin/education/school/administrators/edit.html.erb b/app/views/admin/education/school/administrators/edit.html.erb
new file mode 100644
index 000000000..d2a829946
--- /dev/null
+++ b/app/views/admin/education/school/administrators/edit.html.erb
@@ -0,0 +1,3 @@
+<% content_for :title, @administrator %>
+
+<%= render 'form', administrator: @administrator %>
diff --git a/app/views/admin/education/school/administrators/new.html.erb b/app/views/admin/education/school/administrators/new.html.erb
new file mode 100644
index 000000000..491f71583
--- /dev/null
+++ b/app/views/admin/education/school/administrators/new.html.erb
@@ -0,0 +1,3 @@
+<% content_for :title, Education::School::Administrator.model_name.human %>
+
+<%= render 'form', administrator: @administrator %>
diff --git a/app/views/admin/education/schools/show.html.erb b/app/views/admin/education/schools/show.html.erb
index 6c3c7800c..5367e4558 100644
--- a/app/views/admin/education/schools/show.html.erb
+++ b/app/views/admin/education/schools/show.html.erb
@@ -56,6 +56,16 @@
 
 </div>
 
+<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>
+  <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 %>
+  </div>
+</div>
+
 <% content_for :action_bar_right do %>
   <%= edit_link @school %>
 <% end %>
diff --git a/config/locales/education/en.yml b/config/locales/education/en.yml
index 1cb84dcbc..011a5cad4 100644
--- a/config/locales/education/en.yml
+++ b/config/locales/education/en.yml
@@ -19,6 +19,9 @@ en:
       education/school:
         one: School
         other: Schools
+      education/school/administrator:
+        one: Administrator
+        other: Administrators
     attributes:
       education/program:
         accessibility: Accessibilité
@@ -55,6 +58,7 @@ en:
         person: Person
       education/school:
         address: Address
+        administrators: Administrators
         city: City
         country: Country
         name: Name
@@ -62,6 +66,9 @@ en:
         programs: Programs provided
         websites: Associated websites
         zipcode: Zipcode
+      education/school/administrator:
+        description: Description
+        person: Person
   education:
     manage_teachers: Manage teachers
     number_of_programs: Number of programs
diff --git a/config/locales/education/fr.yml b/config/locales/education/fr.yml
index 755c0845c..ceece0535 100644
--- a/config/locales/education/fr.yml
+++ b/config/locales/education/fr.yml
@@ -19,6 +19,9 @@ fr:
       education/school:
         one: École
         other: Écoles
+      education/school/administrator:
+        one: Administrateur·trice
+        other: Administrateurs·trices
     attributes:
       education/program:
         accessibility: Accessibilité
@@ -57,6 +60,7 @@ fr:
         person: Personne
       education/school:
         address: Adresse
+        administrators: Administrateurs·trices
         city: Ville
         country: Pays
         name: Nom
@@ -64,6 +68,9 @@ fr:
         programs: Formations dispensées
         websites: Sites webs associés
         zipcode: Code postal
+      education/school/administrator:
+        description: Description
+        person: Personne
   education:
     manage_teachers: Gérer les Enseignants·es
     number_of_programs: Nombre de formations
diff --git a/config/routes/admin/education.rb b/config/routes/admin/education.rb
index 79e0e2555..c3ac5899e 100644
--- a/config/routes/admin/education.rb
+++ b/config/routes/admin/education.rb
@@ -1,6 +1,8 @@
 namespace :education do
   resources :teachers, only: [:index, :show]
-  resources :schools
+  resources :schools do
+    resources :administrators, controller: 'school/administrators', except: [:index, :show]
+  end
   resources :programs do
     resources :roles, controller: 'program/roles', except: :index do
       resources :people, controller: 'program/role/people', except: [:index, :show, :edit, :update] do
diff --git a/db/migrate/20220107111002_create_education_school_administrators.rb b/db/migrate/20220107111002_create_education_school_administrators.rb
new file mode 100644
index 000000000..d3454d325
--- /dev/null
+++ b/db/migrate/20220107111002_create_education_school_administrators.rb
@@ -0,0 +1,11 @@
+class CreateEducationSchoolAdministrators < ActiveRecord::Migration[6.1]
+  def change
+    create_table :education_school_administrators, id: :uuid do |t|
+      t.text :description
+      t.references :school, null: false, foreign_key: { to_table: :education_schools }, type: :uuid
+      t.references :person, null: false, foreign_key: { to_table: :university_people }, type: :uuid
+
+      t.timestamps
+    end
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 0271d5650..da37739db 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.define(version: 2022_01_07_094053) do
+ActiveRecord::Schema.define(version: 2022_01_07_111002) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "pgcrypto"
@@ -405,6 +405,16 @@ ActiveRecord::Schema.define(version: 2022_01_07_094053) do
     t.index ["education_school_id", "education_program_id"], name: "school_program"
   end
 
+  create_table "education_school_administrators", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+    t.text "description"
+    t.uuid "school_id", null: false
+    t.uuid "person_id", null: false
+    t.datetime "created_at", precision: 6, null: false
+    t.datetime "updated_at", precision: 6, null: false
+    t.index ["person_id"], name: "index_education_school_administrators_on_person_id"
+    t.index ["school_id"], name: "index_education_school_administrators_on_school_id"
+  end
+
   create_table "education_schools", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.string "name"
@@ -608,6 +618,8 @@ ActiveRecord::Schema.define(version: 2022_01_07_094053) do
   add_foreign_key "education_program_teachers", "university_people", column: "person_id"
   add_foreign_key "education_programs", "education_programs", column: "parent_id"
   add_foreign_key "education_programs", "universities"
+  add_foreign_key "education_school_administrators", "education_schools", column: "school_id"
+  add_foreign_key "education_school_administrators", "university_people", column: "person_id"
   add_foreign_key "education_schools", "universities"
   add_foreign_key "research_journal_articles", "research_journal_volumes"
   add_foreign_key "research_journal_articles", "research_journals"
diff --git a/test/fixtures/education/school/administrators.yml b/test/fixtures/education/school/administrators.yml
new file mode 100644
index 000000000..cb3dfca46
--- /dev/null
+++ b/test/fixtures/education/school/administrators.yml
@@ -0,0 +1,32 @@
+# == Schema Information
+#
+# Table name: education_school_administrators
+#
+#  id          :uuid             not null, primary key
+#  description :text
+#  created_at  :datetime         not null
+#  updated_at  :datetime         not null
+#  person_id   :uuid             not null
+#  school_id   :uuid             not null
+#
+# Indexes
+#
+#  index_education_school_administrators_on_person_id  (person_id)
+#  index_education_school_administrators_on_school_id  (school_id)
+#
+# Foreign Keys
+#
+#  fk_rails_...  (person_id => university_people.id)
+#  fk_rails_...  (school_id => education_schools.id)
+#
+# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+one:
+  description: MyText
+  school: one
+  person: one
+
+two:
+  description: MyText
+  school: two
+  person: two
diff --git a/test/models/education/school/administrator_test.rb b/test/models/education/school/administrator_test.rb
new file mode 100644
index 000000000..bdf223d6d
--- /dev/null
+++ b/test/models/education/school/administrator_test.rb
@@ -0,0 +1,28 @@
+# == Schema Information
+#
+# Table name: education_school_administrators
+#
+#  id          :uuid             not null, primary key
+#  description :text
+#  created_at  :datetime         not null
+#  updated_at  :datetime         not null
+#  person_id   :uuid             not null
+#  school_id   :uuid             not null
+#
+# Indexes
+#
+#  index_education_school_administrators_on_person_id  (person_id)
+#  index_education_school_administrators_on_school_id  (school_id)
+#
+# Foreign Keys
+#
+#  fk_rails_...  (person_id => university_people.id)
+#  fk_rails_...  (school_id => education_schools.id)
+#
+require "test_helper"
+
+class Education::School::AdministratorTest < ActiveSupport::TestCase
+  # test "the truth" do
+  #   assert true
+  # end
+end
-- 
GitLab