diff --git a/app/controllers/admin/communication/websites/localizations_controller.rb b/app/controllers/admin/communication/websites/localizations_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..afc6d455ce3200687cede9cb08627bd0b26466ac --- /dev/null +++ b/app/controllers/admin/communication/websites/localizations_controller.rb @@ -0,0 +1,38 @@ +class Admin::Communication::Websites::LocalizationsController < Admin::Communication::Websites::ApplicationController + before_action :load_localization + + def show + breadcrumb + end + + def update + if @localization.update_and_sync(localization_params) + redirect_to admin_communication_website_localization_path, notice: t('admin.successfully_updated_html', model: Communication::Website::Localization.model_name.human) + else + breadcrumb + render :show, status: :unprocessable_entity + end + end + + protected + + def load_localization + @localization = @website.find_or_create_localization_for(current_website_language) + authorize! :update, @localization + end + + def breadcrumb + super + add_breadcrumb helpers.language_name(current_website_language.iso_code) + add_breadcrumb t('admin.communication.website.localizations.title') + end + + def localization_params + params.require(:communication_website_localization) + .permit( + :name, + :social_email, :social_facebook, :social_github, :social_instagram, :social_linkedin, + :social_mastodon, :social_peertube, :social_tiktok, :social_vimeo, :social_x, :social_youtube + ) + end +end diff --git a/app/helpers/admin/communication/website/localizations_helper.rb b/app/helpers/admin/communication/website/localizations_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..e30177825a91f379fb2dd4352d90b28667cbfa5a --- /dev/null +++ b/app/helpers/admin/communication/website/localizations_helper.rb @@ -0,0 +1,17 @@ +module Admin::Communication::Website::LocalizationsHelper + def localization_input(f, attribute_name, website) + label = Communication::Website.human_attribute_name(attribute_name) + + is_editing_master = f.object.is_a?(Communication::Website) + master_value = website.public_send(attribute_name) + if !is_editing_master && master_value.present? + hint = t('admin.communication.website.localizations.fallback_hint_html', master_value: master_value) + else + hint = nil + end + + f.input attribute_name, + label: label, + hint: hint + end +end \ No newline at end of file diff --git a/app/models/ability/admin.rb b/app/models/ability/admin.rb index 3d711e79ad8f38fc92ab5c2080b1e91d5288eba5..dd196ad2129812b2a913060de667ae0c16c7b055 100644 --- a/app/models/ability/admin.rb +++ b/app/models/ability/admin.rb @@ -55,6 +55,7 @@ class Ability::Admin < Ability # Est-ce bien raisonnable de laisser supprimer un site ? # Le risque de faussse manip est grand. cannot :destroy, Communication::Website, university_id: @user.university_id + can :manage, Communication::Website::Localization, university_id: @user.university_id can :manage, Communication::Website::Agenda::Event, university_id: @user.university_id can :manage, Communication::Website::Agenda::Category, university_id: @user.university_id can :manage, Communication::Website::Post::Category, university_id: @user.university_id @@ -63,7 +64,7 @@ class Ability::Admin < Ability can :manage, Communication::Website::Page, university_id: @user.university_id can :manage, Communication::Website::Post, university_id: @user.university_id end - + def admin_communication_extranet can [:read, :update], Communication::Extranet, university_id: @user.university_id can :manage, Communication::Extranet::Connection, university_id: @user.university_id diff --git a/app/models/ability/website_manager.rb b/app/models/ability/website_manager.rb index e519439038c3334cae1443cd0da48be5adbf3377..d4700e289898af27e5e547f4f914b2f0773861c1 100644 --- a/app/models/ability/website_manager.rb +++ b/app/models/ability/website_manager.rb @@ -4,6 +4,7 @@ class Ability::WebsiteManager < Ability super manage_blocks can [:read, :analytics], Communication::Website, university_id: @user.university_id, id: managed_websites_ids + can :manage, Communication::Website::Localization, university_id: @user.university_id, communication_website_id: managed_websites_ids can :manage, Communication::Website::Agenda::Event, university_id: @user.university_id, communication_website_id: managed_websites_ids can :manage, Communication::Website::Agenda::Category, university_id: @user.university_id, communication_website_id: managed_websites_ids can :manage, Communication::Website::Post::Category, university_id: @user.university_id, communication_website_id: managed_websites_ids diff --git a/app/models/communication/extranet.rb b/app/models/communication/extranet.rb index 4c3532ad3e2916de1e3869647cadd3650d2e3d29..cf6ce6177e36aff2255b4fef25e435e982857b50 100644 --- a/app/models/communication/extranet.rb +++ b/app/models/communication/extranet.rb @@ -2,35 +2,34 @@ # # Table name: communication_extranets # -# 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 +# 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 # # Indexes # diff --git a/app/models/communication/website/localization.rb b/app/models/communication/website/localization.rb new file mode 100644 index 0000000000000000000000000000000000000000..a1d171c3bca1cc713ea10467fc5638dc4ab733ec --- /dev/null +++ b/app/models/communication/website/localization.rb @@ -0,0 +1,66 @@ +# == Schema Information +# +# Table name: communication_website_localizations +# +# id :uuid not null, primary key +# name :string +# social_email :string +# social_facebook :string +# social_github :string +# social_instagram :string +# social_linkedin :string +# social_mastodon :string +# social_peertube :string +# social_tiktok :string +# social_vimeo :string +# social_x :string +# social_youtube :string +# created_at :datetime not null +# updated_at :datetime not null +# communication_website_id :uuid not null, indexed +# language_id :uuid not null, indexed +# university_id :uuid not null, indexed +# +# Indexes +# +# idx_on_communication_website_id_ed4630e334 (communication_website_id) +# index_communication_website_localizations_on_language_id (language_id) +# index_communication_website_localizations_on_university_id (university_id) +# +# Foreign Keys +# +# fk_rails_2b920b0a3a (language_id => languages.id) +# fk_rails_431797c26c (communication_website_id => communication_websites.id) +# fk_rails_fc42676b8b (university_id => universities.id) +# +class Communication::Website::Localization < ApplicationRecord + include AsDirectObject + include Sanitizable + include WithUniversity + + belongs_to :language + + validates :language_id, uniqueness: { scope: :communication_website_id } + + before_validation :set_university_id, on: :create + + # Localization is not directly exportable to git + # Whereas the languages config in the dependencies is exportable to git + def exportable_to_git? + false + end + + def dependencies + [website.config_default_languages] + end + + def computed_name + name.present? ? "#{name}" : website.to_s + end + + private + + def set_university_id + self.university_id = website.university_id + end +end diff --git a/app/models/communication/website/with_languages.rb b/app/models/communication/website/with_languages.rb index 258d4b6f9759a6aa5e9960163e6756901578e746..95591dcdf8c7cb8e6d880729ae74427e35f40e63 100644 --- a/app/models/communication/website/with_languages.rb +++ b/app/models/communication/website/with_languages.rb @@ -11,6 +11,9 @@ module Communication::Website::WithLanguages foreign_key: :communication_website_id, association_foreign_key: :language_id, after_remove: :flag_languages_change + has_many :localizations, + foreign_key: :communication_website_id, + dependent: :destroy validates :languages, length: { minimum: 1 } validate :languages_must_include_default_language @@ -27,6 +30,18 @@ module Communication::Website::WithLanguages languages.find_by(iso_code: iso_code) || default_language end + def localization_for(language) + return self if language.id == default_language_id + localization = localizations.find_by(language_id: language.id) + localization ||= self + localization + end + + def find_or_create_localization_for(language) + return self if language.id == default_language_id + localizations.find_or_create_by(language_id: language.id) + end + protected def languages_must_include_default_language diff --git a/app/services/icon.rb b/app/services/icon.rb index f8a94ca5f33476e99b430d201d4bcf40e890e64e..b09a73897fdd87c7293b7ccbb6464f855755690f 100644 --- a/app/services/icon.rb +++ b/app/services/icon.rb @@ -5,6 +5,7 @@ class Icon COMMUNICATION_EXTRANET = 'fas fa-project-diagram' COMMUNICATION_WEBSITE = 'fas fa-sitemap' COMMUNICATION_WEBSITE_HOME = 'fas fa-home' + COMMUNICATION_WEBSITE_LOCALIZATIONS = 'fas fa-globe' COMMUNICATION_WEBSITE_POST = 'fas fa-newspaper' COMMUNICATION_WEBSITE_PAGE = 'fas fa-file' COMMUNICATION_WEBSITE_PAGES = 'fas fa-sitemap' @@ -60,7 +61,7 @@ class Icon OSUNY_USER = 'fas fa-user' USER = OSUNY_USER - + ADD = 'fas fa-plus' ARROW_RIGHT = 'fas fa-arrow-right' A11Y = 'fas fa-universal-access' diff --git a/app/views/admin/communication/websites/_sidebar.html.erb b/app/views/admin/communication/websites/_sidebar.html.erb index ebd838a964c77d1885ece044b7f398625327ad18..43b53ce044975c590caadad0baa9c646bce69377 100644 --- a/app/views/admin/communication/websites/_sidebar.html.erb +++ b/app/views/admin/communication/websites/_sidebar.html.erb @@ -38,6 +38,13 @@ ability: can?(:read, Communication::Website::Post::Category) } + navigation << { + title: t('admin.communication.website.localizations.title'), + path: admin_communication_website_localization_path(website_id: @website), + icon: Icon::COMMUNICATION_WEBSITE_LOCALIZATIONS, + ability: can?(:read, Communication::Website::Localization) + } if @website.languages.many? + navigation << { title: t('communication.website.analytics'), path: analytics_admin_communication_website_path(@website.id, website_id: nil), diff --git a/app/views/admin/communication/websites/configs/default_languages/static.html.erb b/app/views/admin/communication/websites/configs/default_languages/static.html.erb index acddc20ec56dc6637870f81175ce95c335464808..619e265e0655bc14789835070394daf0edc5044d 100644 --- a/app/views/admin/communication/websites/configs/default_languages/static.html.erb +++ b/app/views/admin/communication/websites/configs/default_languages/static.html.erb @@ -1,11 +1,37 @@ # DO NOT EDIT THIS FILE BY HAND - IT WILL BE OVERWRITTEN BY OSUNY -<% @website.languages.each do |language| %> +<% +@website.languages.each do |language| + localization = @website.localization_for(language) +%> <%= language.iso_code %>: - title: <%= @website %><%# TODO I18n: Traduire le nom du site %> + title: <%= localization.computed_name %> contentDir: content/<%= language.iso_code %> languageCode: <%= language.iso_code %> languageName: <%= language.name %> + params: + social: + <%- + [ + :email, + :mastodon, + :peertube, + :x, + :github, + :linkedin, + :youtube, + :vimeo, + :instagram, + :facebook, + :tiktok + ].each do |social_element| + value = localization.public_send "social_#{social_element}" + value = @website.public_send "social_#{social_element}" if value.blank? + next if value.blank? + -%> + <%= social_element %>: >- + <%= value %> + <%- end -%> permalinks: <% Communication::Website::Permalink.config_in_website(@website, language).each do |key, value| %> <%= key %>: <%= value %> diff --git a/app/views/admin/communication/websites/localizations/show.html.erb b/app/views/admin/communication/websites/localizations/show.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..7c438b159c0db4f6bc5a52fc29259ec3d4b91b44 --- /dev/null +++ b/app/views/admin/communication/websites/localizations/show.html.erb @@ -0,0 +1,43 @@ +<% content_for :title, "#{t('admin.communication.website.localizations.title')}" %> + +<% content_for :title_right do %> + <%= language_name(current_website_language.iso_code) %> +<% end %> + +<%= render 'admin/communication/websites/sidebar' do %> + <%= simple_form_for [:admin, @localization], as: :communication_website_localization, url: admin_communication_website_localization_path do |f| %> + <%= f.error_notification %> + <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %> + + <%= osuny_panel t('content') do %> + <%= localization_input f, :name, @website %> + <% end %> + + <%= osuny_panel Communication::Website.human_attribute_name('social') do %> + <div class="row"> + <div class="col-lg-6"> + <p><%= t('admin.communication.website.social.free') %></p> + <%= localization_input f, :social_email, @website %> + <%= localization_input f, :social_mastodon, @website %> + <%= localization_input f, :social_peertube, @website %> + </div> + <div class="col-lg-6"> + <p><%= t('admin.communication.website.social.private') %></p> + <%= localization_input f, :social_x, @website %> + <%= localization_input f, :social_github, @website %> + <%= localization_input f, :social_linkedin, @website %> + <%= localization_input f, :social_youtube, @website %> + <%= localization_input f, :social_vimeo, @website %> + <%= localization_input f, :social_instagram, @website %> + <%= localization_input f, :social_facebook, @website %> + <%= localization_input f, :social_tiktok, @website %> + </div> + </div> + <% end %> + + <% content_for :action_bar_right do %> + <%= submit f %> + <% end %> + <% end %> + +<% end %> diff --git a/app/views/admin/communication/websites/static.html.erb b/app/views/admin/communication/websites/static.html.erb index f1c6884b2ec02687da51b5998e3bedbca05070a6..8bc86ef5bd4417733ecf792d3239c40b34d7fdb1 100644 --- a/app/views/admin/communication/websites/static.html.erb +++ b/app/views/admin/communication/websites/static.html.erb @@ -18,10 +18,10 @@ social: :instagram, :facebook, :tiktok -].each do |network| - value = @website.send "social_#{network}" +].each do |social_element| + value = @website.send "social_#{social_element}" next if value.blank? %> - <%= network %>: >- + <%= social_element %>: >- <%= value %> <% end %> \ No newline at end of file diff --git a/config/locales/communication/en.yml b/config/locales/communication/en.yml index 7b2d2e04922f916921640173dc4ab6e2940628a8..2f0971b8ade0203dec9395949866c55445643861 100644 --- a/config/locales/communication/en.yml +++ b/config/locales/communication/en.yml @@ -280,6 +280,9 @@ en: editorial: label: Editorial description: Everything related to content + localizations: + fallback_hint_html: "Leave blank to use the default value: <i>%{master_value}</i>" + title: Internationalization technical: label: Technical description: Everything related to technical settings diff --git a/config/locales/communication/fr.yml b/config/locales/communication/fr.yml index c54f405afab76963ea787d5dc6596dda7ff13609..099aee1bfb3e23bde05ae36e603c23930ebb4645 100644 --- a/config/locales/communication/fr.yml +++ b/config/locales/communication/fr.yml @@ -280,6 +280,9 @@ fr: editorial: label: Éditorial description: Tout ce qui est lié au contenu + localizations: + fallback_hint_html: "Laisser vide pour utiliser la valeur par défaut : <i>%{master_value}</i>" + title: Internationalisation technical: label: Technique description: Tout ce qui est lié aux réglages techniques diff --git a/config/routes/admin/communication.rb b/config/routes/admin/communication.rb index bb24319d55a16786f58e26fbecde068dc28ae24e..303289d08b65fb3442e4cca0d5d3345bdf993fae 100644 --- a/config/routes/admin/communication.rb +++ b/config/routes/admin/communication.rb @@ -41,7 +41,7 @@ namespace :communication do get :children get :static end - end + end resources :authors, controller: '/admin/communication/websites/posts/authors', path: '/:lang/authors', only: [:index, :show] end resources :posts, controller: 'websites/posts', path: '/:lang/posts' do @@ -87,6 +87,7 @@ namespace :communication do end end end + resource :localization, controller: 'websites/localizations', path: '/:lang/localization', only: [:show, :update] end scope "/contents/:about_type/:about_id", as: :contents, controller: 'contents' do get :write diff --git a/db/migrate/20240122132556_create_communication_website_localizations.rb b/db/migrate/20240122132556_create_communication_website_localizations.rb new file mode 100644 index 0000000000000000000000000000000000000000..f079fba2470b8bb132514254c7ab8e73039508c8 --- /dev/null +++ b/db/migrate/20240122132556_create_communication_website_localizations.rb @@ -0,0 +1,23 @@ +class CreateCommunicationWebsiteLocalizations < ActiveRecord::Migration[7.1] + def change + create_table :communication_website_localizations, id: :uuid do |t| + t.references :communication_website, null: false, foreign_key: true, type: :uuid + t.references :language, null: false, foreign_key: true, type: :uuid + t.references :university, null: false, foreign_key: true, type: :uuid + t.string :name + t.string :email + t.string :mastodon + t.string :peertube + t.string :x + t.string :github + t.string :linkedin + t.string :youtube + t.string :vimeo + t.string :instagram + t.string :facebook + t.string :tiktok + + t.timestamps + end + end +end diff --git a/db/migrate/20240122144217_rename_social_attributes_in_localizations.rb b/db/migrate/20240122144217_rename_social_attributes_in_localizations.rb new file mode 100644 index 0000000000000000000000000000000000000000..e9178cd76ac5e0418ca7f50ba3dfa9f93a690168 --- /dev/null +++ b/db/migrate/20240122144217_rename_social_attributes_in_localizations.rb @@ -0,0 +1,15 @@ +class RenameSocialAttributesInLocalizations < ActiveRecord::Migration[7.1] + def change + rename_column :communication_website_localizations, :email, :social_email + rename_column :communication_website_localizations, :mastodon, :social_mastodon + rename_column :communication_website_localizations, :peertube, :social_peertube + rename_column :communication_website_localizations, :x, :social_x + rename_column :communication_website_localizations, :github, :social_github + rename_column :communication_website_localizations, :linkedin, :social_linkedin + rename_column :communication_website_localizations, :youtube, :social_youtube + rename_column :communication_website_localizations, :vimeo, :social_vimeo + rename_column :communication_website_localizations, :instagram, :social_instagram + rename_column :communication_website_localizations, :facebook, :social_facebook + rename_column :communication_website_localizations, :tiktok, :social_tiktok + end +end diff --git a/db/schema.rb b/db/schema.rb index f6ea6ac594ca9c363ac720e1b2d557a3cbb08df0..13fed44a6deed1228bf58449d77229dcb6a05f54 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -106,8 +106,8 @@ ActiveRecord::Schema[7.1].define(version: 2024_01_29_100647) do t.datetime "updated_at", null: false t.string "title" t.boolean "published", default: true - t.uuid "communication_website_id" t.uuid "heading_id" + t.uuid "communication_website_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,7 +229,6 @@ ActiveRecord::Schema[7.1].define(version: 2024_01_29_100647) 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 @@ -327,6 +326,29 @@ ActiveRecord::Schema[7.1].define(version: 2024_01_29_100647) do t.index ["website_id"], name: "index_communication_website_git_files_on_website_id" end + create_table "communication_website_localizations", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.uuid "communication_website_id", null: false + t.uuid "language_id", null: false + t.uuid "university_id", null: false + t.string "name" + t.string "social_email" + t.string "social_mastodon" + t.string "social_peertube" + t.string "social_x" + t.string "social_github" + t.string "social_linkedin" + t.string "social_youtube" + t.string "social_vimeo" + t.string "social_instagram" + t.string "social_facebook" + t.string "social_tiktok" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["communication_website_id"], name: "idx_on_communication_website_id_ed4630e334" + t.index ["language_id"], name: "index_communication_website_localizations_on_language_id" + t.index ["university_id"], name: "index_communication_website_localizations_on_university_id" + end + create_table "communication_website_menu_items", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t| t.uuid "university_id", null: false t.uuid "website_id", null: false @@ -397,7 +419,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_01_29_100647) do t.index ["university_id"], name: "index_communication_website_pages_on_university_id" end - create_table "communication_website_permalinks", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + create_table "communication_website_permalinks", id: :uuid, default: -> { "public.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 @@ -1173,6 +1195,9 @@ ActiveRecord::Schema[7.1].define(version: 2024_01_29_100647) do add_foreign_key "communication_website_connections", "communication_websites", column: "website_id" add_foreign_key "communication_website_connections", "universities" add_foreign_key "communication_website_git_files", "communication_websites", column: "website_id" + add_foreign_key "communication_website_localizations", "communication_websites" + add_foreign_key "communication_website_localizations", "languages" + add_foreign_key "communication_website_localizations", "universities" add_foreign_key "communication_website_menu_items", "communication_website_menu_items", column: "parent_id" add_foreign_key "communication_website_menu_items", "communication_website_menus", column: "menu_id" add_foreign_key "communication_website_menu_items", "communication_websites", column: "website_id" diff --git a/test/fixtures/communication/website/localizations.yml b/test/fixtures/communication/website/localizations.yml new file mode 100644 index 0000000000000000000000000000000000000000..3c813952b1e1b691d851aa2caeee90ba3498e635 --- /dev/null +++ b/test/fixtures/communication/website/localizations.yml @@ -0,0 +1,7 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +website_with_gitlab_en: + university: default_university + website: website_with_gitlab + language: en + name: Site with gitlab english