From ab3a594e5c2ecd0d39781ebe0fae5cde2876bff3 Mon Sep 17 00:00:00 2001
From: Juan Carlos Garrote <juanca_arrabal@hotmail.com>
Date: Fri, 14 Apr 2023 11:02:21 +0200
Subject: [PATCH] Create network call to create file via app provider

---
 ...reateRemoteFileWithAppProviderOperation.kt | 108 ++++++++++++++++++
 .../GetUrlToOpenInWebRemoteOperation.kt       |  11 +-
 .../services/AppRegistryService.kt            |   7 ++
 .../services/OCAppRegistryService.kt          |  13 +++
 4 files changed, 134 insertions(+), 5 deletions(-)
 create mode 100644 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/CreateRemoteFileWithAppProviderOperation.kt

diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/CreateRemoteFileWithAppProviderOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/CreateRemoteFileWithAppProviderOperation.kt
new file mode 100644
index 00000000..e4f85a32
--- /dev/null
+++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/CreateRemoteFileWithAppProviderOperation.kt
@@ -0,0 +1,108 @@
+/* ownCloud Android Library is available under MIT license
+ *   Copyright (C) 2023 ownCloud GmbH.
+ *
+ *   Permission is hereby granted, free of charge, to any person obtaining a copy
+ *   of this software and associated documentation files (the "Software"), to deal
+ *   in the Software without restriction, including without limitation the rights
+ *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *   copies of the Software, and to permit persons to whom the Software is
+ *   furnished to do so, subject to the following conditions:
+ *
+ *   The above copyright notice and this permission notice shall be included in
+ *   all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ *   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ *   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ *   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ *   THE SOFTWARE.
+ *
+ */
+
+package com.owncloud.android.lib.resources.appregistry
+
+import com.owncloud.android.lib.common.OwnCloudClient
+import com.owncloud.android.lib.common.http.HttpConstants
+import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod
+import com.owncloud.android.lib.common.network.WebdavUtils
+import com.owncloud.android.lib.common.operations.RemoteOperation
+import com.owncloud.android.lib.common.operations.RemoteOperationResult
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonAdapter
+import com.squareup.moshi.JsonClass
+import com.squareup.moshi.Moshi
+import okhttp3.FormBody
+import okhttp3.RequestBody
+import timber.log.Timber
+import java.net.URL
+import java.util.concurrent.TimeUnit
+
+class CreateRemoteFileWithAppProviderOperation(
+    private val createFileWithAppProviderEndpoint: String,
+    private val parentContainerId: String,
+    private val filename: String,
+) : RemoteOperation<String>() {
+
+    override fun run(client: OwnCloudClient): RemoteOperationResult<String> {
+        return try {
+
+            val createFileWithAppProviderRequestBody = CreateFileWithAppProviderParams(parentContainerId, filename)
+                .toRequestBody()
+
+            val stringUrl = client.baseUri.toString() + WebdavUtils.encodePath(createFileWithAppProviderEndpoint)
+
+            val postMethod = PostMethod(URL(stringUrl), createFileWithAppProviderRequestBody).apply {
+                setReadTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
+                setConnectionTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
+            }
+
+            val status = client.executeHttpMethod(postMethod)
+            Timber.d("Create file $filename with app provider in folder with ID $parentContainerId - $status${if (!isSuccess(status)) "(FAIL)" else ""}")
+
+            if (isSuccess(status)) RemoteOperationResult<String>(ResultCode.OK).apply {
+                val moshi = Moshi.Builder().build()
+                val adapter: JsonAdapter<CreateFileWithAppProviderResponse> = moshi.adapter(CreateFileWithAppProviderResponse::class.java)
+
+                data = postMethod.getResponseBodyAsString()?.let { adapter.fromJson(it)!!.fileId }
+            }
+            else RemoteOperationResult<String>(postMethod).apply { data = "" }
+
+        } catch (e: Exception) {
+            val result = RemoteOperationResult<String>(e)
+            Timber.e(e, "Create file $filename with app provider in folder with ID $parentContainerId failed")
+            result
+        }
+    }
+
+    private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK
+
+    data class CreateFileWithAppProviderParams(
+        val parentContainerId: String,
+        val filename: String,
+    ) {
+        fun toRequestBody(): RequestBody =
+            FormBody.Builder()
+                .add(PARAM_PARENT_CONTAINER_ID, parentContainerId)
+                .add(PARAM_FILENAME, filename)
+                .build()
+
+        companion object {
+            const val PARAM_PARENT_CONTAINER_ID = "parent_container_id"
+            const val PARAM_FILENAME = "filename"
+        }
+    }
+
+    @JsonClass(generateAdapter = true)
+    data class CreateFileWithAppProviderResponse(
+        @Json(name = "file_id")
+        val fileId: String,
+    )
+
+    companion object {
+        private const val TIMEOUT: Long = 5_000
+    }
+}
diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/GetUrlToOpenInWebRemoteOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/GetUrlToOpenInWebRemoteOperation.kt
index 422db268..84b32514 100644
--- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/GetUrlToOpenInWebRemoteOperation.kt
+++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/GetUrlToOpenInWebRemoteOperation.kt
@@ -1,5 +1,5 @@
 /* ownCloud Android Library is available under MIT license
-*   Copyright (C) 2022 ownCloud GmbH.
+*   Copyright (C) 2023 ownCloud GmbH.
 *
 *   Permission is hereby granted, free of charge, to any person obtaining a copy
 *   of this software and associated documentation files (the "Software"), to deal
@@ -21,6 +21,7 @@
 *   THE SOFTWARE.
 *
 */
