diff --git a/Gemfile b/Gemfile index 612a5bc28ebb7f29a3513dd5722e0d3d73a96c4a..63370895bb064f8f55e6fd88362e1ac62b1d9d79 100644 --- a/Gemfile +++ b/Gemfile @@ -27,6 +27,7 @@ gem "font-awesome-sass" gem "front_matter_parser" gem "gdpr" gem "geocoder", "~> 1.8" +gem "geo_point" gem "gitlab" gem "hal_openscience", "~> 0.1" # gem "hal_openscience", path: "../hal_openscience" @@ -38,6 +39,7 @@ gem "jquery-rails" gem "jquery-ui-rails", "~> 6.0.1" gem "kamifusen"#, path: "../kamifusen" gem "kaminari" +gem "leaflet-rails" gem "mini_magick" gem "octokit" gem "omniauth-rails_csrf_protection", "~> 1.0" diff --git a/Gemfile.lock b/Gemfile.lock index c6747c13781548393616547c5d55a2288f0e2c64..b067b14958b12f266689deb332dfa6dddaa31a27 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -221,6 +221,20 @@ GEM js_cookie_rails rails sassc-rails + geo_calc (0.7.8) + activesupport (>= 3.0.1) + geo_units (~> 0.3.2) + i18n (>= 0.5) + require_all (>= 1.2.0) + sugar-high (~> 0.7.2) + sweetloader + geo_point (0.2.6) + geo_calc (>= 0.7.7.1) + geo_units (0.3.4) + activesupport (>= 4) + i18n (>= 0.8) + sugar-high (~> 0.7.2) + sweetloader (~> 0.1.6) geocoder (1.8.1) gitlab (4.19.0) httparty (~> 0.20) @@ -277,6 +291,8 @@ GEM activerecord kaminari-core (= 1.2.2) kaminari-core (1.2.2) + leaflet-rails (1.9.3) + rails (>= 4.2.0) listen (3.8.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) @@ -408,6 +424,7 @@ GEM ffi (~> 1.0) regexp_parser (2.7.0) requests (1.0.2) + require_all (3.0.0) responders (3.1.0) actionpack (>= 5.2) railties (>= 5.2) @@ -479,6 +496,10 @@ GEM activesupport (>= 5.2) sprockets (>= 3.0.0) stringio (3.0.5) + sugar-high (0.7.3) + sweetloader (0.1.6) + activesupport (>= 3.0.1) + i18n terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) thor (1.2.1) @@ -560,6 +581,7 @@ DEPENDENCIES font-awesome-sass front_matter_parser gdpr + geo_point geocoder (~> 1.8) gitlab hal_openscience (~> 0.1) @@ -571,6 +593,7 @@ DEPENDENCIES jquery-ui-rails (~> 6.0.1) kamifusen kaminari + leaflet-rails listen (~> 3.3) mini_magick octokit diff --git a/app/assets/javascripts/extranet.js b/app/assets/javascripts/extranet.js index ca7451c7833082a0749e90a3db42f26611bb8c36..1bb3ee541721c56a5c7d12ec8380345569d8f078 100644 --- a/app/assets/javascripts/extranet.js +++ b/app/assets/javascripts/extranet.js @@ -10,6 +10,7 @@ //= require simple_form_bs5_file_input //= require summernote/summernote-bs5 //= require gdpr/cookie_consent +//= require leaflet //= require autocomplete-rails //= require_tree ./application/plugins //= require_tree ./extranet diff --git a/app/assets/stylesheets/extranet.sass b/app/assets/stylesheets/extranet.sass index b0734c2c9ff3388d1896cc41a01490858f54abba..f502e046a4e4422e45379503f399721372a9a218 100644 --- a/app/assets/stylesheets/extranet.sass +++ b/app/assets/stylesheets/extranet.sass @@ -10,6 +10,7 @@ @import 'cropperjs/dist/cropper' @import 'commons/summernote' @import 'commons/bootstrap-icons' +@import 'leaflet' // Default @import 'extranet/layout/*' diff --git a/app/assets/stylesheets/extranet/layout/_leaflet.sass b/app/assets/stylesheets/extranet/layout/_leaflet.sass new file mode 100644 index 0000000000000000000000000000000000000000..715e7ceffaa7ffaa10e3359181947391be033139 --- /dev/null +++ b/app/assets/stylesheets/extranet/layout/_leaflet.sass @@ -0,0 +1,2 @@ +#map + height: 300px \ No newline at end of file diff --git a/app/assets/stylesheets/extranet/layout/_typography.sass b/app/assets/stylesheets/extranet/layout/_typography.sass index 1da69d9fe841a674a87875baa8f1340de88e9194..023898c348f5b397a4cda95a052d0560bfaa2b5d 100644 --- a/app/assets/stylesheets/extranet/layout/_typography.sass +++ b/app/assets/stylesheets/extranet/layout/_typography.sass @@ -5,13 +5,6 @@ font-weight: 400 src: asset-url("Basier-Square/basiersquare-regular-webfont.woff2") format("woff2"), url("Basier-Square/basiersquare-regular-webfont.woff") format("woff") -@font-face - font-display: swap - font-family: 'Basier Square' - font-style: normal - font-weight: 500 - src: asset-url("Basier-Square/basiersquare-medium-webfont.woff2") format("woff2"), url("Basier-Square/basiersquare-medium-webfont.woff") format("woff") - @font-face font-display: swap font-family: 'Basier Square' @@ -21,7 +14,7 @@ h1 margin-top: 20px - font-weight: 500 + font-weight: 700 line-height: 125% @include media-breakpoint-up(md) max-width: 70vw diff --git a/app/controllers/admin/university/organizations_controller.rb b/app/controllers/admin/university/organizations_controller.rb index 3f56e50328a8d0a8952682f20049316c13b00157..853399ad3c9204edf4904c332fbd41f3b06d90f6 100644 --- a/app/controllers/admin/university/organizations_controller.rb +++ b/app/controllers/admin/university/organizations_controller.rb @@ -70,7 +70,7 @@ class Admin::University::OrganizationsController < Admin::University::Applicatio params.require(:university_organization) .permit( :name, :long_name, :slug, :meta_description, :summary, :active, :siren, :kind, - :address, :zipcode, :city, :country, :text, + :address, :address_name, :address_additional, :zipcode, :city, :country, :text, :url, :phone, :email, :linkedin, :twitter, :mastodon, :logo, :logo_delete, :logo_infos, :logo_on_dark_background, :logo_on_dark_background_delete, :logo_on_dark_background_infos, diff --git a/app/models/concerns/with_geolocation.rb b/app/models/concerns/with_geolocation.rb index d233db29ec68b0e415874f6a697f2f012e08dd59..df92252bd5228b5eefd05626eeca2dc4a85820d6 100644 --- a/app/models/concerns/with_geolocation.rb +++ b/app/models/concerns/with_geolocation.rb @@ -11,6 +11,28 @@ module WithGeolocation "#{address}, #{zipcode} #{city} #{country}" end + def full_address + string = "" + string += "#{address_name}<br>" if address_name.present? + string += "#{address}<br>" if address.present? + string += "#{address_additional}<br>" if address_additional.present? + string += "#{zipcode} #{city}" + string += "<br>#{ISO3166::Country[country]}" if country + string + end + + def geolocated? + latitude.present? && longitude.present? + end + + def latlong + @latlong ||= [latitude, longitude] + end + + def geo_point + @geo_point ||= GeoPoint.new latitude, longitude + end + protected def full_street_address_present? diff --git a/app/models/university/organization.rb b/app/models/university/organization.rb index 142c0c8c7eb69517cc7007f57953b76af735c8e1..26ec7059d1f864b72ae4e27ff8894ce0e799b61a 100644 --- a/app/models/university/organization.rb +++ b/app/models/university/organization.rb @@ -2,32 +2,34 @@ # # Table name: university_organizations # -# id :uuid not null, primary key -# active :boolean default(TRUE) -# address :string -# city :string -# country :string -# email :string -# kind :integer default("company") -# latitude :float -# linkedin :string -# long_name :string -# longitude :float -# mastodon :string -# meta_description :text -# name :string -# nic :string -# phone :string -# siren :string -# slug :string -# summary :text -# text :text -# twitter :string -# url :string -# zipcode :string -# created_at :datetime not null -# updated_at :datetime not null -# university_id :uuid not null, indexed +# id :uuid not null, primary key +# active :boolean default(TRUE) +# address :string +# address_additional :string +# address_name :string +# city :string +# country :string +# email :string +# kind :integer default("company") +# latitude :float +# linkedin :string +# long_name :string +# longitude :float +# mastodon :string +# meta_description :text +# name :string +# nic :string +# phone :string +# siren :string +# slug :string +# summary :text +# text :text +# twitter :string +# url :string +# zipcode :string +# created_at :datetime not null +# updated_at :datetime not null +# university_id :uuid not null, indexed # # Indexes # diff --git a/app/views/admin/university/organizations/_form.html.erb b/app/views/admin/university/organizations/_form.html.erb index 213edbf4319c8f3b4b005f949c44c5e56e6eb019..fd52c9d8d69016727929ec7fc05f723be3e9d6db 100644 --- a/app/views/admin/university/organizations/_form.html.erb +++ b/app/views/admin/university/organizations/_form.html.erb @@ -13,20 +13,22 @@ data: { 'summernote-config' => 'mini-list' } } %> <% end %> - <%= osuny_panel University::Organization.human_attribute_name('contact') do %> + <%= osuny_panel University::Organization.human_attribute_name('physical') do %> <div class="row pure__row--small"> <div class="col-xl-6"> + <%= f.input :address_name %> <%= f.input :address %> + <%= f.input :address_additional %> </div> <div class="col-xl-6"> <%= f.input :zipcode %> - </div> - <div class="col-xl-6"> <%= f.input :city %> - </div> - <div class="col-xl-6"> <%= f.input :country, input_html: { class: 'form-select' } %> </div> + </div> + <% end %> + <%= osuny_panel University::Organization.human_attribute_name('digital') do %> + <div class="row pure__row--small"> <div class="col-xl-6"> <%= f.input :url %> </div> diff --git a/app/views/admin/university/organizations/show.html.erb b/app/views/admin/university/organizations/show.html.erb index ca48b6993f9cde4f5d61b0c5e076117a83e3374f..760bf3e64e1e0b7f07030a315876c3f4ae82a179 100644 --- a/app/views/admin/university/organizations/show.html.erb +++ b/app/views/admin/university/organizations/show.html.erb @@ -7,21 +7,40 @@ <%= @organization.text.to_s.html_safe %> <% end if strip_tags(@organization.text.to_s).present? %> - <%= osuny_panel University::Organization.human_attribute_name('contact') do %> + <%= osuny_panel University::Organization.human_attribute_name('physical') do %> <div class="row pure__row--small"> - <% [ - :address, + <div class="col-xxl-6"> + <% [ + :address_name, + :address, + :address_additional, + ].each do |property| %> + <% value = @organization.send property %> + <% next if value.blank? %> + <%= osuny_label University::Organization.human_attribute_name(property) %> + <p><%= value %></p> + <% end %> + </div> + <div class="col-xxl-6"> + <% [ :zipcode, :city, - :country + :country, ].each do |property| %> - <% value = @organization.send property %> - <% next if value.blank? %> - <div class="col-xxl-6"> - <%= osuny_label University::Organization.human_attribute_name(property) %> - <p><%= value %></p> - </div> - <% end %> + <% value = @organization.send property %> + <% next if value.blank? %> + <%= osuny_label University::Organization.human_attribute_name(property) %> + <p><%= value %></p> + <% end %> + </div> + </div> + <% if @organization.geolocated? %> + <%= osuny_label University::Organization.human_attribute_name('geolocation') %> + <p><%= @organization.geo_point.to_s %></p> + <% end %> + <% end %> + <%= osuny_panel University::Organization.human_attribute_name('digital') do %> + <div class="row pure__row--small"> <% unless @organization.url.blank? %> <div class="col-xxl-6"> <%= osuny_label University::Organization.human_attribute_name('url') %> @@ -47,6 +66,7 @@ </div> <% end %> + <%= osuny_panel University::Organization.human_attribute_name('legal') do %> <div class="row pure__row--small"> <div class="col-xxl-6"> diff --git a/app/views/admin/university/organizations/static.html.erb b/app/views/admin/university/organizations/static.html.erb index d5dfa7df56673c1eeab9a2531df5b28da1df3518..60054f0d4fbeacd0eb5c737974fdfedd7db117d9 100644 --- a/app/views/admin/university/organizations/static.html.erb +++ b/app/views/admin/university/organizations/static.html.erb @@ -10,7 +10,9 @@ kind: [ :long_name, :siren, + :address_name, :address, + :address_additional, :zipcode, :city, :country, diff --git a/app/views/extranet/contacts/organizations/show.html.erb b/app/views/extranet/contacts/organizations/show.html.erb index 0a7a6118ac8d40bc55b83df475bfe731aa392d36..7e294913f1fba849ab800f8e7e133a04d0cd0924 100644 --- a/app/views/extranet/contacts/organizations/show.html.erb +++ b/app/views/extranet/contacts/organizations/show.html.erb @@ -13,6 +13,8 @@ <div class="offset-md-1 col-md-3 order-1 order-md-2"> <%= kamifusen_tag @organization.logo, width: 400, class: 'img-fluid organization__logo' if @organization.logo.attached? %> <dl> + <dt><%= University::Organization.human_attribute_name(:address) %></dt> + <dd><%= sanitize @organization.full_address %></dd> <% if @organization.phone.present? %> <dt><%= University::Organization.human_attribute_name(:phone) %></dt> <dd><a href="tel:<%= @organization.phone %>" target="_blank" rel="noreferrer"><%= @organization.phone %></a></dd> @@ -29,6 +31,20 @@ </a> </dd> <% end %> + <% if @organization.geolocated? %> + <dt><%= University::Organization.human_attribute_name(:map) %></dt> + <dl><%= map( + center: { + latlng: @organization.latlong, + zoom: 15 + }, + markers: [ + { + latlng: @organization.latlong + } + ] + ) %></dl> + <% end %> </dl> </div> </div> diff --git a/config/initializers/leaflet.rb b/config/initializers/leaflet.rb new file mode 100644 index 0000000000000000000000000000000000000000..d0bf69b811405d9748d79c4e78e5224f525210ea --- /dev/null +++ b/config/initializers/leaflet.rb @@ -0,0 +1,3 @@ +Leaflet.tile_layer = "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" +Leaflet.attribution = "Osuny" +Leaflet.max_zoom = 18 diff --git a/config/locales/university/en.yml b/config/locales/university/en.yml index e379782d10e5dcad662ac08e502acabb48e37bbc..b71021709b80578c36b747a0c278993028422419 100644 --- a/config/locales/university/en.yml +++ b/config/locales/university/en.yml @@ -85,19 +85,24 @@ en: target_id: '' university/organization: address: Address + address_name: Address name + address_additional: Additional address city: City - contact: Contact information country: Country - email: Email description: Personne morale liée à une université, une composante, un laboratoire, etc. + digital: Digital contact + email: Email + geolocation: Geographical coordinates kind: Kind legal: Legal information linkedin: LinkedIn logo: Logo for light backgrounds (default) logo_on_dark_background: Logo for dark backgrounds (optional) long_name: Long name + map: Map name: Name phone: Telephone + physical: Contact information siren: Legal identification number text: Text twitter: Twitter @@ -140,9 +145,15 @@ en: sms_sender_name: "11 characters max. Only alphanumeric chars ([A-Z][a-z][0-9])." sso_button_label: "Default: Sign in via SSO" university_organization: + address: 'This field is used for geolocation. Ex: 3 rue de la Poste' + address_name: 'This field is not used for geolocation. Ex: Hôtel du Département' + address_additional: 'This field is not used for geolocation. Ex: Bureau 508' + city: 'This field is used for geolocation. Ex: Cenon' + country: 'This field is used for geolocation. Ex: France' description: If this field is empty the main text's begining will be used. logo: This logo should contrast properly on a light bacgkground (white or pale grey) logo_on_dark_background: This logo should contrast on a dark background (black or dark grey) + zipcode: 'This field is used for geolocation. Ex: 33150' university_person: description: If this field is empty, "short description" field will be used. If also emty the main text's begining will be used. habilitation: "Possesses an accreditation to supervise research." diff --git a/config/locales/university/fr.yml b/config/locales/university/fr.yml index e27af33f636acd2ce38a7bd662c4108628ab29a1..8214f25cd9d402d78a1fbc9b3e43e5651ab27f36 100644 --- a/config/locales/university/fr.yml +++ b/config/locales/university/fr.yml @@ -85,19 +85,24 @@ fr: target_id: '' university/organization: address: Adresse + address_name: Nom de l'adresse + address_additional: Complément d'adresse city: Ville - contact: Informations de contact country: Pays description: Personne morale liée à une université, une composante, un laboratoire, etc. + digital: Coordonnées numériques email: Email kind: Type + geolocation: Coordonnées géographiques legal: Informations légales linkedin: LinkedIn logo: Logo sur fond clair (par défaut) logo_on_dark_background: Logo sur fond sombre (optionnel) long_name: Nom complet + map: Carte name: Nom phone: Téléphone + physical: Coordonnées physiques siren: Numéro de SIREN text: Texte twitter: Twitter @@ -140,9 +145,15 @@ fr: sms_sender_name: "11 caractères maximum. Que des caractères alphadécimaux ([A-Z][a-z][0-9])." sso_button_label: "Par défaut : Se connecter en SSO" university_organization: + address: 'Ce champ est utilisé pour géolocaliser. Ex: 3 rue de la Poste' + address_name: 'Ce champ est ignoré dans la géolocalisation. Ex: Hôtel du Département' + address_additional: 'Ce champ est ignoré dans la géolocalisation. Ex: Bureau 508' + city: 'Ce champ est utilisé pour géolocaliser. Ex: Cenon' + country: 'Ce champ est utilisé pour géolocaliser. Ex: France' description: Si ce champ est vide le début du texte principal sera utilisé. logo: Ce logo doit contraster sur un fond clair (blanc ou gris pâle) logo_on_dark_background: Ce logo doit contraster sur un fond sombre (noir ou gris sombre). + zipcode: 'Ce champ est utilisé pour géolocaliser. Ex: 33150' university_person: description: Si ce champ est vide la "description courte" sera utilisée. Si elle est également vide le début du texte principal sera utilisé. habilitation: "Détient une Habilitation à Diriger des Recherches (HDR)." diff --git a/db/migrate/20230308101244_add_fields_to_organizations.rb b/db/migrate/20230308101244_add_fields_to_organizations.rb new file mode 100644 index 0000000000000000000000000000000000000000..4d60c93a1c48e9035c2ecb02b5af0f4b271e3a00 --- /dev/null +++ b/db/migrate/20230308101244_add_fields_to_organizations.rb @@ -0,0 +1,6 @@ +class AddFieldsToOrganizations < ActiveRecord::Migration[7.0] + def change + add_column :university_organizations, :address_name, :string + add_column :university_organizations, :address_additional, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index f251f5c2ae822b96294a2f34a340d224b3369ec5..09f523c210fd8e21609d5c0ac2aa79ef42ac003e 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[7.0].define(version: 2023_03_07_145748) do +ActiveRecord::Schema[7.0].define(version: 2023_03_08_101244) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -847,6 +847,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_03_07_145748) do t.string "mastodon" t.float "latitude" t.float "longitude" + t.string "address_name" + t.string "address_additional" t.index ["university_id"], name: "index_university_organizations_on_university_id" end diff --git a/test/fixtures/university/organizations.yml b/test/fixtures/university/organizations.yml index fb69b56e39737260f1e867d432a547c1d89b405a..ecf596addfc3eec3eec8dde25ca316f82fdd2a90 100644 --- a/test/fixtures/university/organizations.yml +++ b/test/fixtures/university/organizations.yml @@ -2,32 +2,34 @@ # # Table name: university_organizations # -# id :uuid not null, primary key -# active :boolean default(TRUE) -# address :string -# city :string -# country :string -# email :string -# kind :integer default("company") -# latitude :float -# linkedin :string -# long_name :string -# longitude :float -# mastodon :string -# meta_description :text -# name :string -# nic :string -# phone :string -# siren :string -# slug :string -# summary :text -# text :text -# twitter :string -# url :string -# zipcode :string -# created_at :datetime not null -# updated_at :datetime not null -# university_id :uuid not null, indexed +# id :uuid not null, primary key +# active :boolean default(TRUE) +# address :string +# address_additional :string +# address_name :string +# city :string +# country :string +# email :string +# kind :integer default("company") +# latitude :float +# linkedin :string +# long_name :string +# longitude :float +# mastodon :string +# meta_description :text +# name :string +# nic :string +# phone :string +# siren :string +# slug :string +# summary :text +# text :text +# twitter :string +# url :string +# zipcode :string +# created_at :datetime not null +# updated_at :datetime not null +# university_id :uuid not null, indexed # # Indexes # diff --git a/test/models/university/organization_test.rb b/test/models/university/organization_test.rb index 3a0b94b80e731d45da8c2a723999d4e8efe1b7ef..b358e842fff8fafabf0dc9309c869d602b8870b8 100644 --- a/test/models/university/organization_test.rb +++ b/test/models/university/organization_test.rb @@ -2,32 +2,34 @@ # # Table name: university_organizations # -# id :uuid not null, primary key -# active :boolean default(TRUE) -# address :string -# city :string -# country :string -# email :string -# kind :integer default("company") -# latitude :float -# linkedin :string -# long_name :string -# longitude :float -# mastodon :string -# meta_description :text -# name :string -# nic :string -# phone :string -# siren :string -# slug :string -# summary :text -# text :text -# twitter :string -# url :string -# zipcode :string -# created_at :datetime not null -# updated_at :datetime not null -# university_id :uuid not null, indexed +# id :uuid not null, primary key +# active :boolean default(TRUE) +# address :string +# address_additional :string +# address_name :string +# city :string +# country :string +# email :string +# kind :integer default("company") +# latitude :float +# linkedin :string +# long_name :string +# longitude :float +# mastodon :string +# meta_description :text +# name :string +# nic :string +# phone :string +# siren :string +# slug :string +# summary :text +# text :text +# twitter :string +# url :string +# zipcode :string +# created_at :datetime not null +# updated_at :datetime not null +# university_id :uuid not null, indexed # # Indexes #