diff --git a/.travis.yml b/.travis.yml index 8ccad6c8..d12be4a9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +sudo: false language: android android: components: @@ -20,8 +21,8 @@ script: - ./gradlew clean build env: global: - - secure: HxHoqnC8mauCKi87zlo7pQcSsSw0W5MtW+iUcB8T11quwTBgUPWIOmycXv2FcmwpST0E43Ct+dhE+mttm+6P+5PSB33HQNLq00hfTVIJ4ttcb/5eWW8MnP7L+kPK8d0EtfDG6GQto7QktaybeG4+sNKKD336ZlFfM7xgPtPv+tg= - - secure: WQMw0ciloe8i2ApGhePhuTmmH8UgAV1Ri10C1qhUH9hVOJAr+/1X5A93VPYGrgJ2EH5MdiL6f2XMDCYAgb9efuvZIUKNE0J92xh8m/yRa8nAVWNBE0PBdS4+OycoHpIQfMcUghooERXjP4GUYd/ZwICvWA+sXdOYWDdKjODUgl4= - - secure: QPxKT8vC7sm1b/hYJcfkQkLgpwNRBvVKk8S8S0t43mmqPJfs94FJTQHH4kZaGSwOeuDkRQbGuKzYtXOnGOKX2hhUBqKJd1idpJnUID8id8Kqo6VutjG017+XxZQp0hPHmfmDxYkDvlaLeoZpP2NkpwZ1p4TL2MSCr2Ibl6uTWvc= + - secure: a21NrzTCQnkTKtRGo7B1lyF2WWbpBT2N64V2Tf+oUcRLOUx3XM/mDi60mAdGd0WXV9tHD8GGmu0tQ7LGZ2VsIxixVxjzEYwX4HRTodewYez6WxBMjVEHHy+3jmc1zU4k3AAqr+uW7L4BKa5r9tH+nq9ecJMDMgW8o9MKXuP7Vso= + - secure: UVnaC5Qzat2C8WlMMb8aycz1ChZKjP8Kz89qBbVcqYK+PLAGKpUNxFa39/2oA5jkMyyOcXYC9bX1ZYzHLH7nJ8LbQgaxXMT4gvgvN0l6KezjDavIW60idD9BbugkwzNj/cjoU/DdxBykPsTn4vSRaESVNTdEbM27YU4FBPzTANY= + - secure: XEQY8s7p65lWWOuKbVDdTh6ZJtRTJ74Zw3H/+2Ms6vjZhFZsdUJjGo66LW6YvlhmYDXgiPB9piYQGcrGgT3hXJwXoge6n1pdixnV250J0T0dIZMbXYTWTARxDsyq48+LgUuF3pgqvqDWhBcemrePWv48q7fs/mwzuFSOyc8QwLk= matrix: - ANDROID_TARGET=android-19 ANDROID_ABI=armeabi-v7a diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java index ceb3f25f..28709905 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java @@ -107,7 +107,8 @@ public class RemoteOperationResult implements Serializable { INVALID_COPY_INTO_DESCENDANT, PARTIAL_MOVE_DONE, PARTIAL_COPY_DONE, - INVALID_CHARACTER_DETECT_IN_SERVER + SHARE_WRONG_PARAMETER, + WRONG_SERVER_RESPONSE, INVALID_CHARACTER_DETECT_IN_SERVER } private boolean mSuccess = false; diff --git a/src/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.java b/src/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.java index f3d38779..21545222 100644 --- a/src/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.java +++ b/src/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.java @@ -1,4 +1,6 @@ /* ownCloud Android Library is available under MIT license + * @author masensio + * @author David A. Velasco * Copyright (C) 2015 ownCloud Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -24,24 +26,16 @@ package com.owncloud.android.lib.resources.shares; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.ArrayList; - import org.apache.commons.httpclient.methods.PostMethod; import org.apache.http.HttpStatus; 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.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.lib.common.utils.Log_OC; /** * Creates a new share. This allows sharing with a user or group or as a link. - * - * @author masensio - * */ public class CreateRemoteShareOperation extends RemoteOperation { @@ -54,20 +48,20 @@ public class CreateRemoteShareOperation extends RemoteOperation { private static final String PARAM_PASSWORD = "password"; private static final String PARAM_PERMISSIONS = "permissions"; - private ArrayList mShares; // List of shares for result, one share in this case - private String mRemoteFilePath; private ShareType mShareType; private String mShareWith; private boolean mPublicUpload; private String mPassword; private int mPermissions; + private boolean mGetShareDetails; /** * Constructor * @param remoteFilePath Full path of the file/folder being shared. Mandatory argument * @param shareType 0 = user, 1 = group, 3 = Public link. Mandatory argument - * @param shareWith User/group ID with who the file should be shared. This is mandatory for shareType of 0 or 1 + * @param shareWith User/group ID with who the file should be shared. This is mandatory for shareType + * of 0 or 1 * @param publicUpload If false (default) public cannot upload to a public shared folder. * If true public can upload to a shared folder. Only available for public link shares * @param password Password to protect a public link share. Only available for public link shares @@ -81,8 +75,14 @@ public class CreateRemoteShareOperation extends RemoteOperation { * To obtain combinations, add the desired values together. * For instance, for Re-Share, delete, read, update, add 16+8+2+1 = 27. */ - public CreateRemoteShareOperation(String remoteFilePath, ShareType shareType, String shareWith, boolean publicUpload, - String password, int permissions) { + public CreateRemoteShareOperation( + String remoteFilePath, + ShareType shareType, + String shareWith, + boolean publicUpload, + String password, + int permissions + ) { mRemoteFilePath = remoteFilePath; mShareType = shareType; @@ -90,6 +90,15 @@ public class CreateRemoteShareOperation extends RemoteOperation { mPublicUpload = publicUpload; mPassword = password; mPermissions = permissions; + mGetShareDetails = false; // defaults to false for backwards compatibility + } + + public boolean isGettingShareDetails () { + return mGetShareDetails; + } + + public void setGetShareDetails(boolean set) { + mGetShareDetails = set; } @Override @@ -102,7 +111,6 @@ public class CreateRemoteShareOperation extends RemoteOperation { try { // Post Method post = new PostMethod(client.getBaseUri() + ShareUtils.SHARING_API_PATH); - //Log_OC.d(TAG, "URL ------> " + client.getBaseUri() + ShareUtils.SHARING_API_PATH); post.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); // necessary for special characters @@ -111,12 +119,14 @@ public class CreateRemoteShareOperation extends RemoteOperation { post.addParameter(PARAM_SHARE_TYPE, Integer.toString(mShareType.getValue())); post.addParameter(PARAM_SHARE_WITH, mShareWith); if (mPublicUpload) { - post.addParameter(PARAM_PUBLIC_UPLOAD, Boolean.toString(mPublicUpload)); + post.addParameter(PARAM_PUBLIC_UPLOAD, Boolean.toString(true)); } if (mPassword != null && mPassword.length() > 0) { post.addParameter(PARAM_PASSWORD, mPassword); } - post.addParameter(PARAM_PERMISSIONS, Integer.toString(mPermissions)); + if (OCShare.DEFAULT_PERMISSION != mPermissions) { + post.addParameter(PARAM_PERMISSIONS, Integer.toString(mPermissions)); + } post.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE); @@ -125,31 +135,21 @@ public class CreateRemoteShareOperation extends RemoteOperation { if(isSuccess(status)) { String response = post.getResponseBodyAsString(); - result = new RemoteOperationResult(ResultCode.OK); - - // Parse xml response --> obtain the response in ShareFiles ArrayList - // convert String into InputStream - InputStream is = new ByteArrayInputStream(response.getBytes()); - ShareXMLParser xmlParser = new ShareXMLParser(); - mShares = xmlParser.parseXMLResponse(is); - if (xmlParser.isSuccess()) { - if (mShares != null) { - Log_OC.d(TAG, "Created " + mShares.size() + " share(s)"); - result = new RemoteOperationResult(ResultCode.OK); - ArrayList sharesObjects = new ArrayList(); - for (OCShare share: mShares) { - sharesObjects.add(share); - } - result.setData(sharesObjects); - } - } else if (xmlParser.isFileNotFound()){ - result = new RemoteOperationResult(ResultCode.SHARE_NOT_FOUND); - - } else if (xmlParser.isFailure()) { - result = new RemoteOperationResult(ResultCode.SHARE_FORBIDDEN); + ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser( + new ShareXMLParser() + ); + parser.setOneOrMoreSharesRequired(true); + parser.setOwnCloudVersion(client.getOwnCloudVersion()); + parser.setServerBaseUri(client.getBaseUri()); + result = parser.parse(response); - } else { - result = new RemoteOperationResult(false, status, post.getResponseHeaders()); + if (result.isSuccess() && mGetShareDetails) { + // retrieve more info - POST only returns the index of the new share + OCShare emptyShare = (OCShare) result.getData().get(0); + GetRemoteShareOperation getInfo = new GetRemoteShareOperation( + emptyShare.getIdRemoteShared() + ); + result = getInfo.execute(client); } } else { diff --git a/src/com/owncloud/android/lib/resources/shares/GetRemoteShareOperation.java b/src/com/owncloud/android/lib/resources/shares/GetRemoteShareOperation.java new file mode 100644 index 00000000..9189b9f0 --- /dev/null +++ b/src/com/owncloud/android/lib/resources/shares/GetRemoteShareOperation.java @@ -0,0 +1,101 @@ +/* ownCloud Android Library is available under MIT license + * @author David A. Velasco + * Copyright (C) 2015 ownCloud Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.resources.shares; + +import 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.methods.GetMethod; +import org.apache.http.HttpStatus; + + +/** + * Get the data about a Share resource, known its remote ID. + */ + +public class GetRemoteShareOperation extends RemoteOperation { + + private static final String TAG = GetRemoteShareOperation.class.getSimpleName(); + + private long mRemoteId; + + + public GetRemoteShareOperation(long remoteId) { + mRemoteId = remoteId; + } + + + @Override + protected RemoteOperationResult run(OwnCloudClient client) { + RemoteOperationResult result = null; + int status = -1; + + // Get Method + GetMethod get = null; + + // Get the response + try{ + get = new GetMethod(client.getBaseUri() + ShareUtils.SHARING_API_PATH + "/" + Long.toString(mRemoteId)); + get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE); + + status = client.executeMethod(get); + + if(isSuccess(status)) { + String response = get.getResponseBodyAsString(); + + // Parse xml response and obtain the list of shares + ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser( + new ShareXMLParser() + ); + parser.setOneOrMoreSharesRequired(true); + parser.setOwnCloudVersion(client.getOwnCloudVersion()); + parser.setServerBaseUri(client.getBaseUri()); + result = parser.parse(response); + + } else { + result = new RemoteOperationResult(false, status, get.getResponseHeaders()); + } + + } catch (Exception e) { + result = new RemoteOperationResult(e); + Log_OC.e(TAG, "Exception while getting remote shares ", e); + + } finally { + if (get != null) { + get.releaseConnection(); + } + } + return result; + } + + private boolean isSuccess(int status) { + return (status == HttpStatus.SC_OK); + } + + +} diff --git a/src/com/owncloud/android/lib/resources/shares/GetRemoteShareesOperation.java b/src/com/owncloud/android/lib/resources/shares/GetRemoteShareesOperation.java new file mode 100644 index 00000000..132b017f --- /dev/null +++ b/src/com/owncloud/android/lib/resources/shares/GetRemoteShareesOperation.java @@ -0,0 +1,199 @@ +/* ownCloud Android Library is available under MIT license + * + * @author masensio + * @author David A. Velasco + * Copyright (C) 2015 ownCloud Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.resources.shares; + +import android.net.Uri; + +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.operations.RemoteOperation; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.utils.Log_OC; + +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.http.HttpStatus; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.ArrayList; + +/** + * Created by masensio on 08/10/2015. + * + * Retrieves a list of sharees (possible targets of a share) from the ownCloud server. + * + * Currently only handles users and groups. Users in other OC servers (federation) should be added later. + * + * Depends on SHAREE API. {@See https://github.com/owncloud/documentation/issues/1626} + * + * Syntax: + * Entry point: ocs/v2.php/apps/files_sharing/api/v1/sharees + * HTTP method: GET + * url argument: itemType - string, required + * url argument: format - string, optional + * url argument: search - string, optional + * url arguments: perPage - int, optional + * url arguments: page - int, optional + * + * Status codes: + * 100 - successful + */ +public class GetRemoteShareesOperation extends RemoteOperation{ + + private static final String TAG = GetRemoteShareesOperation.class.getSimpleName(); + + // OCS Routes + private static final String OCS_ROUTE = "ocs/v2.php/apps/files_sharing/api/v1/sharees"; // from OC 8.2 + + // Arguments - names + private static final String PARAM_FORMAT = "format"; + private static final String PARAM_ITEM_TYPE = "itemType"; + private static final String PARAM_SEARCH = "search"; + private static final String PARAM_PAGE = "page"; // default = 1 + private static final String PARAM_PER_PAGE = "perPage"; // default = 200 + + // Arguments - constant values + private static final String VALUE_FORMAT = "json"; + private static final String VALUE_ITEM_TYPE = "search"; // to get the server search for users / groups + + + // JSON Node names + private static final String NODE_OCS = "ocs"; + private static final String NODE_DATA = "data"; + private static final String NODE_EXACT = "exact"; + private static final String NODE_USERS = "users"; + private static final String NODE_GROUPS = "groups"; + public static final String NODE_VALUE = "value"; + public static final String PROPERTY_LABEL = "label"; + public static final String PROPERTY_SHARE_TYPE = "shareType"; + public static final String PROPERTY_SHARE_WITH = "shareWith"; + + // Result types + public static final Byte USER_TYPE = 0; + public static final Byte GROUP_TYPE = 1; + + private String mSearchString; + private int mPage; + private int mPerPage; + + /** + * Constructor + * + * @param searchString string for searching users, optional + * @param page page index in the list of results; beginning in 1 + * @param perPage maximum number of results in a single page + */ + public GetRemoteShareesOperation(String searchString, int page, int perPage) { + mSearchString = searchString; + mPage = page; + mPerPage = perPage; + } + + @Override + protected RemoteOperationResult run(OwnCloudClient client) { + RemoteOperationResult result = null; + int status; + GetMethod get = null; + + try{ + Uri requestUri = client.getBaseUri(); + Uri.Builder uriBuilder = requestUri.buildUpon(); + uriBuilder.appendEncodedPath(OCS_ROUTE); + uriBuilder.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT); + uriBuilder.appendQueryParameter(PARAM_ITEM_TYPE, VALUE_ITEM_TYPE); + uriBuilder.appendQueryParameter(PARAM_SEARCH, Uri.encode(mSearchString, "@")); + uriBuilder.appendQueryParameter(PARAM_PAGE, String.valueOf(mPage)); + uriBuilder.appendQueryParameter(PARAM_PER_PAGE, String.valueOf(mPerPage)); + + // Get Method + get = new GetMethod(uriBuilder.build().toString()); + get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE); + + status = client.executeMethod(get); + + if(isSuccess(status)) { + String response = get.getResponseBodyAsString(); + Log_OC.d(TAG, "Successful response: " + response); + + // Parse the response + JSONObject respJSON = new JSONObject(response); + JSONObject respOCS = respJSON.getJSONObject(NODE_OCS); + JSONObject respData = respOCS.getJSONObject(NODE_DATA); + JSONObject respExact = respData.getJSONObject(NODE_EXACT); + JSONArray respExactUsers = respExact.getJSONArray(NODE_USERS); + JSONArray respExactGroups = respExact.getJSONArray(NODE_GROUPS); + JSONArray respPartialUsers = respData.getJSONArray(NODE_USERS); + JSONArray respPartialGroups = respData.getJSONArray(NODE_GROUPS); + JSONArray[] jsonResults = { + respExactUsers, + respExactGroups, + respPartialUsers, + respPartialGroups + }; + + ArrayList data = new ArrayList(); // For result data + for (int i=0; i<4; i++) { + for(int j=0; j< jsonResults[i].length(); j++){ + JSONObject jsonResult = jsonResults[i].getJSONObject(j); + data.add(jsonResult); + Log_OC.d(TAG, "*** Added item: " + jsonResult.getString(PROPERTY_LABEL)); + } + } + + // Result + result = new RemoteOperationResult(true, status, get.getResponseHeaders()); + result.setData(data); + + Log_OC.d(TAG, "*** Get Users or groups completed " ); + + } else { + result = new RemoteOperationResult(false, status, get.getResponseHeaders()); + String response = get.getResponseBodyAsString(); + Log_OC.e(TAG, "Failed response while getting users/groups from the server "); + if (response != null) { + Log_OC.e(TAG, "*** status code: " + status + "; response message: " + response); + } else { + Log_OC.e(TAG, "*** status code: " + status); + } + } + + } catch (Exception e) { + result = new RemoteOperationResult(e); + Log_OC.e(TAG, "Exception while getting users/groups", e); + + } finally { + if (get != null) { + get.releaseConnection(); + } + } + return result; + } + + private boolean isSuccess(int status) { + return (status == HttpStatus.SC_OK); + } +} diff --git a/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesForFileOperation.java b/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesForFileOperation.java index 37241844..1381d272 100644 --- a/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesForFileOperation.java +++ b/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesForFileOperation.java @@ -1,4 +1,6 @@ /* ownCloud Android Library is available under MIT license + * @author masensio + * @author David A. Velasco * Copyright (C) 2015 ownCloud Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -24,10 +26,6 @@ package com.owncloud.android.lib.resources.shares; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.ArrayList; - import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.http.HttpStatus; @@ -35,19 +33,14 @@ import org.apache.http.HttpStatus; 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.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.lib.resources.status.OwnCloudVersion; + /** * Provide a list shares for a specific file. * The input is the full path of the desired file. * The output is a list of everyone who has the file shared with them. - * - * @author masensio - * */ - public class GetRemoteSharesForFileOperation extends RemoteOperation { private static final String TAG = GetRemoteSharesForFileOperation.class.getSimpleName(); @@ -56,8 +49,6 @@ public class GetRemoteSharesForFileOperation extends RemoteOperation { private static final String PARAM_RESHARES = "reshares"; private static final String PARAM_SUBFILES = "subfiles"; - private ArrayList mShares; // List of shares for result, one share in this case - private String mRemoteFilePath; private boolean mReshares; private boolean mSubfiles; @@ -104,29 +95,16 @@ public class GetRemoteSharesForFileOperation extends RemoteOperation { if(isSuccess(status)) { String response = get.getResponseBodyAsString(); - result = new RemoteOperationResult(ResultCode.OK); - - // Parse xml response --> obtain the response in ShareFiles ArrayList - // convert String into InputStream - InputStream is = new ByteArrayInputStream(response.getBytes()); - ShareXMLParser xmlParser = new ShareXMLParser(); - mShares = xmlParser.parseXMLResponse(is); - if (mShares != null) { - Log_OC.d(TAG, "Got " + mShares.size() + " shares"); - result = new RemoteOperationResult(ResultCode.OK); - ArrayList sharesObjects = new ArrayList(); - for (OCShare share: mShares) { - // Build the link - if (( share.getShareLink() == null) && - (share.getToken().length() > 0)) { - String linkToken = ShareUtils.getSharingToken( - client.getOwnCloudVersion()); - share.setShareLink(client.getBaseUri() + linkToken + - share.getToken()); - } - sharesObjects.add(share); - } - result.setData(sharesObjects); + // Parse xml response and obtain the list of shares + ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser( + new ShareXMLParser() + ); + parser.setOwnCloudVersion(client.getOwnCloudVersion()); + parser.setServerBaseUri(client.getBaseUri()); + result = parser.parse(response); + + if (result.isSuccess()) { + Log_OC.d(TAG, "Got " + result.getData().size() + " shares"); } } else { diff --git a/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesOperation.java b/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesOperation.java index 38b75194..acd8ca23 100644 --- a/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesOperation.java +++ b/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesOperation.java @@ -1,4 +1,6 @@ /* ownCloud Android Library is available under MIT license + * @author masensio + * @author David A. Velasco * Copyright (C) 2015 ownCloud Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -24,34 +26,25 @@ package com.owncloud.android.lib.resources.shares; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.ArrayList; - import org.apache.commons.httpclient.methods.GetMethod; import org.apache.http.HttpStatus; 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.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.lib.common.utils.Log_OC; /** - * Get the data from the server to know shares + * Get the data from the server about ALL the known shares owned by the requester. * - * @author masensio - * */ public class GetRemoteSharesOperation extends RemoteOperation { private static final String TAG = GetRemoteSharesOperation.class.getSimpleName(); - private ArrayList mShares; // List of shares for result - public GetRemoteSharesOperation() { } @@ -68,23 +61,18 @@ public class GetRemoteSharesOperation extends RemoteOperation { get = new GetMethod(client.getBaseUri() + ShareUtils.SHARING_API_PATH); get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE); status = client.executeMethod(get); + if(isSuccess(status)) { String response = get.getResponseBodyAsString(); - // Parse xml response --> obtain the response in ShareFiles ArrayList - // convert String into InputStream - InputStream is = new ByteArrayInputStream(response.getBytes()); - ShareXMLParser xmlParser = new ShareXMLParser(); - mShares = xmlParser.parseXMLResponse(is); - if (mShares != null) { - Log_OC.d(TAG, "Got " + mShares.size() + " shares"); - result = new RemoteOperationResult(ResultCode.OK); - ArrayList sharesObjects = new ArrayList(); - for (OCShare share: mShares) { - sharesObjects.add(share); - } - result.setData(sharesObjects); - } + // Parse xml response and obtain the list of shares + ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser( + new ShareXMLParser() + ); + parser.setOwnCloudVersion(client.getOwnCloudVersion()); + parser.setServerBaseUri(client.getBaseUri()); + result = parser.parse(response); + } else { result = new RemoteOperationResult(false, status, get.getResponseHeaders()); } diff --git a/src/com/owncloud/android/lib/resources/shares/OCShare.java b/src/com/owncloud/android/lib/resources/shares/OCShare.java index 16f0c394..644955cc 100644 --- a/src/com/owncloud/android/lib/resources/shares/OCShare.java +++ b/src/com/owncloud/android/lib/resources/shares/OCShare.java @@ -45,7 +45,9 @@ public class OCShare implements Parcelable, Serializable { private static final long serialVersionUID = 4124975224281327921L; private static final String TAG = OCShare.class.getSimpleName(); - + + public static final int DEFAULT_PERMISSION = -1; + private long mId; private long mFileSource; private long mItemSource; diff --git a/src/com/owncloud/android/lib/resources/shares/RemoveRemoteShareOperation.java b/src/com/owncloud/android/lib/resources/shares/RemoveRemoteShareOperation.java index 4db29051..68a94db4 100644 --- a/src/com/owncloud/android/lib/resources/shares/RemoveRemoteShareOperation.java +++ b/src/com/owncloud/android/lib/resources/shares/RemoveRemoteShareOperation.java @@ -1,4 +1,6 @@ /* ownCloud Android Library is available under MIT license + * @author masensio + * @author David A. Velasco * Copyright (C) 2015 ownCloud Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -24,23 +26,16 @@ package com.owncloud.android.lib.resources.shares; -import java.io.ByteArrayInputStream; -import java.io.InputStream; - import org.apache.commons.httpclient.HttpStatus; import org.apache.jackrabbit.webdav.client.methods.DeleteMethod; 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.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.lib.common.utils.Log_OC; /** * Remove a share - * - * @author masensio - * */ public class RemoveRemoteShareOperation extends RemoteOperation { @@ -78,22 +73,14 @@ public class RemoveRemoteShareOperation extends RemoteOperation { if(isSuccess(status)) { String response = delete.getResponseBodyAsString(); - result = new RemoteOperationResult(ResultCode.OK); - - // Parse xml response - // convert String into InputStream - InputStream is = new ByteArrayInputStream(response.getBytes()); - ShareXMLParser xmlParser = new ShareXMLParser(); - xmlParser.parseXMLResponse(is); - if (xmlParser.isSuccess()) { - result = new RemoteOperationResult(ResultCode.OK); - } else if (xmlParser.isFileNotFound()){ - result = new RemoteOperationResult(ResultCode.SHARE_NOT_FOUND); - } else { - result = new RemoteOperationResult(false, status, delete.getResponseHeaders()); - } - + // Parse xml response and obtain the list of shares + ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser( + new ShareXMLParser() + ); + result = parser.parse(response); + Log_OC.d(TAG, "Unshare " + id + ": " + result.getLogMessage()); + } else { result = new RemoteOperationResult(false, status, delete.getResponseHeaders()); } diff --git a/src/com/owncloud/android/lib/resources/shares/ShareToRemoteOperationResultParser.java b/src/com/owncloud/android/lib/resources/shares/ShareToRemoteOperationResultParser.java new file mode 100644 index 00000000..c59ba8ed --- /dev/null +++ b/src/com/owncloud/android/lib/resources/shares/ShareToRemoteOperationResultParser.java @@ -0,0 +1,144 @@ +/* ownCloud Android Library is available under MIT license + * @author David A. Velasco + * Copyright (C) 2015 ownCloud Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.resources.shares; + +import android.net.Uri; + +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.lib.resources.status.OwnCloudVersion; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +public class ShareToRemoteOperationResultParser { + + private static final String TAG = ShareToRemoteOperationResultParser.class.getSimpleName(); + + private ShareXMLParser mShareXmlParser = null; + private boolean mOneOrMoreSharesRequired = false; + private OwnCloudVersion mOwnCloudVersion = null; + private Uri mServerBaseUri = null; + + + public ShareToRemoteOperationResultParser(ShareXMLParser shareXmlParser) { + mShareXmlParser = shareXmlParser; + } + + public void setOneOrMoreSharesRequired(boolean oneOrMoreSharesRequired) { + mOneOrMoreSharesRequired = oneOrMoreSharesRequired; + } + + public void setOwnCloudVersion(OwnCloudVersion ownCloudVersion) { + mOwnCloudVersion = ownCloudVersion; + } + + public void setServerBaseUri(Uri serverBaseURi) { + mServerBaseUri = serverBaseURi; + } + + public RemoteOperationResult parse(String serverResponse) { + if (serverResponse == null || serverResponse.length() == 0) { + return new RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE); + } + + RemoteOperationResult result = null; + ArrayList resultData = new ArrayList(); + + try { + // Parse xml response and obtain the list of shares + InputStream is = new ByteArrayInputStream(serverResponse.getBytes()); + if (mShareXmlParser == null) { + Log_OC.w(TAG, "No ShareXmlParser provided, creating new instance "); + mShareXmlParser = new ShareXMLParser(); + } + List shares = mShareXmlParser.parseXMLResponse(is); + + if (mShareXmlParser.isSuccess()) { + if ((shares != null && shares.size() > 0) || !mOneOrMoreSharesRequired) { + result = new RemoteOperationResult(RemoteOperationResult.ResultCode.OK); + if (shares != null) { + for (OCShare share : shares) { + resultData.add(share); + // build the share link if not in the response (only received when the share is created) + if (share.getShareType() == ShareType.PUBLIC_LINK && + share.getShareLink() == null && + share.getToken().length() > 0 + ) { + if (mServerBaseUri != null) { + String sharingLinkPath = ShareUtils.getSharingLinkPath(mOwnCloudVersion); + share.setShareLink(mServerBaseUri + sharingLinkPath + share.getToken()); + } else { + Log_OC.e(TAG, "Couldn't build link for public share"); + } + } + } + } + result.setData(resultData); + + } else { + result = new RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE); + Log_OC.e(TAG, "Successful status with no share in the response"); + } + + } else if (mShareXmlParser.isWrongParameter()){ + result = new RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_WRONG_PARAMETER); + resultData.add(mShareXmlParser.getMessage()); + result.setData(resultData); + + } else if (mShareXmlParser.isNotFound()){ + result = new RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND); + resultData.add(mShareXmlParser.getMessage()); + result.setData(resultData); + + } else if (mShareXmlParser.isForbidden()) { + result = new RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_FORBIDDEN); + resultData.add(mShareXmlParser.getMessage()); + result.setData(resultData); + + } else { + result = new RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE); + + } + + } catch (XmlPullParserException e) { + Log_OC.e(TAG, "Error parsing response from server ", e); + result = new RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE); + + } catch (IOException e) { + Log_OC.e(TAG, "Error reading response from server ", e); + result = new RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE); + } + + return result; + } + +} diff --git a/src/com/owncloud/android/lib/resources/shares/ShareUtils.java b/src/com/owncloud/android/lib/resources/shares/ShareUtils.java index 8ab9b118..ae4bc8b8 100644 --- a/src/com/owncloud/android/lib/resources/shares/ShareUtils.java +++ b/src/com/owncloud/android/lib/resources/shares/ShareUtils.java @@ -39,17 +39,15 @@ public class ShareUtils { public static final String SHARING_API_PATH ="/ocs/v1.php/apps/files_sharing/api/v1/shares"; // String to build the link with the token of a share: - // server address + "/public.php?service=files&t=" + token - public static final String SHARING_LINK_TOKEN_BEFORE_VERSION_8 = "/public.php?service=files&t="; - public static final String SHARING_LINK_TOKEN_AFTER_VERSION_8= "/index.php/s/"; + public static final String SHARING_LINK_PATH_BEFORE_VERSION_8 = "/public.php?service=files&t="; + public static final String SHARING_LINK_PATH_AFTER_VERSION_8 = "/index.php/s/"; - public static String getSharingToken(OwnCloudVersion version){ + public static String getSharingLinkPath(OwnCloudVersion version){ if (version!= null && version.isAfter8Version()){ - return SHARING_LINK_TOKEN_AFTER_VERSION_8; + return SHARING_LINK_PATH_AFTER_VERSION_8; } else { - return SHARING_LINK_TOKEN_BEFORE_VERSION_8; + return SHARING_LINK_PATH_BEFORE_VERSION_8; } - } - + } diff --git a/src/com/owncloud/android/lib/resources/shares/ShareXMLParser.java b/src/com/owncloud/android/lib/resources/shares/ShareXMLParser.java index b19d5772..e672deeb 100644 --- a/src/com/owncloud/android/lib/resources/shares/ShareXMLParser.java +++ b/src/com/owncloud/android/lib/resources/shares/ShareXMLParser.java @@ -57,7 +57,7 @@ public class ShareXMLParser { private static final String NODE_META = "meta"; private static final String NODE_STATUS = "status"; private static final String NODE_STATUS_CODE = "statuscode"; - //private static final String NODE_MESSAGE = "message"; + private static final String NODE_MESSAGE = "message"; private static final String NODE_DATA = "data"; private static final String NODE_ELEMENT = "element"; @@ -75,18 +75,20 @@ public class ShareXMLParser { private static final String NODE_TOKEN = "token"; private static final String NODE_STORAGE = "storage"; private static final String NODE_MAIL_SEND = "mail_send"; - private static final String NODE_SHARE_WITH_DISPLAY_NAME = "share_with_display_name"; + private static final String NODE_SHARE_WITH_DISPLAY_NAME = "share_with_displayname"; private static final String NODE_URL = "url"; private static final String TYPE_FOLDER = "folder"; private static final int SUCCESS = 100; - private static final int FAILURE = 403; - private static final int FILE_NOT_FOUND = 404; + private static final int ERROR_WRONG_PARAMETER = 403; + private static final int ERROR_FORBIDDEN = 403; + private static final int ERROR_NOT_FOUND = 404; private String mStatus; private int mStatusCode; + private String mMessage; // Getters and Setters public String getStatus() { @@ -104,21 +106,36 @@ public class ShareXMLParser { public void setStatusCode(int statusCode) { this.mStatusCode = statusCode; } + + public String getMessage() { + return mMessage; + } + + public void setMessage(String message) { + this.mMessage = message; + } + // Constructor public ShareXMLParser() { - mStatusCode = 100; + mStatusCode = -1; } public boolean isSuccess() { return mStatusCode == SUCCESS; } - public boolean isFailure() { - return mStatusCode == FAILURE; + + public boolean isForbidden() { + return mStatusCode == ERROR_FORBIDDEN; } - public boolean isFileNotFound() { - return mStatusCode == FILE_NOT_FOUND; + + public boolean isNotFound() { + return mStatusCode == ERROR_NOT_FOUND; } - + + public boolean isWrongParameter() { + return mStatusCode == ERROR_WRONG_PARAMETER; + } + /** * Parse is as response of Share API * @param is @@ -197,6 +214,9 @@ public class ShareXMLParser { } else if (name.equalsIgnoreCase(NODE_STATUS_CODE)) { setStatusCode(Integer.parseInt(readNode(parser, NODE_STATUS_CODE))); + } else if (name.equalsIgnoreCase(NODE_MESSAGE)) { + setMessage(readNode(parser, NODE_MESSAGE)); + } else { skip(parser); } @@ -348,9 +368,7 @@ public class ShareXMLParser { } private boolean isValidShare(OCShare share) { - return ((share.getIdRemoteShared() > -1) && - (share.getShareType() == ShareType.PUBLIC_LINK) // at this moment we only care about public shares - ); + return (share.getIdRemoteShared() > -1); } private void fixPathForFolder(OCShare share) { diff --git a/src/com/owncloud/android/lib/resources/status/OwnCloudVersion.java b/src/com/owncloud/android/lib/resources/status/OwnCloudVersion.java index f3da9f47..8c30c7ab 100644 --- a/src/com/owncloud/android/lib/resources/status/OwnCloudVersion.java +++ b/src/com/owncloud/android/lib/resources/status/OwnCloudVersion.java @@ -43,6 +43,8 @@ public class OwnCloudVersion implements Comparable { public static final int MINIMUM_SERVER_VERSION_FOR_REMOTE_THUMBNAILS = 0x07080000; // 7.8.0 + public static final int MINIMUM_VERSION_FOR_SEARCHING_USERS = 0x08020000; //8.2 + public static final int VERSION_8 = 0x08000000; // 8.0 private static final int MAX_DOTS = 3; @@ -138,6 +140,10 @@ public class OwnCloudVersion implements Comparable { public boolean isAfter8Version(){ return (mVersion >= VERSION_8); } + + public boolean isSearchUsersSupported() { + return (mVersion >= MINIMUM_VERSION_FOR_SEARCHING_USERS); + } } diff --git a/src/com/owncloud/android/lib/resources/users/GetRemoteUserNameOperation.java b/src/com/owncloud/android/lib/resources/users/GetRemoteUserNameOperation.java index cecd639f..d6b85a7a 100644 --- a/src/com/owncloud/android/lib/resources/users/GetRemoteUserNameOperation.java +++ b/src/com/owncloud/android/lib/resources/users/GetRemoteUserNameOperation.java @@ -50,7 +50,7 @@ public class GetRemoteUserNameOperation extends RemoteOperation { private static final String TAG = GetRemoteUserNameOperation.class.getSimpleName(); // OCS Route - private static final String OCS_ROUTE ="/index.php/ocs/cloud/user?format=json"; + private static final String OCS_ROUTE ="/index.php/ocs/cloud/user?format=json"; // JSON Node names private static final String NODE_OCS = "ocs"; diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/CreateShareTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/CreateShareTest.java index 782c06d8..8d08dd81 100644 --- a/test_client/tests/src/com/owncloud/android/lib/test_project/test/CreateShareTest.java +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/CreateShareTest.java @@ -31,6 +31,9 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCo import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.lib.test_project.TestActivity; +/** + * Test Create Share: the server must support SHARE API + */ public class CreateShareTest extends RemoteTest { private static final String LOG_TAG = CreateShareTest.class.getCanonicalName(); @@ -38,15 +41,20 @@ public class CreateShareTest extends RemoteTest { /* File to share.*/ private static final String FILE_TO_SHARE = "/fileToShare.txt"; + /* Non-existent file*/ + private static final String NON_EXISTENT_FILE = "/nonExistentFile.txt"; + private TestActivity mActivity; private String mFullPath2FileToShare; + private String mFullPath2NonExistentFile; @Override protected void setUp() throws Exception { super.setUp(); setActivityInitialTouchMode(false); mActivity = getActivity(); - mFullPath2FileToShare = mBaseFolderPath + FILE_TO_SHARE; + mFullPath2FileToShare = mBaseFolderPath + FILE_TO_SHARE; + mFullPath2NonExistentFile = mBaseFolderPath + NON_EXISTENT_FILE; File textFile = mActivity.extractAsset(TestActivity.ASSETS__TEXT_FILE_NAME); RemoteOperationResult result = mActivity.uploadFile( @@ -57,11 +65,13 @@ public class CreateShareTest extends RemoteTest { Utils.logAndThrow(LOG_TAG, result); } } - + /** - * Test Create Share: the server must support SHARE API + * Test creation of public shares */ public void testCreatePublicShare() { + + /// Successful cases RemoteOperationResult result = mActivity.createShare( mFullPath2FileToShare, ShareType.PUBLIC_LINK, @@ -70,6 +80,141 @@ public class CreateShareTest extends RemoteTest { "", 1); assertTrue(result.isSuccess()); + + /// Failed cases + + // file doesn't exist + result = mActivity.createShare( + mFullPath2NonExistentFile, + ShareType.PUBLIC_LINK, + "", + false, + "", + 1); + assertFalse(result.isSuccess()); + assertEquals( + RemoteOperationResult.ResultCode.SHARE_NOT_FOUND, + result.getCode() + ); + assertTrue( // error message from server as part of the result + result.getData().size() == 1 && + result.getData().get(0) instanceof String + ); + + } + + + /** + * Test creation of private shares with groups + */ + public void testCreatePrivateShareWithUser() { + + /// Successful cases + RemoteOperationResult result = mActivity.createShare( + mFullPath2FileToShare, + ShareType.USER, + "admin", + false, + "", + 31); + assertTrue(result.isSuccess()); + + + /// Failed cases + + // sharee doesn't exist + result = mActivity.createShare( + mFullPath2FileToShare, + ShareType.USER, + "no_exist", + false, + "", + 31); + assertFalse(result.isSuccess()); + assertEquals( + RemoteOperationResult.ResultCode.SHARE_WRONG_PARAMETER, + result.getCode() + ); + assertTrue( // error message from server as part of the result + result.getData().size() == 1 && + result.getData().get(0) instanceof String + ); + + // file doesn't exist + result = mActivity.createShare( + mFullPath2NonExistentFile, + ShareType.USER, + "admin", + false, + "", + 31); + assertFalse(result.isSuccess()); + assertEquals( + RemoteOperationResult.ResultCode.SHARE_NOT_FOUND, + result.getCode() + ); + assertTrue( // error message from server as part of the result + result.getData().size() == 1 && + result.getData().get(0) instanceof String + ); + + } + + + /** + * Test creation of private shares with groups + */ + public void testCreatePrivateShareWithGroup() { + + /// Successful cases + RemoteOperationResult result = mActivity.createShare( + mFullPath2FileToShare, + ShareType.GROUP, + "admin", + false, + "", + 1); + assertTrue(result.isSuccess()); + + + /// Failed cases + + // sharee doesn't exist + result = mActivity.createShare( + mFullPath2FileToShare, + ShareType.GROUP, + "no_exist", + false, + "", + 31); + assertFalse(result.isSuccess()); + assertEquals( + RemoteOperationResult.ResultCode.SHARE_WRONG_PARAMETER, + result.getCode() + ); + assertTrue( // error message from server as part of the result + result.getData().size() == 1 && + result.getData().get(0) instanceof String + ); + + // file doesn't exist + result = mActivity.createShare( + mFullPath2NonExistentFile, + ShareType.GROUP, + "admin", + false, + "", + 31); + assertFalse(result.isSuccess()); + assertEquals( + RemoteOperationResult.ResultCode.SHARE_NOT_FOUND, + result.getCode() + ); + assertTrue( // error message from server as part of the result + result.getData().size() == 1 && + result.getData().get(0) instanceof String + ); + } diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/GetShareesTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/GetShareesTest.java new file mode 100644 index 00000000..80bcd107 --- /dev/null +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/GetShareesTest.java @@ -0,0 +1,228 @@ +/* ownCloud Android Library is available under MIT license + * @author David A. Velasco + * Copyright (C) 2015 ownCloud Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.test_project.test; + +import java.security.GeneralSecurityException; + +import junit.framework.AssertionFailedError; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.protocol.Protocol; +import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; +import org.json.JSONException; +import org.json.JSONObject; + +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudClientFactory; +import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; +import com.owncloud.android.lib.common.network.NetworkUtils; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.resources.shares.GetRemoteShareesOperation; +import com.owncloud.android.lib.test_project.R; +import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory; + +import android.content.Context; +import android.net.Uri; +import android.util.Log; + +/** + * Class to test GetRemoteShareesOperation + * + * With this TestCase we are experimenting a bit to improve the test suite design, in two aspects: + * + * - Reduce the dependency from the set of test cases on the "test project" needed to + * have an instrumented APK to install in the device, as required by the testing framework + * provided by Android. To get there, this class avoids calling TestActivity methods in the test + * method. + * + * - Reduce the impact of creating a remote fixture over the Internet, while the structure of the + * TestCase is kept easy to maintain. To get this, all the tests are done in a single test method, + * granting this way that setUp and tearDown are run only once. + * + */ + +public class GetShareesTest extends RemoteTest { + + private static final String LOG_TAG = GetShareesTest.class.getCanonicalName(); + + String mServerUri, mUser, mPass; + OwnCloudClient mClient = null; + + public GetShareesTest() { + super(); + + Protocol pr = Protocol.getProtocol("https"); + if (pr == null || !(pr.getSocketFactory() instanceof SelfSignedConfidentSslSocketFactory)) { + try { + ProtocolSocketFactory psf = new SelfSignedConfidentSslSocketFactory(); + Protocol.registerProtocol( + "https", + new Protocol("https", psf, 443)); + + } catch (GeneralSecurityException e) { + throw new AssertionFailedError( + "Self-signed confident SSL context could not be loaded"); + } + } + + } + + + protected Context getContext() { + return getActivity(); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + // Next initialization cannot be done in the constructor because getContext() is not + // ready yet, returns NULL. + initAccessToServer(getContext()); + + Log.v(LOG_TAG, "Setting up the remote fixture..."); + + Log.v(LOG_TAG, "Remote fixture created."); + + } + + + /** + * Test get sharees + * + * Requires OC server 8.2 or later + */ + public void testGetRemoteShareesOperation() { + Log.v(LOG_TAG, "testGetRemoteSharees in"); + + /// successful cases + + // search for sharees including "a" + GetRemoteShareesOperation getShareesOperation = new GetRemoteShareesOperation("a", 1, 50); + RemoteOperationResult result = getShareesOperation.execute(mClient); + JSONObject resultItem; + JSONObject value; + byte type; + int userCount = 0, groupCount = 0; + assertTrue(result.isSuccess() && result.getData().size() == 3); + try { + for (int i=0; i<3; i++) { + resultItem = (JSONObject) result.getData().get(i); + value = resultItem.getJSONObject(GetRemoteShareesOperation.NODE_VALUE); + type = (byte) value.getInt(GetRemoteShareesOperation.PROPERTY_SHARE_TYPE); + if (GetRemoteShareesOperation.GROUP_TYPE.equals(type)) { + groupCount++; + } else { + userCount++; + } + } + assertEquals(userCount, 2); + assertEquals(groupCount, 1); + } catch (JSONException e) { + AssertionFailedError afe = new AssertionFailedError(e.getLocalizedMessage()); + afe.setStackTrace(e.getStackTrace()); + throw afe; + } + + // search for sharees including "ad" + getShareesOperation = new GetRemoteShareesOperation("ad", 1, 50); + result = getShareesOperation.execute(mClient); + assertTrue(result.isSuccess() && result.getData().size() == 2); + userCount = 0; groupCount = 0; + try { + for (int i=0; i<2; i++) { + resultItem = (JSONObject) result.getData().get(i); + value = resultItem.getJSONObject(GetRemoteShareesOperation.NODE_VALUE); + type = (byte) value.getInt(GetRemoteShareesOperation.PROPERTY_SHARE_TYPE); + if (GetRemoteShareesOperation.GROUP_TYPE.equals(type)) { + groupCount++; + } else { + userCount++; + } + } + assertEquals(userCount, 1); + assertEquals(groupCount, 1); + } catch (JSONException e) { + AssertionFailedError afe = new AssertionFailedError(e.getLocalizedMessage()); + afe.setStackTrace(e.getStackTrace()); + throw afe; + } + + + // search for sharees including "b" + getShareesOperation = new GetRemoteShareesOperation("b", 1, 50); + result = getShareesOperation.execute(mClient); + assertTrue(result.isSuccess() && result.getData().size() == 0); + + + /// failed cases + + // search for sharees including wrong page values + getShareesOperation = new GetRemoteShareesOperation("a", 0, 50); + result = getShareesOperation.execute(mClient); + assertTrue(!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_BAD_REQUEST); + + getShareesOperation = new GetRemoteShareesOperation("a", 1, 0); + result = getShareesOperation.execute(mClient); + assertTrue(!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_BAD_REQUEST); + } + + @Override + protected void tearDown() throws Exception { + Log.v(LOG_TAG, "Deleting remote fixture..."); + super.tearDown(); + Log.v(LOG_TAG, "Remote fixture delete."); + } + + + private void initAccessToServer(Context context) { + Log.v(LOG_TAG, "Setting up client instance to access OC server..."); + + mServerUri = context.getString(R.string.server_base_url); + mUser = context.getString(R.string.username); + mPass = context.getString(R.string.password); + + mClient = new OwnCloudClient( + Uri.parse(mServerUri), + NetworkUtils.getMultiThreadedConnManager() + ); + mClient.setDefaultTimeouts( + OwnCloudClientFactory.DEFAULT_DATA_TIMEOUT, + OwnCloudClientFactory.DEFAULT_CONNECTION_TIMEOUT); + mClient.setFollowRedirects(true); + mClient.setCredentials( + OwnCloudCredentialsFactory.newBasicCredentials( + mUser, + mPass + ) + ); + + Log.v(LOG_TAG, "Client instance set up."); + + } + + +}