+
 package com.owncloud.android.lib.resources.appregistry
 
 import com.owncloud.android.lib.common.OwnCloudClient
@@ -40,9 +41,9 @@ import java.net.URL
 import java.util.concurrent.TimeUnit
 
 class GetUrlToOpenInWebRemoteOperation(
-    val openWithWebEndpoint: String,
-    val fileId: String,
-    val appName: String,
+    private val openWithWebEndpoint: String,
+    private val fileId: String,
+    private val appName: String,
 ) : RemoteOperation<String>() {
 
     override fun run(client: OwnCloudClient): RemoteOperationResult<String> {
@@ -76,7 +77,7 @@ class GetUrlToOpenInWebRemoteOperation(
         }
     }
 
-    private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK || status == HttpConstants.HTTP_MULTI_STATUS
+    private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK
 
     data class OpenInWebParams(
         val fileId: String,
diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/services/AppRegistryService.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/services/AppRegistryService.kt
index 4b94f1f7..50145892 100644
--- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/services/AppRegistryService.kt
+++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/services/AppRegistryService.kt
@@ -20,6 +20,7 @@
  *   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  *   THE SOFTWARE.
  */
+
 package com.owncloud.android.lib.resources.appregistry.services
 
 import com.owncloud.android.lib.common.operations.RemoteOperationResult
@@ -34,4 +35,10 @@ interface AppRegistryService : Service {
         fileId: String,
         appName: String,
     ): RemoteOperationResult<String>
+
+    fun createFileWithAppProvider(
+        createFileWithAppProviderEndpoint: String,
+        parentContainerId: String,
+        filename: String,
+    ): RemoteOperationResult<String>
 }
diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/services/OCAppRegistryService.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/services/OCAppRegistryService.kt
index f80fe821..e07ac100 100644
--- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/services/OCAppRegistryService.kt
+++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/appregistry/services/OCAppRegistryService.kt
@@ -20,10 +20,12 @@
  *   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  *   THE SOFTWARE.
  */
+
 package com.owncloud.android.lib.resources.appregistry.services
 
 import com.owncloud.android.lib.common.OwnCloudClient
 import com.owncloud.android.lib.common.operations.RemoteOperationResult
+import com.owncloud.android.lib.resources.appregistry.CreateRemoteFileWithAppProviderOperation
 import com.owncloud.android.lib.resources.appregistry.GetRemoteAppRegistryOperation
 import com.owncloud.android.lib.resources.appregistry.GetUrlToOpenInWebRemoteOperation
 import com.owncloud.android.lib.resources.appregistry.responses.AppRegistryResponse
@@ -38,4 +40,15 @@ class OCAppRegistryService(override val client: OwnCloudClient) : AppRegistrySer
             fileId = fileId,
             appName = appName
         ).execute(client)
+
+    override fun createFileWithAppProvider(
+        createFileWithAppProviderEndpoint: String,
+        parentContainerId: String,
+        filename: String
+    ): RemoteOperationResult<String> =
+        CreateRemoteFileWithAppProviderOperation(
+            createFileWithAppProviderEndpoint = createFileWithAppProviderEndpoint,
+            parentContainerId = parentContainerId,
+            filename = filename,
+        ).execute(client)
 }