From 91bd322b68c45db0cdba82e7e956826a3bb735fd Mon Sep 17 00:00:00 2001 From: Fernando Sanz Date: Tue, 31 Aug 2021 14:47:48 +0200 Subject: [PATCH] The ShareXMLParser has been removed from UpdateRemoteShareOperation.kt class. --- .../ShareToRemoteOperationResultParser.kt | 120 ----- .../lib/resources/shares/ShareUtils.java | 41 -- .../lib/resources/shares/ShareXMLParser.kt | 420 ------------------ .../shares/UpdateRemoteShareOperation.kt | 229 ++++++---- 4 files changed, 132 insertions(+), 678 deletions(-) delete mode 100644 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareToRemoteOperationResultParser.kt delete mode 100644 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareUtils.java delete mode 100644 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.kt diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareToRemoteOperationResultParser.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareToRemoteOperationResultParser.kt deleted file mode 100644 index 389ded4e..00000000 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareToRemoteOperationResultParser.kt +++ /dev/null @@ -1,120 +0,0 @@ -/* ownCloud Android Library is available under MIT license - * @author David A. Velasco - * @author David González Verdugo - * @author Christian Schabesberger - * Copyright (C) 2020 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.shares - -import android.net.Uri -import com.owncloud.android.lib.common.operations.RemoteOperationResult -import com.owncloud.android.lib.resources.status.OwnCloudVersion -import org.xmlpull.v1.XmlPullParserException -import timber.log.Timber -import java.io.ByteArrayInputStream -import java.io.IOException -import java.util.ArrayList - -class ShareToRemoteOperationResultParser(private var shareXmlParser: ShareXMLParser?) { - var oneOrMoreSharesRequired = false - var ownCloudVersion: OwnCloudVersion? = null - var serverBaseUri: Uri? = null - - fun parse(serverResponse: String?): RemoteOperationResult { - if (serverResponse.isNullOrEmpty()) { - return RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE) - } - - var result: RemoteOperationResult - val resultData: List? - - try { - // Parse xml response and obtain the list of shares - val byteArrayServerResponse = ByteArrayInputStream(serverResponse.toByteArray()) - if (shareXmlParser == null) { - Timber.w("No ShareXmlParser provided, creating new instance") - shareXmlParser = ShareXMLParser() - } - val shares = shareXmlParser?.parseXMLResponse(byteArrayServerResponse) - - when { - shareXmlParser?.isSuccess!! -> { - if (!shares.isNullOrEmpty() || !oneOrMoreSharesRequired) { - result = RemoteOperationResult(RemoteOperationResult.ResultCode.OK) - - resultData = shares?.map { share -> - if (share.shareType != ShareType.PUBLIC_LINK || - share.shareLink.isNotEmpty() || - share.token.isEmpty() - ) { - return@map share - } - - if (serverBaseUri != null) { - val sharingLinkPath = ShareUtils.SHARING_LINK_PATH - share.shareLink = serverBaseUri.toString() + sharingLinkPath + share.token - } else { - Timber.e("Couldn't build link for public share :(") - } - - share - } - - if (resultData != null) { - result.setData(ShareResponse(ArrayList(resultData.toMutableList()))) - } - - } else { - result = RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE) - Timber.e("Successful status with no share in the response") - } - } - shareXmlParser?.isWrongParameter!! -> { - result = RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_WRONG_PARAMETER) - result.httpPhrase = shareXmlParser?.message - } - shareXmlParser?.isNotFound!! -> { - result = RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND) - result.httpPhrase = shareXmlParser?.message - } - shareXmlParser?.isForbidden!! -> { - result = RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_FORBIDDEN) - result.httpPhrase = shareXmlParser?.message - } - else -> { - result = RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE) - } - } - } catch (e: XmlPullParserException) { - Timber.e(e, "Error parsing response from server") - result = RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE) - - } catch (e: IOException) { - Timber.e(e, "Error reading response from server") - result = RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE) - } - - return result - } -} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareUtils.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareUtils.java deleted file mode 100644 index 518666a1..00000000 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareUtils.java +++ /dev/null @@ -1,41 +0,0 @@ -/* ownCloud Android Library is available under MIT license - * Copyright (C) 2020 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.shares; - -/** - * Contains Constants for Share Operation - * - * @author masensio - * @author David González Verdugo - */ - -public class ShareUtils { - - // OCS Route - public static final String SHARING_API_PATH = "ocs/v2.php/apps/files_sharing/api/v1/shares"; - - // String to build the link with the token of a share: - public static final String SHARING_LINK_PATH = "/index.php/s/"; -} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.kt deleted file mode 100644 index a0f0e0b9..00000000 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.kt +++ /dev/null @@ -1,420 +0,0 @@ -/* ownCloud Android Library is available under MIT license - * Copyright (C) 2020 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.shares - -import android.util.Xml -import com.owncloud.android.lib.common.network.WebdavUtils -import org.xmlpull.v1.XmlPullParser -import org.xmlpull.v1.XmlPullParserException -import org.xmlpull.v1.XmlPullParserFactory -import java.io.File -import java.io.IOException -import java.io.InputStream -import java.util.ArrayList - -/** - * Parser for Share API Response - * - * @author masensio - * @author David González Verdugo - */ - -class ShareXMLParser { - // Getters and Setters - var status: String? = null - var statusCode: Int = 0 - var message: String? = null - - val isSuccess: Boolean - get() = statusCode == SUCCESS - - val isForbidden: Boolean - get() = statusCode == ERROR_FORBIDDEN - - val isNotFound: Boolean - get() = statusCode == ERROR_NOT_FOUND - - val isWrongParameter: Boolean - get() = statusCode == ERROR_WRONG_PARAMETER - - // Constructor - init { - statusCode = INIT - } - - /** - * Parse is as response of Share API - * @param inputStream - * @return List of ShareRemoteFiles - * @throws XmlPullParserException - * @throws IOException - */ - @Throws(XmlPullParserException::class, IOException::class) - fun parseXMLResponse(inputStream: InputStream): ArrayList { - - try { - // XMLPullParser - val factory = XmlPullParserFactory.newInstance() - factory.isNamespaceAware = true - - val parser = Xml.newPullParser() - parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false) - parser.setInput(inputStream, null) - parser.nextTag() - return readOCS(parser) - - } finally { - inputStream.close() - } - } - - /** - * Parse OCS node - * @param parser - * @return List of ShareRemoteFiles - * @throws XmlPullParserException - * @throws IOException - */ - @Throws(XmlPullParserException::class, IOException::class) - private fun readOCS(parser: XmlPullParser): ArrayList { - var shares = ArrayList() - parser.require(XmlPullParser.START_TAG, ns, NODE_OCS) - while (parser.next() != XmlPullParser.END_TAG) { - if (parser.eventType != XmlPullParser.START_TAG) { - continue - } - val name = parser.name - // read NODE_META and NODE_DATA - when { - name.equals(NODE_META, ignoreCase = true) -> { - readMeta(parser) - } - name.equals(NODE_DATA, ignoreCase = true) -> { - shares = readData(parser) - } - else -> { - skip(parser) - } - } - } - return shares - } - - /** - * Parse Meta node - * @param parser - * @throws XmlPullParserException - * @throws IOException - */ - @Throws(XmlPullParserException::class, IOException::class) - private fun readMeta(parser: XmlPullParser) { - parser.require(XmlPullParser.START_TAG, ns, NODE_META) - while (parser.next() != XmlPullParser.END_TAG) { - if (parser.eventType != XmlPullParser.START_TAG) { - continue - } - val name = parser.name - - when { - name.equals(NODE_STATUS, ignoreCase = true) -> { - status = readNode(parser, NODE_STATUS) - } - name.equals(NODE_STATUS_CODE, ignoreCase = true) -> { - statusCode = Integer.parseInt(readNode(parser, NODE_STATUS_CODE)) - } - name.equals(NODE_MESSAGE, ignoreCase = true) -> { - message = readNode(parser, NODE_MESSAGE) - } - else -> { - skip(parser) - } - } - } - } - - /** - * Parse Data node - * @param parser - * @return - * @throws XmlPullParserException - * @throws IOException - */ - @Throws(XmlPullParserException::class, IOException::class) - private fun readData(parser: XmlPullParser): ArrayList { - val shares = ArrayList() - var share: RemoteShare? = null - - parser.require(XmlPullParser.START_TAG, ns, NODE_DATA) - while (parser.next() != XmlPullParser.END_TAG) { - if (parser.eventType != XmlPullParser.START_TAG) { - continue - } - val name = parser.name - when { - name.equals(NODE_ELEMENT, ignoreCase = true) -> { - readElement(parser, shares) - } - name.equals(NODE_ID, ignoreCase = true) -> { // Parse Create XML Response - share = RemoteShare() - val value = readNode(parser, NODE_ID) - share.id = value - } - name.equals(NODE_URL, ignoreCase = true) -> { - // NOTE: this field is received in all the public shares from OC 9.0.0 - // in previous versions, it's received in the result of POST requests, but not - // in GET requests - share!!.shareType = ShareType.PUBLIC_LINK - val value = readNode(parser, NODE_URL) - share.shareLink = value - } - name.equals(NODE_TOKEN, ignoreCase = true) -> { - share!!.token = readNode(parser, NODE_TOKEN) - } - else -> { - skip(parser) - } - } - } - - if (share != null) { - // this is the response of a request for creation; don't pass to isValidShare() - shares.add(share) - } - - return shares - - } - - /** - * Parse Element node - * @param parser - * @return - * @throws XmlPullParserException - * @throws IOException - */ - @Throws(XmlPullParserException::class, IOException::class) - private fun readElement(parser: XmlPullParser, shares: ArrayList) { - parser.require(XmlPullParser.START_TAG, ns, NODE_ELEMENT) - - val remoteShare = RemoteShare() - - while (parser.next() != XmlPullParser.END_TAG) { - if (parser.eventType != XmlPullParser.START_TAG) { - continue - } - - val name = parser.name - - when { - name.equals(NODE_ELEMENT, ignoreCase = true) -> { - // patch to work around servers responding with extra surrounding all - // the shares on the same file before - // https://github.com/owncloud/core/issues/6992 was fixed - readElement(parser, shares) - } - - name.equals(NODE_ID, ignoreCase = true) -> { - remoteShare.id = readNode(parser, NODE_ID) - } - - name.equals(NODE_ITEM_TYPE, ignoreCase = true) -> { - remoteShare.isFolder = readNode(parser, NODE_ITEM_TYPE).equals(TYPE_FOLDER, ignoreCase = true) - fixPathForFolder(remoteShare) - } - - name.equals(NODE_PARENT, ignoreCase = true) -> { - readNode(parser, NODE_PARENT) - } - - name.equals(NODE_SHARE_TYPE, ignoreCase = true) -> { - val value = Integer.parseInt(readNode(parser, NODE_SHARE_TYPE)) - remoteShare.shareType = ShareType.fromValue(value) - } - - name.equals(NODE_SHARE_WITH, ignoreCase = true) -> { - remoteShare.shareWith = readNode(parser, NODE_SHARE_WITH) - } - - name.equals(NODE_PATH, ignoreCase = true) -> { - remoteShare.path = readNode(parser, NODE_PATH) - fixPathForFolder(remoteShare) - } - - name.equals(NODE_PERMISSIONS, ignoreCase = true) -> { - remoteShare.permissions = Integer.parseInt(readNode(parser, NODE_PERMISSIONS)) - } - - name.equals(NODE_STIME, ignoreCase = true) -> { - remoteShare.sharedDate = java.lang.Long.parseLong(readNode(parser, NODE_STIME)) - } - - name.equals(NODE_EXPIRATION, ignoreCase = true) -> { - val value = readNode(parser, NODE_EXPIRATION) - if (value.isNotEmpty()) { - remoteShare.expirationDate = WebdavUtils.parseResponseDate(value)!!.time - } - } - - name.equals(NODE_TOKEN, ignoreCase = true) -> { - remoteShare.token = readNode(parser, NODE_TOKEN) - } - - name.equals(NODE_STORAGE, ignoreCase = true) -> { - readNode(parser, NODE_STORAGE) - } - - name.equals(NODE_MAIL_SEND, ignoreCase = true) -> { - readNode(parser, NODE_MAIL_SEND) - } - - name.equals(NODE_SHARE_WITH_DISPLAY_NAME, ignoreCase = true) -> { - remoteShare.sharedWithDisplayName = readNode(parser, NODE_SHARE_WITH_DISPLAY_NAME) - } - - name.equals(NODE_SHARE_WITH_ADDITIONAL_INFO, ignoreCase = true) -> { - remoteShare.sharedWithAdditionalInfo = readNode(parser, NODE_SHARE_WITH_ADDITIONAL_INFO) - } - - name.equals(NODE_URL, ignoreCase = true) -> { - val value = readNode(parser, NODE_URL) - remoteShare.shareLink = value - } - - name.equals(NODE_NAME, ignoreCase = true) -> { - remoteShare.name = readNode(parser, NODE_NAME) - } - - else -> { - skip(parser) - } - } - } - - shares.add(remoteShare) - } - - private fun fixPathForFolder(share: RemoteShare) { - if (share.isFolder && share.path.isNotEmpty() && - !share.path.endsWith(File.separator) - ) { - share.path = share.path + File.separator - } - } - - /** - * Parse a node, to obtain its text. Needs readText method - * @param parser - * @param node - * @return Text of the node - * @throws XmlPullParserException - * @throws IOException - */ - @Throws(XmlPullParserException::class, IOException::class) - private fun readNode(parser: XmlPullParser, node: String): String { - parser.require(XmlPullParser.START_TAG, ns, node) - val value = readText(parser) - parser.require(XmlPullParser.END_TAG, ns, node) - return value - } - - /** - * Read the text from a node - * @param parser - * @return Text of the node - * @throws IOException - * @throws XmlPullParserException - */ - @Throws(IOException::class, XmlPullParserException::class) - private fun readText(parser: XmlPullParser): String { - var result = "" - if (parser.next() == XmlPullParser.TEXT) { - result = parser.text - parser.nextTag() - } - return result - } - - /** - * Skip tags in parser procedure - * @param parser - * @throws XmlPullParserException - * @throws IOException - */ - @Throws(XmlPullParserException::class, IOException::class) - private fun skip(parser: XmlPullParser) { - if (parser.eventType != XmlPullParser.START_TAG) { - throw IllegalStateException() - } - var depth = 1 - while (depth != 0) { - when (parser.next()) { - XmlPullParser.END_TAG -> depth-- - XmlPullParser.START_TAG -> depth++ - } - } - } - - companion object { - - // No namespaces - private val ns: String? = null - - // NODES for XML Parser - private const val NODE_OCS = "ocs" - - private const val NODE_META = "meta" - private const val NODE_STATUS = "status" - private const val NODE_STATUS_CODE = "statuscode" - private const val NODE_MESSAGE = "message" - - private const val NODE_DATA = "data" - private const val NODE_ELEMENT = "element" - private const val NODE_ID = "id" - private const val NODE_ITEM_TYPE = "item_type" - private const val NODE_PARENT = "parent" - private const val NODE_SHARE_TYPE = "share_type" - private const val NODE_SHARE_WITH = "share_with" - private const val NODE_PATH = "path" - private const val NODE_PERMISSIONS = "permissions" - private const val NODE_STIME = "stime" - private const val NODE_EXPIRATION = "expiration" - private const val NODE_TOKEN = "token" - private const val NODE_STORAGE = "storage" - private const val NODE_MAIL_SEND = "mail_send" - private const val NODE_SHARE_WITH_DISPLAY_NAME = "share_with_displayname" - private const val NODE_SHARE_WITH_ADDITIONAL_INFO = "share_with_additional_info" - private const val NODE_NAME = "name" - - private const val NODE_URL = "url" - - private const val TYPE_FOLDER = "folder" - - private const val SUCCESS = 200 - private const val ERROR_WRONG_PARAMETER = 400 - private const val ERROR_FORBIDDEN = 403 - private const val ERROR_NOT_FOUND = 404 - private const val INIT = -1 - } -} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/UpdateRemoteShareOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/UpdateRemoteShareOperation.kt index 0ddb69a1..dcec411a 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/UpdateRemoteShareOperation.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/UpdateRemoteShareOperation.kt @@ -1,38 +1,45 @@ -/* ownCloud Android Library is available under MIT license +/* + * ownCloud Android client application * - * Copyright (C) 2020 ownCloud GmbH. + * @author David A. Velasco + * @author David González Verdugo + * @author Fernando Sanz Velasco + * Copyright (C) 2021 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * - * 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.shares +import android.net.Uri import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.http.HttpConstants import com.owncloud.android.lib.common.http.methods.nonwebdav.PutMethod import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.resources.CommonOcsResponse import com.owncloud.android.lib.resources.shares.RemoteShare.Companion.DEFAULT_PERMISSION +import com.owncloud.android.lib.resources.shares.responses.ShareItem +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.Moshi +import com.squareup.moshi.Types import okhttp3.FormBody import timber.log.Timber +import java.lang.reflect.Type import java.net.URL import java.text.SimpleDateFormat import java.util.Calendar @@ -40,12 +47,7 @@ import java.util.Locale /** * Updates parameters of an existing Share resource, known its remote ID. - * - * * Allow updating several parameters, triggering a request to the server per parameter. - * - * @author David A. Velasco - * @author David González Verdugo */ class UpdateRemoteShareOperation /** @@ -99,100 +101,133 @@ class UpdateRemoteShareOperation var retrieveShareDetails = false // To retrieve more info about the just updated share - override fun run(client: OwnCloudClient): RemoteOperationResult { - var result: RemoteOperationResult + private fun buildRequestUri(baseUri: Uri) = + baseUri.buildUpon() + .appendEncodedPath(OCS_ROUTE) + .appendEncodedPath(remoteId) + .appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT) + .build() - try { - val formBodyBuilder = FormBody.Builder() + private fun parseResponse(response: String): ShareResponse? { + val moshi = Moshi.Builder().build() + val commonOcsType: Type = Types.newParameterizedType(CommonOcsResponse::class.java, ShareItem::class.java) + val adapter: JsonAdapter> = moshi.adapter(commonOcsType) + val remoteShare = adapter.fromJson(response)?.ocs?.data?.toRemoteShare() + return ShareResponse(remoteShare?.let { listOf(it) } ?: listOf()) + } - // Parameters to update - if (name != null) { - formBodyBuilder.add(PARAM_NAME, name!!) - } + private fun onResultUnsuccessful( + method: PutMethod, + response: String?, + status: Int + ): RemoteOperationResult { + Timber.e("Failed response while while updating remote shares ") + if (response != null) { + Timber.e("*** status code: $status; response message: $response") + } else { + Timber.e("*** status code: $status") + } + return RemoteOperationResult(method) + } - if (password != null) { - formBodyBuilder.add(PARAM_PASSWORD, password!!) - } + private fun onRequestSuccessful(response: String?): RemoteOperationResult { + val result = RemoteOperationResult(RemoteOperationResult.ResultCode.OK) + Timber.d("Successful response: $response") + result.data = parseResponse(response!!) + Timber.d("*** Retrieve the index of the new share completed ") + val emptyShare = result.data.shares.first() - if (expirationDateInMillis < INITIAL_EXPIRATION_DATE_IN_MILLIS) { - // clear expiration date - formBodyBuilder.add(PARAM_EXPIRATION_DATE, "") + return if (retrieveShareDetails) { + // retrieve more info - PUT only returns the index of the new share + GetRemoteShareOperation(emptyShare.id).execute(client) + } else { + result + } + } - } else if (expirationDateInMillis > INITIAL_EXPIRATION_DATE_IN_MILLIS) { - // set expiration date - val dateFormat = SimpleDateFormat(FORMAT_EXPIRATION_DATE, Locale.getDefault()) - val expirationDate = Calendar.getInstance() - expirationDate.timeInMillis = expirationDateInMillis - val formattedExpirationDate = dateFormat.format(expirationDate.time) - formBodyBuilder.add(PARAM_EXPIRATION_DATE, formattedExpirationDate) - } // else, ignore - no update + private fun createFormBodyBuilder(): FormBody.Builder { + val formBodyBuilder = FormBody.Builder() - if (publicUpload != null) { - formBodyBuilder.add(PARAM_PUBLIC_UPLOAD, publicUpload.toString()) - } - - // IMPORTANT: permissions parameter needs to be updated after mPublicUpload parameter, - // otherwise they would be set always as 1 (READ) in the server when mPublicUpload was updated - if (permissions > DEFAULT_PERMISSION) { - // set permissions - formBodyBuilder.add(PARAM_PERMISSIONS, permissions.toString()) - } - - val requestUri = client.baseUri - val uriBuilder = requestUri.buildUpon() - uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH) - uriBuilder.appendEncodedPath(remoteId.toString()) - - val putMethod = PutMethod(URL(uriBuilder.build().toString()), formBodyBuilder.build()) - - putMethod.setRequestHeader(HttpConstants.CONTENT_TYPE_HEADER, HttpConstants.CONTENT_TYPE_URLENCODED_UTF8) - putMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE) - - val status = client.executeHttpMethod(putMethod) - - // Parse xml response - val parser = ShareToRemoteOperationResultParser( - ShareXMLParser() - ) - - if (!isSuccess(status)) { - return parser.parse(putMethod.getResponseBodyAsString()) - } - - parser.ownCloudVersion = client.ownCloudVersion - parser.serverBaseUri = client.baseUri - result = parser.parse(putMethod.getResponseBodyAsString()) - - if (result.isSuccess && retrieveShareDetails) { - // retrieve more info - PUT only returns the index of the new share - val emptyShare = result.data.shares.first() - val getShares = GetRemoteShareOperation( - emptyShare.id - ) - result = getShares.execute(client) - } - - } catch (e: Exception) { - result = RemoteOperationResult(e) - Timber.e(e, "Exception while Creating New Share") + // Parameters to update + if (name != null) { + formBodyBuilder.add(PARAM_NAME, name!!) } - return result + if (password != null) { + formBodyBuilder.add(PARAM_PASSWORD, password!!) + } + + if (expirationDateInMillis < INITIAL_EXPIRATION_DATE_IN_MILLIS) { + // clear expiration date + formBodyBuilder.add(PARAM_EXPIRATION_DATE, "") + + } else if (expirationDateInMillis > INITIAL_EXPIRATION_DATE_IN_MILLIS) { + // set expiration date + val dateFormat = SimpleDateFormat(FORMAT_EXPIRATION_DATE, Locale.getDefault()) + val expirationDate = Calendar.getInstance() + expirationDate.timeInMillis = expirationDateInMillis + val formattedExpirationDate = dateFormat.format(expirationDate.time) + formBodyBuilder.add(PARAM_EXPIRATION_DATE, formattedExpirationDate) + } // else, ignore - no update + + if (publicUpload != null) { + formBodyBuilder.add(PARAM_PUBLIC_UPLOAD, publicUpload.toString()) + } + + // IMPORTANT: permissions parameter needs to be updated after mPublicUpload parameter, + // otherwise they would be set always as 1 (READ) in the server when mPublicUpload was updated + if (permissions > DEFAULT_PERMISSION) { + // set permissions + formBodyBuilder.add(PARAM_PERMISSIONS, permissions.toString()) + } + + return formBodyBuilder + } + + override fun run(client: OwnCloudClient): RemoteOperationResult { + val requestUri = buildRequestUri(client.baseUri) + + val formBodyBuilder = createFormBodyBuilder() + + val putMethod = PutMethod(URL(requestUri.toString()), formBodyBuilder.build()).apply { + setRequestHeader(HttpConstants.CONTENT_TYPE_HEADER, HttpConstants.CONTENT_TYPE_URLENCODED_UTF8) + addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE) + } + + + return try { + val status = client.executeHttpMethod(putMethod) + val response = putMethod.getResponseBodyAsString() + + if (!isSuccess(status)) { + onResultUnsuccessful(putMethod, response, status) + } else { + onRequestSuccessful(response) + } + } catch (e: Exception) { + Timber.e(e, "Exception while updating remote share") + RemoteOperationResult(e) + } } private fun isSuccess(status: Int): Boolean = status == HttpConstants.HTTP_OK companion object { + //OCS Route + private const val OCS_ROUTE = "ocs/v2.php/apps/files_sharing/api/v1/shares" + + //Arguments - names + private const val PARAM_FORMAT = "format" private const val PARAM_NAME = "name" private const val PARAM_PASSWORD = "password" private const val PARAM_EXPIRATION_DATE = "expireDate" private const val PARAM_PERMISSIONS = "permissions" private const val PARAM_PUBLIC_UPLOAD = "publicUpload" - private const val FORMAT_EXPIRATION_DATE = "yyyy-MM-dd" - private const val ENTITY_CONTENT_TYPE = "application/x-www-form-urlencoded" - private const val ENTITY_CHARSET = "UTF-8" + //Arguments - constant values + private const val VALUE_FORMAT = "json" + private const val FORMAT_EXPIRATION_DATE = "yyyy-MM-dd" private const val INITIAL_EXPIRATION_DATE_IN_MILLIS: Long = 0 } }