diff --git a/app/controllers/admin/education/programs_controller.rb b/app/controllers/admin/education/programs_controller.rb index 858e124aaf59ac2c3725ddfe2697fe4d8f4339a1..25a6e312a0878a22e5e17d0f86de5bd96fd31627 100644 --- a/app/controllers/admin/education/programs_controller.rb +++ b/app/controllers/admin/education/programs_controller.rb @@ -56,6 +56,6 @@ class Admin::Education::ProgramsController < Admin::Education::ApplicationContro params.require(:education_program) .permit(:name, :level, :capacity, :ects, :continuing, :prerequisites, :objectives, :duration, :registration, :pedagogy, - :evaluation, :accessibility, :pricing, :contacts, :opportunities, :other, school_ids: []) + :evaluation, :accessibility, :pricing, :contacts, :opportunities, :other, school_ids: [], teacher_ids: []) end end diff --git a/app/controllers/admin/education/teachers_controller.rb b/app/controllers/admin/education/teachers_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..adc6bdbd623e0a338acdb708b3d2622f324a121e --- /dev/null +++ b/app/controllers/admin/education/teachers_controller.rb @@ -0,0 +1,65 @@ +class Admin::Education::TeachersController < Admin::Education::ApplicationController + load_and_authorize_resource class: Education::Teacher + + def index + @teachers = current_university.teachers.ordered.page(params[:page]) + breadcrumb + end + + def show + breadcrumb + end + + def publish + @teacher.force_publish! + redirect_to admin_education_teacher_path(@teacher), notice: t('admin.will_be_published_html', model: @teacher.to_s) + end + + def new + breadcrumb + end + + def edit + breadcrumb + add_breadcrumb t('edit') + end + + def create + if @teacher.save + redirect_to admin_education_teacher_path(@teacher), notice: t('admin.successfully_created_html', model: @teacher.to_s) + else + breadcrumb + render :new, status: :unprocessable_entity + end + end + + def update + if @teacher.update(teacher_params) + redirect_to admin_education_teacher_path(@teacher), notice: t('admin.successfully_updated_html', model: @teacher.to_s) + else + breadcrumb + add_breadcrumb t('edit') + render :edit, status: :unprocessable_entity + end + end + + def destroy + @teacher.destroy + redirect_to admin_education_teachers_url, notice: t('admin.successfully_destroyed_html', model: @teacher.to_s) + end + + protected + + def breadcrumb + super + add_breadcrumb Education::Teacher.model_name.human(count: 2), + admin_education_teachers_path + breadcrumb_for @teacher + end + + def teacher_params + params.require(:education_teacher) + .permit(:first_name, :last_name, :biography, :slug, :user_id) + .merge(university_id: current_university.id) + end +end diff --git a/app/models/concerns/with_slug.rb b/app/models/concerns/with_slug.rb index cec6fd76aef447ba36fed0f321811b1d3a56b1d4..81ec3bc25299ccd0f01729c3665ea52eead0fef1 100644 --- a/app/models/concerns/with_slug.rb +++ b/app/models/concerns/with_slug.rb @@ -3,7 +3,8 @@ module WithSlug included do validates :slug, - uniqueness: { scope: :university_id }, + uniqueness: { scope: :university_id } + validates :slug, format: { with: /\A[a-z0-9\-]+\z/, message: "ne peut contenir que des lettres minuscules, des chiffres et des traits d'union." }, allow_blank: true end diff --git a/app/models/education/program.rb b/app/models/education/program.rb index 4a4fa6f9d687f29600fcf1aa13a57748b5d88873..6cb08e5d8c59773edcb8d40999d8c384f2e5fb55 100644 --- a/app/models/education/program.rb +++ b/app/models/education/program.rb @@ -39,6 +39,11 @@ class Education::Program < ApplicationRecord join_table: 'education_programs_schools', foreign_key: 'education_program_id', association_foreign_key: 'education_school_id' + has_and_belongs_to_many :teachers, + class_name: 'Education::Teacher', + join_table: 'education_programs_teachers', + foreign_key: 'education_program_id', + association_foreign_key: 'education_teacher_id' enum level: { bachelor: 300, diff --git a/app/models/education/teacher.rb b/app/models/education/teacher.rb new file mode 100644 index 0000000000000000000000000000000000000000..41ad533f93b0746638c62bc451973805c2ceac5c --- /dev/null +++ b/app/models/education/teacher.rb @@ -0,0 +1,57 @@ +# == Schema Information +# +# Table name: education_teachers +# +# id :uuid not null, primary key +# first_name :string +# github_path :text +# last_name :string +# slug :string +# created_at :datetime not null +# updated_at :datetime not null +# university_id :uuid not null +# user_id :uuid +# +# Indexes +# +# index_education_teachers_on_university_id (university_id) +# index_education_teachers_on_user_id (user_id) +# +# Foreign Keys +# +# fk_rails_... (university_id => universities.id) +# fk_rails_... (user_id => users.id) +# +class Education::Teacher < ApplicationRecord + include WithGithub + include WithSlug + + has_rich_text :biography + + belongs_to :university + belongs_to :user, optional: true + has_and_belongs_to_many :programs, + class_name: 'Education::Program', + join_table: 'education_programs_teachers', + foreign_key: 'education_teacher_id', + association_foreign_key: 'education_program_id' + + + scope :ordered, -> { order(:last_name, :first_name) } + + def to_s + "#{last_name} #{first_name}" + end + + def github_path_generated + "_teachers/#{slug}.html" + end + + def to_jekyll + ApplicationController.render( + template: 'admin/education/teachers/jekyll', + layout: false, + assigns: { teacher: self } + ) + end +end diff --git a/app/models/university/with_education.rb b/app/models/university/with_education.rb index 5acddc90f4055bb204487797d97d6994c82a189e..786749c3ed9cbd68d69179609186859d5fd08f1f 100644 --- a/app/models/university/with_education.rb +++ b/app/models/university/with_education.rb @@ -2,6 +2,7 @@ module University::WithEducation extend ActiveSupport::Concern included do + has_many :teachers, class_name: 'Education::Teacher', dependent: :destroy has_many :education_programs, class_name: 'Education::Program', dependent: :destroy has_many :education_schools, class_name: 'Education::School', dependent: :destroy end diff --git a/app/views/admin/education/programs/_form.html.erb b/app/views/admin/education/programs/_form.html.erb index 1a38d3141b767bef9b73bea8d1c051eccc198fff..4f54820cbaf34aeeb697cea5dfc740486255d1ce 100644 --- a/app/views/admin/education/programs/_form.html.erb +++ b/app/views/admin/education/programs/_form.html.erb @@ -9,8 +9,7 @@ <%= f.input :continuing %> <%= f.association :schools, as: :check_boxes, - collection: current_university.education_schools.ordered - %> + collection: current_university.education_schools.ordered %> </div> <div class="col-md-8"> <h2 class="h4"><%= t('education.program.useful_informations') %></h2> @@ -32,6 +31,9 @@ <div class="col-md-6"> <%= f.input :pedagogy, as: :rich_text_area %> <%= f.input :evaluation, as: :rich_text_area %> + <%= f.association :teachers, + as: :check_boxes, + collection: current_university.teachers.ordered %> </div> </div> <% content_for :action_bar_right do %> diff --git a/app/views/admin/education/teachers/_form.html.erb b/app/views/admin/education/teachers/_form.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..a84f051ff3922be78f74c441e07c8ae0ca3a4332 --- /dev/null +++ b/app/views/admin/education/teachers/_form.html.erb @@ -0,0 +1,37 @@ +<%= simple_form_for [:admin, teacher] do |f| %> + <div class="row"> + <div class="col-md-8"> + <div class="card flex-fill w-100"> + <div class="card-header"> + <h5 class="card-title mb-0"><%= t('content') %></h5> + </div> + <div class="card-body"> + <%= f.input :first_name %> + <%= f.input :last_name %> + <%= f.input :biography, as: :rich_text_area %> + </div> + </div> + </div> + <div class="col-md-4"> + <div class="card flex-fill w-100"> + <div class="card-header"> + <h5 class="card-title mb-0"><%= t('metadata') %></h5> + </div> + <div class="card-body"> + <%= f.input :slug, + as: :string, + input_html: teacher.persisted? ? {} : { + class: 'js-slug-input', + data: { source: '#education_teacher_first_name, #education_teacher_last_name' } + } %> + <%= f.association :user, collection: current_university.users.ordered %> + <ul> + </ul> + </div> + </div> + </div> + </div> + <% content_for :action_bar_right do %> + <%= submit f %> + <% end %> +<% end %> diff --git a/app/views/admin/education/teachers/_list.html.erb b/app/views/admin/education/teachers/_list.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..87e1befee2026a66c4609d9467f08538e50b6c33 --- /dev/null +++ b/app/views/admin/education/teachers/_list.html.erb @@ -0,0 +1,27 @@ +<table class="<%= table_classes %>"> + <thead> + <tr> + <th><%= Education::Teacher.human_attribute_name('name') %></th> + <th></th> + </tr> + </thead> + <tbody> + <% teachers.each do |teacher| %> + <tr> + <td><%= link_to teacher, admin_education_teacher_path(teacher) %></td> + <td class="text-end"> + <div class="btn-group" role="group"> + <%= link_to t('edit'), + edit_admin_education_teacher_path(teacher), + class: button_classes %> + <%= link_to t('delete'), + admin_education_teacher_path(teacher), + method: :delete, + data: { confirm: t('please-confirm') }, + class: button_classes_danger %> + </div> + </td> + </tr> + <% end %> + </tbody> +</table> diff --git a/app/views/admin/education/teachers/edit.html.erb b/app/views/admin/education/teachers/edit.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..b3f94ca300bb5361d5c000f96b377bd2bd76eb0e --- /dev/null +++ b/app/views/admin/education/teachers/edit.html.erb @@ -0,0 +1,3 @@ +<% content_for :title, @teacher %> + +<%= render 'form', teacher: @teacher %> diff --git a/app/views/admin/education/teachers/index.html.erb b/app/views/admin/education/teachers/index.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..44ce68d4d10ef722296bdb5430f0cf8bae26f57c --- /dev/null +++ b/app/views/admin/education/teachers/index.html.erb @@ -0,0 +1,9 @@ +<% content_for :title, "#{Education::Teacher.model_name.human(count: 2)} (#{@teachers.total_count})" %> + +<%= render 'admin/education/teachers/list', teachers: @teachers %> +<%= paginate @teachers, theme: 'bootstrap-5' %> + + +<% content_for :action_bar_right do %> + <%= create_link Education::Teacher %> +<% end %> diff --git a/app/views/admin/education/teachers/jekyll.html.erb b/app/views/admin/education/teachers/jekyll.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..8aa58250eeda0702d4f386b63321b42378225bd3 --- /dev/null +++ b/app/views/admin/education/teachers/jekyll.html.erb @@ -0,0 +1,10 @@ +--- +title: "<%= @author.to_s %>" +identifier: "<%= @author.id %>" +first_name: "<%= @author.first_name %>" +last_name: "<%= @author.last_name %>" +slug: "<%= @author.slug %>" +biography: > + <%= prepare_for_github @author.biography, @author.university %> +--- +<%= @author.github_frontmatter.content.html_safe %> diff --git a/app/views/admin/education/teachers/new.html.erb b/app/views/admin/education/teachers/new.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..9d2a7e6cf6e8da788d90d7014ed2af0fca92cd6d --- /dev/null +++ b/app/views/admin/education/teachers/new.html.erb @@ -0,0 +1,3 @@ +<% content_for :title, Education::Teacher.model_name.human %> + +<%= render 'form', teacher: @teacher %> diff --git a/app/views/admin/education/teachers/show.html.erb b/app/views/admin/education/teachers/show.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..41bddec60768185dac8f24bcc2d63f4457ea6028 --- /dev/null +++ b/app/views/admin/education/teachers/show.html.erb @@ -0,0 +1,44 @@ +<% content_for :title, @teacher %> + +<div class="row"> + + <div class="col-md-8"> + <div class="card flex-fill w-100"> + <div class="card-header"> + <h2 class="card-title mb-0 h5"><%= t('content') %></h2> + </div> + <div class="card-body"> + <h3 class="h5"><%= Education::Teacher.human_attribute_name('biography') %></h3> + <%= @teacher.biography %> + </div> + </div> + </div> + + <div class="col-md-4"> + <div class="card flex-fill w-100"> + <div class="card-header"> + <h2 class="card-title mb-0 h5"><%= t('metadata') %></h2> + </div> + <table class="<%= table_classes %>"> + <tbody> + <tr> + <td width="150"><%= Education::Teacher.human_attribute_name('slug') %></td> + <td><%= @teacher.slug %></td> + </tr> + <% if @teacher.user %> + <tr> + <td width="150"><%= Education::Teacher.human_attribute_name('user') %></td> + <td><%= link_to_if can?(:read, @teacher.user), @teacher.user, admin_user_path(@teacher.user) %></td> + </tr> + <% end %> + </tbody> + </table> + </div> + </div> + +</div> + + +<% content_for :action_bar_right do %> + <%= edit_link @teacher %> +<% end %> diff --git a/config/admin_navigation.rb b/config/admin_navigation.rb index 5cee38c3a407b151643b9bb4fcb4722b33c2ecb1..759ca515528955b895236b599f6bc60e209224a2 100644 --- a/config/admin_navigation.rb +++ b/config/admin_navigation.rb @@ -8,7 +8,7 @@ SimpleNavigation::Configuration.run do |navigation| if can?(:read, Education::Program) primary.item :education, Education.model_name.human, nil, { kind: :header } - primary.item :education, 'Enseignants', nil, { icon: 'user-graduate' } + primary.item :education, Education::Teacher.model_name.human(count: 2), admin_education_teachers_path, { icon: 'user-graduate' } primary.item :education, Education::School.model_name.human(count: 2), admin_education_schools_path, { icon: 'university' } if can?(:read, Education::School) primary.item :education_programs, Education::Program.model_name.human(count: 2), admin_education_programs_path, { icon: 'graduation-cap' } if can?(:read, Education::Program) primary.item :education, 'Ressources éducatives', nil, { icon: 'laptop' } diff --git a/config/locales/education/en.yml b/config/locales/education/en.yml index 5ebe188817786dfc889b3d104858787fecc1fbdc..43f72170495fb0916f8117eee46ef5bb2089ae72 100644 --- a/config/locales/education/en.yml +++ b/config/locales/education/en.yml @@ -10,6 +10,9 @@ en: education/school: one: School other: Schools + education/teacher: + one: Teacher + other: Teachers attributes: education/program: accessibility: Accessibilité @@ -28,12 +31,21 @@ en: prerequisites: Prérequis pricing: Tarifs registration: Modalités et délais d’accès + schools: Schools + teachers: Teachers education/school: - address:: Address + address: Address city: City country: Country name: Name zipcode: Zipcode + education/teacher: + biography: Biography + first_name: First name + last_name: Last name + name: Name + slug: Slug + user: User education: program: main_informations: Main informations diff --git a/config/locales/education/fr.yml b/config/locales/education/fr.yml index a32a5805c63bc69882d451978849357426ed8c4f..480298bcebc04998f6d7c590758ac49eedd86d59 100644 --- a/config/locales/education/fr.yml +++ b/config/locales/education/fr.yml @@ -10,6 +10,9 @@ fr: education/school: one: École other: Écoles + education/teacher: + one: Enseignant·e + other: Enseignants·es attributes: education/program: accessibility: Accessibilité @@ -28,12 +31,21 @@ fr: prerequisites: Prérequis pricing: Tarifs registration: Modalités et délais d’accès + schools: Écoles + teachers: Enseignants·es education/school: address: Adresse city: Ville country: Pays name: Nom zipcode: Code postal + education/teacher: + biography: Biographie + first_name: Prénom + last_name: Nom de famille + name: Nom + slug: Slug + user: Utilisateur education: program: main_informations: Informations essentielles diff --git a/config/routes/admin/education.rb b/config/routes/admin/education.rb index 9f158d5913f21e726c3547314429eaeabb3901e3..6969aa6f3afd12a510125c0df297b1623f13b427 100644 --- a/config/routes/admin/education.rb +++ b/config/routes/admin/education.rb @@ -1,3 +1,3 @@ namespace :education do - resources :programs, :schools + resources :programs, :schools, :teachers end diff --git a/db/migrate/20211115154841_create_education_teacher.rb b/db/migrate/20211115154841_create_education_teacher.rb new file mode 100644 index 0000000000000000000000000000000000000000..41cae970a07b96fc7787fb3d0b0533ac1eb97159 --- /dev/null +++ b/db/migrate/20211115154841_create_education_teacher.rb @@ -0,0 +1,15 @@ +class CreateEducationTeacher < ActiveRecord::Migration[6.1] + def change + create_table :education_teachers, id: :uuid do |t| + t.references :university, null: false, foreign_key: true, type: :uuid + t.string :first_name + t.string :last_name + t.string :slug + t.text :github_path + t.references :user, null: true, foreign_key: true, type: :uuid + + + t.timestamps + end + end +end diff --git a/db/migrate/20211115162245_create_join_table_programs_teachers.rb b/db/migrate/20211115162245_create_join_table_programs_teachers.rb new file mode 100644 index 0000000000000000000000000000000000000000..1e9081128b868e6c52448d8a3df96306a05e793d --- /dev/null +++ b/db/migrate/20211115162245_create_join_table_programs_teachers.rb @@ -0,0 +1,8 @@ +class CreateJoinTableProgramsTeachers < ActiveRecord::Migration[6.1] + def change + create_join_table :education_programs, :education_teachers, column_options: {type: :uuid} do |t| + t.index [:education_program_id, :education_teacher_id], name: 'program_teacher' + t.index [:education_teacher_id, :education_program_id], name: 'teacher_program' + end + end +end diff --git a/db/schema.rb b/db/schema.rb index cec373177240b054194f018b73c8962e5161bce9..85299fd5125630c41413ea4cd6b9e94f1bcb2415 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: 2021_11_15_134945) do +ActiveRecord::Schema.define(version: 2021_11_15_162245) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" @@ -345,6 +345,13 @@ ActiveRecord::Schema.define(version: 2021_11_15_134945) do t.index ["education_school_id", "education_program_id"], name: "school_program" end + create_table "education_programs_teachers", id: false, force: :cascade do |t| + t.uuid "education_program_id", null: false + t.uuid "education_teacher_id", null: false + t.index ["education_program_id", "education_teacher_id"], name: "program_teacher" + t.index ["education_teacher_id", "education_program_id"], name: "teacher_program" + end + create_table "education_schools", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.uuid "university_id", null: false t.string "name" @@ -359,6 +366,19 @@ ActiveRecord::Schema.define(version: 2021_11_15_134945) do t.index ["university_id"], name: "index_education_schools_on_university_id" end + create_table "education_teachers", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.uuid "university_id", null: false + t.string "first_name" + t.string "last_name" + t.string "slug" + t.text "github_path" + t.uuid "user_id" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.index ["university_id"], name: "index_education_teachers_on_university_id" + t.index ["user_id"], name: "index_education_teachers_on_user_id" + end + create_table "languages", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.string "name" t.string "iso_code" @@ -533,6 +553,8 @@ ActiveRecord::Schema.define(version: 2021_11_15_134945) do add_foreign_key "communication_websites", "universities" add_foreign_key "education_programs", "universities" add_foreign_key "education_schools", "universities" + add_foreign_key "education_teachers", "universities" + add_foreign_key "education_teachers", "users" add_foreign_key "research_journal_articles", "research_journal_volumes" add_foreign_key "research_journal_articles", "research_journals" add_foreign_key "research_journal_articles", "universities"