From 828bf44b2bc28e79521a6e67fb823dc1e7bdfdf9 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoit@matrix.org>
Date: Thu, 20 Aug 2020 15:44:28 +0200
Subject: [PATCH] Better handling DM creation when invitees cannot be inviting
 due to denied federation As we do not know the created roomId, we cannot add
 it to the DM list though. But at least the user is informed that a room has
 been created and won't retry because the screen will be closed.

---
 CHANGES.md                                    |  1 +
 .../session/room/failure/CreateRoomFailure.kt |  5 +--
 .../session/room/create/CreateRoomTask.kt     | 17 +++++++--
 .../createdirect/CreateDirectRoomActivity.kt  | 36 ++++++++++++-------
 vector/src/main/res/values/strings.xml        |  1 +
 5 files changed, 43 insertions(+), 17 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 495247b50e..34ffdbcfd6 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -9,6 +9,7 @@ Improvements 🙌:
  - Give user the possibility to prevent accidental call (#1869)
  - Display device information (name, id and key) in Cryptography setting screen (#1784)
  - Ensure users do not accidentally ignore other users (#1890)
+ - Better handling DM creation when invitees cannot be inviting due to denied federation
  - Support new config.json format and config.domain.json files (#1682)
  - Increase Font size on Calling screen (#1643)
  - Make the user's Avatar live in the general settings
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt
index d70dae3454..508cf5ea1d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt
@@ -18,8 +18,9 @@
 package org.matrix.android.sdk.api.session.room.failure
 
 import org.matrix.android.sdk.api.failure.Failure
+import org.matrix.android.sdk.api.failure.MatrixError
 
 sealed class CreateRoomFailure : Failure.FeatureFailure() {
-
-    object CreatedWithTimeout: CreateRoomFailure()
+    object CreatedWithTimeout : CreateRoomFailure()
+    data class CreatedWithFederationFailure(val matrixError: MatrixError) : CreateRoomFailure()
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt
index 4db3a47502..6738c7d881 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt
@@ -21,6 +21,8 @@ import com.zhuinden.monarchy.Monarchy
 import io.realm.RealmConfiguration
 import kotlinx.coroutines.TimeoutCancellationException
 import org.greenrobot.eventbus.EventBus
+import org.matrix.android.sdk.api.failure.Failure
+import org.matrix.android.sdk.api.failure.MatrixError
 import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
 import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
 import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
@@ -62,8 +64,19 @@ internal class DefaultCreateRoomTask @Inject constructor(
 
         val createRoomBody = createRoomBodyBuilder.build(params)
 
-        val createRoomResponse = executeRequest<CreateRoomResponse>(eventBus) {
-            apiCall = roomAPI.createRoom(createRoomBody)
+        val createRoomResponse = try {
+            executeRequest<CreateRoomResponse>(eventBus) {
+                apiCall = roomAPI.createRoom(createRoomBody)
+            }
+        } catch (throwable: Throwable) {
+            if (throwable is Failure.ServerError
+                    && throwable.httpCode == 403
+                    && throwable.error.code == MatrixError.M_FORBIDDEN
+                    && throwable.error.message.startsWith("Federation denied with")) {
+                throw CreateRoomFailure.CreatedWithFederationFailure(throwable.error)
+            } else {
+                throw throwable
+            }
         }
         val roomId = createRoomResponse.roomId
         // Wait for room to come back from the sync (but it can maybe be in the DB if the sync response is received before)
diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt
index 5d6bef4e2f..41260b06c8 100644
--- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt
@@ -48,9 +48,9 @@ import im.vector.app.features.userdirectory.UserDirectoryFragment
 import im.vector.app.features.userdirectory.UserDirectorySharedAction
 import im.vector.app.features.userdirectory.UserDirectorySharedActionViewModel
 import im.vector.app.features.userdirectory.UserDirectoryViewModel
+import kotlinx.android.synthetic.main.activity.*
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
-import kotlinx.android.synthetic.main.activity.*
 import java.net.HttpURLConnection
 import javax.inject.Inject
 
@@ -138,19 +138,29 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
 
     private fun renderCreationFailure(error: Throwable) {
         hideWaitingView()
-        if (error is CreateRoomFailure.CreatedWithTimeout) {
-            finish()
-        } else {
-            val message = if (error is Failure.ServerError && error.httpCode == HttpURLConnection.HTTP_INTERNAL_ERROR /*500*/) {
-                // This error happen if the invited userId does not exist.
-                getString(R.string.create_room_dm_failure)
-            } else {
-                errorFormatter.toHumanReadable(error)
+        when (error) {
+            is CreateRoomFailure.CreatedWithTimeout -> {
+                finish()
+            }
+            is CreateRoomFailure.CreatedWithFederationFailure -> {
+                AlertDialog.Builder(this)
+                        .setMessage(getString(R.string.create_room_federation_error, error.matrixError.message))
+                        .setCancelable(false)
+                        .setPositiveButton(R.string.ok) { _, _ -> finish() }
+                        .show()
+            }
+            else                                              -> {
+                val message = if (error is Failure.ServerError && error.httpCode == HttpURLConnection.HTTP_INTERNAL_ERROR /*500*/) {
+                    // This error happen if the invited userId does not exist.
+                    getString(R.string.create_room_dm_failure)
+                } else {
+                    errorFormatter.toHumanReadable(error)
+                }
+                AlertDialog.Builder(this)
+                        .setMessage(message)
+                        .setPositiveButton(R.string.ok, null)
+                        .show()
             }
-            AlertDialog.Builder(this)
-                    .setMessage(message)
-                    .setPositiveButton(R.string.ok, null)
-                    .show()
         }
     }
 
diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml
index 34cf24b476..25ec5de33b 100644
--- a/vector/src/main/res/values/strings.xml
+++ b/vector/src/main/res/values/strings.xml
@@ -1640,6 +1640,7 @@
     <string name="create_room_public_description">"Anyone will be able to join this room"</string>
     <string name="create_room_directory_title">"Room Directory"</string>
     <string name="create_room_directory_description">"Publish this room in the room directory"</string>
+    <string name="create_room_federation_error">"The room has been created, but some invitations have not been sent for the following reason:\n\n%s"</string>
 
     <string name="keys_backup_unable_to_get_trust_info">"An error occurred getting trust info"</string>
     <string name="keys_backup_unable_to_get_keys_backup_data">"An error occurred getting keys backup data"</string>