From 65749ede9762a3650f4f5b7eca76c1b8cc51865f Mon Sep 17 00:00:00 2001
From: pabois <pierreandre.boissinot@noesya.coop>
Date: Tue, 12 Oct 2021 18:17:17 +0200
Subject: [PATCH] wip

---
 Gemfile                                       |  1 +
 Gemfile.lock                                  |  9 +++++-
 app/assets/javascripts/admin.js               |  2 ++
 app/assets/javascripts/admin/notyf.js         | 31 +++++++++++++++++++
 app/assets/javascripts/admin/user_menu.js     |  6 ++++
 app/assets/stylesheets/admin.sass             |  3 +-
 .../stylesheets/application/layout.sass       |  5 +++
 .../users/registrations_controller.rb         | 22 +++++++++++--
 app/models/user.rb                            |  2 +-
 app/views/admin/application/_top.html.erb     | 10 ++++--
 app/views/admin/layouts/application.html.erb  | 12 +++++++
 app/views/devise/registrations/edit.html.erb  | 13 ++++----
 app/views/devise/registrations/new.html.erb   | 16 +++++++++-
 app/views/layouts/application.html.erb        |  1 +
 app/views/layouts/devise.html.erb             |  4 +--
 config/locales/en.yml                         |  2 ++
 config/locales/fr.yml                         |  2 ++
 package.json                                  |  5 +++
 yarn.lock                                     |  4 +++
 19 files changed, 132 insertions(+), 18 deletions(-)
 create mode 100644 app/assets/javascripts/admin/notyf.js
 create mode 100644 app/assets/javascripts/admin/user_menu.js
 create mode 100644 package.json

diff --git a/Gemfile b/Gemfile
index b9c56883d..e70f6e4b9 100644
--- a/Gemfile
+++ b/Gemfile
@@ -23,6 +23,7 @@ gem 'i18n_data'
 gem 'cancancan'
 gem 'simple_form'
 gem 'simple_form_password_with_hints'
+gem 'simple_form_image_fields', path: '../simple_form_image_fields'
 gem 'enum_help'
 gem 'enum-i18n'
 gem 'country_select'
diff --git a/Gemfile.lock b/Gemfile.lock
index 1f4173929..6f7f5e6e9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -9,6 +9,13 @@ GIT
       randexp
       rotp (>= 4.0.0)
 
+PATH
+  remote: ../simple_form_image_fields
+  specs:
+    simple_form_image_fields (0.0.2)
+      rails
+      simple_form
+
 GEM
   remote: https://rubygems.org/
   specs:
@@ -402,8 +409,8 @@ DEPENDENCIES
   sib-api-v3-sdk
   simple-navigation
   simple_form
+  simple_form_image_fields!
   simple_form_password_with_hints
-  sort_alphabetical
   spring
   two_factor_authentication!
   tzinfo-data
diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js
index ab6a73603..8b8031a41 100644
--- a/app/assets/javascripts/admin.js
+++ b/app/assets/javascripts/admin.js
@@ -1,4 +1,6 @@
 //= require jquery3
 //= require jquery_ujs
+//= require notyf/notyf.min
 //= require simple_form_password_with_hints
 //= require appstack/app
