From 12429b7ab955c872eee561cba0dd0edffd3c983b Mon Sep 17 00:00:00 2001 From: davigonz Date: Tue, 8 May 2018 12:53:32 +0200 Subject: [PATCH 1/5] Update operation to get remote user quota --- .../lib/common/network/WebdavUtils.java | 11 ++ .../operations/RemoteOperationResult.java | 9 +- .../files/ReadRemoteFolderOperation.java | 1 - .../users/GetRemoteUserQuotaOperation.java | 129 ++++++++++-------- 4 files changed, 91 insertions(+), 59 deletions(-) diff --git a/src/com/owncloud/android/lib/common/network/WebdavUtils.java b/src/com/owncloud/android/lib/common/network/WebdavUtils.java index 8c307b60..1bbf3aa9 100644 --- a/src/com/owncloud/android/lib/common/network/WebdavUtils.java +++ b/src/com/owncloud/android/lib/common/network/WebdavUtils.java @@ -140,6 +140,17 @@ public class WebdavUtils { return propSet; } + /** + * Builds a DavPropertyNameSet with properties for user quotas + * @return set of quota properties + */ + public static DavPropertyNameSet getQuotaPropSet() { + DavPropertyNameSet propSet = new DavPropertyNameSet(); + propSet.add(DavPropertyName.create(WebdavEntry.PROPERTY_QUOTA_AVAILABLE_BYTES)); + propSet.add(DavPropertyName.create(WebdavEntry.PROPERTY_QUOTA_USED_BYTES)); + return propSet; + } + /** * * @param rawEtag diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java index e8699e7d..56722fe5 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java @@ -1,5 +1,5 @@ /* ownCloud Android Library is available under MIT license - * Copyright (C) 2016 ownCloud GmbH. + * Copyright (C) 2018 ownCloud GmbH. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -55,11 +55,12 @@ import javax.net.ssl.SSLException; /** * The result of a remote operation required to an ownCloud server. - *

+ * * Provides a common classification of remote operation results for all the * application. * * @author David A. Velasco + * @author David González Verdugo */ public class RemoteOperationResult implements Serializable { @@ -378,8 +379,8 @@ public class RemoteOperationResult implements Serializable { } } - public void setData(ArrayList files) { - mData = files; + public void setData(ArrayList items) { + mData = items; } public ArrayList getData() { diff --git a/src/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java b/src/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java index 53b8295f..d6caae8e 100644 --- a/src/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java +++ b/src/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java @@ -150,7 +150,6 @@ public class ReadRemoteFolderOperation extends RemoteOperation { remoteFile = fillOCFile(we); mFolderAndFiles.add(remoteFile); } - } /** diff --git a/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java b/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java index a1e64aca..d6e9c4c6 100644 --- a/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java +++ b/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java @@ -1,6 +1,6 @@ /* ownCloud Android Library is available under MIT license * - * Copyright (C) 2015 ownCloud Inc. + * Copyright (C) 2018 ownCloud Inc. * Copyright (C) 2015 Bartosz Przybylski * Copyright (C) 2014 Marcello Steiner * @@ -28,20 +28,23 @@ package com.owncloud.android.lib.resources.users; import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.authentication.OwnCloudCredentials; +import com.owncloud.android.lib.common.network.WebdavEntry; +import com.owncloud.android.lib.common.network.WebdavUtils; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.NameValuePair; -import org.apache.commons.httpclient.methods.GetMethod; -import org.json.JSONObject; +import org.apache.jackrabbit.webdav.DavConstants; +import org.apache.jackrabbit.webdav.MultiStatus; +import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; +import java.math.BigDecimal; import java.util.ArrayList; /** * @author marcello + * @author David González Verdugo */ public class GetRemoteUserQuotaOperation extends RemoteOperation { @@ -64,72 +67,66 @@ public class GetRemoteUserQuotaOperation extends RemoteOperation { private static final String TAG = GetRemoteUserQuotaOperation.class.getSimpleName(); - private static final String NODE_OCS = "ocs"; - private static final String NODE_DATA = "data"; - private static final String NODE_QUOTA = "quota"; - private static final String NODE_QUOTA_FREE = "free"; - private static final String NODE_QUOTA_USED = "used"; - private static final String NODE_QUOTA_TOTAL = "total"; - private static final String NODE_QUOTA_RELATIVE = "relative"; + private String mRemotePath; - // OCS Route - private static final String OCS_ROUTE ="/ocs/v1.php/cloud/users/"; + /** + * Constructor + * + * @param remotePath Remote path of the file. + */ + public GetRemoteUserQuotaOperation(String remotePath) { + mRemotePath = remotePath; + } @Override protected RemoteOperationResult run(OwnCloudClient client) { RemoteOperationResult result = null; - int status; - GetMethod get = null; + PropFindMethod query = null; - - //Get the user try { - OwnCloudCredentials credentials = client.getCredentials(); - String url = client.getBaseUri() + OCS_ROUTE + credentials.getUsername(); + // remote request + query = new PropFindMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath), + WebdavUtils.getQuotaPropSet(), + DavConstants.DEPTH_0); - get = new GetMethod(url); - get.setQueryString(new NameValuePair[]{new NameValuePair("format","json")}); - get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE); - status = client.executeMethod(get); + int status = client.executeMethod(query); - if(isSuccess(status)) { - String response = get.getResponseBodyAsString(); + if (isSuccess(status)) { + // get data from remote folder + MultiStatus dataInServer = query.getResponseBodyAsMultiStatus(); + Quota quota = readData(dataInServer, client); - // Parse the response - JSONObject respJSON = new JSONObject(response); - JSONObject respOCS = respJSON.getJSONObject(NODE_OCS); - JSONObject respData = respOCS.getJSONObject(NODE_DATA); - JSONObject quota = respData.getJSONObject(NODE_QUOTA); - final Long quotaFree = quota.getLong(NODE_QUOTA_FREE); - final Long quotaUsed = quota.getLong(NODE_QUOTA_USED); - final Long quotaTotal = quota.getLong(NODE_QUOTA_TOTAL); - final Double quotaRelative = quota.getDouble(NODE_QUOTA_RELATIVE); + // Result of the operation + result = new RemoteOperationResult(true, query); + ArrayList data = new ArrayList<>(); + data.add(quota); - // Result - result = new RemoteOperationResult(true, get); - //Quota data in data collection - ArrayList data = new ArrayList(); - data.add(new Quota(quotaFree, quotaUsed, quotaTotal, quotaRelative)); - result.setData(data); - - } else { - result = new RemoteOperationResult(false, get); - String response = get.getResponseBodyAsString(); - Log_OC.e(TAG, "Failed response while getting user quota information "); - if (response != null) { - Log_OC.e(TAG, "*** status code: " + status + " ; response message: " + response); - } else { - Log_OC.e(TAG, "*** status code: " + status); + // Add data to the result + if (result.isSuccess()) { + result.setData(data); } + } else { + // synchronization failed + result = new RemoteOperationResult(false, query); } + } catch (Exception e) { result = new RemoteOperationResult(e); - Log_OC.e(TAG, "Exception while getting OC user information", e); + } finally { - if (get != null) { - get.releaseConnection(); + if (query != null) + query.releaseConnection(); // let the connection available for other methods + if (result.isSuccess()) { + Log_OC.i(TAG, "Get quota from " + mRemotePath + ": " + result.getLogMessage()); + } else { + if (result.isException()) { + Log_OC.e(TAG, "Get quota from " + mRemotePath + ": " + result.getLogMessage(), + result.getException()); + } else { + Log_OC.e(TAG, "Get quota from " + mRemotePath + ": " + result.getLogMessage()); + } } } @@ -137,8 +134,32 @@ public class GetRemoteUserQuotaOperation extends RemoteOperation { } private boolean isSuccess(int status) { - return (status == HttpStatus.SC_OK); + return status == HttpStatus.SC_MULTI_STATUS || status == HttpStatus.SC_OK; } + /** + * Read the data retrieved from the server about the quota + * + * @param remoteData Full response got from the server with the data of the quota + * @param client Client instance to the remote server where the data were retrieved + * @return new Quota instance representing the data read from the server + */ + private Quota readData(MultiStatus remoteData, OwnCloudClient client) { + // parse data from remote folder + WebdavEntry we = new WebdavEntry(remoteData.getResponses()[0], client.getWebdavUri().getPath()); + + BigDecimal totalQuota = we.quotaAvailableBytes().add(we.quotaUsedBytes()); + + BigDecimal relativeQuota = we.quotaUsedBytes().multiply(new BigDecimal(100)).divide(totalQuota); + + Quota quota = new Quota( + we.quotaAvailableBytes().longValue(), + we.quotaUsedBytes().longValue(), + totalQuota.longValue(), + relativeQuota.doubleValue() + ); + + return quota; + } } From ec08bfbd7acc7a170eaeaf593fcdc1ced4875002 Mon Sep 17 00:00:00 2001 From: davigonz Date: Tue, 8 May 2018 13:16:07 +0200 Subject: [PATCH 2/5] Fix get quota test --- .../owncloud/android/lib/test_project/TestActivity.java | 7 ++++--- .../android/lib/test_project/test/GetUserQuotaTest.java | 8 ++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java b/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java index 9b9ecc3d..46beb44e 100644 --- a/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java +++ b/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java @@ -1,5 +1,5 @@ /* ownCloud Android Library is available under MIT license - * Copyright (C) 2016 ownCloud GmbH. + * Copyright (C) 2018 ownCloud GmbH. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -65,6 +65,7 @@ import com.owncloud.android.lib.resources.users.GetRemoteUserAvatarOperation; * Activity to test OC framework * @author masensio * @author David A. Velasco + * @author David González Verdugo */ public class TestActivity extends Activity { @@ -338,8 +339,8 @@ public class TestActivity extends Activity { } - public RemoteOperationResult getQuota() { - GetRemoteUserQuotaOperation getUserQuotaOperation = new GetRemoteUserQuotaOperation(); + public RemoteOperationResult getQuota(String remotePath) { + GetRemoteUserQuotaOperation getUserQuotaOperation = new GetRemoteUserQuotaOperation(remotePath); return getUserQuotaOperation.execute(mClient); } diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/GetUserQuotaTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/GetUserQuotaTest.java index b18c90a5..8d4f41a8 100644 --- a/test_client/tests/src/com/owncloud/android/lib/test_project/test/GetUserQuotaTest.java +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/GetUserQuotaTest.java @@ -1,6 +1,6 @@ /* ownCloud Android Library is available under MIT license * - * Copyright (C) 2015 ownCloud Inc. + * Copyright (C) 2018 ownCloud Inc. * Copyright (C) 2015 Bartosz Przybylski * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -38,6 +38,7 @@ import com.owncloud.android.lib.test_project.TestActivity; * * @author Bartosz Przybylski * @author David A. Velasco + * @author David González Verdugo */ public class GetUserQuotaTest extends RemoteTest { @@ -45,6 +46,8 @@ public class GetUserQuotaTest extends RemoteTest { private static final String LOG_TAG = GetUserQuotaTest.class.getCanonicalName(); private TestActivity mActivity; + private String mFullPath2Root; + private String ROOT_PATH = "/"; @Override @@ -52,13 +55,14 @@ public class GetUserQuotaTest extends RemoteTest { super.setUp(); setActivityInitialTouchMode(false); mActivity = getActivity(); + mFullPath2Root = mBaseFolderPath + ROOT_PATH; } /** * Test GetUserQuota */ public void testGetUserQuota() { - RemoteOperationResult result = mActivity.getQuota(); + RemoteOperationResult result = mActivity.getQuota(mFullPath2Root); assertTrue(result.isSuccess()); Quota quota = (Quota)((ArrayList)result.getData()).get(0); assertTrue(quota.getFree() >= 0); From a21614fd5a1e48644d00402e539464fbbaa3d1df Mon Sep 17 00:00:00 2001 From: davigonz Date: Tue, 8 May 2018 17:13:37 +0200 Subject: [PATCH 3/5] Handle pending, unknown and unlimited quota --- .../users/GetRemoteUserQuotaOperation.java | 41 +++++++++++++++---- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java b/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java index d6e9c4c6..69e775aa 100644 --- a/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java +++ b/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java @@ -49,6 +49,16 @@ import java.util.ArrayList; public class GetRemoteUserQuotaOperation extends RemoteOperation { static public class Quota { + + // Not computed yet, e.g. external storage mounted but folder sizes need scanning + public static final int PENDING_FREE_QUOTA = -1; + + // Storage not accessible, e.g. external storage with no API to ask for the free space + public static final int UNKNOWN_FREE_QUOTA = -2; + + // Quota using all the storage + public static final int UNLIMITED_FREE_QUOTA = -3; + long mFree, mUsed, mTotal; double mRelative; @@ -149,17 +159,30 @@ public class GetRemoteUserQuotaOperation extends RemoteOperation { // parse data from remote folder WebdavEntry we = new WebdavEntry(remoteData.getResponses()[0], client.getWebdavUri().getPath()); - BigDecimal totalQuota = we.quotaAvailableBytes().add(we.quotaUsedBytes()); + // If there's a special case, available bytes will contain a negative code + if (we.quotaAvailableBytes().compareTo(new BigDecimal(0)) == -1) { - BigDecimal relativeQuota = we.quotaUsedBytes().multiply(new BigDecimal(100)).divide(totalQuota); + return new Quota( + we.quotaAvailableBytes().longValue(), + we.quotaUsedBytes().longValue(), + 0, + 0 + ); - Quota quota = new Quota( - we.quotaAvailableBytes().longValue(), - we.quotaUsedBytes().longValue(), - totalQuota.longValue(), - relativeQuota.doubleValue() - ); + } else { - return quota; + BigDecimal totalQuota = we.quotaAvailableBytes().add(we.quotaUsedBytes()); + + BigDecimal relativeQuota = we.quotaUsedBytes() + .multiply(new BigDecimal(100)) + .divide(totalQuota); + + return new Quota( + we.quotaAvailableBytes().longValue(), + we.quotaUsedBytes().longValue(), + totalQuota.longValue(), + relativeQuota.doubleValue() + ); + } } } From f3566d667e6f949d35b7fd91240a28d130b22675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Gonz=C3=A1lez?= Date: Tue, 15 May 2018 13:07:44 +0200 Subject: [PATCH 4/5] Handle case with quota 0 --- .../users/GetRemoteUserQuotaOperation.java | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java b/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java index 69e775aa..849784ed 100644 --- a/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java +++ b/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java @@ -160,8 +160,10 @@ public class GetRemoteUserQuotaOperation extends RemoteOperation { WebdavEntry we = new WebdavEntry(remoteData.getResponses()[0], client.getWebdavUri().getPath()); // If there's a special case, available bytes will contain a negative code - if (we.quotaAvailableBytes().compareTo(new BigDecimal(0)) == -1) { - + // -1, PENDING: Not computed yet, e.g. external storage mounted but folder sizes need scanning + // -2, UNKNOWN: Storage not accessible, e.g. external storage with no API to ask for the free space + // -3, UNLIMITED: Quota using all the storage + if (we.quotaAvailableBytes().compareTo(new BigDecimal(1)) == -1) { return new Quota( we.quotaAvailableBytes().longValue(), we.quotaUsedBytes().longValue(), @@ -171,18 +173,18 @@ public class GetRemoteUserQuotaOperation extends RemoteOperation { } else { - BigDecimal totalQuota = we.quotaAvailableBytes().add(we.quotaUsedBytes()); + BigDecimal totalQuota = we.quotaAvailableBytes().add(we.quotaUsedBytes()); - BigDecimal relativeQuota = we.quotaUsedBytes() - .multiply(new BigDecimal(100)) - .divide(totalQuota); + BigDecimal relativeQuota = we.quotaUsedBytes() + .multiply(new BigDecimal(100)) + .divide(totalQuota); - return new Quota( - we.quotaAvailableBytes().longValue(), - we.quotaUsedBytes().longValue(), - totalQuota.longValue(), - relativeQuota.doubleValue() - ); + return new Quota( + we.quotaAvailableBytes().longValue(), + we.quotaUsedBytes().longValue(), + totalQuota.longValue(), + relativeQuota.doubleValue() + ); } } } From fdbe23923ef047b0e527d1d9df682b5fc15af61a Mon Sep 17 00:00:00 2001 From: davigonz Date: Wed, 16 May 2018 17:47:12 +0200 Subject: [PATCH 5/5] Fix Incorrect output with Other option --- .../users/GetRemoteUserQuotaOperation.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java b/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java index 849784ed..2109efb4 100644 --- a/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java +++ b/src/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java @@ -40,6 +40,7 @@ import org.apache.jackrabbit.webdav.MultiStatus; import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.ArrayList; /** @@ -173,18 +174,18 @@ public class GetRemoteUserQuotaOperation extends RemoteOperation { } else { - BigDecimal totalQuota = we.quotaAvailableBytes().add(we.quotaUsedBytes()); + BigDecimal totalQuota = we.quotaAvailableBytes().add(we.quotaUsedBytes()); - BigDecimal relativeQuota = we.quotaUsedBytes() - .multiply(new BigDecimal(100)) - .divide(totalQuota); + BigDecimal relativeQuota = we.quotaUsedBytes() + .multiply(new BigDecimal(100)) + .divide(totalQuota, 2, RoundingMode.HALF_UP); - return new Quota( - we.quotaAvailableBytes().longValue(), - we.quotaUsedBytes().longValue(), - totalQuota.longValue(), - relativeQuota.doubleValue() - ); + return new Quota( + we.quotaAvailableBytes().longValue(), + we.quotaUsedBytes().longValue(), + totalQuota.longValue(), + relativeQuota.doubleValue() + ); } } }