From 1d79d591233901a90600acd97311bb06f44858c6 Mon Sep 17 00:00:00 2001 From: A117870935 Date: Thu, 27 Apr 2023 11:54:02 +0530 Subject: [PATCH 1/4] Implemented download limit functionality to link type file shares. --- .../operations/UpdateShareInfoOperation.java | 52 ++++ ...DeleteShareDownloadLimitRemoteOperation.kt | 77 +++++ .../download_limit/DownloadLimitResponse.kt | 18 ++ .../download_limit/DownloadLimitXMLParser.kt | 263 ++++++++++++++++++ .../GetShareDownloadLimitOperation.kt | 79 ++++++ .../download_limit/ShareDownloadLimitUtils.kt | 30 ++ ...UpdateShareDownloadLimitRemoteOperation.kt | 96 +++++++ .../android/services/OperationsService.java | 17 ++ .../android/ui/activity/FileActivity.java | 31 +++ .../fragment/FileDetailSharingFragment.java | 2 + .../FileDetailsSharingProcessFragment.kt | 102 ++++++- .../ui/helpers/FileOperationsHelper.java | 22 +- .../owncloud/android/utils/KeyboardUtils.kt | 8 + .../file_details_sharing_process_fragment.xml | 57 +++- app/src/main/res/values/strings.xml | 5 + 15 files changed, 852 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/com/owncloud/android/operations/download_limit/DeleteShareDownloadLimitRemoteOperation.kt create mode 100644 app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitResponse.kt create mode 100644 app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitXMLParser.kt create mode 100644 app/src/main/java/com/owncloud/android/operations/download_limit/GetShareDownloadLimitOperation.kt create mode 100644 app/src/main/java/com/owncloud/android/operations/download_limit/ShareDownloadLimitUtils.kt create mode 100644 app/src/main/java/com/owncloud/android/operations/download_limit/UpdateShareDownloadLimitRemoteOperation.kt diff --git a/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java b/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java index 580cfc7f2b56..281ad851b1d9 100644 --- a/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java @@ -27,10 +27,14 @@ import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.shares.GetShareRemoteOperation; import com.owncloud.android.lib.resources.shares.OCShare; +import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.lib.resources.shares.UpdateShareRemoteOperation; import com.owncloud.android.operations.common.SyncOperation; +import com.owncloud.android.operations.download_limit.DeleteShareDownloadLimitRemoteOperation; +import com.owncloud.android.operations.download_limit.UpdateShareDownloadLimitRemoteOperation; /** @@ -38,6 +42,7 @@ */ public class UpdateShareInfoOperation extends SyncOperation { + private static final String TAG = UpdateShareInfoOperation.class.getSimpleName(); private OCShare share; private long shareId; private long expirationDateInMillis; @@ -46,6 +51,8 @@ public class UpdateShareInfoOperation extends SyncOperation { private int permissions = -1; private String password; private String label; + //download limit for link share + private long downloadLimit; /** * Constructor @@ -116,6 +123,9 @@ protected RemoteOperationResult run(OwnCloudClient client) { if (result.isSuccess() && shareId > 0) { OCShare ocShare = (OCShare) result.getData().get(0); ocShare.setPasswordProtected(!TextUtils.isEmpty(password)); + + executeShareDownloadLimitOperation(client, ocShare); + getStorageManager().saveShare(ocShare); } @@ -124,6 +134,44 @@ protected RemoteOperationResult run(OwnCloudClient client) { return result; } + /** + * method will be used to update or delete the download limit for the particular share + * + * @param client + * @param ocShare share object + */ + private void executeShareDownloadLimitOperation(OwnCloudClient client, OCShare ocShare) { + //if share type is of Link Share then only we have to update the download limit if configured by user + if (ocShare.getShareType() == ShareType.PUBLIC_LINK && !ocShare.isFolder()) { + + //if download limit it greater than 0 then update the limit + //else delete the download limit + if (downloadLimit > 0) { + //api will update the download limit for the particular share + UpdateShareDownloadLimitRemoteOperation updateShareDownloadLimitRemoteOperation = + new UpdateShareDownloadLimitRemoteOperation(ocShare.getToken(), downloadLimit); + + RemoteOperationResult downloadLimitOp = + updateShareDownloadLimitRemoteOperation.execute(client); + if (downloadLimitOp.isSuccess()) { + Log_OC.d(TAG, "Download limit updated for the share."); + Log_OC.d(TAG, "Download limit " + downloadLimit); + } + } else { + //api will delete the download limit for the particular share + DeleteShareDownloadLimitRemoteOperation limitRemoteOperation = + new DeleteShareDownloadLimitRemoteOperation(ocShare.getToken()); + + RemoteOperationResult deleteDownloadLimitOp = + limitRemoteOperation.execute(client); + if (deleteDownloadLimitOp.isSuccess()) { + Log_OC.d(TAG, "Download limit delete for the share."); + } + } + + } + } + public void setExpirationDateInMillis(long expirationDateInMillis) { this.expirationDateInMillis = expirationDateInMillis; } @@ -147,5 +195,9 @@ public void setPassword(String password) { public void setLabel(String label) { this.label = label; } + + public void setDownloadLimit(long downloadLimit) { + this.downloadLimit = downloadLimit; + } } diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/DeleteShareDownloadLimitRemoteOperation.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/DeleteShareDownloadLimitRemoteOperation.kt new file mode 100644 index 000000000000..3ad41ddd9ab9 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/operations/download_limit/DeleteShareDownloadLimitRemoteOperation.kt @@ -0,0 +1,77 @@ +/** + * ownCloud Android client application + * + * @author TSI-mc Copyright (C) 2021 TSI-mc + * + * + * 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 + * //www.gnu.org/licenses/>. + */ +package com.owncloud.android.operations.download_limit + +import com.owncloud.android.lib.common.OwnCloudClient +import com.owncloud.android.lib.common.operations.RemoteOperation +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.common.utils.Log_OC +import org.apache.commons.httpclient.HttpStatus +import org.apache.commons.httpclient.methods.DeleteMethod + +/** + * class to delete the download limit for the link share + * this has to be executed when user has toggled off the download limit + * + * + * API : //DELETE to /ocs/v2.php/apps/files_downloadlimit/{share_token}/limit + */ +class DeleteShareDownloadLimitRemoteOperation(private val shareToken: String) : + RemoteOperation() { + override fun run(client: OwnCloudClient): RemoteOperationResult { + var result: RemoteOperationResult + val status: Int + var deleteMethod: DeleteMethod? = null + try { + // Post Method + deleteMethod = DeleteMethod( + client.baseUri.toString() + ShareDownloadLimitUtils.getDownloadLimitApiPath( + shareToken + ) + ) + deleteMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE) + status = client.executeMethod(deleteMethod) + if (isSuccess(status)) { + val response = deleteMethod.responseBodyAsString + Log_OC.d(TAG, "Delete Download Limit response: $response") + val parser = DownloadLimitXMLParser() + result = parser.parse(true, response) + if (result.isSuccess) { + return result + } + } else { + result = RemoteOperationResult(false, deleteMethod) + } + } catch (e: Exception) { + result = RemoteOperationResult(e) + Log_OC.e(TAG, "Exception while deleting share download limit", e) + } finally { + deleteMethod?.releaseConnection() + } + return result + } + + private fun isSuccess(status: Int): Boolean { + return status == HttpStatus.SC_OK || status == HttpStatus.SC_BAD_REQUEST + } + + companion object { + private val TAG = DeleteShareDownloadLimitRemoteOperation::class.java.simpleName + } +} \ No newline at end of file diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitResponse.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitResponse.kt new file mode 100644 index 000000000000..29ebad9e9829 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitResponse.kt @@ -0,0 +1,18 @@ +package com.owncloud.android.operations.download_limit + +/** + * response from the Get download limit api + * + * + * + * ok + * 200 + * OK + * + * + * 5 + * 0 + * + * + */ +data class DownloadLimitResponse(var limit: Long = 0, var count: Long = 0) \ No newline at end of file diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitXMLParser.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitXMLParser.kt new file mode 100644 index 000000000000..4f016d813600 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitXMLParser.kt @@ -0,0 +1,263 @@ +package com.owncloud.android.operations.download_limit + +import android.util.Xml +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.common.utils.Log_OC +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import org.xmlpull.v1.XmlPullParserFactory +import java.io.ByteArrayInputStream +import java.io.IOException +import java.io.InputStream + +/** + * class to parse the Download Limit api XML response This class code referenced from java in NC library + */ +class DownloadLimitXMLParser { + // Getters and Setters + var status: String? = null + var statusCode = 0 + var message = "" + val isSuccess: Boolean + get() = statusCode == SUCCESS || statusCode == OK + private val isForbidden: Boolean + get() = statusCode == ERROR_FORBIDDEN + private val isNotFound: Boolean + get() = statusCode == ERROR_NOT_FOUND + private val isWrongParameter: Boolean + get() = statusCode == ERROR_WRONG_PARAMETER + + /** + * method to parse the Download limit response + * @param isGet check if parsing has to do for GET api or not + * because the parsing will depend on that + * if API is GET then response will have tag else it wont have + * @param serverResponse + * @return + */ + fun parse(isGet: Boolean, serverResponse: String?): RemoteOperationResult { + if (serverResponse == null || serverResponse.isEmpty()) { + return RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE) + } + var result: RemoteOperationResult + try { + // Parse xml response and obtain the list of downloadLimitResponse + val inputStream: InputStream = ByteArrayInputStream(serverResponse.toByteArray()) + val downloadLimitResponse = parseXMLResponse(inputStream) + if (isSuccess) { + if (isGet) { + result = RemoteOperationResult(RemoteOperationResult.ResultCode.OK) + result.setResultData(downloadLimitResponse) + } else { + result = RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE) + Log_OC.e(TAG, "Successful status with no share in the response") + } + } else if (isWrongParameter) { + result = RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_WRONG_PARAMETER) + result.setMessage(message) + } else if (isNotFound) { + result = RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND) + result.setMessage(message) + } else if (isForbidden) { + result = RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_FORBIDDEN) + result.setMessage(message) + } else { + result = RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE) + result.setMessage(message) + } + } catch (e: XmlPullParserException) { + Log_OC.e(TAG, "Error parsing response from server ", e) + result = RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE) + } catch (e: IOException) { + Log_OC.e(TAG, "Error reading response from server ", e) + result = RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE) + } + return result + } + + /** + * Parse is as response of Share API + * + * @param `is` InputStream to parse + * @return List of ShareRemoteFiles + * @throws XmlPullParserException + * @throws IOException + */ + @Throws(XmlPullParserException::class, IOException::class) + private fun parseXMLResponse(inputStream: InputStream): DownloadLimitResponse { + return inputStream.use { + // XMLPullParser + val factory = XmlPullParserFactory.newInstance() + factory.isNamespaceAware = true + val parser = Xml.newPullParser() + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false) + parser.setInput(it, null) + parser.nextTag() + readOCS(parser) + } + } + + /** + * Parse OCS node + * + * @param parser + * @return List of ShareRemoteFiles + * @throws XmlPullParserException + * @throws IOException + */ + @Throws(XmlPullParserException::class, IOException::class) + private fun readOCS(parser: XmlPullParser): DownloadLimitResponse { + var downloadLimitResponse = DownloadLimitResponse() + 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 + if (NODE_META.equals(name, ignoreCase = true)) { + readMeta(parser) + } else if (NODE_DATA.equals(name, ignoreCase = true)) { + downloadLimitResponse = readData(parser) + } else { + skip(parser) + } + } + return downloadLimitResponse + } + + /** + * 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 + if (NODE_STATUS.equals(name, ignoreCase = true)) { + status = readNode(parser, NODE_STATUS) + } else if (NODE_STATUS_CODE.equals(name, ignoreCase = true)) { + statusCode = readNode(parser, NODE_STATUS_CODE).toInt() + } else if (NODE_MESSAGE.equals(name, 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): DownloadLimitResponse { + val downloadLimitResponse = DownloadLimitResponse() + parser.require(XmlPullParser.START_TAG, ns, NODE_DATA) + //Log_OC.d(TAG, "---- NODE DATA ---"); + while (parser.next() != XmlPullParser.END_TAG) { + if (parser.eventType != XmlPullParser.START_TAG) { + continue + } + val name = parser.name + if (NODE_LIMIT.equals(name, ignoreCase = true)) { + val downloadLimit = readNode(parser, NODE_LIMIT) + downloadLimitResponse.limit = if (downloadLimit.isNotEmpty()) downloadLimit.toLong() else 0L + } else if (NODE_COUNT.equals(name, ignoreCase = true)) { + val downloadCount = readNode(parser, NODE_COUNT) + downloadLimitResponse.count = if (downloadCount.isNotEmpty()) downloadCount.toLong() else 0L + } else { + skip(parser) + } + } + return downloadLimitResponse + } + + /** + * 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) + //Log_OC.d(TAG, "node= " + node + ", value= " + value); + 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) { + check(parser.eventType == XmlPullParser.START_TAG) + var depth = 1 + while (depth != 0) { + when (parser.next()) { + XmlPullParser.END_TAG -> depth-- + XmlPullParser.START_TAG -> depth++ + } + } + } + + companion object { + private val TAG = DownloadLimitXMLParser::class.java.simpleName + + // 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_LIMIT = "limit" + private const val NODE_COUNT = "count" + private const val SUCCESS = 100 + private const val OK = 200 + private const val ERROR_WRONG_PARAMETER = 400 + private const val ERROR_FORBIDDEN = 403 + private const val ERROR_NOT_FOUND = 404 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/GetShareDownloadLimitOperation.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/GetShareDownloadLimitOperation.kt new file mode 100644 index 000000000000..cd74e38d99a5 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/operations/download_limit/GetShareDownloadLimitOperation.kt @@ -0,0 +1,79 @@ +/** + * ownCloud Android client application + * + * @author TSI-mc Copyright (C) 2021 TSI-mc + * + * + * 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 + * //www.gnu.org/licenses/>. + */ +package com.owncloud.android.operations.download_limit + +import com.owncloud.android.lib.common.OwnCloudClient +import com.owncloud.android.lib.common.operations.RemoteOperation +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.operations.download_limit.ShareDownloadLimitUtils.getDownloadLimitApiPath +import org.apache.commons.httpclient.HttpStatus +import org.apache.commons.httpclient.methods.GetMethod + +/** + * class to fetch the download limit for the link share it requires share token to fetch the data + * + * + * API : //GET to /ocs/v2.php/apps/files_downloadlimit/{share_token}/limit + */ +class GetShareDownloadLimitOperation( + //share token from OCShare + private val shareToken: String +) : RemoteOperation() { + override fun run(client: OwnCloudClient): RemoteOperationResult { + var result: RemoteOperationResult + var status = -1 + var get: GetMethod? = null + try { + // Get Method + get = GetMethod( + client.baseUri.toString() + getDownloadLimitApiPath( + shareToken + ) + ) + get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE) + status = client.executeMethod(get) + if (isSuccess(status)) { + val response = get.responseBodyAsString + Log_OC.d(TAG, "Get Download Limit response: $response") + val parser = DownloadLimitXMLParser() + result = parser.parse(true, response) + if (result.isSuccess) { + Log_OC.d(TAG, "Got " + result.resultData + " Response") + } + } else { + result = RemoteOperationResult(false, get) + } + } catch (e: Exception) { + result = RemoteOperationResult(e) + Log_OC.e(TAG, "Exception while getting share download limit", e) + } finally { + get?.releaseConnection() + } + return result + } + + private fun isSuccess(status: Int): Boolean { + return status == HttpStatus.SC_OK + } + + companion object { + private val TAG = GetShareDownloadLimitOperation::class.java.simpleName + } +} \ No newline at end of file diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/ShareDownloadLimitUtils.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/ShareDownloadLimitUtils.kt new file mode 100644 index 000000000000..1316989e6981 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/operations/download_limit/ShareDownloadLimitUtils.kt @@ -0,0 +1,30 @@ +/** + * ownCloud Android client application + * + * @author TSI-mc Copyright (C) 2021 TSI-mc + *

+ * 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 + * . + */ + +package com.owncloud.android.operations.download_limit + +object ShareDownloadLimitUtils { + + private const val SHARE_TOKEN_PATH = "{share_token}" + + //ocs route + //replace the {share_token} + private const val SHARE_DOWNLOAD_LIMIT_API_PATH = "/ocs/v2.php/apps/files_downloadlimit/$SHARE_TOKEN_PATH/limit" + + fun getDownloadLimitApiPath(shareToken: String): String { + return SHARE_DOWNLOAD_LIMIT_API_PATH.replace(SHARE_TOKEN_PATH, shareToken) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/UpdateShareDownloadLimitRemoteOperation.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/UpdateShareDownloadLimitRemoteOperation.kt new file mode 100644 index 000000000000..2addbbe8aae6 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/operations/download_limit/UpdateShareDownloadLimitRemoteOperation.kt @@ -0,0 +1,96 @@ +/** + * ownCloud Android client application + * + * @author TSI-mc Copyright (C) 2021 TSI-mc + * + * + * 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 + * //www.gnu.org/licenses/>. + */ +package com.owncloud.android.operations.download_limit + +import android.util.Pair +import com.owncloud.android.lib.common.OwnCloudClient +import com.owncloud.android.lib.common.operations.RemoteOperation +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.operations.download_limit.ShareDownloadLimitUtils.getDownloadLimitApiPath +import org.apache.commons.httpclient.HttpStatus +import org.apache.commons.httpclient.methods.PutMethod +import org.apache.commons.httpclient.methods.StringRequestEntity + +/** + * class to update the download limit for the link share + * + * + * API : //PUT to /ocs/v2.php/apps/files_downloadlimit/{share_token}/limit + * + * + * Body: {"token" : "Bpd4oEAgPqn3AbG", "limit" : 5} + */ +class UpdateShareDownloadLimitRemoteOperation(private val shareToken: String, private val downloadLimit: Long) : + RemoteOperation() { + override fun run(client: OwnCloudClient): RemoteOperationResult { + var result: RemoteOperationResult + val status: Int + var put: PutMethod? = null + try { + // Post Method + put = PutMethod( + client.baseUri.toString() + getDownloadLimitApiPath( + shareToken + ) + ) + put.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE) + val parametersToUpdate: MutableList> = ArrayList() + parametersToUpdate.add(Pair(PARAM_TOKEN, shareToken)) + parametersToUpdate.add(Pair(PARAM_LIMIT, downloadLimit.toString())) + for (parameter in parametersToUpdate) { + put.requestEntity = StringRequestEntity( + parameter.first + "=" + parameter.second, + ENTITY_CONTENT_TYPE, + ENTITY_CHARSET + ) + } + status = client.executeMethod(put) + if (isSuccess(status)) { + val response = put.responseBodyAsString + Log_OC.d(TAG, "Download Limit response: $response") + val parser = DownloadLimitXMLParser() + result = parser.parse(true, response) + if (result.isSuccess) { + return result + } + } else { + result = RemoteOperationResult(false, put) + } + } catch (e: Exception) { + result = RemoteOperationResult(e) + Log_OC.e(TAG, "Exception while updating share download limit", e) + } finally { + put?.releaseConnection() + } + return result + } + + private fun isSuccess(status: Int): Boolean { + return status == HttpStatus.SC_OK || status == HttpStatus.SC_BAD_REQUEST + } + + companion object { + private val TAG = UpdateShareDownloadLimitRemoteOperation::class.java.simpleName + private const val PARAM_TOKEN = "token" + private const val PARAM_LIMIT = "limit" + private const val ENTITY_CONTENT_TYPE = "application/x-www-form-urlencoded" + private const val ENTITY_CHARSET = "UTF-8" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/owncloud/android/services/OperationsService.java b/app/src/main/java/com/owncloud/android/services/OperationsService.java index ce6ca4697eb2..4c669e867dda 100644 --- a/app/src/main/java/com/owncloud/android/services/OperationsService.java +++ b/app/src/main/java/com/owncloud/android/services/OperationsService.java @@ -73,6 +73,7 @@ import com.owncloud.android.operations.UpdateShareInfoOperation; import com.owncloud.android.operations.UpdateSharePermissionsOperation; import com.owncloud.android.operations.UpdateShareViaLinkOperation; +import com.owncloud.android.operations.download_limit.GetShareDownloadLimitOperation; import java.io.IOException; import java.util.Iterator; @@ -109,6 +110,8 @@ public class OperationsService extends Service { public static final String EXTRA_SHARE_ID = "SHARE_ID"; public static final String EXTRA_SHARE_NOTE = "SHARE_NOTE"; public static final String EXTRA_IN_BACKGROUND = "IN_BACKGROUND"; + public static final String EXTRA_SHARE_TOKEN = "SHARE_TOKEN"; + public static final String EXTRA_SHARE_DOWNLOAD_LIMIT = "SHARE_DOWNLOAD_LIMIT"; public static final String ACTION_CREATE_SHARE_VIA_LINK = "CREATE_SHARE_VIA_LINK"; public static final String ACTION_CREATE_SECURE_FILE_DROP = "CREATE_SECURE_FILE_DROP"; @@ -129,6 +132,7 @@ public class OperationsService extends Service { public static final String ACTION_COPY_FILE = "COPY_FILE"; public static final String ACTION_CHECK_CURRENT_CREDENTIALS = "CHECK_CURRENT_CREDENTIALS"; public static final String ACTION_RESTORE_VERSION = "RESTORE_VERSION"; + public static final String ACTION_GET_SHARE_DOWNLOAD_LIMIT = "GET_SHARE_DOWNLOAD_LIMIT"; private ServiceHandler mOperationsHandler; private OperationsServiceBinder mOperationsBinder; @@ -643,6 +647,12 @@ private Pair newOperation(Intent operationIntent) { updateShare.setLabel(operationIntent.getStringExtra(EXTRA_SHARE_PUBLIC_LABEL)); } + //download limit for link share type + if (operationIntent.hasExtra(EXTRA_SHARE_DOWNLOAD_LIMIT)) { + updateShare.setDownloadLimit(operationIntent.getLongExtra(EXTRA_SHARE_DOWNLOAD_LIMIT, + 0L)); + } + operation = updateShare; } break; @@ -734,6 +744,13 @@ private Pair newOperation(Intent operationIntent) { fileVersion.getFileName()); break; + case ACTION_GET_SHARE_DOWNLOAD_LIMIT: + String shareToken = operationIntent.getStringExtra(EXTRA_SHARE_TOKEN); + if (!TextUtils.isEmpty(shareToken)) { + operation = new GetShareDownloadLimitOperation(shareToken); + } + break; + default: // do nothing break; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index 0563b3fb4a16..d9df4ce1fddb 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -78,6 +78,8 @@ import com.owncloud.android.operations.UpdateShareInfoOperation; import com.owncloud.android.operations.UpdateSharePermissionsOperation; import com.owncloud.android.operations.UpdateShareViaLinkOperation; +import com.owncloud.android.operations.download_limit.DownloadLimitResponse; +import com.owncloud.android.operations.download_limit.GetShareDownloadLimitOperation; import com.owncloud.android.providers.UsersAndGroupsSearchProvider; import com.owncloud.android.services.OperationsService; import com.owncloud.android.services.OperationsService.OperationsServiceBinder; @@ -89,6 +91,7 @@ import com.owncloud.android.ui.dialog.SslUntrustedCertDialog; import com.owncloud.android.ui.fragment.FileDetailFragment; import com.owncloud.android.ui.fragment.FileDetailSharingFragment; +import com.owncloud.android.ui.fragment.FileDetailsSharingProcessFragment; import com.owncloud.android.ui.fragment.OCFileListFragment; import com.owncloud.android.ui.helpers.FileOperationsHelper; import com.owncloud.android.ui.preview.PreviewImageActivity; @@ -415,6 +418,8 @@ public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationRe onUpdateShareInformation(result, R.string.unsharing_failed); } else if (operation instanceof UpdateNoteForShareOperation) { onUpdateNoteForShareOperationFinish(result); + } else if (operation instanceof GetShareDownloadLimitOperation) { + onShareDownloadLimitFetched(result); } } @@ -846,6 +851,24 @@ private void onCreateShareViaLinkOperationFinish(CreateShareViaLinkOperation ope } } + /** + * method will be called when download limit is fetched + * + * @param result + */ + private void onShareDownloadLimitFetched(RemoteOperationResult result) { + FileDetailSharingFragment sharingFragment = getShareFileFragment(); + + if (result.isSuccess() && sharingFragment != null) { + if (result.isSuccess() && result.getResultData() != null) { + if (result.getResultData() instanceof DownloadLimitResponse) { + onLinkShareDownloadLimitFetched(((DownloadLimitResponse) result.getResultData()).getLimit(), + ((DownloadLimitResponse) result.getResultData()).getCount()); + } + } + } + } + /** * Shortcut to get access to the {@link FileDetailSharingFragment} instance, if any * @@ -923,6 +946,14 @@ public void editExistingShare(OCShare share, int screenTypePermission, boolean i } } + @Override + public void onLinkShareDownloadLimitFetched(long downloadLimit, long downloadCount) { + Fragment fileDetailsSharingProcessFragment = getSupportFragmentManager().findFragmentByTag(FileDetailsSharingProcessFragment.TAG); + if (fileDetailsSharingProcessFragment != null) { + ((FileDetailsSharingProcessFragment) fileDetailsSharingProcessFragment).onLinkShareDownloadLimitFetched(downloadLimit, downloadCount); + } + } + /** * callback triggered on closing/finishing the sharing process */ diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index cde91289f708..1c04b7cc1791 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -551,5 +551,7 @@ void editExistingShare(OCShare share, int screenTypePermission, boolean isReshar boolean isExpiryDateShown); void onShareProcessClosed(); + + void onLinkShareDownloadLimitFetched(long downloadLimit, long downloadCount); } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 513119a59abe..fa152ecd5546 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -24,6 +24,8 @@ package com.owncloud.android.ui.fragment import android.content.Context import android.content.res.Configuration import android.os.Bundle +import android.os.Handler +import android.os.Looper import android.text.TextUtils import android.view.LayoutInflater import android.view.View @@ -42,6 +44,7 @@ import com.owncloud.android.ui.fragment.util.SharingMenuHelper import com.owncloud.android.ui.helpers.FileOperationsHelper import com.owncloud.android.utils.ClipboardUtil import com.owncloud.android.utils.DisplayUtils +import com.owncloud.android.utils.KeyboardUtils import com.owncloud.android.utils.theme.ViewThemeUtils import java.text.SimpleDateFormat import java.util.Date @@ -108,6 +111,8 @@ class FileDetailsSharingProcessFragment : @Inject lateinit var viewThemeUtils: ViewThemeUtils + @Inject + lateinit var keyboardUtils: KeyboardUtils private lateinit var onEditShareListener: FileDetailSharingFragment.OnEditShareListener @@ -125,6 +130,7 @@ class FileDetailsSharingProcessFragment : private var share: OCShare? = null private var isReshareShown: Boolean = true // show or hide reshare option private var isExpDateShown: Boolean = true // show or hide expiry date option + private var isDownloadCountFetched: Boolean = false private var expirationDatePickerFragment: ExpirationDatePickerDialogFragment? = null @@ -191,9 +197,11 @@ class FileDetailsSharingProcessFragment : viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessSetExpDateSwitch) viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessHideDownloadCheckbox) viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessChangeNameSwitch) + viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessDownloadLimitSwitch) viewThemeUtils.material.colorTextInputLayout(binding.shareProcessEnterPasswordContainer) viewThemeUtils.material.colorTextInputLayout(binding.shareProcessChangeNameContainer) + viewThemeUtils.material.colorTextInputLayout(binding.shareProcessDownloadLimitContainer) viewThemeUtils.material.colorTextInputLayout(binding.noteContainer) viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.shareProcessBtnNext) @@ -284,8 +292,7 @@ class FileDetailsSharingProcessFragment : private fun updateViewForShareType() { // external share if (shareType == ShareType.EMAIL) { - binding.shareProcessChangeNameSwitch.visibility = View.GONE - binding.shareProcessChangeNameContainer.visibility = View.GONE + hideLinkLabelViews() updateViewForExternalAndLinkShare() } // link share @@ -297,11 +304,27 @@ class FileDetailsSharingProcessFragment : binding.shareProcessChangeNameSwitch.isChecked = !TextUtils.isEmpty(share?.label) } showChangeNameInput(binding.shareProcessChangeNameSwitch.isChecked) + + //download limit will only be available for files + if (share?.isFolder == false || file?.isFolder == false) { + binding.shareProcessDownloadLimitSwitch.visibility = View.VISIBLE + + //fetch the download limit for link share + fetchDownloadLimitForShareLink() + } else { + binding.shareProcessDownloadLimitSwitch.visibility = View.GONE + } + + //the input for download limit will be hidden initially + //and can be visible back or no depending on the api result + //from the download limit api + binding.shareProcessDownloadLimitContainer.visibility = View.GONE + binding.shareProcessRemainingDownloadCountTv.visibility = View.GONE + } // internal share else { - binding.shareProcessChangeNameSwitch.visibility = View.GONE - binding.shareProcessChangeNameContainer.visibility = View.GONE + hideLinkLabelViews() binding.shareProcessHideDownloadCheckbox.visibility = View.GONE binding.shareProcessAllowResharingCheckbox.visibility = View.VISIBLE binding.shareProcessSetPasswordSwitch.visibility = View.GONE @@ -314,6 +337,14 @@ class FileDetailsSharingProcessFragment : } } + private fun hideLinkLabelViews() { + binding.shareProcessChangeNameSwitch.visibility = View.GONE + binding.shareProcessChangeNameContainer.visibility = View.GONE + + binding.shareProcessDownloadLimitSwitch.visibility = View.GONE + binding.shareProcessDownloadLimit.visibility = View.GONE + binding.shareProcessRemainingDownloadCountTv.visibility = View.GONE + } /** * update views where share type external or link share */ @@ -402,6 +433,10 @@ class FileDetailsSharingProcessFragment : binding.shareProcessSelectExpDate.setOnClickListener { showExpirationDateDialog() } + binding.shareProcessDownloadLimitSwitch.setOnCheckedChangeListener { _, isChecked -> + showDownloadLimitInput(isChecked) + } + } private fun showExpirationDateDialog(chosenDateInMillis: Long = chosenExpDateInMills) { @@ -423,6 +458,20 @@ class FileDetailsSharingProcessFragment : } } + private fun showDownloadLimitInput(isChecked: Boolean) { + binding.shareProcessDownloadLimitContainer.visibility = if (isChecked) View.VISIBLE else View.GONE + binding.shareProcessRemainingDownloadCountTv.visibility = if (isChecked) View.VISIBLE else View.GONE + if (!isChecked) { + binding.shareProcessDownloadLimit.setText("") + if (!isDownloadCountFetched) { + binding.shareProcessRemainingDownloadCountTv.text = + String.format(resources.getString(R.string.download_text), "0") + } + //hide keyboard when user unchecks + hideKeyboard() + } + } + private fun onCancelClick() { // if modifying the existing share then on back press remove the current fragment if (share != null) { @@ -459,6 +508,12 @@ class FileDetailsSharingProcessFragment : } } + private fun hideKeyboard() { + if (this::binding.isInitialized) { + keyboardUtils.hideKeyboardFrom(requireContext(), binding.root) + } + } + private fun removeCurrentFragment() { onEditShareListener.onShareProcessClosed() fileActivity?.supportFragmentManager?.beginTransaction()?.remove(this)?.commit() @@ -502,6 +557,17 @@ class FileDetailsSharingProcessFragment : return } + if (binding.shareProcessDownloadLimitSwitch.isChecked) { + val downloadLimit = binding.shareProcessDownloadLimit.text?.trim() + if (downloadLimit.isNullOrEmpty()) { + DisplayUtils.showSnackMessage(binding.root, R.string.download_limit_empty) + return + } else if (downloadLimit.toString().toLong() <= 0) { + DisplayUtils.showSnackMessage(binding.root, R.string.download_limit_zero) + return + } + } + // if modifying existing share information then execute the process if (share != null) { updateShare() @@ -533,7 +599,8 @@ class FileDetailsSharingProcessFragment : binding.shareProcessHideDownloadCheckbox.isChecked, binding.shareProcessEnterPassword.text.toString().trim(), chosenExpDateInMills, - binding.shareProcessChangeName.text.toString().trim() + binding.shareProcessChangeName.text.toString().trim(), + binding.shareProcessDownloadLimit.text.toString().trim() ) // copy the share link if available if (!TextUtils.isEmpty(share?.shareLink)) { @@ -567,6 +634,19 @@ class FileDetailsSharingProcessFragment : removeCurrentFragment() } + /** + * fetch the download limit for the link share + * the response will be received in FileActivity --> onRemoteOperationFinish() method + */ + private fun fetchDownloadLimitForShareLink() { + //need to call this method in handler else to show progress dialog it will throw exception + Handler(Looper.getMainLooper()).post { + share?.let { + fileOperationsHelper?.getShareDownloadLimit(it.token) + } + } + } + /** * method will be called from DrawerActivity on back press to handle screen backstack */ @@ -587,4 +667,16 @@ class FileDetailsSharingProcessFragment : override fun onDateUnSet() { binding.shareProcessSetExpDateSwitch.isChecked = false } + + /** + * will be called when download limit is fetched + */ + fun onLinkShareDownloadLimitFetched(downloadLimit: Long, downloadCount: Long) { + binding.shareProcessDownloadLimitSwitch.isChecked = downloadLimit > 0 + showDownloadLimitInput(binding.shareProcessDownloadLimitSwitch.isChecked) + binding.shareProcessDownloadLimit.setText(if (downloadLimit > 0) downloadLimit.toString() else "") + binding.shareProcessRemainingDownloadCountTv.text = + String.format(resources.getString(R.string.download_text), downloadCount.toString()) + isDownloadCountFetched = true + } } diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 229d4786d986..ee41634950fa 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -777,7 +777,7 @@ public void updateNoteToShare(OCShare share, String note) { */ public void updateShareInformation(OCShare share, int permissions, boolean hideFileDownload, String password, long expirationTimeInMillis, - String label) { + String label, String downloadLimit) { Intent updateShareIntent = new Intent(fileActivity, OperationsService.class); updateShareIntent.setAction(OperationsService.ACTION_UPDATE_SHARE_INFO); updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount()); @@ -787,6 +787,26 @@ public void updateShareInformation(OCShare share, int permissions, updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PASSWORD, (password == null) ? "" : password); updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS, expirationTimeInMillis); updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PUBLIC_LABEL, (label == null) ? "" : label); + + //download limit for link share type + updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_DOWNLOAD_LIMIT, + (downloadLimit == null || downloadLimit.equals("")) ? 0 : + Long.parseLong(downloadLimit)); + + queueShareIntent(updateShareIntent); + } + + /** + * method to fetch the download limit for the particular share Note: Download limit is only for Link share type + * + * @param shareToken of the OCShare + */ + public void getShareDownloadLimit(String shareToken) { + Intent updateShareIntent = new Intent(fileActivity, OperationsService.class); + updateShareIntent.setAction(OperationsService.ACTION_GET_SHARE_DOWNLOAD_LIMIT); + updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount()); + updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_TOKEN, shareToken); + queueShareIntent(updateShareIntent); } diff --git a/app/src/main/java/com/owncloud/android/utils/KeyboardUtils.kt b/app/src/main/java/com/owncloud/android/utils/KeyboardUtils.kt index 2d0b922a0bf3..e1e812d8213d 100644 --- a/app/src/main/java/com/owncloud/android/utils/KeyboardUtils.kt +++ b/app/src/main/java/com/owncloud/android/utils/KeyboardUtils.kt @@ -22,7 +22,9 @@ package com.owncloud.android.utils +import android.app.Activity import android.content.Context +import android.view.View import android.view.inputmethod.InputMethodManager import android.widget.EditText import javax.inject.Inject @@ -41,6 +43,12 @@ class KeyboardUtils @Inject constructor() { }, SHOW_INPUT_DELAY_MILLIS) } + fun hideKeyboardFrom(context: Context, view: View) { + view.clearFocus() + val imm = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(view.windowToken, 0) + } + companion object { private const val SHOW_INPUT_DELAY_MILLIS = 100L } diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index 5514622bf6e3..32e8e693f17c 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -227,6 +227,60 @@ + + + + + + + + + + + + + + share_process_change_name_container, share_process_download_limit_switch, + share_process_download_limit_container, share_process_remaining_download_count_tv" /> Delete Link Settings Confirm + Download Limit + Download limit cannot be empty. + Enter download limit + Downloads: %s + Download limit should be greater than 0. Strict mode: no HTTP connection allowed! Destination filename Suggest From bbdd82a5605ccaea7196c5835894f810ab961e63 Mon Sep 17 00:00:00 2001 From: A117870935 Date: Thu, 27 Apr 2023 13:43:29 +0530 Subject: [PATCH 2/4] Test case updated. --- .../android/ui/fragment/FileDetailSharingFragmentIT.kt | 4 ++++ .../owncloud/android/ui/helpers/FileOperationsHelper.java | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 404f31485b2d..7bf0da364642 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -269,6 +269,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(not(isDisplayed()))) + onView(ViewMatchers.withId(R.id.share_process_download_limit_switch)).check(matches(not(isDisplayed()))) // read-only onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isChecked())) @@ -397,6 +398,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(not(isDisplayed()))) + onView(ViewMatchers.withId(R.id.share_process_download_limit_switch)).check(matches(isDisplayed())) // read-only publicShare.permissions = 17 // from server @@ -514,6 +516,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.share_process_download_limit_switch)).check(matches(not(isDisplayed()))) // read-only userShare.permissions = 17 // from server @@ -637,6 +640,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.share_process_download_limit_switch)).check(matches(not(isDisplayed()))) // read-only userShare.permissions = 17 // from server diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index ee41634950fa..3799cd153a66 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -636,9 +636,10 @@ public void unshareShare(OCFile file, OCShare share) { private void queueShareIntent(Intent shareIntent) { // Unshare the file - mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(shareIntent); - - fileActivity.showLoadingDialog(fileActivity.getApplicationContext().getString(R.string.wait_a_moment)); + if(fileActivity.getOperationsServiceBinder() != null) { + mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(shareIntent); + fileActivity.showLoadingDialog(fileActivity.getApplicationContext().getString(R.string.wait_a_moment)); + } } /** From 650a89f71826334bc297b61549e226f3012255db Mon Sep 17 00:00:00 2001 From: A117870935 Date: Thu, 27 Apr 2023 13:44:52 +0530 Subject: [PATCH 3/4] Copyright updated. --- .../fragment/FileDetailSharingFragmentIT.kt | 2 +- .../operations/UpdateShareInfoOperation.java | 2 +- ...DeleteShareDownloadLimitRemoteOperation.kt | 28 +++++++++------- .../download_limit/DownloadLimitResponse.kt | 22 +++++++++++++ .../download_limit/DownloadLimitXMLParser.kt | 22 +++++++++++++ .../GetShareDownloadLimitOperation.kt | 28 +++++++++------- .../download_limit/ShareDownloadLimitUtils.kt | 32 +++++++++++-------- ...UpdateShareDownloadLimitRemoteOperation.kt | 28 +++++++++------- .../android/services/OperationsService.java | 2 +- .../android/ui/activity/FileActivity.java | 2 +- .../fragment/FileDetailSharingFragment.java | 2 +- .../FileDetailsSharingProcessFragment.kt | 2 +- .../owncloud/android/utils/KeyboardUtils.kt | 2 ++ .../file_details_sharing_process_fragment.xml | 2 +- 14 files changed, 120 insertions(+), 56 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 7bf0da364642..d0beb01ba579 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -6,7 +6,7 @@ * @author TSI-mc * Copyright (C) 2020 Tobias Kaminsky * Copyright (C) 2020 Nextcloud GmbH - * Copyright (C) 2021 TSI-mc + * Copyright (C) 2023 TSI-mc * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by diff --git a/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java b/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java index 281ad851b1d9..930ad74dacd2 100644 --- a/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java @@ -2,7 +2,7 @@ * Nextcloud Android client application * * @author TSI-mc - * Copyright (C) 2021 TSI-mc + * Copyright (C) 2023 TSI-mc * Copyright (C) 2021 Nextcloud GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/DeleteShareDownloadLimitRemoteOperation.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/DeleteShareDownloadLimitRemoteOperation.kt index 3ad41ddd9ab9..7988030cdec8 100644 --- a/app/src/main/java/com/owncloud/android/operations/download_limit/DeleteShareDownloadLimitRemoteOperation.kt +++ b/app/src/main/java/com/owncloud/android/operations/download_limit/DeleteShareDownloadLimitRemoteOperation.kt @@ -1,21 +1,25 @@ -/** - * ownCloud Android client application - * - * @author TSI-mc Copyright (C) 2021 TSI-mc +/* * + * Nextcloud Android client application * - * 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. + * @author TSI-mc + * Copyright (C) 2023 TSI-mc + * Copyright (C) 2023 Nextcloud GmbH * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * 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. + * 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 Affero 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 - * //www.gnu.org/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ + package com.owncloud.android.operations.download_limit import com.owncloud.android.lib.common.OwnCloudClient diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitResponse.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitResponse.kt index 29ebad9e9829..3740701a271e 100644 --- a/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitResponse.kt +++ b/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitResponse.kt @@ -1,3 +1,25 @@ +/* + * + * Nextcloud Android client application + * + * @author TSI-mc + * Copyright (C) 2023 TSI-mc + * Copyright (C) 2023 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + package com.owncloud.android.operations.download_limit /** diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitXMLParser.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitXMLParser.kt index 4f016d813600..16f5589218f8 100644 --- a/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitXMLParser.kt +++ b/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitXMLParser.kt @@ -1,3 +1,25 @@ +/* + * + * Nextcloud Android client application + * + * @author TSI-mc + * Copyright (C) 2023 TSI-mc + * Copyright (C) 2023 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + package com.owncloud.android.operations.download_limit import android.util.Xml diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/GetShareDownloadLimitOperation.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/GetShareDownloadLimitOperation.kt index cd74e38d99a5..f9ea43da8bd1 100644 --- a/app/src/main/java/com/owncloud/android/operations/download_limit/GetShareDownloadLimitOperation.kt +++ b/app/src/main/java/com/owncloud/android/operations/download_limit/GetShareDownloadLimitOperation.kt @@ -1,21 +1,25 @@ -/** - * ownCloud Android client application - * - * @author TSI-mc Copyright (C) 2021 TSI-mc +/* * + * Nextcloud Android client application * - * 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. + * @author TSI-mc + * Copyright (C) 2023 TSI-mc + * Copyright (C) 2023 Nextcloud GmbH * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * 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. + * 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 Affero 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 - * //www.gnu.org/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ + package com.owncloud.android.operations.download_limit import com.owncloud.android.lib.common.OwnCloudClient diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/ShareDownloadLimitUtils.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/ShareDownloadLimitUtils.kt index 1316989e6981..b0b2d0dfedb3 100644 --- a/app/src/main/java/com/owncloud/android/operations/download_limit/ShareDownloadLimitUtils.kt +++ b/app/src/main/java/com/owncloud/android/operations/download_limit/ShareDownloadLimitUtils.kt @@ -1,17 +1,23 @@ -/** - * ownCloud Android client application +/* * - * @author TSI-mc Copyright (C) 2021 TSI-mc - *

- * 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 - * . + * Nextcloud Android client application + * + * @author TSI-mc + * Copyright (C) 2023 TSI-mc + * Copyright (C) 2023 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ package com.owncloud.android.operations.download_limit diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/UpdateShareDownloadLimitRemoteOperation.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/UpdateShareDownloadLimitRemoteOperation.kt index 2addbbe8aae6..16613c2c146e 100644 --- a/app/src/main/java/com/owncloud/android/operations/download_limit/UpdateShareDownloadLimitRemoteOperation.kt +++ b/app/src/main/java/com/owncloud/android/operations/download_limit/UpdateShareDownloadLimitRemoteOperation.kt @@ -1,21 +1,25 @@ -/** - * ownCloud Android client application - * - * @author TSI-mc Copyright (C) 2021 TSI-mc +/* * + * Nextcloud Android client application * - * 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. + * @author TSI-mc + * Copyright (C) 2023 TSI-mc + * Copyright (C) 2023 Nextcloud GmbH * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * 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. + * 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 Affero 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 - * //www.gnu.org/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ + package com.owncloud.android.operations.download_limit import android.util.Pair diff --git a/app/src/main/java/com/owncloud/android/services/OperationsService.java b/app/src/main/java/com/owncloud/android/services/OperationsService.java index 4c669e867dda..8323b8883d2b 100644 --- a/app/src/main/java/com/owncloud/android/services/OperationsService.java +++ b/app/src/main/java/com/owncloud/android/services/OperationsService.java @@ -7,7 +7,7 @@ * @author TSI-mc * Copyright (C) 2015 ownCloud Inc. * Copyright (C) 2018 Andy Scherzinger - * Copyright (C) 2021 TSI-mc + * Copyright (C) 2023 TSI-mc * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index d9df4ce1fddb..26fd8508d5cf 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -7,7 +7,7 @@ * Copyright (C) 2011 Bartek Przybylski * Copyright (C) 2016 ownCloud Inc. * Copyright (C) 2019 Chris Narkiewicz - * Copyright (C) 2021 TSI-mc + * Copyright (C) 2023 TSI-mc * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index 1c04b7cc1791..68e80271efd0 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -7,7 +7,7 @@ * * Copyright (C) 2018 Andy Scherzinger * Copyright (C) 2020 Chris Narkiewicz - * Copyright (C) 2020 TSI-mc + * Copyright (C) 2023 TSI-mc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index fa152ecd5546..30086833087b 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -2,7 +2,7 @@ * Nextcloud Android client application * * @author TSI-mc - * Copyright (C) 2021 TSI-mc + * Copyright (C) 2023 TSI-mc * Copyright (C) 2021 Nextcloud GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/app/src/main/java/com/owncloud/android/utils/KeyboardUtils.kt b/app/src/main/java/com/owncloud/android/utils/KeyboardUtils.kt index e1e812d8213d..8f4898e695c4 100644 --- a/app/src/main/java/com/owncloud/android/utils/KeyboardUtils.kt +++ b/app/src/main/java/com/owncloud/android/utils/KeyboardUtils.kt @@ -2,8 +2,10 @@ * Nextcloud Android client application * * @author Álvaro Brey + * @author TSI-mc * Copyright (C) 2022 Álvaro Brey * Copyright (C) 2022 Nextcloud GmbH + * Copyright (C) 2023 TSI-mc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index 32e8e693f17c..597987f72e3a 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -3,7 +3,7 @@ Nextcloud Android client application @author TSI-mc - Copyright (C) 2021 TSI-mc + Copyright (C) 2023 TSI-mc Copyright (C) 2021 Nextcloud GmbH This program is free software: you can redistribute it and/or modify From f21db867d84c05cf1e05907cf58ee45ce57921f4 Mon Sep 17 00:00:00 2001 From: A117870935 Date: Wed, 3 May 2023 00:38:07 +0530 Subject: [PATCH 4/4] Download limit operations moved to android-library. --- .../operations/UpdateShareInfoOperation.java | 4 +- ...DeleteShareDownloadLimitRemoteOperation.kt | 81 ----- .../download_limit/DownloadLimitResponse.kt | 40 --- .../download_limit/DownloadLimitXMLParser.kt | 285 ------------------ .../GetShareDownloadLimitOperation.kt | 83 ----- .../download_limit/ShareDownloadLimitUtils.kt | 36 --- ...UpdateShareDownloadLimitRemoteOperation.kt | 100 ------ .../android/services/OperationsService.java | 2 +- .../android/ui/activity/FileActivity.java | 4 +- 9 files changed, 5 insertions(+), 630 deletions(-) delete mode 100644 app/src/main/java/com/owncloud/android/operations/download_limit/DeleteShareDownloadLimitRemoteOperation.kt delete mode 100644 app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitResponse.kt delete mode 100644 app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitXMLParser.kt delete mode 100644 app/src/main/java/com/owncloud/android/operations/download_limit/GetShareDownloadLimitOperation.kt delete mode 100644 app/src/main/java/com/owncloud/android/operations/download_limit/ShareDownloadLimitUtils.kt delete mode 100644 app/src/main/java/com/owncloud/android/operations/download_limit/UpdateShareDownloadLimitRemoteOperation.kt diff --git a/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java b/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java index 930ad74dacd2..20c2644d8a7c 100644 --- a/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java @@ -28,13 +28,13 @@ import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.lib.resources.download_limit.DeleteShareDownloadLimitRemoteOperation; +import com.owncloud.android.lib.resources.download_limit.UpdateShareDownloadLimitRemoteOperation; import com.owncloud.android.lib.resources.shares.GetShareRemoteOperation; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.lib.resources.shares.UpdateShareRemoteOperation; import com.owncloud.android.operations.common.SyncOperation; -import com.owncloud.android.operations.download_limit.DeleteShareDownloadLimitRemoteOperation; -import com.owncloud.android.operations.download_limit.UpdateShareDownloadLimitRemoteOperation; /** diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/DeleteShareDownloadLimitRemoteOperation.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/DeleteShareDownloadLimitRemoteOperation.kt deleted file mode 100644 index 7988030cdec8..000000000000 --- a/app/src/main/java/com/owncloud/android/operations/download_limit/DeleteShareDownloadLimitRemoteOperation.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * - * Nextcloud Android client application - * - * @author TSI-mc - * Copyright (C) 2023 TSI-mc - * Copyright (C) 2023 Nextcloud GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package com.owncloud.android.operations.download_limit - -import com.owncloud.android.lib.common.OwnCloudClient -import com.owncloud.android.lib.common.operations.RemoteOperation -import com.owncloud.android.lib.common.operations.RemoteOperationResult -import com.owncloud.android.lib.common.utils.Log_OC -import org.apache.commons.httpclient.HttpStatus -import org.apache.commons.httpclient.methods.DeleteMethod - -/** - * class to delete the download limit for the link share - * this has to be executed when user has toggled off the download limit - * - * - * API : //DELETE to /ocs/v2.php/apps/files_downloadlimit/{share_token}/limit - */ -class DeleteShareDownloadLimitRemoteOperation(private val shareToken: String) : - RemoteOperation() { - override fun run(client: OwnCloudClient): RemoteOperationResult { - var result: RemoteOperationResult - val status: Int - var deleteMethod: DeleteMethod? = null - try { - // Post Method - deleteMethod = DeleteMethod( - client.baseUri.toString() + ShareDownloadLimitUtils.getDownloadLimitApiPath( - shareToken - ) - ) - deleteMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE) - status = client.executeMethod(deleteMethod) - if (isSuccess(status)) { - val response = deleteMethod.responseBodyAsString - Log_OC.d(TAG, "Delete Download Limit response: $response") - val parser = DownloadLimitXMLParser() - result = parser.parse(true, response) - if (result.isSuccess) { - return result - } - } else { - result = RemoteOperationResult(false, deleteMethod) - } - } catch (e: Exception) { - result = RemoteOperationResult(e) - Log_OC.e(TAG, "Exception while deleting share download limit", e) - } finally { - deleteMethod?.releaseConnection() - } - return result - } - - private fun isSuccess(status: Int): Boolean { - return status == HttpStatus.SC_OK || status == HttpStatus.SC_BAD_REQUEST - } - - companion object { - private val TAG = DeleteShareDownloadLimitRemoteOperation::class.java.simpleName - } -} \ No newline at end of file diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitResponse.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitResponse.kt deleted file mode 100644 index 3740701a271e..000000000000 --- a/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitResponse.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Nextcloud Android client application - * - * @author TSI-mc - * Copyright (C) 2023 TSI-mc - * Copyright (C) 2023 Nextcloud GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package com.owncloud.android.operations.download_limit - -/** - * response from the Get download limit api - * - * - * - * ok - * 200 - * OK - * - * - * 5 - * 0 - * - * - */ -data class DownloadLimitResponse(var limit: Long = 0, var count: Long = 0) \ No newline at end of file diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitXMLParser.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitXMLParser.kt deleted file mode 100644 index 16f5589218f8..000000000000 --- a/app/src/main/java/com/owncloud/android/operations/download_limit/DownloadLimitXMLParser.kt +++ /dev/null @@ -1,285 +0,0 @@ -/* - * - * Nextcloud Android client application - * - * @author TSI-mc - * Copyright (C) 2023 TSI-mc - * Copyright (C) 2023 Nextcloud GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package com.owncloud.android.operations.download_limit - -import android.util.Xml -import com.owncloud.android.lib.common.operations.RemoteOperationResult -import com.owncloud.android.lib.common.utils.Log_OC -import org.xmlpull.v1.XmlPullParser -import org.xmlpull.v1.XmlPullParserException -import org.xmlpull.v1.XmlPullParserFactory -import java.io.ByteArrayInputStream -import java.io.IOException -import java.io.InputStream - -/** - * class to parse the Download Limit api XML response This class code referenced from java in NC library - */ -class DownloadLimitXMLParser { - // Getters and Setters - var status: String? = null - var statusCode = 0 - var message = "" - val isSuccess: Boolean - get() = statusCode == SUCCESS || statusCode == OK - private val isForbidden: Boolean - get() = statusCode == ERROR_FORBIDDEN - private val isNotFound: Boolean - get() = statusCode == ERROR_NOT_FOUND - private val isWrongParameter: Boolean - get() = statusCode == ERROR_WRONG_PARAMETER - - /** - * method to parse the Download limit response - * @param isGet check if parsing has to do for GET api or not - * because the parsing will depend on that - * if API is GET then response will have tag else it wont have - * @param serverResponse - * @return - */ - fun parse(isGet: Boolean, serverResponse: String?): RemoteOperationResult { - if (serverResponse == null || serverResponse.isEmpty()) { - return RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE) - } - var result: RemoteOperationResult - try { - // Parse xml response and obtain the list of downloadLimitResponse - val inputStream: InputStream = ByteArrayInputStream(serverResponse.toByteArray()) - val downloadLimitResponse = parseXMLResponse(inputStream) - if (isSuccess) { - if (isGet) { - result = RemoteOperationResult(RemoteOperationResult.ResultCode.OK) - result.setResultData(downloadLimitResponse) - } else { - result = RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE) - Log_OC.e(TAG, "Successful status with no share in the response") - } - } else if (isWrongParameter) { - result = RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_WRONG_PARAMETER) - result.setMessage(message) - } else if (isNotFound) { - result = RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND) - result.setMessage(message) - } else if (isForbidden) { - result = RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_FORBIDDEN) - result.setMessage(message) - } else { - result = RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE) - result.setMessage(message) - } - } catch (e: XmlPullParserException) { - Log_OC.e(TAG, "Error parsing response from server ", e) - result = RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE) - } catch (e: IOException) { - Log_OC.e(TAG, "Error reading response from server ", e) - result = RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE) - } - return result - } - - /** - * Parse is as response of Share API - * - * @param `is` InputStream to parse - * @return List of ShareRemoteFiles - * @throws XmlPullParserException - * @throws IOException - */ - @Throws(XmlPullParserException::class, IOException::class) - private fun parseXMLResponse(inputStream: InputStream): DownloadLimitResponse { - return inputStream.use { - // XMLPullParser - val factory = XmlPullParserFactory.newInstance() - factory.isNamespaceAware = true - val parser = Xml.newPullParser() - parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false) - parser.setInput(it, null) - parser.nextTag() - readOCS(parser) - } - } - - /** - * Parse OCS node - * - * @param parser - * @return List of ShareRemoteFiles - * @throws XmlPullParserException - * @throws IOException - */ - @Throws(XmlPullParserException::class, IOException::class) - private fun readOCS(parser: XmlPullParser): DownloadLimitResponse { - var downloadLimitResponse = DownloadLimitResponse() - 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 - if (NODE_META.equals(name, ignoreCase = true)) { - readMeta(parser) - } else if (NODE_DATA.equals(name, ignoreCase = true)) { - downloadLimitResponse = readData(parser) - } else { - skip(parser) - } - } - return downloadLimitResponse - } - - /** - * 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 - if (NODE_STATUS.equals(name, ignoreCase = true)) { - status = readNode(parser, NODE_STATUS) - } else if (NODE_STATUS_CODE.equals(name, ignoreCase = true)) { - statusCode = readNode(parser, NODE_STATUS_CODE).toInt() - } else if (NODE_MESSAGE.equals(name, 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): DownloadLimitResponse { - val downloadLimitResponse = DownloadLimitResponse() - parser.require(XmlPullParser.START_TAG, ns, NODE_DATA) - //Log_OC.d(TAG, "---- NODE DATA ---"); - while (parser.next() != XmlPullParser.END_TAG) { - if (parser.eventType != XmlPullParser.START_TAG) { - continue - } - val name = parser.name - if (NODE_LIMIT.equals(name, ignoreCase = true)) { - val downloadLimit = readNode(parser, NODE_LIMIT) - downloadLimitResponse.limit = if (downloadLimit.isNotEmpty()) downloadLimit.toLong() else 0L - } else if (NODE_COUNT.equals(name, ignoreCase = true)) { - val downloadCount = readNode(parser, NODE_COUNT) - downloadLimitResponse.count = if (downloadCount.isNotEmpty()) downloadCount.toLong() else 0L - } else { - skip(parser) - } - } - return downloadLimitResponse - } - - /** - * 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) - //Log_OC.d(TAG, "node= " + node + ", value= " + value); - 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) { - check(parser.eventType == XmlPullParser.START_TAG) - var depth = 1 - while (depth != 0) { - when (parser.next()) { - XmlPullParser.END_TAG -> depth-- - XmlPullParser.START_TAG -> depth++ - } - } - } - - companion object { - private val TAG = DownloadLimitXMLParser::class.java.simpleName - - // 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_LIMIT = "limit" - private const val NODE_COUNT = "count" - private const val SUCCESS = 100 - private const val OK = 200 - private const val ERROR_WRONG_PARAMETER = 400 - private const val ERROR_FORBIDDEN = 403 - private const val ERROR_NOT_FOUND = 404 - } -} \ No newline at end of file diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/GetShareDownloadLimitOperation.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/GetShareDownloadLimitOperation.kt deleted file mode 100644 index f9ea43da8bd1..000000000000 --- a/app/src/main/java/com/owncloud/android/operations/download_limit/GetShareDownloadLimitOperation.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * - * Nextcloud Android client application - * - * @author TSI-mc - * Copyright (C) 2023 TSI-mc - * Copyright (C) 2023 Nextcloud GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package com.owncloud.android.operations.download_limit - -import com.owncloud.android.lib.common.OwnCloudClient -import com.owncloud.android.lib.common.operations.RemoteOperation -import com.owncloud.android.lib.common.operations.RemoteOperationResult -import com.owncloud.android.lib.common.utils.Log_OC -import com.owncloud.android.operations.download_limit.ShareDownloadLimitUtils.getDownloadLimitApiPath -import org.apache.commons.httpclient.HttpStatus -import org.apache.commons.httpclient.methods.GetMethod - -/** - * class to fetch the download limit for the link share it requires share token to fetch the data - * - * - * API : //GET to /ocs/v2.php/apps/files_downloadlimit/{share_token}/limit - */ -class GetShareDownloadLimitOperation( - //share token from OCShare - private val shareToken: String -) : RemoteOperation() { - override fun run(client: OwnCloudClient): RemoteOperationResult { - var result: RemoteOperationResult - var status = -1 - var get: GetMethod? = null - try { - // Get Method - get = GetMethod( - client.baseUri.toString() + getDownloadLimitApiPath( - shareToken - ) - ) - get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE) - status = client.executeMethod(get) - if (isSuccess(status)) { - val response = get.responseBodyAsString - Log_OC.d(TAG, "Get Download Limit response: $response") - val parser = DownloadLimitXMLParser() - result = parser.parse(true, response) - if (result.isSuccess) { - Log_OC.d(TAG, "Got " + result.resultData + " Response") - } - } else { - result = RemoteOperationResult(false, get) - } - } catch (e: Exception) { - result = RemoteOperationResult(e) - Log_OC.e(TAG, "Exception while getting share download limit", e) - } finally { - get?.releaseConnection() - } - return result - } - - private fun isSuccess(status: Int): Boolean { - return status == HttpStatus.SC_OK - } - - companion object { - private val TAG = GetShareDownloadLimitOperation::class.java.simpleName - } -} \ No newline at end of file diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/ShareDownloadLimitUtils.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/ShareDownloadLimitUtils.kt deleted file mode 100644 index b0b2d0dfedb3..000000000000 --- a/app/src/main/java/com/owncloud/android/operations/download_limit/ShareDownloadLimitUtils.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * - * Nextcloud Android client application - * - * @author TSI-mc - * Copyright (C) 2023 TSI-mc - * Copyright (C) 2023 Nextcloud GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package com.owncloud.android.operations.download_limit - -object ShareDownloadLimitUtils { - - private const val SHARE_TOKEN_PATH = "{share_token}" - - //ocs route - //replace the {share_token} - private const val SHARE_DOWNLOAD_LIMIT_API_PATH = "/ocs/v2.php/apps/files_downloadlimit/$SHARE_TOKEN_PATH/limit" - - fun getDownloadLimitApiPath(shareToken: String): String { - return SHARE_DOWNLOAD_LIMIT_API_PATH.replace(SHARE_TOKEN_PATH, shareToken) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/owncloud/android/operations/download_limit/UpdateShareDownloadLimitRemoteOperation.kt b/app/src/main/java/com/owncloud/android/operations/download_limit/UpdateShareDownloadLimitRemoteOperation.kt deleted file mode 100644 index 16613c2c146e..000000000000 --- a/app/src/main/java/com/owncloud/android/operations/download_limit/UpdateShareDownloadLimitRemoteOperation.kt +++ /dev/null @@ -1,100 +0,0 @@ -/* - * - * Nextcloud Android client application - * - * @author TSI-mc - * Copyright (C) 2023 TSI-mc - * Copyright (C) 2023 Nextcloud GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package com.owncloud.android.operations.download_limit - -import android.util.Pair -import com.owncloud.android.lib.common.OwnCloudClient -import com.owncloud.android.lib.common.operations.RemoteOperation -import com.owncloud.android.lib.common.operations.RemoteOperationResult -import com.owncloud.android.lib.common.utils.Log_OC -import com.owncloud.android.operations.download_limit.ShareDownloadLimitUtils.getDownloadLimitApiPath -import org.apache.commons.httpclient.HttpStatus -import org.apache.commons.httpclient.methods.PutMethod -import org.apache.commons.httpclient.methods.StringRequestEntity - -/** - * class to update the download limit for the link share - * - * - * API : //PUT to /ocs/v2.php/apps/files_downloadlimit/{share_token}/limit - * - * - * Body: {"token" : "Bpd4oEAgPqn3AbG", "limit" : 5} - */ -class UpdateShareDownloadLimitRemoteOperation(private val shareToken: String, private val downloadLimit: Long) : - RemoteOperation() { - override fun run(client: OwnCloudClient): RemoteOperationResult { - var result: RemoteOperationResult - val status: Int - var put: PutMethod? = null - try { - // Post Method - put = PutMethod( - client.baseUri.toString() + getDownloadLimitApiPath( - shareToken - ) - ) - put.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE) - val parametersToUpdate: MutableList> = ArrayList() - parametersToUpdate.add(Pair(PARAM_TOKEN, shareToken)) - parametersToUpdate.add(Pair(PARAM_LIMIT, downloadLimit.toString())) - for (parameter in parametersToUpdate) { - put.requestEntity = StringRequestEntity( - parameter.first + "=" + parameter.second, - ENTITY_CONTENT_TYPE, - ENTITY_CHARSET - ) - } - status = client.executeMethod(put) - if (isSuccess(status)) { - val response = put.responseBodyAsString - Log_OC.d(TAG, "Download Limit response: $response") - val parser = DownloadLimitXMLParser() - result = parser.parse(true, response) - if (result.isSuccess) { - return result - } - } else { - result = RemoteOperationResult(false, put) - } - } catch (e: Exception) { - result = RemoteOperationResult(e) - Log_OC.e(TAG, "Exception while updating share download limit", e) - } finally { - put?.releaseConnection() - } - return result - } - - private fun isSuccess(status: Int): Boolean { - return status == HttpStatus.SC_OK || status == HttpStatus.SC_BAD_REQUEST - } - - companion object { - private val TAG = UpdateShareDownloadLimitRemoteOperation::class.java.simpleName - private const val PARAM_TOKEN = "token" - private const val PARAM_LIMIT = "limit" - private const val ENTITY_CONTENT_TYPE = "application/x-www-form-urlencoded" - private const val ENTITY_CHARSET = "UTF-8" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/owncloud/android/services/OperationsService.java b/app/src/main/java/com/owncloud/android/services/OperationsService.java index 8323b8883d2b..25d0b0b6b9f4 100644 --- a/app/src/main/java/com/owncloud/android/services/OperationsService.java +++ b/app/src/main/java/com/owncloud/android/services/OperationsService.java @@ -52,6 +52,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.lib.resources.download_limit.GetShareDownloadLimitOperation; import com.owncloud.android.lib.resources.files.RestoreFileVersionRemoteOperation; import com.owncloud.android.lib.resources.files.model.FileVersion; import com.owncloud.android.lib.resources.shares.OCShare; @@ -73,7 +74,6 @@ import com.owncloud.android.operations.UpdateShareInfoOperation; import com.owncloud.android.operations.UpdateSharePermissionsOperation; import com.owncloud.android.operations.UpdateShareViaLinkOperation; -import com.owncloud.android.operations.download_limit.GetShareDownloadLimitOperation; import java.io.IOException; import java.util.Iterator; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index 26fd8508d5cf..0da269f60a6b 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -66,6 +66,8 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.lib.resources.download_limit.GetShareDownloadLimitOperation; +import com.owncloud.android.lib.resources.download_limit.model.DownloadLimitResponse; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.operations.CreateShareViaLinkOperation; @@ -78,8 +80,6 @@ import com.owncloud.android.operations.UpdateShareInfoOperation; import com.owncloud.android.operations.UpdateSharePermissionsOperation; import com.owncloud.android.operations.UpdateShareViaLinkOperation; -import com.owncloud.android.operations.download_limit.DownloadLimitResponse; -import com.owncloud.android.operations.download_limit.GetShareDownloadLimitOperation; import com.owncloud.android.providers.UsersAndGroupsSearchProvider; import com.owncloud.android.services.OperationsService; import com.owncloud.android.services.OperationsService.OperationsServiceBinder;