From 7257ff63b008cbccd4d08889c41304fb643072a4 Mon Sep 17 00:00:00 2001 From: pabois <pierreandre.boissinot@noesya.coop> Date: Fri, 27 Oct 2023 17:11:48 +0200 Subject: [PATCH] add importer for people --- .../university/people/imports_controller.rb | 52 +++++++++ app/models/communication/extranet.rb | 57 +++++----- app/models/import.rb | 2 +- app/services/importers/cleaner.rb | 2 +- app/services/importers/hash_to_cohort.rb | 6 +- app/services/importers/hash_to_experience.rb | 20 ++-- app/services/importers/hash_to_person.rb | 2 + .../importers/{person.rb => people.rb} | 3 +- .../alumni/cohorts/imports/new.html.erb | 4 + .../people/experiences/imports/new.html.erb | 4 + .../university/people/imports/index.html.erb | 12 ++ .../university/people/imports/new.html.erb | 107 ++++++++++++++++++ .../admin/university/people/index.html.erb | 3 + config/locales/university/en.yml | 16 +-- config/locales/university/fr.yml | 16 +-- config/routes/admin/university.rb | 12 +- db/schema.rb | 5 +- test/fixtures/communication/extranets.yml | 57 +++++----- 18 files changed, 286 insertions(+), 94 deletions(-) create mode 100644 app/controllers/admin/university/people/imports_controller.rb rename app/services/importers/{person.rb => people.rb} (89%) create mode 100644 app/views/admin/university/people/imports/index.html.erb create mode 100644 app/views/admin/university/people/imports/new.html.erb diff --git a/app/controllers/admin/university/people/imports_controller.rb b/app/controllers/admin/university/people/imports_controller.rb new file mode 100644 index 000000000..1fb35d64c --- /dev/null +++ b/app/controllers/admin/university/people/imports_controller.rb @@ -0,0 +1,52 @@ +class Admin::University::People::ImportsController < Admin::University::ApplicationController + load_and_authorize_resource class: Import, + through: :current_university, + through_association: :imports + + has_scope :for_status + + def index + @imports = apply_scopes(@imports.kind_people).ordered.page(params[:page]) + breadcrumb + end + + def show + breadcrumb + render 'admin/imports/show' + end + + def new + breadcrumb + end + + def create + @import.kind = :people + @import.university = current_university + @import.user = current_user + if @import.save + redirect_to admin_university_people_import_path(@import), + notice: t('admin.successfully_created_html', model: @import.to_s) + else + breadcrumb + render :new, status: :unprocessable_entity + end + end + + protected + + def breadcrumb + super + add_breadcrumb University::Person.model_name.human(count: 2), + admin_university_people_path + add_breadcrumb Import.model_name.human(count: 2), + admin_university_people_imports_path + return unless @import + @import.persisted? ? add_breadcrumb(@import, admin_university_people_import_path(@import)) + : add_breadcrumb(t('create')) + end + + def import_params + params.require(:import) + .permit(:file) + end +end diff --git a/app/models/communication/extranet.rb b/app/models/communication/extranet.rb index 0dc316363..1a4615b3d 100644 --- a/app/models/communication/extranet.rb +++ b/app/models/communication/extranet.rb @@ -2,34 +2,35 @@ # # Table name: communication_extranets # -# id :uuid not null, primary key -# about_type :string indexed => [about_id] -# color :string -# cookies_policy :text -# css :text -# feature_alumni :boolean default(FALSE) -# feature_contacts :boolean default(FALSE) -# feature_jobs :boolean default(FALSE) -# feature_library :boolean default(FALSE) -# feature_posts :boolean default(FALSE) -# has_sso :boolean default(FALSE) -# home_sentence :text -# host :string -# name :string -# privacy_policy :text -# registration_contact :string -# sass :text -# sso_button_label :string -# sso_cert :text -# sso_mapping :jsonb -# sso_name_identifier_format :string -# sso_provider :integer default("saml") -# sso_target_url :string -# terms :text -# created_at :datetime not null -# updated_at :datetime not null -# about_id :uuid indexed => [about_type] -# university_id :uuid not null, indexed +# id :uuid not null, primary key +# about_type :string indexed => [about_id] +# allow_experiences_modification :boolean default(TRUE) +# color :string +# cookies_policy :text +# css :text +# feature_alumni :boolean default(FALSE) +# feature_contacts :boolean default(FALSE) +# feature_jobs :boolean default(FALSE) +# feature_library :boolean default(FALSE) +# feature_posts :boolean default(FALSE) +# has_sso :boolean default(FALSE) +# home_sentence :text +# host :string +# name :string +# privacy_policy :text +# registration_contact :string +# sass :text +# sso_button_label :string +# sso_cert :text +# sso_mapping :jsonb +# sso_name_identifier_format :string +# sso_provider :integer default("saml") +# sso_target_url :string +# terms :text +# created_at :datetime not null +# updated_at :datetime not null +# about_id :uuid indexed => [about_type] +# university_id :uuid not null, indexed # # Indexes # diff --git a/app/models/import.rb b/app/models/import.rb index 6e4c56d27..9fab30626 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -28,7 +28,7 @@ class Import < ApplicationRecord has_one_attached_deletable :file - enum kind: { organizations: 0, alumni_cohorts: 1, people_experiences: 2 }, _prefix: :kind + enum kind: { organizations: 0, alumni_cohorts: 1, people_experiences: 2, people: 3 }, _prefix: :kind enum status: { pending: 0, finished: 1, finished_with_errors: 2 } validate :file_validation diff --git a/app/services/importers/cleaner.rb b/app/services/importers/cleaner.rb index ac6cf93f2..a240a2dba 100644 --- a/app/services/importers/cleaner.rb +++ b/app/services/importers/cleaner.rb @@ -54,7 +54,7 @@ module Importers def self.remove_control_chars(string) # Control chars & LSEP are invisible or hard to detect - string = string.delete("
", "
", "
", "Â’") + string = string.delete("", "
", "
", "Â’") string = string.gsub /\u2028/, '' string end diff --git a/app/services/importers/hash_to_cohort.rb b/app/services/importers/hash_to_cohort.rb index 8cd20a98f..086a6b138 100644 --- a/app/services/importers/hash_to_cohort.rb +++ b/app/services/importers/hash_to_cohort.rb @@ -28,9 +28,9 @@ module Importers protected def extract_variables - @school_id = @hash[17].to_s.strip - @program_id = @hash[18].to_s.strip - @year = @hash[19].to_s.strip.to_i + @school_id = @hash[18].to_s.strip + @program_id = @hash[19].to_s.strip + @year = @hash[20].to_s.strip.to_i end def school diff --git a/app/services/importers/hash_to_experience.rb b/app/services/importers/hash_to_experience.rb index 6c3604a92..551c8a250 100644 --- a/app/services/importers/hash_to_experience.rb +++ b/app/services/importers/hash_to_experience.rb @@ -24,12 +24,12 @@ module Importers protected def extract_variables - @company_name = @hash[17].to_s.strip - @company_siren = @hash[18].to_s.strip - @company_nic = @hash[19].to_s.strip - @experience_job = @hash[20].to_s.strip - @experience_from = @hash[21].to_s.strip - @experience_to = @hash[22].to_s.strip + @company_name = @hash[18].to_s.strip + @company_siren = @hash[19].to_s.strip + @company_nic = @hash[20].to_s.strip + @experience_job = @hash[21].to_s.strip + @experience_from = @hash[22].to_s.strip + @experience_to = @hash[23].to_s.strip end def experience @@ -51,19 +51,19 @@ module Importers # Search by SIREN+NIC, then SIREN, then name, or create it with everything if @company_siren.present? && @company_nic.present? obj = @university.organizations - .for_language_id(current_university.default_language_id) + .for_language_id(@university.default_language_id) .find_by siren: @company_siren, nic: @company_nic elsif @company_siren.present? obj = @university.organizations - .for_language_id(current_university.default_language_id) + .for_language_id(@university.default_language_id) .find_by siren: @company_siren end obj ||= @university.organizations - .for_language_id(current_university.default_language_id) + .for_language_id(@university.default_language_id) .find_by name: @company_name obj ||= @university.organizations - .for_language_id(current_university.default_language_id) + .for_language_id(@university.default_language_id) .where( name: @company_name, siren: @company_siren, nic: @company_nic) diff --git a/app/services/importers/hash_to_person.rb b/app/services/importers/hash_to_person.rb index 273b9394d..d5f1ce568 100644 --- a/app/services/importers/hash_to_person.rb +++ b/app/services/importers/hash_to_person.rb @@ -48,6 +48,7 @@ module Importers @biography = @hash[14].to_s.strip @social_twitter = @hash[15].to_s.strip @social_linkedin = @hash[16].to_s.strip + @social_mastodon = @hash[17].to_s.strip end def build_person @@ -76,6 +77,7 @@ module Importers person.biography = @biography person.twitter = @social_twitter person.linkedin = @social_linkedin + person.mastodon = @social_mastodon person.slug = person.to_s.parameterize.dasherize person.language_id = @university.default_language_id person diff --git a/app/services/importers/person.rb b/app/services/importers/people.rb similarity index 89% rename from app/services/importers/person.rb rename to app/services/importers/people.rb index 90c3827b4..9d2574ca4 100644 --- a/app/services/importers/person.rb +++ b/app/services/importers/people.rb @@ -1,5 +1,5 @@ module Importers - class Person < Base + class People < Base protected @@ -9,5 +9,4 @@ module Importers end end - end diff --git a/app/views/admin/university/alumni/cohorts/imports/new.html.erb b/app/views/admin/university/alumni/cohorts/imports/new.html.erb index 41edf446a..b38a141fc 100644 --- a/app/views/admin/university/alumni/cohorts/imports/new.html.erb +++ b/app/views/admin/university/alumni/cohorts/imports/new.html.erb @@ -100,6 +100,10 @@ <th>social_linkedin</th> <td>https://www.linkedin.com/in/stephanedupond</td> </tr> + <tr> + <th>social_mastodon</th> + <td>https://mastodon.social/@stephanedupond</td> + </tr> <tr> <th>school*</th> <td>af96c31c-2e6b-4485-b88f-e28843480e3f</td> diff --git a/app/views/admin/university/people/experiences/imports/new.html.erb b/app/views/admin/university/people/experiences/imports/new.html.erb index 38a41bb96..5af71af2f 100644 --- a/app/views/admin/university/people/experiences/imports/new.html.erb +++ b/app/views/admin/university/people/experiences/imports/new.html.erb @@ -96,6 +96,10 @@ <th>social_linkedin</th> <td>https://www.linkedin.com/in/stephanedupond</td> </tr> + <tr> + <th>social_mastodon</th> + <td>https://mastodon.social/@stephanedupond</td> + </tr> <tr> <th>company_name</th> <td>Le Monde</td> diff --git a/app/views/admin/university/people/imports/index.html.erb b/app/views/admin/university/people/imports/index.html.erb new file mode 100644 index 000000000..405852395 --- /dev/null +++ b/app/views/admin/university/people/imports/index.html.erb @@ -0,0 +1,12 @@ +<% content_for :title, "#{University::Person.model_name.human(count: 2)}" %> + +<%= render 'filters', current_path: admin_university_people_imports_path, filters: @filters if @filters.any? %> + +<%= render 'admin/imports/list', imports: @imports, path_pattern: 'admin_university_people_import_path' %> + +<% content_for :action_bar_right do %> + <%= link_to_if can?(:create, University::Person), + t('create'), + new_admin_university_people_import_path, + class: button_classes %> +<% end %> diff --git a/app/views/admin/university/people/imports/new.html.erb b/app/views/admin/university/people/imports/new.html.erb new file mode 100644 index 000000000..00a3838d9 --- /dev/null +++ b/app/views/admin/university/people/imports/new.html.erb @@ -0,0 +1,107 @@ +<% content_for :title, Import.model_name.human %> + +<div class="row"> + <div class="col-md-6"> + <p> + <%= t('imports.hint_html') %> + <br> + <%= t('university.person.import_hint_html') %> + </p> + <%= simple_form_for @import, + url: admin_university_people_imports_path do |f| %> + + <%= f.error_notification %> + <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %> + + <%# as file can be empty the global object can be unset. To prevent crash in controller add an (unused) hidden field %> + <%= f.input :id, as: :hidden %> + + <%= f.input :file %> + + <% content_for :action_bar_right do %> + <%= submit f %> + <% end %> + <% end %> + + </div> + <div class="col-md-6"> + <div class="table-responsive"> + <table class="<%= table_classes %>"> + <tbody> + <tr> + <th>first_name*</th> + <td>Stéphane</td> + </tr> + <tr> + <th>last_name*</th> + <td>Dupond</td> + </tr> + <tr> + <th>gender</th> + <td>m</td> + </tr> + <tr> + <th>birth</th> + <td>2006-05-26</td> + </tr> + <tr> + <th>mail</th> + <td>stephane.dupond@gmail.com</td> + </tr> + <tr> + <th>photo</th> + <td>https://www.example.com/photo.jpg</td> + </tr> + <tr> + <th>url</th> + <td>https://www.stephanedupond.fr</td> + </tr> + <tr> + <th>phone_professional</th> + <td>+33 1 01 01 01 01</td> + </tr> + <tr> + <th>phone_personal</th> + <td>+33 1 01 01 01 01</td> + </tr> + <tr> + <th>mobile</th> + <td>+33 6 01 01 01 01</td> + </tr> + <tr> + <th>address</th> + <td>1 rue Jacques Ellul</td> + </tr> + <tr> + <th>zipcode</th> + <td>33000</td> + </tr> + <tr> + <th>city</th> + <td>Bordeaux</td> + </tr> + <tr> + <th>country</th> + <td>FR</td> + </tr> + <tr> + <th>biography</th> + <td>Product Designer</td> + </tr> + <tr> + <th>social_twitter</th> + <td>stephanedupond</td> + </tr> + <tr> + <th>social_linkedin</th> + <td>https://www.linkedin.com/in/stephanedupond</td> + </tr> + <tr> + <th>social_mastodon</th> + <td>https://mastodon.social/@stephanedupond</td> + </tr> + </tbody> + </table> + </div> + </div> +</div> diff --git a/app/views/admin/university/people/index.html.erb b/app/views/admin/university/people/index.html.erb index 6ef11496c..e2a06dd97 100644 --- a/app/views/admin/university/people/index.html.erb +++ b/app/views/admin/university/people/index.html.erb @@ -27,6 +27,9 @@ subtitle = t('admin.elements', count: @categories.total_count) <% end %> <% content_for :action_bar_left do %> + <%= link_to t('university.person.import_btn'), + new_admin_university_people_import_path, + class: button_classes if can? :create, University::Person %> <%= link_to t('university.person.experiences.import_btn'), new_admin_university_people_experiences_import_path, class: button_classes if can? :create, University::Person::Experience %> diff --git a/config/locales/university/en.yml b/config/locales/university/en.yml index 667271820..032c07762 100644 --- a/config/locales/university/en.yml +++ b/config/locales/university/en.yml @@ -158,6 +158,13 @@ en: university/role: one: Role other: Roles + enums: + university: + organization: + kind: + company: Company + non_profit: Association + government: Government simple_form: hints: university: @@ -195,13 +202,6 @@ en: organization: Select organization school: Select school year: Select year - enums: - university: - organization: - kind: - company: Company - non_profit: Association - government: Government university: alumni: cohorts: @@ -248,6 +248,8 @@ en: import_btn: Import experiences import_hint_html: "Possible values for <i>gender</i> are: m (male), f (female) and n (non binary).<br><i>Phone_professional</i>, <i>phone_personal</i>, <i>mobile</i> and <i>zipcode</i> fields must have a text format, not numbers.<br><i>Country</i> field must contain the ISO 3166 code of the country, so 2 upcase characters (<a href=\"https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes\" target=\_blank\">list</a>).<br><i>Social_twitter</i> field should have no @." title: Experiences imports + import_btn: Import people + import_hint_html: "Possible values for <i>gender</i> are: m (male), f (female) and n (non binary).<br><i>Phone_professional</i>, <i>phone_personal</i>, <i>mobile</i> and <i>zipcode</i> fields must have a text format, not numbers.<br><i>Country</i> field must contain the ISO 3166 code of the country, so 2 upcase characters (<a href=\"https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes\" target=\_blank\">list</a>).<br><i>Social_twitter</i> field should have no @." personal_data_warning: Warning! The information provided below can be publicly visible on the websites and the extranets about you. search: Search by name taught_programs: Taught programs diff --git a/config/locales/university/fr.yml b/config/locales/university/fr.yml index 7e71a8b68..407e8a7b0 100644 --- a/config/locales/university/fr.yml +++ b/config/locales/university/fr.yml @@ -158,6 +158,13 @@ fr: university/role: one: Rôle other: Rôles + enums: + university: + organization: + kind: + company: Entreprise + non_profit: Association + government: Structure gouvernementale simple_form: hints: university: @@ -195,13 +202,6 @@ fr: organization: Sélectionnez une organisation school: Sélectionnez une école year: Sélectionnez une année - enums: - university: - organization: - kind: - company: Entreprise - non_profit: Association - government: Structure gouvernementale university: alumni: cohorts: @@ -248,6 +248,8 @@ fr: import_btn: Importer des expériences import_hint_html: "Les valeurs pour <i>gender</i> peuvent être m (masculin), f (féminin) et n (non binaire).<br>Les champs <i>phone_professional</i>, <i>phone_personal</i>, <i>mobile</i> et <i>zipcode</i> doivent être au format texte, pas nombre.<br>Le champ <i>country</i> doit contenir le code ISO 3166 du pays, sur 2 caratères en majuscule (<a href=\"https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes\" target=\_blank\">liste</a>)<br>Le champ <i>social_twitter</i> ne doit pas contenir d'@." title: Imports d'expériences + import_btn: Importer des personnes + import_hint_html: "Les valeurs pour <i>gender</i> peuvent être m (masculin), f (féminin) et n (non binaire).<br>Les champs <i>phone_professional</i>, <i>phone_personal</i>, <i>mobile</i> et <i>zipcode</i> doivent être au format texte, pas nombre.<br>Le champ <i>country</i> doit contenir le code ISO 3166 du pays, sur 2 caratères en majuscule (<a href=\"https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes\" target=\_blank\">liste</a>)<br>Le champ <i>social_twitter</i> ne doit pas contenir d'@." search: Rechercher par nom de personne personal_data_warning: Attention ! Les informations renseignées ici sont susceptibles d'être visibles publiquement sur les sites web et les extranets vous concernant. taught_programs: Formations enseignées diff --git a/config/routes/admin/university.rb b/config/routes/admin/university.rb index 440e4fb71..37e56775a 100644 --- a/config/routes/admin/university.rb +++ b/config/routes/admin/university.rb @@ -17,6 +17,12 @@ namespace :university do patch 'cohorts' => 'alumni/cohorts#update' end end + namespace :people do + resources :imports, only: [:index, :show, :new, :create] + namespace :experiences do + resources :imports, only: [:index, :show, :new, :create] + end + end resources :people do collection do get :search, defaults: { format: 'json' } @@ -29,11 +35,7 @@ namespace :university do patch 'experiences' => 'people/experiences#update' end end - namespace :people do - namespace :experiences do - resources :imports, only: [:index, :show, :new, :create] - end - end + resources :organizations do collection do get :search, defaults: { format: 'json' } diff --git a/db/schema.rb b/db/schema.rb index 659e0ae39..6eb8a178c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -106,8 +106,8 @@ ActiveRecord::Schema[7.1].define(version: 2023_10_18_182341) do t.datetime "updated_at", null: false t.string "title" t.boolean "published", default: true - t.uuid "heading_id" t.uuid "communication_website_id" + t.uuid "heading_id" t.string "migration_identifier" t.index ["about_type", "about_id"], name: "index_communication_website_blocks_on_about" t.index ["communication_website_id"], name: "index_communication_blocks_on_communication_website_id" @@ -229,6 +229,7 @@ ActiveRecord::Schema[7.1].define(version: 2023_10_18_182341) do t.text "home_sentence" t.text "sass" t.text "css" + t.boolean "allow_experiences_modification", default: true t.index ["about_type", "about_id"], name: "index_communication_extranets_on_about" t.index ["university_id"], name: "index_communication_extranets_on_university_id" end @@ -390,7 +391,7 @@ ActiveRecord::Schema[7.1].define(version: 2023_10_18_182341) do t.index ["university_id"], name: "index_communication_website_pages_on_university_id" end - create_table "communication_website_permalinks", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t| + create_table "communication_website_permalinks", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.uuid "university_id", null: false t.uuid "website_id", null: false t.string "about_type", null: false diff --git a/test/fixtures/communication/extranets.yml b/test/fixtures/communication/extranets.yml index c4a725645..5b00f559b 100644 --- a/test/fixtures/communication/extranets.yml +++ b/test/fixtures/communication/extranets.yml @@ -2,34 +2,35 @@ # # Table name: communication_extranets # -# id :uuid not null, primary key -# about_type :string indexed => [about_id] -# color :string -# cookies_policy :text -# css :text -# feature_alumni :boolean default(FALSE) -# feature_contacts :boolean default(FALSE) -# feature_jobs :boolean default(FALSE) -# feature_library :boolean default(FALSE) -# feature_posts :boolean default(FALSE) -# has_sso :boolean default(FALSE) -# home_sentence :text -# host :string -# name :string -# privacy_policy :text -# registration_contact :string -# sass :text -# sso_button_label :string -# sso_cert :text -# sso_mapping :jsonb -# sso_name_identifier_format :string -# sso_provider :integer default("saml") -# sso_target_url :string -# terms :text -# created_at :datetime not null -# updated_at :datetime not null -# about_id :uuid indexed => [about_type] -# university_id :uuid not null, indexed +# id :uuid not null, primary key +# about_type :string indexed => [about_id] +# allow_experiences_modification :boolean default(TRUE) +# color :string +# cookies_policy :text +# css :text +# feature_alumni :boolean default(FALSE) +# feature_contacts :boolean default(FALSE) +# feature_jobs :boolean default(FALSE) +# feature_library :boolean default(FALSE) +# feature_posts :boolean default(FALSE) +# has_sso :boolean default(FALSE) +# home_sentence :text +# host :string +# name :string +# privacy_policy :text +# registration_contact :string +# sass :text +# sso_button_label :string +# sso_cert :text +# sso_mapping :jsonb +# sso_name_identifier_format :string +# sso_provider :integer default("saml") +# sso_target_url :string +# terms :text +# created_at :datetime not null +# updated_at :datetime not null +# about_id :uuid indexed => [about_type] +# university_id :uuid not null, indexed # # Indexes # -- GitLab