From 9ab7c139e124dc1b03fbc18557ad8fb7d2112a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abel=20Garc=C3=ADa=20de=20Prada?= Date: Thu, 18 Aug 2022 12:34:48 +0200 Subject: [PATCH 1/5] Retrieve the app providers from the capabilities --- .../lib/resources/status/RemoteCapability.kt | 12 +++++++++- .../status/responses/CapabilityResponse.kt | 22 ++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/RemoteCapability.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/RemoteCapability.kt index 8295d5ff..2f9f3f86 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/RemoteCapability.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/RemoteCapability.kt @@ -66,7 +66,8 @@ data class RemoteCapability( // Files var filesBigFileChunking: CapabilityBooleanType = CapabilityBooleanType.UNKNOWN, var filesUndelete: CapabilityBooleanType = CapabilityBooleanType.UNKNOWN, - var filesVersioning: CapabilityBooleanType = CapabilityBooleanType.UNKNOWN + var filesVersioning: CapabilityBooleanType = CapabilityBooleanType.UNKNOWN, + val remoteOcisProviders: List?, ) { /** * Enum for Boolean Type in capabilities, with values: @@ -98,4 +99,13 @@ data class RemoteCapability( } } } + + data class RemoteOCISProvider( + val enabled: Boolean, + val version: String, + val appsUrl: String?, + val openUrl: String?, + val openWebUrl: String?, + val newUrl: String?, + ) } diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt index 2965530b..82a1bca7 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt @@ -26,6 +26,7 @@ package com.owncloud.android.lib.resources.status.responses import com.owncloud.android.lib.resources.status.RemoteCapability import com.owncloud.android.lib.resources.status.RemoteCapability.CapabilityBooleanType +import com.owncloud.android.lib.resources.status.RemoteCapability.RemoteOCISProvider import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @@ -68,6 +69,7 @@ data class CapabilityResponse( filesBigFileChunking = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.bigfilechunking), filesUndelete = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.undelete), filesVersioning = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.versioning), + remoteOcisProviders = capabilities?.fileCapabilities?.appProviders?.map { it.toOCISProvider() }, filesSharingFederationIncoming = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingFederation?.incoming), filesSharingFederationOutgoing = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingFederation?.outgoing), filesSharingUserProfilePicture = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingUser?.profilePicture), @@ -160,9 +162,27 @@ data class FileSharingUser( data class FileCapabilities( val bigfilechunking: Boolean?, val undelete: Boolean?, - val versioning: Boolean? + val versioning: Boolean?, + @Json(name = "app_providers") + val appProviders: List? ) +@JsonClass(generateAdapter = true) +data class AppProvider( + val enabled: Boolean, + val version: String, + @Json(name = "apps_url") + val appsUrl: String?, + @Json(name = "open_url") + val openUrl: String?, + @Json(name = "open_web_url") + val openWebUrl: String?, + @Json(name = "new_url") + val newUrl: String?, +) { + fun toOCISProvider() = RemoteOCISProvider(enabled, version, appsUrl, openUrl, openWebUrl, newUrl) +} + @JsonClass(generateAdapter = true) data class DavCapabilities( val chunking: String? From 6d235fe74a76ede610560f28bb3f80e1e6b05a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abel=20Garc=C3=ADa=20de=20Prada?= Date: Wed, 24 Aug 2022 11:36:17 +0200 Subject: [PATCH 2/5] Add a new remote operation to retrieve the url to open a file with ocis provider --- .../files/GetUrlToOpenInWebRemoteOperation.kt | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/GetUrlToOpenInWebRemoteOperation.kt diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/GetUrlToOpenInWebRemoteOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/GetUrlToOpenInWebRemoteOperation.kt new file mode 100644 index 00000000..b36cb760 --- /dev/null +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/GetUrlToOpenInWebRemoteOperation.kt @@ -0,0 +1,98 @@ +/* ownCloud Android Library is available under MIT license +* Copyright (C) 2022 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.files + +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.owncloud.android.lib.resources.files.GetUrlToOpenInWebRemoteOperation.OpenInWebParams.Companion.PARAM_FILE_ID +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 GetUrlToOpenInWebRemoteOperation( + val openWithWebEndpoint: String, + val fileId: String, +) : RemoteOperation() { + + override fun run(client: OwnCloudClient): RemoteOperationResult { + return try { + + val openInWebRequestBody = OpenInWebParams(fileId).toRequestBody() + + val stringUrl = client.baseUri.toString() + WebdavUtils.encodePath(openWithWebEndpoint) + "?$PARAM_FILE_ID=$fileId" + + val postMethod = PostMethod(URL(stringUrl), openInWebRequestBody).apply { + setReadTimeout(TIMEOUT, TimeUnit.MILLISECONDS) + setConnectionTimeout(TIMEOUT, TimeUnit.MILLISECONDS) + } + + val status = client.executeHttpMethod(postMethod) + Timber.d("Open in web for file: $fileId - $status${if (!isSuccess(status)) "(FAIL)" else ""}") + + if (isSuccess(status)) RemoteOperationResult(ResultCode.OK).apply { + val moshi = Moshi.Builder().build() + val adapter: JsonAdapter = moshi.adapter(OpenInWebResponse::class.java) + + data = postMethod.getResponseBodyAsString()?.let { adapter.fromJson(it)!!.uri } + } + else RemoteOperationResult(postMethod).apply { data = "" } + + } catch (e: Exception) { + val result = RemoteOperationResult(e) + Timber.e(e, "Open in web for file: $fileId failed") + result + } + } + + private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK || status == HttpConstants.HTTP_MULTI_STATUS + + data class OpenInWebParams(val fileId: String) { + fun toRequestBody(): RequestBody = + FormBody.Builder().build() + + companion object { + const val PARAM_FILE_ID = "file_id" + } + } + + @JsonClass(generateAdapter = true) + data class OpenInWebResponse(val uri: String) + + companion object { + /** + * Maximum time to wait for a response from the server in milliseconds. + */ + private const val TIMEOUT = 5_000L + } +} From 6282fbd419c95fbe58afabf5d8a685cf5ee6625d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abel=20Garc=C3=ADa=20de=20Prada?= Date: Wed, 24 Aug 2022 11:37:12 +0200 Subject: [PATCH 3/5] Add the open in web to the service facade --- .../android/lib/resources/files/services/FileService.kt | 1 + .../resources/files/services/implementation/OCFileService.kt | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/services/FileService.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/services/FileService.kt index 4296fa54..4de85052 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/services/FileService.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/services/FileService.kt @@ -28,4 +28,5 @@ import com.owncloud.android.lib.resources.Service interface FileService : Service { fun checkPathExistence(path: String, isUserLogged: Boolean): RemoteOperationResult + fun getUrlToOpenInWeb(openWebEndpoint: String, fileId: String): RemoteOperationResult } diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/services/implementation/OCFileService.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/services/implementation/OCFileService.kt index 522a5ac4..b0670a9f 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/services/implementation/OCFileService.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/services/implementation/OCFileService.kt @@ -26,6 +26,7 @@ package com.owncloud.android.lib.resources.files.services.implementation import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.resources.files.CheckPathExistenceRemoteOperation +import com.owncloud.android.lib.resources.files.GetUrlToOpenInWebRemoteOperation import com.owncloud.android.lib.resources.files.services.FileService class OCFileService(override val client: OwnCloudClient) : @@ -35,4 +36,8 @@ class OCFileService(override val client: OwnCloudClient) : remotePath = path, isUserLoggedIn = isUserLogged ).execute(client) + + override fun getUrlToOpenInWeb(openWebEndpoint: String, fileId: String): RemoteOperationResult = + GetUrlToOpenInWebRemoteOperation(openWithWebEndpoint = openWebEndpoint, fileId = fileId).execute(client) + } From 32ef5d21250f0b41e191984a217a1a1246d7cf7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abel=20Garc=C3=ADa=20de=20Prada?= Date: Thu, 25 Aug 2022 08:41:27 +0200 Subject: [PATCH 4/5] Add a new capability to allow/disallow private links --- .../owncloud/android/lib/resources/status/RemoteCapability.kt | 3 ++- .../lib/resources/status/responses/CapabilityResponse.kt | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/RemoteCapability.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/RemoteCapability.kt index 2f9f3f86..ff7f5b4f 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/RemoteCapability.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/RemoteCapability.kt @@ -67,7 +67,8 @@ data class RemoteCapability( var filesBigFileChunking: CapabilityBooleanType = CapabilityBooleanType.UNKNOWN, var filesUndelete: CapabilityBooleanType = CapabilityBooleanType.UNKNOWN, var filesVersioning: CapabilityBooleanType = CapabilityBooleanType.UNKNOWN, - val remoteOcisProviders: List?, + val filesPrivateLinks: CapabilityBooleanType = CapabilityBooleanType.UNKNOWN, + val filesAppProviders: List?, ) { /** * Enum for Boolean Type in capabilities, with values: diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt index 82a1bca7..b71ac2ec 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt @@ -69,7 +69,8 @@ data class CapabilityResponse( filesBigFileChunking = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.bigfilechunking), filesUndelete = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.undelete), filesVersioning = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.versioning), - remoteOcisProviders = capabilities?.fileCapabilities?.appProviders?.map { it.toOCISProvider() }, + filesPrivateLinks = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.privateLinks), + filesAppProviders = capabilities?.fileCapabilities?.appProviders?.map { it.toOCISProvider() }, filesSharingFederationIncoming = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingFederation?.incoming), filesSharingFederationOutgoing = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingFederation?.outgoing), filesSharingUserProfilePicture = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingUser?.profilePicture), @@ -163,6 +164,7 @@ data class FileCapabilities( val bigfilechunking: Boolean?, val undelete: Boolean?, val versioning: Boolean?, + val privateLinks: Boolean?, @Json(name = "app_providers") val appProviders: List? ) From 0be462c9aacb239d88a6d6b84e09a3ca927b83e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abel=20Garc=C3=ADa=20de=20Prada?= Date: Mon, 29 Aug 2022 13:09:35 +0200 Subject: [PATCH 5/5] Set private link capability to unknown type when it is not retrieved The CapabilityBooleanType.fromBooleanValue set it to FALSE when the capability is not retrieved. We don't want this for this case. Probably neither for the rest, but changing that now would need deeper testing --- .../lib/resources/status/responses/CapabilityResponse.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt index b71ac2ec..d4000b93 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt @@ -69,7 +69,7 @@ data class CapabilityResponse( filesBigFileChunking = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.bigfilechunking), filesUndelete = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.undelete), filesVersioning = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.versioning), - filesPrivateLinks = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.privateLinks), + filesPrivateLinks = capabilities?.fileCapabilities?.privateLinks?.let { CapabilityBooleanType.fromBooleanValue(it) } ?: CapabilityBooleanType.UNKNOWN, filesAppProviders = capabilities?.fileCapabilities?.appProviders?.map { it.toOCISProvider() }, filesSharingFederationIncoming = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingFederation?.incoming), filesSharingFederationOutgoing = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingFederation?.outgoing),