diff --git a/Gemfile b/Gemfile index e9a3e9d08c682fd80d70743c5bb69052af08320a..8d4ec9427bdea39f5c7ab4eb6ce7acb93a548a73 100644 --- a/Gemfile +++ b/Gemfile @@ -19,7 +19,7 @@ gem 'bootsnap', '>= 1.4.4', require: false gem 'curation'#, path: '../../arnaudlevy/curation' gem 'delayed_job_active_record' gem 'delayed_job_web' -gem 'faceted_search' +gem 'faceted_search', path: '../faceted_search' gem 'has_scope', '~> 0.8.0' gem 'hash_dot' gem 'rails', '~> 6.1' diff --git a/Gemfile.lock b/Gemfile.lock index 7c67efbadce67ca42440a938fc10a2854c533788..4afd329cd3a5f3ce4865014d842dc92d8a6d138b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -17,63 +17,70 @@ GIT randexp rotp (>= 4.0.0) +PATH + remote: ../faceted_search + specs: + faceted_search (3.5.12) + font-awesome-sass + rails (>= 5.2.0, < 7) + GEM remote: https://rubygems.org/ specs: - actioncable (6.1.5) - actionpack (= 6.1.5) - activesupport (= 6.1.5) + actioncable (6.1.5.1) + actionpack (= 6.1.5.1) + activesupport (= 6.1.5.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.1.5) - actionpack (= 6.1.5) - activejob (= 6.1.5) - activerecord (= 6.1.5) - activestorage (= 6.1.5) - activesupport (= 6.1.5) + actionmailbox (6.1.5.1) + actionpack (= 6.1.5.1) + activejob (= 6.1.5.1) + activerecord (= 6.1.5.1) + activestorage (= 6.1.5.1) + activesupport (= 6.1.5.1) mail (>= 2.7.1) - actionmailer (6.1.5) - actionpack (= 6.1.5) - actionview (= 6.1.5) - activejob (= 6.1.5) - activesupport (= 6.1.5) + actionmailer (6.1.5.1) + actionpack (= 6.1.5.1) + actionview (= 6.1.5.1) + activejob (= 6.1.5.1) + activesupport (= 6.1.5.1) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.1.5) - actionview (= 6.1.5) - activesupport (= 6.1.5) + actionpack (6.1.5.1) + actionview (= 6.1.5.1) + activesupport (= 6.1.5.1) rack (~> 2.0, >= 2.0.9) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.1.5) - actionpack (= 6.1.5) - activerecord (= 6.1.5) - activestorage (= 6.1.5) - activesupport (= 6.1.5) + actiontext (6.1.5.1) + actionpack (= 6.1.5.1) + activerecord (= 6.1.5.1) + activestorage (= 6.1.5.1) + activesupport (= 6.1.5.1) nokogiri (>= 1.8.5) - actionview (6.1.5) - activesupport (= 6.1.5) + actionview (6.1.5.1) + activesupport (= 6.1.5.1) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.1.5) - activesupport (= 6.1.5) + activejob (6.1.5.1) + activesupport (= 6.1.5.1) globalid (>= 0.3.6) - activemodel (6.1.5) - activesupport (= 6.1.5) - activerecord (6.1.5) - activemodel (= 6.1.5) - activesupport (= 6.1.5) - activestorage (6.1.5) - actionpack (= 6.1.5) - activejob (= 6.1.5) - activerecord (= 6.1.5) - activesupport (= 6.1.5) + activemodel (6.1.5.1) + activesupport (= 6.1.5.1) + activerecord (6.1.5.1) + activemodel (= 6.1.5.1) + activesupport (= 6.1.5.1) + activestorage (6.1.5.1) + actionpack (= 6.1.5.1) + activejob (= 6.1.5.1) + activerecord (= 6.1.5.1) + activesupport (= 6.1.5.1) marcel (~> 1.0) mini_mime (>= 1.1.0) - activesupport (6.1.5) + activesupport (6.1.5.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -88,20 +95,20 @@ GEM autoprefixer-rails (10.4.2.0) execjs (~> 2) aws-eventstream (1.2.0) - aws-partitions (1.576.0) - aws-sdk-core (3.130.1) + aws-partitions (1.580.0) + aws-sdk-core (3.130.2) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.525.0) aws-sigv4 (~> 1.1) jmespath (~> 1.0) - aws-sdk-kms (1.55.0) + aws-sdk-kms (1.56.0) aws-sdk-core (~> 3, >= 3.127.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.113.0) + aws-sdk-s3 (1.113.2) aws-sdk-core (~> 3, >= 3.127.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.4) - aws-sigv4 (1.4.0) + aws-sigv4 (1.5.0) aws-eventstream (~> 1, >= 1.0.2) bcrypt (3.1.17) bindex (0.8.1) @@ -172,9 +179,6 @@ GEM ethon (0.15.0) ffi (>= 1.15.0) execjs (2.8.1) - faceted_search (3.5.11) - font-awesome-sass - rails (>= 5.2.0, < 7) faraday (1.10.0) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -321,20 +325,20 @@ GEM rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.1.5) - actioncable (= 6.1.5) - actionmailbox (= 6.1.5) - actionmailer (= 6.1.5) - actionpack (= 6.1.5) - actiontext (= 6.1.5) - actionview (= 6.1.5) - activejob (= 6.1.5) - activemodel (= 6.1.5) - activerecord (= 6.1.5) - activestorage (= 6.1.5) - activesupport (= 6.1.5) + rails (6.1.5.1) + actioncable (= 6.1.5.1) + actionmailbox (= 6.1.5.1) + actionmailer (= 6.1.5.1) + actionpack (= 6.1.5.1) + actiontext (= 6.1.5.1) + actionview (= 6.1.5.1) + activejob (= 6.1.5.1) + activemodel (= 6.1.5.1) + activerecord (= 6.1.5.1) + activestorage (= 6.1.5.1) + activesupport (= 6.1.5.1) bundler (>= 1.15.0) - railties (= 6.1.5) + railties (= 6.1.5.1) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) @@ -344,9 +348,9 @@ GEM rails-i18n (7.0.3) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) - railties (6.1.5) - actionpack (= 6.1.5) - activesupport (= 6.1.5) + railties (6.1.5.1) + actionpack (= 6.1.5.1) + activesupport (= 6.1.5.1) method_source rake (>= 12.2) thor (~> 1.0) @@ -355,7 +359,7 @@ GEM rb-fsevent (0.11.1) rb-inotify (0.10.1) ffi (~> 1.0) - regexp_parser (2.3.0) + regexp_parser (2.3.1) responders (3.0.1) actionpack (>= 5.0) railties (>= 5.0) @@ -474,7 +478,7 @@ DEPENDENCIES devise devise-i18n enum_help - faceted_search + faceted_search! figaro front_matter_parser gdpr diff --git a/app/assets/stylesheets/application.sass b/app/assets/stylesheets/application.sass index 1d71576b129df81fc868efe53a4d0f83414091a8..cbdad2dd5161fd3e130203aabb7e325e41f39451 100644 --- a/app/assets/stylesheets/application.sass +++ b/app/assets/stylesheets/application.sass @@ -4,5 +4,6 @@ @import 'simple_form_bs5_file_input' @import 'cropperjs/dist/cropper' @import 'gdpr/cookie_consent' +@import 'faceted_search' @import 'commons/*' @import 'application/*' diff --git a/app/assets/stylesheets/application/faceted_search.sass b/app/assets/stylesheets/application/faceted_search.sass new file mode 100644 index 0000000000000000000000000000000000000000..d3d8bb19432f4bc79f47c1c1fdc63c46c989f821 --- /dev/null +++ b/app/assets/stylesheets/application/faceted_search.sass @@ -0,0 +1,7 @@ +.faceted + &__facet-selected + a + text-decoration: none + &__facet__list + .faceted__facet__list__value + display: inline-block diff --git a/app/controllers/extranet/persons_controller.rb b/app/controllers/extranet/persons_controller.rb index 977822b952ee1ffafc832be937586bb7e6a607f4..e3975a7a7afe0f01c3a25506c8d5b567a25fc03c 100644 --- a/app/controllers/extranet/persons_controller.rb +++ b/app/controllers/extranet/persons_controller.rb @@ -11,7 +11,8 @@ class Extranet::PersonsController < Extranet::ApplicationController } @people = @facets.results .ordered - .page params[:page] + .page(params[:page]) + .per(60) @count = @people.total_count breadcrumb end diff --git a/app/models/education/academic_year.rb b/app/models/education/academic_year.rb index 42878678e309e949e9123a3fd43c8270ae39c61d..ac89369971fb7286c5a8a2b490707b66089b7be3 100644 --- a/app/models/education/academic_year.rb +++ b/app/models/education/academic_year.rb @@ -21,6 +21,11 @@ class Education::AcademicYear < ApplicationRecord has_many :cohorts, class_name: 'Education::Cohort' + # Dénormalisation des alumni pour le faceted search + has_and_belongs_to_many :university_people, + class_name: 'University::Person', + foreign_key: 'education_academic_year_id', + association_foreign_key: 'university_person_id' has_many :people, class_name: 'University::Person', through: :cohorts diff --git a/app/models/education/program.rb b/app/models/education/program.rb index f1829148334801bb7a90187e875f41c2eb9c1451..eff93c5cd761cd388fe14f7cd6cffb05d8e72571 100644 --- a/app/models/education/program.rb +++ b/app/models/education/program.rb @@ -114,12 +114,12 @@ class Education::Program < ApplicationRecord has_many :alumni, through: :cohorts, source: :people - has_many :alumni_experiences, + has_many :alumni_experiences, -> { distinct }, class_name: 'University::Person::Experience', through: :alumni, source: :experiences - has_many :alumni_organizations, + has_many :alumni_organizations, -> { distinct }, class_name: 'University::Organization', through: :alumni_experiences, diff --git a/app/models/university/person.rb b/app/models/university/person.rb index 242b23a70ce295607b4075ee8c35815767300701..df746435d0c942f8e57ccaa90a477fb3029f96c6 100644 --- a/app/models/university/person.rb +++ b/app/models/university/person.rb @@ -46,7 +46,13 @@ class University::Person < ApplicationRecord include WithPicture include WithEducation - LIST_OF_ROLES = [:administration, :teacher, :researcher, :alumnus, :author].freeze + LIST_OF_ROLES = [ + :administration, + :teacher, + :researcher, + :alumnus, + :author + ].freeze has_summernote :biography @@ -91,8 +97,6 @@ class University::Person < ApplicationRecord through: :education_programs, source: :websites - has_many :experiences - accepts_nested_attributes_for :involvements validates_presence_of :first_name, :last_name diff --git a/app/models/university/person/alumnus/facets.rb b/app/models/university/person/alumnus/facets.rb index 5cc231c589b36592225e9da3205ecf377f1eb44e..6c8c4f7ab582feab146cbfc8fd8dd0e31230438c 100644 --- a/app/models/university/person/alumnus/facets.rb +++ b/app/models/university/person/alumnus/facets.rb @@ -5,12 +5,18 @@ class University::Person::Alumnus::Facets < FacetedSearch::Facets @model = options[:model] @about = options[:about] - filter_with_text :name + filter_with_text :name, { + title: University::Person.human_attribute_name('name') + } - # TODO année de diplôme + filter_with_list :diploma_years, { + source: @about.academic_years.ordered, + title: Education::AcademicYear.model_name.human(count: 2), + habtm: true + } # TODO liste des formations (si about ≠formation) - # filter_with_list :program, { + # filter_with_list :programs, { # source: @about.programs, # habtm: true # } diff --git a/app/models/university/person/alumnus/import.rb b/app/models/university/person/alumnus/import.rb index f8a05b767bb3d6168450dff2c1e1dbc205ba63c5..6da4f7198ebb804489d97287313c3f89bc247bba 100644 --- a/app/models/university/person/alumnus/import.rb +++ b/app/models/university/person/alumnus/import.rb @@ -87,7 +87,7 @@ class University::Person::Alumnus::Import < ApplicationRecord person.phone ||= row['phone_professional'] byebug unless person.valid? person.save - cohort.people << person unless person.in?(cohort.people) + person.add_to_cohort cohort add_picture person, row['photo'] company_name = clean_encoding row['company_name'] diff --git a/app/models/university/person/with_education.rb b/app/models/university/person/with_education.rb index 049d08f97bfa94e462c09995152b1430e9f8b52c..0c52aba8c4efb01e71d983b1ce449c65a0cd4ccb 100644 --- a/app/models/university/person/with_education.rb +++ b/app/models/university/person/with_education.rb @@ -2,20 +2,28 @@ module University::Person::WithEducation extend ActiveSupport::Concern included do - has_many :involvements_as_teacher, - -> { where(kind: 'teacher') }, - class_name: 'University::Person::Involvement', - dependent: :destroy + has_many :involvements_as_teacher, + -> { where(kind: 'teacher') }, + class_name: 'University::Person::Involvement', + dependent: :destroy - has_many :education_programs_as_teacher, - through: :involvements_as_teacher, - source: :target, - source_type: "Education::Program" + has_many :education_programs_as_teacher, + through: :involvements_as_teacher, + source: :target, + source_type: "Education::Program" + + has_many :experiences has_and_belongs_to_many :cohorts, class_name: 'Education::Cohort', foreign_key: 'university_person_id', association_foreign_key: 'education_cohort_id' + + # Dénormalisation des liens via cohorts, pour la recherche par facettes + has_and_belongs_to_many :diploma_years, + class_name: 'Education::AcademicYear', + foreign_key: 'university_person_id', + association_foreign_key: 'education_academic_year_id' end def education_programs_as_administrator @@ -24,4 +32,9 @@ module University::Person::WithEducation .where(university_person_involvements: { person_id: id }) .distinct end + + def add_to_cohort(cohort) + cohorts << cohort unless cohort.in?(cohorts) + diploma_years << cohort.academic_year unless cohort.academic_year.in? diploma_years + end end diff --git a/db/migrate/20220427072259_create_join_table_university_people_education_academic_year.rb b/db/migrate/20220427072259_create_join_table_university_people_education_academic_year.rb new file mode 100644 index 0000000000000000000000000000000000000000..9e28fe6f4ad5b2a17ce45db7427dec8f3e7925d2 --- /dev/null +++ b/db/migrate/20220427072259_create_join_table_university_people_education_academic_year.rb @@ -0,0 +1,8 @@ +class CreateJoinTableUniversityPeopleEducationAcademicYear < ActiveRecord::Migration[6.1] + def change + create_join_table :university_people, :education_academic_years, column_options: {type: :uuid} do |t| + t.index [:"university_person_id", :"education_academic_year_id"], name: 'index_person_academic_year' + t.index [:"education_academic_year_id", :"university_person_id"], name: 'index_academic_year_person' + end + end +end diff --git a/db/schema.rb b/db/schema.rb index bf0583b11350e281eb844e4e6968bde0c0af469d..866a939b398a369a9a709e39135e936ba920dd10 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_04_25_152944) do +ActiveRecord::Schema.define(version: 2022_04_27_072259) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" @@ -407,6 +407,13 @@ ActiveRecord::Schema.define(version: 2022_04_25_152944) do t.index ["university_id"], name: "index_education_academic_years_on_university_id" end + create_table "education_academic_years_university_people", id: false, force: :cascade do |t| + t.uuid "university_person_id", null: false + t.uuid "education_academic_year_id", null: false + t.index ["education_academic_year_id", "university_person_id"], name: "index_academic_year_person" + t.index ["university_person_id", "education_academic_year_id"], name: "index_person_academic_year" + end + create_table "education_cohorts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.uuid "university_id", null: false t.uuid "program_id", null: false