From 3399d998456a6e9699b5aaf697492eda081f9b91 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 9 Apr 2025 16:46:15 +0200 Subject: [PATCH 01/15] add attributes Signed-off-by: alperozturk --- .../com/owncloud/android/lib/resources/shares/OCShare.kt | 4 ++++ .../android/lib/resources/shares/ShareXMLParser.java | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt index 31aacfa9b4..50010ff080 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt @@ -73,6 +73,7 @@ class OCShare : var ownerDisplayName: String? = null var isFavorite = false var fileDownloadLimit: FileDownloadLimit? = null + var attributes: String? = null constructor() : super() { resetData() @@ -114,6 +115,7 @@ class OCShare : mimetype = "" ownerDisplayName = "" fileDownloadLimit = null + attributes = null } /** @@ -154,6 +156,7 @@ class OCShare : mimetype = source.readString() ownerDisplayName = source.readString() fileDownloadLimit = source.readSerializableCompat() + attributes = source.readString() } override fun describeContents(): Int = this.hashCode() @@ -184,6 +187,7 @@ class OCShare : dest.writeString(mimetype) dest.writeString(ownerDisplayName) dest.writeSerializable(fileDownloadLimit) + dest.writeString(attributes) } companion object { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java b/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java index ad7d08c49f..14635989b4 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java @@ -12,6 +12,7 @@ import android.util.Xml; import com.owncloud.android.lib.common.network.WebdavUtils; +import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.files.FileUtils; import org.xmlpull.v1.XmlPullParser; @@ -70,8 +71,9 @@ public class ShareXMLParser { private static final String NODE_DISPLAYNAME_FILE_OWNER = "displayname_file_owner"; private static final String NODE_TAGS = "tags"; private static final String NODE_URL = "url"; + private static final String NODE_ATTRIBUTES = "attributes"; - private static final String TAG_FAVORITE = "_$!"; + private static final String TAG_FAVORITE = "_$!"; private static final String TYPE_FOLDER = "folder"; @@ -418,6 +420,10 @@ private void readElement(XmlPullParser parser, ArrayList shares) } break; + case NODE_ATTRIBUTES: + final var aa = readNode(parser, NODE_ATTRIBUTES); + Log_OC.d("asdas","asdasd: "+ aa); + default: skip(parser); break; From 9826f682b837e7d22166b2029ded382ad15bc15d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 10 Apr 2025 10:49:06 +0200 Subject: [PATCH 02/15] add attributes Signed-off-by: alperozturk --- library/build.gradle | 3 + .../android/lib/resources/shares/OCShare.kt | 10 +++ .../lib/resources/shares/ShareXMLParser.java | 8 ++- .../shares/attributes/ShareAttributes.kt | 21 ++++++ .../attributes/ShareAttributesJsonParser.kt | 28 ++++++++ .../attributes/ShareAttributesSerializer.kt | 69 +++++++++++++++++++ 6 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonParser.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt diff --git a/library/build.gradle b/library/build.gradle index 404df25c31..9e12cbb126 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -29,6 +29,7 @@ buildscript { } plugins { + id "org.jetbrains.kotlin.plugin.serialization" version "2.1.20" id "com.diffplug.spotless" version "7.0.3" } @@ -59,6 +60,8 @@ configurations { } dependencies { + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0" + implementation 'org.apache.jackrabbit:jackrabbit-webdav:2.13.5' api 'com.squareup.okhttp3:okhttp:5.0.0-alpha.14' implementation 'com.github.bitfireAT:dav4jvm:2.2.1' diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt index 50010ff080..82c1b8a570 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt @@ -73,6 +73,16 @@ class OCShare : var ownerDisplayName: String? = null var isFavorite = false var fileDownloadLimit: FileDownloadLimit? = null + + /** + * Field to store raw JSON data representing advanced share attributes. + * + * The `attributes` field stores the share attributes as a raw JSON string, allowing for flexible handling + * of versioned responses (V1 and V2). The `ShareAttributesSerializer` is used for serialization and + * deserialization. Storing as a `String` prevents complex parcel write/read logic associated with + * `kotlinx.serialization` and ensures compatibility with the Nextcloud API, which requires raw JSON for + * requests and responses. + */ var attributes: String? = null constructor() : super() { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java b/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java index 14635989b4..3032b03f8d 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java @@ -12,7 +12,6 @@ import android.util.Xml; import com.owncloud.android.lib.common.network.WebdavUtils; -import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.files.FileUtils; import org.xmlpull.v1.XmlPullParser; @@ -25,6 +24,7 @@ import java.util.Date; import java.util.List; + /** * Parser for Share API Response * @@ -421,8 +421,10 @@ private void readElement(XmlPullParser parser, ArrayList shares) break; case NODE_ATTRIBUTES: - final var aa = readNode(parser, NODE_ATTRIBUTES); - Log_OC.d("asdas","asdasd: "+ aa); + final var rawAttributesString = readText(parser); + // final var attributes = ShareAttributesJsonParser.INSTANCE.parseJson(rawAttributesString); + share.setAttributes(rawAttributesString); + break; default: skip(parser); diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt new file mode 100644 index 0000000000..0c75a7cc80 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt @@ -0,0 +1,21 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Your Name + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.lib.resources.shares.attributes + +import kotlinx.serialization.Serializable + +@Serializable(with = ShareAttributesSerializer::class) +data class ShareAttributes( + val scope: String, + val key: String, + var isEnabled: Boolean +) + +fun List?.getDownloadAttribute(): ShareAttributes? { + return this?.find { it.key == "download" } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonParser.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonParser.kt new file mode 100644 index 0000000000..979e71c2b5 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonParser.kt @@ -0,0 +1,28 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.lib.resources.shares.attributes + +import kotlinx.serialization.json.Json + +object ShareAttributesJsonHandler { + private val json = Json { ignoreUnknownKeys = true } + + /** + * Parses a JSON string into a list of `ShareAttributes` objects. + */ + fun parseJson(jsonString: String): List { + return json.decodeFromString(jsonString) + } + + /** + * Converts a list of `ShareAttributes` objects into a JSON string. + */ + fun toJson(shareAttributes: List): String { + return json.encodeToString(shareAttributes) + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt new file mode 100644 index 0000000000..7981569ca7 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt @@ -0,0 +1,69 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Your Name + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.lib.resources.shares.attributes + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerializationException +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.JsonDecoder +import kotlinx.serialization.json.JsonEncoder +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.booleanOrNull +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive + +/** + * Custom serializer for the ShareAttributes class. + * This handles the deserialization and serialization of the ShareAttributes data class. + * Since Nextcloud 30, the enabled key have bee renamed to value and supports more than boolean. + */ +object ShareAttributesSerializer : KSerializer { + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("ShareAttributes") { + element("scope", PrimitiveSerialDescriptor("scope", PrimitiveKind.STRING)) + element("key", PrimitiveSerialDescriptor("key", PrimitiveKind.STRING)) + element("enabled", PrimitiveSerialDescriptor("enabled", PrimitiveKind.BOOLEAN), isOptional = true) + element("value", PrimitiveSerialDescriptor("value", PrimitiveKind.BOOLEAN), isOptional = true) + } + + override fun deserialize(decoder: Decoder): ShareAttributes { + val input = decoder as? JsonDecoder + ?: throw SerializationException("Expected JsonDecoder") + + val jsonObject = input.decodeJsonElement().jsonObject + val scope = jsonObject["scope"]?.jsonPrimitive?.content + ?: throw SerializationException("Missing 'scope'") + val key = jsonObject["key"]?.jsonPrimitive?.content + ?: throw SerializationException("Missing 'key'") + + // Check for the 'enabled' or 'value' field. If neither is found, throw an exception. + val isEnabled = jsonObject["enabled"]?.jsonPrimitive?.booleanOrNull + ?: jsonObject["value"]?.jsonPrimitive?.booleanOrNull + ?: throw SerializationException("Missing 'enabled' or 'value'") + + return ShareAttributes(scope, key, isEnabled) + } + + override fun serialize(encoder: Encoder, value: ShareAttributes) { + val output = encoder as? JsonEncoder + ?: throw SerializationException("Expected JsonEncoder") + + val json = buildJsonObject { + put("scope", JsonPrimitive(value.scope)) + put("key", JsonPrimitive(value.key)) + put("value", JsonPrimitive(value.isEnabled)) + } + + output.encodeJsonElement(json) + } +} From 1fd0c184ae7755e4287775b592d21d623997e479 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 10 Apr 2025 10:50:29 +0200 Subject: [PATCH 03/15] fix code analytics Signed-off-by: alperozturk --- .../shares/attributes/ShareAttributes.kt | 4 +- ...arser.kt => ShareAttributesJsonHandler.kt} | 8 +-- .../attributes/ShareAttributesSerializer.kt | 56 +++++++++++-------- 3 files changed, 36 insertions(+), 32 deletions(-) rename library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/{ShareAttributesJsonParser.kt => ShareAttributesJsonHandler.kt} (68%) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt index 0c75a7cc80..61dd9c1b19 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt @@ -16,6 +16,4 @@ data class ShareAttributes( var isEnabled: Boolean ) -fun List?.getDownloadAttribute(): ShareAttributes? { - return this?.find { it.key == "download" } -} +fun List?.getDownloadAttribute(): ShareAttributes? = this?.find { it.key == "download" } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonParser.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonHandler.kt similarity index 68% rename from library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonParser.kt rename to library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonHandler.kt index 979e71c2b5..1f71877f75 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonParser.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonHandler.kt @@ -15,14 +15,10 @@ object ShareAttributesJsonHandler { /** * Parses a JSON string into a list of `ShareAttributes` objects. */ - fun parseJson(jsonString: String): List { - return json.decodeFromString(jsonString) - } + fun parseJson(jsonString: String): List = json.decodeFromString(jsonString) /** * Converts a list of `ShareAttributes` objects into a JSON string. */ - fun toJson(shareAttributes: List): String { - return json.encodeToString(shareAttributes) - } + fun toJson(shareAttributes: List): String = json.encodeToString(shareAttributes) } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt index 7981569ca7..be5f2e2284 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt @@ -29,40 +29,50 @@ import kotlinx.serialization.json.jsonPrimitive * Since Nextcloud 30, the enabled key have bee renamed to value and supports more than boolean. */ object ShareAttributesSerializer : KSerializer { - override val descriptor: SerialDescriptor = buildClassSerialDescriptor("ShareAttributes") { - element("scope", PrimitiveSerialDescriptor("scope", PrimitiveKind.STRING)) - element("key", PrimitiveSerialDescriptor("key", PrimitiveKind.STRING)) - element("enabled", PrimitiveSerialDescriptor("enabled", PrimitiveKind.BOOLEAN), isOptional = true) - element("value", PrimitiveSerialDescriptor("value", PrimitiveKind.BOOLEAN), isOptional = true) - } + override val descriptor: SerialDescriptor = + buildClassSerialDescriptor("ShareAttributes") { + element("scope", PrimitiveSerialDescriptor("scope", PrimitiveKind.STRING)) + element("key", PrimitiveSerialDescriptor("key", PrimitiveKind.STRING)) + element("enabled", PrimitiveSerialDescriptor("enabled", PrimitiveKind.BOOLEAN), isOptional = true) + element("value", PrimitiveSerialDescriptor("value", PrimitiveKind.BOOLEAN), isOptional = true) + } override fun deserialize(decoder: Decoder): ShareAttributes { - val input = decoder as? JsonDecoder - ?: throw SerializationException("Expected JsonDecoder") + val input = + decoder as? JsonDecoder + ?: throw SerializationException("Expected JsonDecoder") val jsonObject = input.decodeJsonElement().jsonObject - val scope = jsonObject["scope"]?.jsonPrimitive?.content - ?: throw SerializationException("Missing 'scope'") - val key = jsonObject["key"]?.jsonPrimitive?.content - ?: throw SerializationException("Missing 'key'") + val scope = + jsonObject["scope"]?.jsonPrimitive?.content + ?: throw SerializationException("Missing 'scope'") + val key = + jsonObject["key"]?.jsonPrimitive?.content + ?: throw SerializationException("Missing 'key'") // Check for the 'enabled' or 'value' field. If neither is found, throw an exception. - val isEnabled = jsonObject["enabled"]?.jsonPrimitive?.booleanOrNull - ?: jsonObject["value"]?.jsonPrimitive?.booleanOrNull - ?: throw SerializationException("Missing 'enabled' or 'value'") + val isEnabled = + jsonObject["enabled"]?.jsonPrimitive?.booleanOrNull + ?: jsonObject["value"]?.jsonPrimitive?.booleanOrNull + ?: throw SerializationException("Missing 'enabled' or 'value'") return ShareAttributes(scope, key, isEnabled) } - override fun serialize(encoder: Encoder, value: ShareAttributes) { - val output = encoder as? JsonEncoder - ?: throw SerializationException("Expected JsonEncoder") + override fun serialize( + encoder: Encoder, + value: ShareAttributes + ) { + val output = + encoder as? JsonEncoder + ?: throw SerializationException("Expected JsonEncoder") - val json = buildJsonObject { - put("scope", JsonPrimitive(value.scope)) - put("key", JsonPrimitive(value.key)) - put("value", JsonPrimitive(value.isEnabled)) - } + val json = + buildJsonObject { + put("scope", JsonPrimitive(value.scope)) + put("key", JsonPrimitive(value.key)) + put("value", JsonPrimitive(value.isEnabled)) + } output.encodeJsonElement(json) } From af3d5d7544e1d20f1d1fe0f0bc5326af1e551c8d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 10 Apr 2025 11:02:51 +0200 Subject: [PATCH 04/15] update file operations Signed-off-by: alperozturk --- .../shares/CreateShareRemoteOperationIT.kt | 3 ++- .../shares/UpdateShareRemoteOperationIT.kt | 3 ++- .../shares/CreateShareRemoteOperation.java | 20 ++++++++++++++----- .../shares/UpdateShareRemoteOperation.java | 10 ++++++++++ .../shares/attributes/ShareAttributes.kt | 6 ++++++ 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt index 06bfbe7017..21353332b3 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt @@ -49,7 +49,8 @@ class CreateShareRemoteOperationIT : AbstractIT() { "", OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER, true, - note + note, + null ).execute(client) junit.framework.Assert.assertTrue(sut.isSuccess) diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperationIT.kt index 368d9dc59f..dae6aa80e2 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperationIT.kt @@ -57,7 +57,8 @@ class UpdateShareRemoteOperationIT : AbstractIT() { "", OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER, true, - "" + "", + null ).execute(client) assertTrue(createOperationResult.isSuccess) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperation.java index 0ef9a46e98..622d21e43c 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperation.java @@ -37,6 +37,7 @@ public class CreateShareRemoteOperation extends RemoteOperation> { private static final String PARAM_PASSWORD = "password"; private static final String PARAM_PERMISSIONS = "permissions"; private static final String PARAM_NOTE = "note"; + private static final String PARAM_ATTRIBUTES = "attributes"; private final String remoteFilePath; private final ShareType shareType; @@ -46,6 +47,7 @@ public class CreateShareRemoteOperation extends RemoteOperation> { private final int permissions; private boolean getShareDetails; private String note; + private String attributes; /** * Constructor @@ -67,6 +69,7 @@ public class CreateShareRemoteOperation extends RemoteOperation> { * For user or group shares. * To obtain combinations, add the desired values together. * For instance, for Re-Share, delete, read, update, add 16+8+2+1 = 27. + * @param attributes Share attributes are used for more advanced flags like permissions. */ public CreateShareRemoteOperation( String remoteFilePath, @@ -76,7 +79,8 @@ public CreateShareRemoteOperation( String password, int permissions, boolean getShareDetails, - String note + String note, + String attributes ) { this.remoteFilePath = remoteFilePath; this.shareType = shareType; @@ -86,6 +90,7 @@ public CreateShareRemoteOperation( this.permissions = permissions; this.getShareDetails = getShareDetails; // defaults to false for backwards compatibility this.note = note; + this.attributes = attributes; } public CreateShareRemoteOperation( @@ -95,7 +100,7 @@ public CreateShareRemoteOperation( boolean publicUpload, String password, int permissions) { - this(remoteFilePath, shareType, shareWith, publicUpload, password, permissions, false, ""); + this(remoteFilePath, shareType, shareWith, publicUpload, password, permissions, false, "", null); } public CreateShareRemoteOperation( @@ -105,8 +110,9 @@ public CreateShareRemoteOperation( boolean publicUpload, String password, int permissions, - String note) { - this(remoteFilePath, shareType, shareWith, publicUpload, password, permissions, false, note); + String note, + String attributes) { + this(remoteFilePath, shareType, shareWith, publicUpload, password, permissions, false, note, attributes); } public CreateShareRemoteOperation( @@ -117,7 +123,7 @@ public CreateShareRemoteOperation( String password, int permissions, boolean getShareDetails) { - this(remoteFilePath, shareType, shareWith, publicUpload, password, permissions, getShareDetails, ""); + this(remoteFilePath, shareType, shareWith, publicUpload, password, permissions, getShareDetails, "", null); } public boolean isGettingShareDetails() { @@ -158,6 +164,10 @@ protected RemoteOperationResult> run(OwnCloudClient client) { post.addParameter(PARAM_NOTE, note); } + if (!TextUtils.isEmpty(attributes)) { + post.addParameter(PARAM_ATTRIBUTES, attributes); + } + post.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE); status = client.executeMethod(post); diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperation.java index 830a677249..826c772848 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperation.java @@ -49,6 +49,7 @@ public class UpdateShareRemoteOperation extends RemoteOperation { private static final String FORMAT_EXPIRATION_DATE = "yyyy-MM-dd"; private static final String ENTITY_CONTENT_TYPE = "application/x-www-form-urlencoded"; private static final String ENTITY_CHARSET = "UTF-8"; + private static final String PARAM_ATTRIBUTES = "attributes"; /** @@ -78,6 +79,7 @@ public class UpdateShareRemoteOperation extends RemoteOperation { private String note; private String label; + private String attributes; /** @@ -137,6 +139,10 @@ public void setLabel(String label) { this.label = label; } + public void setAttributes(String attributes) { + this.attributes = attributes; + } + public void setNote(String note) { this.note = note; } @@ -181,6 +187,10 @@ protected RemoteOperationResult> run(OwnCloudClient client) { parametersToUpdate.add(new Pair<>(PARAM_LABEL, URLEncoder.encode(label))); } + if (attributes != null) { + parametersToUpdate.add(new Pair<>(PARAM_ATTRIBUTES, URLEncoder.encode(attributes))); + } + /// perform required PUT requests PutMethod put = null; String uriString; diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt index 61dd9c1b19..b962f7f598 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt @@ -9,6 +9,12 @@ package com.owncloud.android.lib.resources.shares.attributes import kotlinx.serialization.Serializable +/** + * Share attributes are used for more advanced flags like permissions. + * + * + * https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html#share-attributes + */ @Serializable(with = ShareAttributesSerializer::class) data class ShareAttributes( val scope: String, From db030498cc8553e9a12fc572ed9eb17993915871 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 10 Apr 2025 11:05:38 +0200 Subject: [PATCH 05/15] update doc Signed-off-by: alperozturk --- .../java/com/owncloud/android/lib/resources/shares/OCShare.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt index 82c1b8a570..b2fd77a5aa 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt @@ -80,8 +80,10 @@ class OCShare : * The `attributes` field stores the share attributes as a raw JSON string, allowing for flexible handling * of versioned responses (V1 and V2). The `ShareAttributesSerializer` is used for serialization and * deserialization. Storing as a `String` prevents complex parcel write/read logic associated with - * `kotlinx.serialization` and ensures compatibility with the Nextcloud API, which requires raw JSON for + * `kotlinx.serialization` and provides compatibility with the Share API, which requires raw JSON for * requests and responses. + * + * https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html#share-attributes */ var attributes: String? = null From d5fcb1c911665fe0abc04dec1b2af4e776feb7c0 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 10 Apr 2025 11:06:58 +0200 Subject: [PATCH 06/15] update doc Signed-off-by: alperozturk --- .../owncloud/android/lib/resources/shares/ShareXMLParser.java | 3 +-- .../android/lib/resources/shares/attributes/ShareAttributes.kt | 2 +- .../resources/shares/attributes/ShareAttributesSerializer.kt | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java b/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java index 3032b03f8d..79579ba411 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java @@ -73,7 +73,7 @@ public class ShareXMLParser { private static final String NODE_URL = "url"; private static final String NODE_ATTRIBUTES = "attributes"; - private static final String TAG_FAVORITE = "_$!"; + private static final String TAG_FAVORITE = "_$!"; private static final String TYPE_FOLDER = "folder"; @@ -422,7 +422,6 @@ private void readElement(XmlPullParser parser, ArrayList shares) case NODE_ATTRIBUTES: final var rawAttributesString = readText(parser); - // final var attributes = ShareAttributesJsonParser.INSTANCE.parseJson(rawAttributesString); share.setAttributes(rawAttributesString); break; diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt index b962f7f598..5b0305f8dd 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt @@ -1,7 +1,7 @@ /* * Nextcloud - Android Client * - * SPDX-FileCopyrightText: 2025 Your Name + * SPDX-FileCopyrightText: 2025 Alper Ozturk * SPDX-License-Identifier: AGPL-3.0-or-later */ diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt index be5f2e2284..f8541f8e62 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt @@ -1,7 +1,7 @@ /* * Nextcloud - Android Client * - * SPDX-FileCopyrightText: 2025 Your Name + * SPDX-FileCopyrightText: 2025 Alper Ozturk * SPDX-License-Identifier: AGPL-3.0-or-later */ From c1b9257f60d713d037f4879976d138fbc027eced Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 10 Apr 2025 12:35:40 +0200 Subject: [PATCH 07/15] remove unnecessary logic Signed-off-by: alperozturk --- library/build.gradle | 3 - .../android/lib/resources/shares/OCShare.kt | 12 --- .../shares/attributes/ShareAttributes.kt | 4 - .../attributes/ShareAttributesJsonHandler.kt | 30 +++++--- .../attributes/ShareAttributesSerializer.kt | 75 ++++--------------- 5 files changed, 35 insertions(+), 89 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index 9e12cbb126..404df25c31 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -29,7 +29,6 @@ buildscript { } plugins { - id "org.jetbrains.kotlin.plugin.serialization" version "2.1.20" id "com.diffplug.spotless" version "7.0.3" } @@ -60,8 +59,6 @@ configurations { } dependencies { - implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0" - implementation 'org.apache.jackrabbit:jackrabbit-webdav:2.13.5' api 'com.squareup.okhttp3:okhttp:5.0.0-alpha.14' implementation 'com.github.bitfireAT:dav4jvm:2.2.1' diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt index b2fd77a5aa..50010ff080 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/OCShare.kt @@ -73,18 +73,6 @@ class OCShare : var ownerDisplayName: String? = null var isFavorite = false var fileDownloadLimit: FileDownloadLimit? = null - - /** - * Field to store raw JSON data representing advanced share attributes. - * - * The `attributes` field stores the share attributes as a raw JSON string, allowing for flexible handling - * of versioned responses (V1 and V2). The `ShareAttributesSerializer` is used for serialization and - * deserialization. Storing as a `String` prevents complex parcel write/read logic associated with - * `kotlinx.serialization` and provides compatibility with the Share API, which requires raw JSON for - * requests and responses. - * - * https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html#share-attributes - */ var attributes: String? = null constructor() : super() { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt index 5b0305f8dd..c0dedb9a8b 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt @@ -7,15 +7,11 @@ package com.owncloud.android.lib.resources.shares.attributes -import kotlinx.serialization.Serializable - /** * Share attributes are used for more advanced flags like permissions. * - * * https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html#share-attributes */ -@Serializable(with = ShareAttributesSerializer::class) data class ShareAttributes( val scope: String, val key: String, diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonHandler.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonHandler.kt index 1f71877f75..b0327762c2 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonHandler.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonHandler.kt @@ -7,18 +7,28 @@ package com.owncloud.android.lib.resources.shares.attributes -import kotlinx.serialization.json.Json +import com.google.gson.GsonBuilder +import com.google.gson.reflect.TypeToken object ShareAttributesJsonHandler { - private val json = Json { ignoreUnknownKeys = true } + private val gson = GsonBuilder() + .registerTypeAdapter(ShareAttributes::class.java, ShareAttributesDeserializer()) + .create() - /** - * Parses a JSON string into a list of `ShareAttributes` objects. - */ - fun parseJson(jsonString: String): List = json.decodeFromString(jsonString) + fun toList(jsonString: String?): List? { + if (jsonString == null) { + return null + } - /** - * Converts a list of `ShareAttributes` objects into a JSON string. - */ - fun toJson(shareAttributes: List): String = json.encodeToString(shareAttributes) + val listType = object : TypeToken>() {}.type + return gson.fromJson(jsonString, listType) + } + + fun toJson(shareAttributes: List?): String? { + if (shareAttributes == null) { + return null + } + + return gson.toJson(shareAttributes) + } } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt index f8541f8e62..82eec1736f 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt @@ -7,73 +7,28 @@ package com.owncloud.android.lib.resources.shares.attributes -import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerializationException -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.descriptors.buildClassSerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import kotlinx.serialization.json.JsonDecoder -import kotlinx.serialization.json.JsonEncoder -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.booleanOrNull -import kotlinx.serialization.json.buildJsonObject -import kotlinx.serialization.json.jsonObject -import kotlinx.serialization.json.jsonPrimitive +import com.google.gson.JsonDeserializationContext +import com.google.gson.JsonDeserializer +import com.google.gson.JsonElement +import java.lang.reflect.Type /** * Custom serializer for the ShareAttributes class. * This handles the deserialization and serialization of the ShareAttributes data class. * Since Nextcloud 30, the enabled key have bee renamed to value and supports more than boolean. */ -object ShareAttributesSerializer : KSerializer { - override val descriptor: SerialDescriptor = - buildClassSerialDescriptor("ShareAttributes") { - element("scope", PrimitiveSerialDescriptor("scope", PrimitiveKind.STRING)) - element("key", PrimitiveSerialDescriptor("key", PrimitiveKind.STRING)) - element("enabled", PrimitiveSerialDescriptor("enabled", PrimitiveKind.BOOLEAN), isOptional = true) - element("value", PrimitiveSerialDescriptor("value", PrimitiveKind.BOOLEAN), isOptional = true) +class ShareAttributesDeserializer: JsonDeserializer { + override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): ShareAttributes? { + val jsonObject = json?.asJsonObject + val scope = jsonObject?.get("scope")?.asString ?: "" + val key = jsonObject?.get("key")?.asString ?: "" + + val status = when { + jsonObject?.has("enabled") == true -> jsonObject.get("enabled").asBoolean + jsonObject?.has("value") == true -> jsonObject.get("value").asBoolean + else -> false } - override fun deserialize(decoder: Decoder): ShareAttributes { - val input = - decoder as? JsonDecoder - ?: throw SerializationException("Expected JsonDecoder") - - val jsonObject = input.decodeJsonElement().jsonObject - val scope = - jsonObject["scope"]?.jsonPrimitive?.content - ?: throw SerializationException("Missing 'scope'") - val key = - jsonObject["key"]?.jsonPrimitive?.content - ?: throw SerializationException("Missing 'key'") - - // Check for the 'enabled' or 'value' field. If neither is found, throw an exception. - val isEnabled = - jsonObject["enabled"]?.jsonPrimitive?.booleanOrNull - ?: jsonObject["value"]?.jsonPrimitive?.booleanOrNull - ?: throw SerializationException("Missing 'enabled' or 'value'") - - return ShareAttributes(scope, key, isEnabled) - } - - override fun serialize( - encoder: Encoder, - value: ShareAttributes - ) { - val output = - encoder as? JsonEncoder - ?: throw SerializationException("Expected JsonEncoder") - - val json = - buildJsonObject { - put("scope", JsonPrimitive(value.scope)) - put("key", JsonPrimitive(value.key)) - put("value", JsonPrimitive(value.isEnabled)) - } - - output.encodeJsonElement(json) + return ShareAttributes(scope, key, status) } } From 06ae6af4e88c2074a843e175246aaa3c67b772cd Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 10 Apr 2025 12:36:54 +0200 Subject: [PATCH 08/15] clear doc Signed-off-by: alperozturk --- .../android/lib/resources/shares/ShareXMLParser.java | 3 +-- .../lib/resources/shares/attributes/ShareAttributes.kt | 5 ----- .../shares/attributes/ShareAttributesSerializer.kt | 10 ++++++++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java b/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java index 79579ba411..70c8de62f0 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java @@ -421,8 +421,7 @@ private void readElement(XmlPullParser parser, ArrayList shares) break; case NODE_ATTRIBUTES: - final var rawAttributesString = readText(parser); - share.setAttributes(rawAttributesString); + share.setAttributes(readText(parser)); break; default: diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt index c0dedb9a8b..f0a0a3dc9b 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt @@ -7,11 +7,6 @@ package com.owncloud.android.lib.resources.shares.attributes -/** - * Share attributes are used for more advanced flags like permissions. - * - * https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html#share-attributes - */ data class ShareAttributes( val scope: String, val key: String, diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt index 82eec1736f..c236cb467d 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt @@ -16,9 +16,15 @@ import java.lang.reflect.Type * Custom serializer for the ShareAttributes class. * This handles the deserialization and serialization of the ShareAttributes data class. * Since Nextcloud 30, the enabled key have bee renamed to value and supports more than boolean. + * + * https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html#share-attributes */ -class ShareAttributesDeserializer: JsonDeserializer { - override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): ShareAttributes? { +class ShareAttributesDeserializer : JsonDeserializer { + override fun deserialize( + json: JsonElement?, + typeOfT: Type?, + context: JsonDeserializationContext? + ): ShareAttributes? { val jsonObject = json?.asJsonObject val scope = jsonObject?.get("scope")?.asString ?: "" val key = jsonObject?.get("key")?.asString ?: "" From a2fe11e802707c072eaeaa762eeb76dbbd77b521 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 10 Apr 2025 14:24:46 +0200 Subject: [PATCH 09/15] fix potential crashes Signed-off-by: alperozturk --- .../extensions/JsonObjectExtensions.kt | 22 +++++++++++++++++++ .../shares/attributes/ShareAttributes.kt | 15 ++++++++++--- .../attributes/ShareAttributesSerializer.kt | 11 +++------- 3 files changed, 37 insertions(+), 11 deletions(-) create mode 100644 library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt diff --git a/library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt b/library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt new file mode 100644 index 0000000000..423a70065e --- /dev/null +++ b/library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt @@ -0,0 +1,22 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.extensions + +import com.google.gson.JsonObject + +fun JsonObject?.getBoolean(key: String): Boolean? { + if (this == null) { + return null + } + + if (has(key) && get(key).isJsonPrimitive) { + return get(key).asBoolean + } + + return null +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt index f0a0a3dc9b..652bc86b6b 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt @@ -10,7 +10,16 @@ package com.owncloud.android.lib.resources.shares.attributes data class ShareAttributes( val scope: String, val key: String, - var isEnabled: Boolean -) + var value: Boolean +) { + companion object { + const val DOWNLOAD_ATTRIBUTE_KEY = "download" -fun List?.getDownloadAttribute(): ShareAttributes? = this?.find { it.key == "download" } + fun createDownloadAttributes(value: Boolean): ShareAttributes { + return ShareAttributes(scope = "permissions", key = DOWNLOAD_ATTRIBUTE_KEY, value = value) + } + } +} + +fun List?.getDownloadAttribute(): ShareAttributes? = + this?.find { it.key == ShareAttributes.DOWNLOAD_ATTRIBUTE_KEY } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt index c236cb467d..d37c780cab 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt @@ -10,6 +10,7 @@ package com.owncloud.android.lib.resources.shares.attributes import com.google.gson.JsonDeserializationContext import com.google.gson.JsonDeserializer import com.google.gson.JsonElement +import com.nextcloud.extensions.getBoolean import java.lang.reflect.Type /** @@ -28,13 +29,7 @@ class ShareAttributesDeserializer : JsonDeserializer { val jsonObject = json?.asJsonObject val scope = jsonObject?.get("scope")?.asString ?: "" val key = jsonObject?.get("key")?.asString ?: "" - - val status = when { - jsonObject?.has("enabled") == true -> jsonObject.get("enabled").asBoolean - jsonObject?.has("value") == true -> jsonObject.get("value").asBoolean - else -> false - } - - return ShareAttributes(scope, key, status) + val value = (jsonObject.getBoolean("value") ?: jsonObject.getBoolean("enabled")) == true + return ShareAttributes(scope, key, value) } } From 5981cc501a43861d6e9a730dc47d50bc48cec04d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 10 Apr 2025 16:08:18 +0200 Subject: [PATCH 10/15] fix code analytics Signed-off-by: alperozturk --- .../java/com/nextcloud/extensions/JsonObjectExtensions.kt | 1 + .../lib/resources/shares/attributes/ShareAttributes.kt | 5 ++--- ...ributesSerializer.kt => ShareAttributesDeserializer.kt} | 2 +- .../shares/attributes/ShareAttributesJsonHandler.kt | 7 ++++--- 4 files changed, 8 insertions(+), 7 deletions(-) rename library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/{ShareAttributesSerializer.kt => ShareAttributesDeserializer.kt} (92%) diff --git a/library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt b/library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt index 423a70065e..9f92806b25 100644 --- a/library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt +++ b/library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt @@ -9,6 +9,7 @@ package com.nextcloud.extensions import com.google.gson.JsonObject +@Suppress("ReturnCount") fun JsonObject?.getBoolean(key: String): Boolean? { if (this == null) { return null diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt index 652bc86b6b..a746f29d44 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt @@ -15,9 +15,8 @@ data class ShareAttributes( companion object { const val DOWNLOAD_ATTRIBUTE_KEY = "download" - fun createDownloadAttributes(value: Boolean): ShareAttributes { - return ShareAttributes(scope = "permissions", key = DOWNLOAD_ATTRIBUTE_KEY, value = value) - } + fun createDownloadAttributes(value: Boolean): ShareAttributes = + ShareAttributes(scope = "permissions", key = DOWNLOAD_ATTRIBUTE_KEY, value = value) } } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesDeserializer.kt similarity index 92% rename from library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt rename to library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesDeserializer.kt index d37c780cab..157342f121 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesSerializer.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesDeserializer.kt @@ -16,7 +16,7 @@ import java.lang.reflect.Type /** * Custom serializer for the ShareAttributes class. * This handles the deserialization and serialization of the ShareAttributes data class. - * Since Nextcloud 30, the enabled key have bee renamed to value and supports more than boolean. + * Since Nextcloud 30, the enabled key have been renamed to value and supports more than boolean. * * https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html#share-attributes */ diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonHandler.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonHandler.kt index b0327762c2..d22b36501d 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonHandler.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonHandler.kt @@ -11,9 +11,10 @@ import com.google.gson.GsonBuilder import com.google.gson.reflect.TypeToken object ShareAttributesJsonHandler { - private val gson = GsonBuilder() - .registerTypeAdapter(ShareAttributes::class.java, ShareAttributesDeserializer()) - .create() + private val gson = + GsonBuilder() + .registerTypeAdapter(ShareAttributes::class.java, ShareAttributesDeserializer()) + .create() fun toList(jsonString: String?): List? { if (jsonString == null) { From 48f16c7a9f25789336fab753ba09bd34988362ad Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 6 May 2025 11:46:54 +0200 Subject: [PATCH 11/15] fix SPDX license Signed-off-by: alperozturk --- .../java/com/nextcloud/extensions/JsonObjectExtensions.kt | 5 +++-- .../lib/resources/shares/attributes/ShareAttributes.kt | 5 +++-- .../shares/attributes/ShareAttributesDeserializer.kt | 5 +++-- .../shares/attributes/ShareAttributesJsonHandler.kt | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt b/library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt index 9f92806b25..f721622828 100644 --- a/library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt +++ b/library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt @@ -1,8 +1,9 @@ /* - * Nextcloud - Android Client + * Nextcloud Android Library * + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2025 Alper Ozturk - * SPDX-License-Identifier: AGPL-3.0-or-later + * SPDX-License-Identifier: MIT */ package com.nextcloud.extensions diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt index a746f29d44..56c685e9fc 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributes.kt @@ -1,8 +1,9 @@ /* - * Nextcloud - Android Client + * Nextcloud Android Library * + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2025 Alper Ozturk - * SPDX-License-Identifier: AGPL-3.0-or-later + * SPDX-License-Identifier: MIT */ package com.owncloud.android.lib.resources.shares.attributes diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesDeserializer.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesDeserializer.kt index 157342f121..3457b1240a 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesDeserializer.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesDeserializer.kt @@ -1,8 +1,9 @@ /* - * Nextcloud - Android Client + * Nextcloud Android Library * + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2025 Alper Ozturk - * SPDX-License-Identifier: AGPL-3.0-or-later + * SPDX-License-Identifier: MIT */ package com.owncloud.android.lib.resources.shares.attributes diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonHandler.kt b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonHandler.kt index d22b36501d..50c4d5a68f 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonHandler.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/attributes/ShareAttributesJsonHandler.kt @@ -1,8 +1,9 @@ /* - * Nextcloud - Android Client + * Nextcloud Android Library * + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2025 Alper Ozturk - * SPDX-License-Identifier: AGPL-3.0-or-later + * SPDX-License-Identifier: MIT */ package com.owncloud.android.lib.resources.shares.attributes From cefe9bf2d2079617b350ba61604f65589df9b65e Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 6 May 2025 11:59:58 +0200 Subject: [PATCH 12/15] add attributes test Signed-off-by: alperozturk --- .../shares/CreateShareRemoteOperationIT.kt | 71 ++++++++++++------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt index 21353332b3..d213a8c126 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt @@ -9,11 +9,13 @@ package com.owncloud.android.lib.resources.shares import com.owncloud.android.AbstractIT import com.owncloud.android.lib.resources.files.CreateFolderRemoteOperation +import com.owncloud.android.lib.resources.shares.attributes.ShareAttributes +import com.owncloud.android.lib.resources.shares.attributes.ShareAttributesJsonHandler import com.owncloud.android.lib.resources.status.GetStatusRemoteOperation import com.owncloud.android.lib.resources.status.NextcloudVersion import com.owncloud.android.lib.resources.status.OwnCloudVersion -import org.junit.Assert import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Assume import org.junit.Before import org.junit.Test @@ -22,41 +24,58 @@ class CreateShareRemoteOperationIT : AbstractIT() { @Before fun before() { val result = GetStatusRemoteOperation(context).execute(client) - Assert.assertTrue(result.isSuccess) + assertTrue(result.isSuccess) val data = result.data as ArrayList val ownCloudVersion = data[0] as OwnCloudVersion Assume.assumeTrue(ownCloudVersion.isNewerOrEqual(NextcloudVersion.nextcloud_24)) } @Test - fun createShareWithNote() { - val note = "This is the note" - - Assert.assertTrue( - CreateFolderRemoteOperation( - "/share/", - true - ).execute(client).isSuccess + fun createShareWithNoteAndAttributes() { + val attributes = ShareAttributesJsonHandler.toJson( + listOf(ShareAttributes.createDownloadAttributes(true)) ) + val note = "Note with attributes" + val path = "/shareWithAttributes/" - // share folder to user "admin" - val sut = - CreateShareRemoteOperation( - "/share/", - ShareType.USER, - "admin", - false, - "", - OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER, - true, - note, - null - ).execute(client) - - junit.framework.Assert.assertTrue(sut.isSuccess) + createFolder(path) + val share = createShare(path, "admin", note, attributes) + assertEquals(note, share.note) + } - val share = sut.resultData[0] + @Test + fun createShareWithNote() { + val note = "This is the note" + val path = "/share/" + createFolder(path) + val share = createShare(path, "admin", note) assertEquals(note, share.note) } + + private fun createFolder(path: String) { + assertTrue(CreateFolderRemoteOperation(path, true).execute(client).isSuccess) + } + + private fun createShare( + path: String, + accountName: String, + note: String, + attributes: String? = null + ): OCShare { + val operation = CreateShareRemoteOperation( + path, + ShareType.USER, + accountName, + false, + "", + OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER, + true, + note, + attributes + ) + val result = operation.execute(client) + assertTrue(result.isSuccess) + return result.resultData[0] + } } From 8918f9b8945c307d428fe5e2825225a5a2ef3a07 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 6 May 2025 12:00:12 +0200 Subject: [PATCH 13/15] fix code analytics Signed-off-by: alperozturk --- .../shares/CreateShareRemoteOperationIT.kt | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt index d213a8c126..34d3fa0a23 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt @@ -32,9 +32,10 @@ class CreateShareRemoteOperationIT : AbstractIT() { @Test fun createShareWithNoteAndAttributes() { - val attributes = ShareAttributesJsonHandler.toJson( - listOf(ShareAttributes.createDownloadAttributes(true)) - ) + val attributes = + ShareAttributesJsonHandler.toJson( + listOf(ShareAttributes.createDownloadAttributes(true)) + ) val note = "Note with attributes" val path = "/shareWithAttributes/" @@ -63,17 +64,18 @@ class CreateShareRemoteOperationIT : AbstractIT() { note: String, attributes: String? = null ): OCShare { - val operation = CreateShareRemoteOperation( - path, - ShareType.USER, - accountName, - false, - "", - OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER, - true, - note, - attributes - ) + val operation = + CreateShareRemoteOperation( + path, + ShareType.USER, + accountName, + false, + "", + OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER, + true, + note, + attributes + ) val result = operation.execute(client) assertTrue(result.isSuccess) return result.resultData[0] From aa578fc8002a32a050f451f87b314b016a429ad3 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 4 Jun 2025 15:37:24 +0800 Subject: [PATCH 14/15] catch asBoolean Signed-off-by: alperozturk --- .../java/com/nextcloud/extensions/JsonObjectExtensions.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt b/library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt index f721622828..222777667f 100644 --- a/library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt +++ b/library/src/main/java/com/nextcloud/extensions/JsonObjectExtensions.kt @@ -17,7 +17,11 @@ fun JsonObject?.getBoolean(key: String): Boolean? { } if (has(key) && get(key).isJsonPrimitive) { - return get(key).asBoolean + return try { + get(key).asBoolean + } catch (_: UnsupportedOperationException) { + null + } } return null From d922facdb4b20bfda48b89786c144cd6df50400f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alper=20=C3=96zt=C3=BCrk?= <67455295+alperozturk96@users.noreply.github.com> Date: Fri, 6 Jun 2025 18:57:45 +0800 Subject: [PATCH 15/15] Update library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tom <70907959+ZetaTom@users.noreply.github.com> Signed-off-by: Alper Öztürk <67455295+alperozturk96@users.noreply.github.com> --- .../lib/resources/shares/CreateShareRemoteOperationIT.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt index 34d3fa0a23..a239adf67d 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt @@ -32,16 +32,14 @@ class CreateShareRemoteOperationIT : AbstractIT() { @Test fun createShareWithNoteAndAttributes() { - val attributes = - ShareAttributesJsonHandler.toJson( - listOf(ShareAttributes.createDownloadAttributes(true)) - ) + val attributes = listOf(ShareAttributes.createDownloadAttributes(true)) val note = "Note with attributes" val path = "/shareWithAttributes/" createFolder(path) - val share = createShare(path, "admin", note, attributes) + val share = createShare(path, "admin", note, ShareAttributesJsonHandler.toJson(attributes)) assertEquals(note, share.note) + assertEquals(attributes, ShareAttributesJsonHandler.toList(share.attributes)) } @Test