From 89f9f6a82a2fa5765fa0a198383049177f9f25e0 Mon Sep 17 00:00:00 2001
From: Samuel Couillard <43917914+scouillard@users.noreply.github.com>
Date: Mon, 16 Jan 2023 09:48:49 -0500
Subject: [PATCH] Migration upgrade (V2): addition of RolePermissions,
 RoomSettings, SharedAccess, SiteSettings, RoomConfiguration data (#4339)

* Add SiteSettings and RoomConfigs to migration

* Create standalone task for Room Settings

* Quickfixes

* Quickfix

* Rubo

* Add JSON parse

* Fix RoomSettings data structure

* Remove default values from room_settings hash

* Put RoomSettings logicin Room task

* Add SharedAccess task

* Fix SharedAccess logs

* Fix SiteSettings task

* Fix registration method

* Add RolePermissions to Role task

* Move SharedAccess to Room, fix SiteSettings

* Fix SharedAccess

* Add RoomsConfiguration

* Fix Roles after test

* Rename SiteSettings to Settings

* Rubocop

* Add logic to bypass HomeRoom empty string

* fix typos

* Rubocop

* Remove PrimaryColorDark from settings data
---
 lib/tasks/migrations/migrations.rake | 192 ++++++++++++++++++++-------
 1 file changed, 143 insertions(+), 49 deletions(-)

diff --git a/lib/tasks/migrations/migrations.rake b/lib/tasks/migrations/migrations.rake
index 30bd86da..8d9dd6c7 100644
--- a/lib/tasks/migrations/migrations.rake
+++ b/lib/tasks/migrations/migrations.rake
@@ -17,20 +17,36 @@ namespace :migrations do
         .select(:id, :name)
         .where.not(name: COMMON[:filtered_roles])
         .find_each(batch_size: COMMON[:batch_size]) do |r|
-          params = { role: { name: r.name.capitalize } }
-          response = Net::HTTP.post(uri('roles'), payload(params), COMMON[:headers])
-
-          case response
-          when Net::HTTPCreated
-            puts green "Succesfully migrated Role:"
-            puts cyan "  ID: #{r.id}"
-            puts cyan "  Name: #{params[:role][:name]}"
-          else
-            puts red "Unable to migrate Role:"
-            puts yellow "  ID: #{r.id}"
-            puts yellow "  Name: #{params[:role][:name]}"
-            has_encountred_issue = 1 # At least one of the migrations failed.
-          end
+      # RolePermissions
+      role_permissions_hash = RolePermission.where(role_id: r.id).pluck(:name, :value).to_h
+      # Returns nil if the RolePermission value is the same as the corresponding default value in V3
+      role_permissions = {
+        CreateRoom: role_permissions_hash['can_create_rooms'] == "true" ? nil : "false",
+        CanRecord: role_permissions_hash['can_launch_recording'] == "true" ? nil : "false",
+        ManageUsers: role_permissions_hash['can_manage_users'] == "false" ? nil : "true",
+        ManageRoles: role_permissions_hash['can_edit_roles'] == "false" ? nil : "true",
+        # In V3, can_manage_room_recordings is split into two distinct permissions: ManageRooms and ManageRecordings
+        ManageRooms: role_permissions_hash['can_manage_rooms_recordings'] == "false" ? nil : "true",
+        ManageRecordings: role_permissions_hash['can_manage_room_recordings'] == "false" ? nil : "true",
+        ManageSiteSettings: role_permissions_hash['can_edit_site_settings'] == "false" ? nil : "true"
+      }.compact
+
+      params = { role: { name: r.name.capitalize,
+                         role_permissions: role_permissions } }
+
+      response = Net::HTTP.post(uri('roles'), payload(params), COMMON[:headers])
+
+      case response
+      when Net::HTTPCreated
+        puts green "Succesfully migrated Role:"
+        puts cyan "  ID: #{r.id}"
+        puts cyan "  Name: #{params[:role][:name]}"
+      else
+        puts red "Unable to migrate Role:"
+        puts yellow "  ID: #{r.id}"
+        puts yellow "  Name: #{params[:role][:name]}"
+        has_encountred_issue = 1 # At least one of the migrations failed.
+      end
     end
 
     puts
@@ -48,21 +64,22 @@ namespace :migrations do
         .includes(:role)
         .where.not(roles: { name: COMMON[:filtered_user_roles] }, deleted: true)
         .find_each(start: start, finish: stop, batch_size: COMMON[:batch_size]) do |u|
-          role_name = infer_role_name(u.role.name)
-          params = { user: { name: u.name, email: u.email, external_id: u.social_uid, language: u.language, role: role_name } }
-          response = Net::HTTP.post(uri('users'), payload(params), COMMON[:headers])
-
-          case response
-          when Net::HTTPCreated
-            puts green "Succesfully migrated User:"
-            puts cyan "  UID: #{u.uid}"
-            puts cyan "  Name: #{params[:user][:name]}"
-          else
-            puts red "Unable to migrate User:"
-            puts yellow "  UID: #{u.uid}"
-            puts yellow "  Name: #{params[:user][:name]}"
-            has_encountred_issue = 1 # At least one of the migrations failed.
-          end
+      role_name = infer_role_name(u.role.name)
+      params = { user: { name: u.name, email: u.email, external_id: u.social_uid, language: u.language, role: role_name } }
+
+      response = Net::HTTP.post(uri('users'), payload(params), COMMON[:headers])
+
+      case response
+      when Net::HTTPCreated
+        puts green "Succesfully migrated User:"
+        puts cyan "  UID: #{u.uid}"
+        puts cyan "  Name: #{params[:user][:name]}"
+      else
+        puts red "Unable to migrate User:"
+        puts yellow "  UID: #{u.uid}"
+        puts yellow "  Name: #{params[:user][:name]}"
+        has_encountred_issue = 1 # At least one of the migrations failed.
+      end
     end
 
     puts
@@ -85,29 +102,48 @@ namespace :migrations do
                              .where(name: COMMON[:filtered_user_roles])
                              .pluck(:id)
 
-    Room.unscoped
-        .select(:id, :uid, :name, :bbb_id, :last_session, :user_id)
+    Room.unscoped.select(:id, :uid, :name, :bbb_id, :last_session, :user_id, :room_settings)
         .includes(:owner)
         .where.not(users: { role_id: filtered_roles_ids, deleted: true }, deleted: true)
         .find_each(start: start, finish: stop, batch_size: COMMON[:batch_size]) do |r|
-          params = { room: { friendly_id: r.uid,
-                             name: r.name,
-                             meeting_id: r.bbb_id,
-                             last_session: r.last_session&.to_datetime,
-                             owner_email: r.owner.email } }
-          response = Net::HTTP.post(uri('rooms'), payload(params), COMMON[:headers])
-
-          case response
-          when Net::HTTPCreated
-            puts green "Succesfully migrated Room:"
-            puts cyan "  UID: #{r.uid}"
-            puts cyan "  Name: #{r.name}"
-          else
-            puts red "Unable to migrate Room:"
-            puts yellow "  UID: #{r.uid}"
-            puts yellow "  Name: #{r.name}"
-            has_encountred_issue = 1 # At least one of the migrations failed.
-          end
+      # RoomSettings
+      parsed_room_settings = JSON.parse(r.room_settings)
+      # Returns nil if the RoomSetting value is the same as the corresponding default value in V3
+      room_settings = if parsed_room_settings.empty? # Bypass Home Rome room_settings which is an empty hash by default
+                        {}
+                      else
+                        {
+                          record: parsed_room_settings["recording"] == false ? nil : "true",
+                          muteOnStart: parsed_room_settings["muteOnStart"] == false ? nil : "true",
+                          glAnyoneCanStart: parsed_room_settings["anyoneCanStart"] == false ? nil : "true",
+                          glAnyoneJoinAsModerator: parsed_room_settings["joinModerator"] == false ? nil : "true",
+                          guestPolicy: parsed_room_settings["requireModeratorApproval"] == false ? nil : "ASK_MODERATOR",
+                        }.compact
+                      end
+
+      shared_users_emails = SharedAccess.joins(:user).where(room_id: r.id).pluck(:'users.email')
+
+      params = { room: { friendly_id: r.uid,
+                         name: r.name,
+                         meeting_id: r.bbb_id,
+                         last_session: r.last_session&.to_datetime,
+                         owner_email: r.owner.email,
+                         room_settings: room_settings,
+                         shared_users_emails: shared_users_emails } }
+
+      response = Net::HTTP.post(uri('rooms'), payload(params), COMMON[:headers])
+
+      case response
+      when Net::HTTPCreated
+        puts green "Succesfully migrated Room:"
+        puts cyan "  UID: #{r.uid}"
+        puts cyan "  Name: #{r.name}"
+      else
+        puts red "Unable to migrate Room:"
+        puts yellow "  UID: #{r.uid}"
+        puts yellow "  Name: #{r.name}"
+        has_encountred_issue = 1 # At least one of the migrations failed.
+      end
     end
 
     puts
@@ -121,6 +157,52 @@ namespace :migrations do
     exit has_encountred_issue
   end
 
+  task settings: :environment do |_task|
+    has_encountred_issue = 0
+
+    settings_hash = Setting.find_by(provider: 'greenlight').features.pluck(:name, :value).to_h
+
+    # SiteSettings
+    site_settings = {
+      PrimaryColor: settings_hash['Primary Color'],
+      PrimaryColorLight: settings_hash['Primary Color Lighten'],
+      Terms: settings_hash['Legal URL'],
+      PrivacyPolicy: settings_hash['Privacy Policy URL'],
+      RegistrationMethod: infer_registration_method(settings_hash['Registration Method']),
+      ShareRooms: settings_hash['Shared Access'],
+      PreuploadPresentation: settings_hash['Preupload Presentation'],
+    }.compact
+
+    # RoomConfigurations
+    room_configurations = {
+      record: settings_hash['Room Configuration Recording'],
+      muteOnStart: settings_hash['Room Configuration Mute On Join'],
+      guestPolicy: settings_hash['Room Configuration Require Moderator'],
+      glAnyoneCanStart: settings_hash['Room Configuration Allow Any Start'],
+      glAnyoneJoinAsModerator: settings_hash['Room Configuration All Join Moderator'],
+      glRequireAuthentication: settings_hash['Room Authentication']
+    }.compact
+
+    params = { settings: { site_settings: site_settings, room_configurations: room_configurations } }
+
+    response = Net::HTTP.post(uri('settings'), payload(params), COMMON[:headers])
+
+    case response
+    when Net::HTTPCreated
+      puts green "Successfully migrated Settings"
+    else
+      puts red "Unable to migrate Settings"
+      has_encountred_issue = 1 # At least one of the migrations failed.
+    end
+
+    puts
+    puts green "Settings migration completed."
+
+    puts yellow "In case of an error please retry the process to resolve." unless has_encountred_issue.zero?
+
+    exit has_encountred_issue
+  end
+
   private
 
   def encrypt_params(params)
@@ -165,4 +247,16 @@ namespace :migrations do
   def infer_role_name(name)
     DEFAULT_ROLES_MAP[name] || name.capitalize
   end
+
+  # Registration Method returns "0", "1" or "2" but V3 expects "open", "invite" or "approval"
+  def infer_registration_method(registration_method)
+    case registration_method
+    when "1"
+      "invite"
+    when "2"
+      "approval"
+    else
+      "open"
+    end
+  end
 end
-- 
GitLab