+//= require_tree ./admin
diff --git a/app/assets/javascripts/admin/notyf.js b/app/assets/javascripts/admin/notyf.js
new file mode 100644
index 000000000..a70f7aa75
--- /dev/null
+++ b/app/assets/javascripts/admin/notyf.js
@@ -0,0 +1,31 @@
+/*global Notyf */
+var notyfAlerts = document.getElementsByClassName('js-notyf-alert'),
+    notyfNotices = document.getElementsByClassName('js-notyf-notice'),
+    notyf = new Notyf();
+
+if (notyfAlerts.length > 0) {
+    notyf.open({
+        type: 'error',
+        position: {
+            x: 'right',
+            y: 'top'
+        },
+        message: notyfAlerts[0].innerHTML,
+        duration: 9000,
+        ripple: true,
+        dismissible: true
+    });
+}
+if (notyfNotices.length > 0) {
+    notyf.open({
+        type: 'success',
+        position: {
+            x: 'right',
+            y: 'top'
+        },
+        message: notyfNotices[0].innerHTML,
+        duration: 9000,
+        ripple: true,
+        dismissible: true
+    });
+}
diff --git a/app/assets/javascripts/admin/user_menu.js b/app/assets/javascripts/admin/user_menu.js
new file mode 100644
index 000000000..c57d6cfbf
--- /dev/null
+++ b/app/assets/javascripts/admin/user_menu.js
@@ -0,0 +1,6 @@
+/*global $ */
+$('.js-user-button').click(function (e) {
+    'use strict';
+    e.stopPropagation();
+    $('.js-user-dropdown-toggle').dropdown('toggle');
+});
diff --git a/app/assets/stylesheets/admin.sass b/app/assets/stylesheets/admin.sass
index 9a243d739..9d74d3b72 100644
--- a/app/assets/stylesheets/admin.sass
+++ b/app/assets/stylesheets/admin.sass
@@ -1,4 +1,5 @@
-@import 'appstack/light'
+@import 'notyf/notyf.min'
 @import 'simple_form_password_with_hints'
 @import 'commons/*'
 @import 'admin/*'
+@import 'appstack/light'
diff --git a/app/assets/stylesheets/application/layout.sass b/app/assets/stylesheets/application/layout.sass
index 16ae7bbad..5e912ccbf 100644
--- a/app/assets/stylesheets/application/layout.sass
+++ b/app/assets/stylesheets/application/layout.sass
@@ -1,2 +1,7 @@
 footer
     margin-top: 100px
+
+.alert
+    padding: .95rem
+    &-danger
+        color: #82322F
diff --git a/app/controllers/users/registrations_controller.rb b/app/controllers/users/registrations_controller.rb
index 779a6029c..cebe81996 100644
--- a/app/controllers/users/registrations_controller.rb
+++ b/app/controllers/users/registrations_controller.rb
@@ -4,13 +4,31 @@ class Users::RegistrationsController < Devise::RegistrationsController
   before_action :configure_sign_up_params, only: :create
   before_action :configure_account_update_params, only: :update
 
+  def update
+    # to prevent cognitive complexity (the bottom block should be in an if condition where password present)
+    # Password not provided when user from sso
+    params[:user][:password] ||= ''
+
+    if params[:user][:password].empty?
+      params[:user].delete(:password)
+    else
+      resource.reset_password(params[:user][:password], params[:user][:password])
+    end
+
+    super
+  end
+
   protected
 
+  def update_resource(resource, params)
+    resource.update(params)
+  end
+
   def configure_sign_up_params
-    devise_parameter_sanitizer.permit(:sign_up, keys: [:language_id, :first_name, :last_name])
+    devise_parameter_sanitizer.permit(:sign_up, keys: [:language_id, :first_name, :last_name, :picture, :picture_delete])
   end
 
   def configure_account_update_params
-    devise_parameter_sanitizer.permit(:account_update, keys: [:mobile_phone, :language_id])
+    devise_parameter_sanitizer.permit(:account_update, keys: [:mobile_phone, :language_id, :first_name, :last_name, :picture, :picture_delete])
   end
 end
diff --git a/app/models/user.rb b/app/models/user.rb
index 12c38e59d..70045a197 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -59,7 +59,7 @@ class User < ApplicationRecord
   belongs_to :university
   belongs_to :language
   has_one :researcher, class_name: 'Research::Researcher'
-  has_one_attached :picture
+  has_one_attached_deletable :picture
 
   scope :ordered, -> { order(:last_name, :first_name) }
 
