diff --git a/Gemfile b/Gemfile index 4a42a43119ec930d1f161e54c5f2af473dad0a8e..c9678d58eb34c8551601e31f5e9d6b9b6a02d2ff 100644 --- a/Gemfile +++ b/Gemfile @@ -4,60 +4,58 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.7.5' # Infrastructure +gem 'angularjs-rails' gem 'aws-sdk-s3' -gem 'bugsnag' -gem 'gitlab' -gem 'image_processing' -gem 'mini_magick' -gem 'octokit' -gem 'pg', '~> 1.1' -gem 'puma' - -# Back-end -gem 'cancancan' gem 'bootsnap', '>= 1.4.4', require: false -gem 'curation'#, path: '../../arnaudlevy/curation' -gem 'delayed_job_active_record' -gem 'delayed_job_web' -gem 'faceted_search'#, path: '../faceted_search' -gem 'has_scope', '~> 0.8.0' -gem 'hash_dot' -gem 'rails', '~> 6.1' -gem 'rails-i18n' -gem 'sanitize' -gem 'sib-api-v3-sdk' -gem 'two_factor_authentication', git: 'https://github.com/noesya/two_factor_authentication.git' -# gem 'two_factor_authentication', path: '../two_factor_authentication' - -# Front-end -gem 'angularjs-rails' gem 'bootstrap' gem 'bootstrap5-kaminari-views' gem 'breadcrumbs_on_rails' +gem 'bugsnag' +gem 'cancancan' gem 'cocoon', '~> 1.2' gem 'country_select' +gem 'curation'#, path: '../../arnaudlevy/curation' +gem 'delayed_job_active_record' +gem 'delayed_job_web' gem 'devise' gem 'devise-i18n' gem 'enum_help' +gem 'faceted_search'#, path: '../faceted_search' gem 'front_matter_parser' gem 'gdpr' +gem 'gitlab' +gem 'has_scope', '~> 0.8.0' +gem 'hash_dot' +gem 'image_processing' gem 'jbuilder' gem 'jquery-rails' gem 'kamifusen'#, path: '../kamifusen' gem 'kaminari' +gem 'mini_magick' +gem 'octokit' +gem 'omniauth-saml' +gem 'pg', '~> 1.1' +gem 'puma' +gem 'rails', '~> 6.1' +gem 'rails-i18n' +gem 'sanitize' gem 'sassc-rails' +gem 'sib-api-v3-sdk' +gem 'simple-navigation' gem 'simple_form' gem 'simple_form_bs5_file_input'#, path: '../simple_form_bs5_file_input' gem 'simple_form_password_with_hints'#, path: '../simple_form_password_with_hints' -gem 'simple-navigation' gem 'summernote-rails', git: 'https://github.com/noesya/summernote-rails.git', branch: 'activestorage' # gem 'summernote-rails', path: '../summernote-rails' +gem 'two_factor_authentication', git: 'https://github.com/noesya/two_factor_authentication.git' +# gem 'two_factor_authentication', path: '../two_factor_authentication' + group :development, :test do gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] gem 'figaro' - gem 'webmock' gem 'vcr' + gem 'webmock' end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 106b97d221040a40d7d50ad3ec093bc5b3b43faa..7a8d96bb71c06f190cf877abac06ad6408937b8b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -228,6 +228,7 @@ GEM activesupport (>= 5.2) hash_dot (2.5.0) hashdiff (1.0.1) + hashie (5.0.0) http-cookie (1.0.4) domain_name (~> 0.5) httparty (0.20.0) @@ -307,6 +308,12 @@ GEM octokit (4.22.0) faraday (>= 0.9) sawyer (~> 0.8.0, >= 0.5.3) + omniauth (1.9.1) + hashie (>= 3.4.6) + rack (>= 1.6.2, < 3) + omniauth-saml (1.10.3) + omniauth (~> 1.3, >= 1.3.2) + ruby-saml (~> 1.9) orm_adapter (0.5.0) pg (1.3.5) popper_js (2.9.3) @@ -361,6 +368,9 @@ GEM railties (>= 5.0) rexml (3.2.5) rotp (6.2.0) + ruby-saml (1.13.0) + nokogiri (>= 1.10.5) + rexml ruby-vips (2.1.4) ffi (~> 1.12) ruby2_keywords (0.0.5) @@ -489,6 +499,7 @@ DEPENDENCIES listen (~> 3.3) mini_magick octokit + omniauth-saml pg (~> 1.1) puma rack-mini-profiler (~> 2.0) diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js index fd05f8daf796de400418bcf938fa3f32b819e3f3..43e04d1b6d9290f7cb778462f5841c181a75b45a 100644 --- a/app/assets/javascripts/admin.js +++ b/app/assets/javascripts/admin.js @@ -17,5 +17,6 @@ //= require_tree ./admin/commons //= require_tree ./admin/plugins //= require ./admin/communication/init +//= require ./admin/university/init window.osuny = {}; diff --git a/app/assets/javascripts/admin/commons/batch-selectable.js b/app/assets/javascripts/admin/commons/batch-selectable.js index 09f9f4f6c896865bf5639443f4c6acc33a2d39a3..24d954826cc31c9de41dc7a56129be4a6aa656b9 100644 --- a/app/assets/javascripts/admin/commons/batch-selectable.js +++ b/app/assets/javascripts/admin/commons/batch-selectable.js @@ -4,25 +4,46 @@ window.osuny.BatchSelectable = function BatchSelectable (element) { this.element = element; this.selectAllInput = this.element.querySelector('[data-batch-selectable-role="select-all"]'); this.selectSingleInputs = this.element.querySelectorAll('[data-batch-selectable-role="select-single"]'); + this.actionsContainer = this.element.querySelector('[data-batch-selectable-role="actions-container"]'); this.initEvents(); + this.toggleActionsContainer(); }; window.osuny.BatchSelectable.prototype.initEvents = function () { 'use strict'; - if (this.selectAllInput === null) { - return; + var i; + if (this.selectAllInput !== null) { + this.selectAllInput.addEventListener('change', this.toggleSingleInputs.bind(this)); + } + if (this.actionsContainer !== null) { + for (i = 0; i < this.selectSingleInputs.length; i += 1) { + this.selectSingleInputs[i].addEventListener('change', this.toggleActionsContainer.bind(this)); + } } - this.selectAllInput.addEventListener('change', function () { - this.toggleSingleInputs(this.selectAllInput.checked); - }.bind(this)); }; -window.osuny.BatchSelectable.prototype.toggleSingleInputs = function (checked) { +window.osuny.BatchSelectable.prototype.toggleSingleInputs = function (event) { 'use strict'; - var i; + var checked = event.currentTarget.checked, + i; for (i = 0; i < this.selectSingleInputs.length; i += 1) { this.selectSingleInputs[i].checked = checked; } + if (this.actionsContainer !== null) { + this.toggleActionsContainer(); + } +}; + +window.osuny.BatchSelectable.prototype.toggleActionsContainer = function () { + 'use strict'; + var i; + for (i = 0; i < this.selectSingleInputs.length; i += 1) { + if (this.selectSingleInputs[i].checked) { + this.actionsContainer.classList.remove('d-none'); + return; + } + } + this.actionsContainer.classList.add('d-none'); }; window.addEventListener('DOMContentLoaded', function () { diff --git a/app/assets/javascripts/admin/university/edit.js b/app/assets/javascripts/admin/university/edit.js new file mode 100644 index 0000000000000000000000000000000000000000..9799b2a344ed7d58e4e802377eb1091bc79ba1fe --- /dev/null +++ b/app/assets/javascripts/admin/university/edit.js @@ -0,0 +1,36 @@ +window.osuny.university.edit = { + init: function () { + 'use strict'; + this.hasSsoInput = document.querySelector('input[type="checkbox"][name="university[has_sso]"]'); + this.hasSsoInput.addEventListener('change', this.onHasSsoChange.bind(this)); + this.ssoFields = document.getElementById('sso-inputs'); + this.onHasSsoChange(); + }, + + onHasSsoChange: function () { + 'use strict'; + var value = this.hasSsoInput.checked; + if (value) { + this.ssoFields.classList.remove('d-none'); + } else { + this.ssoFields.classList.add('d-none'); + } + }, + + invoke: function () { + 'use strict'; + return { + init: this.init.bind(this) + }; + } +}.invoke(); + +window.addEventListener('DOMContentLoaded', function () { + 'use strict'; + if (document.body.classList.contains('universities-new') + || document.body.classList.contains('universities-create') + || document.body.classList.contains('universities-edit') + || document.body.classList.contains('universities-update')) { + window.osuny.university.edit.init(); + } +}); diff --git a/app/assets/javascripts/admin/university/init.js b/app/assets/javascripts/admin/university/init.js new file mode 100644 index 0000000000000000000000000000000000000000..1c33bd9eb5e950e7bc13965380783a4a7a10b073 --- /dev/null +++ b/app/assets/javascripts/admin/university/init.js @@ -0,0 +1,4 @@ +//= require_self +//= require ./edit + +window.osuny.university = {}; diff --git a/app/controllers/server/universities_controller.rb b/app/controllers/server/universities_controller.rb index dd43e821ac5100a5926c4d48dba949fee9a7b2e4..db42c8fb802eb74ae03e190555a1b4bc74d9c2df 100644 --- a/app/controllers/server/universities_controller.rb +++ b/app/controllers/server/universities_controller.rb @@ -59,6 +59,10 @@ class Server::UniversitiesController < Server::ApplicationController end def university_params - params.require(:university).permit(:name, :address, :zipcode, :city, :country, :private, :identifier, :logo, :logo_delete, :sms_sender_name, :invoice_date, :invoice_amount) + params.require(:university).permit(:name, + :address, :zipcode, :city, :country, + :private, :identifier, :logo, :logo_delete, :sms_sender_name, + :has_sso, :sso_target_url, :sso_cert, :sso_name_identifier_format, + :invoice_date, :invoice_amount) end end diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..be8f1f99dfc7cd5b53c57a3c380f90d5ab0fdea8 --- /dev/null +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -0,0 +1,48 @@ +class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController + # include Users::AddBrandToRequestParams + # include I18nHelper + + protect_from_forgery except: :saml + before_action :redirect_unless_university_has_sso + skip_before_action :verify_authenticity_token, only: :saml + + def saml + response = OneLogin::RubySaml::Response.new(params[:SAMLResponse]) + ############################################################################### + # response.name_id : "pierreandre.boissinot@noesya.coop" + # response.attributes.all : {"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"=>["Pierre-André"], "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"=>["Boissinot"], "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"=>["paboissinot@lespoupees.paris"], "b2bylon_role"=>["superadmin"], "language"=>["fr"], "interests"=>["interest_1", "interest_3"]} + ############################################################################### + puts response.name_id + puts response.attributes.to_s + puts response.to_s + manage_user(response.attributes.all) + end + + def saml_setup + # SAML config is stored in current brand + request.env['omniauth.strategy'].options[:issuer] = "#{user_saml_omniauth_authorize_url}/metadata" + request.env['omniauth.strategy'].options[:idp_sso_target_url] = current_university.sso_target_url + request.env['omniauth.strategy'].options[:idp_cert] = current_university.sso_cert + request.env['omniauth.strategy'].options[:name_identifier_format] = current_university.sso_name_identifier_format + + render plain: "Omniauth SAML setup phase.", status: 404 + end + + private + + def manage_user(user_infos) + @user = User.from_omniauth(current_university, user_infos) + + if @user&.persisted? + @user.remember_me = true + sign_in_and_redirect @user, event: :authentication + else + flash[:notice] = tt('devise.omniauth_callbacks.failure') + redirect_to new_user_session_url + end + end + + def redirect_unless_university_has_sso + redirect_to root_path and return unless current_university.has_sso? + end +end diff --git a/app/models/university/with_sso.rb b/app/models/university/with_sso.rb index 34f6afb8bccf895f1ab689f5b99552227bb37a5c..08dec1a53fc213d78f7a0515ba35688a90cd5e20 100644 --- a/app/models/university/with_sso.rb +++ b/app/models/university/with_sso.rb @@ -2,7 +2,10 @@ module University::WithSso extend ActiveSupport::Concern included do - enum sso_provider: { saml: 0, oauth2: 10 }, _prefix: :with_sso_via + enum sso_provider: { saml: 0 }, _prefix: :with_sso_via + + validates :sso_cert, :sso_name_identifier_format, :sso_target_url, presence: true, if: :has_sso? + end # Setter to serialize data as JSON diff --git a/app/models/user.rb b/app/models/user.rb index 7b81885d3f973407cb183d57143322436d968872..97c8b7767781e08d02385cc1a8f3b73b6c7b82e7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -56,6 +56,7 @@ class User < ApplicationRecord has_one_attached_deletable :picture # In this order, "resize avatar" callback will be fired after the others. include WithUniversity include WithAuthentication + include WithOmniauth include WithPerson include WithRoles include WithSyncBetweenUniversities diff --git a/app/models/user/with_authentication.rb b/app/models/user/with_authentication.rb index 933ba2c8f2b7d7b67672d9da4133ceb74008266a..54de19f4f987d0ac67f895f2ba2dd4ba7ef3c8e7 100644 --- a/app/models/user/with_authentication.rb +++ b/app/models/user/with_authentication.rb @@ -3,7 +3,7 @@ module User::WithAuthentication included do devise :database_authenticatable, :registerable, :recoverable, :rememberable, - :timeoutable, :confirmable, :trackable, :lockable, :two_factor_authenticatable + :timeoutable, :confirmable, :trackable, :lockable, :two_factor_authenticatable, :omniauthable, omniauth_providers: [:saml] # note : i do not use :validatable because of the non-uniqueness of the email. :validatable is replaced by the validation sequences below diff --git a/app/models/user/with_omniauth.rb b/app/models/user/with_omniauth.rb new file mode 100644 index 0000000000000000000000000000000000000000..1a4261360df7a08bb88741d57d59ef76c388db77 --- /dev/null +++ b/app/models/user/with_omniauth.rb @@ -0,0 +1,18 @@ +module User::WithOmniauth + extend ActiveSupport::Concern + + included do + + def self.from_omniauth(university, attributes) + mapping = university.sso_mapping + email = 'pierreandre.boissinot@noesya.coop' + + user = User.where(university: university, email: email).first_or_create do |u| + u.password = "#{Devise.friendly_token[0,20]}!" # meets password complexity requirements + end + user + end + + end + +end diff --git a/app/views/admin/communication/website/posts/_list.html.erb b/app/views/admin/communication/website/posts/_list.html.erb index 5fbf2c99b59aab4d456a1f2279dbb01bb8ae0457..76f5e5861d7dccd73629c6d3e4073ee5790b4a45 100644 --- a/app/views/admin/communication/website/posts/_list.html.erb +++ b/app/views/admin/communication/website/posts/_list.html.erb @@ -3,7 +3,10 @@ hide_category |= false selectable |= false %> -<table class="<%= table_classes %>" <%= "data-batch-selectable" if selectable %>> +<% if selectable %> +<input type="hidden" name="ids[]" value=""> +<% end %> +<table class="<%= table_classes %>"> <thead> <tr> <% if selectable %> diff --git a/app/views/admin/communication/website/posts/index.html.erb b/app/views/admin/communication/website/posts/index.html.erb index 2c19431f83b214fc60b6916c97a4e2b9ebdb41d9..5688ab1246448d9cb21c061ef28b70d5c14869bb 100644 --- a/app/views/admin/communication/website/posts/index.html.erb +++ b/app/views/admin/communication/website/posts/index.html.erb @@ -3,28 +3,29 @@ <%= render 'admin/communication/websites/sidebar' do %> <%= render 'filters', current_path: admin_communication_website_posts_path, filters: @filters if @filters.any? %> - <div class="card"> + <div class="card" data-batch-selectable> <%= form_tag publish_admin_communication_website_posts_path do %> - <input type="hidden" name="ids[]" value=""> <%= render 'admin/communication/website/posts/list', posts: @posts, selectable: true %> <div class="card-footer"> <% if @posts.total_pages > 1 %> - <div class="float-end"> + <div class="float-end mb-3"> <%= paginate @posts, theme: 'bootstrap-5' %> </div> <% end %> - <div class="row align-items-center"> - <div class="col-auto"> - Modifier la sélection - </div> - <div class="col-auto"> - <select name="published" class="form-select"> - <option value="false">Non publiée</option> - <option value="true">Publiée</option> - </select> - </div> - <div class="col-auto"> - <input type="submit" value="Enregistrer" class="btn btn-primary"> + <div data-batch-selectable-role="actions-container"> + <div class="d-flex align-items-center"> + <div class="col-auto me-3"> + <%= t('batch_selectable.title') %> + </div> + <div class="col-auto me-3"> + <select name="published" class="form-select"> + <option value="false"><%= t('communication.website.posts.unpublished') %></option> + <option value="true"><%= t('communication.website.posts.published') %></option> + </select> + </div> + <div class="col-auto me-3"> + <%= submit_tag t("save"), class: "btn btn-primary" %> + </div> </div> </div> </div> diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index 691715882917faff3e85378614de7146a79cae07..f22889e4730e48e6ae0633f5f47641eb51bf69c3 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -10,40 +10,49 @@ </div> <div class="col-md-6"> <h2 class="mb-4"><%= t('login.already_registered') %></h2> - <%= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> - <div class="form-inputs"> - <%= f.input :email, - required: false, - autofocus: true, - input_html: { autocomplete: "email" } %> - <div class="mb-3 password optional user_password password_with_hints"> - <%= f.input :password, - as: :password_with_hints, - allow_password_uncloaking: true, + <% if current_university.has_sso? %> + <p><%= link_to t('login.sign_in_with_sso'), omniauth_authorize_path(resource_name, current_university.sso_provider), class: 'btn btn-primary' %></p> + <p><%= t('login.or') %></p> + <a href="#collapseLoginForm" class="btn btn-primary mb-3" data-bs-toggle="collapse"><%= t('login.sign_in_with_credentials') %></a> + <% end %> + + <div class="<%= 'collapse' if current_university.has_sso? %> <%= 'show' unless alert.blank? %>" id="collapseLoginForm"> + + <%= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> + <div class="form-inputs"> + <%= f.input :email, required: false, - wrapper: false, - input_html: { autocomplete: "current-password" } %> - <small> - <%= link_to t("devise.passwords.new.forgot_your_password"), new_password_path(resource_name) %> - </small> + autofocus: true, + input_html: { autocomplete: "email" } %> + <div class="mb-3 password optional user_password password_with_hints"> + <%= f.input :password, + as: :password_with_hints, + allow_password_uncloaking: true, + required: false, + wrapper: false, + input_html: { autocomplete: "current-password" } %> + <small> + <%= link_to t("devise.passwords.new.forgot_your_password"), new_password_path(resource_name) %> + </small> + </div> + <%= f.input :remember_me, as: :boolean if devise_mapping.rememberable? %> </div> - <%= f.input :remember_me, as: :boolean if devise_mapping.rememberable? %> - </div> - <div class="form-actions"> - <%= f.button :submit, t(".sign_in"), class: 'btn btn-primary' %> + <div class="form-actions"> + <%= f.button :submit, t(".sign_in"), class: 'btn btn-primary' %> - <div class="mt-3"> + </div> + <% end %> + </div> + <div class="mt-3"> + <% if devise_mapping.confirmable? %> + <%= link_to t('devise.shared.links.didn_t_receive_confirmation_instructions'), new_confirmation_path(resource_name) %><br /> + <% end %> - <% if devise_mapping.confirmable? %> - <%= link_to t('devise.shared.links.didn_t_receive_confirmation_instructions'), new_confirmation_path(resource_name) %><br /> - <% end %> + <% if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) %> + <%= link_to t('devise.shared.links.didn_t_receive_unlock_instructions'), new_unlock_path(resource_name) %><br /> + <% end %> + </div> - <% if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) %> - <%= link_to t('devise.shared.links.didn_t_receive_unlock_instructions'), new_unlock_path(resource_name) %><br /> - <% end %> - </div> - </div> - <% end %> </div> </div> diff --git a/app/views/server/layouts/application.html.erb b/app/views/server/layouts/application.html.erb index b3f5fb58c8f5e9ad6bb4448f3dd2b27ac456056d..f03b783ffba7661f48a548598cff361b78abdaf9 100644 --- a/app/views/server/layouts/application.html.erb +++ b/app/views/server/layouts/application.html.erb @@ -11,7 +11,7 @@ <%= stylesheet_link_tag 'admin', media: 'all' %> <%= favicon_link_tag 'favicon.png' %> </head> - <body data-theme="default" data-layout="fluid" data-sidebar-position="left" data-sidebar-behavior="sticky"> + <body class="<%= body_classes %>" data-theme="default" data-layout="fluid" data-sidebar-position="left" data-sidebar-behavior="sticky"> <div class="toasts-container" style="position: fixed; top: 20px; right: 20px; z-index: 100000;"> <% unless notice.nil? %> <div class="js-notyf-notice d-none"> diff --git a/app/views/server/universities/_form.html.erb b/app/views/server/universities/_form.html.erb index 4fbcd19ddbd32ab09c2c29d509ee7c74df4f6015..c3e2a4743b9860e325cb2746712564c7c1375b42 100644 --- a/app/views/server/universities/_form.html.erb +++ b/app/views/server/universities/_form.html.erb @@ -27,6 +27,20 @@ direct_upload: true %> </div> </div> + + <div class="row"> + <div class="col-md-6"> + <h3 class="mt-5"><%= t('university.sso') %></h3> + <%= f.input :has_sso %> + <div id="sso-inputs"> + <%= f.input :sso_target_url, required: true %> + <%= f.input :sso_cert, required: true %> + <%= f.input :sso_name_identifier_format, required: true %> + + <%#= render 'sso_mapping', brand: brand %> + </div> + </div> + <h3 class="mt-5"><%= t('university.invoice_informations') %></h3> <div class="row"> <div class="col-md-4"> diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 43596a34d3e4d589b1abaf5020bf94558c1da37d..a410372234a5f728412e3ac50d9693a71c03124b 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -272,6 +272,7 @@ Devise.setup do |config| # Add a new OmniAuth provider. Check the wiki for more information on setting # up on your models and hooks. # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo' + config.omniauth :saml, setup: true # ==> Warden configuration # If you want to use other strategies, that are not supported by Devise, or diff --git a/config/locales/communication/en.yml b/config/locales/communication/en.yml index 39a6494acc73829e34e1a92b6d99e77c52ba672f..22b74a1f11458031f17f16d7a46bd3f5a2175128 100644 --- a/config/locales/communication/en.yml +++ b/config/locales/communication/en.yml @@ -113,7 +113,7 @@ en: featured_image: Featured image featured_image_alt: Alt text pinned: Pinned - published: Published + published: Published? published_at: Publication date slug: Slug text: Text @@ -303,6 +303,9 @@ en: title: Educational team posts: new_curation: New curation + published: Published + successful_batch_update: Posts have been updated succesfully + unpublished: Unpublished see_all: See the full list (%{number} elements) enums: communication: diff --git a/config/locales/communication/fr.yml b/config/locales/communication/fr.yml index ae6edc47f0f39fd380c8397264f9d0da3849dc0f..0fce32c9e07ef3652c8a2a1f5ccccd8ae127f402 100644 --- a/config/locales/communication/fr.yml +++ b/config/locales/communication/fr.yml @@ -113,7 +113,7 @@ fr: featured_image: Image à la une featured_image_alt: Texte alternatif pinned: Mis en avant - published: Publié + published: Publié ? published_at: Date de publication slug: Slug text: Texte @@ -305,7 +305,9 @@ fr: title: Équipe pédagogique posts: new_curation: Nouvelle curation + published: Publiée successful_batch_update: Les actualités ont bien été mises à jour + unpublished: Non publiée see_all: Voir la liste complète (%{number} éléments) enums: communication: diff --git a/config/locales/en.yml b/config/locales/en.yml index 6d9128aca701db5f2b89b871a73482cc2116ec53..e150188d2bba3cd947c520368fc7cef9d5c8281b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -56,6 +56,8 @@ en: not_locked_html: '<i>%{model}</i> was not locked.' successfully_unlocked_html: "<i>%{model}</i> was successfully unlocked." will_be_published_html: "<i>%{model}</i> will soon be published." + batch_selectable: + title: Edit the selection content: Content cookies_consent_choice: Cookies consent choice cookies_policy: Cookies policy @@ -119,6 +121,9 @@ en: already_registered: Already registered? not_registered_yet: Not registered yet? not_registered_yet_details: Register if you have no account yet. + or: or + sign_in_with_credentials: Sign in with credentials + sign_in_with_sso: Sign in through SSO subtitle: Sign in to your account to continue menu: admin: Admin diff --git a/config/locales/fr.yml b/config/locales/fr.yml index ce749793162a5b13cb214707753688e744513c1f..b04ef9f9d665aa4b5e3397ca89fe670bb5b04fcd 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -56,6 +56,8 @@ fr: not_locked_html: "<i>%{model}</i> n'était pas verrouillé(e)." successfully_unlocked_html: "<i>%{model}</i> a bien été déverrouillé(e)." will_be_published_html: "<i>%{model}</i> va bientôt être publié(e)." + batch_selectable: + title: Modifier la sélection content: Contenu cookies_consent_choice: Choix en matière de cookies cookies_policy: Politique de cookies @@ -119,6 +121,9 @@ fr: already_registered: Déjà inscrit ? not_registered_yet: Pas encore inscrit ? not_registered_yet_details: Inscrivez-vous si vous n'avez pas encore de compte. + or: ou bien + sign_in_with_credentials: Se connecter avec ses identifiants + sign_in_with_sso: Se connecter en SSO subtitle: Vous devez être authentifié pour continuer menu: admin: Admin diff --git a/config/locales/university/en.yml b/config/locales/university/en.yml index dcd43222b31c92c6049f9ab1ea77c12c41bc0948..63a83a4e13d8231a460c218b51e5f82d13f3b9b9 100644 --- a/config/locales/university/en.yml +++ b/config/locales/university/en.yml @@ -5,6 +5,7 @@ en: address: Address city: City country: Country + has_sso: Has SSO? identifier: Identifier invoice_amount: Invoice amount invoice_date: Invoice date @@ -14,6 +15,9 @@ en: public: Public public_or_private: Public/private sms_sender_name: SMS sender name + sso_cert: Certificate + sso_name_identifier_format: Name Identifier Format + sso_target_url: Target URL url: URL zipcode: Zipcode university/person: @@ -125,3 +129,4 @@ en: person: administrator_roles: Administrator roles taught_programs: Taught programs + sso: SSO diff --git a/config/locales/university/fr.yml b/config/locales/university/fr.yml index a401225ae0a8c5cf267e499a01385dd8b14804fe..f263aead1db38c3fbd9063474e72394808a2a9e9 100644 --- a/config/locales/university/fr.yml +++ b/config/locales/university/fr.yml @@ -5,6 +5,7 @@ fr: address: Adresse city: Ville country: Pays + has_sso: A un SSO ? identifier: Identifiant invoice_amount: Montant de facturation invoice_date: Date de facturation @@ -14,6 +15,9 @@ fr: public: Public public_or_private: Public/privé sms_sender_name: Nom de l'expéditeur SMS + sso_cert: Certificat + sso_name_identifier_format: Name Identifier Format + sso_target_url: URL cible url: 'URL' zipcode: Code postal university/person: @@ -125,3 +129,4 @@ fr: person: administrator_roles: Rôles administratifs taught_programs: Formations enseignées + sso: SSO diff --git a/config/routes.rb b/config/routes.rb index 5f10a141b009ccfa85992cf44ce2902944570d54..5e9f0af119a7ec261e2d338a89ae71c11d8b3d96 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -5,12 +5,17 @@ Rails.application.routes.draw do devise_for :users, controllers: { confirmations: 'users/confirmations', + omniauth_callbacks: 'users/omniauth_callbacks', passwords: 'users/passwords', registrations: 'users/registrations', sessions: 'users/sessions', unlocks: 'users/unlocks' } + devise_scope :user do + match '/users/auth/saml/setup' => 'users/omniauth_callbacks#saml_setup', via: [:get, :post] + end + namespace :admin do resources :users do patch 'unlock' => 'users#unlock', on: :member