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 + } +} 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) + } 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..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 @@ -66,7 +66,9 @@ 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 filesPrivateLinks: CapabilityBooleanType = CapabilityBooleanType.UNKNOWN, + val filesAppProviders: List?, ) { /** * Enum for Boolean Type in capabilities, with values: @@ -98,4 +100,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..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 @@ -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,8 @@ data class CapabilityResponse( filesBigFileChunking = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.bigfilechunking), filesUndelete = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.undelete), filesVersioning = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.versioning), + 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), filesSharingUserProfilePicture = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingUser?.profilePicture), @@ -160,9 +163,28 @@ data class FileSharingUser( data class FileCapabilities( val bigfilechunking: Boolean?, val undelete: Boolean?, - val versioning: Boolean? + val versioning: Boolean?, + val privateLinks: 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?