diff --git a/app/views/admin/application/_top.html.erb b/app/views/admin/application/_top.html.erb
index ec95c6a8a..a7941becc 100644
--- a/app/views/admin/application/_top.html.erb
+++ b/app/views/admin/application/_top.html.erb
@@ -6,7 +6,7 @@
     <%= render_breadcrumbs builder: Appstack::BreadcrumbsOnRailsBuilder %>
     <ul class="navbar-nav navbar-align">
       <li class="nav-item dropdown">
-        <a class="nav-link dropdown-toggle d-none d-sm-inline-block" href="#" data-bs-toggle="dropdown">
+        <a class="nav-link dropdown-toggle d-none d-sm-inline-block js-user-dropdown-toggle" href="#" data-bs-toggle="dropdown">
           <span class="text-dark"><%= current_user %></span>
         </a>
         <div class="dropdown-menu dropdown-menu-end">
@@ -15,8 +15,12 @@
         </div>
       </li>
       <li>
-        <a class="nav-link nav-link--last" href="#">
-          <%= image_tag 'avatar.jpg', class: 'avatar img-fluid rounded-circle' %>
+        <a class="nav-link nav-link--last js-user-button" href="#">
+          <% if current_user.picture.attached? && current_user.picture.variable? %>
+            <%= image_tag current_user.picture.variant(resize: '40x40'), class: 'avatar img-fluid rounded-circle' %>
+          <% else %>
+            <%= image_tag 'avatar.jpg', class: 'avatar img-fluid rounded-circle' %>
+          <% end %>
         </a>
       </li>
     </ul>
diff --git a/app/views/admin/layouts/application.html.erb b/app/views/admin/layouts/application.html.erb
index 59d936533..9f49453fe 100644
--- a/app/views/admin/layouts/application.html.erb
+++ b/app/views/admin/layouts/application.html.erb
@@ -12,6 +12,18 @@
     <%= favicon_link_tag 'favicon.png' %>
   </head>
   <body data-layout="fluid" data-sidebar-position="left">
+    <div class="toasts-container" style="position: fixed; top: 20px; right: 20px; z-index: 100000;">
+      <% unless notice.nil? %>
+        <div class="js-notyf-notice d-none">
+          <%= notice %>
+        </div>
+      <% end %>
+      <% unless alert.nil? %>
+        <div class="js-notyf-alert d-none">
+          <%= alert %>
+        </div>
+      <% end %>
+    </div>
     <div class="wrapper">
       <%= render 'admin/application/nav' %>
       <div class="main">
diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb
index 2e6a1b6cd..b6da31641 100644
--- a/app/views/devise/registrations/edit.html.erb
+++ b/app/views/devise/registrations/edit.html.erb
@@ -20,17 +20,16 @@
     <%= f.input :mobile_phone %>
     <%= f.association :language, include_blank: false %>
 
+    <%= f.input :picture,
+                      as: :single_deletable_file,
+                      input_html: { accept: '.png' } %>
+
     <%= f.input :password,
                 hint: t(".leave_blank_if_you_don_t_want_to_change_it"),
                 required: false,
                 input_html: { autocomplete: "new-password" } %>
-    <%= f.input :password_confirmation,
-                required: false,
-                input_html: { autocomplete: "new-password" } %>
-    <%= f.input :current_password,
-                hint: t(".we_need_your_current_password_to_confirm_your_changes"),
-                required: true,
-                input_html: { autocomplete: "current-password" } %>
+  
+
   </div>
 
   <div class="form-actions">
diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb
index 759226799..f72cf237a 100644
--- a/app/views/devise/registrations/new.html.erb
+++ b/app/views/devise/registrations/new.html.erb
@@ -15,16 +15,30 @@
                 required: true,
                 input_html: { autocomplete: "email" } %>
     <%= f.input :password,
+                as: :password_with_hints,
                 required: true,
