diff --git a/Gemfile b/Gemfile index 462207015b60367404a31d87e6258ec1a92ea0e2..edec4b7f812caf2af0cb6b27f81ebd7c14e8f631 100644 --- a/Gemfile +++ b/Gemfile @@ -35,6 +35,7 @@ gem 'bootstrap5-kaminari-views' gem 'octokit' gem 'front_matter_parser' gem 'two_factor_authentication', git: 'https://github.com/noesya/two_factor_authentication.git' +# gem 'two_factor_authentication', path: '../two_factor_authentication' # Front gem 'jquery-rails' diff --git a/Gemfile.lock b/Gemfile.lock index d85d58665eccb63be9445b8142567f993b181461..75035b78d269be03c6c4fe9f976243d541bde854 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -330,7 +330,11 @@ GEM simple_form_bs5_file_input (0.0.3) rails simple_form +<<<<<<< HEAD simple_form_password_with_hints (0.0.4) +======= + simple_form_password_with_hints (0.0.3) +>>>>>>> 353f910894520e230e8ba00dd407158a1901b980 rails simple_form sinatra (2.1.0) diff --git a/README.md b/README.md index 4ea1a7844f646b3326f5ac0d1b46cd118b26d1d6..158ba0d197fcf6abdbee16fe647c4d04e0b42c5f 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,8 @@ Open Source University, la plateforme numérique en source ouverte des Universit [](https://codeclimate.com/github/noesya/osuny/maintainability) -Démarrer l'app en dev : +## Setup -``` -bundle install -rails app:start -``` +- Lancer `bin/setup` +- Paramétrer les variables d'environnement dans `config/application.yml` +- Démarrer le serveur avec `rails app:start` \ No newline at end of file diff --git a/app/assets/javascripts/admin/notyf.js b/app/assets/javascripts/admin/notyf.js index e5fb41244591bc9c3d6d8a2a0335c75adabce716..68499577b5c1695a8ec1a79dc9659ebb2c3f0909 100644 --- a/app/assets/javascripts/admin/notyf.js +++ b/app/assets/javascripts/admin/notyf.js @@ -7,8 +7,8 @@ if (notyfAlerts.length > 0) { notyf.open({ type: 'error', position: { - x: 'right', - y: 'top' + x: 'center', + y: 'bottom' }, message: notyfAlerts[0].innerText, duration: 9000, diff --git a/app/assets/javascripts/admin/sortable.js b/app/assets/javascripts/admin/sortable.js new file mode 100644 index 0000000000000000000000000000000000000000..e34e6fbfd08c626604e59e291d180ac10a2ed92b --- /dev/null +++ b/app/assets/javascripts/admin/sortable.js @@ -0,0 +1,26 @@ +/*global $, Sortable */ +$(function () { + 'use strict'; + // Re-order elements of a table. Needs a "table-sortable" class on the table, a "data-reorder-url" param on the tbody and a "data-id" param on each tr + var nestedSortables = [].slice.call(document.querySelectorAll('.table-sortable tbody')), + i; + for (i = 0; i < nestedSortables.length; i += 1) { + new Sortable(nestedSortables[i], { + handle: '.handle', + group: 'nested', + animation: 150, + fallbackOnBody: true, + swapThreshold: 0.65, + onEnd: function (evt) { + var to = evt.to, + ids = [], + url = $(to).attr('data-reorder-url'); + // get list of ids + $('> tr', to).each(function () { + ids.push($(this).attr('data-id')); + }); + $.post(url, { ids: ids }); + } + }); + } +}); diff --git a/app/assets/javascripts/admin/treeview.js b/app/assets/javascripts/admin/treeview.js index e2889ea78f778262a0f9ccf1ab52e871495151ef..f0be31424445e933c5970b0c2cdc015c942acd78 100644 --- a/app/assets/javascripts/admin/treeview.js +++ b/app/assets/javascripts/admin/treeview.js @@ -13,7 +13,7 @@ window.osuny.treeView = { var nestedSortables, i; - nestedSortables = [].slice.call(document.querySelectorAll('.js-treeview-sortable')); + nestedSortables = [].slice.call(document.querySelectorAll('.js-treeview-sortable-container')); for (i = 0; i < nestedSortables.length; i += 1) { new Sortable(nestedSortables[i], { group: 'nested', @@ -24,13 +24,32 @@ window.osuny.treeView = { var from = evt.from, to = evt.to, ids = [], - parentId; + parentId, + url; + + // get list of ids $('> .js-treeview-element', to).each(function () { ids.push($(this).attr('data-id')); }); + + // as the "to" can be the root object where the data-sort-url is set we use "closest" and not "parents" + url = $(to).closest('.js-treeview-sortable') + .attr('data-sort-url'); parentId = to.dataset.id; - console.log(parentId, ids, from === to); - // TODO + + // manage emptyness + $(to).closest('.js-treeview-element') + .removeClass('treeview__element--empty'); + if ($('> .js-treeview-element', from).length === 0) { + $(from).closest('.js-treeview-element') + .addClass('treeview__element--empty'); + } + + // call to application + $.post(url, { + parentId: parentId, + ids: ids + }); } }); } @@ -39,11 +58,11 @@ window.osuny.treeView = { branchClicked: function (e) { 'use strict'; var $target = $(e.currentTarget), - $branch = $target.closest('.js-treeview-branch'); + $branch = $target.closest('.js-treeview-element'); - $branch.toggleClass('treeview__branch--opened'); + $branch.toggleClass('treeview__element--opened'); - if ($branch.hasClass('treeview__branch--loaded')) { + if ($branch.hasClass('treeview__element--loaded')) { e.preventDefault(); e.stopPropagation(); } diff --git a/app/assets/stylesheets/admin/treeview.sass b/app/assets/stylesheets/admin/treeview.sass index 050204eac291492cb0f761ffd9f287244de85ab3..fa8dfffbf0c3a3fb998a41db9901938e5ff182f5 100644 --- a/app/assets/stylesheets/admin/treeview.sass +++ b/app/assets/stylesheets/admin/treeview.sass @@ -1,20 +1,27 @@ .treeview - &__branch, &__leaf - & > .treeview__label - & > .move_btn - opacity: 0 - transition: opacity 0.1s - &:hover - & > .treeview__label - & > .move_btn - opacity: 1 + &__element + & > .treeview__children .treeview__empty + display: none - &__branch & > .treeview__label & > a .close_btn display: none + .close_btn--with_children + display: inline + .close_btn--without_children + display: none + & > a .open_btn display: inline + .open_btn--with_children + display: inline + .open_btn--without_children + display: none + + & > .move_btn + opacity: 0 + transition: opacity 0.1s + & > .treeview__children display: none @@ -27,12 +34,30 @@ & > .treeview__children display: block - &__leaf - & > .treeview__label - & > a .close_btn - display: none - & > a .open_btn + &--loaded + & > .treeview__children .treeview__loading display: none - & > .treeview__children - display: none + &--empty + & > .treeview__label + & > a .close_btn + .close_btn--with_children + display: none + .close_btn--without_children + display: inline + + & > a .open_btn + .open_btn--with_children + display: none + .open_btn--without_children + display: inline + + & > .treeview__children .treeview__empty + display: inline + + &--sortable + .treeview__element + &:hover + & > .treeview__label + & > .move_btn + opacity: 1 diff --git a/app/assets/stylesheets/commons/_forms.sass b/app/assets/stylesheets/commons/_forms.sass index 082da47e49878b719ad443896771cf24ccfc9422..4b1f04f6b170b8ff2aaeb18ba952d2c03abb4e0a 100644 --- a/app/assets/stylesheets/commons/_forms.sass +++ b/app/assets/stylesheets/commons/_forms.sass @@ -2,3 +2,6 @@ position: relative .sfpwh-password-toggle top: calc(50% - 6px) + +legend ~ * + clear: left diff --git a/app/controllers/admin/communication/application_controller.rb b/app/controllers/admin/communication/application_controller.rb index f9e5ff5722e8aa43bb5a8d27a0c3934db6c89ab5..f26a9a0f7552608dd5850f36362fcaa9457d4018 100644 --- a/app/controllers/admin/communication/application_controller.rb +++ b/app/controllers/admin/communication/application_controller.rb @@ -1,6 +1,14 @@ class Admin::Communication::ApplicationController < Admin::ApplicationController + + protected + def breadcrumb - super - add_breadcrumb Communication.model_name.human + if @website + short_breadcrumb + breadcrumb_for @website + else + super + add_breadcrumb Communication.model_name.human + end end end diff --git a/app/controllers/admin/communication/website/application_controller.rb b/app/controllers/admin/communication/website/application_controller.rb index 351e872c3d844f2c3ad9e6936ade85508d792d86..7c1f26e8b59b2a793c5b3255101a44d0b77d8d15 100644 --- a/app/controllers/admin/communication/website/application_controller.rb +++ b/app/controllers/admin/communication/website/application_controller.rb @@ -3,11 +3,6 @@ class Admin::Communication::Website::ApplicationController < Admin::Communicatio protected - def breadcrumb - short_breadcrumb - breadcrumb_for @website, website_id: nil - end - def default_url_options return {} unless params.has_key? :website_id { diff --git a/app/controllers/admin/communication/website/categories_controller.rb b/app/controllers/admin/communication/website/categories_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..e4ed189322b48bf825a59f7a31cccf10fc940eed --- /dev/null +++ b/app/controllers/admin/communication/website/categories_controller.rb @@ -0,0 +1,64 @@ +class Admin::Communication::Website::CategoriesController < Admin::Communication::Website::ApplicationController + load_and_authorize_resource class: Communication::Website::Category + + include Admin::Reorderable + + def index + @categories = @website.categories.ordered + breadcrumb + end + + def show + breadcrumb + end + + def new + @category.website = @website + breadcrumb + end + + def edit + breadcrumb + add_breadcrumb t('edit') + end + + def create + @category.university = current_university + @category.website = @website + if @category.save + redirect_to admin_communication_website_category_path(@category), notice: t('admin.successfully_created_html', model: @category.to_s) + else + breadcrumb + render :new, status: :unprocessable_entity + end + end + + def update + if @category.update(category_params) + redirect_to admin_communication_website_category_path(@category), notice: t('admin.successfully_updated_html', model: @category.to_s) + else + breadcrumb + add_breadcrumb t('edit') + render :edit, status: :unprocessable_entity + end + end + + def destroy + @category.destroy + redirect_to admin_communication_website_categories_url, notice: t('admin.successfully_destroyed_html', model: @category.to_s) + end + + protected + + def breadcrumb + super + add_breadcrumb Communication::Website::Category.model_name.human(count: 2), + admin_communication_website_categories_path + breadcrumb_for @category + end + + def category_params + params.require(:communication_website_category) + .permit(:university_id, :website_id, :name, :description) + end +end diff --git a/app/controllers/admin/communication/website/pages_controller.rb b/app/controllers/admin/communication/website/pages_controller.rb index 73d263dcad833ca5184fbfaccd3ba8fa8a74c3f1..3238ed54087aed073c24b3539b264f388fc90b24 100644 --- a/app/controllers/admin/communication/website/pages_controller.rb +++ b/app/controllers/admin/communication/website/pages_controller.rb @@ -1,11 +1,25 @@ class Admin::Communication::Website::PagesController < Admin::Communication::Website::ApplicationController load_and_authorize_resource class: Communication::Website::Page + before_action :get_root_pages, only: [:index, :new, :create, :edit, :update] + def index - @pages = @website.pages.root.ordered + breadcrumb end + def reorder + parent_id = params['parentId'].blank? ? nil : params['parentId'] + ids = params['ids'] + ids.each.with_index do |id, index| + page = @website.pages.find(id) + page.update( + parent_id: parent_id, + position: index + 1 + ) + end + end + def children return unless request.xhr? @page = @website.pages.find(params[:id]) @@ -54,6 +68,10 @@ class Admin::Communication::Website::PagesController < Admin::Communication::Web protected + def get_root_pages + @root_pages = @website.pages.root.ordered + end + def breadcrumb super add_breadcrumb Communication::Website::Page.model_name.human(count: 2), @@ -65,6 +83,7 @@ class Admin::Communication::Website::PagesController < Admin::Communication::Web params.require(:communication_website_page) .permit(:university_id, :communication_website_id, :title, :description, :text, :about_type, :about_id, :slug, :published, + :featured_image, :featured_image_delete, :featured_image_infos, :parent_id) end end diff --git a/app/controllers/admin/communication/website/posts_controller.rb b/app/controllers/admin/communication/website/posts_controller.rb index ed5450d9ec3fe49abbc8296a3c86083a16973ed5..1358b60c5cb0026e5fd56c979467d73cabf80fb4 100644 --- a/app/controllers/admin/communication/website/posts_controller.rb +++ b/app/controllers/admin/communication/website/posts_controller.rb @@ -57,6 +57,6 @@ class Admin::Communication::Website::PostsController < Admin::Communication::Web def post_params params.require(:communication_website_post) - .permit(:university_id, :website_id, :title, :description, :text, :published, :published_at) + .permit(:university_id, :website_id, :title, :description, :text, :published, :published_at, :featured_image, :featured_image_delete, :featured_image_infos, :slug, category_ids: []) end end diff --git a/app/controllers/admin/communication/websites_controller.rb b/app/controllers/admin/communication/websites_controller.rb index fbe9b765d544c2fb14f878feb8132543d711135c..66cff8d0661bb0171f51bf64488eea16c95d8b35 100644 --- a/app/controllers/admin/communication/websites_controller.rb +++ b/app/controllers/admin/communication/websites_controller.rb @@ -22,7 +22,7 @@ class Admin::Communication::WebsitesController < Admin::Communication::Applicati @imported_website = @website.imported_website @imported_pages = @imported_website.pages.page params[:pages_page] @imported_posts = @imported_website.posts.page params[:posts_page] - @imported_media = @imported_website.media.with_attached_file.page params[:media_page] + @imported_media = @imported_website.media.includes(file_attachment: :blob ).page params[:media_page] @imported_media_total_size = @imported_website.media.joins(file_attachment: :blob).sum(:byte_size) breadcrumb add_breadcrumb Communication::Website::Imported::Website.model_name.human @@ -60,12 +60,6 @@ class Admin::Communication::WebsitesController < Admin::Communication::Applicati protected - def breadcrumb - super - add_breadcrumb Communication::Website.model_name.human(count: 2), admin_communication_websites_path - breadcrumb_for @website - end - def website_params params.require(:communication_website).permit(:name, :domain, :repository, :access_token, :about_type, :about_id) end diff --git a/app/controllers/admin/education/schools_controller.rb b/app/controllers/admin/education/schools_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..821eb116ef1f81cd475fbc4d9486036aeb704754 --- /dev/null +++ b/app/controllers/admin/education/schools_controller.rb @@ -0,0 +1,59 @@ +class Admin::Education::SchoolsController < Admin::Education::ApplicationController + load_and_authorize_resource class: Education::School + + def index + @schools = current_university.education_schools + breadcrumb + end + + def show + breadcrumb + end + + def new + breadcrumb + end + + def edit + breadcrumb + add_breadcrumb t('edit') + end + + def create + @school.university = current_university + if @school.save + redirect_to [:admin, @school], notice: t('admin.successfully_created_html', model: @school.to_s) + else + breadcrumb + render :new, status: :unprocessable_entity + end + end + + def update + if @school.update(school_params) + redirect_to [:admin, @school], notice: t('admin.successfully_updated_html', model: @school.to_s) + else + breadcrumb + add_breadcrumb t('edit') + render :edit, status: :unprocessable_entity + end + end + + def destroy + @school.destroy + redirect_to admin_university_schools_url, notice: t('admin.successfully_destroyed_html', model: @school.to_s) + end + + private + + def breadcrumb + super + add_breadcrumb Education::School.model_name.human(count: 2), admin_education_schools_path + breadcrumb_for @school + end + + def school_params + params.require(:education_school) + .permit(:university_id, :name, :address, :zipcode, :city, :country, :latitude, :longitude) + end +end diff --git a/app/controllers/admin/research/application_controller.rb b/app/controllers/admin/research/application_controller.rb index 9ef7b886138ccb1a80d7503f6913068dc0dde0a9..438eafb32ce50d10cbe3e8fdcad708068b161555 100644 --- a/app/controllers/admin/research/application_controller.rb +++ b/app/controllers/admin/research/application_controller.rb @@ -3,7 +3,12 @@ class Admin::Research::ApplicationController < Admin::ApplicationController protected def breadcrumb - super - add_breadcrumb Research.model_name.human + if @journal + short_breadcrumb + breadcrumb_for @journal + else + super + add_breadcrumb Research.model_name.human + end end end diff --git a/app/controllers/admin/research/journal/application_controller.rb b/app/controllers/admin/research/journal/application_controller.rb index a4365619e623fa21d840e35e3e709942f152c64c..2702de20d5ab1cfc010d72c70887ffa6de070a0f 100644 --- a/app/controllers/admin/research/journal/application_controller.rb +++ b/app/controllers/admin/research/journal/application_controller.rb @@ -3,11 +3,6 @@ class Admin::Research::Journal::ApplicationController < Admin::Research::Applica protected - def breadcrumb - short_breadcrumb - breadcrumb_for @journal, journal_id: nil - end - def default_url_options return {} unless params.has_key? :journal_id { diff --git a/app/controllers/admin/research/journals_controller.rb b/app/controllers/admin/research/journals_controller.rb index 8c9a16327a6aaaa441e886845789009fb78930b4..0ea7bd97ee5e74f6afc7749cfcfb5cf381323d82 100644 --- a/app/controllers/admin/research/journals_controller.rb +++ b/app/controllers/admin/research/journals_controller.rb @@ -45,12 +45,6 @@ class Admin::Research::JournalsController < Admin::Research::ApplicationControll protected - def breadcrumb - super - add_breadcrumb Research::Journal.model_name.human(count: 2), admin_research_journals_path(journal_id: nil) - breadcrumb_for @journal - end - def journal_params params.require(:research_journal).permit(:title, :description, :issn, :access_token, :repository) end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 4cdcd84776ff097150d2c0a3001f93f199d55888..387e155c57dbed9a2ffd76d979197c6227f2129b 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -2,7 +2,7 @@ class Admin::UsersController < Admin::ApplicationController load_and_authorize_resource def index - @users = current_university.users.ordered + @users = current_university.users.ordered.page(params[:page]) breadcrumb end diff --git a/app/controllers/concerns/admin/reorderable.rb b/app/controllers/concerns/admin/reorderable.rb new file mode 100644 index 0000000000000000000000000000000000000000..2ce07bf582985548f7f69d1f07f0363034e669e6 --- /dev/null +++ b/app/controllers/concerns/admin/reorderable.rb @@ -0,0 +1,18 @@ +module Admin::Reorderable + extend ActiveSupport::Concern + + included do + def reorder + ids = params[:ids] + ids.each.with_index do |id, index| + object = model.find_by(id: id) + object.update_column(:position, index + 1) unless object.nil? + end + end + + def model + self.class.to_s.remove('Admin::').remove('Controller').singularize.safe_constantize + end + end + +end diff --git a/app/controllers/users/registrations_controller.rb b/app/controllers/users/registrations_controller.rb index f77babf2f6e6b3c5ce4100ad32f40fc4bb713bbd..d0eb01033367647e06e9620c41b84761865b3d5e 100644 --- a/app/controllers/users/registrations_controller.rb +++ b/app/controllers/users/registrations_controller.rb @@ -26,6 +26,10 @@ class Users::RegistrationsController < Devise::RegistrationsController protected + def sign_up(resource_name, resource) + sign_in(resource, event: :authentication) + end + def update_resource(resource, params) resource.update(params) end diff --git a/app/helpers/admin/application_helper.rb b/app/helpers/admin/application_helper.rb index c27d0ae74c0a6c6e15028fc975080187ad2bcaf4..1924e94f45cda33c26b6f8c080351697c95b0a7b 100644 --- a/app/helpers/admin/application_helper.rb +++ b/app/helpers/admin/application_helper.rb @@ -61,12 +61,13 @@ module Admin::ApplicationHelper end def prepare_for_github(html) - text = sanitize html.to_s, - tags: %w(table a figure img figcaption i em b strong h2 h3 h4 h5 h6 blockquote), + text = html.to_s + text = sanitize text, + tags: %w(table a figure img figcaption i em b strong p h2 h3 h4 h5 h6 blockquote), attributes: %w(href alt title target rel src srcset width height) - text = CGI.escapeHTML text - text = text.strip - text + text.gsub! "\r", '' + text.gsub! "\n", ' ' + sanitize text end private diff --git a/app/models/ability.rb b/app/models/ability.rb index ec5b779113b2189822207f4f60e2fc32f018e7c1..488d9fb67168192e6ba9ce02ce0ab7bc6714b453 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -20,6 +20,7 @@ class Ability can :read, Communication::Website::Imported::Page, university_id: @user.university_id can :read, Communication::Website::Imported::Post, university_id: @user.university_id can :read, Education::Program, university_id: @user.university_id + can :read, Education::School, university_id: @user.university_id can :read, Research::Researcher can :read, Research::Journal, university_id: @user.university_id can :read, Research::Journal::Article, university_id: @user.university_id diff --git a/app/models/communication/website.rb b/app/models/communication/website.rb index dc939770197e5d782eb77a4b383dfde968f0944e..95edecc5134a3d398f39a27749fcb539805100d8 100644 --- a/app/models/communication/website.rb +++ b/app/models/communication/website.rb @@ -27,16 +27,21 @@ class Communication::Website < ApplicationRecord belongs_to :about, polymorphic: true, optional: true has_many :pages, foreign_key: :communication_website_id has_many :posts, foreign_key: :communication_website_id + has_many :categories, class_name: 'Communication::Website::Category', foreign_key: :communication_website_id has_one :imported_website, class_name: 'Communication::Website::Imported::Website', dependent: :destroy def self.about_types - [nil, Research::Journal.name] + [nil, Education::School.name, Research::Journal.name] end def domain_url - "https://#{ domain }" + "https://#{domain}" + end + + def uploads_url + "#{domain_url}/wp-content/uploads" end def import! diff --git a/app/models/communication/website/category.rb b/app/models/communication/website/category.rb new file mode 100644 index 0000000000000000000000000000000000000000..8f8fec3a190be72815628ff8da92fa582ab7be89 --- /dev/null +++ b/app/models/communication/website/category.rb @@ -0,0 +1,58 @@ +# == Schema Information +# +# Table name: communication_website_categories +# +# id :uuid not null, primary key +# description :text +# name :string +# position :integer +# created_at :datetime not null +# updated_at :datetime not null +# communication_website_id :uuid not null +# university_id :uuid not null +# +# Indexes +# +# idx_communication_website_post_cats_on_communication_website_id (communication_website_id) +# index_communication_website_categories_on_university_id (university_id) +# +# Foreign Keys +# +# fk_rails_... (communication_website_id => communication_websites.id) +# fk_rails_... (university_id => universities.id) +# +class Communication::Website::Category < ApplicationRecord + + belongs_to :university + belongs_to :website, + foreign_key: :communication_website_id + has_and_belongs_to_many :posts, + class_name: 'Communication::Website::Post', + join_table: 'communication_website_categories_posts', + foreign_key: 'communication_website_category_id', + association_foreign_key: 'communication_website_post_id' + + validates :name, presence: true + + scope :ordered, -> { order(:position) } + + before_create :set_position + + + def to_s + "#{name}" + end + + protected + + def set_position + last_element = website.categories.ordered.last + + unless last_element.nil? + self.position = last_element.position + 1 + else + self.position = 1 + end + end + +end diff --git a/app/models/communication/website/imported/medium.rb b/app/models/communication/website/imported/medium.rb index ad230818055d9bfaca40ed60f3d5d334e612e17a..80801c768b903857709b2dac731c050a9fb44ee4 100644 --- a/app/models/communication/website/imported/medium.rb +++ b/app/models/communication/website/imported/medium.rb @@ -2,17 +2,17 @@ # # Table name: communication_website_imported_media # -# id :uuid not null, primary key -# data :jsonb -# file_url :text -# filename :string -# identifier :string -# remote_created_at :datetime -# remote_updated_at :datetime -# created_at :datetime not null -# updated_at :datetime not null -# university_id :uuid not null -# website_id :uuid not null +# id :uuid not null, primary key +# data :jsonb +# file_url :text +# filename :string +# identifier :string +# mime_type :string +# variant_urls :text default([]), is an Array +# created_at :datetime +# updated_at :datetime +# university_id :uuid not null +# website_id :uuid not null # # Indexes # @@ -28,43 +28,32 @@ class Communication::Website::Imported::Medium < ApplicationRecord belongs_to :university belongs_to :website, class_name: 'Communication::Website::Imported::Website' - has_many :pages, class_name: 'Communication::Website::Imported::Page', foreign_key: :featured_medium_id - has_many :posts, class_name: 'Communication::Website::Imported::Post', foreign_key: :featured_medium_id + has_many :pages, + class_name: 'Communication::Website::Imported::Page', + foreign_key: :featured_medium_id + has_many :posts, + class_name: 'Communication::Website::Imported::Post', + foreign_key: :featured_medium_id - has_one_attached :file + has_one_attached_deletable :file - after_commit :download_file_from_file_url, on: [:create, :update], if: :saved_change_to_file_url + scope :for_variant_url, -> (variant_url) { where('? = ANY(variant_urls)', variant_url) } def data=(value) super value - escaped_source_url = Addressable::URI.parse(value['source_url']).display_uri.to_s - self.file_url = escaped_source_url - self.filename = File.basename(URI(escaped_source_url).path) - # TODO unify with page and post? - self.remote_created_at = DateTime.parse(value['date_gmt']) - self.remote_updated_at = DateTime.parse(value['modified_gmt']) + sanitized_file_url = Addressable::URI.parse(value['source_url']).display_uri.to_s # ASCII-only for URI + self.file_url = sanitized_file_url + self.filename = File.basename(URI(file_url).path) + self.mime_type = value['mime_type'] + self.created_at = value['date_gmt'] + self.updated_at = value['modified_gmt'] + self.variant_urls = (value['media_details']['sizes'] || {}).values.map { |variant| + Addressable::URI.parse(variant['source_url']).display_uri.to_s + } end - protected - - def download_file_from_file_url - uri = URI(file_url) - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = true - # IUT Bordeaux Montaigne pb with certificate - http.verify_mode = OpenSSL::SSL::VERIFY_NONE - request = Net::HTTP::Get.new(uri.request_uri) - response = http.request(request) - tempfile = Tempfile.open("Osuny-ImportedMedium-#{SecureRandom.hex}", Dir.tmpdir) - begin - tempfile.binmode - tempfile.write(response.body) - tempfile.flush - tempfile.rewind - file.attach(io: tempfile, filename: filename, content_type: data['mime_type']) - ensure - tempfile.close! - end + def load_remote_file! + download_service = DownloadService.download(file_url) + file.attach(download_service.attachable_data) end - handle_asynchronously :download_file_from_file_url, queue: 'default' end diff --git a/app/models/communication/website/imported/page.rb b/app/models/communication/website/imported/page.rb index a1d19fa65456d4fc25896b226f3e86746c584f92..827fa184fca2c20313002e40066dac5e7f06ee89 100644 --- a/app/models/communication/website/imported/page.rb +++ b/app/models/communication/website/imported/page.rb @@ -23,6 +23,7 @@ # Indexes # # idx_communication_website_imported_pages_on_featured_medium_id (featured_medium_id) +# index_communication_website_imported_pages_on_identifier (identifier) # index_communication_website_imported_pages_on_page_id (page_id) # index_communication_website_imported_pages_on_university_id (university_id) # index_communication_website_imported_pages_on_website_id (website_id) @@ -35,6 +36,9 @@ # fk_rails_... (website_id => communication_website_imported_websites.id) # class Communication::Website::Imported::Page < ApplicationRecord + include Communication::Website::Imported::WithFeaturedImage + include Communication::Website::Imported::WithRichText + belongs_to :university belongs_to :website, class_name: 'Communication::Website::Imported::Website' @@ -57,7 +61,7 @@ class Communication::Website::Imported::Page < ApplicationRecord self.excerpt = value['excerpt']['rendered'] self.content = value['content']['rendered'] self.parent = value['parent'] - self.featured_medium = value['featured_media'] == 0 ? nil : website.media.find_by(identifier: value['featured_media']) + self.featured_medium = website.media.find_by(identifier: value['featured_media']) unless value['featured_media'] == 0 self.created_at = value['date_gmt'] self.updated_at = value['modified_gmt'] end @@ -75,17 +79,25 @@ class Communication::Website::Imported::Page < ApplicationRecord slug: path self.page.title = "Untitled" self.page.save + else + # Continue only if there are remote changes + # Don't touch if there are local changes (page.updated_at > updated_at) + # Don't touch if there are no remote changes (page.updated_at == updated_at) + # return unless updated_at > page.updated_at end - # Don't touch if there are local changes (this would destroy some nice work) - # return if page.updated_at > updated_at - # Don't touch if there are no remote changes (this would do useless server workload) - # return if page.updated_at == updated_at puts "Update page #{page.id}" + sanitized_title = Wordpress.clean_string self.title.to_s + page.title = sanitized_title unless sanitized_title.blank? # If there is no title, leave it with "Untitled" page.slug = slug - page.title = Wordpress.clean title.to_s - page.description = ActionView::Base.full_sanitizer.sanitize excerpt.to_s - page.text = Wordpress.clean content.to_s + page.description = Wordpress.clean_string excerpt.to_s + page.text = Wordpress.clean_html content.to_s page.published = true page.save + if featured_medium.present? + download_featured_medium_file_as_featured_image(page) + else + download_first_image_in_text_as_featured_image(page) + end + page.update(text: rich_text_with_attachments(page.text.to_s)) end end diff --git a/app/models/communication/website/imported/post.rb b/app/models/communication/website/imported/post.rb index e3701668d5a3ecd23f907c8c5f4c27d9516cb41a..9ff448c557eae487a2d2e478666853089c32a004 100644 --- a/app/models/communication/website/imported/post.rb +++ b/app/models/communication/website/imported/post.rb @@ -35,6 +35,9 @@ # fk_rails_... (website_id => communication_website_imported_websites.id) # class Communication::Website::Imported::Post < ApplicationRecord + include Communication::Website::Imported::WithFeaturedImage + include Communication::Website::Imported::WithRichText + belongs_to :university belongs_to :website, class_name: 'Communication::Website::Imported::Website' @@ -60,7 +63,7 @@ class Communication::Website::Imported::Post < ApplicationRecord self.created_at = value['date_gmt'] self.updated_at = value['modified_gmt'] self.published_at = value['date_gmt'] - self.featured_medium = website.media.find_by(identifier: value['featured_medium']) + self.featured_medium = website.media.find_by(identifier: value['featured_media']) unless value['featured_media'] == 0 end def to_s @@ -75,21 +78,28 @@ class Communication::Website::Imported::Post < ApplicationRecord website: website.website # Real website, not imported website self.post.title = "Untitled" # No title yet self.post.save + else + # Continue only if there are remote changes + # Don't touch if there are local changes (post.updated_at > updated_at) + # Don't touch if there are no remote changes (post.updated_at == updated_at) + # return unless updated_at > post.updated_at end - # Don't touch if there are local changes (this would destroy some nice work) - # return if post.updated_at > updated_at - # Don't touch if there are no remote changes (this would do useless server workload) - # return if post.updated_at == updated_at - title = Wordpress.clean title.to_s puts "Update post #{post.id}" - post.title = title unless title.blank? # If there is no title, leave it with "Untitled" + sanitized_title = Wordpress.clean_string self.title.to_s + post.title = sanitized_title unless sanitized_title.blank? # If there is no title, leave it with "Untitled" post.slug = slug - post.description = ActionView::Base.full_sanitizer.sanitize excerpt.to_s - post.text = Wordpress.clean content.to_s + post.description = Wordpress.clean_string excerpt.to_s + post.text = Wordpress.clean_html content.to_s post.created_at = created_at post.updated_at = updated_at post.published_at = published_at if published_at post.published = true post.save + if featured_medium.present? + download_featured_medium_file_as_featured_image(post) + else + download_first_image_in_text_as_featured_image(post) + end + post.update(text: rich_text_with_attachments(post.text.to_s)) end end diff --git a/app/models/communication/website/imported/website.rb b/app/models/communication/website/imported/website.rb index 7f1a202b1caf713195aa8eb3c58ccc1087b5f7bc..4ddbcc00111d2b7f17084ad915344309c4b9625b 100644 --- a/app/models/communication/website/imported/website.rb +++ b/app/models/communication/website/imported/website.rb @@ -45,15 +45,16 @@ class Communication::Website::Imported::Website < ApplicationRecord def sync_media wordpress.media.each do |data| - medium = media.where(university: university, identifier: data['id']).first_or_create + medium = media.where(university: university, identifier: data['id']).first_or_initialize medium.data = data medium.save end end def sync_pages + Communication::Website::Page.skip_callback(:save, :after, :publish_to_github) wordpress.pages.each do |data| - page = pages.where(university: university, identifier: data['id']).first_or_create + page = pages.where(university: university, identifier: data['id']).first_or_initialize page.data = data page.save end @@ -66,13 +67,34 @@ class Communication::Website::Imported::Website < ApplicationRecord generated_page.parent = parent.page generated_page.save end + # Batch update all changes (1 query only, good for github API limits) + github = Github.with_site website + if github.valid? + website.pages.find_each do |page| + github.add_to_batch path: page.github_path_generated, + previous_path: page.github_path, + data: page.to_jekyll + end + github.commit_batch '[Page] Batch update from import' + end + Communication::Website::Page.set_callback(:save, :after, :publish_to_github) end def sync_posts + Communication::Website::Post.skip_callback(:save, :after, :publish_to_github) + github = Github.with_site website wordpress.posts.each do |data| - post = posts.where(university: university, identifier: data['id']).first_or_create + post = posts.where(university: university, identifier: data['id']).first_or_initialize post.data = data post.save + generated_post = post.post + if github.valid? + github.add_to_batch path: generated_post.github_path_generated, + previous_path: generated_post.github_path, + data: generated_post.to_jekyll + end end + github.commit_batch '[Post] Batch update from import' if github.valid? + Communication::Website::Post.set_callback(:save, :after, :publish_to_github) end end diff --git a/app/models/communication/website/imported/with_featured_image.rb b/app/models/communication/website/imported/with_featured_image.rb new file mode 100644 index 0000000000000000000000000000000000000000..460d0d8b30f3facc8d333a40b244aa8fb903d3e9 --- /dev/null +++ b/app/models/communication/website/imported/with_featured_image.rb @@ -0,0 +1,28 @@ +module Communication::Website::Imported::WithFeaturedImage + extend ActiveSupport::Concern + + protected + + def download_featured_medium_file_as_featured_image(object) + featured_medium.load_remote_file! unless featured_medium.file.attached? + object.featured_image.attach( + io: URI.open(featured_medium.file.blob.url), + filename: featured_medium.file.blob.filename, + content_type: featured_medium.file.blob.content_type + ) + end + + def download_first_image_in_text_as_featured_image(object) + fragment = Nokogiri::HTML.fragment(object.text.to_s) + image = fragment.css('img').first + return unless image.present? + begin + url = image.attr('src') + download_service = DownloadService.download(url) + object.featured_image.attach(download_service.attachable_data) + image.remove + object.update(text: fragment.to_html) + rescue + end + end +end diff --git a/app/models/communication/website/imported/with_rich_text.rb b/app/models/communication/website/imported/with_rich_text.rb new file mode 100644 index 0000000000000000000000000000000000000000..a1ac94cdaca424f38ac642a8ab04cc07fffff8bc --- /dev/null +++ b/app/models/communication/website/imported/with_rich_text.rb @@ -0,0 +1,40 @@ +module Communication::Website::Imported::WithRichText + extend ActiveSupport::Concern + + protected + + def rich_text_with_attachments(text) + fragment = Nokogiri::HTML.fragment(text) + images = fragment.css("img[src*=\"#{website.website.uploads_url}\"]") + images.each do |image| + begin + url = image.attr('src') + blob = load_blob_from_url(url) + image.replace ActionText::Attachment.from_attachable(blob).node.to_s + rescue + end + end + fragment.to_html + end + + def load_blob_from_url(url) + medium = website.media.for_variant_url(url).first + if medium.present? + medium.load_remote_file! unless medium.file.attached? + # Currently a copy, should we link the medium blob instead? + blob = medium.file.blob.open do |tempfile| + ActiveStorage::Blob.create_and_upload!( + io: tempfile, + filename: medium.file.blob.filename, + content_type: medium.file.blob.content_type + ) + end + else + download_service = DownloadService.download(url) + blob = ActiveStorage::Blob.create_and_upload!(download_service.attachable_data) + end + blob.update_column(:university_id, self.university_id) + blob.analyze_later + blob + end +end diff --git a/app/models/communication/website/page.rb b/app/models/communication/website/page.rb index ad4e52d14a72e60b17fc268a1a6fa6adb3af4a9f..7f2e3da5448cf75bab7511b9499578448b6114ba 100644 --- a/app/models/communication/website/page.rb +++ b/app/models/communication/website/page.rb @@ -5,11 +5,12 @@ # id :uuid not null, primary key # about_type :string # description :text +# github_path :text +# old_text :text # path :text # position :integer default(0), not null # published :boolean default(FALSE) # slug :string -# text :text # title :string # created_at :datetime not null # updated_at :datetime not null @@ -33,8 +34,12 @@ # class Communication::Website::Page < ApplicationRecord + include WithGithub include WithSlug - include Communication::Website::WithGithub + include WithTree + + has_rich_text :text + has_one_attached_deletable :featured_image belongs_to :university belongs_to :website, @@ -45,21 +50,34 @@ class Communication::Website::Page < ApplicationRecord has_many :children, class_name: 'Communication::Website::Page', foreign_key: :parent_id - has_one :imported_page, - class_name: 'Communication::Website::Imported::Page', - foreign_key: :page_id, - dependent: :destroy validates :title, presence: true before_save :make_path + after_save :update_children_paths if :saved_change_to_path? scope :ordered, -> { order(:position) } scope :recent, -> { order(updated_at: :desc).limit(5) } - scope :root, -> { where(parent_id: nil) } - def has_children? - children.any? + def github_path_generated + "_pages/#{path}/index.html".gsub('//', '/') + end + + def to_jekyll + ApplicationController.render( + template: 'admin/communication/website/pages/jekyll', + layout: false, + assigns: { page: self } + ) + end + + def list_of_other_pages + pages = [] + website.pages.where.not(id: id).root.ordered.each do |page| + pages.concat(page.self_and_children(0)) + end + pages.reject! { |p| p[:id] == id } + pages end def to_s @@ -72,18 +90,7 @@ class Communication::Website::Page < ApplicationRecord self.path = "#{parent&.path}/#{slug}".gsub('//', '/') end - def github_path - "_pages/#{github_file}" - end - - def publish_to_github - github.publish kind: :pages, - file: "#{ id }.html", - title: to_s, - data: ApplicationController.render( - template: 'admin/communication/website/pages/jekyll', - layout: false, - assigns: { page: self } - ) + def update_children_paths + children.each(&:save) end end diff --git a/app/models/communication/website/post.rb b/app/models/communication/website/post.rb index 23c8cb3f0bfdae6f04b1415205630c13b9d5cae4..42fd81f8ca215fd88dbca5788c68ea89b29f1569 100644 --- a/app/models/communication/website/post.rb +++ b/app/models/communication/website/post.rb @@ -4,7 +4,9 @@ # # id :uuid not null, primary key # description :text +# github_path :text # old_text :text +# path :text # published :boolean default(FALSE) # published_at :datetime # slug :text @@ -26,46 +28,38 @@ # class Communication::Website::Post < ApplicationRecord include WithSlug - include Communication::Website::WithGithub + include WithGithub has_rich_text :text + has_one_attached_deletable :featured_image belongs_to :university belongs_to :website, foreign_key: :communication_website_id - has_one :imported_post, - class_name: 'Communication::Website::Imported::Post', - foreign_key: :post_id, - dependent: :destroy + has_and_belongs_to_many :categories, + class_name: 'Communication::Website::Category', + join_table: 'communication_website_categories_posts', + foreign_key: 'communication_website_post_id', + association_foreign_key: 'communication_website_category_id' scope :ordered, -> { order(published_at: :desc, created_at: :desc) } scope :recent, -> { order(published_at: :desc).limit(5) } validates :title, presence: true - def to_s - "#{title}" + def github_path_generated + "_posts/#{published_at.year}/#{published_at.strftime "%Y-%m-%d"}-#{slug}.html" end - protected - - def github_file - "#{published_at.year}/#{published_at.month}/#{published_at.strftime "%Y-%m-%d"}-#{id}.html" + def to_jekyll + ApplicationController.render( + template: 'admin/communication/website/posts/jekyll', + layout: false, + assigns: { post: self } + ) end - def github_path - "_posts/#{github_file}" - end - - def publish_to_github - return if published_at.nil? - github.publish kind: :posts, - file: github_file, - title: to_s, - data: ApplicationController.render( - template: 'admin/communication/website/posts/jekyll', - layout: false, - assigns: { post: self } - ) + def to_s + "#{title}" end end diff --git a/app/models/communication/website/with_github.rb b/app/models/communication/website/with_github.rb deleted file mode 100644 index ed89d0e8cb6d392621670d46b04408a09c324993..0000000000000000000000000000000000000000 --- a/app/models/communication/website/with_github.rb +++ /dev/null @@ -1,39 +0,0 @@ -module Communication::Website::WithGithub - extend ActiveSupport::Concern - - included do - after_save :publish_to_github - end - - def content - @content ||= github.read_file_at github_path - end - - def frontmatter - @frontmatter ||= FrontMatterParser::Parser.new(:md).call(content) - end - - def content_without_frontmatter - frontmatter.content - end - - def github_file - "#{ id }.html" - end - - # Needs override - def github_path - '' - end - - protected - - def github - @github ||= Github.with_site(website) - end - - # Needs override - def publish_to_github - '' - end -end diff --git a/app/models/concerns/with_github.rb b/app/models/concerns/with_github.rb new file mode 100644 index 0000000000000000000000000000000000000000..906ad62e5bb8bcd2a906f45559b80f50e337a3af --- /dev/null +++ b/app/models/concerns/with_github.rb @@ -0,0 +1,40 @@ +module WithGithub + extend ActiveSupport::Concern + + included do + after_save :publish_to_github + end + + def github_content + @content ||= github.read_file_at github_path + end + + def github_frontmatter + @frontmatter ||= FrontMatterParser::Parser.new(:md).call(github_content) + end + + def github_path_generated + '' # Needs override + end + + protected + + def github + @github ||= Github.with_site(website) + end + + def github_commit_message + "[#{self.class.name.demodulize}] Save #{ to_s }" + end + + def publish_to_github + return unless github.valid? + if github.publish(path: github_path_generated, + previous_path: github_path, + commit: github_commit_message, + data: to_jekyll) + update_column :github_path, github_path_generated + end + end + handle_asynchronously :publish_to_github, queue: 'default' +end diff --git a/app/models/concerns/with_tree.rb b/app/models/concerns/with_tree.rb new file mode 100644 index 0000000000000000000000000000000000000000..e45bc999d33ebcf758f8a7dc34712b21939686f4 --- /dev/null +++ b/app/models/concerns/with_tree.rb @@ -0,0 +1,25 @@ +module WithTree + extend ActiveSupport::Concern + + included do + + scope :root, -> { where(parent_id: nil) } + + def has_children? + children.any? + end + + def self_and_children(level) + pages = [] + label = " " * level + self.to_s + pages << { label: label, id: self.id } + children.each do |child| + pages.concat(child.self_and_children(level + 1)) + end + pages + end + + end + + +end diff --git a/app/models/education/school.rb b/app/models/education/school.rb new file mode 100644 index 0000000000000000000000000000000000000000..422d7f10269ad1fe0e85a650feee8c3a381f9cd2 --- /dev/null +++ b/app/models/education/school.rb @@ -0,0 +1,32 @@ +# == Schema Information +# +# Table name: education_schools +# +# id :uuid not null, primary key +# address :string +# city :string +# country :string +# latitude :float +# longitude :float +# name :string +# zipcode :string +# created_at :datetime not null +# updated_at :datetime not null +# university_id :uuid not null +# +# Indexes +# +# index_education_schools_on_university_id (university_id) +# +# Foreign Keys +# +# fk_rails_... (university_id => universities.id) +# +class Education::School < ApplicationRecord + belongs_to :university + has_one :website, class_name: 'Communication::Website', foreign_key: :about + + def to_s + "#{name}" + end +end diff --git a/app/models/research/journal/article.rb b/app/models/research/journal/article.rb index 0410c664d3b6e9859bf11e853a325e9043904631..b389b460a43c48f1e2bc0828b6ac870f261ca7a1 100644 --- a/app/models/research/journal/article.rb +++ b/app/models/research/journal/article.rb @@ -4,6 +4,7 @@ # # id :uuid not null, primary key # abstract :text +# github_path :text # keywords :text # published_at :date # references :text @@ -31,13 +32,15 @@ # fk_rails_... (updated_by_id => users.id) # class Research::Journal::Article < ApplicationRecord + include WithGithub + belongs_to :university belongs_to :journal, foreign_key: :research_journal_id belongs_to :volume, foreign_key: :research_journal_volume_id, optional: true belongs_to :updated_by, class_name: 'User' has_and_belongs_to_many :researchers, class_name: 'Research::Researcher' - after_commit :publish_to_github + after_commit :update_researchers has_one_attached :pdf @@ -47,28 +50,31 @@ class Research::Journal::Article < ApplicationRecord "/assets/articles/#{id}/#{pdf.filename}" end + def website + journal.website + end + def to_s "#{ title }" end protected - def publish_to_github - github.publish kind: :articles, - file: "#{id}.md", - title: title, - data: ApplicationController.render( - template: 'admin/research/journal/articles/jekyll', - layout: false, - assigns: { article: self } - ) + def github_path_generated + "_articles/#{id}.html" + end + + def to_jekyll + ApplicationController.render( + template: 'admin/research/journal/articles/jekyll', + layout: false, + assigns: { article: self } + ) + end + + def update_researchers researchers.each do |researcher| researcher.publish_to_website(journal.website) end - github.send_file pdf, pdf_path if pdf.attached? - end - - def github - @github ||= Github.with_site(journal.website) end end diff --git a/app/models/research/journal/volume.rb b/app/models/research/journal/volume.rb index 86e614af0bd4b353689968fb0b3a9ffe9c159fe1..ce5f8aa08374f17b00bab6835efc58528d66a12b 100644 --- a/app/models/research/journal/volume.rb +++ b/app/models/research/journal/volume.rb @@ -4,6 +4,7 @@ # # id :uuid not null, primary key # description :text +# github_path :text # keywords :text # number :integer # published_at :date @@ -24,12 +25,12 @@ # fk_rails_... (university_id => universities.id) # class Research::Journal::Volume < ApplicationRecord + include WithGithub + belongs_to :university belongs_to :journal, foreign_key: :research_journal_id has_many :articles, foreign_key: :research_journal_volume_id - after_commit :publish_to_github - has_one_attached :cover scope :ordered, -> { order(number: :desc, published_at: :desc) } @@ -38,25 +39,25 @@ class Research::Journal::Volume < ApplicationRecord "/assets/img/volumes/#{id}#{cover.filename.extension_with_delimiter}" end + def website + journal.website + end + def to_s "##{ number } #{ title }" end protected - def publish_to_github - github.publish kind: :volumes, - file: "#{id}.md", - title: title, - data: ApplicationController.render( - template: 'admin/research/journal/volumes/jekyll', - layout: false, - assigns: { volume: self } - ) - github.send_file cover, cover_path if cover.attached? + def github_path_generated + "_volumes/#{id}.html" end - def github - @github ||= Github.with_site(journal.website) + def to_jekyll + ApplicationController.render( + template: 'admin/research/journal/volumes/jekyll', + layout: false, + assigns: { volume: self } + ) end end diff --git a/app/models/research/researcher.rb b/app/models/research/researcher.rb index 8504f16ae1c86961be821ca8cd2e5b3e05e3b6da..ff77867859bf3e087872113b89da2c4f14b4518d 100644 --- a/app/models/research/researcher.rb +++ b/app/models/research/researcher.rb @@ -2,13 +2,14 @@ # # Table name: research_researchers # -# id :uuid not null, primary key -# biography :text -# first_name :string -# last_name :string -# created_at :datetime not null -# updated_at :datetime not null -# user_id :uuid +# id :uuid not null, primary key +# biography :text +# first_name :string +# github_path :text +# last_name :string +# created_at :datetime not null +# updated_at :datetime not null +# user_id :uuid # # Indexes # @@ -31,14 +32,10 @@ class Research::Researcher < ApplicationRecord def publish_to_website(website) github = Github.new website.access_token, website.repository - github.publish kind: :authors, - file: "#{ id }.md", - title: to_s, - data: ApplicationController.render( - template: 'admin/research/researchers/jekyll', - layout: false, - assigns: { researcher: self } - ) + return unless github.valid? + github.publish path: "_authors/#{ id }.md", + data: to_jekyll, + commit: "[Researcher] Save #{to_s}" end def to_s @@ -47,6 +44,14 @@ class Research::Researcher < ApplicationRecord protected + def to_jekyll + ApplicationController.render( + template: 'admin/research/researchers/jekyll', + layout: false, + assigns: { researcher: self } + ) + end + def publish_to_github websites.each { |website| publish_to_website(website) } end diff --git a/app/models/university/with_education.rb b/app/models/university/with_education.rb index 35317c68f38b1f230b63a80de21ec1a6583c0775..5acddc90f4055bb204487797d97d6994c82a189e 100644 --- a/app/models/university/with_education.rb +++ b/app/models/university/with_education.rb @@ -3,5 +3,6 @@ module University::WithEducation included do has_many :education_programs, class_name: 'Education::Program', dependent: :destroy + has_many :education_schools, class_name: 'Education::School', dependent: :destroy end end diff --git a/app/models/user.rb b/app/models/user.rb index 19c3bd790a7470b740187ac150ce4bf607b22dfa..6ab66091be996263f2dad35fc5a0b96d198205c6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -53,6 +53,8 @@ # fk_rails_... (university_id => universities.id) # class User < ApplicationRecord + # In this order, "resize avatar" callback will be fired after the others. + include WithAvatar include WithAuthentication include WithRoles include WithSyncBetweenUniversities @@ -60,11 +62,9 @@ class User < ApplicationRecord belongs_to :university belongs_to :language has_one :researcher, class_name: 'Research::Researcher' - has_one_attached_deletable :picture scope :ordered, -> { order(:last_name, :first_name) } - def to_s "#{first_name} #{last_name}" end diff --git a/app/models/user/with_avatar.rb b/app/models/user/with_avatar.rb new file mode 100644 index 0000000000000000000000000000000000000000..b06f566c44bc93a834623fe280aa59b99223f900 --- /dev/null +++ b/app/models/user/with_avatar.rb @@ -0,0 +1,7 @@ +module User::WithAvatar + extend ActiveSupport::Concern + + included do + has_one_attached_deletable :picture + end +end diff --git a/app/services/download_service.rb b/app/services/download_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..e0469ccfce588827aca48a6ea842a22bc1953497 --- /dev/null +++ b/app/services/download_service.rb @@ -0,0 +1,40 @@ +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/github.rb b/app/services/github.rb index b860a19de4da7810a73738bc3c0c4b2551912ffc..e47b9b4ec0403cd6bff32d4daff5d766070e95cf 100644 --- a/app/services/github.rb +++ b/app/services/github.rb @@ -2,7 +2,7 @@ class Github attr_reader :access_token, :repository def self.with_site(site) - new site.access_token, site.repository + new site&.access_token, site&.repository end def initialize(access_token, repository) @@ -10,46 +10,78 @@ class Github @repository = repository end - def publish(kind:, file:, title:, data:) - local_directory = "tmp/jekyll/#{ kind }" - local_path = "#{ local_directory }/#{ file }" + def valid? + repository.present? && access_token.present? + end + + def publish(path: nil, + previous_path: nil, + commit: nil, + data:) + local_path = "#{ tmp_directory }/#{ path }" Pathname(local_path).dirname.mkpath File.write local_path, data return if repository.blank? - remote_file = "_#{ kind }/#{ file }" - begin - content = client.content repository, path: remote_file - sha = content[:sha] - rescue - sha = nil + if !previous_path.blank? && path != previous_path + move_file previous_path, path end - commit_message ||= "[#{kind}] Save #{ title }" client.create_contents repository, - remote_file, - commit_message, + path, + commit, file: local_path, - sha: sha + sha: file_sha(path) + true rescue - # byebug + false end def send_file(attachment, path) - begin - content = client.content repository, path: path - sha = content[:sha] - rescue - sha = nil - end - commit_message ||= "[file] Save #{ path }" return if repository.blank? + commit_message = "[file] Save #{ path }" path_without_slash = path[1..-1] client.create_contents repository, path_without_slash, commit_message, attachment.download, - sha: sha + sha: file_sha(path) + true rescue - # byebug + false + end + + def add_to_batch( path: nil, + previous_path: nil, + data:) + @batch ||= [] + file = find_in_tree previous_path + if file.nil? # New file + @batch << { + path: path, + mode: '100644', # https://docs.github.com/en/rest/reference/git#create-a-tree + type: 'blob', + content: data + } + else # Existing file + @batch << { + path: previous_path, + mode: file[:mode], + type: file[:type], + sha: nil + } + @batch << { + path: path, + mode: file[:mode], + type: file[:type], + content: data + } + end + end + + def commit_batch(commit_message) + new_tree = client.create_tree repository, @batch, base_tree: tree[:sha] + commit = client.create_commit repository, commit_message, new_tree[:sha], branch_sha + client.update_branch repository, default_branch, commit[:sha] + @tree = nil end def read_file_at(path) @@ -59,6 +91,8 @@ class Github '' end + protected + def pages list = client.contents repository, path: '_pages' list.map do |hash| @@ -83,4 +117,63 @@ class Github def client @client ||= Octokit::Client.new access_token: access_token end + + # https://medium.com/@obodley/renaming-a-file-using-the-git-api-fed1e6f04188 + def move_file(from, to) + file = find_in_tree from + return if file.nil? + content = [{ + path: from, + mode: file[:mode], + type: file[:type], + sha: nil + }, + { + path: to, + mode: file[:mode], + type: file[:type], + sha: file[:sha] + }] + new_tree = client.create_tree repository, content, base_tree: tree[:sha] + message = "Move #{from} to #{to}" + commit = client.create_commit repository, message, new_tree[:sha], branch_sha + client.update_branch repository, default_branch, commit[:sha] + @tree = nil + true + rescue + false + end + + def file_sha(path) + begin + content = client.content repository, path: path + sha = content[:sha] + rescue + sha = nil + end + sha + end + + def default_branch + @default_branch ||= client.repo(repository)[:default_branch] + end + + def branch_sha + @branch_sha ||= client.branch(repository, default_branch)[:commit][:sha] + end + + def tree + @tree ||= client.tree repository, branch_sha, recursive: true + end + + def find_in_tree(path) + tree[:tree].each do |file| + return file if path == file[:path] + end + nil + end + + def tmp_directory + "tmp/github/#{repository}" + end end diff --git a/app/services/wordpress.rb b/app/services/wordpress.rb index 2e70cde3065c40e12a47ecb998407c6fa1bfb137..6eda98ebd7d11869424d9c327015387aac068d64 100644 --- a/app/services/wordpress.rb +++ b/app/services/wordpress.rb @@ -1,13 +1,29 @@ class Wordpress attr_reader :domain - def self.clean(html) + + def self.clean_string(string) + string = string.gsub(' ', ' ') + string = string.gsub('&', '&') + string = ActionView::Base.full_sanitizer.sanitize string + string = remove_lsep string + string + end + + def self.clean_html(html) + # 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.delete('class'), - 'a' => Sanitize::Config::RELAXED[:attributes]['a'].dup.delete('rel') + '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]).delete('div'), + elements: Set.new(Sanitize::Config::RELAXED[:elements]).delete('div') + ['iframe'], whitespace_elements: { 'div' => { :before => "", :after => "" } } @@ -19,7 +35,16 @@ class Wordpress fragment.css("h#{i}").each { |element| element.name = "h#{i+1}" } end end - fragment.to_html(preserve_newline: true) + html = fragment.to_html(preserve_newline: true) + html = remove_lsep html + html + end + + def self.remove_lsep(string) + # LSEP is invisible! + string = string.delete("
", "
", "
") + string = string.gsub /\u2028/, '' + string end def initialize(domain) @@ -58,13 +83,7 @@ class Wordpress end def load_url(url) - uri = URI(url) - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = true - # IUT Bordeaux Montaigne pb with certificate - http.verify_mode = OpenSSL::SSL::VERIFY_NONE - request = Net::HTTP::Get.new(uri.request_uri) - response = http.request(request) - JSON.parse(response.body) + download_service = DownloadService.download(url) + JSON.parse(download_service.response.body) end end diff --git a/app/views/active_storage/blobs/_blob.html.erb b/app/views/active_storage/blobs/_blob.html.erb index 49ba357dd1d4afc63ac0bae78dbcd1a882df9e9e..3daa58bc67b70fe52af1b1f38a6711885bc044bd 100644 --- a/app/views/active_storage/blobs/_blob.html.erb +++ b/app/views/active_storage/blobs/_blob.html.erb @@ -1,14 +1,16 @@ <figure class="attachment attachment--<%= blob.representable? ? "preview" : "file" %> attachment--<%= blob.filename.extension %>"> <% if blob.representable? %> <%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %> + <% else %> + <p> + <span class="attachment__name"><%= blob.filename %></span> + <span class="attachment__size"><%= number_to_human_size blob.byte_size %></span> + </p> <% end %> - <figcaption class="attachment__caption"> - <% if caption = blob.try(:caption) %> + <% if caption = blob.try(:caption) %> + <figcaption class="attachment__caption"> <%= caption %> - <% else %> - <span class="attachment__name"><%= blob.filename %></span> - <span class="attachment__size"><%= number_to_human_size blob.byte_size %></span> - <% end %> - </figcaption> + </figcaption> + <% end %> </figure> diff --git a/app/views/admin/communication/website/categories/_form.html.erb b/app/views/admin/communication/website/categories/_form.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..1d988e3fa744856c5353c2aef0df3e1a7ce668c2 --- /dev/null +++ b/app/views/admin/communication/website/categories/_form.html.erb @@ -0,0 +1,18 @@ +<%= simple_form_for [:admin, category] do |f| %> + <div class="row"> + <div class="col-md-8"> + <div class="card flex-fill w-100"> + <div class="card-header"> + <h5 class="card-title mb-0"><%= t('communication.website.content') %></h5> + </div> + <div class="card-body"> + <%= f.input :name %> + <%= f.input :description %> + </div> + </div> + </div> + </div> + <% content_for :action_bar_right do %> + <%= submit f %> + <% end %> +<% end %> diff --git a/app/views/admin/communication/website/categories/_list.html.erb b/app/views/admin/communication/website/categories/_list.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..dad41187f932bc67d1d0a660a9a80ac7a5156b2d --- /dev/null +++ b/app/views/admin/communication/website/categories/_list.html.erb @@ -0,0 +1,27 @@ +<table class="<%= table_classes %> table-sortable"> + <thead> + <tr> + <% if can? :reorder, Communication::Website::Category %> + <th width="20"> </th> + <% end %> + <th><%= Communication::Website::Category.human_attribute_name('title') %></th> + <th></th> + </tr> + </thead> + <tbody data-reorder-url="<%= reorder_admin_communication_website_categories_path(@website) %>"> + <% categories.each do |category| %> + <tr data-id="<%= category.id %>"> + <% if can? :reorder, Communication::Website::Category %> + <td><i class="fa fa-bars handle"></i></td> + <% end %> + <td><%= link_to category, admin_communication_website_category_path(website_id: category.website.id, id: category.id) %></td> + <td class="text-end"> + <div class="btn-group" role="group"> + <%= edit_link category %> + <%= destroy_link category %> + </div> + </td> + </tr> + <% end %> + </tbody> +</table> diff --git a/app/views/admin/communication/website/categories/edit.html.erb b/app/views/admin/communication/website/categories/edit.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..123bc888b09752ba30b4db4eba62ec37bcbd07d2 --- /dev/null +++ b/app/views/admin/communication/website/categories/edit.html.erb @@ -0,0 +1,3 @@ +<% content_for :title, @category %> + +<%= render 'form', category: @category %> diff --git a/app/views/admin/communication/website/categories/index.html.erb b/app/views/admin/communication/website/categories/index.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..bb47a5f4750937fd78a5d7a2c2141a87ae266782 --- /dev/null +++ b/app/views/admin/communication/website/categories/index.html.erb @@ -0,0 +1,7 @@ +<% content_for :title, "#{Communication::Website::Category.model_name.human(count: 2)} (#{@categories.count})" %> + +<%= render 'list', categories: @categories %> + +<% content_for :action_bar_right do %> + <%= create_link Communication::Website::Category %> +<% end %> diff --git a/app/views/admin/communication/website/categories/new.html.erb b/app/views/admin/communication/website/categories/new.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..f92532bde4aa34d077cb23a65cfdc18643b689a7 --- /dev/null +++ b/app/views/admin/communication/website/categories/new.html.erb @@ -0,0 +1,3 @@ +<% content_for :title, Communication::Website::Category.model_name.human %> + +<%= render 'form', category: @category %> diff --git a/app/views/admin/communication/website/categories/show.html.erb b/app/views/admin/communication/website/categories/show.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..96aa0af3fe3d008b278a5d1891db34d087e95f12 --- /dev/null +++ b/app/views/admin/communication/website/categories/show.html.erb @@ -0,0 +1,21 @@ +<% content_for :title, @category %> + +<div class="row"> + <div class="col-md-8"> + <div class="card flex-fill w-100"> + <div class="card-header"> + <h5 class="card-title mb-0"><%= t('communication.website.content') %></h5> + </div> + <div class="card-body"> + <p> + <strong><%= Communication::Website::Category.human_attribute_name('description') %></strong> + </p> + <%= sanitize @category.description %> + </div> + </div> + </div> +</div> + +<% content_for :action_bar_right do %> + <%= edit_link @category %> +<% end %> diff --git a/app/views/admin/communication/website/pages/_form.html.erb b/app/views/admin/communication/website/pages/_form.html.erb index 1e658226c49b66da37c2d2f21b047b26fbc0325f..b4788412c3d9717f748b2b6bb827475d22d71d74 100644 --- a/app/views/admin/communication/website/pages/_form.html.erb +++ b/app/views/admin/communication/website/pages/_form.html.erb @@ -3,24 +3,40 @@ <div class="col-md-8"> <div class="card flex-fill w-100"> <div class="card-header"> - <h5 class="card-title">Content</h5> + <h5 class="card-title mb-0"><%= t('communication.website.content') %></h5> </div> <div class="card-body"> <%= f.input :title %> <%= f.input :description %> - <%= f.input :text, input_html: { rows: 20 } %> + <%= f.input :text, as: :rich_text_area %> </div> </div> </div> <div class="col-md-4"> <div class="card flex-fill w-100"> <div class="card-header"> - <h5 class="card-title">Metadata</h5> + <h5 class="card-title mb-0"><%= t('communication.website.metadata') %></h5> </div> <div class="card-body"> - <%= f.input :slug %> + <%= f.input :slug, as: :string %> <%= f.input :published %> - <%= f.association :parent, collection: page.website.pages.where.not(id: page) %> + <%= f.association :parent, collection: page.list_of_other_pages, label_method: ->(p) { sanitize p[:label] }, value_method: ->(p) { p[:id] } %> + <ul> + </ul> + </div> + </div> + <div class="card flex-fill w-100"> + <div class="card-header"> + <h5 class="card-title mb-0"><%= t('activerecord.attributes.communication/website/page.featured_image') %></h5> + </div> + <div class="card-body"> + <%= f.input :featured_image, + as: :single_deletable_file, + direct_upload: true, + label: false, + input_html: { accept: '.jpg,.jpeg,.png' }, + preview: true + %> </div> </div> </div> diff --git a/app/views/admin/communication/website/pages/_list.html.erb b/app/views/admin/communication/website/pages/_list.html.erb index 310b52c540e636663293fbb8f0f42e8406bda86f..066342f1b48d52bacdfd94a2a3e1b59578baa372 100644 --- a/app/views/admin/communication/website/pages/_list.html.erb +++ b/app/views/admin/communication/website/pages/_list.html.erb @@ -2,8 +2,6 @@ <thead> <tr> <th><%= Communication::Website::Page.human_attribute_name('title') %></th> - <th><%= Communication::Website::Page.human_attribute_name('path') %></th> - <th><%= Communication::Website::Page.human_attribute_name('parent') %></th> <th width="150"></th> </tr> </thead> @@ -11,8 +9,6 @@ <% pages.each do |page| %> <tr> <td><%= link_to page, admin_communication_website_page_path(website_id: page.website.id, id: page.id) %></td> - <td><%= page.path %></td> - <td><%= link_to page.parent, admin_communication_website_page_path(website_id: page.website.id, id: page.parent.id) if page.parent %></td> <td class="text-end"> <div class="btn-group" role="group"> <%= link_to t('edit'), diff --git a/app/views/admin/communication/website/pages/_treebranch.html.erb b/app/views/admin/communication/website/pages/_treebranch.html.erb index 599e099c65fe92e510febc907b45b64dd60340b9..cad2da67b7a6c2bc2f675c889e8deb6e7758bb38 100644 --- a/app/views/admin/communication/website/pages/_treebranch.html.erb +++ b/app/views/admin/communication/website/pages/_treebranch.html.erb @@ -1,20 +1,28 @@ <% pages.each do |page| %> - <li class="js-treeview-element <%= page.has_children? ? 'treeview__branch js-treeview-branch' : 'treeview__leaf' %>" data-id="<%= page.id %>" data-parent="<%= page.parent_id %>"> + <li class="treeview__element js-treeview-element <%= 'treeview__element--empty' unless page.has_children? %>" data-id="<%= page.id %>" data-parent="<%= page.parent_id %>"> <div class="d-flex align-items-center treeview__label border-bottom p-1"> - <% if page.has_children? %> - <%= link_to children_admin_communication_website_page_path(website_id: page.website.id, id: page.id), - class: 'js-treeview-openzone d-inline-block p-2 ps-0', style: 'width: 22px', remote: true do %> - <span class="open_btn"><i class="fas fa-folder"></i></span> - <span class="close_btn"><i class="fas fa-folder-open"></i></span> - <% end %> + <%= link_to children_admin_communication_website_page_path(website_id: page.website.id, id: page.id), + class: 'js-treeview-openzone d-inline-block p-2 ps-0', style: 'width: 22px', remote: true do %> + <% icon_style = page.has_children? ? 'fas' : 'far' %> + <span class="open_btn"> + <i class="open_btn--with_children fas fa-folder"></i> + <i class="open_btn--without_children far fa-folder"></i> + </span> + <span class="close_btn"> + <i class="close_btn--with_children fas fa-folder-open"></i> + <i class="close_btn--without_children far fa-folder-open"></i> + </span> <% end %> <%= link_to page, admin_communication_website_page_path(website_id: page.website.id, id: page.id) %> <span class="move_btn py-2 ps-2"><i class="fas fa-sort"></i></span> </div> - <% if page.has_children? %> - <ul class="list-unstyled treeview__children js-treeview-children js-treeview-sortable ms-4" data-id="<%= page.id %>"> - <li>loading...</li> - </ul> - <% end %> + <ul class="list-unstyled treeview__children js-treeview-children js-treeview-sortable-container ms-4" data-id="<%= page.id %>"> + <li class="treeview__empty"> + <div class="d-flex align-items-center treeview__label border-bottom p-1"> + <span class="p-2 ps-0"><%= t('empty_folder') %></span> + </div> + </li> + <li class="treeview__loading"><%= t('loading') %></li> + </ul> </li> <% end %> diff --git a/app/views/admin/communication/website/pages/children.js.erb b/app/views/admin/communication/website/pages/children.js.erb index 0351232a9a14132053bc1732b8d9c363e8739710..3af22dfe0f0425dfe013a42dbed5250a215837a5 100644 --- a/app/views/admin/communication/website/pages/children.js.erb +++ b/app/views/admin/communication/website/pages/children.js.erb @@ -1,4 +1,8 @@ -$branch = $('.js-treeview-branch[data-id=<%= @page.id %>]'); -$('.js-treeview-children', $branch).html("<%= escape_javascript(render 'treebranch', pages: @children) %>"); -$branch.addClass('treeview__branch--loaded'); +$branch = $('.js-treeview-element[data-id=<%= @page.id %>]'); +<% if @children.any? %> + $('.js-treeview-children', $branch).append("<%= escape_javascript(render 'treebranch', pages: @children) %>"); +<% else %> + $branch.addClass('treeview__element--empty'); +<% end %> +$branch.addClass('treeview__element--loaded'); window.osuny.treeView.initSortable(); diff --git a/app/views/admin/communication/website/pages/index.html.erb b/app/views/admin/communication/website/pages/index.html.erb index 9c2a0a948eac6cc5036f33d61a6c718ae96ae0c4..ddd2e1f5d519c555a389e30c190ea858aa295c3b 100644 --- a/app/views/admin/communication/website/pages/index.html.erb +++ b/app/views/admin/communication/website/pages/index.html.erb @@ -1,7 +1,8 @@ -<% content_for :title, Communication::Website::Page.model_name.human(count: 2) %> +<% content_for :title, "#{Communication::Website::Page.model_name.human(count: 2)} (#{@website.pages.count})" %> -<ul class="list-unstyled treeview js-treeview js-treeview-sortable" data-id=""> - <%= render 'treebranch', pages: @pages %> + +<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_pages_path %>"> + <%= render 'treebranch', pages: @root_pages %> </ul> <% content_for :action_bar_right do %> diff --git a/app/views/admin/communication/website/pages/jekyll.html.erb b/app/views/admin/communication/website/pages/jekyll.html.erb index a3207c1db23d0f7dfd5bc2219454ae96e261bdde..16629fafabcfdfb45fb52529582a35d6bfc107dd 100644 --- a/app/views/admin/communication/website/pages/jekyll.html.erb +++ b/app/views/admin/communication/website/pages/jekyll.html.erb @@ -2,7 +2,9 @@ title: "<%= @page.title %>" permalink: "<%= @page.path %>" parent: "<%= @page.parent_id %>" -description: "<%= prepare_for_github @page.description %>" -text: "<%= prepare_for_github @page.text %>" +description: > + <%= prepare_for_github @page.description %> +text: > + <%= prepare_for_github @page.text %> --- -<%= @page.content_without_frontmatter.html_safe %> +<%= @page.github_frontmatter.content.html_safe %> diff --git a/app/views/admin/communication/website/pages/show.html.erb b/app/views/admin/communication/website/pages/show.html.erb index a989bb177b51b90bd5fcdcda932d9897450d595b..ed4e45b2f89098015f5f98dca82482375e520c9b 100644 --- a/app/views/admin/communication/website/pages/show.html.erb +++ b/app/views/admin/communication/website/pages/show.html.erb @@ -4,25 +4,25 @@ <div class="col-md-8"> <div class="card flex-fill w-100"> <div class="card-header"> - <h5 class="card-title mb-0">Content</h5> + <h5 class="card-title mb-0"><%= t('communication.website.content') %></h5> </div> <div class="card-body"> <p> - <strong>Description</strong> + <strong><%= Communication::Website::Page.human_attribute_name('description') %></strong> </p> <%= sanitize @page.description %> <p> - <strong>Text</strong> + <strong><%= Communication::Website::Page.human_attribute_name('text') %></strong> </p> - <%= sanitize @page.text %> + <%= @page.text %> </div> </div> </div> <div class="col-md-4"> <div class="card flex-fill w-100"> <div class="card-header"> - <h5 class="card-title mb-0">Metadata</h5> + <h5 class="card-title mb-0"><%= t('communication.website.metadata') %></h5> </div> <table class="<%= table_classes %>"> <tbody> @@ -34,16 +34,17 @@ <td><%= Communication::Website::Page.human_attribute_name('path') %></td> <td><%= @page.path %></td> </tr> - <% if @page.imported_page %> - <tr> - <td>Imported from</td> - <td><a href="<%= @page.imported_page.url %>" target="_blank">Original URL</a></td> - </tr> - <% end %> + <tr> + <td><%= Communication::Website::Page.human_attribute_name('published') %></td> + <td> + <%= t @page.published %> + </td> + </tr> <% if @page.parent %> <tr> <td><%= Communication::Website::Page.human_attribute_name('parent') %></td> - <td><%= link_to @page.parent, + <td><%= link_to_if can?(:read, @page.parent), + @page.parent, admin_communication_website_page_path( website_id: @website.id, id: @page.parent.id @@ -56,7 +57,8 @@ <td> <ul class="list-unstyled mb-0"> <% @page.children.each do |child| %> - <li><%= link_to child, + <li><%= link_to_if can?(:read, child), + child, admin_communication_website_page_path( website_id: @website.id, id: child.id @@ -69,6 +71,16 @@ </tbody> </table> </div> + <% if @page.featured_image.attached? %> + <div class="card flex-fill w-100"> + <div class="card-header"> + <h5 class="card-title mb-0"><%= t('activerecord.attributes.communication/website/page.featured_image') %></h5> + </div> + <div class="card-body"> + <%= image_tag @page.featured_image.variant(resize: '600'), class: 'img-fluid mb-3' %><br> + </div> + </div> + <% end %> </div> </div> diff --git a/app/views/admin/communication/website/posts/_form.html.erb b/app/views/admin/communication/website/posts/_form.html.erb index 3bf62603ef38e6905409c09c8d955f10ac110456..97b5236b11575dfb82166af6eea7082ca9ee756d 100644 --- a/app/views/admin/communication/website/posts/_form.html.erb +++ b/app/views/admin/communication/website/posts/_form.html.erb @@ -18,8 +18,24 @@ <h5 class="card-title mb-0"><%= t('communication.website.metadata') %></h5> </div> <div class="card-body"> + <%= f.input :slug, as: :string %> <%= f.input :published %> <%= f.input :published_at, html5: true %> + <%= f.association :categories, as: :check_boxes if @website.categories.any? %> + </div> + </div> + <div class="card flex-fill w-100"> + <div class="card-header"> + <h5 class="card-title mb-0"><%= t('activerecord.attributes.communication/website/post.featured_image') %></h5> + </div> + <div class="card-body"> + <%= f.input :featured_image, + as: :single_deletable_file, + direct_upload: true, + label: false, + input_html: { accept: '.jpg,.jpeg,.png' }, + preview: true + %> </div> </div> </div> diff --git a/app/views/admin/communication/website/posts/_list.html.erb b/app/views/admin/communication/website/posts/_list.html.erb index 7f6971c59852bde5ff9f35caa6c9e264f52b9ab1..508c7314a48f9368fecf5fbf993c3452db1fa9e7 100644 --- a/app/views/admin/communication/website/posts/_list.html.erb +++ b/app/views/admin/communication/website/posts/_list.html.erb @@ -2,6 +2,7 @@ <thead> <tr> <th><%= Communication::Website::Post.human_attribute_name('title') %></th> + <th><%= Communication::Website::Post.human_attribute_name('featured_image') %></th> <th><%= Communication::Website::Post.human_attribute_name('published_at') %></th> <th></th> </tr> @@ -10,6 +11,8 @@ <% posts.each do |post| %> <tr> <td><%= link_to post, admin_communication_website_post_path(website_id: post.website.id, id: post.id) %></td> + <td><%= image_tag post.featured_image.representation(resize: 'x100'), + height: 50 if post.featured_image.attached? && post.featured_image.representable? %></td> <td><%= l post.published_at, format: :long if post.published_at %></td> <td class="text-end"> <div class="btn-group" role="group"> diff --git a/app/views/admin/communication/website/posts/index.html.erb b/app/views/admin/communication/website/posts/index.html.erb index 760c743c07a5b8de9b2b1320a7515d8eba82b306..192c8fde23befce2e6a0232ec6d6e712f131d358 100644 --- a/app/views/admin/communication/website/posts/index.html.erb +++ b/app/views/admin/communication/website/posts/index.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, Communication::Website::Post.model_name.human(count: 2) %> +<% content_for :title, "#{Communication::Website::Post.model_name.human(count: 2)} (#{@posts.total_count})" %> <%= render 'admin/communication/website/posts/list', posts: @posts %> <%= paginate @posts, theme: 'bootstrap-5' %> diff --git a/app/views/admin/communication/website/posts/jekyll.html.erb b/app/views/admin/communication/website/posts/jekyll.html.erb index 6739f18c7a37273bd516d71242875d5188f091ce..72ba139212956f54e6702b22d93b0c77bd442c45 100644 --- a/app/views/admin/communication/website/posts/jekyll.html.erb +++ b/app/views/admin/communication/website/posts/jekyll.html.erb @@ -2,7 +2,12 @@ title: "<%= @post.title %>" date: <%= @post.published_at %> UTC slug: "<%= @post.slug %>" -description: "<%= prepare_for_github @post.description %>" -text: "<%= prepare_for_github @post.text %>" +<% if @post.featured_image.attached? %> +image: "<%= @post.featured_image.blob.url %>" +<% end %> +description: > + <%= prepare_for_github @post.description %> +text: > + <%= prepare_for_github @post.text %> --- -<%= @post.content_without_frontmatter.html_safe %> +<%= @post.github_frontmatter.content.html_safe %> diff --git a/app/views/admin/communication/website/posts/show.html.erb b/app/views/admin/communication/website/posts/show.html.erb index 1fd65d4beb3b14368fd0bdf5bdda7f97e909004d..2a95763dd05bd20a4a513c76a79e0298a8f1e4c6 100644 --- a/app/views/admin/communication/website/posts/show.html.erb +++ b/app/views/admin/communication/website/posts/show.html.erb @@ -26,26 +26,43 @@ <table class="<%= table_classes %>"> <tbody> <tr> - <td width="150"><%= Communication::Website::Page.human_attribute_name('slug') %></td> + <td width="150"><%= Communication::Website::Post.human_attribute_name('slug') %></td> <td><%= @post.slug %></td> </tr> <tr> - <td><%= Communication::Website::Page.human_attribute_name('published_at') %></td> - <td><%= l @post.published_at, format: :long if @post.published_at %></td> + <td><%= Communication::Website::Post.human_attribute_name('published') %></td> + <td> + <%= t @post.published %> + <% if @post.published & @post.published_at %> + <p><small><%= l @post.published_at, format: :long if @post.published_at %></small></p> + <% end %> + </td> </tr> - <tr> - <td><%= Communication::Website::Page.human_attribute_name('published') %></td> - <td><%= t @post.published %></td> - </tr> - <% if @post.imported_post %> + <% if @post.categories.any? %> <tr> - <td><%= t('communication.website.imported.from') %></td> - <td><a href="<%= @post.imported_post.url %>" target="_blank">Original URL</a></td> + <td><%= Communication::Website::Post.human_attribute_name('categories') %></td> + <td> + <ul class="list-unstyled mb-0"> + <% @post.categories.each do |category| %> + <li><%= link_to_if can?(:read, category), category, [:admin, category] %></li> + <% end %> + </ul> + </td> </tr> <% end %> </tbody> </table> </div> + <% if @post.featured_image.attached? %> + <div class="card flex-fill w-100"> + <div class="card-header"> + <h5 class="card-title mb-0"><%= t('activerecord.attributes.communication/website/post.featured_image') %></h5> + </div> + <div class="card-body"> + <%= image_tag @post.featured_image.variant(resize: '600'), class: 'img-fluid mb-3' %><br> + </div> + </div> + <% end %> </div> </div> diff --git a/app/views/admin/communication/websites/_form.html.erb b/app/views/admin/communication/websites/_form.html.erb index 3ad7c36fae29967d3ecf8cdc7fa32781fa9bf8db..c9cf878a4fe8a23da656a555ea3cb0e62c0f947c 100644 --- a/app/views/admin/communication/websites/_form.html.erb +++ b/app/views/admin/communication/websites/_form.html.erb @@ -13,6 +13,8 @@ case website.about_type when Research::Journal.name collection = current_university.research_journals + when Education::School.name + collection = current_university.education_schools end %> <%= f.input :about_id, diff --git a/app/views/admin/communication/websites/import.html.erb b/app/views/admin/communication/websites/import.html.erb index 086d4f676b9fbf4cb6e4d5e83b3b2fe71b23f26a..0274d1e7abccbe17f75cb18e6154133d6327e82f 100644 --- a/app/views/admin/communication/websites/import.html.erb +++ b/app/views/admin/communication/websites/import.html.erb @@ -84,9 +84,9 @@ <% @imported_media.each do |medium| %> <tr> <td><%= medium.filename %></td> - <td><%= number_to_human_size(medium.file.blob.byte_size) if medium.file.attached? %></td> + <td><%= number_to_human_size(medium.file.blob.byte_size) if medium&.file&.attached? %></td> <td class="text-end"> - <% if medium.file.attached? %> + <% if medium&.file&.attached? %> <%= link_to t('show'), url_for(medium.file), class: button_classes, diff --git a/app/views/admin/communication/websites/show.html.erb b/app/views/admin/communication/websites/show.html.erb index 50107a846f815cebb8308b921fc0b4b9372085bc..950960f1fb67b6f65c28b19c30fd25f8b18b536b 100644 --- a/app/views/admin/communication/websites/show.html.erb +++ b/app/views/admin/communication/websites/show.html.erb @@ -1,44 +1,81 @@ <% content_for :title, @website %> -<p> - <%= link_to @website.domain_url, @website.domain_url, target: :_blank %> -</p> - -<p> +<% content_for :title_right do %> + <% unless @website.domain.blank? %> + <%= link_to @website.domain_url, @website.domain_url, target: :_blank %><br> + <% end %> <%= I18n.t("activerecord.attributes.communication/website.about_#{@website.about_type}") %> - <%= link_to @website.about, [:admin, @website.about] unless @website.about.nil? %> -</p> + <% if @website.about %> + (<%= link_to @website.about, [:admin, @website.about] unless @website.about.nil? %>) + <% end %> +<% end %> <div class="card mt-5"> <div class="card-header"> <div class="float-end"> - <%= link_to t('activerecord.models.communication/website/post.all'), - admin_communication_website_posts_path(website_id: @website), - class: 'me-3' %> - <%= link_to t('create'), + <%= link_to_if can?(:create, Communication::Website::Post), + t('create'), new_admin_communication_website_post_path(website_id: @website), class: button_classes %> </div> - <h2 class="card-title"><%= Communication::Website::Post.model_name.human(count: 2) %></h2> + <h2 class="card-title"> + <%= link_to admin_communication_website_posts_path(website_id: @website) do %> + <%= t('communication.website.last_posts') %> + <small> + - + <%= t('communication.website.see_all', number: @website.posts.count) %> + </small> + <% end %> + </h2> </div> <%= render 'admin/communication/website/posts/list', posts: @website.posts.recent %> </div> -<div class="card mt-5"> - <div class="card-header"> - <div class="float-end"> - <%= link_to t('activerecord.models.communication/website/page.all'), - admin_communication_website_pages_path(website_id: @website), - class: 'me-3' %> - <%= link_to t('create'), - new_admin_communication_website_page_path(website_id: @website), - class: button_classes %> + +<div class="row"> + <div class="col-md-7"> + <div class="card mt-5"> + <div class="card-header"> + <div class="float-end"> + <%= link_to t('create'), + new_admin_communication_website_page_path(website_id: @website), + class: button_classes %> + </div> + <h2 class="card-title"> + <%= link_to admin_communication_website_pages_path(website_id: @website) do %> + <%= t('communication.website.last_pages') %> + <small> + - + <%= t('communication.website.see_all', number: @website.pages.count) %> + </small> + <% end %> + </h2> + </div> + <%= render 'admin/communication/website/pages/list', pages: @website.pages.recent %> + </div> + </div> + <div class="col-md-5"> + <div class="card mt-5"> + <div class="card-header"> + <div class="float-end"> + <%= link_to t('create'), + new_admin_communication_website_category_path(website_id: @website), + class: button_classes %> + </div> + <h2 class="card-title"> + <%= link_to admin_communication_website_categories_path(website_id: @website) do %> + <%= Communication::Website::Category.model_name.human(count: 2) %> + <small> + - + <%= t('communication.website.see_all', number: @website.categories.count) %> + </small> + <% end %> + </h2> + </div> + <%= render 'admin/communication/website/categories/list', categories: @website.categories.ordered %> </div> - <h2 class="card-title"><%= Communication::Website::Page.model_name.human(count: 2) %></h2> </div> - <%= render 'admin/communication/website/pages/list', pages: @website.pages.recent %> </div> - <% content_for :action_bar_right do %> <% if @website.imported? %> <%= link_to t('communication.website.imported.show'), diff --git a/app/views/admin/education/programs/index.html.erb b/app/views/admin/education/programs/index.html.erb index e220d4867bc49606aebee8b787486df754eb94f4..9d3783318ad8f3433eec879937d09ed1f8ba20eb 100644 --- a/app/views/admin/education/programs/index.html.erb +++ b/app/views/admin/education/programs/index.html.erb @@ -14,8 +14,10 @@ <td><%= link_to program, [:admin, program] %></td> <td><%= program.level %></td> <td class="text-end"> - <%= edit_link program %> - <%= destroy_link program %> + <div class="btn-group" role="group"> + <%= edit_link program %> + <%= destroy_link program %> + </div> </td> </tr> <% end %> diff --git a/app/views/admin/education/schools/_form.html.erb b/app/views/admin/education/schools/_form.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..a6859f685187a580f2a959d908626175ddce92ac --- /dev/null +++ b/app/views/admin/education/schools/_form.html.erb @@ -0,0 +1,22 @@ +<%= simple_form_for [:admin, school] do |f| %> + <div class="row"> + <div class="col-md-4"> + <%= f.input :name %> + </div> + <div class="col-md-8"> + <%= f.input :address %> + <div class="row"> + <div class="col-md-4"> + <%= f.input :zipcode %> + </div> + <div class="col-md-8"> + <%= f.input :city %> + </div> + </div> + <%= f.input :country %> + </div> + </div> + <% content_for :action_bar_right do %> + <%= submit f %> + <% end %> +<% end %> diff --git a/app/views/admin/education/schools/edit.html.erb b/app/views/admin/education/schools/edit.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..2ffe2c0eae8f57cc9cf0e87a198f1758245bf694 --- /dev/null +++ b/app/views/admin/education/schools/edit.html.erb @@ -0,0 +1,3 @@ +<% content_for :title, @school %> + +<%= render 'form', school: @school %> diff --git a/app/views/admin/education/schools/index.html.erb b/app/views/admin/education/schools/index.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..60026b10e5e4bb122924ca5ba9b74f55685e5c26 --- /dev/null +++ b/app/views/admin/education/schools/index.html.erb @@ -0,0 +1,33 @@ +<% content_for :title, Education::School.model_name.human(count: 2) %> + +<table class="table"> + <thead> + <tr> + <th><%= Education::School.human_attribute_name('name') %></th> + <th><%= Education::School.human_attribute_name('address') %></th> + <th><%= Education::School.human_attribute_name('zipcode') %></th> + <th><%= Education::School.human_attribute_name('city') %></th> + <th></th> + </tr> + </thead> + + <tbody> + <% @schools.each do |school| %> + <tr> + <td><%= link_to school.name, [:admin, school] %></td> + <td><%= school.address %></td> + <td><%= school.zipcode %></td> + <td><%= school.city %></td> + <td class="text-end"> + <div class="btn-group" role="group"> + <%= edit_link school %> + <%= destroy_link school %> + </div> + </td> + <% end %> + </tbody> +</table> + +<% content_for :action_bar_right do %> + <%= create_link Education::School %> +<% end %> diff --git a/app/views/admin/education/schools/new.html.erb b/app/views/admin/education/schools/new.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..788e600fdea80796a7f45d2ef9ed33894ce484e4 --- /dev/null +++ b/app/views/admin/education/schools/new.html.erb @@ -0,0 +1,3 @@ +<% content_for :title, Education::School.model_name.human %> + +<%= render 'form', school: @school %> diff --git a/app/views/admin/education/schools/show.html.erb b/app/views/admin/education/schools/show.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..2947ba58b407a651e38fbc0e1a673a89f416b974 --- /dev/null +++ b/app/views/admin/education/schools/show.html.erb @@ -0,0 +1,19 @@ +<% content_for :title, @school %> + +<% content_for :title_right do %> + <% if @school.website %> + <%= Communication::Website.model_name.human %> + <i class="fas fa-arrow-right small"></i> + <%= link_to @school.website, [:admin, @school.website] %><br> + <% end %> +<% end %> + +<p> + <%= @school.address %><br> + <%= @school.zipcode %> <%= @school.city %><br> + <%= @school.country %> +</p> + +<% content_for :action_bar_right do %> + <%= edit_link @school %> +<% end %> diff --git a/app/views/admin/layouts/application.html.erb b/app/views/admin/layouts/application.html.erb index f0cef5d551bf999a8f33c91541cc20c90d46bf39..94b603dc8736a2d557193600c99ec66e05321797 100644 --- a/app/views/admin/layouts/application.html.erb +++ b/app/views/admin/layouts/application.html.erb @@ -31,6 +31,7 @@ <%= render 'admin/application/top' %> <main class="content"> <div class="container-fluid p-0"> + <p class="float-end text-end pt-1"><%= yield :title_right %></p> <h1><%= yield :title %></h1> <%= yield %> </div> diff --git a/app/views/admin/research/journal/articles/_list.html.erb b/app/views/admin/research/journal/articles/_list.html.erb index 1c089777464f258bd43c7501dabcaf388a6e3c2c..3d8425c402f71789117f21e81b67e27bda38eb99 100644 --- a/app/views/admin/research/journal/articles/_list.html.erb +++ b/app/views/admin/research/journal/articles/_list.html.erb @@ -1,7 +1,7 @@ <table class="table"> <thead> <tr> - <th class="ps-0"><%= Research::Journal::Article.model_name.human %></th> + <th><%= Research::Journal::Article.model_name.human %></th> <th><%= Research::Journal::Article.human_attribute_name('published_at') %></th> <th></th> </tr> @@ -9,17 +9,19 @@ <tbody> <% articles.each do |article| %> <tr> - <td class="ps-0"><%= link_to article, admin_research_journal_article_path(journal_id: @journal, id: article) %></td> + <td><%= link_to article, admin_research_journal_article_path(journal_id: @journal, id: article) %></td> <td><%= article.published_at %></td> - <td class="text-end pe-0"> - <%= link_to t('edit'), - edit_admin_research_journal_article_path(journal_id: @journal, id: article), - class: button_classes %> - <%= link_to t('delete'), - admin_research_journal_article_path(journal_id: @journal, id: article), - method: :delete, - data: { confirm: t('please-confirm') }, - class: button_classes_danger %> + <td class="text-end"> + <div class="btn-group" role="group"> + <%= link_to t('edit'), + edit_admin_research_journal_article_path(journal_id: @journal, id: article), + class: button_classes %> + <%= link_to t('delete'), + admin_research_journal_article_path(journal_id: @journal, id: article), + method: :delete, + data: { confirm: t('please-confirm') }, + class: button_classes_danger %> + </div> </td> </tr> <% end %> diff --git a/app/views/admin/research/journal/volumes/index.html.erb b/app/views/admin/research/journal/volumes/index.html.erb index 6998ad87a3d0dd48d11dbb6404e4f9ad161b4568..6cc3da67ae2a67c2e560d702432c5f056ee9051a 100644 --- a/app/views/admin/research/journal/volumes/index.html.erb +++ b/app/views/admin/research/journal/volumes/index.html.erb @@ -4,7 +4,8 @@ <thead> <tr> <th><%= Research::Journal::Volume.model_name.human %></th> - <th>Published at</th> + <th><%= Research::Journal::Volume.human_attribute_name('cover') %></th> + <th><%= Research::Journal::Volume.human_attribute_name('published_at') %></th> <th></th> </tr> </thead> @@ -12,10 +13,14 @@ <% @volumes.each do |volume| %> <tr> <td><%= link_to volume, admin_research_journal_volume_path(journal_id: @journal, id: volume) %></td> + <td><%= image_tag volume.cover.variant(resize: 'x200'), + height: 100 if volume.cover.attached? %></td> <td><%= volume.published_at %></td> <td class="text-end"> - <%= edit_link volume, { journal_id: @journal.id } %> - <%#= destroy_link volume, journal_id: @journal.id %> + <div class="btn-group" role="group"> + <%= edit_link volume, { journal_id: @journal.id } %> + <%#= destroy_link volume, journal_id: @journal.id %> + </div> </td> </tr> <% end %> diff --git a/app/views/admin/research/journal/volumes/show.html.erb b/app/views/admin/research/journal/volumes/show.html.erb index dcdaedf03db2db5814edf8e941107625465df612..e5eb67fa85b902e78aae48cbbe701604f1acf38a 100644 --- a/app/views/admin/research/journal/volumes/show.html.erb +++ b/app/views/admin/research/journal/volumes/show.html.erb @@ -1,7 +1,17 @@ <% content_for :title, @volume %> <div class="row"> - <div class="col-md-3"> + <div class="col-md-8"> + <div class="card flex-fill w-100"> + <div class="card-header"> + <h2 class="card-title mb-0 h5">Articles</h2> + </div> + <div class="card-body"> + <%= render 'admin/research/journal/articles/list', articles: @volume.articles %> + </div> + </div> + </div> + <div class="col-md-4"> <% if @volume.cover.attached? %> <%= image_tag @volume.cover, class: 'img-fluid img-thumbnail bg-light mb-4' %> <% end %> @@ -15,16 +25,6 @@ </p> <%= @volume.description %> </div> - <div class="col-md-9"> - <div class="card flex-fill w-100"> - <div class="card-header"> - <h2 class="card-title mb-0 h5">Articles</h2> - </div> - <div class="card-body"> - <%= render 'admin/research/journal/articles/list', articles: @volume.articles %> - </div> - </div> - </div> </div> <% content_for :action_bar_right do %> diff --git a/app/views/admin/research/journals/index.html.erb b/app/views/admin/research/journals/index.html.erb index e3a66dd73fccf3f6efa14d5eca051482a9ae85b7..3f4804c69d25a01b022b1fd595fe0b613c767085 100644 --- a/app/views/admin/research/journals/index.html.erb +++ b/app/views/admin/research/journals/index.html.erb @@ -17,8 +17,10 @@ <td><%= link_to "#{journal.volumes.count}", admin_research_journal_volumes_path(journal_id: journal) %></td> <td><%= link_to "#{journal.articles.count}", admin_research_journal_articles_path(journal_id: journal) %></td> <td class="text-end"> - <%= edit_link journal %> - <%= destroy_link journal %> + <div class="btn-group" role="group"> + <%= edit_link journal %> + <%= destroy_link journal %> + </div> </td> </tr> <% end %> diff --git a/app/views/admin/research/journals/show.html.erb b/app/views/admin/research/journals/show.html.erb index 8517584e362c995152997f1c3bbb18f3b3038b8d..674a37a04f68355ec1d1953767ba39e0d96538c3 100644 --- a/app/views/admin/research/journals/show.html.erb +++ b/app/views/admin/research/journals/show.html.erb @@ -1,46 +1,55 @@ <% content_for :title, @journal %> -<p>ISSN : <%= @journal.issn %></p> - -<% if @journal.website %> - <p> - Site : - <%= link_to @journal.website, [:admin, @journal.website] %> - </p> +<% content_for :title_right do %> + <% if @journal.website %> + <%= Communication::Website.model_name.human %> + <i class="fas fa-arrow-right small"></i> + <%= link_to @journal.website, [:admin, @journal.website] %><br> + <% end %> + <% if @journal.issn %><%= Research::Journal.human_attribute_name('issn') %> <%= @journal.issn %><% end %> <% end %> -<h2 class="mt-5"><%= Research::Journal::Volume.model_name.human(count: 2) %></h2> - -<%= link_to t('create'), - new_admin_research_journal_volume_path(journal_id: @journal), - class: button_classes('me-3') %> -<%= link_to 'Tous les volumes', - admin_research_journal_volumes_path(journal_id: @journal) %> - -<div class="row"> - <% @journal.volumes.ordered.limit(4).each do |volume| %> - <div class="col-md-3 mt-4"> - <div class="card"> - <%= image_tag volume.cover, class: 'img-fluid' if volume.cover.attached? %> - <div class="card-body"> - <%= link_to volume, admin_research_journal_volume_path(journal_id: @journal, id: volume), class: 'stretched-link' %> +<div class="card mt-5"> + <div class="card-header"> + <div class="float-end"> + <%= link_to t('create'), + new_admin_research_journal_volume_path(journal_id: @journal), + class: button_classes %> + </div> + <h2 class="card-title"> + <%= link_to Research::Journal::Volume.model_name.human(count: 2), + admin_research_journal_volumes_path(journal_id: @journal) %></h2> + </div> + <div class="card-body"> + <div class="row"> + <% @journal.volumes.ordered.limit(4).each do |volume| %> + <div class="col-md-3 mt-4"> + <div class="card"> + <%= image_tag volume.cover, class: 'img-fluid' if volume.cover.attached? %> + <div class="card-body"> + <%= link_to volume, admin_research_journal_volume_path(journal_id: @journal, id: volume), class: 'stretched-link' %> + </div> + </div> </div> - </div> + <% end %> </div> - <% end %> + </div> </div> -<h2 class="mt-5"><%= Research::Journal::Article.model_name.human(count: 2) %></h2> - -<%= link_to t('create'), - new_admin_research_journal_article_path(journal_id: @journal), - class: button_classes('me-3') %> - -<%= link_to 'Tous les articles', - admin_research_journal_articles_path(journal_id: @journal) %> - -<%= render 'admin/research/journal/articles/list', articles: @journal.articles.ordered.limit(10) %> +<div class="card mt-5"> + <div class="card-header"> + <div class="float-end"> + <%= link_to t('create'), + new_admin_research_journal_article_path(journal_id: @journal), + class: button_classes %> + </div> + <h2 class="card-title"> + <%= link_to Research::Journal::Article.model_name.human(count: 2), + admin_research_journal_articles_path(journal_id: @journal) %></h2> + </div> + <%= render 'admin/research/journal/articles/list', articles: @journal.articles.ordered.limit(10) %> +</div> <% content_for :action_bar_right do %> <%= edit_link @journal %> diff --git a/app/views/admin/research/researchers/index.html.erb b/app/views/admin/research/researchers/index.html.erb index f7307ecaba379dfd569cdf8aa1df0d34e972880e..c975d12203568d10a7df768e0ea306e29885d53f 100644 --- a/app/views/admin/research/researchers/index.html.erb +++ b/app/views/admin/research/researchers/index.html.erb @@ -17,8 +17,10 @@ <td><%= link_to researcher.last_name, [:admin, researcher] %></td> <td><%= link_to researcher.user, [:admin, researcher.user] if researcher.user %></td> <td class="text-end"> - <%= edit_link researcher %> - <%= destroy_link researcher %> + <div class="btn-group" role="group"> + <%= edit_link researcher %> + <%= destroy_link researcher %> + </div> </td> </tr> <% end %> diff --git a/app/views/admin/users/index.html.erb b/app/views/admin/users/index.html.erb index 3164b6cefc6505956adfc8c77eb07a84c655bb74..b161dcbcd90a13939ca78fddb993908723e7f261 100644 --- a/app/views/admin/users/index.html.erb +++ b/app/views/admin/users/index.html.erb @@ -1,4 +1,5 @@ -<% content_for :title, User.model_name.human(count: 2) %> +<% content_for :title, "#{User.model_name.human(count: 2)} (#{@users.total_count})" %> + <table class="table"> <thead> @@ -29,6 +30,7 @@ <% end %> </tbody> </table> +<%= paginate @users, theme: 'bootstrap-5' %> <% content_for :action_bar_right do %> <%= create_link User %> diff --git a/app/views/application/_bugsnag.html.erb b/app/views/application/_bugsnag.html.erb index 11eccb31e7e8a0420355c1208dec1efd7bdb81ef..9847d93b66881498989b2da4fd3977202e86e777 100644 --- a/app/views/application/_bugsnag.html.erb +++ b/app/views/application/_bugsnag.html.erb @@ -5,6 +5,11 @@ apiKey: "<%= j ENV['BUGSNAG_JAVASCRIPT_KEY'] %>", releaseStage: "<%= j ENV['APPLICATION_ENV'] %>" }); + Bugsnag.addOnError(function (event) { + if (event.originalError === 'ResizeObserver loop limit exceeded') { + return false; + } + }); <% if user_signed_in? %> Bugsnag.setUser("<%= j current_user.id %>", "<%= j current_user.email %>", "<%= j current_user.to_s %>"); <% end %> diff --git a/app/views/devise/two_factor_authentication/max_login_attempts_reached.html.erb b/app/views/devise/two_factor_authentication/max_login_attempts_reached.html.erb index 32d0b6cef07e61e1482759660b315009334da0d6..b0e613863d58d910f854e42d60740a45d499624b 100644 --- a/app/views/devise/two_factor_authentication/max_login_attempts_reached.html.erb +++ b/app/views/devise/two_factor_authentication/max_login_attempts_reached.html.erb @@ -1,4 +1,4 @@ <div class="alert alert-danger" role="alert"> <%= t('devise.two_factor_authentication.max_login_attempts_reached').html_safe %> </div> -<%= link_to t('devise.shared.links.sign_out'), destroy_user_session_path, class: "btn btn-danger" %> +<%= link_to t('devise.shared.links.sign_out'), destroy_user_session_path, method: :delete, class: "btn btn-danger" %> diff --git a/bin/setup b/bin/setup index 90700ac4f9a38d569058bc83f2243a08b4c90eb7..310e9886ae476f01af38ca95763f0c8908dcca66 100755 --- a/bin/setup +++ b/bin/setup @@ -20,14 +20,17 @@ FileUtils.chdir APP_ROOT do # Install JavaScript dependencies system! 'bin/yarn' - # puts "\n== Copying sample files ==" - # unless File.exist?('config/database.yml') - # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' - # end + puts "\n== Copying sample files ==" + unless File.exist?('config/application.yml') + FileUtils.cp 'config/application.yml.sample', 'config/application.yml' + end puts "\n== Preparing database ==" system! 'bin/rails db:prepare' + puts "\n== Seeding database ==" + system! 'bin/rails db:seed' + puts "\n== Removing old logs and tempfiles ==" system! 'bin/rails log:clear tmp:clear' diff --git a/config/admin_navigation.rb b/config/admin_navigation.rb index eb04f04d58421c52c8412310218f73209a0b5ef1..5cee38c3a407b151643b9bb4fcb4722b33c2ecb1 100644 --- a/config/admin_navigation.rb +++ b/config/admin_navigation.rb @@ -9,7 +9,7 @@ SimpleNavigation::Configuration.run do |navigation| if can?(:read, Education::Program) primary.item :education, Education.model_name.human, nil, { kind: :header } primary.item :education, 'Enseignants', nil, { icon: 'user-graduate' } - primary.item :education, 'Ecoles', nil, { icon: 'university' } + primary.item :education, Education::School.model_name.human(count: 2), admin_education_schools_path, { icon: 'university' } if can?(:read, Education::School) primary.item :education_programs, Education::Program.model_name.human(count: 2), admin_education_programs_path, { icon: 'graduation-cap' } if can?(:read, Education::Program) primary.item :education, 'Ressources éducatives', nil, { icon: 'laptop' } primary.item :education, 'Feedbacks', nil, { icon: 'comments' } diff --git a/config/application.yml.sample b/config/application.yml.sample new file mode 100644 index 0000000000000000000000000000000000000000..2ba8a01b6898d37597746e1f4d0c61fdfdf40a81 --- /dev/null +++ b/config/application.yml.sample @@ -0,0 +1,25 @@ +APPLICATION_ENV: development + +BUGSNAG_JAVASCRIPT_KEY: +BUGSNAG_RUBY_KEY: + +MAIL_FROM_DEFAULT_ADDRESS: +MAIL_FROM_DEFAULT_NAME: + +OSUNY_STAGING_APP_NAME: +OSUNY_STAGING_PG_ADDON_ID: + +OTP_SECRET_ENCRYPTION_KEY: + +SCALEWAY_OS_ACCESS_KEY_ID: +SCALEWAY_OS_BUCKET: +SCALEWAY_OS_ENDPOINT: +SCALEWAY_OS_REGION: +SCALEWAY_OS_SECRET_ACCESS_KEY: + +SECRET_KEY_BASE: + +SEND_IN_BLUE_API_KEY: + +SMTP_USER: +SMTP_PASSWORD: diff --git a/config/locales/communication/en.yml b/config/locales/communication/en.yml index ae2c0416a935ecbdb37f73ccbc9da04bbc7c0c52..52cb38cbc2ef08eed38723a066b8b39b4281a61d 100644 --- a/config/locales/communication/en.yml +++ b/config/locales/communication/en.yml @@ -6,13 +6,17 @@ en: from: Imported from launch: Launch import launched: Import in progress + original_url: Original URL media: file_size: File size not_imported_yet: Not imported yet refresh: Refresh import show: Show import pending: Import in progress + last_pages: Last pages + last_posts: Last posts metadata: Metadata + see_all: See the full list (%{number} elements) activemodel: models: communication: Communication @@ -21,6 +25,13 @@ en: communication/website: one: Website other: Websites + communication/website/category: + one: Category + other: Categories + all: All categories + communication/website/imported/website: + one: Imported website + other: Imported websites communication/website/page: one: Page other: Pages @@ -29,22 +40,24 @@ en: one: Post other: Posts all: All posts - communication/website/imported/website: - one: Imported website - other: Imported websites attributes: communication/website: + categories: Categories name: Name domain: Domain about_type: About - about_: Nothing (independent website) + about_: Independent website (no specific subject) about_Research::Journal: Journal website - about_School: School website + about_Education::School: School website + communication/website/category: + description: Description + title: Title communication/website/imported/medium: filename: Filename communication/website/page: title: Title description: Description (SEO) + featured_image: Featured image text: Text published: Published ? parent: Parent page @@ -52,6 +65,7 @@ en: communication/website/post: title: Title description: Description (SEO) + featured_image: Featured image text: Text published: Published ? published_at: Publication date diff --git a/config/locales/communication/fr.yml b/config/locales/communication/fr.yml index 9ba816755606a7d15353ce07450acac0ccdc0d44..ae1d3c0a4f86a07cd299721e0e2c94c358e094c4 100644 --- a/config/locales/communication/fr.yml +++ b/config/locales/communication/fr.yml @@ -6,13 +6,17 @@ fr: from: Importé depuis launch: Importer le site launched: Importation en cours + original_url: URL originale media: file_size: Taille du fichier not_imported_yet: Non importé pour le moment refresh: Relancer l'import show: Voir l'import pending: Import en cours + last_pages: Dernières pages + last_posts: Dernières actualités metadata: Informations + see_all: Voir la liste complète (%{number} éléments) activemodel: models: communication: Communication @@ -21,6 +25,13 @@ fr: communication/website: one: Site Web other: Sites Web + communication/website/category: + one: Catégorie + other: Catégories + all: Toutes les catégories + communication/website/imported/website: + one: Site importé + other: Sites importés communication/website/page: one: Page other: Pages @@ -29,28 +40,31 @@ fr: one: Actualité other: Actualités all: Toutes les actualités - communication/website/imported/website: - one: Site importé - other: Sites importés attributes: communication/website: name: Nom domain: Domaine about_type: Sujet du site - about_: Aucun sujet (site indépendant) + about_: Site indépendant (aucun sujet) about_Research::Journal: Site de revue scientifique - about_School: Site d'école + about_Education::School: Site d'école + communication/website/category: + description: Description + title: Titre communication/website/imported/medium: filename: Nom du fichier communication/website/page: description: Description (SEO) + featured_image: Image à la une parent: Page parente published: Publié ? text: Texte title: Titre website: Site Web communication/website/post: + categories: Categories description: Description (SEO) + featured_image: Image à la une published: Publié ? published_at: Date de publication text: Texte diff --git a/config/locales/education/en.yml b/config/locales/education/en.yml index de3454cea74f4e79e334c451a2e3871f50fda1b1..6fe56f66bc7f578accbb56deba4ec2133eb74063 100644 --- a/config/locales/education/en.yml +++ b/config/locales/education/en.yml @@ -7,6 +7,9 @@ en: education/program: one: Program other: Programs + education/school: + one: School + other: Schools attributes: education/program: name: Name diff --git a/config/locales/education/fr.yml b/config/locales/education/fr.yml index ce89d9fb20eb74968cdf491c66c6ba0534e0a27f..983bb8e43e123ab3da8773a00286770977e090e7 100644 --- a/config/locales/education/fr.yml +++ b/config/locales/education/fr.yml @@ -7,6 +7,9 @@ fr: education/program: one: Formation other: Formations + education/school: + one: École + other: Écoles attributes: education/program: name: Nom diff --git a/config/locales/en.yml b/config/locales/en.yml index 199c04af62b8b960c62402d5978d67d21461d9d3..1ee509842757e2d28055340c3f53afd18cc94d81 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -60,7 +60,7 @@ en: mailer: two_factor_authentication_code: subject: "Two-factor authentication code" - text_html: "Your two-factor authentication code for %{university} is %{code}<br>It will expire in 5 minutes." + text_html: "Your two-factor authentication code for %{university} is: <br><br><b>%{code}</b><br><br>It will expire in 5 minutes." sessions: signed_in: '' shared: @@ -81,6 +81,7 @@ en: send_email_code: 'Send me a code via email' success: "" edit: Edit + empty_folder: Empty folder false: No gdpr: privacy_policy: https://osuny.org/politique-de-confidentialite @@ -88,6 +89,7 @@ en: languages: en: English fr: French + loading: Loading... login: already_registered: Already registered? not_registered_yet: Not registered yet? diff --git a/config/locales/fr.yml b/config/locales/fr.yml index cd24e48a182aad0992e8d830caf8a6d17b98f814..b34e7ed94917978403c2992c53e18273f70f1a20 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -60,7 +60,7 @@ fr: mailer: two_factor_authentication_code: subject: "Code d'authentification à deux facteurs" - text_html: "Votre code d'authentification pour %{university} est %{code}<br>Il expirera dans 5 minutes." + text_html: "Votre code d'authentification pour %{university} est :<br><br><b>%{code}</b><br><br>Il expirera dans 5 minutes." sessions: signed_in: '' shared: @@ -81,6 +81,7 @@ fr: send_email_code: 'Envoyer le code par email' success: "" edit: Modifier + empty_folder: Dossier vide false: Non gdpr: privacy_policy: https://osuny.org/politique-de-confidentialite @@ -88,6 +89,7 @@ fr: languages: en: Anglais fr: Français + loading: Chargement... login: already_registered: Déjà inscrit ? not_registered_yet: Pas encore inscrit ? @@ -118,3 +120,10 @@ fr: terms_of_service_url: https://osuny.org/conditions-d-utilisation true: Oui validate: Valider + views: + pagination: + first: "« Premier" + last: "Dernier »" + previous: "‹ Précédent" + next: "Suivant ›" + truncate: "…" diff --git a/config/locales/research/en.yml b/config/locales/research/en.yml index 986e1e44d7deb9872ac358a9d765083f2b3b993a..b135f9ccb6c35d701608e9643e5f81bf62a061b7 100644 --- a/config/locales/research/en.yml +++ b/config/locales/research/en.yml @@ -19,6 +19,7 @@ en: attributes: research/journal: title: Title + issn: ISSN research/journal/article: title: Title researchers: Authors diff --git a/config/locales/research/fr.yml b/config/locales/research/fr.yml index 69b5a722876660f5d95466c6bac445912fef2ea1..8bc0da52991b77319d535d68c0526359cdc5500c 100644 --- a/config/locales/research/fr.yml +++ b/config/locales/research/fr.yml @@ -19,6 +19,7 @@ fr: attributes: research/journal: title: Titre + issn: ISSN research/journal/article: title: Titre researchers: Auteu·rs·rices diff --git a/config/routes.rb b/config/routes.rb index 7741968a9db05e355dce1c3aaf9bb4c6582ac0ac..47406f626d9ccb002e8f6b0dfda383fcd4b24754 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,6 @@ Rails.application.routes.draw do - match "/delayed_job" => DelayedJobWeb, :anchor => false, :via => [:get, :post] - + devise_for :users, controllers: { confirmations: 'users/confirmations', passwords: 'users/passwords', diff --git a/config/routes/admin/communication.rb b/config/routes/admin/communication.rb index d32660f95fbc8981a457086447f38b25d3afe7f4..ece4457558c25348270668532e66de271dab4e7d 100644 --- a/config/routes/admin/communication.rb +++ b/config/routes/admin/communication.rb @@ -5,10 +5,18 @@ namespace :communication do post :import end resources :pages, controller: 'website/pages' do + collection do + post :reorder + end member do get :children end end + resources :categories, controller: 'website/categories' do + collection do + post :reorder + end + end resources :posts, controller: 'website/posts' end end diff --git a/config/routes/admin/education.rb b/config/routes/admin/education.rb index c6f58926f146a580495fc6c75d818000dd9ba9dd..9f158d5913f21e726c3547314429eaeabb3901e3 100644 --- a/config/routes/admin/education.rb +++ b/config/routes/admin/education.rb @@ -1,3 +1,3 @@ namespace :education do - resources :programs + resources :programs, :schools end diff --git a/config/storage.yml b/config/storage.yml index 66f3ff1fac2a9e91eb39d96180e07e79e8179d47..6b5af23d90bcd79093889204a7ccc5b736f0f837 100644 --- a/config/storage.yml +++ b/config/storage.yml @@ -7,7 +7,7 @@ local: root: <%= Rails.root.join("storage") %> scaleway: - service: S3 + service: Scaleway access_key_id: <%= ENV['SCALEWAY_OS_ACCESS_KEY_ID'] %> secret_access_key: <%= ENV['SCALEWAY_OS_SECRET_ACCESS_KEY'] %> region: <%= ENV['SCALEWAY_OS_REGION'] %> diff --git a/db/migrate/20211021132416_create_communication_website_media.rb b/db/migrate/20211021132416_create_communication_website_media.rb new file mode 100644 index 0000000000000000000000000000000000000000..4c67abade8feea97bd0fcffb95f673f070854b1e --- /dev/null +++ b/db/migrate/20211021132416_create_communication_website_media.rb @@ -0,0 +1,14 @@ +class CreateCommunicationWebsiteMedia < ActiveRecord::Migration[6.1] + def change + create_table :communication_website_media, id: :uuid do |t| + t.string :identifier + t.string :filename + t.string :mime_type + t.text :file_url + t.references :university, null: false, foreign_key: true, type: :uuid + t.references :website, null: false, foreign_key: { to_table: :communication_websites }, type: :uuid + + t.timestamps + end + end +end diff --git a/db/migrate/20211021132440_add_medium_to_communication_website_imported_media.rb b/db/migrate/20211021132440_add_medium_to_communication_website_imported_media.rb new file mode 100644 index 0000000000000000000000000000000000000000..3c0ed4f57742afbced0b0394ffca67d73cab6bb8 --- /dev/null +++ b/db/migrate/20211021132440_add_medium_to_communication_website_imported_media.rb @@ -0,0 +1,5 @@ +class AddMediumToCommunicationWebsiteImportedMedia < ActiveRecord::Migration[6.1] + def change + add_reference :communication_website_imported_media, :medium, foreign_key: { to_table: :communication_website_media }, type: :uuid + end +end diff --git a/db/migrate/20211021144633_replace_datetimes_in_communication_website_imported_media.rb b/db/migrate/20211021144633_replace_datetimes_in_communication_website_imported_media.rb new file mode 100644 index 0000000000000000000000000000000000000000..667fb85a33073bf9aacd328a80206b080d6caeb0 --- /dev/null +++ b/db/migrate/20211021144633_replace_datetimes_in_communication_website_imported_media.rb @@ -0,0 +1,8 @@ +class ReplaceDatetimesInCommunicationWebsiteImportedMedia < ActiveRecord::Migration[6.1] + def change + remove_column :communication_website_imported_media, :created_at, :datetime + remove_column :communication_website_imported_media, :updated_at, :datetime + rename_column :communication_website_imported_media, :remote_created_at, :created_at + rename_column :communication_website_imported_media, :remote_updated_at, :updated_at + end +end diff --git a/db/migrate/20211021152728_add_mime_type_to_communication_website_imported_media.rb b/db/migrate/20211021152728_add_mime_type_to_communication_website_imported_media.rb new file mode 100644 index 0000000000000000000000000000000000000000..22a217137337c5f970f3b89f38b629b820617db9 --- /dev/null +++ b/db/migrate/20211021152728_add_mime_type_to_communication_website_imported_media.rb @@ -0,0 +1,5 @@ +class AddMimeTypeToCommunicationWebsiteImportedMedia < ActiveRecord::Migration[6.1] + def change + add_column :communication_website_imported_media, :mime_type, :string + end +end diff --git a/db/migrate/20211023063050_add_path_to_communication_website_post.rb b/db/migrate/20211023063050_add_path_to_communication_website_post.rb new file mode 100644 index 0000000000000000000000000000000000000000..0cd1c7266b3c9cad1babc75c96af48c75d97980e --- /dev/null +++ b/db/migrate/20211023063050_add_path_to_communication_website_post.rb @@ -0,0 +1,7 @@ +class AddPathToCommunicationWebsitePost < ActiveRecord::Migration[6.1] + def change + add_column :communication_website_posts, :path, :text + add_column :communication_website_posts, :github_path, :text + add_column :communication_website_pages, :github_path, :text + end +end diff --git a/db/migrate/20211023153416_add_github_path_to_volumes_and_articles_and_researchers.rb b/db/migrate/20211023153416_add_github_path_to_volumes_and_articles_and_researchers.rb new file mode 100644 index 0000000000000000000000000000000000000000..9708358994a1317c59278439c59e6a79c201dd89 --- /dev/null +++ b/db/migrate/20211023153416_add_github_path_to_volumes_and_articles_and_researchers.rb @@ -0,0 +1,7 @@ +class AddGithubPathToVolumesAndArticlesAndResearchers < ActiveRecord::Migration[6.1] + def change + add_column :research_journal_articles, :github_path, :text + add_column :research_journal_volumes, :github_path, :text + add_column :research_researchers, :github_path, :text + end +end diff --git a/db/migrate/20211025062028_add_index_to_communication_website_imported_pages.rb b/db/migrate/20211025062028_add_index_to_communication_website_imported_pages.rb new file mode 100644 index 0000000000000000000000000000000000000000..fa7fd412a75df458b88b774f5d2cb0bac0464522 --- /dev/null +++ b/db/migrate/20211025062028_add_index_to_communication_website_imported_pages.rb @@ -0,0 +1,5 @@ +class AddIndexToCommunicationWebsiteImportedPages < ActiveRecord::Migration[6.1] + def change + add_index :communication_website_imported_pages, :identifier + end +end diff --git a/db/migrate/20211025102046_rename_text_for_website_pages.rb b/db/migrate/20211025102046_rename_text_for_website_pages.rb new file mode 100644 index 0000000000000000000000000000000000000000..0a6ad3ff6a05b263d575ec77cbcea2bc158e1071 --- /dev/null +++ b/db/migrate/20211025102046_rename_text_for_website_pages.rb @@ -0,0 +1,6 @@ +class RenameTextForWebsitePages < ActiveRecord::Migration[6.1] + def change + rename_column :communication_website_pages, :text, :old_text + + end +end diff --git a/db/migrate/20211025124617_remove_communication_website_media.rb b/db/migrate/20211025124617_remove_communication_website_media.rb new file mode 100644 index 0000000000000000000000000000000000000000..688ee3ce1d3ff8dacd83fe1adc7755d21a9738dc --- /dev/null +++ b/db/migrate/20211025124617_remove_communication_website_media.rb @@ -0,0 +1,6 @@ +class RemoveCommunicationWebsiteMedia < ActiveRecord::Migration[6.1] + def change + remove_column :communication_website_imported_media, :medium_id + drop_table :communication_website_media + end +end diff --git a/db/migrate/20211026035253_create_university_schools.rb b/db/migrate/20211026035253_create_university_schools.rb new file mode 100644 index 0000000000000000000000000000000000000000..020a3a4b76f49fc05bfe8611cd3b0787da91bb33 --- /dev/null +++ b/db/migrate/20211026035253_create_university_schools.rb @@ -0,0 +1,16 @@ +class CreateUniversitySchools < ActiveRecord::Migration[6.1] + def change + create_table :education_schools, id: :uuid do |t| + t.references :university, null: false, foreign_key: true, type: :uuid + t.string :name + t.string :address + t.string :zipcode + t.string :city + t.string :country + t.float :latitude + t.float :longitude + + t.timestamps + end + end +end diff --git a/db/migrate/20211026094556_add_variant_urls_to_communication_website_imported_media.rb b/db/migrate/20211026094556_add_variant_urls_to_communication_website_imported_media.rb new file mode 100644 index 0000000000000000000000000000000000000000..5e13899d60357156d11869ba09997f27348ae9e8 --- /dev/null +++ b/db/migrate/20211026094556_add_variant_urls_to_communication_website_imported_media.rb @@ -0,0 +1,5 @@ +class AddVariantUrlsToCommunicationWebsiteImportedMedia < ActiveRecord::Migration[6.1] + def change + add_column :communication_website_imported_media, :variant_urls, :text, array: true, default: [] + end +end diff --git a/db/migrate/20211026124139_create_communication_website_categories.rb b/db/migrate/20211026124139_create_communication_website_categories.rb new file mode 100644 index 0000000000000000000000000000000000000000..febee26b527912f20c22fb12a9e0eed423c1b343 --- /dev/null +++ b/db/migrate/20211026124139_create_communication_website_categories.rb @@ -0,0 +1,16 @@ +class CreateCommunicationWebsiteCategories < ActiveRecord::Migration[6.1] + def change + create_table :communication_website_categories, id: :uuid do |t| + t.references :university, null: false, foreign_key: true, type: :uuid + t.references :communication_website, + null: false, + foreign_key: { to_table: :communication_websites }, + type: :uuid, + index: { name: 'idx_communication_website_post_cats_on_communication_website_id' } + t.string :name + t.text :description + t.integer :position + t.timestamps + end + end +end diff --git a/db/migrate/20211026142142_create_join_table_website_posts_categories.rb b/db/migrate/20211026142142_create_join_table_website_posts_categories.rb new file mode 100644 index 0000000000000000000000000000000000000000..82d4186620080ad767fd8136dab13396d6b79498 --- /dev/null +++ b/db/migrate/20211026142142_create_join_table_website_posts_categories.rb @@ -0,0 +1,8 @@ +class CreateJoinTableWebsitePostsCategories < ActiveRecord::Migration[6.1] + def change + create_join_table :communication_website_posts, :communication_website_categories, column_options: {type: :uuid} do |t| + t.index [:communication_website_post_id, :communication_website_category_id], name: 'post_category' + t.index [:communication_website_category_id, :communication_website_post_id], name: 'category_post' + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 84ec856e3dcd325301e07961061964a644bbc816..3b75d9b9f394c2c1f2e1f9c1611697d822dbdb7b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_10_21_095157) do +ActiveRecord::Schema.define(version: 2021_10_26_142142) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" @@ -78,17 +78,36 @@ ActiveRecord::Schema.define(version: 2021_10_21_095157) do t.index ["criterion_id"], name: "index_administration_qualiopi_indicators_on_criterion_id" end + create_table "communication_website_categories", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.uuid "university_id", null: false + t.uuid "communication_website_id", null: false + t.string "name" + t.text "description" + t.integer "position" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.index ["communication_website_id"], name: "idx_communication_website_post_cats_on_communication_website_id" + t.index ["university_id"], name: "index_communication_website_categories_on_university_id" + end + + create_table "communication_website_categories_posts", id: false, force: :cascade do |t| + t.uuid "communication_website_post_id", null: false + t.uuid "communication_website_category_id", null: false + t.index ["communication_website_category_id", "communication_website_post_id"], name: "category_post" + t.index ["communication_website_post_id", "communication_website_category_id"], name: "post_category" + end + create_table "communication_website_imported_media", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.string "identifier" t.jsonb "data" t.text "file_url" - t.datetime "remote_created_at" - t.datetime "remote_updated_at" + t.datetime "created_at" + t.datetime "updated_at" t.uuid "university_id", null: false t.uuid "website_id", null: false - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false t.string "filename" + t.string "mime_type" + t.text "variant_urls", default: [], array: true t.index ["university_id"], name: "index_communication_website_imported_media_on_university_id" t.index ["website_id"], name: "index_communication_website_imported_media_on_website_id" end @@ -111,6 +130,7 @@ ActiveRecord::Schema.define(version: 2021_10_21_095157) do t.jsonb "data" t.uuid "featured_medium_id" t.index ["featured_medium_id"], name: "idx_communication_website_imported_pages_on_featured_medium_id" + t.index ["identifier"], name: "index_communication_website_imported_pages_on_identifier" t.index ["page_id"], name: "index_communication_website_imported_pages_on_page_id" t.index ["university_id"], name: "index_communication_website_imported_pages_on_university_id" t.index ["website_id"], name: "index_communication_website_imported_pages_on_website_id" @@ -162,8 +182,9 @@ ActiveRecord::Schema.define(version: 2021_10_21_095157) do t.uuid "about_id" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false - t.text "text" + t.text "old_text" t.boolean "published", default: false + t.text "github_path" t.index ["about_type", "about_id"], name: "index_communication_website_pages_on_about" t.index ["communication_website_id"], name: "index_communication_website_pages_on_communication_website_id" t.index ["parent_id"], name: "index_communication_website_pages_on_parent_id" @@ -181,6 +202,8 @@ ActiveRecord::Schema.define(version: 2021_10_21_095157) do t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false t.text "slug" + t.text "path" + t.text "github_path" t.index ["communication_website_id"], name: "index_communication_website_posts_on_communication_website_id" t.index ["university_id"], name: "index_communication_website_posts_on_university_id" end @@ -235,6 +258,20 @@ ActiveRecord::Schema.define(version: 2021_10_21_095157) do t.index ["university_id"], name: "index_education_programs_on_university_id" end + create_table "education_schools", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.uuid "university_id", null: false + t.string "name" + t.string "address" + t.string "zipcode" + t.string "city" + t.string "country" + t.float "latitude" + t.float "longitude" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.index ["university_id"], name: "index_education_schools_on_university_id" + end + create_table "languages", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.string "name" t.string "iso_code" @@ -255,6 +292,7 @@ ActiveRecord::Schema.define(version: 2021_10_21_095157) do t.text "abstract" t.text "references" t.text "keywords" + t.text "github_path" t.index ["research_journal_id"], name: "index_research_journal_articles_on_research_journal_id" t.index ["research_journal_volume_id"], name: "index_research_journal_articles_on_research_journal_volume_id" t.index ["university_id"], name: "index_research_journal_articles_on_university_id" @@ -278,6 +316,7 @@ ActiveRecord::Schema.define(version: 2021_10_21_095157) do t.datetime "updated_at", precision: 6, null: false t.text "description" t.text "keywords" + t.text "github_path" t.index ["research_journal_id"], name: "index_research_journal_volumes_on_research_journal_id" t.index ["university_id"], name: "index_research_journal_volumes_on_university_id" end @@ -301,6 +340,7 @@ ActiveRecord::Schema.define(version: 2021_10_21_095157) do t.uuid "user_id" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false + t.text "github_path" t.index ["user_id"], name: "index_research_researchers_on_user_id" end @@ -365,6 +405,8 @@ ActiveRecord::Schema.define(version: 2021_10_21_095157) do add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" add_foreign_key "administration_qualiopi_indicators", "administration_qualiopi_criterions", column: "criterion_id" + add_foreign_key "communication_website_categories", "communication_websites" + add_foreign_key "communication_website_categories", "universities" add_foreign_key "communication_website_imported_media", "communication_website_imported_websites", column: "website_id" add_foreign_key "communication_website_imported_media", "universities" add_foreign_key "communication_website_imported_pages", "communication_website_imported_media", column: "featured_medium_id" @@ -384,6 +426,7 @@ ActiveRecord::Schema.define(version: 2021_10_21_095157) do add_foreign_key "communication_website_posts", "universities" add_foreign_key "communication_websites", "universities" add_foreign_key "education_programs", "universities" + add_foreign_key "education_schools", "universities" add_foreign_key "research_journal_articles", "research_journal_volumes" add_foreign_key "research_journal_articles", "research_journals" add_foreign_key "research_journal_articles", "universities" diff --git a/db/seeds.rb b/db/seeds.rb index 1f63f50f71430073ac00c0abbc4b52ffd4ea56b0..6415a82700766664cda817f4c0b1f36a79e99ed9 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,4 +1,4 @@ -University.create name: 'Osuny', identifier: 'demo' +University.create name: 'Osuny', identifier: 'demo', sms_sender_name: 'Osuny' Language.where(name: 'French', iso_code: 'fr').first_or_create Language.where(name: 'English', iso_code: 'en').first_or_create diff --git a/docs/models.md b/docs/models.md index 9df28aff1c56747536c59644b03e5e7695cfab50..b34f9b807007166e172a03de55d7bbbd9d6468ce 100644 --- a/docs/models.md +++ b/docs/models.md @@ -17,6 +17,8 @@ - zipcode:string - city:string - country:string +- latitude:float +- longitude:float ## university/Campus diff --git a/docs/websites/export.md b/docs/websites/export.md new file mode 100644 index 0000000000000000000000000000000000000000..32f1173a4bc9f5b7bd88fa3963ee13cdd65759e4 --- /dev/null +++ b/docs/websites/export.md @@ -0,0 +1,3 @@ +# Export + +Comment exporter les attachments, qu'ils soient liés à un objet active storage, ou dans un champ action text ? \ No newline at end of file diff --git a/docs/websites/import.md b/docs/websites/import.md index 3dca015fe554a88cc1d724fe46545efbb79ecc12..2e2127707493b46bcc38a1cfc14ce2dd66c741cd 100644 --- a/docs/websites/import.md +++ b/docs/websites/import.md @@ -43,6 +43,35 @@ Etapes : 4. Import du contenu brut des pages importées 5. Analyse du contenu des pages importées et création / mise à jour des pages +## Import depuis WordPress + +### Media +1. On importe les media depuis l'API +2. On crée des objets en DB (Communication::Website::Imported::Medium) + +### Pages +1. On importe les pages depuis l'API +2. On crée des objets en DB (Communication::Website::Imported::Page) +3. Les objets importés créent ou mettent à jour les objets réels (Communication::Website::Page) + 3.1 sans écraser de modifs locales + 3.2 uniquement si l'import a bougé + 3.3 Le contenu de l'html est filtré + 3.3.1 enlever les balises problématiques + 3.3.2 supprimer les classes + 3.3.3 supprimer les ids + 3.3.4 décaler les titres si h1 + 3.4 la featured image est transformée en attachment + 3.5 si pas de featured image, la première image est enlevée du texte et devient featured + 3.6 les medias dans le texte html sont transformés en action text attachments + 3.6.1 lister les files dans le domaine + 3.6.2 identifier le media master correspondant (via data:jsonb) + 3.6.3 s'il n'existe pas, le créer (le cas se produit il ?) + 3.6.4 crée l'attachment + 3.6.5 on remplace le code du media par l'action text attachement + +### Posts +Idem pages + ## Exemples ### Condé diff --git a/lib/active_storage/service/scaleway_service.rb b/lib/active_storage/service/scaleway_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..917bfd032d09389a0fabc2ffbb27d5c58c76e64c --- /dev/null +++ b/lib/active_storage/service/scaleway_service.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# cf https://github.com/rails/rails/issues/41070 + +require 'active_storage/service/s3_service.rb' + +module ActiveStorage + class Service::ScalewayService < Service::S3Service + + def headers_for_direct_upload(key, content_type:, checksum:, filename: nil, disposition: nil, **) + content_disposition = content_disposition_with(type: disposition, filename: filename) if filename + + headers = public? ? { "x-amz-acl" => "public-read" } : {} + + headers.merge({ "Content-Type" => content_type, "Content-MD5" => checksum, "Content-Disposition" => content_disposition }) + end + end +end diff --git a/lib/tasks/app.rake b/lib/tasks/app.rake index 059f700376a0b0bcdc6c4d52522b6844d1801d27..c8ab3b1458c05fc56ca777726b2c94e9f48aa941 100644 --- a/lib/tasks/app.rake +++ b/lib/tasks/app.rake @@ -22,6 +22,12 @@ namespace :app do Communication::Website::Post.find_each { |post| post.update(text: post.old_text) } + Communication::Website::Page.find_each { |page| + page.update(text: page.old_text) + } + Communication::Website::Medium.find_each { |medium| + medium.send(:set_featured_images) + } end namespace :db do diff --git a/test/fixtures/action_text/rich_texts.yml b/test/fixtures/action_text/rich_texts.yml deleted file mode 100644 index 8b371ea604af5fba7cacf8f712528c1e12949959..0000000000000000000000000000000000000000 --- a/test/fixtures/action_text/rich_texts.yml +++ /dev/null @@ -1,4 +0,0 @@ -# one: -# record: name_of_fixture (ClassOfFixture) -# name: content -# body: <p>In a <i>million</i> stars!</p> diff --git a/test/fixtures/communication/website/imported/media.yml b/test/fixtures/communication/website/imported/media.yml deleted file mode 100644 index 3414bff4c3836dd4bf5fe3edf65305dce2ee33c5..0000000000000000000000000000000000000000 --- a/test/fixtures/communication/website/imported/media.yml +++ /dev/null @@ -1,44 +0,0 @@ -# == Schema Information -# -# Table name: communication_website_imported_media -# -# id :uuid not null, primary key -# data :jsonb -# file_url :text -# filename :string -# identifier :string -# remote_created_at :datetime -# remote_updated_at :datetime -# created_at :datetime not null -# updated_at :datetime not null -# university_id :uuid not null -# website_id :uuid not null -# -# Indexes -# -# index_communication_website_imported_media_on_university_id (university_id) -# index_communication_website_imported_media_on_website_id (website_id) -# -# Foreign Keys -# -# fk_rails_... (university_id => universities.id) -# fk_rails_... (website_id => communication_website_imported_websites.id) -# - -one: - university: one - identifier: MyString - website: one - data: - remote_created_at: 2021-10-19 11:18:47 - remote_updated_at: 2021-10-19 11:18:47 - file_url: MyText - -two: - university: two - identifier: MyString - website: two - data: - remote_created_at: 2021-10-19 11:18:47 - remote_updated_at: 2021-10-19 11:18:47 - file_url: MyText diff --git a/test/models/communication/website/imported/medium_test.rb b/test/models/communication/website/imported/medium_test.rb deleted file mode 100644 index c084dcee90ecb6e7e80e343b3a0ed8befaae13ac..0000000000000000000000000000000000000000 --- a/test/models/communication/website/imported/medium_test.rb +++ /dev/null @@ -1,33 +0,0 @@ -# == Schema Information -# -# Table name: communication_website_imported_media -# -# id :uuid not null, primary key -# data :jsonb -# file_url :text -# filename :string -# identifier :string -# remote_created_at :datetime -# remote_updated_at :datetime -# created_at :datetime not null -# updated_at :datetime not null -# university_id :uuid not null -# website_id :uuid not null -# -# Indexes -# -# index_communication_website_imported_media_on_university_id (university_id) -# index_communication_website_imported_media_on_website_id (website_id) -# -# Foreign Keys -# -# fk_rails_... (university_id => universities.id) -# fk_rails_... (website_id => communication_website_imported_websites.id) -# -require "test_helper" - -class Communication::Website::Imported::MediumTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end -end diff --git a/test/models/wordpress_test.rb b/test/models/wordpress_test.rb index 8cbab5c3517badcc7a04719ecd173792fde23897..8ab63b607b573857e7b79040e48b339d81c14740 100644 --- a/test/models/wordpress_test.rb +++ b/test/models/wordpress_test.rb @@ -2,53 +2,66 @@ require "test_helper" class WordpressTest < ActiveSupport::TestCase test "convert apostroph" do - assert_equal Wordpress.clean('Ouverture du CRM pendant les vacances d’Avril'), - 'Ouverture du CRM pendant les vacances d’Avril' + 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 Wordpress.clean('Le CRM fait le tri dans ses collections … et vous propose une vente de livres'), - 'Le CRM fait le tri dans ses collections … et vous propose une vente de livres' + 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 Wordpress.clean('Conférence Joëlle Zask : “Ecologie de la participation”'), - 'Conférence Joëlle Zask : “Ecologie de la participationâ€' + 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 Wordpress.clean('<h1>B.U.T. Métiers du multimédia et de l’internet</h1>'), - '<h2>B.U.T. Métiers du multimédia et de l’internet</h2>' + 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 Wordpress.clean('<h2>B.U.T. Métiers du multimédia et de l’internet</h2>'), - '<h2>B.U.T. Métiers du multimédia et de l’internet</h2>' + 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 Wordpress.clean('<h1>Bachelor Universitaire de Technologie</h1><h2>B.U.T. Métiers du multimédia et de l’internet</h2>'), - '<h2>Bachelor Universitaire de Technologie</h2><h3>B.U.T. Métiers du multimédia et de l’internet</h3>' + 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 Wordpress.clean('TRAVAILLER DEMAIN, Débat – le 10 mai à 18h30'), - 'TRAVAILLER DEMAIN, Débat – le 10 mai à 18h30' + 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 Wordpress.clean('<h2 class="titre-diplome">→ Qu’est-ce que le B.U.T. ?</h2>'), - '<h2>→ Qu’est-ce que le B.U.T. ?</h2>' + 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 Wordpress.clean('<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>'), - '<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>' + 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 "authorize iframes" do + 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/system/university/schools_test.rb b/test/system/university/schools_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..3055e119d1ed67d5ef2008ac5d96f69da11d84a9 --- /dev/null +++ b/test/system/university/schools_test.rb @@ -0,0 +1,57 @@ +require "application_system_test_case" + +class University::SchoolsTest < ApplicationSystemTestCase + setup do + @university_school = university_schools(:one) + end + + test "visiting the index" do + visit university_schools_url + assert_selector "h1", text: "University/Schools" + end + + test "creating a School" do + visit university_schools_url + click_on "New University/School" + + fill_in "Address", with: @university_school.address + fill_in "City", with: @university_school.city + fill_in "Country", with: @university_school.country + fill_in "Latitude", with: @university_school.latitude + fill_in "Longitude", with: @university_school.longitude + fill_in "Name", with: @university_school.name + fill_in "University", with: @university_school.university_id + fill_in "Zipcode", with: @university_school.zipcode + click_on "Create School" + + assert_text "School was successfully created" + click_on "Back" + end + + test "updating a School" do + visit university_schools_url + click_on "Edit", match: :first + + fill_in "Address", with: @university_school.address + fill_in "City", with: @university_school.city + fill_in "Country", with: @university_school.country + fill_in "Latitude", with: @university_school.latitude + fill_in "Longitude", with: @university_school.longitude + fill_in "Name", with: @university_school.name + fill_in "University", with: @university_school.university_id + fill_in "Zipcode", with: @university_school.zipcode + click_on "Update School" + + assert_text "School was successfully updated" + click_on "Back" + end + + test "destroying a School" do + visit university_schools_url + page.accept_confirm do + click_on "Destroy", match: :first + end + + assert_text "School was successfully destroyed" + end +end