diff --git a/Gemfile b/Gemfile index 9ea80345a3218bae8cce0fdce3a816504a7bc477..adac6511dd369e7771746f8528a8a8c48c5762b2 100644 --- a/Gemfile +++ b/Gemfile @@ -97,4 +97,4 @@ group :test do gem "simplecov", require: false end -gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby] \ No newline at end of file +gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby] diff --git a/Gemfile.lock b/Gemfile.lock index 92752520c18be1642a33a4a52e2e9595a2b3cdf5..2f33cc0cfa84fa1e38f0c4ef6c3645554c6a3612 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -68,7 +68,7 @@ GEM erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - active_storage_validations (1.0.4) + active_storage_validations (1.1.1) activejob (>= 5.2.0) activemodel (>= 5.2.0) activestorage (>= 5.2.0) @@ -111,7 +111,7 @@ GEM autoprefixer-rails (10.4.15.0) execjs (~> 2) aws-eventstream (1.2.0) - aws-partitions (1.834.0) + aws-partitions (1.842.0) aws-sdk-core (3.185.1) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) @@ -124,7 +124,7 @@ GEM aws-sdk-core (~> 3, >= 3.181.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.6) - aws-sigv4 (1.6.0) + aws-sigv4 (1.6.1) aws-eventstream (~> 1, >= 1.0.2) base64 (0.1.1) bcrypt (3.1.19) @@ -132,10 +132,9 @@ GEM bindex (0.8.1) bootsnap (1.16.0) msgpack (~> 1.2) - bootstrap (5.3.1) + bootstrap (5.3.2) autoprefixer-rails (>= 9.1.0) popper_js (>= 2.11.8, < 3) - sassc-rails (>= 2.0.0) bootstrap5-kaminari-views (0.0.1) kaminari (>= 0.13) rails (>= 3.1) @@ -190,7 +189,7 @@ GEM date (3.3.3) delayed_job (4.1.11) activesupport (>= 3.0, < 8.0) - delayed_job_active_record (4.1.7) + delayed_job_active_record (4.1.8) activerecord (>= 3.0, < 8.0) delayed_job (>= 3.0, < 5) delayed_job_prevent_duplicate (0.1.4) @@ -298,7 +297,7 @@ GEM mini_magick (>= 4.9.5, < 5) ruby-vips (>= 2.0.17, < 3) io-console (0.6.0) - irb (1.8.1) + irb (1.8.3) rdoc reline (>= 0.3.8) jbuilder (2.11.5) @@ -369,7 +368,7 @@ GEM nesty (1.0.2) net-http (0.3.2) uri - net-imap (0.4.1) + net-imap (0.4.2) date net-protocol net-pop (0.1.2) @@ -417,7 +416,7 @@ GEM requests (~> 1.0.2) pg (1.5.4) popper_js (2.11.8) - psych (5.1.1) + psych (5.1.1.1) stringio public_suffix (5.0.3) puma (6.4.0) @@ -492,7 +491,7 @@ GEM ruby-saml (1.16.0) nokogiri (>= 1.13.10) rexml - ruby-vips (2.1.4) + ruby-vips (2.2.0) ffi (~> 1.12) ruby2_keywords (0.0.5) rubyzip (2.3.2) @@ -525,7 +524,7 @@ GEM simple_form (5.3.0) actionpack (>= 5.2) activemodel (>= 5.2) - simple_form_bs5_file_input (0.1.0) + simple_form_bs5_file_input (0.1.2) rails simple_form simple_form_password_with_hints (0.0.7) @@ -561,7 +560,7 @@ GEM i18n terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) - thor (1.2.2) + thor (1.3.0) tilt (2.3.0) time (0.2.2) date diff --git a/app/assets/images/communication/blocks/templates/agenda/large.png b/app/assets/images/communication/blocks/templates/agenda/large.png new file mode 100644 index 0000000000000000000000000000000000000000..15437e403e15231df8afbbd9fe740f545e5a3f62 Binary files /dev/null and b/app/assets/images/communication/blocks/templates/agenda/large.png differ diff --git a/app/assets/stylesheets/admin/commons/offcanvas.sass b/app/assets/stylesheets/admin/commons/offcanvas.sass new file mode 100644 index 0000000000000000000000000000000000000000..728e70af6bcdfdd7a335247b16318dd2d1bfcded --- /dev/null +++ b/app/assets/stylesheets/admin/commons/offcanvas.sass @@ -0,0 +1,4 @@ +.offcanvas + &__redirections + @include media-breakpoint-up(md) + width: 50vw !important \ No newline at end of file diff --git a/app/assets/stylesheets/extranet/layout/_nav.sass b/app/assets/stylesheets/extranet/layout/_nav.sass index bfe58ba9c021174e2a18a3fee42cca2cf1f6ac94..a15d37a376101b3e6ada794b67da62a96f6d7130 100644 --- a/app/assets/stylesheets/extranet/layout/_nav.sass +++ b/app/assets/stylesheets/extranet/layout/_nav.sass @@ -5,7 +5,7 @@ padding-top: 30px .navbar-brand img - max-width: 100px + object-fit: contain .nav-link color: black .active diff --git a/app/assets/stylesheets/extranet/pages/_devise.sass b/app/assets/stylesheets/extranet/pages/_devise.sass index 1912649d4e81c42ea626a6fc08596e52ca3e61f3..ee5e3a23810ace49650d54c49fd69b9570657f25 100644 --- a/app/assets/stylesheets/extranet/pages/_devise.sass +++ b/app/assets/stylesheets/extranet/pages/_devise.sass @@ -1,8 +1,8 @@ .layout-devise background-color: $header-color .logo - max-width: 150px margin: 120px 0 + object-fit: contain footer margin-top: 100px border-top: 1px solid $light-border-color diff --git a/app/controllers/admin/communication/websites/permalinks_controller.rb b/app/controllers/admin/communication/websites/permalinks_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..49a39f0c4d723c22af3f1e60a082819609f8b9ce --- /dev/null +++ b/app/controllers/admin/communication/websites/permalinks_controller.rb @@ -0,0 +1,8 @@ +class Admin::Communication::Websites::PermalinksController < Admin::Communication::Websites::ApplicationController + + def create + @path = params['communication_website_permalink']['path'] + @about = PolymorphicObjectFinder.find(params, :about) + @permalink = @about.add_redirection(@path) + end +end \ No newline at end of file diff --git a/app/controllers/admin/communication/websites/posts/curations_controller.rb b/app/controllers/admin/communication/websites/posts/curations_controller.rb index 111b201ca983bcdff52ddcaab87b9036a5123c46..436b60dfc08bd03ffd7efda246e2cdb059c3aa79 100644 --- a/app/controllers/admin/communication/websites/posts/curations_controller.rb +++ b/app/controllers/admin/communication/websites/posts/curations_controller.rb @@ -4,7 +4,7 @@ class Admin::Communication::Websites::Posts::CurationsController < Admin::Commun end def create - @curator = Curator.new @website, current_user, current_website_language, curation_params[:url] + @curator = Importers::Curator.new @website, current_user, current_website_language, curation_params[:url] if @curator.valid? redirect_to [:admin, @curator.post], notice: t('admin.successfully_created_html', model: @curator.post.to_s) diff --git a/app/controllers/admin/communication/websites_controller.rb b/app/controllers/admin/communication/websites_controller.rb index 4d931dc92ab87943f0689be935bc2f1c3a4803b5..cd77a57143929e40b4a99e477a2451577cae5599 100644 --- a/app/controllers/admin/communication/websites_controller.rb +++ b/app/controllers/admin/communication/websites_controller.rb @@ -17,6 +17,12 @@ class Admin::Communication::WebsitesController < Admin::Communication::Websites: add_breadcrumb t('communication.website.security') end + def production + @website.in_production = true + breadcrumb + add_breadcrumb t('communication.website.golive.title') + end + def show @all_pages = @website.pages.accessible_by(current_ability).for_language(current_website_language) @pages = @all_pages.recent diff --git a/app/controllers/api/osuny/application_controller.rb b/app/controllers/api/osuny/application_controller.rb index 74e5ba47e8acb595529a58bf52c2eb90195d2ecc..5f3111aecfbca56e4eeb7d5fc8a2f7ed3899c2b4 100644 --- a/app/controllers/api/osuny/application_controller.rb +++ b/app/controllers/api/osuny/application_controller.rb @@ -1,8 +1,10 @@ class Api::Osuny::ApplicationController < Api::ApplicationController + protected def verify_app_token @app = current_university.apps.find_by(token: request.headers['X-Osuny-Token']) raise_403_unless @app end + end \ No newline at end of file diff --git a/app/controllers/api/osuny/communication/websites/application_controller.rb b/app/controllers/api/osuny/communication/websites/application_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..c90b5342523f93584d5ed8ed65a63e311317f414 --- /dev/null +++ b/app/controllers/api/osuny/communication/websites/application_controller.rb @@ -0,0 +1,9 @@ +class Api::Osuny::Communication::Websites::ApplicationController < Api::Osuny::ApplicationController + + protected + + def website + @website ||= current_university.websites.find params[:website_id] + end + +end diff --git a/app/controllers/api/osuny/communication/websites/pages_controller.rb b/app/controllers/api/osuny/communication/websites/pages_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..ec16240c53da100e2253e9bbede77f1b8c3d6331 --- /dev/null +++ b/app/controllers/api/osuny/communication/websites/pages_controller.rb @@ -0,0 +1,11 @@ +class Api::Osuny::Communication::Websites::PagesController < Api::Osuny::Communication::Websites::ApplicationController + skip_before_action :verify_authenticity_token, only: :import + before_action :verify_app_token, only: :import + + def import + Importers::Api::Osuny::Communication::Website::Page.new university: current_university, + website: website, + params: params[:page] + render json: :ok + end +end diff --git a/app/controllers/api/osuny/communication/websites/posts_controller.rb b/app/controllers/api/osuny/communication/websites/posts_controller.rb index 9047d91a0bc231c4684a150d40968a0f0c5361e6..0b04dacf07e79575b872dec2b4dd66a9098cea34 100644 --- a/app/controllers/api/osuny/communication/websites/posts_controller.rb +++ b/app/controllers/api/osuny/communication/websites/posts_controller.rb @@ -1,66 +1,12 @@ -class Api::Osuny::Communication::Websites::PostsController < Api::Osuny::ApplicationController +class Api::Osuny::Communication::Websites::PostsController < Api::Osuny::Communication::Websites::ApplicationController skip_before_action :verify_authenticity_token, only: :import before_action :verify_app_token, only: :import def import - create_post - import_blocks + Importers::Api::Osuny::Communication::Website::Post.new university: current_university, + website: website, + params: params[:post] render json: :ok end - protected - - def create_post - post.language = website.default_language - post.update post_params - post.save - end - - def post - @post ||= website.posts - .where( - university: current_university, - website: website, - migration_identifier: migration_identifier - ) - .first_or_initialize - end - - def import_blocks - blocks.each do |b| - migration_identifier = b[:migration_identifier] - template_kind = b[:template_kind] - block = post.blocks - .where( - template_kind: template_kind, - migration_identifier: migration_identifier - ) - .first_or_initialize - block.university = current_university - data = b[:data].to_unsafe_hash - block.data = block.template.data.merge data - block.save - end - end - - def blocks - return [] unless params[:post].has_key?(:blocks) - @blocks ||= params[:post][:blocks] - end - - def website - @website ||= current_university.websites.find params[:website_id] - end - - def migration_identifier - @migration_identifier ||= params[:migration_identifier] - end - - def post_params - params.require(:post) - .permit( - :title, :language, :meta_description, :summary, - ) - end - end diff --git a/app/controllers/server/application_controller.rb b/app/controllers/server/application_controller.rb index 15ed3b9a9354c93889e6ee07cd0c0feef2ad220f..9ae2ed234f5b6b1b0b1237ffa0b6fcb45830011d 100644 --- a/app/controllers/server/application_controller.rb +++ b/app/controllers/server/application_controller.rb @@ -12,7 +12,7 @@ class Server::ApplicationController < ApplicationController end def breadcrumb - add_breadcrumb t('admin.dashboard'), :server_root_path + add_breadcrumb t('server_admin.dashboard'), :server_root_path end def ensure_user_if_server_admin diff --git a/app/controllers/server/websites_controller.rb b/app/controllers/server/websites_controller.rb index 1269d7b89965744f3b7d9b5cf98c87d9774507e4..61eedc5f944557aa503f10827f6309b0545ac2d3 100644 --- a/app/controllers/server/websites_controller.rb +++ b/app/controllers/server/websites_controller.rb @@ -1,5 +1,5 @@ class Server::WebsitesController < Server::ApplicationController - before_action :load_website, only: [:sync_theme_version, :update_theme] + before_action :load_website, except: :index has_scope :for_theme_version has_scope :for_production @@ -10,7 +10,6 @@ class Server::WebsitesController < Server::ApplicationController def index @websites = apply_scopes(Communication::Website.all).ordered breadcrumb - add_breadcrumb Communication::Website.model_name.human(count: 2), server_websites_path end def sync_theme_version @@ -21,8 +20,24 @@ class Server::WebsitesController < Server::ApplicationController @website.update_theme_version end + def show + breadcrumb + add_breadcrumb @website + end + + def update + university_id = params.dig(:communication_website, :university_id) + @website.move_to_university(university_id) if university_id + redirect_to server_website_path(@website), notice: t('admin.successfully_updated_html', model: @website.to_s) + end + protected + def breadcrumb + super + add_breadcrumb Communication::Website.model_name.human(count: 2), server_websites_path + end + def load_website @website = Communication::Website.find params[:id] end diff --git a/app/mailers/notification_mailer.rb b/app/mailers/notification_mailer.rb index c4c9aa3b11e0c942ef52317d3bf54b3525f615cb..4325862409463736c68493a4a2c225cdeb80a6c4 100644 --- a/app/mailers/notification_mailer.rb +++ b/app/mailers/notification_mailer.rb @@ -34,8 +34,18 @@ class NotificationMailer < ApplicationMailer merge_with_university_infos(university, {}) @credits = credits.to_i mails = university.users.server_admin.pluck(:email) + I18n.locale = university.default_language.iso_code subject = t('mailers.notifications.low_sms_credits.subject', credits: @credits) mail(from: university.mail_from[:full], to: mails, subject: subject) end + + def new_registration(university, user) + merge_with_university_infos(university, {}) + @user = user + mails = university.users.where.not(id: @user.id).where(role: [:server_admin, :admin]).pluck(:email) + I18n.locale = university.default_language.iso_code + subject = t('mailers.notifications.new_registration.subject', mail: @user.email) + mail(from: university.mail_from[:full], to: mails, subject: subject) + end end diff --git a/app/models/communication/block/template/agenda.rb b/app/models/communication/block/template/agenda.rb index 5a59c7bbf78e99ca0cf148aed9ade2c63524b1c0..9f462772ad0d33f748d47471526fa6f18d411cb6 100644 --- a/app/models/communication/block/template/agenda.rb +++ b/app/models/communication/block/template/agenda.rb @@ -1,6 +1,13 @@ class Communication::Block::Template::Agenda < Communication::Block::Template::Base - has_layouts [:grid, :list] + AUTHORIZED_SCOPES = [ + 'future_or_present', + 'future', + 'present', + 'archive' + ] + + has_layouts [:grid, :list, :large] has_component :description, :rich_text has_component :quantity, :number, options: 3 @@ -10,6 +17,10 @@ class Communication::Block::Template::Agenda < Communication::Block::Template::B @selected_events ||= events_with_time_scope end + def dependencies + selected_events + end + def allowed_for_about? website.present? end @@ -17,25 +28,9 @@ class Communication::Block::Template::Agenda < Communication::Block::Template::B protected def events_with_time_scope - events = block.about&.website - .events - .for_language(block.language) - .published - .limit(quantity) - # Whitelist for security - # (not very elegant though) - case time - when 'future_or_present' - events.future_or_present - when 'future' - events.future - when 'present' - events.present - when 'archive' - events.archive - else - events - end + events = website.events.for_language(block.language).published + events = events.send(time) if time.in? AUTHORIZED_SCOPES + events = events.limit(quantity) end end diff --git a/app/models/communication/extranet.rb b/app/models/communication/extranet.rb index 1a4615b3d6c6865f180dd318b43f9c1268235907..0dc31636314ab864924471003317609996665e7c 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.rb b/app/models/communication/website.rb index 0886d3dfcc57f6cdc360b6c147ce63507a18a4dc..48f24a2fb4e3eae7d12110bc8cbd300dbfa4c10b 100644 --- a/app/models/communication/website.rb +++ b/app/models/communication/website.rb @@ -145,6 +145,14 @@ class Communication::Website < ApplicationRecord end handle_asynchronously :sync_with_git, queue: 'default' + def move_to_university(new_university_id) + return if self.university_id == new_university_id + update_column :university_id, new_university_id + recursive_dependencies_syncable_following_direct.each do |dependency| + reconnect_dependency dependency, new_university_id + end + end + protected def sanitize_fields @@ -155,4 +163,27 @@ class Communication::Website < ApplicationRecord self.repository = Osuny::Sanitizer.sanitize(self.repository, 'string') self.url = Osuny::Sanitizer.sanitize(self.url, 'string') end + + def reconnect_dependency(dependency, new_university_id) + # puts + # puts "reconnect dependency #{dependency} - #{dependency.class}" + unless dependency.respond_to?(:university_id) + # puts "no university" + return + end + # puts " respond to university_id" + # vérifier par les connexions qu'un objet indirect n'est pas utilisé dans un autre website + if dependency.respond_to?(:connections) && dependency.connections.where.not(website: self).any? + # puts "other connection found, not moving" + return + end + # puts " no other connection" + # il faut si l'objet est une person déconnecter le user éventuellement associé. + if dependency.is_a? University::Person + # puts "person, disconnecting from user" + dependency.update_column :user_id, nil + end + # puts "connecting to #{new_university_id}" + dependency.update_column :university_id, new_university_id + end end diff --git a/app/models/communication/website/agenda/event.rb b/app/models/communication/website/agenda/event.rb index 13a3bb61ac4ceb4085725638193e7b47cdd59a7d..7713d33681dd33b4097b4f98a552f0b4841f5630 100644 --- a/app/models/communication/website/agenda/event.rb +++ b/app/models/communication/website/agenda/event.rb @@ -64,9 +64,10 @@ class Communication::Website::Agenda::Event < ApplicationRecord scope :recent, -> { order(:updated_at).limit(5) } scope :published, -> { where(published: true) } scope :draft, -> { where(published: false) } + scope :future, -> { where('from_day > :today', today: Date.today).ordered_asc } scope :future_or_present, -> { where('from_day >= :today', today: Date.today).ordered_asc } - scope :present, -> { where('(from_day >= :today AND to_day IS NULL) OR (from_day >= :today AND to_day <= :today)', today: Date.today).ordered_asc } + scope :present, -> { where('(from_day <= :today AND to_day IS NULL) OR (from_day <= :today AND to_day >= :today)', today: Date.today).ordered_asc } scope :archive, -> { where('to_day < :today', today: Date.today).ordered_desc } scope :past, -> { archive } @@ -124,6 +125,11 @@ class Communication::Website::Agenda::Event < ApplicationRecord [website.config_default_content_security_policy] end + def references + menus + + abouts_with_agenda_block + end + def to_s "#{title}" end @@ -142,4 +148,8 @@ class Communication::Website::Agenda::Event < ApplicationRecord def explicit_blob_ids super.concat [featured_image&.blob_id] end + + def abouts_with_agenda_block + website.blocks.agenda.collect(&:about) + end end diff --git a/app/models/communication/website/page.rb b/app/models/communication/website/page.rb index 571354899ec667ef9ed6997be87feaab60837db3..6ddca2a2d837f8c13e0f96d7c7052b5d184a7569 100644 --- a/app/models/communication/website/page.rb +++ b/app/models/communication/website/page.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/accessibility.rb b/app/models/communication/website/page/accessibility.rb index 9905f2880bf9f857e0acefc0887df64ee598be61..6c0928dd50554288fe14fd36d40b8f8351623cef 100644 --- a/app/models/communication/website/page/accessibility.rb +++ b/app/models/communication/website/page/accessibility.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/administrator.rb b/app/models/communication/website/page/administrator.rb index ca6144eade91f91c98b17053ded8c394b9cc0112..df545493462dc27eeb09614b202e8376aef311b4 100644 --- a/app/models/communication/website/page/administrator.rb +++ b/app/models/communication/website/page/administrator.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/author.rb b/app/models/communication/website/page/author.rb index dd81fa6dbe901b31501860039c397d8b22b0d103..d8fff0dfa6c86c7b6f350da19112dbc191753008 100644 --- a/app/models/communication/website/page/author.rb +++ b/app/models/communication/website/page/author.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/communication_agenda.rb b/app/models/communication/website/page/communication_agenda.rb index 4e17c15e04162d22fee8c2df61e41aa0abecaa10..48c0fc6401c2ffab35bae56647ee2e736cd5fa54 100644 --- a/app/models/communication/website/page/communication_agenda.rb +++ b/app/models/communication/website/page/communication_agenda.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/communication_agenda_archive.rb b/app/models/communication/website/page/communication_agenda_archive.rb index 822731a13b6da15b49b878638cbb6989a5161d46..018f0b0e80fc33fd85dbfa0b6336f78aad890275 100644 --- a/app/models/communication/website/page/communication_agenda_archive.rb +++ b/app/models/communication/website/page/communication_agenda_archive.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/communication_post.rb b/app/models/communication/website/page/communication_post.rb index 7d08bc227ebf4805206da7ac54cc6045313d1a49..1ab6d6b24abe2f836a1ed92ede62317911ea30e3 100644 --- a/app/models/communication/website/page/communication_post.rb +++ b/app/models/communication/website/page/communication_post.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/education_diploma.rb b/app/models/communication/website/page/education_diploma.rb index 416c168f758f92179f229d53b95321bff6131e76..a3205229dcb789c01d3de3860f9b7093cf137c2e 100644 --- a/app/models/communication/website/page/education_diploma.rb +++ b/app/models/communication/website/page/education_diploma.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/education_program.rb b/app/models/communication/website/page/education_program.rb index 6a1e2827046b2252cf570ef5914c1bbb395b7a49..6712e72d8e0a9dfea6a65d19cbae4ae6c1863447 100644 --- a/app/models/communication/website/page/education_program.rb +++ b/app/models/communication/website/page/education_program.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/home.rb b/app/models/communication/website/page/home.rb index 8c944b1248ae956c77169ea77b1a968886a041ca..c75c3aca6673f536ab8bde22359143470c31896a 100644 --- a/app/models/communication/website/page/home.rb +++ b/app/models/communication/website/page/home.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/legal_term.rb b/app/models/communication/website/page/legal_term.rb index 91deae0750e8bf5fccf1693ea9016c5dc1d1cb6f..8f187975e66609b6dae32e95c3393450cc82b4ae 100644 --- a/app/models/communication/website/page/legal_term.rb +++ b/app/models/communication/website/page/legal_term.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/organization.rb b/app/models/communication/website/page/organization.rb index f160ede8c709f85d331440b4a44c4420af834a99..b17a2c96df03ca8f4819200d84a799838bdfbaef 100644 --- a/app/models/communication/website/page/organization.rb +++ b/app/models/communication/website/page/organization.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/person.rb b/app/models/communication/website/page/person.rb index 175d5ec7aa62fe1fb670803c912656709c0e660f..4c11cd187e8f3ffe3983031d02bd4906cf685d39 100644 --- a/app/models/communication/website/page/person.rb +++ b/app/models/communication/website/page/person.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/privacy_policy.rb b/app/models/communication/website/page/privacy_policy.rb index f1508624d2169413ec48d6977b1a86a9598b5a10..a5ae32aded565f1588ff053175c47c0e20c6c4b0 100644 --- a/app/models/communication/website/page/privacy_policy.rb +++ b/app/models/communication/website/page/privacy_policy.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/research_hal_publication.rb b/app/models/communication/website/page/research_hal_publication.rb index c6d3c4dee4005907fb55f7ca8b094eb57c8b5ca1..0e4a31a61df98a7dd1775a7ad8a78b886fbd27fa 100644 --- a/app/models/communication/website/page/research_hal_publication.rb +++ b/app/models/communication/website/page/research_hal_publication.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/research_paper.rb b/app/models/communication/website/page/research_paper.rb index 4312f9faf2c0c489aa9b35fb6fd76cc467514d8c..d8e10336593dc0ca1c02b444f171160e9c2aa80f 100644 --- a/app/models/communication/website/page/research_paper.rb +++ b/app/models/communication/website/page/research_paper.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/research_volume.rb b/app/models/communication/website/page/research_volume.rb index a4f383ee94591c114d8508d02f06da2fcf383c50..e732c2b7d8ffeb7f2e25940e9abb560a004c2c1a 100644 --- a/app/models/communication/website/page/research_volume.rb +++ b/app/models/communication/website/page/research_volume.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/researcher.rb b/app/models/communication/website/page/researcher.rb index c5ac173da59f5fa282ab2ef07f59d33c5c808af0..a82afe69a19a0a306ef64add4a08495a7c2ed86c 100644 --- a/app/models/communication/website/page/researcher.rb +++ b/app/models/communication/website/page/researcher.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/sitemap.rb b/app/models/communication/website/page/sitemap.rb index fe79d1768f24777ba90962f05b3f5b6ac6ae4674..cf8ce880f93f244d9ec5db07b3e8add146d76c94 100644 --- a/app/models/communication/website/page/sitemap.rb +++ b/app/models/communication/website/page/sitemap.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/page/teacher.rb b/app/models/communication/website/page/teacher.rb index 3b55bacc26db6160aedff1821b59fcfaa52cd875..ad29eedad7063952ad2dbecc8891454ee9424cd2 100644 --- a/app/models/communication/website/page/teacher.rb +++ b/app/models/communication/website/page/teacher.rb @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/app/models/communication/website/permalink.rb b/app/models/communication/website/permalink.rb index f0ad95d3bb04b34534913a03848e509c009197fa..9d3493a2a55252388d939c4eaddd5a6a2ff90811 100644 --- a/app/models/communication/website/permalink.rb +++ b/app/models/communication/website/permalink.rb @@ -92,6 +92,17 @@ class Communication::Website::Permalink < ApplicationRecord raise NotImplementedError end + def self.clean_path(path) + clean_path = path.dup + # Remove eventual host + clean_path = URI(clean_path).path + # Leading slash for absolute path + clean_path = "/#{clean_path}" unless clean_path.start_with?('/') + # Trailing slash for coherence + clean_path = "#{clean_path}/" unless clean_path.end_with?('/') + clean_path + end + def pattern language = about.respond_to?(:language) ? about.language : website.default_language self.class.pattern_in_website(website, language) @@ -116,6 +127,10 @@ class Communication::Website::Permalink < ApplicationRecord end end + def to_s + "#{path}" + end + protected def self.required_kinds_in_website(website) @@ -152,5 +167,4 @@ class Communication::Website::Permalink < ApplicationRecord def set_university self.university_id = website.university_id end - end diff --git a/app/models/communication/website/with_deuxfleurs.rb b/app/models/communication/website/with_deuxfleurs.rb index f1d37cc39b6d4927a400dbf079a91f36619a6e1a..5b590d295ce2b2f8f9302f26885d54032fc8da18 100644 --- a/app/models/communication/website/with_deuxfleurs.rb +++ b/app/models/communication/website/with_deuxfleurs.rb @@ -2,6 +2,7 @@ module Communication::Website::WithDeuxfleurs extend ActiveSupport::Concern included do + before_save :deuxfleurs_golive, if: :deuxfleurs_hosting after_save :deuxfleurs_setup, if: :deuxfleurs_hosting end @@ -26,6 +27,17 @@ module Communication::Website::WithDeuxfleurs end handle_asynchronously :deuxfleurs_setup + def deuxfleurs_golive + return unless in_production_changed? && in_production + # https://www.test.com -> www.test.com + new_identifier = URI(url).host + if deuxfleurs.rename_bucket(self.deuxfleurs_identifier, new_identifier) + self.deuxfleurs_identifier = new_identifier + else + errors.add :url + end + end + def deuxfleurs_create_bucket deuxfleurs_identifier = deuxfleurs.create_bucket(deuxfleurs_default_identifier) update_columns deuxfleurs_identifier: deuxfleurs_identifier, diff --git a/app/models/communication/website/with_security.rb b/app/models/communication/website/with_security.rb index 91cb5e05d7f689dd115a6ba7f4cc5fb1be5c06e3..9803230b6abf77d55cb78ed44a009169cd4aa251 100644 --- a/app/models/communication/website/with_security.rb +++ b/app/models/communication/website/with_security.rb @@ -13,11 +13,11 @@ module Communication::Website::WithSecurity def allowed_domains_default [ - 'osuny-1b4da.kxcdn.com', # KeyCDN for assets resize + ENV['KEYCDN_HOST'], # KeyCDN for assets resize '*.osuny.org', # Osuny for assets resize 'osuny.s3.fr-par.scw.cloud', # Scaleway for direct assets 'tile.openstreetmap.org' # Open Street Map default tiles - ] + ].compact end def allowed_domains_plausible diff --git a/app/models/concerns/with_permalink.rb b/app/models/concerns/with_permalink.rb index 1246b2464b12450cfe25959e1462fd1bb79decc2..68cd521b0b1127e963319c1c5e581105bf4fcf12 100644 --- a/app/models/concerns/with_permalink.rb +++ b/app/models/concerns/with_permalink.rb @@ -29,4 +29,13 @@ module WithPermalink new_permalink_in_website(website).save_if_needed end + def add_redirection(path) + clean_path = Communication::Website::Permalink.clean_path(path) + Communication::Website::Permalink.create( + website: website, + about: self, + is_current: false, + path: clean_path + ) + end end diff --git a/app/models/import.rb b/app/models/import.rb index d3ebfb313898a94e3b54ae7f60567fb31e867287..6e4c56d279484c96f3e5ed1fc582447e72afb004 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -10,7 +10,7 @@ # created_at :datetime not null # updated_at :datetime not null # university_id :uuid not null, indexed -# user_id :uuid not null, indexed +# user_id :uuid indexed # # Indexes # @@ -24,11 +24,10 @@ # class Import < ApplicationRecord belongs_to :university - belongs_to :user + belongs_to :user, optional: true has_one_attached_deletable :file - enum kind: { organizations: 0, alumni_cohorts: 1, people_experiences: 2 }, _prefix: :kind enum status: { pending: 0, finished: 1, finished_with_errors: 2 } diff --git a/app/models/user.rb b/app/models/user.rb index 3da9b8ced4d07c41daa1ab9719aa18aec6cc34d6..6e92659a9ac22e4f2158d41a21945b85fa84ff7c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -72,6 +72,7 @@ class User < ApplicationRecord belongs_to :language has_many :university_people, class_name: 'University::Person', dependent: :nullify + has_many :imports, class_name: 'Import', dependent: :nullify scope :ordered, -> { order(:last_name, :first_name) } scope :for_language, -> (language_id) { where(language_id: language_id) } diff --git a/app/models/user/with_registration_context.rb b/app/models/user/with_registration_context.rb index 2b994b4dd04a1644e00764dfd7a3d17ec8978583..a06d5dda1f32aef0b4eacd07b3fd5be1d509c2e8 100644 --- a/app/models/user/with_registration_context.rb +++ b/app/models/user/with_registration_context.rb @@ -6,6 +6,8 @@ module User::WithRegistrationContext validate :extranet_access, on: :create, if: -> { registration_context.is_a?(Communication::Extranet) } + after_create :send_notification_to_admins, unless: -> { registration_context.is_a?(Communication::Extranet) } + private def extranet_access @@ -30,5 +32,9 @@ module User::WithRegistrationContext registration_context.has_feature?(:contacts) && registration_context.connected_people.where(email: email).any? end + def send_notification_to_admins + NotificationMailer.new_registration(university, self).deliver_later + end + end end diff --git a/app/models/user/with_sync_between_universities.rb b/app/models/user/with_sync_between_universities.rb index da5871829b39ed39968771eda9241c88f31f854e..11aa0aae808d787f2437939455aabc56d0c0cb29 100644 --- a/app/models/user/with_sync_between_universities.rb +++ b/app/models/user/with_sync_between_universities.rb @@ -5,6 +5,7 @@ module User::WithSyncBetweenUniversities attr_accessor :skip_server_admin_sync after_save :sync_between_universities, if: Proc.new { |user| user.server_admin? && !user.skip_server_admin_sync } + after_destroy :remove_from_all_universities, if: Proc.new { |user| user.server_admin? && !user.skip_server_admin_sync } def self.synchronize_server_admin_users(source_university, target_university) source_university.users.server_admin.each do |user| @@ -48,4 +49,12 @@ module User::WithSyncBetweenUniversities user.update_column(:encrypted_password, self.encrypted_password) if user.valid? end + def remove_from_all_universities + # As a "server_admin" is synced between universities, any removal destroys the accounts of the concerned user in every university + User.where(email: email, role: :server_admin).each do |user| + user.skip_server_admin_sync = true + user.destroy + end + end + end diff --git a/app/services/curator.rb b/app/services/curator.rb deleted file mode 100644 index 4f7c5042800995657d8cb46f6614626fb6e8a485..0000000000000000000000000000000000000000 --- a/app/services/curator.rb +++ /dev/null @@ -1,54 +0,0 @@ -class Curator - attr_reader :website, :user, :language, :url, :post - - def initialize(website, user, language, url) - @website = website - @user = user - @language = language - @url = url - create_post! - attach_image! unless page.image.blank? - rescue - end - - def valid? - @post.valid? - end - - protected - - def create_post! - @post = website.posts.create( - university: website.university, - title: page.title, - slug: page.title.parameterize, - author: @user.person, - published_at: Time.now, - language_id: @language.id - ) - @chapter = @post.blocks.create( - university: website.university, - template_kind: :chapter, - published: true, - position: 0 - ) - text = Wordpress.clean_html("#{page.text}<p><a href=\"#{@url}\" target=\"_blank\">Source</a></p>") - data = @chapter.data.deep_dup - data['text'] = text - @chapter.data = data - @chapter.save - end - - def attach_image! - @post.featured_image.attach( - io: URI.open(page.image), - filename: File.basename(page.image).split('?').first - ) - rescue - puts "Attach image failed" - end - - def page - @page ||= Curation::Page.new(@url) - end -end diff --git a/app/services/deuxfleurs.rb b/app/services/deuxfleurs.rb index d0594d413f439167f216f0fe9ea909a719678bc6..468bb77daf1b7980ddd98e572bee079ca2c88026 100644 --- a/app/services/deuxfleurs.rb +++ b/app/services/deuxfleurs.rb @@ -6,6 +6,12 @@ class Deuxfleurs data.dig('vhost', 'name') end + def rename_bucket(host, new_identifier) + params = "{ \"vhost\": \"#{new_identifier}\" }" + response = client.patch("website/#{host}", params) + response.status == 200 + end + def default_url_for(host) "https://#{host}.web.deuxfleurs.fr" end diff --git a/app/services/download_service.rb b/app/services/download_service.rb deleted file mode 100644 index e0469ccfce588827aca48a6ea842a22bc1953497..0000000000000000000000000000000000000000 --- a/app/services/download_service.rb +++ /dev/null @@ -1,40 +0,0 @@ -class DownloadService - attr_reader :response - - def self.download(url) - new(url) - end - - def initialize(url) - @url = url - process! - end - - def attachable_data - { io: io, filename: filename, content_type: content_type } - end - - def io - @io ||= StringIO.new(@response.body) - end - - def filename - @filename ||= File.basename(@url) - end - - def content_type - @content_type ||= @response['Content-Type'] - end - - protected - - def process! - uri = URI(@url) - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = true - http.verify_mode = OpenSSL::SSL::VERIFY_NONE - - request = Net::HTTP::Get.new(uri.request_uri) - @response = http.request(request) - end -end \ No newline at end of file diff --git a/app/services/importers/api/osuny/communication/website/base.rb b/app/services/importers/api/osuny/communication/website/base.rb new file mode 100644 index 0000000000000000000000000000000000000000..22524bcfa459708dbfa5d36fe557fece635a8d4f --- /dev/null +++ b/app/services/importers/api/osuny/communication/website/base.rb @@ -0,0 +1,51 @@ +class Importers::Api::Osuny::Communication::Website::Base + + attr_reader :university, :website, :params + + def initialize(university:, website:, params:) + @university = university + @website = website + @params = params.to_unsafe_hash + import + end + + protected + + def import + raise NotImplementedError + end + + def object + raise NotImplementedError + end + + def language + # TODO specific language set in params + website.default_language + end + + def migration_identifier + @migration_identifier ||= params[:migration_identifier] + end + + def blocks + return [] unless params.has_key?(:blocks) + @blocks ||= params[:blocks] + end + + def import_blocks + blocks.each do |b| + migration_identifier = b[:migration_identifier] + template_kind = b[:template_kind] + block = object.blocks + .where( + migration_identifier: migration_identifier, + template_kind: template_kind + ) + .first_or_initialize + block.university = university + block.data = block.template.data.merge b[:data] + block.save + end + end +end \ No newline at end of file diff --git a/app/services/importers/api/osuny/communication/website/page.rb b/app/services/importers/api/osuny/communication/website/page.rb new file mode 100644 index 0000000000000000000000000000000000000000..48b139e1db2a3176f1cffa9842074320bd0b0580 --- /dev/null +++ b/app/services/importers/api/osuny/communication/website/page.rb @@ -0,0 +1,46 @@ +class Importers::Api::Osuny::Communication::Website::Page < Importers::Api::Osuny::Communication::Website::Base + + protected + + def import + import_params + import_blocks + end + + def import_params + object.title = Importers::Cleaner.clean_string params[:title] + object.summary = Importers::Cleaner.html_to_string params[:summary] + object.parent = parent + object.save + end + + def home_page + website.special_page(Communication::Website::Page::Home, language: language) + end + + def parent + parent_migration_identifier = params.dig(:parent, :migration_identifier) + @parent = page_with parent_migration_identifier if parent_migration_identifier + @parent = home_page if @parent.nil? + @parent + end + + def object + @object ||= page_with migration_identifier + end + + def page_with(migration_identifier) + website.pages.where( + university: university, + website: website, + migration_identifier: migration_identifier, + language: language + ).first_or_initialize + end + + def page_params + ActionController::Parameters.new({ page: params }) + .require(:page) + .permit(:title, :language, :meta_description, :summary) + end +end \ No newline at end of file diff --git a/app/services/importers/api/osuny/communication/website/post.rb b/app/services/importers/api/osuny/communication/website/post.rb new file mode 100644 index 0000000000000000000000000000000000000000..971ba20d1ed6d1faac822989ece0f10edd3da2c9 --- /dev/null +++ b/app/services/importers/api/osuny/communication/website/post.rb @@ -0,0 +1,51 @@ +class Importers::Api::Osuny::Communication::Website::Post < Importers::Api::Osuny::Communication::Website::Base + + protected + + def import + import_params + import_blocks + import_categories + end + + def object + @object ||= website.posts.where( + university: university, + website: website, + migration_identifier: migration_identifier, + language: language + ).first_or_initialize + end + + def import_params + object.title = Importers::Cleaner.clean_string params[:title] + object.summary = Importers::Cleaner.html_to_string params[:summary] + object.published_at = params[:published_at] + object.created_at = object.published_at + object.save + end + + def import_categories + categories.each do |c| + category = find_or_create_category c + next if category.nil? || category.in?(object.categories) + object.categories << category + end + end + + def find_or_create_category(data) + if data.has_key? 'name' + website.categories.where( + university: university, + website: website, + name: data['name'], + language: language + ).first_or_create + end + end + + def categories + return [] unless params.has_key?(:categories) + @categories ||= params[:categories] + end +end \ No newline at end of file diff --git a/app/services/importers/cleaner.rb b/app/services/importers/cleaner.rb new file mode 100644 index 0000000000000000000000000000000000000000..ac6cf93f2d8dcd355cf3e7fbc41d31a2b7a3b9b2 --- /dev/null +++ b/app/services/importers/cleaner.rb @@ -0,0 +1,63 @@ +module Importers + class Cleaner + + def self.html_to_string(html) + h = html + h = Importers::Cleaner.clean_html h + h = ActionController::Base.helpers.strip_tags h + h + end + + def self.clean_string(string) + string = string.gsub(' ', ' ') + string = string.gsub('&', '&') + string = ActionView::Base.full_sanitizer.sanitize string + string = remove_control_chars string + string + end + + def self.clean_html(html) + # invalid byte sequence in UTF-8 + # https://stackoverflow.com/questions/32826781/invalid-byte-sequence-in-utf-8-when-sanitizing-wordpress-export-content + html = html.force_encoding('UTF-8').scrub + # Relaxed config : https://github.com/rgrove/sanitize/blob/main/lib/sanitize/config/relaxed.rb + # iframe attributes from MDN : https://developer.mozilla.org/fr/docs/Web/HTML/Element/iframe + fragment = Sanitize.fragment(html, Sanitize::Config.merge(Sanitize::Config::RELAXED, + attributes: Sanitize::Config::RELAXED[:attributes].merge({ + all: Sanitize::Config::RELAXED[:attributes][:all].dup - ['class', 'style'], + 'a' => Sanitize::Config::RELAXED[:attributes]['a'].dup.delete('rel'), + 'iframe' => [ + 'allow', 'allowfullscreen', 'allowpaymentrequest', 'csp', 'height', 'loading', + 'name', 'referrerpolicy', 'sandbox', 'src', 'srcdoc', 'width', 'align', + 'frameborder', 'longdesc', 'marginheight', 'marginwidth', 'scrolling' + ] + }), + elements: Set.new(Sanitize::Config::RELAXED[:elements]) - ['div', 'style'] + ['iframe'], + remove_contents: ['math', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'xmp'], + whitespace_elements: { + 'div' => { :before => "", :after => "" } + } + )) + fragment = Nokogiri::HTML5.fragment(fragment) + if fragment.css('h1').any? + # h1 => h2 ; h2 => h3 ; ... + (1..5).to_a.reverse.each do |i| + fragment.css("h#{i}").each { |element| element.name = "h#{i+1}" } + end + end + html = fragment.to_html(preserve_newline: true) + html = remove_control_chars html + html + end + + protected + + def self.remove_control_chars(string) + # Control chars & LSEP are invisible or hard to detect + string = string.delete("
", "
", "
", "Â’") + string = string.gsub /\u2028/, '' + string + end + + end +end \ No newline at end of file diff --git a/app/services/importers/curator.rb b/app/services/importers/curator.rb new file mode 100644 index 0000000000000000000000000000000000000000..5e2631caaf1149a031489739d8fb8056c5acc6eb --- /dev/null +++ b/app/services/importers/curator.rb @@ -0,0 +1,56 @@ +module Importers + class Curator + attr_reader :website, :user, :language, :url, :post + + def initialize(website, user, language, url) + @website = website + @user = user + @language = language + @url = url + create_post! + attach_image! unless page.image.blank? + rescue + end + + def valid? + @post.valid? + end + + protected + + def create_post! + @post = website.posts.create( + university: website.university, + title: page.title, + slug: page.title.parameterize, + author: @user.person, + published_at: Time.now, + language_id: @language.id + ) + @chapter = @post.blocks.create( + university: website.university, + template_kind: :chapter, + published: true, + position: 0 + ) + text = Importers::Cleaner.clean_html("#{page.text}<p><a href=\"#{@url}\" target=\"_blank\">Source</a></p>") + data = @chapter.data.deep_dup + data['text'] = text + @chapter.data = data + @chapter.save + end + + def attach_image! + @post.featured_image.attach( + io: URI.open(page.image), + filename: File.basename(page.image).split('?').first + ) + rescue + puts "Attach image failed" + end + + def page + @page ||= Curation::Page.new(@url) + end + end +end \ No newline at end of file diff --git a/app/services/wordpress.rb b/app/services/wordpress.rb deleted file mode 100644 index 2b0240d70944d54929ccfa45af597cc0c8cfe246..0000000000000000000000000000000000000000 --- a/app/services/wordpress.rb +++ /dev/null @@ -1,100 +0,0 @@ -class Wordpress - attr_reader :url - - def self.clean_string(string) - string = string.gsub(' ', ' ') - string = string.gsub('&', '&') - string = ActionView::Base.full_sanitizer.sanitize string - string = remove_control_chars string - string - end - - def self.clean_html(html) - # invalid byte sequence in UTF-8 - # https://stackoverflow.com/questions/32826781/invalid-byte-sequence-in-utf-8-when-sanitizing-wordpress-export-content - html = html.force_encoding('UTF-8').scrub - # Relaxed config : https://github.com/rgrove/sanitize/blob/main/lib/sanitize/config/relaxed.rb - # iframe attributes from MDN : https://developer.mozilla.org/fr/docs/Web/HTML/Element/iframe - fragment = Sanitize.fragment(html, Sanitize::Config.merge(Sanitize::Config::RELAXED, - attributes: Sanitize::Config::RELAXED[:attributes].merge({ - all: Sanitize::Config::RELAXED[:attributes][:all].dup - ['class', 'style'], - 'a' => Sanitize::Config::RELAXED[:attributes]['a'].dup.delete('rel'), - 'iframe' => [ - 'allow', 'allowfullscreen', 'allowpaymentrequest', 'csp', 'height', 'loading', - 'name', 'referrerpolicy', 'sandbox', 'src', 'srcdoc', 'width', 'align', - 'frameborder', 'longdesc', 'marginheight', 'marginwidth', 'scrolling' - ] - }), - elements: Set.new(Sanitize::Config::RELAXED[:elements]) - ['div', 'style'] + ['iframe'], - remove_contents: ['math', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'xmp'], - whitespace_elements: { - 'div' => { :before => "", :after => "" } - } - )) - fragment = Nokogiri::HTML5.fragment(fragment) - if fragment.css('h1').any? - # h1 => h2 ; h2 => h3 ; ... - (1..5).to_a.reverse.each do |i| - fragment.css("h#{i}").each { |element| element.name = "h#{i+1}" } - end - end - html = fragment.to_html(preserve_newline: true) - html = remove_control_chars html - html - end - - def self.remove_control_chars(string) - # Control chars & LSEP are invisible or hard to detect - string = string.delete("
", "
", "
", "Â’") - string = string.gsub /\u2028/, '' - string - end - - def initialize(url) - @url = url - end - - def authors - load "#{url}/wp-json/wp/v2/users" - end - - def categories - load "#{url}/wp-json/wp/v2/categories" - end - - def posts - load "#{url}/wp-json/wp/v2/posts" - end - - def pages - load "#{url}/wp-json/wp/v2/pages" - end - - def media - load "#{url}/wp-json/wp/v2/media" - end - - protected - - def load(url) - page = 1 - posts = [] - loop do - batch = load_paged url, page - break if batch.is_a?(Hash) || batch.empty? - posts += batch - page += 1 - end - posts - end - - def load_paged(url, page) - puts "Load #{url } on page #{page}" - load_url "#{url}?page=#{page}&per_page=100" - end - - def load_url(url) - download_service = DownloadService.download(url) - JSON.parse(download_service.response.body) - end -end diff --git a/app/views/admin/application/permalinks/_redirects.html.erb b/app/views/admin/application/permalinks/_redirects.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..91dbab67ca8eadcbcdb304cc053b9998579da653 --- /dev/null +++ b/app/views/admin/application/permalinks/_redirects.html.erb @@ -0,0 +1,38 @@ +<p> + <a class="action" data-bs-toggle="offcanvas" href="#offcanvasRedirects" role="button" aria-controls="offcanvasRedirects"> + <%= t('admin.communication.website.redirects.button') %> + </a> +</p> +<div class="offcanvas offcanvas-end offcanvas__redirections" tabindex="-1" id="offcanvasRedirects" aria-labelledby="Redirections"> + <div class="offcanvas-header"> + <h2 class="offcanvas-title"><%= t('admin.communication.website.redirects.title') %></h2> + <button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button> + </div> + <div class="offcanvas-body"> + <%= osuny_panel t('admin.communication.website.redirects.current_path'), small: true do %> + <p class="lead"> + <%= @page.current_permalink_in_website(@website) %> + </p> + <% end %> + <%= osuny_panel t('admin.communication.website.redirects.previous_paths'), small: true do %> + <table id="previous-permalinks" class="table border-top"> + <tbody> + <% @page.previous_permalinks_in_website(@website).each do |link| %> + <tr> + <td><%= link.to_s %></td> + </tr> + <% end %> + </tbody> + </table> + <%= simple_form_for Communication::Website::Permalink.new, + url: admin_communication_website_permalinks_path( + about_type: about.class, + about_id: about.id + ), + remote: true do |f| %> + <%= f.input :path, label: t('admin.communication.website.redirects.add_path') %> + <%= f.button :submit, t('add'), class: button_classes %> + <% end %> + <% end %> + </div> +</div> \ No newline at end of file diff --git a/app/views/admin/communication/websites/categories/_treebranch.html.erb b/app/views/admin/communication/websites/categories/_treebranch.html.erb index b1a0cb7ef8b45f8b28add048009709af01ea671e..77ea107f355951cf0c9f63fd3a3ca45ffdfed139 100644 --- a/app/views/admin/communication/websites/categories/_treebranch.html.erb +++ b/app/views/admin/communication/websites/categories/_treebranch.html.erb @@ -13,8 +13,17 @@ <span class="close_text"><%= t 'folder.close' %></span> <% end %> <div class="btn-group ms-auto" role="group"> - <%= edit_link category %> - <%= destroy_link category %> + <%= link_to t('show'), + admin_communication_website_category_path(website_id: @website.id, id: category.id), + class: 'action ps-3' %> + <%= link_to t('edit'), + edit_admin_communication_website_category_path(website_id: @website.id, id: category.id), + class: 'action ps-3' %> + <%= link_to t('delete'), + admin_communication_website_category_path(website_id: @website.id, id: category.id), + method: :delete, + data: { confirm: t('please_confirm') }, + class: 'action text-danger ps-3' %> </div> </div> <ul class="list-unstyled treeview__children js-treeview-children js-treeview-sortable-container ms-4" data-id="<%= category.id %>"> diff --git a/app/views/admin/communication/websites/categories/index.html.erb b/app/views/admin/communication/websites/categories/index.html.erb index 37c76d8b756561e4225e0a303e334acece5ba99c..6a78ae52ca8a61793ae36036fa9a1a12c3e83408 100644 --- a/app/views/admin/communication/websites/categories/index.html.erb +++ b/app/views/admin/communication/websites/categories/index.html.erb @@ -1,17 +1,14 @@ <% content_for :title, "#{Communication::Website::Category.model_name.human(count: 2)} (#{@categories.count})" %> <%= render 'admin/communication/websites/sidebar' do %> - <div class="card"> - <div class="card-body"> - <ul class="list-unstyled treeview treeview--sortable js-treeview js-treeview-sortable js-treeview-sortable-container" - data-id="" - data-sort-url="<%= reorder_admin_communication_website_categories_path %>"> - <%= render 'treebranch', categories: @root_categories %> - </ul> - </div> - </div> -<% end %> - -<% content_for :action_bar_right do %> - <%= create_link Communication::Website::Category %> + <% + action = create_link Communication::Website::Category + %> + <%= osuny_panel Communication::Website::Category.model_name.human(count: 2), action: action do %> + <ul class="list-unstyled treeview treeview--sortable js-treeview js-treeview-sortable js-treeview-sortable-container" + data-id="" + data-sort-url="<%= reorder_admin_communication_website_categories_path %>"> + <%= render 'treebranch', categories: @root_categories %> + </ul> + <% end %> <% end %> diff --git a/app/views/admin/communication/websites/pages/show/_metadata.html.erb b/app/views/admin/communication/websites/pages/show/_metadata.html.erb index 11f23bc1deabecc8cac8a5ed0344d8844598d576..6d7e56fb26163c162d8b786f7c698996eb6bb266 100644 --- a/app/views/admin/communication/websites/pages/show/_metadata.html.erb +++ b/app/views/admin/communication/websites/pages/show/_metadata.html.erb @@ -3,6 +3,7 @@ # @pa t'affole pas, c'est pas encore le cas %> <%= osuny_panel t('metadata'), small: true do %> + <p> <% if @page.is_special_page? %> <% page_type = t("communication.website.pages.defaults.#{@page.type_key}.title") %> <% if page_type != @page.to_s %> @@ -16,12 +17,12 @@ <% if @page.parent && !@page.parent.is_home? %> dans - <%= link_to_if can?(:read, @page.parent), + “<%= link_to_if can?(:read, @page.parent), @page.parent, admin_communication_website_page_path( website_id: @website.id, id: @page.parent.id - ) %>. + ) %>†<% end %> <% if @page.children.any? %> @@ -32,12 +33,13 @@ admin_communication_website_page_path( website_id: @website.id, id: child.id), class: "#{'draft' unless child.published?}" - }.join(', ') %>. + }.join(', ') %> <% end %> <% if @page.full_width %> - <br> - Pleine largeur + en pleine largeur <% end %> + </p> + + <%= render 'admin/application/permalinks/redirects', about: @page %> <% end %> - diff --git a/app/views/admin/communication/websites/permalinks/create.js.erb b/app/views/admin/communication/websites/permalinks/create.js.erb new file mode 100644 index 0000000000000000000000000000000000000000..f16602c9a719d62e97847ce6fd89610c6ed14841 --- /dev/null +++ b/app/views/admin/communication/websites/permalinks/create.js.erb @@ -0,0 +1,7 @@ +document.getElementById('previous-permalinks') + .getElementsByTagName('tbody')[0] + .insertRow() + .insertCell() + .appendChild( + document.createTextNode('<%= @permalink.path %>') + ) diff --git a/app/views/admin/communication/websites/production.html.erb b/app/views/admin/communication/websites/production.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..7968e6a332d7030a16427314b62afea035a88196 --- /dev/null +++ b/app/views/admin/communication/websites/production.html.erb @@ -0,0 +1,18 @@ +<% content_for :title, t('communication.website.golive.title') %> + +<%= simple_form_for [:admin, @website] do |f| %> + <%= f.error_notification %> + <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %> + + <%= f.input :in_production, as: :hidden %> + + <div class="row"> + <div class="col-xl-6"> + <%= f.input :url %> + </div> + </div> + + <% content_for :action_bar_right do %> + <%= submit f %> + <% end %> +<% end %> \ No newline at end of file diff --git a/app/views/admin/communication/websites/show.html.erb b/app/views/admin/communication/websites/show.html.erb index 6b673312c89f6fd32bfbbc2bb578cb37a3303a50..61cca0d9256c8b2f7153b9ca4baade5651ea3c4c 100644 --- a/app/views/admin/communication/websites/show.html.erb +++ b/app/views/admin/communication/websites/show.html.erb @@ -27,4 +27,7 @@ <% content_for :action_bar_right do %> <%= edit_link @website %> + <%= link_to t('communication.website.golive.button'), + production_admin_communication_website_path(@website), + class: button_classes unless @website.in_production %> <% end %> diff --git a/app/views/admin/imports/show.html.erb b/app/views/admin/imports/show.html.erb index 468671382947ee3d91cc767a13ba3a41989cf728..813803e885efb8031f959642097314e867d93248 100644 --- a/app/views/admin/imports/show.html.erb +++ b/app/views/admin/imports/show.html.erb @@ -2,7 +2,14 @@ <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> + <p> + <%= t('imports.initiated_by') %> + <% if @import.user %> + <%= link_to_if can?(:read, @import.user), @import.user, [:admin, @import.user] %> + <% else %> + <%= t('imports.deleted_user') %> + <% end %> + </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 %> diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb index e0840a6cbe9824ffce82b3d59961e6910b92c8a8..0617c8886938f91282c75ab5340fae8cbd2cef96 100644 --- a/app/views/devise/registrations/new.html.erb +++ b/app/views/devise/registrations/new.html.erb @@ -1,4 +1,4 @@ -<%= content_for :title, t('.title') %> +<%= content_for :title, t('.title', title: current_extranet.present? ? current_extranet.name : 'Osuny') %> <h2 class="mb-4"><%= t(".sign_up") %></h2> diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index b88f05d8d82afd9f702a3aba0aa3a9905bc6b719..afd0b0b68e13e685293c3f381ea2985caebf9977 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -1,4 +1,4 @@ -<%= content_for :title, t('.title') %> +<%= content_for :title, t('.title', title: current_extranet.present? ? current_extranet.name : 'Osuny') %> <div class="row"> <div class="col-md-6 mb-5"> diff --git a/app/views/mailers/notifications/low_sms_credits.html.erb b/app/views/mailers/notifications/low_sms_credits.html.erb index 1407e04402742964ae4c37e023a62c8265f7cc82..3bf50e278f95e33042e45ecbf5ed5679a0cc77b7 100644 --- a/app/views/mailers/notifications/low_sms_credits.html.erb +++ b/app/views/mailers/notifications/low_sms_credits.html.erb @@ -1,3 +1,3 @@ -<%= t('mailers.notifications.low_sms_credits.body_1_html', credits: @credits) %> -<br> -<%= t('mailers.notifications.low_sms_credits.body_2_html', link: 'https://app.sendinblue.com/billing/addon/customize/sms') %> \ No newline at end of file +<p><%= t('mailers.notifications.low_sms_credits.body_1_html', credits: @credits) %></p> +<p><%= t('mailers.notifications.low_sms_credits.body_2_html', link: 'https://app.brevo.com/billing/account/customize/message-credits') %></p> +<p><%= t('mailers.yours') %></p> \ No newline at end of file diff --git a/app/views/mailers/notifications/new_registration.html.erb b/app/views/mailers/notifications/new_registration.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..14e3fdb0e88c595604e903ea26646c30f6e9adc8 --- /dev/null +++ b/app/views/mailers/notifications/new_registration.html.erb @@ -0,0 +1,3 @@ +<p><%= t('mailers.notifications.new_registration.body_1_html', username: @user.to_s) %></p> +<p><%= t('mailers.notifications.new_registration.body_2_html', link: admin_user_url(@user)) %></p> +<p><%= t('mailers.yours') %></p> \ No newline at end of file diff --git a/app/views/server/dashboard/index.html.erb b/app/views/server/dashboard/index.html.erb index 0415ed36739a0384b40640773df349fc3969c1ae..d112c6976d705d97df8334fee7f4d239e61564c9 100644 --- a/app/views/server/dashboard/index.html.erb +++ b/app/views/server/dashboard/index.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, t('hello', name: current_user.first_name) %> +<% content_for :title, t('server_admin.dashboard') %> <div class="row"> <% @parts.each do |part| %> diff --git a/app/views/server/websites/_list.html.erb b/app/views/server/websites/_list.html.erb index 348d4f4648266f317bdf849dd32d6363a38df66a..0c60c5694cf32eca98209aad247f14ff8facca8c 100644 --- a/app/views/server/websites/_list.html.erb +++ b/app/views/server/websites/_list.html.erb @@ -14,7 +14,7 @@ <% websites.ordered.each do |website| %> <tr id="website-<%= website.id %>"> <td> - <%= website.name %> + <%= link_to website.name, server_website_path(website) %> <% if website.in_production %> <span class="badge bg-success">Prod</span> <% end %> diff --git a/app/views/server/websites/edit.html.erb b/app/views/server/websites/edit.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..612786613c469d27b4e649aeaf09b022fd4bbd33 --- /dev/null +++ b/app/views/server/websites/edit.html.erb @@ -0,0 +1,11 @@ +<% content_for :title, @website %> +<%= simple_form_for @website, url: server_website_path(@website) do |f| %> + <%= f.error_notification %> + <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %> + + <%= f.association :university, include_blank: false %> + + <% content_for :action_bar_right do %> + <%= submit f %> + <% end %> +<% end %> \ No newline at end of file diff --git a/app/views/server/websites/show.html.erb b/app/views/server/websites/show.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..c24a62d332f6466581eb8316d105bb753b9887bb --- /dev/null +++ b/app/views/server/websites/show.html.erb @@ -0,0 +1,18 @@ +<% content_for :title, @website %> + +<p> + Université : + <%= link_to @website.university, server_university_path(@website.university) %> +</p> + +<%= @website.pages.count %> pages<br> +<%= @website.posts.count %> actualités<br> +<%= @website.events.count %> événements<br> +<%= @website.connections.count %> connexions + (<%= link_to 'détail', admin_communication_website_connections_url(@website, host: @website.university.url), target: :_blank %>)<br> +<%= @website.recursive_dependencies.count %> dépendances + (<%= link_to 'détail', admin_communication_website_dependencies_url(@website, host: @website.university.url), target: :_blank %>)<br> + +<% content_for :action_bar_right do %> + <%= link_to t('edit'), edit_server_website_path(@website), class: button_classes %> +<% end %> diff --git a/config/application.rb b/config/application.rb index 976a5578724769899c1df132e7a6324762dfde31..8ff90a501a0f9a35ed7b0e20f3a04781fc848497 100644 --- a/config/application.rb +++ b/config/application.rb @@ -60,6 +60,8 @@ module Osuny # Need for +repage, because of https://github.com/rails/rails/commit/b2ab8dd3a4a184f3115e72b55c237c7b66405bd9 config.active_storage.supported_image_processing_methods = ["+"] + # TEMP TODO: Corriger le problème des nbsp avec le sanitizer HTML5 + config.action_view.sanitizer_vendor = Rails::HTML4::Sanitizer config.action_view.sanitized_allowed_tags = [ "a", "b", "br", "em", "i", "img", "li", "ol", "p", "strong", "sub", "sup", "ul" ] diff --git a/config/application.sample.yml b/config/application.sample.yml index 02c0dbb10cf5be4547248b15f85b179c9ffc50d5..1791af25fe9aa85b623cab112eca5bc8134255f2 100644 --- a/config/application.sample.yml +++ b/config/application.sample.yml @@ -6,8 +6,8 @@ BUGSNAG_RUBY_KEY: GITHUB_WEBSITE_THEME_BRANCH: GITHUB_WEBSITE_THEME_PATH: GITHUB_WEBSITE_THEME_REPOSITORY: -GITHUB_WEBSITE_TEMPLATE_REPOSITORY: -GITHUB_ACCESS_TOKEN: +GITHUB_WEBSITE_TEMPLATE_REPOSITORY: +GITHUB_ACCESS_TOKEN: MAIL_FROM_DEFAULT_ADDRESS: MAIL_FROM_DEFAULT_NAME: @@ -27,6 +27,8 @@ SCALEWAY_OS_ENDPOINT: SCALEWAY_OS_REGION: SCALEWAY_OS_SECRET_ACCESS_KEY: +KEYCDN_HOST: + SECRET_KEY_BASE: SEND_IN_BLUE_API_KEY: @@ -38,8 +40,8 @@ UNSPLASH_ACCESS_KEY: UNSPLASH_SECRET: PEXELS_API_KEY: -DEUXFLEURS_USER: -DEUXFLEURS_PASSWORD: +DEUXFLEURS_USER: +DEUXFLEURS_PASSWORD: MAINTENANCE: "false" @@ -53,4 +55,3 @@ TEST_GITLAB_BRANCH: TEST_GITLAB_ENDPOINT: TEST_GITLAB_TOKEN: TEST_GITLAB_REPOSITORY: - diff --git a/config/initializers/active_storage.rb b/config/initializers/active_storage.rb index 9d150045ab9405160c8bccb5f79d614fa4b1ace8..958d56d7b41045066bb324a3258265f1ded6d8d7 100644 --- a/config/initializers/active_storage.rb +++ b/config/initializers/active_storage.rb @@ -4,7 +4,7 @@ Rails.application.config.to_prepare do # Hook ActiveStorage::Attachment to add brand_id to attachments records ActiveStorage::Attachment.class_eval do - after_save :denormalize_university_id_for_blob, unless: :university_id + after_save :denormalize_university_id_for_blob def denormalize_university_id_for_blob university_id = case self.record.class.name diff --git a/config/locales/communication/contents/en.yml b/config/locales/communication/contents/en.yml index 648bfb84007f139780f8e23dd3bd0aaf0cda8e09..b9800dba56d3b40a47b4c1dc3285a44174b1077f 100644 --- a/config/locales/communication/contents/en.yml +++ b/config/locales/communication/contents/en.yml @@ -58,7 +58,10 @@ en: description: Events are presented as a grid, from left to right and top to bottom, with constant size cropped images. list: label: List - description: A list of posts with small images the same width. + description: A list of events with dates, small images, all the same width. + large: + label: Grand + description: Each event is presented in majesty, across the full width available, with a large image. edit: description: label: Description diff --git a/config/locales/communication/contents/fr.yml b/config/locales/communication/contents/fr.yml index a16c67cb12bccdd3b96c19ac778bb8217010cec6..1958157b4080dc3f268ac641c98a0165a6fc933c 100644 --- a/config/locales/communication/contents/fr.yml +++ b/config/locales/communication/contents/fr.yml @@ -59,6 +59,9 @@ fr: list: label: Liste description: Une liste d'événements avec de petites images à la même largeur. + large: + label: Grand + description: Chaque événement est présenté en majesté, sur toute la largeur disponible avec une grande image. edit: description: label: Description diff --git a/config/locales/communication/en.yml b/config/locales/communication/en.yml index ab0028d1a18374fba115e4c16ac77d76b81b5cec..7a4aad58855f571ab6a33e525abc5cbf3785c120 100644 --- a/config/locales/communication/en.yml +++ b/config/locales/communication/en.yml @@ -163,6 +163,7 @@ en: social_x: "X, ex-Twitter (private)" social_youtube: "Youtube (private, belongs to Google)" url: URL + university: University communication/website/agenda/event: dates: Dates featured_image: Featured image @@ -217,6 +218,8 @@ en: text: Main page text title: Title website: Website + communication/website/permalink: + path: Path communication/website/post: author: Author category: Category @@ -267,6 +270,12 @@ en: publish: button: Publish notice: Publication in progress, it should take a few minutes to be online. + redirects: + button: Manage redirects + title: Manage redirects + current_path: Current path + previous_paths: Redirects (old paths) + add_path: Add a redirect communication: authors: one: Author @@ -295,6 +304,9 @@ en: website: analytics: Analytics git: Git + golive: + title: Go live + button: Go live hosting: Hosting last_events: Last events last_pages: Last pages @@ -417,6 +429,7 @@ en: languages: 'If you select one language the website urls will not be prefixed. If you select more than one language the website will then be considered as multilingual, and therefore all urls will be prefixed with the language (/fr, /en)' plausible_url: Dashboard link generated following the <a href="https://plausible.io/docs/shared-links" target="_blank">official Plausible documentation</a>. repository: As organization/name, for example noesya/bordeauxmontaigne-iut + university: Please note that changing university will disconnect people and organisations that are used on other sites, and will disconnect people from users. communication_website_page: breadcrumb_title: If the field is empty, page title will be used in breadcrumbs. full_width: On large screens, a full width page uses all available space for the content. This is good for landing pages, or to make them spectacular. If the page is not full width, the content column will be smaller to make reading easier. The unused space might be used for a table of contents. diff --git a/config/locales/communication/fr.yml b/config/locales/communication/fr.yml index 4a2a0fd4bfd8315d3d195d015831c93d7b74dec9..c84e9a75931acc5c4ef6aace2b46bf596b49bfc9 100644 --- a/config/locales/communication/fr.yml +++ b/config/locales/communication/fr.yml @@ -162,6 +162,7 @@ fr: social_vimeo: "Vimeo (privatif)" social_x: "X, ex-Twitter (privatif)" social_youtube: "Youtube (privatif, appartient à Google)" + university: Université url: URL communication/website/agenda/event: dates: Dates @@ -217,6 +218,8 @@ fr: text: Texte principal de la page title: Titre website: Site Web + communication/website/permalink: + path: Chemin communication/website/post: author: Auteur·rice category: Catégorie @@ -267,6 +270,12 @@ fr: publish: button: Publier notice: Publication en cours, cela devrait prendre quelques minutes pour arriver en ligne. + redirects: + button: Gérer les redirections + title: Gérer les redirections + current_path: Chemin actuel + previous_paths: Redirections (anciens chemins) + add_path: Ajouter une redirection communication: authors: one: Auteur·rice @@ -295,6 +304,9 @@ fr: website: analytics: Analytics git: Git + golive: + title: Mise en production + button: Mettre en production hosting: Hébergement last_events: Derniers événements last_pages: Dernières pages @@ -417,6 +429,7 @@ fr: languages: 'Si vous sélectionnez une seule langue les urls ne seront pas préfixées. Si vous en sélectionnez plusieurs le site sera considéré comme multilingue et donc toutes les urls seront préfixées avec la langue (/fr, /en)' plausible_url: Lien de partage généré selon la <a href="https://plausible.io/docs/shared-links" target="_blank">documentation officielle Plausible</a>. repository: Sous la forme organisation/nom, par exemple noesya/bordeauxmontaigne-iut + university: Attention, le changement d'université va déconnecter les personnes et organisations qui sont utilisées dans d'autres sites, et déconnecter les personnes des utilisateurs ou utilisatrices. communication_website_page: breadcrumb_title: Si ce champ est vide le titre de la page sera utilisé dans le fil d'Ariane. full_width: Sur de grands écrans, la page en pleine largeur utilisera tout l'espace disponible, ce qui est pertinent pour événementialiser une page. Si la page n'est pas en pleine largeur, l'espace dédié au contenu sera réduit pour faciliter la lecture, et l'espace libre pourra être utilisé pour une table des matières facilitant la navigation. diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml index a6530d7da264102f4008c1eec24d4819778873ee..e623f762d2a778fbed5121a44ba03cd68df3c890 100644 --- a/config/locales/devise.en.yml +++ b/config/locales/devise.en.yml @@ -12,10 +12,10 @@ en: edit: title: Account edition new: - title: Register on Osuny + title: "Register - %{title}" sessions: new: - title: Welcome to Osuny + title: "Welcome - %{title}" two_factor_authentication: max_login_attempts_reached: title: Maximul login attemps reached diff --git a/config/locales/devise.fr.yml b/config/locales/devise.fr.yml index 8682c0c11b2dc3742b7025206027554230173773..193656edf0f8376c53394d5b7f249e87d4ab0ee4 100644 --- a/config/locales/devise.fr.yml +++ b/config/locales/devise.fr.yml @@ -12,10 +12,10 @@ fr: edit: title: Modification de votre compte new: - title: Inscription sur Osuny + title: "Inscription - %{title}" sessions: new: - title: Bienvenue sur Osuny + title: "Bienvenue - %{title}" two_factor_authentication: max_login_attempts_reached: title: Maximum d'essais atteint diff --git a/config/locales/en.yml b/config/locales/en.yml index b7df966e0689cb975c9b1ab2ef3b9f00f940cd6a..31e2c4cac44c1d5501ba4b893da02c834dbc74b3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -236,6 +236,7 @@ en: hello: "Hello %{name}!" home: Home imports: + deleted_user: Deleted user error_msg: "Line %{line}: %{error}" errors: Errors example_file_html: Download an <a href="%{link}" target="_blank">example file</a> @@ -276,10 +277,14 @@ en: body_1_html: "Warning, your SMS credits are low: %{credits} credits remaining!" body_2_html: "Click <a href=\"%{link}\" target=\"_blank\" style=\"color: #c72b43;\">here</a> to refull." subject: "Osuny - Low SMS Credits (%{credits})" + new_registration: + body_1_html: "A new user (%{username}) just registered." + body_2_html: "Click <a href=\"%{link}\" target=\"_blank\" style=\"color: #c72b43;\">here</a> to see the account." + subject: "A new user just registered: %{mail}" website_invalid_access_token: subject: "Expired access token for \"%{website}\"" text_line_1_html: "The access token used for the website \"%{website}\" has expired and does not allow the website to be updated anymore." - text_line_2_html: "To solve this issue, please fill in a new access token by clicking <a href=\"%{url}\">here</a>." + text_line_2_html: "To solve this issue, please fill in a new access token by clicking <a href=\"%{url}\" target=\"_blank\" style=\"color: #c72b43;\">here</a>." yours: Yours. menu: admin: Admin @@ -310,6 +315,7 @@ en: search: Search select_language: Select language server_admin: + dashboard: Server administration emergency_messages: all_universities: All all_roles: All diff --git a/config/locales/fr.yml b/config/locales/fr.yml index bd8323c6fbace4244be7a38e5e476a9a3fbc8ca5..304eeb6bad444599f70be388756f7fc3b8179454 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -236,6 +236,7 @@ fr: hello: "Bonjour %{name} !" home: Accueil imports: + deleted_user: Utilisateur supprimé error_msg: "Ligne %{line} : %{error}" errors: Erreurs example_file_html: Télécharger un <a href="%{link}" target="_blank">fichier d'exemple</a> @@ -276,10 +277,14 @@ fr: body_1_html: "Attention, vos crédits SMS sont bas : %{credits} crédits restants !" body_2_html: "Cliquez <a href=\"%{link}\" target=\"_blank\" style=\"color: #c72b43;\">ici</a> pour recharger le compte." subject: "Osuny - Credits SMS bas (%{credits})" + new_registration: + body_1_html: "Un nouvel utilisateur (%{username}) vient de s'enregistrer." + body_2_html: "Cliquez <a href=\"%{link}\" target=\"_blank\" style=\"color: #c72b43;\">ici</a> pour voir son compte." + subject: "Un nouvel utilisateur vient de s'inscrire : %{mail}" website_invalid_access_token: subject: Jeton d'accès expiré pour « %{website} » text_line_1_html: Le jeton d'accès utilisé pour le site « %{website} » a expiré et ne permet plus la mise à jour du site. - text_line_2_html: Pour résoudre ce problème, veuillez renseigner un nouveau jeton d'accès en cliquant <a href=\"%{url}\">ici</a>. + text_line_2_html: "Pour résoudre ce problème, veuillez renseigner un nouveau jeton d'accès en cliquant <a href=\"%{url}\" target=\"_blank\" style=\"color: #c72b43;\">ici</a>." yours: Cordialement. menu: admin: Admin @@ -310,6 +315,7 @@ fr: search: Rechercher select_language: Sélectionnez une langue server_admin: + dashboard: Administration du serveur emergency_messages: all_universities: Toutes all_roles: Tous diff --git a/config/routes/admin/communication.rb b/config/routes/admin/communication.rb index 8c851edbc704856e35599db897b260be412d0bee..e739fb561ec0823ee29d5b16c8bd9d5e7a30aa8d 100644 --- a/config/routes/admin/communication.rb +++ b/config/routes/admin/communication.rb @@ -8,11 +8,13 @@ namespace :communication do get :analytics get :security get :static + get :production end get 'style' => 'websites/preview#style', as: :style get 'assets/*path' => 'websites/preview#assets' resources :dependencies, controller: 'websites/dependencies', only: :index resources :connections, controller: 'websites/connections', only: [:index, :show] + resources :permalinks, controller: 'websites/permalinks', only: :create resources :pages, controller: 'websites/pages', path: '/:lang/pages' do collection do post :reorder diff --git a/config/routes/api.rb b/config/routes/api.rb index 8c1950d03bb111156f5d033441356bf04dde7422..61b6b6301cb94156af34801cb245cca59223ed02 100644 --- a/config/routes/api.rb +++ b/config/routes/api.rb @@ -7,6 +7,7 @@ namespace :api do get 'websites' => 'websites#index' namespace :websites do post ':website_id/posts/import' => 'posts#import' + post ':website_id/pages/import' => 'pages#import' end end namespace :server do diff --git a/config/routes/server.rb b/config/routes/server.rb index af417e0c0892810bb70e1b1594b20f9ecc1c5b1b..a5c8ee6adfd9b07fad58a245262daa916a4add7c 100644 --- a/config/routes/server.rb +++ b/config/routes/server.rb @@ -1,7 +1,7 @@ namespace :server do resources :universities resources :languages - resources :websites, only: :index do + resources :websites do member do post :sync_theme_version post :update_theme diff --git a/db/migrate/20231013090313_change_imports_user_nil.rb b/db/migrate/20231013090313_change_imports_user_nil.rb new file mode 100644 index 0000000000000000000000000000000000000000..00404e4079ab0eca3cad3e48bbecc9a808d9e3cc --- /dev/null +++ b/db/migrate/20231013090313_change_imports_user_nil.rb @@ -0,0 +1,5 @@ +class ChangeImportsUserNil < ActiveRecord::Migration[7.0] + def change + change_column_null :imports, :user_id, true + end +end diff --git a/db/migrate/20231018182341_add_migration_identifier_to_communication_website_pages.rb b/db/migrate/20231018182341_add_migration_identifier_to_communication_website_pages.rb new file mode 100644 index 0000000000000000000000000000000000000000..ca4c63d9de0b15a9cdc849015c952c238b1b3787 --- /dev/null +++ b/db/migrate/20231018182341_add_migration_identifier_to_communication_website_pages.rb @@ -0,0 +1,5 @@ +class AddMigrationIdentifierToCommunicationWebsitePages < ActiveRecord::Migration[7.0] + def change + add_column :communication_website_pages, :migration_identifier, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index eb300673cd28c521c85435321edf407fbb8057d0..659e0ae397ed6501c52e9dedbd3b6089c4283ee7 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_10_06_145950) do +ActiveRecord::Schema[7.1].define(version: 2023_10_18_182341) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -381,6 +381,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_10_06_145950) do t.boolean "full_width", default: false t.string "type" t.uuid "original_id" + t.string "migration_identifier" t.index ["communication_website_id"], name: "index_communication_website_pages_on_communication_website_id" t.index ["language_id"], name: "index_communication_website_pages_on_language_id" t.index ["original_id"], name: "index_communication_website_pages_on_original_id" @@ -650,7 +651,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_10_06_145950) do t.integer "kind" t.integer "status", default: 0 t.uuid "university_id", null: false - t.uuid "user_id", null: false + t.uuid "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["university_id"], name: "index_imports_on_university_id" diff --git a/test/fixtures/communication/extranets.yml b/test/fixtures/communication/extranets.yml index 5b00f559b78ac19b9a3871e2736923e92e325c4b..c4a72564511a4905256b44eff1b90d9ad95d76db 100644 --- a/test/fixtures/communication/extranets.yml +++ b/test/fixtures/communication/extranets.yml @@ -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/test/fixtures/communication/website/pages.yml b/test/fixtures/communication/website/pages.yml index 7acaaf1b263b1c1dac961fa81511f525564335bd..f56dc72fa319e3b2114ca661a4126b33a2d1ab4d 100644 --- a/test/fixtures/communication/website/pages.yml +++ b/test/fixtures/communication/website/pages.yml @@ -11,6 +11,7 @@ # header_text :text # kind :integer # meta_description :text +# migration_identifier :string # position :integer default(0), not null # published :boolean default(FALSE) # slug :string indexed diff --git a/test/integration/wordpress_test.rb b/test/integration/wordpress_test.rb deleted file mode 100644 index 8ab63b607b573857e7b79040e48b339d81c14740..0000000000000000000000000000000000000000 --- a/test/integration/wordpress_test.rb +++ /dev/null @@ -1,67 +0,0 @@ -require "test_helper" - -class WordpressTest < ActiveSupport::TestCase - test "convert apostroph" do - assert_equal 'Ouverture du CRM pendant les vacances d’Avril', - Wordpress.clean_html('Ouverture du CRM pendant les vacances d’Avril') - end - - test "convert 3 dots" do - assert_equal 'Le CRM fait le tri dans ses collections … et vous propose une vente de livres', - Wordpress.clean_html('Le CRM fait le tri dans ses collections … et vous propose une vente de livres') - end - - test "convert double quotation marks" do - assert_equal 'Conférence Joëlle Zask : “Ecologie de la participationâ€', - Wordpress.clean_html('Conférence Joëlle Zask : “Ecologie de la participation”') - end - - test "convert h1" do - assert_equal '<h2>B.U.T. Métiers du multimédia et de l’internet</h2>', - Wordpress.clean_html('<h1>B.U.T. Métiers du multimédia et de l’internet</h1>') - end - - test "convert h2 without h1" do - assert_equal '<h2>B.U.T. Métiers du multimédia et de l’internet</h2>', - Wordpress.clean_html('<h2>B.U.T. Métiers du multimédia et de l’internet</h2>') - end - - test "convert h2 with h1" do - assert_equal '<h2>Bachelor Universitaire de Technologie</h2><h3>B.U.T. Métiers du multimédia et de l’internet</h3>', - Wordpress.clean_html('<h1>Bachelor Universitaire de Technologie</h1><h2>B.U.T. Métiers du multimédia et de l’internet</h2>') - end - - test "convert " do - assert_equal 'TRAVAILLER DEMAIN, Débat – le 10 mai à 18h30', - Wordpress.clean_html('TRAVAILLER DEMAIN, Débat – le 10 mai à 18h30') - end - - test "remove classes" do - assert_equal '<h2>→ Qu’est-ce que le B.U.T. ?</h2>', - Wordpress.clean_html('<h2 class="titre-diplome">→ Qu’est-ce que le B.U.T. ?</h2>') - end - - test "remove line_separators (LSEP)" do - # Invisible char before A, and html code - assert_equal "Au ", - Wordpress.clean_html("
Au 
") - end - - test "remove divs" do - # Quid des images ? Comment gérer le transfert vers scaleway + active storage dans le code ? - assert_equal '<figure><a href="https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1.png"><img src="https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1-240x300.png" alt="Le BUT, qu\'est-ce que c\'est ?" width="173" height="216" srcset="https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1-240x300.png 240w, https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1.png 730w"></a></figure>', - Wordpress.clean_html('<div class="wp-block-group"><div class="wp-block-group__inner-container"><div class="wp-block-columns"><div class="wp-block-column"><div class="wp-block-image"><figure class="alignright size-medium is-resized"><a href="https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1.png" rel="lightbox[14475]"><img src="https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1-240x300.png" alt="Le BUT, qu\'est-ce que c\'est ?" class="wp-image-14821" width="173" height="216" srcset="https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1-240x300.png 240w, https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1.png 730w"></a></figure></div></div>') - - - end - - test "convert in titles" do - assert_equal ' ', - Wordpress.clean_string(' ') - end - - test "authorize iframes" do - assert_equal "<figure><iframe loading=\"lazy\" title=\"Le Bachelor Universitaire de Technologie, qu'est-ce que c'est ? - LES IUT\" width=\"640\" height=\"360\" src=\"https://www.youtube.com/embed/5xbeKHi0txk?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen=\"\"></iframe></figure>", - Wordpress.clean_html('<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper"><iframe loading="lazy" title="Le Bachelor Universitaire de Technologie, qu'est-ce que c'est ? - LES IUT" width="640" height="360" src="https://www.youtube.com/embed/5xbeKHi0txk?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div></figure>') - end -end diff --git a/test/mailers/previews/notification_mailer_preview.rb b/test/mailers/previews/notification_mailer_preview.rb index d5557f836e051baa7aea245d9486f0f97b8b3848..eb971f394e801e755c5b26b742e1f169795c1a8f 100644 --- a/test/mailers/previews/notification_mailer_preview.rb +++ b/test/mailers/previews/notification_mailer_preview.rb @@ -23,5 +23,10 @@ class NotificationMailerPreview < BaseMailerPreview NotificationMailer.low_sms_credits(university, credits) end + # Preview this email at http://localhost:3000/rails/mailers/notification_mailer/new_registration + def new_registration + NotificationMailer.new_registration(university, user) + end + end diff --git a/test/services/importers/cleaner_test.rb b/test/services/importers/cleaner_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..eb0cb64db9116e24542892a6395ccaa1e8f885d0 --- /dev/null +++ b/test/services/importers/cleaner_test.rb @@ -0,0 +1,67 @@ +require "test_helper" + +class Importers::CleanerTest < ActiveSupport::TestCase + test "convert apostroph" do + assert_equal 'Ouverture du CRM pendant les vacances d’Avril', + Importers::Cleaner.clean_html('Ouverture du CRM pendant les vacances d’Avril') + end + + test "convert 3 dots" do + assert_equal 'Le CRM fait le tri dans ses collections … et vous propose une vente de livres', + Importers::Cleaner.clean_html('Le CRM fait le tri dans ses collections … et vous propose une vente de livres') + end + + test "convert double quotation marks" do + assert_equal 'Conférence Joëlle Zask : “Ecologie de la participationâ€', + Importers::Cleaner.clean_html('Conférence Joëlle Zask : “Ecologie de la participation”') + end + + test "convert h1" do + assert_equal '<h2>B.U.T. Métiers du multimédia et de l’internet</h2>', + Importers::Cleaner.clean_html('<h1>B.U.T. Métiers du multimédia et de l’internet</h1>') + end + + test "convert h2 without h1" do + assert_equal '<h2>B.U.T. Métiers du multimédia et de l’internet</h2>', + Importers::Cleaner.clean_html('<h2>B.U.T. Métiers du multimédia et de l’internet</h2>') + end + + test "convert h2 with h1" do + assert_equal '<h2>Bachelor Universitaire de Technologie</h2><h3>B.U.T. Métiers du multimédia et de l’internet</h3>', + Importers::Cleaner.clean_html('<h1>Bachelor Universitaire de Technologie</h1><h2>B.U.T. Métiers du multimédia et de l’internet</h2>') + end + + test "convert " do + assert_equal 'TRAVAILLER DEMAIN, Débat – le 10 mai à 18h30', + Importers::Cleaner.clean_html('TRAVAILLER DEMAIN, Débat – le 10 mai à 18h30') + end + + test "remove classes" do + assert_equal '<h2>→ Qu’est-ce que le B.U.T. ?</h2>', + Importers::Cleaner.clean_html('<h2 class="titre-diplome">→ Qu’est-ce que le B.U.T. ?</h2>') + end + + test "remove line_separators (LSEP)" do + # Invisible char before A, and html code + assert_equal "Au ", + Importers::Cleaner.clean_html("
Au 
") + end + + test "remove divs" do + # Quid des images ? Comment gérer le transfert vers scaleway + active storage dans le code ? + assert_equal '<figure><a href="https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1.png"><img src="https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1-240x300.png" alt="Le BUT, qu\'est-ce que c\'est ?" width="173" height="216" srcset="https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1-240x300.png 240w, https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1.png 730w"></a></figure>', + Importers::Cleaner.clean_html('<div class="wp-block-group"><div class="wp-block-group__inner-container"><div class="wp-block-columns"><div class="wp-block-column"><div class="wp-block-image"><figure class="alignright size-medium is-resized"><a href="https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1.png" rel="lightbox[14475]"><img src="https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1-240x300.png" alt="Le BUT, qu\'est-ce que c\'est ?" class="wp-image-14821" width="173" height="216" srcset="https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1-240x300.png 240w, https://www.iut.u-bordeaux-montaigne.fr/wp-content/uploads/2021/01/visuel_1.png 730w"></a></figure></div></div>') + + + end + + test "convert in titles" do + assert_equal ' ', + Importers::Cleaner.clean_string(' ') + end + + test "authorize iframes" do + assert_equal "<figure><iframe loading=\"lazy\" title=\"Le Bachelor Universitaire de Technologie, qu'est-ce que c'est ? - LES IUT\" width=\"640\" height=\"360\" src=\"https://www.youtube.com/embed/5xbeKHi0txk?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen=\"\"></iframe></figure>", + Importers::Cleaner.clean_html('<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper"><iframe loading="lazy" title="Le Bachelor Universitaire de Technologie, qu'est-ce que c'est ? - LES IUT" width="640" height="360" src="https://www.youtube.com/embed/5xbeKHi0txk?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div></figure>') + end +end diff --git a/yarn.lock b/yarn.lock index c7d515077ce9a861f931e17189c3cecd9862a22a..fd10b729c4d949633b45a9b8949776f393257ade 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,105 +2,110 @@ # yarn lockfile v1 -"@babel/parser@^7.16.4": - version "7.20.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.3.tgz#5358cf62e380cf69efcb87a7bb922ff88bfac6e2" - integrity sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg== - -"@vue/compiler-core@3.2.45": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.45.tgz#d9311207d96f6ebd5f4660be129fb99f01ddb41b" - integrity sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A== +"@babel/parser@^7.20.15", "@babel/parser@^7.21.3": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" + integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== + +"@jridgewell/sourcemap-codec@^1.4.15": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@vue/compiler-core@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.3.4.tgz#7fbf591c1c19e1acd28ffd284526e98b4f581128" + integrity sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g== dependencies: - "@babel/parser" "^7.16.4" - "@vue/shared" "3.2.45" + "@babel/parser" "^7.21.3" + "@vue/shared" "3.3.4" estree-walker "^2.0.2" - source-map "^0.6.1" + source-map-js "^1.0.2" -"@vue/compiler-dom@3.2.45": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz#c43cc15e50da62ecc16a42f2622d25dc5fd97dce" - integrity sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw== +"@vue/compiler-dom@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz#f56e09b5f4d7dc350f981784de9713d823341151" + integrity sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w== dependencies: - "@vue/compiler-core" "3.2.45" - "@vue/shared" "3.2.45" + "@vue/compiler-core" "3.3.4" + "@vue/shared" "3.3.4" -"@vue/compiler-sfc@3.2.45": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz#7f7989cc04ec9e7c55acd406827a2c4e96872c70" - integrity sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q== +"@vue/compiler-sfc@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz#b19d942c71938893535b46226d602720593001df" + integrity sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ== dependencies: - "@babel/parser" "^7.16.4" - "@vue/compiler-core" "3.2.45" - "@vue/compiler-dom" "3.2.45" - "@vue/compiler-ssr" "3.2.45" - "@vue/reactivity-transform" "3.2.45" - "@vue/shared" "3.2.45" + "@babel/parser" "^7.20.15" + "@vue/compiler-core" "3.3.4" + "@vue/compiler-dom" "3.3.4" + "@vue/compiler-ssr" "3.3.4" + "@vue/reactivity-transform" "3.3.4" + "@vue/shared" "3.3.4" estree-walker "^2.0.2" - magic-string "^0.25.7" + magic-string "^0.30.0" postcss "^8.1.10" - source-map "^0.6.1" + source-map-js "^1.0.2" -"@vue/compiler-ssr@3.2.45": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz#bd20604b6e64ea15344d5b6278c4141191c983b2" - integrity sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ== +"@vue/compiler-ssr@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz#9d1379abffa4f2b0cd844174ceec4a9721138777" + integrity sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ== dependencies: - "@vue/compiler-dom" "3.2.45" - "@vue/shared" "3.2.45" + "@vue/compiler-dom" "3.3.4" + "@vue/shared" "3.3.4" -"@vue/reactivity-transform@3.2.45": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz#07ac83b8138550c83dfb50db43cde1e0e5e8124d" - integrity sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ== +"@vue/reactivity-transform@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz#52908476e34d6a65c6c21cd2722d41ed8ae51929" + integrity sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw== dependencies: - "@babel/parser" "^7.16.4" - "@vue/compiler-core" "3.2.45" - "@vue/shared" "3.2.45" + "@babel/parser" "^7.20.15" + "@vue/compiler-core" "3.3.4" + "@vue/shared" "3.3.4" estree-walker "^2.0.2" - magic-string "^0.25.7" + magic-string "^0.30.0" -"@vue/reactivity@3.2.45": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.45.tgz#412a45b574de601be5a4a5d9a8cbd4dee4662ff0" - integrity sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A== +"@vue/reactivity@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.3.4.tgz#a27a29c6cd17faba5a0e99fbb86ee951653e2253" + integrity sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ== dependencies: - "@vue/shared" "3.2.45" + "@vue/shared" "3.3.4" -"@vue/runtime-core@3.2.45": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.45.tgz#7ad7ef9b2519d41062a30c6fa001ec43ac549c7f" - integrity sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A== +"@vue/runtime-core@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.3.4.tgz#4bb33872bbb583721b340f3088888394195967d1" + integrity sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA== dependencies: - "@vue/reactivity" "3.2.45" - "@vue/shared" "3.2.45" + "@vue/reactivity" "3.3.4" + "@vue/shared" "3.3.4" -"@vue/runtime-dom@3.2.45": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz#1a2ef6ee2ad876206fbbe2a884554bba2d0faf59" - integrity sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA== +"@vue/runtime-dom@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.3.4.tgz#992f2579d0ed6ce961f47bbe9bfe4b6791251566" + integrity sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ== dependencies: - "@vue/runtime-core" "3.2.45" - "@vue/shared" "3.2.45" - csstype "^2.6.8" - -"@vue/server-renderer@3.2.45": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.2.45.tgz#ca9306a0c12b0530a1a250e44f4a0abac6b81f3f" - integrity sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g== + "@vue/runtime-core" "3.3.4" + "@vue/shared" "3.3.4" + csstype "^3.1.1" + +"@vue/server-renderer@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.3.4.tgz#ea46594b795d1536f29bc592dd0f6655f7ea4c4c" + integrity sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ== dependencies: - "@vue/compiler-ssr" "3.2.45" - "@vue/shared" "3.2.45" + "@vue/compiler-ssr" "3.3.4" + "@vue/shared" "3.3.4" -"@vue/shared@3.2.45": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.45.tgz#a3fffa7489eafff38d984e23d0236e230c818bc2" - integrity sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg== +"@vue/shared@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.3.4.tgz#06e83c5027f464eef861c329be81454bc8b70780" + integrity sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ== bootstrap-icons@^1.9.1: - version "1.10.2" - resolved "https://registry.yarnpkg.com/bootstrap-icons/-/bootstrap-icons-1.10.2.tgz#6a5729e0475e007ed82d752225645e4e6fec48d7" - integrity sha512-PTPYadRn1AMGr+QTSxe4ZCc+Wzv9DGZxbi3lNse/dajqV31n2/wl/7NX78ZpkvFgRNmH4ogdIQPQmxAfhEV6nA== + version "1.11.1" + resolved "https://registry.yarnpkg.com/bootstrap-icons/-/bootstrap-icons-1.11.1.tgz#79e32494871d8c98e9d14f4bcdc278cee9b1dafd" + integrity sha512-F0DDp7nKUX+x/QtpfRZ+XHFya60ng9nfdpdS59vDDfs4Uhuxp7zym/QavMsu/xx51txkoM9eVmpE7D08N35blw== bootstrap-print-css@^1.0.1: version "1.0.1" @@ -108,19 +113,19 @@ bootstrap-print-css@^1.0.1: integrity sha512-I73Cw87BaxCccTjo3qEbvn7KRb55msMxTuT7mpkAAY4Obq8iG9xCybdxnJqq+RrykLD79O3092AiJwaKiEex7w== codemirror@5: - version "5.65.12" - resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.12.tgz#294fdf097d10ac5b56a9e011a91eff252afc73ae" - integrity sha512-z2jlHBocElRnPYysN2HAuhXbO3DNB0bcSKmNz3hcWR2Js2Dkhc1bEOxG93Z3DeUrnm+qx56XOY5wQmbP5KY0sw== + version "5.65.15" + resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.15.tgz#66899278f44a7acde0eb641388cd563fe6dfbe19" + integrity sha512-YC4EHbbwQeubZzxLl5G4nlbLc1T21QTrKGaOal/Pkm9dVDMZXMH7+ieSPEOZCtO9I68i8/oteJKOxzHC2zR+0g== cropperjs@^1.5.12: - version "1.5.12" - resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.5.12.tgz#d9c0db2bfb8c0d769d51739e8f916bbc44e10f50" - integrity sha512-re7UdjE5UnwdrovyhNzZ6gathI4Rs3KGCBSc8HCIjUo5hO42CtzyblmWLj6QWVw7huHyDMfpKxhiO2II77nhDw== + version "1.6.1" + resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.6.1.tgz#fd132021d93b824b1b0f2c2c3b763419fb792d89" + integrity sha512-F4wsi+XkDHCOMrHMYjrTEE4QBOrsHHN5/2VsVAaRq8P7E5z7xQpT75S+f/9WikmBEailas3+yo+6zPIomW+NOA== -csstype@^2.6.8: - version "2.6.21" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.21.tgz#2efb85b7cc55c80017c66a5ad7cbd931fda3a90e" - integrity sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w== +csstype@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" + integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== estree-walker@^2.0.2: version "2.0.2" @@ -132,17 +137,17 @@ jquery-cropper@^1.0.1: resolved "https://registry.yarnpkg.com/jquery-cropper/-/jquery-cropper-1.0.1.tgz#6ba9faf1c2c86c0ac3c648d40554ba53673113cf" integrity sha512-KGlY8b0IJQi2Bxe3lqMKmd5Z2Ce4GrnDE5O8Iciza9xCzXISkL6EqX/jFHwnLL1H6Q4FGjoRguuv3lxezsbKJQ== -magic-string@^0.25.7: - version "0.25.9" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" - integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== +magic-string@^0.30.0: + version "0.30.4" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.4.tgz#c2c683265fc18dda49b56fc7318d33ca0332c98c" + integrity sha512-Q/TKtsC5BPm0kGqgBIF9oXAs/xEf2vRKiIB4wCRQTJOQIByZ1d+NnUOotvJOvNpi5RNIgVOMC3pOuaP1ZTDlVg== dependencies: - sourcemap-codec "^1.4.8" + "@jridgewell/sourcemap-codec" "^1.4.15" -nanoid@^3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" - integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== +nanoid@^3.3.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== notyf@^3.10.0: version "3.10.0" @@ -155,11 +160,11 @@ picocolors@^1.0.0: integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== postcss@^8.1.10: - version "8.4.19" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.19.tgz#61178e2add236b17351897c8bcc0b4c8ecab56fc" - integrity sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA== + version "8.4.31" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== dependencies: - nanoid "^3.3.4" + nanoid "^3.3.6" picocolors "^1.0.0" source-map-js "^1.0.2" @@ -178,28 +183,18 @@ source-map-js@^1.0.2: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== -source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -sourcemap-codec@^1.4.8: - version "1.4.8" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" - integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== - vue-draggable-next@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/vue-draggable-next/-/vue-draggable-next-2.1.1.tgz#49886da82f116d11b3e4df7674320fdacf5d7e04" - integrity sha512-f5lmA7t6LMaL4viR7dU30zzvqJzaKQs0ymL0Jy9UDT9uiZ2tXF3MzPzEvpTH2UODXZJkT+SnjeV1fXHMsgXLYA== + version "2.2.1" + resolved "https://registry.yarnpkg.com/vue-draggable-next/-/vue-draggable-next-2.2.1.tgz#adbe98c74610cca8f4eb63f92042681f96920451" + integrity sha512-EAMS1IRHF0kZO0o5PMOinsQsXIqsrKT1hKmbICxG3UEtn7zLFkLxlAtajcCcUTisNvQ6TtCB5COjD9a1raNADw== vue@^3.2.31: - version "3.2.45" - resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.45.tgz#94a116784447eb7dbd892167784619fef379b3c8" - integrity sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA== + version "3.3.4" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.3.4.tgz#8ed945d3873667df1d0fcf3b2463ada028f88bd6" + integrity sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw== dependencies: - "@vue/compiler-dom" "3.2.45" - "@vue/compiler-sfc" "3.2.45" - "@vue/runtime-dom" "3.2.45" - "@vue/server-renderer" "3.2.45" - "@vue/shared" "3.2.45" + "@vue/compiler-dom" "3.3.4" + "@vue/compiler-sfc" "3.3.4" + "@vue/runtime-dom" "3.3.4" + "@vue/server-renderer" "3.3.4" + "@vue/shared" "3.3.4"