diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavUtils.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavUtils.kt index 22e1981f..a48626d3 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavUtils.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavUtils.kt @@ -26,10 +26,11 @@ package com.owncloud.android.lib.common.http.methods.webdav import at.bitfire.dav4jvm.Property import at.bitfire.dav4jvm.PropertyUtils.getAllPropSet import at.bitfire.dav4jvm.PropertyUtils.getQuotaPropset +import com.owncloud.android.lib.common.http.methods.webdav.properties.OCShareTypes object DavUtils { @JvmStatic val allPropset: Array - get() = getAllPropSet() + get() = getAllPropSet().plus(OCShareTypes.NAME) val quotaPropSet: Array get() = getQuotaPropset() diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/properties/OCShareTypes.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/properties/OCShareTypes.kt new file mode 100644 index 00000000..6111cc17 --- /dev/null +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/properties/OCShareTypes.kt @@ -0,0 +1,44 @@ +/* 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.common.http.methods.webdav.properties + +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.XmlUtils +import org.xmlpull.v1.XmlPullParser + +class OCShareTypes : ShareTypeListProperty() { + + class Factory : ShareTypeListProperty.Factory() { + + override fun create(parser: XmlPullParser) = + create(parser, OCShareTypes()) + + override fun getName(): Property.Name = NAME + } + + companion object { + @JvmField + val NAME = Property.Name(XmlUtils.NS_OWNCLOUD, "share-types") + } +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/properties/ShareTypeListProperty.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/properties/ShareTypeListProperty.kt new file mode 100644 index 00000000..5dd008f2 --- /dev/null +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/properties/ShareTypeListProperty.kt @@ -0,0 +1,46 @@ +/* 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.common.http.methods.webdav.properties + +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils +import org.xmlpull.v1.XmlPullParser +import java.util.LinkedList + +abstract class ShareTypeListProperty : Property { + + val shareTypes = LinkedList() + + override fun toString() = "share types =[" + shareTypes.joinToString(", ") + "]" + + abstract class Factory : PropertyFactory { + + fun create(parser: XmlPullParser, list: ShareTypeListProperty): ShareTypeListProperty { + XmlUtils.readTextPropertyList(parser, Property.Name(XmlUtils.NS_OWNCLOUD, "share-type"), list.shareTypes) + return list + } + + } +} 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/ReadRemoteFolderOperation.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java index e10613b3..bf6a0604 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java @@ -24,6 +24,7 @@ package com.owncloud.android.lib.resources.files; +import at.bitfire.dav4jvm.PropertyRegistry; import at.bitfire.dav4jvm.Response; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.accounts.AccountUtils; @@ -31,6 +32,7 @@ import com.owncloud.android.lib.common.http.HttpConstants; import com.owncloud.android.lib.common.http.methods.webdav.DavConstants; import com.owncloud.android.lib.common.http.methods.webdav.DavUtils; import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod; +import com.owncloud.android.lib.common.http.methods.webdav.properties.OCShareTypes; import com.owncloud.android.lib.common.network.WebdavUtils; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; @@ -72,6 +74,7 @@ public class ReadRemoteFolderOperation extends RemoteOperation> result = null; try { + PropertyRegistry.INSTANCE.register(OCShareTypes.Factory.class.newInstance()); PropfindMethod propfindMethod = new PropfindMethod( new URL(client.getUserFilesWebDavUri() + WebdavUtils.encodePath(mRemotePath)), DavConstants.DEPTH_1, diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/RemoteFile.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/RemoteFile.java index 0557f99e..84a48bcd 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/RemoteFile.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/RemoteFile.java @@ -40,10 +40,14 @@ import at.bitfire.dav4jvm.property.OCPrivatelink; import at.bitfire.dav4jvm.property.OCSize; import at.bitfire.dav4jvm.property.QuotaAvailableBytes; import at.bitfire.dav4jvm.property.QuotaUsedBytes; +import com.owncloud.android.lib.common.http.methods.webdav.properties.OCShareTypes; +import com.owncloud.android.lib.resources.shares.ShareType; +import timber.log.Timber; import java.io.File; import java.io.Serializable; import java.math.BigDecimal; +import java.util.LinkedList; import java.util.List; /** @@ -85,6 +89,8 @@ public class RemoteFile implements Parcelable, Serializable { private BigDecimal mQuotaUsedBytes; private BigDecimal mQuotaAvailableBytes; private String mPrivateLink; + private boolean mSharedByLink; + private boolean mSharedWithSharee; public RemoteFile() { resetData(); @@ -153,6 +159,23 @@ public class RemoteFile implements Parcelable, Serializable { if (property instanceof OCPrivatelink) { this.setPrivateLink(((OCPrivatelink) property).getLink()); } + if (property instanceof OCShareTypes) { + LinkedList list = ((OCShareTypes) property).getShareTypes(); + for (int i = 0; i < list.size(); i++) { + ShareType shareType = ShareType.Companion.fromValue(Integer.parseInt(list.get(i))); + if (shareType == null) { + Timber.d("Illegal share type value: " + list.get(i)); + continue; + } + if (shareType.equals(ShareType.PUBLIC_LINK)) { + this.setSharedViaLink(true); + } else if (shareType.equals(ShareType.USER) || + shareType.equals(ShareType.FEDERATED) || + shareType.equals(ShareType.GROUP)) { + this.setSharedWithSharee(true); + } + } + } } } @@ -266,6 +289,22 @@ public class RemoteFile implements Parcelable, Serializable { mPrivateLink = privateLink; } + public void setSharedWithSharee(boolean shareWithSharee) { + mSharedWithSharee = shareWithSharee; + } + + public boolean isSharedWithSharee() { + return mSharedWithSharee; + } + + public void setSharedViaLink(boolean sharedViaLink) { + mSharedByLink = sharedViaLink; + } + + public boolean isSharedByLink() { + return mSharedByLink; + } + /** * Used internally. Reset all file properties */ @@ -282,6 +321,8 @@ public class RemoteFile implements Parcelable, Serializable { mQuotaUsedBytes = null; mQuotaAvailableBytes = null; mPrivateLink = null; + mSharedWithSharee = false; + mSharedByLink = false; } public void readFromParcel(Parcel source) { @@ -319,4 +360,4 @@ public class RemoteFile implements Parcelable, Serializable { dest.writeSerializable(mQuotaAvailableBytes); dest.writeString(mPrivateLink); } -} \ No newline at end of file +} 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?