-                hint: (t('devise.shared.minimum_password_length', count: @minimum_password_length) if @minimum_password_length),
+                allow_password_uncloaking: true,
+                validators: {
+                  length: Devise.password_length.first,
+                  uppercase_char: true,
+                  lowercase_char: true,
+                  numeric_char: true,
+                  special_char: Rails.application.config.allowed_special_chars
+                },
                 input_html: { autocomplete: "new-password" } %>
     <%= f.input :password_confirmation,
+                as: :password_with_sync,
                 required: true,
+                allow_password_uncloaking: true,
+                compare_with_field: :password,
                 input_html: { autocomplete: "new-password" } %>
     <%= f.association :language,
                       required: true,
                       label_method: lambda { |l| I18nData.languages(I18n.locale.to_s.upcase)[l.iso_code.to_s.upcase].capitalize },
                       include_blank: 'Sélectionnez une langue' %>
+    <%= f.input :picture,
+                      as: :single_deletable_file,
+                      input_html: { accept: '.png' } %>
   </div>
 
   <div class="form-actions text-center mt-3">
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 5726df05b..c2009000b 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -13,6 +13,7 @@
   <body>
     <%= render 'nav' %>
     <main class="container">
+      
       <%= render_breadcrumbs builder: Appstack::BreadcrumbsOnRailsBuilder %>
       <%= yield %>
     </main>
diff --git a/app/views/layouts/devise.html.erb b/app/views/layouts/devise.html.erb
index df3736443..c46882bdd 100644
--- a/app/views/layouts/devise.html.erb
+++ b/app/views/layouts/devise.html.erb
@@ -14,8 +14,8 @@
     <div class="main d-flex justify-content-center w-100">
       <main class="content d-flex p-0">
         <div class="container d-flex flex-column">
-          <% unless notice.blank? %><div class="alert alert-success mt-2" role="alert"><div class="alert-message"><%= notice.html_safe %></div></div><% end %>
-          <% unless alert.blank? %><div class="alert alert-danger mt-2" role="alert"><div class="alert-message"><%= alert.html_safe %></div></div><% end %>
+          <% unless notice.blank? %><div class="alert alert-success mt-2" role="alert"><%= notice.html_safe %></div><% end %>
+          <% unless alert.blank? %><div class="alert alert-danger mt-2" role="alert"><%= alert.html_safe %></div><% end %>
 
           <div class="row h-100">
             <div class="col-sm-10 col-md-8 col-lg-6 mx-auto d-table h-100">
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 56dec7625..1a81b6369 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -74,6 +74,8 @@ en:
     subtitle: Sign in to your account to continue
   please-confirm: Are you sure?
   simple_form:
+    error_notification:
+      default_message: "Please review the problems below:"
     hints:
       user:
         mobile_phone: "International format (+XX)"
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 1ee02d4dd..20c631a12 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -74,6 +74,8 @@ fr:
     subtitle: Vous devez être authentifié pour continuer
   please-confirm: Est-ce que vous confirmez ?
   simple_form:
+    error_notification:
+      default_message: "Les erreurs ci-dessous empêchent la validation :"
     hints:
       user:
         mobile_phone: "Format international (+XX)"
diff --git a/package.json b/package.json
new file mode 100644
index 000000000..587e15688
--- /dev/null
+++ b/package.json
@@ -0,0 +1,5 @@
+{
+  "dependencies": {
+    "notyf": "^3.10.0"
+  }
+}
diff --git a/yarn.lock b/yarn.lock
index fb57ccd13..a4bd56507 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,3 +2,7 @@
 # yarn lockfile v1
 
 
+notyf@^3.10.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/notyf/-/notyf-3.10.0.tgz#67a64443c69ea0e6495c56ea0f91198860163d06"
+  integrity sha512-Mtnp+0qiZxgrH+TzVlzhWyZceHdAZ/UWK0/ju9U0HQeDpap1mZ8cC7H5wSI5mwgni6yeAjaxsTw0sbMK+aSuHw==
-- 
GitLab