From a339cb35e7f561e12656a53faa85319fb2201fb1 Mon Sep 17 00:00:00 2001 From: pabois <pierreandre.boissinot@noesya.coop> Date: Mon, 23 May 2022 18:14:52 +0200 Subject: [PATCH] wip refont imports --- Gemfile | 1 + Gemfile.lock | 4 + .../organizations/imports_controller.rb | 17 ++-- app/models/import.rb | 86 +++++++++++++++++++ app/models/university.rb | 2 + .../with_people_and_organizations.rb | 10 --- .../admin/university/organizations/imports.rb | 13 +++ app/services/importers/base.rb | 59 +++++++++++++ app/services/importers/organizations.rb | 83 ++++++++++++++++++ app/views/admin/imports/_list.html.erb | 22 +++++ app/views/admin/imports/show.html.erb | 27 ++++++ .../admin/university/alumni/index.html.erb | 4 +- .../organizations/imports/index.html.erb | 23 ++--- .../organizations/imports/new.html.erb | 14 +-- .../organizations/imports/show.html.erb | 5 -- .../university/organizations/index.html.erb | 4 +- config/initializers/delayed_jobs.rb | 5 ++ config/locales/en.yml | 32 ++++++- config/locales/fr.yml | 32 ++++++- config/locales/university/en.yml | 6 +- config/locales/university/fr.yml | 6 +- db/migrate/20220523102030_create_imports.rb | 13 +++ db/schema.rb | 26 +++--- 23 files changed, 419 insertions(+), 75 deletions(-) create mode 100644 app/models/import.rb create mode 100644 app/services/filters/admin/university/organizations/imports.rb create mode 100644 app/services/importers/base.rb create mode 100644 app/services/importers/organizations.rb create mode 100644 app/views/admin/imports/_list.html.erb create mode 100644 app/views/admin/imports/show.html.erb delete mode 100644 app/views/admin/university/organizations/imports/show.html.erb create mode 100644 config/initializers/delayed_jobs.rb create mode 100644 db/migrate/20220523102030_create_imports.rb diff --git a/Gemfile b/Gemfile index b01ab29ad..74724d81f 100644 --- a/Gemfile +++ b/Gemfile @@ -39,6 +39,7 @@ gem 'pg', '~> 1.1' gem 'puma' gem 'rails', '~> 6.1' gem 'rails-i18n' +gem "roo", "~> 2.9" gem 'sanitize' gem 'sassc-rails' gem 'sib-api-v3-sdk' diff --git a/Gemfile.lock b/Gemfile.lock index e76deb9ae..3ee382ac0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -381,6 +381,9 @@ GEM actionpack (>= 5.0) railties (>= 5.0) rexml (3.2.5) + roo (2.9.0) + nokogiri (~> 1) + rubyzip (>= 1.3.0, < 3.0.0) rotp (6.2.0) ruby-saml (1.14.0) nokogiri (>= 1.10.5) @@ -523,6 +526,7 @@ DEPENDENCIES rack-mini-profiler (~> 2.0) rails (~> 6.1) rails-i18n + roo (~> 2.9) sanitize sassc-rails selenium-webdriver diff --git a/app/controllers/admin/university/organizations/imports_controller.rb b/app/controllers/admin/university/organizations/imports_controller.rb index 608d208ac..31b2f8b3e 100644 --- a/app/controllers/admin/university/organizations/imports_controller.rb +++ b/app/controllers/admin/university/organizations/imports_controller.rb @@ -1,14 +1,18 @@ class Admin::University::Organizations::ImportsController < Admin::University::ApplicationController - load_and_authorize_resource class: University::Organization::Import, + load_and_authorize_resource class: Import, through: :current_university, - through_association: :organization_imports + through_association: :imports + + has_scope :for_status def index + @imports = apply_scopes(@imports.kind_organizations).ordered.page(params[:page]) breadcrumb end def show breadcrumb + render 'admin/imports/show' end def new @@ -16,11 +20,14 @@ class Admin::University::Organizations::ImportsController < Admin::University::A end def create + @import.kind = :organizations @import.university = current_university @import.user = current_user if @import.save - redirect_to [:admin, @import], notice: "Import was successfully created." + redirect_to admin_university_organizations_import_path(@import), + notice: t('admin.successfully_created_html', model: @import.to_s) else + breadcrumb render :new, status: :unprocessable_entity end end @@ -31,7 +38,7 @@ class Admin::University::Organizations::ImportsController < Admin::University::A super add_breadcrumb University::Organization.model_name.human(count: 2), admin_university_organizations_path - add_breadcrumb University::Organization::Import.model_name.human(count: 2), + add_breadcrumb Import.model_name.human(count: 2), admin_university_organizations_imports_path return unless @import @import.persisted? ? add_breadcrumb(@import, admin_university_organizations_import_path(@import)) @@ -39,7 +46,7 @@ class Admin::University::Organizations::ImportsController < Admin::University::A end def import_params - params.require(:university_organization_import) + params.require(:import) .permit(:file) end end diff --git a/app/models/import.rb b/app/models/import.rb new file mode 100644 index 000000000..0d1181faa --- /dev/null +++ b/app/models/import.rb @@ -0,0 +1,86 @@ +# == Schema Information +# +# Table name: imports +# +# id :uuid not null, primary key +# kind :integer +# number_of_lines :integer +# processing_errors :jsonb +# status :integer default("pending") +# created_at :datetime not null +# updated_at :datetime not null +# university_id :uuid not null, indexed +# user_id :uuid not null, indexed +# +# Indexes +# +# index_imports_on_university_id (university_id) +# index_imports_on_user_id (user_id) +# +# Foreign Keys +# +# fk_rails_42cc64a226 (university_id => universities.id) +# fk_rails_b1e2154c26 (user_id => users.id) +# +class Import < ApplicationRecord + belongs_to :university + belongs_to :user + + has_one_attached_deletable :file + + + enum kind: { organizations: 0, alumni: 1 }, _prefix: :kind + enum status: { pending: 0, finished: 1, finished_with_errors: 2 } + + validate :file_validation + + after_create :queue_for_processing + after_commit :send_mail_to_creator, on: :update, if: :status_changed_from_pending? + + scope :for_status, -> (status) { where(status: status) } + scope :ordered, -> { order('created_at DESC') } + + def to_s + I18n.l created_at, format: :date_with_hour + end + + def status_class + return 'text-danger' if finished_with_errors? + return 'text-info' if finished? + return '' + end + + # Setter to serialize data as JSON + def processing_errors=(value) + value = JSON.parse value if value.is_a? String + super(value) + end + + private + + def file_validation + if file.attached? + unless file.blob.content_type == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + file.purge if persisted? + errors.add(:file, :incorrect_type) + end + else + errors.add(:file, :no_file) + end + end + + def queue_for_processing + "Importers::#{kind.capitalize}".constantize.delay(queue: 'imports', priority: 100).execute(self) + end + + def send_mail_to_creator + # TODO + # ImportsMailer.companies(self).deliver_later + end + + def status_changed_from_pending? + saved_change_to_status? && status_before_last_save == 'pending' + end + + +end diff --git a/app/models/university.rb b/app/models/university.rb index 67325b683..8780933af 100644 --- a/app/models/university.rb +++ b/app/models/university.rb @@ -41,6 +41,8 @@ class University < ApplicationRecord # We use after_destroy to let the attachment go first has_many :active_storage_blobs, class_name: 'ActiveStorage::Blob' + has_many :imports, dependent: :destroy + validates_presence_of :name validates :sms_sender_name, presence: true, length: { maximum: 11 } diff --git a/app/models/university/with_people_and_organizations.rb b/app/models/university/with_people_and_organizations.rb index ad18670f9..d543dcbc3 100644 --- a/app/models/university/with_people_and_organizations.rb +++ b/app/models/university/with_people_and_organizations.rb @@ -12,15 +12,5 @@ module University::WithPeopleAndOrganizations dependent: :destroy alias_attribute :organizations, :university_organizations - has_many :university_organization_imports, - class_name: 'University::Organization::Import', - dependent: :destroy - alias_attribute :organization_imports, :university_organization_imports - - has_many :university_person_alumnus_imports, - class_name: 'University::Person::Alumnus::Import', - dependent: :destroy - alias_attribute :person_alumnus_imports, :university_person_alumnus_imports - alias_attribute :alumnus_imports, :university_person_alumnus_imports end end diff --git a/app/services/filters/admin/university/organizations/imports.rb b/app/services/filters/admin/university/organizations/imports.rb new file mode 100644 index 000000000..c0dc57631 --- /dev/null +++ b/app/services/filters/admin/university/organizations/imports.rb @@ -0,0 +1,13 @@ +module Filters + class Admin::University::Organizations::Imports < Filters::Base + def initialize(user) + super + add :for_status, + ::Import::statuses.keys.map { |r| { to_s: I18n.t("enums.import.status.#{r}"), id: r } }, + I18n.t( + 'filters.attributes.element', + element: Import.human_attribute_name('status').downcase + ) + end + end +end diff --git a/app/services/importers/base.rb b/app/services/importers/base.rb new file mode 100644 index 000000000..45b317bd6 --- /dev/null +++ b/app/services/importers/base.rb @@ -0,0 +1,59 @@ +module Importers + class Base + def self.execute(import) + new(import) + end + + def initialize(import) + @import = import + @university = import.university + @errors = [] + analyze_xlsx + manage_errors + save + end + + protected + + def xlsx + return @xlsx if defined?(@xlsx) + @xlsx = Roo::Spreadsheet.open(@import.file.url, extension: :xlsx) + begin @xlsx.info + # ensure we can access basic infos on the excel file. If not the file was incorrect + rescue + add_error("Unable to analyse the xlsx file", 0) + @xlsx = nil + end + end + + def analyze_xlsx + xlsx.each.with_index do |hash, index| + next if index == 0 # Column labels + analyze_hash(hash, index) + end if xlsx + end + + def analyze_hash(hash, index) + raise NotImplementedError + end + + def add_error(error, line) + @errors << { line: line, error: error } + end + + def manage_errors + if @errors.count > 0 + @import.status = :finished_with_errors + @import.processing_errors = @errors + else + @import.status = :finished + end + end + + def save + @import.number_of_lines = xlsx.nil? ? 0 : xlsx.count - 1 + @import.save + end + end + +end diff --git a/app/services/importers/organizations.rb b/app/services/importers/organizations.rb new file mode 100644 index 000000000..ecbb55d66 --- /dev/null +++ b/app/services/importers/organizations.rb @@ -0,0 +1,83 @@ +module Importers + class Organizations < Base + + protected + + def analyze_hash(hash, index) + hash_to_organization = HashToOrganization.new(@university, hash) + add_error(hash_to_organization.error, index + 1) unless hash_to_organization.valid? + end + + end + + class HashToOrganization + def initialize(university, hash) + @university = university + @hash = hash + @error = nil + extract_variables + save if valid? + end + + def valid? + if country_not_found? + @error = "Country #{@country} not found" + elsif !organization.valid? + @error = "Unable to create the organization: #{organization.errors.full_messages}" + end + @error.nil? + end + + def error + @error + end + + def organization_name + @organization_name ||= @hash[0].to_s.strip + end + + protected + + def extract_variables + @long_name = @hash[1].to_s.strip + @kind = @hash[2].to_s.strip + @siren = @hash[3].to_s.strip + @nic = @hash[4].to_s.strip + @description = @hash[5].to_s.strip + @address = @hash[6].to_s.strip + @zipcode = @hash[7].to_s.strip + @city = @hash[8].to_s.strip + @country = @hash[9].to_s.strip + @email = @hash[10].to_s.strip + @phone = @hash[11].to_s.strip + @url = @hash[12].to_s.strip + end + + def country_not_found? + ISO3166::Country[@country].nil? + end + + def organization + unless @organization + @organization = University::Organization.where(university_id: @university.id, name: organization_name).first_or_initialize + @organization.long_name = @long_name + @organization.kind = @kind.to_sym + @organization.siren = @siren + @organization.nic = @nic + @organization.description = @description + @organization.address = @address + @organization.zipcode = @zipcode + @organization.city = @city + @organization.country = @country + @organization.email = @email + @organization.phone = @phone + @organization.url = @url + end + @organization + end + + def save + organization.save + end + end +end diff --git a/app/views/admin/imports/_list.html.erb b/app/views/admin/imports/_list.html.erb new file mode 100644 index 000000000..91a993564 --- /dev/null +++ b/app/views/admin/imports/_list.html.erb @@ -0,0 +1,22 @@ +<table class="<%= table_classes %>"> + <thead> + <tr> + <th><%= Import.human_attribute_name('date') %></th> + <th><%= Import.human_attribute_name('number_of_lines') %></th> + <th><%= Import.human_attribute_name('status') %></th> + <th><%= Import.human_attribute_name('file') %></th> + </tr> + </thead> + <tbody> + <% imports.each do |import| %> + <tr> + <td><%= link_to import, send(path_pattern, import) %></td> + <td><%= import.number_of_lines %></td> + <td class="<%= import.status_class %>"><%= t("enums.import.status.#{import.status}") %></td> + <td><%= link_to t('download'), url_for(import.file), class: button_classes if import.file.attached? %></td> + </tr> + <% end %> + </tbody> +</table> + +<%= paginate imports, theme: 'bootstrap-5' %> diff --git a/app/views/admin/imports/show.html.erb b/app/views/admin/imports/show.html.erb new file mode 100644 index 000000000..468671382 --- /dev/null +++ b/app/views/admin/imports/show.html.erb @@ -0,0 +1,27 @@ +<% content_for :title, @import.to_s %> + +<div class="row"> + <div class="col-md-6"> + <p><%= t('imports.initiated_by') %> <%= link_to_if can?(:read, @import.user), @import.user, [:admin, @import.user] %></p> + <% if @import.file.attached? %> + <p><%= link_to t('download_with_size', size: number_to_human_size(@import.file.byte_size)), url_for(@import.file), class: button_classes %></p> + <% end %> + </div> + <div class="col-md-6"> + <h2><%= t('imports.status') %> <span class="<%= @import.status_class %>"><%= t("enums.import.status.#{@import.status}") %></span></h2> + <% unless @import.pending? %> + <p><%= t('imports.number_of_lines') %> <%= @import.number_of_lines %></p> + <% end %> + <% if @import.pending? && @import.user == current_user %> + <p><%= t('imports.still_pending') %></p> + <% end %> + <% if @import.finished_with_errors? %> + <h3><%= t('imports.errors') %></h3> + <ul> + <% @import.processing_errors.each do |obj| %> + <li><%= t('imports.error_msg', line: obj['line'], error: obj['error']) %></li> + <% end %> + </ul> + <% end %> + </div> +</div> diff --git a/app/views/admin/university/alumni/index.html.erb b/app/views/admin/university/alumni/index.html.erb index 6db0169c7..a9bd4f7f8 100644 --- a/app/views/admin/university/alumni/index.html.erb +++ b/app/views/admin/university/alumni/index.html.erb @@ -7,9 +7,9 @@ <%= paginate @alumni, theme: 'bootstrap-5' %> <% content_for :action_bar_left do %> - <%= link_to t('import'), + <%= link_to t('import_btn'), new_admin_university_alumni_import_path, - class: button_classes if can? :manage, University::Person::Alumnus::Import %> + class: button_classes if can? :create, University::Person::Alumnus %> <% end %> <% content_for :action_bar_right do %> diff --git a/app/views/admin/university/organizations/imports/index.html.erb b/app/views/admin/university/organizations/imports/index.html.erb index 898580ffa..5b504270c 100644 --- a/app/views/admin/university/organizations/imports/index.html.erb +++ b/app/views/admin/university/organizations/imports/index.html.erb @@ -1,24 +1,11 @@ -<% content_for :title, University::Organization::Import.model_name.human(count: 2) %> +<% content_for :title, Import.model_name.human(count: 2) %> -<table class="<%= table_classes %>"> - <thead> - <tr> - <th><%= University::Organization::Import.human_attribute_name('name') %></th> - <th><%= University::Organization::Import.human_attribute_name('lines') %></th> - </tr> - </thead> - <tbody> - <% @imports.each do |import| %> - <tr> - <td><%= link_to import, admin_university_organizations_import_path(import) %></td> - <td><%= import.lines %></td> - </tr> - <% end %> - </tbody> -</table> +<%= render 'filters', current_path: admin_university_organizations_imports_path, filters: @filters if @filters.any? %> + +<%= render 'admin/imports/list', imports: @imports, path_pattern: 'admin_university_organizations_import_path' %> <% content_for :action_bar_right do %> - <%= link_to_if can?(:create, University::Organization::Import), + <%= link_to_if can?(:create, University::Organization), t('create'), new_admin_university_organizations_import_path, class: button_classes %> diff --git a/app/views/admin/university/organizations/imports/new.html.erb b/app/views/admin/university/organizations/imports/new.html.erb index 579fe470d..2ff9088b4 100644 --- a/app/views/admin/university/organizations/imports/new.html.erb +++ b/app/views/admin/university/organizations/imports/new.html.erb @@ -1,21 +1,21 @@ -<% content_for :title, University::Organization::Import.model_name.human %> +<% content_for :title, Import.model_name.human %> <div class="row"> <div class="col-md-6"> <p> - Les données doivent être au format csv, comme l'exemple suivant.<br> - La première ligne doit être dédiée aux entêtes.<br> - Les noms des entêtes sont obligatoires et doivent être respectés strictement.<br> - Le champ name est obligatoire.<br> - Les caractères doivent être encodés en UTF-8.<br> - Les valeurs possibles pour kind sont : company, non_profit, government. + <%= t('imports.hint_html') %> + <br> + <%= t('university.import_hint_html') %> </p> <%= simple_form_for @import, url: admin_university_organizations_imports_path do |f| %> + <%# 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.error_notification %> <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %> <%= f.input :file %> + <% content_for :action_bar_right do %> <%= submit f %> <% end %> diff --git a/app/views/admin/university/organizations/imports/show.html.erb b/app/views/admin/university/organizations/imports/show.html.erb deleted file mode 100644 index 179493a22..000000000 --- a/app/views/admin/university/organizations/imports/show.html.erb +++ /dev/null @@ -1,5 +0,0 @@ -<% content_for :title, @import %> - -<%= link_to "#{@import.file.filename} (#{number_to_human_size @import.file.byte_size})", - url_for(@import.file), - class: button_classes %> diff --git a/app/views/admin/university/organizations/index.html.erb b/app/views/admin/university/organizations/index.html.erb index ad22a22de..d578aa1d6 100644 --- a/app/views/admin/university/organizations/index.html.erb +++ b/app/views/admin/university/organizations/index.html.erb @@ -6,9 +6,9 @@ <%= paginate @organizations, theme: 'bootstrap-5' %> <% content_for :action_bar_left do %> - <%= link_to t('import'), + <%= link_to t('import_btn'), new_admin_university_organizations_import_path, - class: button_classes if can? :manage, University::Organization::Import %> + class: button_classes if can? :create, University::Organization %> <% end %> <% content_for :action_bar_right do %> diff --git a/config/initializers/delayed_jobs.rb b/config/initializers/delayed_jobs.rb new file mode 100644 index 000000000..1ed52dd7c --- /dev/null +++ b/config/initializers/delayed_jobs.rb @@ -0,0 +1,5 @@ +Delayed::Worker.queue_attributes = { + high_priority: { priority: -10 }, + low_priority: { priority: 10 }, + imports: { priority: 5 } +} diff --git a/config/locales/en.yml b/config/locales/en.yml index f4364a70e..ae85766c0 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,6 +1,11 @@ en: activerecord: attributes: + import: + date: Date + file: File + number_of_lines: Number of lines + status: Status language: iso_code: Iso code name: Name @@ -26,11 +31,19 @@ en: websites_to_manage: Websites managed errors: models: + import: + attributes: + file: + incorrect_type: type is incorrect + no_file: must be selected user: attributes: password: password_strength: doesn't match the security policy models: + import: + one: Import + other: Imports language: one: Language other: Languages @@ -99,7 +112,14 @@ en: send_email_code: 'Send me a code via email' success: "" download: Download + download_with_size: Download (%{size}) edit: Edit + enums: + import: + status: + finished: Finished + finished_with_errors: Finished with errors + pending: Pending false: No featured_image: title: Image @@ -127,7 +147,15 @@ en: privacy_policy: https://osuny.org/politique-de-confidentialite hello: "Hello %{name}!" home: Home - import: Import + import: + error_msg: "Line %{line}: %{error}" + errors: Errors + hint_html: "File must be an .xlsx excel file.<br>The first line must contain the headers.<br>The hearders are mandatory and must be strictly respected.<br>All characters must be encoded as UTF-8." + initiated_by: "Initiated by:" + number_of_lines: "Number of lines in the file:" + status: "Status:" + still_pending: "Your import has not been processed yet. You will receive an email as soon as it's ready." + import_btn: Import inactivity_alert: "It seems you have been away a little bit too long. Could you please retry?" languages: en: English @@ -166,6 +194,8 @@ en: error_notification: default_message: "Please review the problems below:" hints: + import: + file: .xlsx file only user: mobile_phone: "International format (+XX). By filling this field, you accept to receive your two-factor authentication codes via SMS." include_blanks: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 623e0d9cd..e034e354a 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1,6 +1,11 @@ fr: activerecord: attributes: + import: + date: Date + file: Fichier + number_of_lines: Nombre de lignes + status: Status language: iso_code: Code Iso name: Nom @@ -26,11 +31,19 @@ fr: websites_to_manage: Sites gérés errors: models: + import: + attributes: + file: + incorrect_type: n'est pas au bon format + no_file: doit être choisi user: attributes: password: password_strength: ne répond pas aux critères de sécurité models: + import: + one: Import + other: Imports language: one: Langue other: Langues @@ -99,7 +112,14 @@ fr: send_email_code: 'Envoyer le code par email' success: "" download: Télécharger + download_with_size: Télécharger (%{size}) edit: Modifier + enums: + import: + status: + finished: Traité + finished_with_errors: Traité avec des erreurs + pending: En cours de traitement false: Non featured_image: title: Image @@ -127,7 +147,15 @@ fr: privacy_policy: https://osuny.org/politique-de-confidentialite hello: "Bonjour %{name} !" home: Accueil - import: Importer + imports: + error_msg: "Ligne %{line} : %{error}" + errors: Erreurs + hint_html: "Les données doivent être au format xlsx.<br>La première ligne doit être dédiée aux entêtes.<br>Les noms des entêtes sont obligatoires et doivent être respectés strictement.<br>Les caractères doivent être encodés en UTF-8." + initiated_by: "Initié par :" + number_of_lines: "Nombre de lignes dans le fichier :" + status: "Status :" + still_pending: "Votre import est toujours en cours de traitement. Vous recevrez un email dès qu'il est prêt." + import_btn: Importer inactivity_alert: "Il semble que vous soyez resté sur la page un peu trop longtemps. Pouvez-vous ré-essayer ?" languages: en: Anglais @@ -166,6 +194,8 @@ fr: error_notification: default_message: "Les erreurs ci-dessous empêchent la validation :" hints: + import: + file: Fichier .xlsx uniquement user: mobile_phone: "Format international (+XX). En renseignant ce champ, vous acceptez de recevoir vos codes de double authentification par SMS." include_blanks: diff --git a/config/locales/university/en.yml b/config/locales/university/en.yml index 0b9428754..be8382d7d 100644 --- a/config/locales/university/en.yml +++ b/config/locales/university/en.yml @@ -77,8 +77,6 @@ en: email: Email kind: Kind siren: Legal identification number - university/organization/import: - file: File (.csv) university/role: description: Description people: People @@ -107,9 +105,6 @@ en: university/organization: one: Organization other: Organizations - university/organization/import: - one: Import - other: Imports university/role: one: Role other: Roles @@ -142,6 +137,7 @@ en: non_profit: Association government: Government university: + import_hint_html: "Name field is mandatory.<br>Possible values for kind are: company, non_profit, government.<br>Siren, nic, zipcode and phone fields must have a text format, not numbers.<br>Country field must contain the ISO 3166 code of the country, so to upcase characters (<a href=\"https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes\" target=\_blank\">list</a>)" internal_key: Internal Key invoice_informations: Invoice informations manage_alumni: Manage alumni diff --git a/config/locales/university/fr.yml b/config/locales/university/fr.yml index 9cb44fa03..38e9bf9f6 100644 --- a/config/locales/university/fr.yml +++ b/config/locales/university/fr.yml @@ -77,8 +77,6 @@ fr: email: Email kind: Type siren: Numéro de SIREN - university/organization/import: - file: Fichier (.csv) university/role: description: Description people: Personnes @@ -107,9 +105,6 @@ fr: university/organization: one: Organisation other: Organisations - university/organization/import: - one: Import - other: Imports university/role: one: Rôle other: Rôles @@ -142,6 +137,7 @@ fr: non_profit: Association government: Structure gouvernementale university: + import_hint_html: "Le champ name est obligatoire.<br>Les valeurs possibles pour kind sont : company, non_profit, government.<br>Les champs siren, nic, zipcode et phone doivent être au format texte, pas nombre.<br>Le champ pays 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>)" internal_key: Clé interne invoice_informations: Données de facturation manage_alumni: Gérer les alumni diff --git a/db/migrate/20220523102030_create_imports.rb b/db/migrate/20220523102030_create_imports.rb new file mode 100644 index 000000000..652737036 --- /dev/null +++ b/db/migrate/20220523102030_create_imports.rb @@ -0,0 +1,13 @@ +class CreateImports < ActiveRecord::Migration[6.1] + def change + create_table :imports, id: :uuid do |t| + t.integer :number_of_lines + t.jsonb :processing_errors + t.integer :kind + t.integer :status, default: 0 + t.references :university, null: false, foreign_key: true, type: :uuid + t.references :user, null: false, foreign_key: true, type: :uuid + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 51b0235db..f00d75039 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_05_19_100506) do +ActiveRecord::Schema.define(version: 2022_05_23_102030) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" @@ -502,21 +502,17 @@ ActiveRecord::Schema.define(version: 2022_05_19_100506) do t.index ["university_id"], name: "index_education_schools_on_university_id" end - create_table "external_organizations", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.string "title" - t.text "description" - t.string "address" - t.string "zipcode" - t.string "city" - t.string "country" - t.string "website" - t.string "phone" - t.string "mail" - t.boolean "active" - t.string "sirene" + create_table "imports", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.integer "number_of_lines" + t.jsonb "processing_errors" t.integer "kind" + t.integer "status", default: 0 + t.uuid "university_id", null: false + t.uuid "user_id", null: false t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false + t.index ["university_id"], name: "index_imports_on_university_id" + t.index ["user_id"], name: "index_imports_on_user_id" end create_table "languages", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| @@ -709,8 +705,8 @@ ActiveRecord::Schema.define(version: 2022_05_19_100506) do t.string "linkedin" t.boolean "is_alumnus", default: false t.text "description_short" - t.string "name" t.boolean "is_author" + t.string "name" t.index ["university_id"], name: "index_university_people_on_university_id" t.index ["user_id"], name: "index_university_people_on_user_id" end @@ -858,6 +854,8 @@ ActiveRecord::Schema.define(version: 2022_05_19_100506) do add_foreign_key "education_programs", "education_programs", column: "parent_id" add_foreign_key "education_programs", "universities" add_foreign_key "education_schools", "universities" + add_foreign_key "imports", "universities" + add_foreign_key "imports", "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" -- GitLab