From 77662ef03f69fe595d888d8c52ece20c359c4e5c Mon Sep 17 00:00:00 2001
From: pabois <pierreandre.boissinot@noesya.coop>
Date: Mon, 2 May 2022 15:12:27 +0200
Subject: [PATCH] wip mapping

---
 app/models/user/with_omniauth.rb             | 48 ++++++++++++++++++--
 app/views/server/universities/_form.html.erb |  6 ++-
 2 files changed, 49 insertions(+), 5 deletions(-)

diff --git a/app/models/user/with_omniauth.rb b/app/models/user/with_omniauth.rb
index f0de9a849..5ce3c64a2 100644
--- a/app/models/user/with_omniauth.rb
+++ b/app/models/user/with_omniauth.rb
@@ -5,10 +5,9 @@ module User::WithOmniauth
 
     def self.from_omniauth(university, attributes)
       mapping = university.sso_mapping
-      email = 'pierreandre.boissinot@noesya.coop'
 
-      # email_sso_key = mapping.select { |elmt| elmt['internal_key'] == 'email' }&.first&.dig('sso_key')
-      email_sso_key = 'email'
+      # first step: we find the email (we are supposed to have an email mapping)
+      email_sso_key = mapping.select { |elmt| elmt['internal_key'] == 'email' }&.first&.dig('sso_key')
       email = attributes.dig(email_sso_key)
       return unless email
       email = email.first if email.is_a?(Array)
@@ -17,6 +16,49 @@ module User::WithOmniauth
       user = User.where(university: university, email: email).first_or_create do |u|
         u.password = "#{Devise.friendly_token[0,20]}!" # meets password complexity requirements
       end
+
+      # update user data according to mapping & infos provided by SSO
+      mapping.select { |elmt| elmt['internal_key'] != 'email' }.each do |mapping_element|
+        user = self.update_data_for_mapping_element(user, mapping_element, attributes)
+      end
+
+      user.save
+      user
+    end
+
+    protected
+
+    def self.update_data_for_mapping_element(user, mapping_element, attributes)
+      sso_key = mapping_element['sso_key']
+      return user if attributes[sso_key].nil? # if not provided by sso, just return
+      internal_key = mapping_element['internal_key']
+      user = self.update_data_for_mapping_element_standard(user, mapping_element, self.get_provided_answer(attributes[sso_key]))
+      user
+    end
+
+    def self.update_data_for_mapping_element_standard(user, mapping_element, sso_value)
+      case mapping_element['type']
+      when 'text'
+        user[mapping_element['internal_key']] = sso_value.first
+      when 'select'
+        value = mapping_element['values'].select { |val| val['sso_value'] == sso_value.first }
+        user[mapping_element['internal_key']] = value.first&.dig('internal_value')
+      when 'newsletter'
+          user.optin_newsletter_basic = '1' if mapping_element['values'].first['sso_value'] == sso_value.first
+      when 'language'
+        user = self.set_best_id_for(user, mapping_element['type'], sso_value.first)
+      end
+      user
+    end
+
+    def self.get_provided_answer(value)
+      # SAML send an array (even for a single value) where OAuth2 send a string for single values. We harmonize to always get an array
+      value.is_a?(Array) ? value : [value]
+    end
+
+    def self.set_best_id_for(user, type, iso)
+      element_id = eval(type.classify).find_by(iso_code: iso)&.id
+      user["#{type}_id"] = element_id unless element_id.nil?
       user
     end
 
diff --git a/app/views/server/universities/_form.html.erb b/app/views/server/universities/_form.html.erb
index c3e2a4743..aafc0fcb5 100644
--- a/app/views/server/universities/_form.html.erb
+++ b/app/views/server/universities/_form.html.erb
@@ -36,8 +36,10 @@
         <%= 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>
+    <div class="col-md-6">
+      <%= render 'sso_mapping', university: university %>
     </div>
   </div>
 
-- 
GitLab