1
0
mirror of https://github.com/owncloud/android-library.git synced 2025-06-08 00:16:09 +00:00

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
mendhak 2016-01-30 08:34:24 +00:00
commit 31836d3f4a
54 changed files with 4276 additions and 493 deletions

View File

@ -1,34 +1,45 @@
sudo: false
language: android
android:
components:
- build-tools-20.0.0
- build-tools-22.0.1
- android-19
- android-17
- android-14
- extra-android-support
licenses:
- 'android-sdk-license-5be876d5'
- 'android-sdk-license-598b93a6'
jdk: oraclejdk7
branches:
only:
- master
before_install:
- echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI -c 20M
- echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI
-c 20M
- emulator -avd test -no-skin -no-audio -no-window &
- rm pom.xml
- android update project -p .
before_script:
- chmod +x ./wait_for_emulator.sh
- ./wait_for_emulator.sh
script:
- ant clean
- ant debug
- cd test_client/tests
- ant acceptance-test
- cd ../..
- ./gradlew clean build
- ant clean
- ant debug
- cd test_client/tests
- ant acceptance-test
- cd ../..
- ./gradlew clean build
env:
global:
- secure: f4Kms/mzkYRG4Kp8k6hsvG3Y0ztbJnA2J79OBw3VdqJOKVTzwsxMd1Yh325YDYO7I4HeHxGXy0H4p3rAPzIWr/nrOJ4wmcDwQYDQtVjF7S1ARWsX51FrCEV6A9ec2LAqNCQ8ZC0SoGb+HsmpFCE3uKAxRQt+B5MzOZvKNcvYpMA=
- secure: aF4U20Xlu/rfrbxCmoJAiGh1doYTAZ10UEDmajuinT+ZGSJLivuqD7DDY/00sI6IXWg+J1vL+7jJm4JSYusHPg38UHZ4q92k6RmZycW2ATUzZnGT54O5FRnY67MfVwgVpIMK9UOL/6NEciBHEjlIOL0wbKQiJB++1YtBZOQLGL4=
- secure: N+ECSwNg8v2GsAFJ2y/tCiffauHDpN76zuFI2pDqf0fjmCtJZHu4BH5ArXBHjyHKmgn20a/8eZXcwJaH1HsJ80bo7vDJ2miShjGIQ90hPcdmUiB2XVJcew4f04CtvMDH5o7DRt4ykWArlbPL2rhVag0jotlSidolHBwRFnbDhDY=
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
- secure: epTZ0zZGDbHL3o6vSC9uNkZsi5j5SA6O/tvQBH7QW/dluuzIJxIjfhNbZHDyBReYDleirLzUFQpdWAUdvulCMLs/qZdIzFGlYXZSpxEnvPYMGQcilwADdJcxLw8L+3+ET5hSexxhjrTGw427IljkqGUpqQTxaLwFdFu98lDWSbc=
# The next 3 declarations are the variables needed to access the test server,
# added via "travis encrypt", using the repo public key
- secure: gPCBnpGLA2sdSMtfhT+/InThmXNEU8XrrS54uuIP8iXBLvVe0yZrNl76GbMosV0ry3YtDngsmsbHwRjPPb0+3mTTdAqZ60HHzGaNPgEm6b5t0t4bpJ3LW9osLZsuf9jRsI2LD66zxblaMrK2+8hN/dUrj707ijsZHp3SPSQJ6g8=
- secure: AnxLVarfwM7IhJ7Sca35USyRlFHFvlcBhWTt2TVDcyQ+ldDyb+U6IWXFK0Yy82QP0ZH/RCLu7FnmHK/rKG0BHNRt1Ymco1VkTQql0MZcHXP+4IKgEvgJyUn1TqYj+hSVmM6lgTA+QUjZYGSfwU8mhUFiU7644ZTdTe6ALdqa+v8=
- secure: ezKyZbb3q1Phcv/vJntuJe0C2req+Hp4/C+tFZIWZ3o8wRO9jVI3bnED9TWQyQOOT0SoRYjJ5zqp0UcEOGCzPeWFO6bA7RWp+zA/R9sziLNcVWMVv3WXnuClQjPBHJeXRnP7YmNjxDmSfV97a14dk5d9LgJZYliTDepH4dLsxro=
matrix:
- ANDROID_TARGET=android-19 ANDROID_ABI=armeabi-v7a
addons:
coverity_scan:
project:
name: owncloud/android-library
description: Build submitted via Travis CI
notification_email: lukas@owncloud.com
build_command_prepend: gradle clean
build_command: gradle build
branch_pattern: coverity_scan

View File

@ -19,14 +19,14 @@ __Step 2.__ Define a dependency within your project. For that, access to Propert
The repository holds two main branches with an infinite lifetime:
- stable
- master
- develop
Branch __origin/master__ is considered the main branch where the source code of HEAD always reflects a production-ready state.
Branch __origin/stable__ is considered the main branch where the source code of HEAD always reflects a production-ready state.
Branch __origin/develop__ is considered the main branch where the source code of HEAD always reflects a state with the latest delivered development changes for the next release.
Branch __origin/master__ is considered the main branch where the source code of HEAD always reflects a state with the latest delivered development changes for the next release.
When the source code in the develop branch reaches a stable point and is ready to be released, all of the changes should be merged back into master somehow and then tagged with a release number.
When the source code in the master branch reaches a stable point and is ready to be released, all of the changes should be merged back into stable somehow and then tagged with a release number.
Other branches, some supporting branches are used to aid parallel development between team members, ease tracking of features, prepare for production releases and to assist in quickly fixing live production problems. Unlike the main branches, these branches always have a limited life time, since they will be removed eventually.
@ -35,9 +35,8 @@ The different types of branches we may use are:
- Branch __perNewFeature__
- Branch __releaseBranches__
Both of them branch off from develop and must merge back into develop branch through a Pull Request in Github. Once the PR is approved and merged, the US branch may be deleted.
Both of them branch off from master and must merge back into master branch through a Pull Request in Github. Once the PR is approved and merged, the US branch may be deleted.
Source: http://nvie.com/posts/a-successful-git-branching-model
### License

View File

@ -3,9 +3,10 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0'
classpath 'com.android.tools.build:gradle:1.2.3'
}
}
apply plugin: 'com.android.library'
repositories {
@ -13,14 +14,12 @@ repositories {
}
dependencies {
compile 'commons-httpclient:commons-httpclient:3.1'
compile 'org.apache.jackrabbit:jackrabbit-webdav:2.7.2'
compile 'org.slf4j:slf4j-api:1.7.5'
compile 'org.apache.jackrabbit:jackrabbit-webdav:2.10.1'
}
android {
compileSdkVersion 19
buildToolsVersion "20.0.0"
buildToolsVersion "22.0.1"
sourceSets {
main {

View File

@ -10,7 +10,7 @@ dependencies {
android {
compileSdkVersion 19
buildToolsVersion "20.0.0"
buildToolsVersion "22.0.1"
sourceSets {
main {
@ -43,4 +43,9 @@ android {
packagingOptions {
exclude 'META-INF/LICENSE.txt'
}
android {
lintOptions {
abortOnError false
}
}
}

View File

@ -49,13 +49,15 @@ import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.network.RedirectionPath;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
public class OwnCloudClient extends HttpClient {
private static final String TAG = OwnCloudClient.class.getSimpleName();
private static final int MAX_REDIRECTIONS_COUNT = 3;
public static final int MAX_REDIRECTIONS_COUNT = 3;
private static final String PARAM_SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header";
private static final boolean PARAM_SINGLE_COOKIE_HEADER_VALUE = true;
@ -68,6 +70,8 @@ public class OwnCloudClient extends HttpClient {
private Uri mBaseUri;
private OwnCloudVersion mVersion = null;
/**
* Constructor
*/
@ -173,8 +177,8 @@ public class OwnCloudClient extends HttpClient {
* @param readTimeout Timeout to set for data reception
* @param connectionTimeout Timeout to set for connection establishment
*/
public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout)
throws HttpException, IOException {
public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws IOException {
int oldSoTimeout = getParams().getSoTimeout();
int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();
try {
@ -193,22 +197,16 @@ public class OwnCloudClient extends HttpClient {
}
@Override
public int executeMethod(HttpMethod method) throws IOException, HttpException {
try { // just to log
boolean customRedirectionNeeded = false;
try {
method.setFollowRedirects(mFollowRedirects);
} catch (Exception e) {
/*
if (mFollowRedirects)
Log_OC.d(TAG, "setFollowRedirects failed for " + method.getName()
+ " method, custom redirection will be used if needed");
/**
* Requests the received method.
*
* Executes the method through the inherited HttpClient.executedMethod(method).
*
* @param method HTTP method request.
*/
customRedirectionNeeded = mFollowRedirects;
}
@Override
public int executeMethod(HttpMethod method) throws IOException {
try {
// Update User Agent
HttpParams params = method.getParams();
String userAgent = OwnCloudClientManagerFactory.getUserAgent();
@ -219,11 +217,12 @@ public class OwnCloudClient extends HttpClient {
// logCookiesAtRequest(method.getRequestHeaders(), "before");
// logCookiesAtState("before");
method.setFollowRedirects(false);
int status = super.executeMethod(method);
if (customRedirectionNeeded) {
status = patchRedirection(status, method);
if (mFollowRedirects) {
status = followRedirection(method).getLastStatus();
}
// logCookiesAtRequest(method.getRequestHeaders(), "after");
@ -233,13 +232,16 @@ public class OwnCloudClient extends HttpClient {
return status;
} catch (IOException e) {
Log_OC.d(TAG + " #" + mInstanceNumber, "Exception occurred", e);
//Log_OC.d(TAG + " #" + mInstanceNumber, "Exception occurred", e);
throw e;
}
}
private int patchRedirection(int status, HttpMethod method) throws HttpException, IOException {
public RedirectionPath followRedirection(HttpMethod method) throws IOException {
int redirectionsCount = 0;
int status = method.getStatusCode();
RedirectionPath result = new RedirectionPath(status, MAX_REDIRECTIONS_COUNT);
while (redirectionsCount < MAX_REDIRECTIONS_COUNT &&
( status == HttpStatus.SC_MOVED_PERMANENTLY ||
status == HttpStatus.SC_MOVED_TEMPORARILY ||
@ -254,18 +256,20 @@ public class OwnCloudClient extends HttpClient {
Log_OC.d(TAG + " #" + mInstanceNumber,
"Location to redirect: " + location.getValue());
String locationStr = location.getValue();
result.addLocation(locationStr);
// Release the connection to avoid reach the max number of connections per host
// due to it will be set a different url
exhaustResponse(method.getResponseBodyAsStream());
method.releaseConnection();
method.setURI(new URI(location.getValue(), true));
method.setURI(new URI(locationStr, true));
Header destination = method.getRequestHeader("Destination");
if (destination == null) {
destination = method.getRequestHeader("destination");
}
if (destination != null) {
String locationStr = location.getValue();
int suffixIndex = locationStr.lastIndexOf(
(mCredentials instanceof OwnCloudBearerCredentials) ?
AccountUtils.ODAV_PATH :
@ -281,6 +285,7 @@ public class OwnCloudClient extends HttpClient {
method.setRequestHeader(destination);
}
status = super.executeMethod(method);
result.addStatus(status);
redirectionsCount++;
} else {
@ -288,7 +293,7 @@ public class OwnCloudClient extends HttpClient {
status = HttpStatus.SC_NOT_FOUND;
}
}
return status;
return result;
}
/**
@ -356,6 +361,9 @@ public class OwnCloudClient extends HttpClient {
mFollowRedirects = followRedirects;
}
public boolean getFollowRedirects() {
return mFollowRedirects;
}
private void logCookiesAtRequest(Header[] headers, String when) {
int counter = 0;
@ -436,4 +444,11 @@ public class OwnCloudClient extends HttpClient {
}
public void setOwnCloudVersion(OwnCloudVersion version){
mVersion = version;
}
public OwnCloudVersion getOwnCloudVersion(){
return mVersion;
}
}

View File

@ -83,6 +83,7 @@ public class OwnCloudClientFactory {
am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null;
OwnCloudClient client = createOwnCloudClient(baseUri, appContext, !isSamlSso);
String username = account.name.substring(0, account.name.lastIndexOf('@'));
if (isOauth2) {
String accessToken = am.blockingGetAuthToken(
account,
@ -100,11 +101,10 @@ public class OwnCloudClientFactory {
false);
client.setCredentials(
OwnCloudCredentialsFactory.newSamlSsoCredentials(accessToken)
OwnCloudCredentialsFactory.newSamlSsoCredentials(username, accessToken)
);
} else {
String username = account.name.substring(0, account.name.lastIndexOf('@'));
//String password = am.getPassword(account);
String password = am.blockingGetAuthToken(
account,
@ -137,6 +137,7 @@ public class OwnCloudClientFactory {
am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null;
OwnCloudClient client = createOwnCloudClient(baseUri, appContext, !isSamlSso);
String username = account.name.substring(0, account.name.lastIndexOf('@'));
if (isOauth2) { // TODO avoid a call to getUserData here
AccountManagerFuture<Bundle> future = am.getAuthToken(
account,
@ -166,12 +167,11 @@ public class OwnCloudClientFactory {
String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN);
if (accessToken == null) throw new AuthenticatorException("WTF!");
client.setCredentials(
OwnCloudCredentialsFactory.newSamlSsoCredentials(accessToken)
OwnCloudCredentialsFactory.newSamlSsoCredentials(username, accessToken)
);
} else {
String username = account.name.substring(0, account.name.lastIndexOf('@'));
//String password = am.getPassword(account);
//String password = am.blockingGetAuthToken(account, MainApp.getAuthTokenTypePass(),
// false);

View File

@ -36,8 +36,8 @@ public class OwnCloudCredentialsFactory {
return new OwnCloudBearerCredentials(authToken);
}
public static OwnCloudCredentials newSamlSsoCredentials(String sessionCookie) {
return new OwnCloudSamlSsoCredentials(sessionCookie);
public static OwnCloudCredentials newSamlSsoCredentials(String username, String sessionCookie) {
return new OwnCloudSamlSsoCredentials(username, sessionCookie);
}
public static final OwnCloudCredentials getAnonymousCredentials() {

View File

@ -30,9 +30,11 @@ import android.net.Uri;
public class OwnCloudSamlSsoCredentials implements OwnCloudCredentials {
private String mUsername;
private String mSessionCookie;
public OwnCloudSamlSsoCredentials(String sessionCookie) {
public OwnCloudSamlSsoCredentials(String username, String sessionCookie) {
mUsername = username != null ? username : "";
mSessionCookie = sessionCookie != null ? sessionCookie : "";
}
@ -63,8 +65,8 @@ public class OwnCloudSamlSsoCredentials implements OwnCloudCredentials {
@Override
public String getUsername() {
// its unknown
return null;
// not relevant for authentication, but relevant for informational purposes
return mUsername;
}
@Override

View File

@ -168,6 +168,8 @@ public class AccountUtils {
account,
AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null;
String username = account.name.substring(0, account.name.lastIndexOf('@'));
if (isOauth2) {
String accessToken = am.blockingGetAuthToken(
account,
@ -182,10 +184,9 @@ public class AccountUtils {
AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type),
false);
credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials(accessToken);
credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials(username, accessToken);
} else {
String username = account.name.substring(0, account.name.lastIndexOf('@'));
String password = am.blockingGetAuthToken(
account,
AccountTypeUtils.getAuthTokenTypePass(account.type),
@ -199,7 +200,7 @@ public class AccountUtils {
}
public static String buildAccountName(Uri serverBaseUrl, String username) {
public static String buildAccountNameOld(Uri serverBaseUrl, String username) {
if (serverBaseUrl.getScheme() == null) {
serverBaseUrl = Uri.parse("https://" + serverBaseUrl.toString());
}
@ -210,6 +211,20 @@ public class AccountUtils {
return accountName;
}
public static String buildAccountName(Uri serverBaseUrl, String username) {
if (serverBaseUrl.getScheme() == null) {
serverBaseUrl = Uri.parse("https://" + serverBaseUrl.toString());
}
// Remove http:// or https://
String url = serverBaseUrl.toString();
if (url.contains("://")) {
url = url.substring(serverBaseUrl.toString().indexOf("://") + 3);
}
String accountName = username + "@" + url;
return accountName;
}
public static void saveClient(OwnCloudClient client, Account savedAccount, Context context) {
@ -336,12 +351,18 @@ public class AccountUtils {
public static final String KEY_SUPPORTS_SAML_WEB_SSO = "oc_supports_saml_web_sso";
/**
* Flag signaling if the ownCloud server supports Share API"
* @deprecated
*/
public static final String KEY_SUPPORTS_SHARE_API = "oc_supports_share_api";
/**
* OC accout cookies
* OC account cookies
*/
public static final String KEY_COOKIES = "oc_account_cookies";
/**
* OC account version
*/
public static final String KEY_OC_ACCOUNT_VERSION = "oc_account_version";
}
}

View File

@ -0,0 +1,127 @@
/* 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.common.network;
import org.apache.http.HttpStatus;
import java.util.Arrays;
/**
* Aggregate saving the list of URLs followed in a sequence of redirections during the exceution of a
* {@link com.owncloud.android.lib.common.operations.RemoteOperation}, and the status codes corresponding to all
* of them.
*
* The last status code saved corresponds to the first response not being a redirection, unless the sequence exceeds
* the maximum length of redirections allowed by the {@link com.owncloud.android.lib.common.OwnCloudClient} instance
* that ran the operation.
*
* If no redirection was followed, the last (and first) status code contained corresponds to the original URL in the
* request.
*/
public class RedirectionPath {
private int[] mStatuses = null;
private int mLastStatus = -1;
private String[] mLocations = null;
private int mLastLocation = -1;
private int maxRedirections;
/**
* Public constructor.
*
* @param status Status code resulting of executing a request on the original URL.
* @param maxRedirections Maximum number of redirections that will be contained.
* @throws IllegalArgumentException If 'maxRedirections' is < 0
*/
public RedirectionPath(int status, int maxRedirections) {
if (maxRedirections < 0) {
throw new IllegalArgumentException("maxRedirections MUST BE zero or greater");
}
mStatuses = new int[maxRedirections + 1];
Arrays.fill(mStatuses, -1);
mStatuses[++mLastStatus] = status;
}
/**
* Adds a new location URL to the list of followed redirections.
*
* @param location URL extracted from a 'Location' header in a redirection.
*/
public void addLocation(String location) {
if (mLocations == null) {
mLocations = new String[mStatuses.length - 1];
}
if (mLastLocation < mLocations.length - 1) {
mLocations[++mLastLocation] = location;
}
}
/**
* Adds a new status code to the list of status corresponding to followed redirections.
*
* @param status Status code from the response of another followed redirection.
*/
public void addStatus(int status) {
if (mLastStatus < mStatuses.length - 1) {
mStatuses[++mLastStatus] = status;
}
}
/**
* @return Last status code saved.
*/
public int getLastStatus() {
return mStatuses[mLastStatus];
}
/**
* @return Last location followed corresponding to a permanent redirection (status code 301).
*/
public String getLastPermanentLocation() {
for (int i = mLastStatus; i >= 0; i--) {
if (mStatuses[i] == HttpStatus.SC_MOVED_PERMANENTLY && i <= mLastLocation) {
return mLocations[i];
}
}
return null;
}
/**
* @return Count of locations.
*/
public int getRedirectionsCount() {
return mLastLocation + 1;
}
}

View File

@ -24,6 +24,7 @@
package com.owncloud.android.lib.common.network;
import java.math.BigDecimal;
import java.util.Date;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
@ -37,6 +38,9 @@ import android.net.Uri;
import com.owncloud.android.lib.common.utils.Log_OC;
public class WebdavEntry {
private static final String TAG = WebdavEntry.class.getSimpleName();
public static final String NAMESPACE_OC = "http://owncloud.org/ns";
public static final String EXTENDED_PROPERTY_NAME_PERMISSIONS = "permissions";
public static final String EXTENDED_PROPERTY_NAME_REMOTE_ID = "id";
@ -49,7 +53,7 @@ public class WebdavEntry {
private String mName, mPath, mUri, mContentType, mEtag, mPermissions, mRemoteId;
private long mContentLength, mCreateTimestamp, mModifiedTimestamp, mSize;
private long mQuotaUsedBytes, mQuotaAvailableBytes;
private BigDecimal mQuotaUsedBytes, mQuotaAvailableBytes;
public WebdavEntry(MultiStatusResponse ms, String splitElement) {
resetData();
@ -125,20 +129,37 @@ public class WebdavEntry {
prop = propSet.get(DavPropertyName.GETETAG);
if (prop != null) {
mEtag = (String) prop.getValue();
mEtag = mEtag.substring(1, mEtag.length()-1);
mEtag = WebdavUtils.parseEtag(mEtag);
}
// {DAV:}quota-used-bytes
prop = propSet.get(DavPropertyName.create(PROPERTY_QUOTA_USED_BYTES));
if (prop != null) {
mQuotaUsedBytes = Long.parseLong((String) prop.getValue());
String quotaUsedBytesSt = (String) prop.getValue();
try {
mQuotaUsedBytes = new BigDecimal(quotaUsedBytesSt);
} catch (NumberFormatException e) {
Log_OC.w(TAG, "No value for QuotaUsedBytes - NumberFormatException");
} catch (NullPointerException e ){
Log_OC.w(TAG, "No value for QuotaUsedBytes - NullPointerException");
}
Log_OC.d(TAG , "QUOTA_USED_BYTES " + quotaUsedBytesSt );
}
// {DAV:}quota-available-bytes
prop = propSet.get(DavPropertyName.create(PROPERTY_QUOTA_AVAILABLE_BYTES));
if (prop != null) {
mQuotaAvailableBytes = Long.parseLong((String) prop.getValue());
String quotaAvailableBytesSt = (String) prop.getValue();
try {
mQuotaAvailableBytes = new BigDecimal(quotaAvailableBytesSt);
} catch (NumberFormatException e) {
Log_OC.w(TAG, "No value for QuotaAvailableBytes - NumberFormatException");
} catch (NullPointerException e ){
Log_OC.w(TAG, "No value for QuotaAvailableBytes");
}
Log_OC.d(TAG , "QUOTA_AVAILABLE_BYTES " + quotaAvailableBytesSt );
}
// OC permissions property <oc:permissions>
prop = propSet.get(
EXTENDED_PROPERTY_NAME_PERMISSIONS, Namespace.getNamespace(NAMESPACE_OC)
@ -222,11 +243,11 @@ public class WebdavEntry {
return mSize;
}
public long quotaUsedBytes() {
public BigDecimal quotaUsedBytes() {
return mQuotaUsedBytes;
}
public long quotaAvailableBytes() {
public BigDecimal quotaAvailableBytes() {
return mQuotaAvailableBytes;
}
@ -234,7 +255,7 @@ public class WebdavEntry {
mName = mUri = mContentType = mPermissions = null; mRemoteId = null;
mContentLength = mCreateTimestamp = mModifiedTimestamp = 0;
mSize = 0;
mQuotaUsedBytes = 0;
mQuotaAvailableBytes = 0;
mQuotaUsedBytes = null;
mQuotaAvailableBytes = null;
}
}

View File

@ -32,6 +32,8 @@ import java.util.Locale;
import android.net.Uri;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.jackrabbit.webdav.property.DavPropertyName;
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
import org.apache.jackrabbit.webdav.xml.Namespace;
@ -131,4 +133,47 @@ public class WebdavUtils {
return propSet;
}
/**
*
* @param rawEtag
* @return
*/
public static String parseEtag(String rawEtag) {
if (rawEtag == null || rawEtag.length() == 0) {
return "";
}
if (rawEtag.endsWith("-gzip")) {
rawEtag = rawEtag.substring(0, rawEtag.length() - 5);
}
if (rawEtag.length() >= 2 && rawEtag.startsWith("\"") && rawEtag.endsWith("\"")) {
rawEtag = rawEtag.substring(1, rawEtag.length() - 1);
}
return rawEtag;
}
/**
*
* @param method
* @return
*/
public static String getEtagFromResponse(HttpMethod method) {
Header eTag = method.getResponseHeader("OC-ETag");
if (eTag == null) {
eTag = method.getResponseHeader("oc-etag");
}
if (eTag == null) {
eTag = method.getResponseHeader("ETag");
}
if (eTag == null) {
eTag = method.getResponseHeader("etag");
}
String result = "";
if (eTag != null) {
result = parseEtag(eTag.getValue());
}
return result;
}
}

View File

@ -0,0 +1,146 @@
/* ownCloud Android Library is available under MIT license
* 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.common.operations;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.IOException;
import java.io.InputStream;
/**
* Parser for Invalid Character server exception
* @author masensio
*/
public class InvalidCharacterExceptionParser {
private static final String EXCEPTION_STRING = "OC\\Connector\\Sabre\\Exception\\InvalidPath";
private static final String EXCEPTION_UPLOAD_STRING = "OCP\\Files\\InvalidPathException";
// No namespaces
private static final String ns = null;
// Nodes for XML Parser
private static final String NODE_ERROR = "d:error";
private static final String NODE_EXCEPTION = "s:exception";
/**
* Parse is as an Invalid Path Exception
* @param is
* @return if The exception is an Invalid Char Exception
* @throws XmlPullParserException
* @throws IOException
*/
public boolean parseXMLResponse(InputStream is) throws XmlPullParserException,
IOException {
boolean result = false;
try {
// XMLPullParser
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(is, null);
parser.nextTag();
result = readError(parser);
} finally {
is.close();
}
return result;
}
/**
* Parse OCS node
* @param parser
* @return List of ShareRemoteFiles
* @throws XmlPullParserException
* @throws IOException
*/
private boolean readError (XmlPullParser parser) throws XmlPullParserException, IOException {
String exception = "";
parser.require(XmlPullParser.START_TAG, ns , NODE_ERROR);
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
// read NODE_EXCEPTION
if (name.equalsIgnoreCase(NODE_EXCEPTION)) {
exception = readText(parser);
} else {
skip(parser);
}
}
return exception.equalsIgnoreCase(EXCEPTION_STRING) ||
exception.equalsIgnoreCase(EXCEPTION_UPLOAD_STRING);
}
/**
* Skip tags in parser procedure
* @param parser
* @throws XmlPullParserException
* @throws IOException
*/
private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
if (parser.getEventType() != XmlPullParser.START_TAG) {
throw new IllegalStateException();
}
int depth = 1;
while (depth != 0) {
switch (parser.next()) {
case XmlPullParser.END_TAG:
depth--;
break;
case XmlPullParser.START_TAG:
depth++;
break;
}
}
}
/**
* Read the text from a node
* @param parser
* @return Text of the node
* @throws IOException
* @throws XmlPullParserException
*/
private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
String result = "";
if (parser.next() == XmlPullParser.TEXT) {
result = parser.getText();
parser.nextTag();
}
return result;
}
}

View File

@ -24,8 +24,6 @@
package com.owncloud.android.lib.common.operations;
import java.io.IOException;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountsException;
@ -42,6 +40,8 @@ import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.io.IOException;
/**
* Operation which execution involves one or several interactions with an ownCloud server.

View File

@ -24,15 +24,21 @@
package com.owncloud.android.lib.common.operations;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import android.accounts.Account;
import android.accounts.AccountsException;
import javax.net.ssl.SSLException;
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
import com.owncloud.android.lib.common.network.CertificateCombinedException;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.Header;
@ -41,17 +47,12 @@ import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavException;
import org.json.JSONException;
import android.accounts.Account;
import android.accounts.AccountsException;
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
import com.owncloud.android.lib.common.network.CertificateCombinedException;
import com.owncloud.android.lib.common.utils.Log_OC;
import javax.net.ssl.SSLException;
/**
* The result of a remote operation required to an ownCloud server.
*
* <p/>
* Provides a common classification of remote operation results for all the
* application.
*
@ -60,9 +61,9 @@ import com.owncloud.android.lib.common.utils.Log_OC;
public class RemoteOperationResult implements Serializable {
/** Generated - should be refreshed every time the class changes!! */;
private static final long serialVersionUID = -9003837206000993465L;
private static final long serialVersionUID = 1129130415603799707L;
private static final String TAG = "RemoteOperationResult";
private static final String TAG = RemoteOperationResult.class.getSimpleName();
public enum ResultCode {
OK,
@ -103,7 +104,11 @@ public class RemoteOperationResult implements Serializable {
SHARE_FORBIDDEN,
OK_REDIRECT_TO_NON_SECURE_CONNECTION,
INVALID_MOVE_INTO_DESCENDANT,
PARTIAL_MOVE_DONE
INVALID_COPY_INTO_DESCENDANT,
PARTIAL_MOVE_DONE,
PARTIAL_COPY_DONE,
SHARE_WRONG_PARAMETER,
WRONG_SERVER_RESPONSE, INVALID_CHARACTER_DETECT_IN_SERVER
}
private boolean mSuccess = false;
@ -112,12 +117,15 @@ public class RemoteOperationResult implements Serializable {
private ResultCode mCode = ResultCode.UNKNOWN_ERROR;
private String mRedirectedLocation;
private String mAuthenticate;
private String mLastPermanentLocation = null;
private ArrayList<Object> mData;
public RemoteOperationResult(ResultCode code) {
mCode = code;
mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL || code == ResultCode.OK_NO_SSL || code == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION);
mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL ||
code == ResultCode.OK_NO_SSL ||
code == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION);
mData = null;
}
@ -150,7 +158,8 @@ public class RemoteOperationResult implements Serializable {
break;
default:
mCode = ResultCode.UNHANDLED_HTTP_CODE;
Log_OC.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " + httpCode);
Log_OC.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " +
httpCode);
}
}
}
@ -159,7 +168,7 @@ public class RemoteOperationResult implements Serializable {
this(success, httpCode);
if (headers != null) {
Header current;
for (int i=0; i<headers.length; i++) {
for (int i = 0; i < headers.length; i++) {
current = headers[i];
if ("location".equals(current.getName().toLowerCase())) {
mRedirectedLocation = current.getValue();
@ -173,6 +182,37 @@ public class RemoteOperationResult implements Serializable {
}
}
public RemoteOperationResult(boolean success, String bodyResponse, int httpCode) {
mSuccess = success;
mHttpCode = httpCode;
if (success) {
mCode = ResultCode.OK;
} else if (httpCode > 0) {
switch (httpCode) {
case HttpStatus.SC_BAD_REQUEST:
InputStream is = new ByteArrayInputStream(bodyResponse.getBytes());
InvalidCharacterExceptionParser xmlParser = new InvalidCharacterExceptionParser();
try {
if (xmlParser.parseXMLResponse(is))
mCode = ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER;
} catch (Exception e) {
mCode = ResultCode.UNHANDLED_HTTP_CODE;
Log_OC.e(TAG, "Exception reading exception from server", e);
}
break;
default:
mCode = ResultCode.UNHANDLED_HTTP_CODE;
Log_OC.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " +
httpCode);
}
}
}
public RemoteOperationResult(Exception e) {
mException = e;
@ -221,11 +261,11 @@ public class RemoteOperationResult implements Serializable {
}
public void setData(ArrayList<Object> files){
public void setData(ArrayList<Object> files) {
mData = files;
}
public ArrayList<Object> getData(){
public ArrayList<Object> getData() {
return mData;
}
@ -264,7 +304,8 @@ public class RemoteOperationResult implements Serializable {
}
Throwable cause = mException.getCause();
Throwable previousCause = null;
while (cause != null && cause != previousCause && !(cause instanceof CertificateCombinedException)) {
while (cause != null && cause != previousCause &&
!(cause instanceof CertificateCombinedException)) {
previousCause = cause;
cause = cause.getCause();
}
@ -314,8 +355,10 @@ public class RemoteOperationResult implements Serializable {
return "Unrecovered transport exception";
} else if (mException instanceof AccountNotFoundException) {
Account failedAccount = ((AccountNotFoundException)mException).getFailedAccount();
return mException.getMessage() + " (" + (failedAccount != null ? failedAccount.name : "NULL") + ")";
Account failedAccount =
((AccountNotFoundException)mException).getFailedAccount();
return mException.getMessage() + " (" +
(failedAccount != null ? failedAccount.name : "NULL") + ")";
} else if (mException instanceof AccountsException) {
return "Exception while using account";
@ -348,13 +391,19 @@ public class RemoteOperationResult implements Serializable {
} else if (mCode == ResultCode.ACCOUNT_NOT_THE_SAME) {
return "Authenticated with a different account than the one updating";
} else if (mCode == ResultCode.INVALID_CHARACTER_IN_NAME) {
return "The file name contains an forbidden character";
} else if (mCode == ResultCode.FILE_NOT_FOUND) {
return "Local file does not exist";
} else if (mCode == ResultCode.SYNC_CONFLICT) {
return "Synchronization conflict";
}
return "Operation finished with HTTP status code " + mHttpCode + " (" + (isSuccess() ? "success" : "fail") + ")";
return "Operation finished with HTTP status code " + mHttpCode + " (" +
(isSuccess() ? "success" : "fail") + ")";
}
@ -393,4 +442,12 @@ public class RemoteOperationResult implements Serializable {
return mAuthenticate;
}
public String getLastPermanentLocation() {
return mLastPermanentLocation;
}
public void setLastPermanentLocation(String lastPermanentLocation) {
mLastPermanentLocation = lastPermanentLocation;
}
}

View File

@ -32,8 +32,7 @@ public class Log_OC {
}
public static void i(String TAG, String message){
// Write the log message to the file
Log.i(TAG, message);
appendLog(TAG+" : "+ message);
}
@ -61,7 +60,7 @@ public class Log_OC {
}
public static void w(String TAG, String message) {
Log.w(TAG,message);
Log.w(TAG, message);
appendLog(TAG+" : "+ message);
}
@ -101,6 +100,14 @@ public class Log_OC {
} catch (IOException e) {
e.printStackTrace();
} finally {
if(mBuf != null) {
try {
mBuf.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
}
@ -160,10 +167,15 @@ public class Log_OC {
mBuf.newLine();
mBuf.write(text);
mBuf.newLine();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
mBuf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// Check if current log file size is bigger than the max file size defined
if (mLogFile.length() > MAX_FILE_SIZE) {

View File

@ -24,19 +24,21 @@
package com.owncloud.android.lib.resources.files;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.Random;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PutMethod;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.ChunkFromFileChannelRequestEntity;
import com.owncloud.android.lib.common.network.ProgressiveDataTransferer;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.InvalidCharacterExceptionParser;
import com.owncloud.android.lib.common.utils.Log_OC;
@ -44,14 +46,21 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation
public static final long CHUNK_SIZE = 1024000;
private static final String OC_CHUNKED_HEADER = "OC-Chunked";
private static final String OC_CHUNK_SIZE_HEADER = "OC-Chunk-Size";
private static final String TAG = ChunkedUploadRemoteFileOperation.class.getSimpleName();
public ChunkedUploadRemoteFileOperation(String storagePath, String remotePath, String mimeType) {
public ChunkedUploadRemoteFileOperation(String storagePath, String remotePath, String mimeType){
super(storagePath, remotePath, mimeType);
}
public ChunkedUploadRemoteFileOperation(
String storagePath, String remotePath, String mimeType, String requiredEtag
){
super(storagePath, remotePath, mimeType, requiredEtag);
}
@Override
protected int uploadFile(OwnCloudClient client) throws HttpException, IOException {
protected int uploadFile(OwnCloudClient client) throws IOException {
int status = -1;
FileChannel channel = null;
@ -61,25 +70,60 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation
raf = new RandomAccessFile(file, "r");
channel = raf.getChannel();
mEntity = new ChunkFromFileChannelRequestEntity(channel, mMimeType, CHUNK_SIZE, file);
//((ProgressiveDataTransferer)mEntity).addDatatransferProgressListeners(getDataTransferListeners());
synchronized (mDataTransferListeners) {
((ProgressiveDataTransferer)mEntity).addDatatransferProgressListeners(mDataTransferListeners);
((ProgressiveDataTransferer)mEntity)
.addDatatransferProgressListeners(mDataTransferListeners);
}
long offset = 0;
String uriPrefix = client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath) + "-chunking-" + Math.abs((new Random()).nextInt(9000)+1000) + "-" ;
long chunkCount = (long) Math.ceil((double)file.length() / CHUNK_SIZE);
String uriPrefix = client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath) +
"-chunking-" + Math.abs((new Random()).nextInt(9000)+1000) + "-" ;
long totalLength = file.length();
long chunkCount = (long) Math.ceil((double)totalLength / CHUNK_SIZE);
String chunkSizeStr = String.valueOf(CHUNK_SIZE);
String totalLengthStr = String.valueOf(file.length());
for (int chunkIndex = 0; chunkIndex < chunkCount ; chunkIndex++, offset += CHUNK_SIZE) {
if (chunkIndex == chunkCount - 1) {
chunkSizeStr = String.valueOf(CHUNK_SIZE * chunkCount - totalLength);
}
if (mPutMethod != null) {
mPutMethod.releaseConnection(); // let the connection available for other methods
mPutMethod.releaseConnection(); // let the connection available
// for other methods
}
mPutMethod = new PutMethod(uriPrefix + chunkCount + "-" + chunkIndex);
if (mRequiredEtag != null && mRequiredEtag.length() > 0) {
mPutMethod.addRequestHeader(IF_MATCH_HEADER, "\"" + mRequiredEtag + "\"");
}
mPutMethod.addRequestHeader(OC_CHUNKED_HEADER, OC_CHUNKED_HEADER);
((ChunkFromFileChannelRequestEntity)mEntity).setOffset(offset);
mPutMethod.addRequestHeader(OC_CHUNK_SIZE_HEADER, chunkSizeStr);
mPutMethod.addRequestHeader(OC_TOTAL_LENGTH_HEADER, totalLengthStr);
((ChunkFromFileChannelRequestEntity) mEntity).setOffset(offset);
mPutMethod.setRequestEntity(mEntity);
if (mCancellationRequested.get()) {
mPutMethod.abort();
// next method will throw an exception
}
status = client.executeMethod(mPutMethod);
if (status == 400) {
InvalidCharacterExceptionParser xmlParser =
new InvalidCharacterExceptionParser();
InputStream is = new ByteArrayInputStream(
mPutMethod.getResponseBodyAsString().getBytes());
try {
mForbiddenCharsInServer = xmlParser.parseXMLResponse(is);
} catch (Exception e) {
mForbiddenCharsInServer = false;
Log_OC.e(TAG, "Exception reading exception from server", e);
}
}
client.exhaustResponse(mPutMethod.getResponseBodyAsStream());
Log_OC.d(TAG, "Upload of " + mLocalPath + " to " + mRemotePath + ", chunk index " + chunkIndex + ", count " + chunkCount + ", HTTP result status " + status);
Log_OC.d(TAG, "Upload of " + mLocalPath + " to " + mRemotePath +
", chunk index " + chunkIndex + ", count " + chunkCount +
", HTTP result status " + status);
if (!isSuccess(status))
break;
}

View File

@ -0,0 +1,215 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 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.files;
import android.util.Log;
import com.owncloud.android.lib.common.OwnCloudClient;
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.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
import org.apache.jackrabbit.webdav.Status;
import org.apache.jackrabbit.webdav.client.methods.CopyMethod;
import java.io.IOException;
/**
* Remote operation moving a remote file or folder in the ownCloud server to a different folder
* in the same account.
* <p/>
* Allows renaming the moving file/folder at the same time.
*
* @author David A. Velasco
*/
public class CopyRemoteFileOperation extends RemoteOperation {
private static final String TAG = CopyRemoteFileOperation.class.getSimpleName();
private static final int COPY_READ_TIMEOUT = 600000;
private static final int COPY_CONNECTION_TIMEOUT = 5000;
private String mSrcRemotePath;
private String mTargetRemotePath;
private boolean mOverwrite;
/**
* Constructor.
* <p/>
* TODO Paths should finish in "/" in the case of folders. ?
*
* @param srcRemotePath Remote path of the file/folder to move.
* @param targetRemotePath Remove path desired for the file/folder after moving it.
*/
public CopyRemoteFileOperation(String srcRemotePath, String targetRemotePath, boolean overwrite
) {
mSrcRemotePath = srcRemotePath;
mTargetRemotePath = targetRemotePath;
mOverwrite = overwrite;
}
/**
* Performs the rename operation.
*
* @param client Client object to communicate with the remote ownCloud server.
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
OwnCloudVersion version = client.getOwnCloudVersion();
boolean versionWithForbiddenChars =
(version != null && version.isVersionWithForbiddenCharacters());
/// check parameters
if (!FileUtils.isValidPath(mTargetRemotePath, versionWithForbiddenChars)) {
return new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME);
}
if (mTargetRemotePath.equals(mSrcRemotePath)) {
// nothing to do!
return new RemoteOperationResult(ResultCode.OK);
}
if (mTargetRemotePath.startsWith(mSrcRemotePath)) {
return new RemoteOperationResult(ResultCode.INVALID_COPY_INTO_DESCENDANT);
}
/// perform remote operation
CopyMethod copyMethod = null;
RemoteOperationResult result = null;
try {
copyMethod = new CopyMethod(
client.getWebdavUri() + WebdavUtils.encodePath(mSrcRemotePath),
client.getWebdavUri() + WebdavUtils.encodePath(mTargetRemotePath),
mOverwrite
);
int status = client.executeMethod(copyMethod, COPY_READ_TIMEOUT, COPY_CONNECTION_TIMEOUT);
/// process response
if (status == HttpStatus.SC_MULTI_STATUS) {
result = processPartialError(copyMethod);
} else if (status == HttpStatus.SC_PRECONDITION_FAILED && !mOverwrite) {
result = new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
client.exhaustResponse(copyMethod.getResponseBodyAsStream());
/// for other errors that could be explicitly handled, check first:
/// http://www.webdav.org/specs/rfc4918.html#rfc.section.9.9.4
} else if (status == 400) {
result = new RemoteOperationResult(copyMethod.succeeded(),
copyMethod.getResponseBodyAsString(), status);
} else {
result = new RemoteOperationResult(
isSuccess(status), // copy.succeeded()? trustful?
status,
copyMethod.getResponseHeaders()
);
client.exhaustResponse(copyMethod.getResponseBodyAsStream());
}
Log.i(TAG, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " +
result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log.e(TAG, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " +
result.getLogMessage(), e);
} finally {
if (copyMethod != null)
copyMethod.releaseConnection();
}
return result;
}
/**
* Analyzes a multistatus response from the OC server to generate an appropriate result.
* <p/>
* In WebDAV, a COPY request on collections (folders) can be PARTIALLY successful: some
* children are copied, some other aren't.
* <p/>
* According to the WebDAV specification, a multistatus response SHOULD NOT include partial
* successes (201, 204) nor for descendants of already failed children (424) in the response
* entity. But SHOULD NOT != MUST NOT, so take carefully.
*
* @param copyMethod Copy operation just finished with a multistatus response
* @return A result for the {@link com.owncloud.android.lib.resources.files.CopyRemoteFileOperation} caller
* @throws java.io.IOException If the response body could not be parsed
* @throws org.apache.jackrabbit.webdav.DavException If the status code is other than MultiStatus or if obtaining
* the response XML document fails
*/
private RemoteOperationResult processPartialError(CopyMethod copyMethod)
throws IOException, DavException {
// Adding a list of failed descendants to the result could be interesting; or maybe not.
// For the moment, let's take the easy way.
/// check that some error really occurred
MultiStatusResponse[] responses = copyMethod.getResponseBodyAsMultiStatus().getResponses();
Status[] status;
boolean failFound = false;
for (int i = 0; i < responses.length && !failFound; i++) {
status = responses[i].getStatus();
failFound = (
status != null &&
status.length > 0 &&
status[0].getStatusCode() > 299
);
}
RemoteOperationResult result;
if (failFound) {
result = new RemoteOperationResult(ResultCode.PARTIAL_COPY_DONE);
} else {
result = new RemoteOperationResult(
true,
HttpStatus.SC_MULTI_STATUS,
copyMethod.getResponseHeaders()
);
}
return result;
}
protected boolean isSuccess(int status) {
return status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT;
}
}

View File

@ -24,7 +24,6 @@
package com.owncloud.android.lib.resources.files;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.client.methods.MkColMethod;
import com.owncloud.android.lib.common.OwnCloudClient;
@ -33,7 +32,7 @@ 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;
/**
@ -58,7 +57,8 @@ public class CreateRemoteFolderOperation extends RemoteOperation {
* Constructor
*
* @param remotePath Full path to the new directory to create in the remote server.
* @param createFullPath 'True' means that all the ancestor folders should be created if don't exist yet.
* @param createFullPath 'True' means that all the ancestor folders should be created
* if don't exist yet.
*/
public CreateRemoteFolderOperation(String remotePath, boolean createFullPath) {
mRemotePath = remotePath;
@ -73,7 +73,10 @@ public class CreateRemoteFolderOperation extends RemoteOperation {
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
boolean noInvalidChars = FileUtils.isValidPath(mRemotePath);
OwnCloudVersion version = client.getOwnCloudVersion();
boolean versionWithForbiddenChars =
(version != null && version.isVersionWithForbiddenCharacters());
boolean noInvalidChars = FileUtils.isValidPath(mRemotePath, versionWithForbiddenChars);
if (noInvalidChars) {
result = createFolder(client);
if (!result.isSuccess() && mCreateFullPath &&
@ -98,8 +101,16 @@ public class CreateRemoteFolderOperation extends RemoteOperation {
try {
mkcol = new MkColMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath));
int status = client.executeMethod(mkcol, READ_TIMEOUT, CONNECTION_TIMEOUT);
result = new RemoteOperationResult(mkcol.succeeded(), status, mkcol.getResponseHeaders());
if ( status == 400 ) {
result = new RemoteOperationResult(mkcol.succeeded(),
mkcol.getResponseBodyAsString(), status);
Log_OC.d(TAG, mkcol.getResponseBodyAsString());
} else {
result = new RemoteOperationResult(mkcol.succeeded(), status,
mkcol.getResponseHeaders());
Log_OC.d(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage());
}
client.exhaustResponse(mkcol.getResponseBodyAsStream());
} catch (Exception e) {

View File

@ -61,6 +61,7 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
private long mModificationTimestamp = 0;
private String mEtag = "";
private GetMethod mGet;
private String mRemotePath;
@ -140,12 +141,24 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
if (transferred == totalToTransfer) { // Check if the file is completed
savedFile = true;
Header modificationTime = mGet.getResponseHeader("Last-Modified");
if (modificationTime == null) {
modificationTime = mGet.getResponseHeader("last-modified");
}
if (modificationTime != null) {
Date d = WebdavUtils.parseResponseDate((String) modificationTime.getValue());
mModificationTimestamp = (d != null) ? d.getTime() : 0;
} else {
Log_OC.e(TAG, "Could not read modification time from response downloading " + mRemotePath);
}
mEtag = WebdavUtils.getEtagFromResponse(mGet);
if (mEtag.length() == 0) {
Log_OC.e(TAG, "Could not read eTag from response downloading " + mRemotePath);
}
} else {
client.exhaustResponse(mGet.getResponseBodyAsStream());
// TODO some kind of error control!
}
} else {
@ -190,4 +203,7 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
return mModificationTimestamp;
}
public String getEtag() {
return mEtag;
}
}

View File

@ -28,9 +28,9 @@ import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.HeadMethod;
import android.content.Context;
import android.net.ConnectivityManager;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.RedirectionPath;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
@ -49,9 +49,23 @@ public class ExistenceCheckRemoteOperation extends RemoteOperation {
private static final String TAG = ExistenceCheckRemoteOperation.class.getSimpleName();
private String mPath;
private Context mContext;
private boolean mSuccessIfAbsent;
/** Sequence of redirections followed. Available only after executing the operation */
private RedirectionPath mRedirectionPath = null;
// TODO move to {@link RemoteOperation}, that needs a nice refactoring
/**
* Full constructor. Success of the operation will depend upon the value of successIfAbsent.
*
* @param remotePath Path to append to the URL owned by the client instance.
* @param successIfAbsent When 'true', the operation finishes in success if the path does
* NOT exist in the remote server (HTTP 404).
*/
public ExistenceCheckRemoteOperation(String remotePath, boolean successIfAbsent) {
mPath = (remotePath != null) ? remotePath : "";
mSuccessIfAbsent = successIfAbsent;
}
/**
* Full constructor. Success of the operation will depend upon the value of successIfAbsent.
@ -60,24 +74,25 @@ public class ExistenceCheckRemoteOperation extends RemoteOperation {
* @param context Android application context.
* @param successIfAbsent When 'true', the operation finishes in success if the path does
* NOT exist in the remote server (HTTP 404).
* @deprecated
*/
public ExistenceCheckRemoteOperation(String remotePath, Context context, boolean successIfAbsent) {
mPath = (remotePath != null) ? remotePath : "";
mContext = context;
mSuccessIfAbsent = successIfAbsent;
this(remotePath, successIfAbsent);
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
if (!isOnline()) {
return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION);
}
RemoteOperationResult result = null;
HeadMethod head = null;
boolean previousFollowRedirects = client.getFollowRedirects();
try {
head = new HeadMethod(client.getWebdavUri() + WebdavUtils.encodePath(mPath));
client.setFollowRedirects(false);
int status = client.executeMethod(head, TIMEOUT, TIMEOUT);
if (previousFollowRedirects) {
mRedirectionPath = client.followRedirection(head);
status = mRedirectionPath.getLastStatus();
}
client.exhaustResponse(head.getResponseBodyAsStream());
boolean success = (status == HttpStatus.SC_OK && !mSuccessIfAbsent) ||
(status == HttpStatus.SC_NOT_FOUND && mSuccessIfAbsent);
@ -97,16 +112,25 @@ public class ExistenceCheckRemoteOperation extends RemoteOperation {
} finally {
if (head != null)
head.releaseConnection();
client.setFollowRedirects(previousFollowRedirects);
}
return result;
}
private boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) mContext
.getSystemService(Context.CONNECTIVITY_SERVICE);
return cm != null && cm.getActiveNetworkInfo() != null
&& cm.getActiveNetworkInfo().isConnectedOrConnecting();
/**
* Gets the sequence of redirections followed during the execution of the operation.
*
* @return Sequence of redirections followed, if any, or NULL if the operation was not executed.
*/
public RedirectionPath getRedirectionPath() {
return mRedirectionPath;
}
/**
* @return 'True' if the operation was executed and at least one redirection was followed.
*/
public boolean wasRedirected() {
return (mRedirectionPath != null && mRedirectionPath.getRedirectionsCount() > 0);
}
}

View File

@ -27,9 +27,12 @@ package com.owncloud.android.lib.resources.files;
import java.io.File;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
public class FileUtils {
private static final String TAG = FileUtils.class.getSimpleName();
public static final String PATH_SEPARATOR = "/";
@ -40,39 +43,44 @@ public class FileUtils {
}
/**
* Validate the fileName to detect if contains any forbidden character: / , \ , < , > , : , " , | , ? , *
* Validate the fileName to detect if contains any forbidden character: / , \ , < , > ,
* : , " , | , ? , *
* @param fileName
* @param versionSupportsForbiddenChars
* @return
*/
public static boolean isValidName(String fileName) {
public static boolean isValidName(String fileName, boolean versionSupportsForbiddenChars) {
boolean result = true;
Log_OC.d("FileUtils", "fileName =======" + fileName);
if (fileName.contains(PATH_SEPARATOR) ||
Log_OC.d(TAG, "fileName =======" + fileName);
if ( (versionSupportsForbiddenChars && fileName.contains(PATH_SEPARATOR)) ||
(!versionSupportsForbiddenChars && ( fileName.contains(PATH_SEPARATOR) ||
fileName.contains("\\") || fileName.contains("<") || fileName.contains(">") ||
fileName.contains(":") || fileName.contains("\"") || fileName.contains("|") ||
fileName.contains("?") || fileName.contains("*")) {
fileName.contains("?") || fileName.contains("*") ) ) ) {
result = false;
}
return result;
}
/**
* Validate the path to detect if contains any forbidden character: \ , < , > , : , " , | , ? , *
* Validate the path to detect if contains any forbidden character: \ , < , > , : , " , | ,
* ? , *
* @param path
* @return
*/
public static boolean isValidPath(String path) {
public static boolean isValidPath(String path, boolean versionSupportsForbidenChars) {
boolean result = true;
Log_OC.d("FileUtils", "path ....... " + path);
if (path.contains("\\") || path.contains("<") || path.contains(">") ||
Log_OC.d(TAG, "path ....... " + path);
if (!versionSupportsForbidenChars &&
(path.contains("\\") || path.contains("<") || path.contains(">") ||
path.contains(":") || path.contains("\"") || path.contains("|") ||
path.contains("?") || path.contains("*")) {
path.contains("?") || path.contains("*") ) ){
result = false;
}
return result;
}
}

View File

@ -39,6 +39,7 @@ 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.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
/**
@ -88,8 +89,12 @@ public class MoveRemoteFileOperation extends RemoteOperation {
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
OwnCloudVersion version = client.getOwnCloudVersion();
boolean versionWithForbiddenChars =
(version != null && version.isVersionWithForbiddenCharacters());
/// check parameters
if (!FileUtils.isValidPath(mTargetRemotePath)) {
if (!FileUtils.isValidPath(mTargetRemotePath, versionWithForbiddenChars)) {
return new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME);
}
@ -128,8 +133,10 @@ public class MoveRemoteFileOperation extends RemoteOperation {
/// for other errors that could be explicitly handled, check first:
/// http://www.webdav.org/specs/rfc4918.html#rfc.section.9.9.4
} else if (status == 400) {
result = new RemoteOperationResult(move.succeeded(),
move.getResponseBodyAsString(), status);
} else {
result = new RemoteOperationResult(
isSuccess(status), // move.succeeded()? trustful?
status,

View File

@ -25,6 +25,7 @@
package com.owncloud.android.lib.resources.files;
import java.io.Serializable;
import java.math.BigDecimal;
import android.os.Parcel;
import android.os.Parcelable;
@ -51,8 +52,8 @@ public class RemoteFile implements Parcelable, Serializable {
private String mPermissions;
private String mRemoteId;
private long mSize;
private long mQuotaUsedBytes;
private long mQuotaAvailableBytes;
private BigDecimal mQuotaUsedBytes;
private BigDecimal mQuotaAvailableBytes;
/**
* Getters and Setters
@ -130,11 +131,11 @@ public class RemoteFile implements Parcelable, Serializable {
mSize = size;
}
public void setQuotaUsedBytes (long quotaUsedBytes) {
public void setQuotaUsedBytes (BigDecimal quotaUsedBytes) {
mQuotaUsedBytes = quotaUsedBytes;
}
public void setQuotaAvailableBytes (long quotaAvailableBytes) {
public void setQuotaAvailableBytes (BigDecimal quotaAvailableBytes) {
mQuotaAvailableBytes = quotaAvailableBytes;
}
@ -184,8 +185,8 @@ public class RemoteFile implements Parcelable, Serializable {
mPermissions = null;
mRemoteId = null;
mSize = 0;
mQuotaUsedBytes = 0;
mQuotaAvailableBytes = 0;
mQuotaUsedBytes = null;
mQuotaAvailableBytes = null;
}
/**
@ -223,8 +224,8 @@ public class RemoteFile implements Parcelable, Serializable {
mPermissions= source.readString();
mRemoteId = source.readString();
mSize = source.readLong();
mQuotaUsedBytes = source.readLong();
mQuotaAvailableBytes = source.readLong();
mQuotaUsedBytes = (BigDecimal) source.readSerializable();
mQuotaAvailableBytes = (BigDecimal) source.readSerializable();
}
@Override
@ -243,8 +244,8 @@ public class RemoteFile implements Parcelable, Serializable {
dest.writeString(mPermissions);
dest.writeString(mRemoteId);
dest.writeLong(mSize);
dest.writeLong(mQuotaUsedBytes);
dest.writeLong(mQuotaAvailableBytes);
dest.writeSerializable(mQuotaUsedBytes);
dest.writeSerializable(mQuotaAvailableBytes);
}
}

View File

@ -34,6 +34,7 @@ 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;
/**
@ -89,16 +90,17 @@ public class RenameRemoteFileOperation extends RemoteOperation {
LocalMoveMethod move = null;
boolean noInvalidChars = FileUtils.isValidPath(mNewRemotePath);
OwnCloudVersion version = client.getOwnCloudVersion();
boolean versionWithForbiddenChars =
(version != null && version.isVersionWithForbiddenCharacters());
boolean noInvalidChars = FileUtils.isValidPath(mNewRemotePath, versionWithForbiddenChars);
if (noInvalidChars) {
try {
if (mNewName.equals(mOldName)) {
return new RemoteOperationResult(ResultCode.OK);
}
// check if a file with the new name already exists
if (client.existsFile(mNewRemotePath)) {
return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
@ -107,13 +109,21 @@ public class RenameRemoteFileOperation extends RemoteOperation {
move = new LocalMoveMethod( client.getWebdavUri() +
WebdavUtils.encodePath(mOldRemotePath),
client.getWebdavUri() + WebdavUtils.encodePath(mNewRemotePath));
int status = client.executeMethod(move, RENAME_READ_TIMEOUT, RENAME_CONNECTION_TIMEOUT);
int status = client.executeMethod(move, RENAME_READ_TIMEOUT,
RENAME_CONNECTION_TIMEOUT);
move.getResponseBodyAsString(); // exhaust response, although not interesting
result = new RemoteOperationResult(move.succeeded(), status, move.getResponseHeaders());
if (status == 400) {
result = new RemoteOperationResult(move.succeeded(),
move.getResponseBodyAsString(), status);
Log_OC.d(TAG, move.getResponseBodyAsString());
} else {
client.exhaustResponse(move.getResponseBodyAsStream());//exhaust response,
// although not interesting
result = new RemoteOperationResult(move.succeeded(), status,
move.getResponseHeaders());
Log_OC.i(TAG, "Rename " + mOldRemotePath + " to " + mNewRemotePath + ": " +
result.getLogMessage());
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Rename " + mOldRemotePath + " to " +
@ -124,6 +134,7 @@ public class RenameRemoteFileOperation extends RemoteOperation {
if (move != null)
move.releaseConnection();
}
} else {
result = new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME);
}

View File

@ -24,13 +24,14 @@
package com.owncloud.android.lib.resources.files;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.http.HttpStatus;
@ -40,9 +41,11 @@ import com.owncloud.android.lib.common.network.FileRequestEntity;
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.common.network.ProgressiveDataTransferer;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.InvalidCharacterExceptionParser;
import com.owncloud.android.lib.common.operations.OperationCancelledException;
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;
/**
* Remote operation performing the upload of a remote file to the ownCloud server.
@ -53,13 +56,19 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
public class UploadRemoteFileOperation extends RemoteOperation {
private static final String TAG = UploadRemoteFileOperation.class.getSimpleName();
protected static final String OC_TOTAL_LENGTH_HEADER = "OC-Total-Length";
protected static final String IF_MATCH_HEADER = "If-Match";
protected String mLocalPath;
protected String mRemotePath;
protected String mMimeType;
protected PutMethod mPutMethod = null;
protected boolean mForbiddenCharsInServer = false;
protected String mRequiredEtag = null;
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
protected final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
protected Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
protected RequestEntity mEntity = null;
@ -70,30 +79,38 @@ public class UploadRemoteFileOperation extends RemoteOperation {
mMimeType = mimeType;
}
public UploadRemoteFileOperation(String localPath, String remotePath, String mimeType, String requiredEtag) {
this(localPath, remotePath, mimeType);
mRequiredEtag = requiredEtag;
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
try {
// / perform the upload
synchronized (mCancellationRequested) {
mPutMethod = new PutMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath));
if (mCancellationRequested.get()) {
throw new OperationCancelledException();
// the operation was cancelled before getting it's turn to be executed in the queue of uploads
result = new RemoteOperationResult(new OperationCancelledException());
} else {
mPutMethod = new PutMethod(client.getWebdavUri() +
WebdavUtils.encodePath(mRemotePath));
}
}
// perform the upload
int status = uploadFile(client);
if (mForbiddenCharsInServer){
result = new RemoteOperationResult(
RemoteOperationResult.ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER);
} else {
result = new RemoteOperationResult(isSuccess(status), status,
(mPutMethod != null ? mPutMethod.getResponseHeaders() : null));
}
}
} catch (Exception e) {
// TODO something cleaner with cancellations
if (mCancellationRequested.get()) {
if (mPutMethod != null && mPutMethod.isAborted()) {
result = new RemoteOperationResult(new OperationCancelledException());
} else {
result = new RemoteOperationResult(e);
}
@ -106,8 +123,7 @@ public class UploadRemoteFileOperation extends RemoteOperation {
status == HttpStatus.SC_NO_CONTENT));
}
protected int uploadFile(OwnCloudClient client) throws HttpException, IOException,
OperationCancelledException {
protected int uploadFile(OwnCloudClient client) throws IOException {
int status = -1;
try {
File f = new File(mLocalPath);
@ -116,8 +132,26 @@ public class UploadRemoteFileOperation extends RemoteOperation {
((ProgressiveDataTransferer)mEntity)
.addDatatransferProgressListeners(mDataTransferListeners);
}
if (mRequiredEtag != null && mRequiredEtag.length() > 0) {
mPutMethod.addRequestHeader(IF_MATCH_HEADER, "\"" + mRequiredEtag + "\"");
}
mPutMethod.addRequestHeader(OC_TOTAL_LENGTH_HEADER, String.valueOf(f.length()));
mPutMethod.setRequestEntity(mEntity);
status = client.executeMethod(mPutMethod);
if (status == 400) {
InvalidCharacterExceptionParser xmlParser = new InvalidCharacterExceptionParser();
InputStream is = new ByteArrayInputStream(
mPutMethod.getResponseBodyAsString().getBytes());
try {
mForbiddenCharsInServer = xmlParser.parseXMLResponse(is);
} catch (Exception e) {
mForbiddenCharsInServer = false;
Log_OC.e(TAG, "Exception reading exception from server", e);
}
}
client.exhaustResponse(mPutMethod.getResponseBodyAsStream());
} finally {

View File

@ -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<OCShare> 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
@ -110,11 +118,15 @@ public class CreateRemoteShareOperation extends RemoteOperation {
post.addParameter(PARAM_PATH, mRemoteFilePath);
post.addParameter(PARAM_SHARE_TYPE, Integer.toString(mShareType.getValue()));
post.addParameter(PARAM_SHARE_WITH, mShareWith);
post.addParameter(PARAM_PUBLIC_UPLOAD, Boolean.toString(mPublicUpload));
if (mPublicUpload) {
post.addParameter(PARAM_PUBLIC_UPLOAD, Boolean.toString(true));
}
if (mPassword != null && mPassword.length() > 0) {
post.addParameter(PARAM_PASSWORD, mPassword);
}
if (OCShare.DEFAULT_PERMISSION != mPermissions) {
post.addParameter(PARAM_PERMISSIONS, Integer.toString(mPermissions));
}
post.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
@ -123,31 +135,21 @@ public class CreateRemoteShareOperation extends RemoteOperation {
if(isSuccess(status)) {
String response = post.getResponseBodyAsString();
result = new RemoteOperationResult(ResultCode.OK);
ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser(
new ShareXMLParser()
);
parser.setOneOrMoreSharesRequired(true);
parser.setOwnCloudVersion(client.getOwnCloudVersion());
parser.setServerBaseUri(client.getBaseUri());
result = parser.parse(response);
// 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<Object> sharesObjects = new ArrayList<Object>();
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);
} 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.getRemoteId()
);
result = getInfo.execute(client);
}
} else {

View File

@ -0,0 +1,100 @@
/* 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);
}
}

View File

@ -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, 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<Object> data = new ArrayList<Object>(); // 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);
}
}

View File

@ -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,18 +33,13 @@ 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;
/**
* 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();
@ -55,8 +48,6 @@ public class GetRemoteSharesForFileOperation extends RemoteOperation {
private static final String PARAM_RESHARES = "reshares";
private static final String PARAM_SUBFILES = "subfiles";
private ArrayList<OCShare> mShares; // List of shares for result, one share in this case
private String mRemoteFilePath;
private boolean mReshares;
private boolean mSubfiles;
@ -65,12 +56,14 @@ public class GetRemoteSharesForFileOperation extends RemoteOperation {
* Constructor
*
* @param remoteFilePath Path to file or folder
* @param reshares If set to false (default), only shares from the current user are returned
* If set to true, all shares from the given file are returned
* @param reshares If set to false (default), only shares owned by the current user are
* returned.
* If set to true, shares owned by any user from the given file are returned.
* @param subfiles If set to false (default), lists only the folder being shared
* If set to true, all shared files within the folder are returned.
*/
public GetRemoteSharesForFileOperation(String remoteFilePath, boolean reshares, boolean subfiles) {
public GetRemoteSharesForFileOperation(String remoteFilePath, boolean reshares,
boolean subfiles) {
mRemoteFilePath = remoteFilePath;
mReshares = reshares;
mSubfiles = subfiles;
@ -88,7 +81,7 @@ public class GetRemoteSharesForFileOperation extends RemoteOperation {
get = new GetMethod(client.getBaseUri() + ShareUtils.SHARING_API_PATH);
// Add Parameters to Get Method
get.setQueryString(new NameValuePair[] {
get.setQueryString(new NameValuePair[]{
new NameValuePair(PARAM_PATH, mRemoteFilePath),
new NameValuePair(PARAM_RESHARES, String.valueOf(mReshares)),
new NameValuePair(PARAM_SUBFILES, String.valueOf(mSubfiles))
@ -101,25 +94,16 @@ public class GetRemoteSharesForFileOperation extends RemoteOperation {
if(isSuccess(status)) {
String response = get.getResponseBodyAsString();
result = new RemoteOperationResult(ResultCode.OK);
// 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);
// 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<Object> sharesObjects = new ArrayList<Object>();
for (OCShare share: mShares) {
// Build the link
if (share.getToken().length() > 0) {
share.setShareLink(client.getBaseUri() + ShareUtils.SHARING_LINK_TOKEN + share.getToken());
}
sharesObjects.add(share);
}
result.setData(sharesObjects);
if (result.isSuccess()) {
Log_OC.d(TAG, "Got " + result.getData().size() + " shares");
}
} else {

View File

@ -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.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
*
* @author masensio
* Get the data from the server about ALL the known shares owned by the requester.
*
*/
@ -49,8 +43,6 @@ public class GetRemoteSharesOperation extends RemoteOperation {
private static final String TAG = GetRemoteSharesOperation.class.getSimpleName();
private ArrayList<OCShare> mShares; // List of shares for result
public GetRemoteSharesOperation() {
}
@ -68,23 +60,17 @@ 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<Object> sharesObjects = new ArrayList<Object>();
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());
}

View File

@ -46,6 +46,23 @@ public class OCShare implements Parcelable, Serializable {
private static final String TAG = OCShare.class.getSimpleName();
public static final int DEFAULT_PERMISSION = -1;
public static final int READ_PERMISSION_FLAG = 1;
public static final int UPDATE_PERMISSION_FLAG = 2;
public static final int CREATE_PERMISSION_FLAG = 4;
public static final int DELETE_PERMISSION_FLAG = 8;
public static final int SHARE_PERMISSION_FLAG = 16;
public static final int MAXIMUM_PERMISSIONS_FOR_FILE =
READ_PERMISSION_FLAG +
UPDATE_PERMISSION_FLAG +
SHARE_PERMISSION_FLAG
;
public static final int MAXIMUM_PERMISSIONS_FOR_FOLDER =
MAXIMUM_PERMISSIONS_FOR_FILE +
CREATE_PERMISSION_FLAG +
DELETE_PERMISSION_FLAG
;
private long mId;
private long mFileSource;
private long mItemSource;
@ -59,7 +76,7 @@ public class OCShare implements Parcelable, Serializable {
private String mSharedWithDisplayName;
private boolean mIsFolder;
private long mUserId;
private long mIdRemoteShared;
private long mRemoteId;
private String mShareLink;
public OCShare() {
@ -84,17 +101,17 @@ public class OCShare implements Parcelable, Serializable {
mFileSource = 0;
mItemSource = 0;
mShareType = ShareType.NO_SHARED;
mShareWith = null;
mPath = null;
mShareWith = "";
mPath = "";
mPermissions = -1;
mSharedDate = 0;
mExpirationDate = 0;
mToken = null;
mSharedWithDisplayName = null;
mToken = "";
mSharedWithDisplayName = "";
mIsFolder = false;
mUserId = -1;
mIdRemoteShared = -1;
mShareLink = null;
mRemoteId = -1;
mShareLink = "";
}
/// Getters and Setters
@ -136,7 +153,7 @@ public class OCShare implements Parcelable, Serializable {
}
public void setShareWith(String shareWith) {
this.mShareWith = shareWith;
this.mShareWith = (shareWith != null) ? shareWith : "";
}
public String getPath() {
@ -144,7 +161,7 @@ public class OCShare implements Parcelable, Serializable {
}
public void setPath(String path) {
this.mPath = path;
this.mPath = (path != null) ? path : "";
}
public int getPermissions() {
@ -176,7 +193,7 @@ public class OCShare implements Parcelable, Serializable {
}
public void setToken(String token) {
this.mToken = token;
this.mToken = (token != null) ? token : "";
}
public String getSharedWithDisplayName() {
@ -184,7 +201,7 @@ public class OCShare implements Parcelable, Serializable {
}
public void setSharedWithDisplayName(String sharedWithDisplayName) {
this.mSharedWithDisplayName = sharedWithDisplayName;
this.mSharedWithDisplayName = (sharedWithDisplayName != null) ? sharedWithDisplayName : "";
}
public boolean isFolder() {
@ -203,12 +220,12 @@ public class OCShare implements Parcelable, Serializable {
this.mUserId = userId;
}
public long getIdRemoteShared() {
return mIdRemoteShared;
public long getRemoteId() {
return mRemoteId;
}
public void setIdRemoteShared(long idRemoteShared) {
this.mIdRemoteShared = idRemoteShared;
public void setIdRemoteShared(long remoteId) {
this.mRemoteId = remoteId;
}
public String getShareLink() {
@ -216,7 +233,11 @@ public class OCShare implements Parcelable, Serializable {
}
public void setShareLink(String shareLink) {
this.mShareLink = shareLink;
this.mShareLink = (shareLink != null) ? shareLink : "";
}
public boolean isPasswordProtected() {
return ShareType.PUBLIC_LINK.equals(mShareType) && mShareWith.length() > 0;
}
/**
@ -262,7 +283,7 @@ public class OCShare implements Parcelable, Serializable {
mSharedWithDisplayName = source.readString();
mIsFolder = source.readInt() == 0;
mUserId = source.readLong();
mIdRemoteShared = source.readLong();
mRemoteId = source.readLong();
mShareLink = source.readString();
}
@ -288,7 +309,7 @@ public class OCShare implements Parcelable, Serializable {
dest.writeString(mSharedWithDisplayName);
dest.writeInt(mIsFolder ? 1 : 0);
dest.writeLong(mUserId);
dest.writeLong(mIdRemoteShared);
dest.writeLong(mRemoteId);
dest.writeString(mShareLink);
}

View File

@ -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());
}

View File

@ -0,0 +1,106 @@
/* 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;
/**
* Provides method to define a set of share permissions and calculate the appropiate
* int value representing it.
*/
public class SharePermissionsBuilder {
/** Set of permissions */
private int mPermissions = OCShare.READ_PERMISSION_FLAG; // READ is minimum permission
/**
* Sets or clears permission to reshare a file or folder.
*
* @param enabled 'True' to set, 'false' to clear.
* @return Instance to builder itself, to allow consecutive calls to setters
*/
public SharePermissionsBuilder setSharePermission(boolean enabled) {
updatePermission(OCShare.SHARE_PERMISSION_FLAG, enabled);
return this;
}
/**
* Sets or clears permission to update a folder or folder.
*
* @param enabled 'True' to set, 'false' to clear.
* @return Instance to builder itself, to allow consecutive calls to setters
*/
public SharePermissionsBuilder setUpdatePermission(boolean enabled) {
updatePermission(OCShare.UPDATE_PERMISSION_FLAG, enabled);
return this;
}
/**
* Sets or clears permission to create files in share folder.
*
* @param enabled 'True' to set, 'false' to clear.
* @return Instance to builder itself, to allow consecutive calls to setters
*/
public SharePermissionsBuilder setCreatePermission(boolean enabled) {
updatePermission(OCShare.CREATE_PERMISSION_FLAG, enabled);
return this;
}
/**
* Sets or clears permission to delete files in a shared folder.
*
* @param enabled 'True' to set, 'false' to clear.
* @return Instance to builder itself, to allow consecutive calls to setters
*/
public SharePermissionsBuilder setDeletePermission(boolean enabled) {
updatePermission(OCShare.DELETE_PERMISSION_FLAG, enabled);
return this;
}
/**
* Common code to update the value of the set of permissions.
*
* @param permissionsFlag Flag for the permission to update.
* @param enable 'True' to set, 'false' to clear.
*/
private void updatePermission(int permissionsFlag, boolean enable) {
if (enable) {
// add permission
mPermissions |= permissionsFlag;
} else {
// delete permission
mPermissions &= ~permissionsFlag;
}
}
/**
* 'Builds' the int value for the accumulated set of permissions.
*
* @return An int value representing the accumulated set of permissions.
*/
public int build() {
return mPermissions;
}
}

View File

@ -0,0 +1,145 @@
/* 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<Object> resultData = new ArrayList<Object>();
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<OCShare> 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.getShareLink().length() <= 0) &&
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;
}
}

View File

@ -24,6 +24,8 @@
package com.owncloud.android.lib.resources.shares;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
/**
* Contains Constants for Share Operation
*
@ -36,7 +38,16 @@ public class ShareUtils {
// OCS Route
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 = "/public.php?service=files&t=";
// String to build the link with the token of a share:
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 getSharingLinkPath(OwnCloudVersion version){
if (version!= null && version.isAfter8Version()){
return SHARING_LINK_PATH_AFTER_VERSION_8;
} else {
return SHARING_LINK_PATH_BEFORE_VERSION_8;
}
}
}

View File

@ -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 = 400;
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,19 +106,34 @@ 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;
}
/**
@ -126,7 +143,8 @@ public class ShareXMLParser {
* @throws XmlPullParserException
* @throws IOException
*/
public ArrayList<OCShare> parseXMLResponse(InputStream is) throws XmlPullParserException, IOException {
public ArrayList<OCShare> parseXMLResponse(InputStream is) throws XmlPullParserException,
IOException {
try {
// XMLPullParser
@ -151,7 +169,8 @@ public class ShareXMLParser {
* @throws XmlPullParserException
* @throws IOException
*/
private ArrayList<OCShare> readOCS (XmlPullParser parser) throws XmlPullParserException, IOException {
private ArrayList<OCShare> readOCS (XmlPullParser parser) throws XmlPullParserException,
IOException {
ArrayList<OCShare> shares = new ArrayList<OCShare>();
parser.require(XmlPullParser.START_TAG, ns , NODE_OCS);
while (parser.next() != XmlPullParser.END_TAG) {
@ -195,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);
}
@ -209,7 +231,8 @@ public class ShareXMLParser {
* @throws XmlPullParserException
* @throws IOException
*/
private ArrayList<OCShare> readData(XmlPullParser parser) throws XmlPullParserException, IOException {
private ArrayList<OCShare> readData(XmlPullParser parser) throws XmlPullParserException,
IOException {
ArrayList<OCShare> shares = new ArrayList<OCShare>();
OCShare share = null;
@ -259,7 +282,8 @@ public class ShareXMLParser {
* @throws XmlPullParserException
* @throws IOException
*/
private void readElement(XmlPullParser parser, ArrayList<OCShare> shares) throws XmlPullParserException, IOException {
private void readElement(XmlPullParser parser, ArrayList<OCShare> shares)
throws XmlPullParserException, IOException {
parser.require(XmlPullParser.START_TAG, ns, NODE_ELEMENT);
OCShare share = new OCShare();
@ -273,7 +297,8 @@ public class ShareXMLParser {
String name = parser.getName();
if (name.equalsIgnoreCase(NODE_ELEMENT)) {
// patch to work around servers responding with extra <element> surrounding all the shares on the same file before
// patch to work around servers responding with extra <element> surrounding all
// the shares on the same file before
// https://github.com/owncloud/core/issues/6992 was fixed
readElement(parser, shares);
@ -327,6 +352,11 @@ public class ShareXMLParser {
} else if (name.equalsIgnoreCase(NODE_SHARE_WITH_DISPLAY_NAME)) {
share.setSharedWithDisplayName(readNode(parser, NODE_SHARE_WITH_DISPLAY_NAME));
} else if (name.equalsIgnoreCase(NODE_URL)) {
share.setShareType(ShareType.PUBLIC_LINK);
String value = readNode(parser, NODE_URL);
share.setShareLink(value);
} else {
skip(parser);
}
@ -338,13 +368,12 @@ 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.getRemoteId() > -1);
}
private void fixPathForFolder(OCShare share) {
if (share.isFolder() && share.getPath() != null && share.getPath().length() > 0 && !share.getPath().endsWith(FileUtils.PATH_SEPARATOR)) {
if (share.isFolder() && share.getPath() != null && share.getPath().length() > 0 &&
!share.getPath().endsWith(FileUtils.PATH_SEPARATOR)) {
share.setPath(share.getPath() + FileUtils.PATH_SEPARATOR);
}
}
@ -357,7 +386,8 @@ public class ShareXMLParser {
* @throws XmlPullParserException
* @throws IOException
*/
private String readNode (XmlPullParser parser, String node) throws XmlPullParserException, IOException{
private String readNode (XmlPullParser parser, String node) throws XmlPullParserException,
IOException{
parser.require(XmlPullParser.START_TAG, ns, node);
String value = readText(parser);
//Log_OC.d(TAG, "node= " + node + ", value= " + value);

View File

@ -0,0 +1,215 @@
/* 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 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 org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.http.HttpStatus;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
/**
* Updates parameters of an existing Share resource, known its remote ID.
*
* Allow updating several parameters, triggering a request to the server per parameter.
*/
public class UpdateRemoteShareOperation extends RemoteOperation {
private static final String TAG = GetRemoteShareOperation.class.getSimpleName();
private static final String PARAM_PASSWORD = "password";
private static final String PARAM_EXPIRATION_DATE = "expireDate";
private static final String PARAM_PERMISSIONS = "permissions";
private static final String FORMAT_EXPIRATION_DATE = "yyyy-MM-dd";
private static final String ENTITY_CONTENT_TYPE = "application/x-www-form-urlencoded";
private static final String ENTITY_CHARSET = "UTF-8";
/** Identifier of the share to update */
private long mRemoteId;
/** Password to set for the public link */
private String mPassword;
/** Expiration date to set for the public link */
private long mExpirationDateInMillis;
/** Access permissions for the file bound to the share */
private int mPermissions;
/**
* Constructor. No update is initialized by default, need to be applied with setters below.
*
* @param remoteId Identifier of the share to update.
*/
public UpdateRemoteShareOperation(long remoteId) {
mRemoteId = remoteId;
mPassword = null; // no update
mExpirationDateInMillis = 0; // no update
}
/**
* Set password to update in Share resource.
*
* @param password Password to set to the target share.
* Empty string clears the current password.
* Null results in no update applied to the password.
*/
public void setPassword(String password) {
mPassword = password;
}
/**
* Set expiration date to update in Share resource.
*
* @param expirationDateInMillis Expiration date to set to the target share.
* A negative value clears the current expiration date.
* Zero value (start-of-epoch) results in no update done on
* the expiration date.
*/
public void setExpirationDate(long expirationDateInMillis) {
mExpirationDateInMillis = expirationDateInMillis;
}
/**
* Set permissions to update in Share resource.
*
* @param permissions Permissions date to set to the target share.
* Values <= 0 result in no update applied to the permissions.
*/
public void setPermissions(int permissions) {
mPermissions = permissions;
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
int status = -1;
/// prepare array of parameters to update
List<Pair<String, String>> parametersToUpdate = new ArrayList<Pair<String, String>>();
if (mPassword != null) {
parametersToUpdate.add(new Pair<String, String>(PARAM_PASSWORD, mPassword));
}
if (mExpirationDateInMillis < 0) {
// clear expiration date
parametersToUpdate.add(new Pair(PARAM_EXPIRATION_DATE, ""));
} else if (mExpirationDateInMillis > 0) {
// set expiration date
DateFormat dateFormat = new SimpleDateFormat(FORMAT_EXPIRATION_DATE);
Calendar expirationDate = Calendar.getInstance();
expirationDate.setTimeInMillis(mExpirationDateInMillis);
String formattedExpirationDate = dateFormat.format(expirationDate.getTime());
parametersToUpdate.add(new Pair(PARAM_EXPIRATION_DATE, formattedExpirationDate));
} // else, ignore - no update
if (mPermissions > 0) {
// set permissions
parametersToUpdate.add(new Pair(PARAM_PERMISSIONS, Integer.toString(mPermissions)));
}
/* TODO complete rest of parameters
if (mPublicUpload != null) {
parametersToUpdate.add(new Pair("publicUpload", mPublicUpload.toString());
}
*/
/// perform required PUT requests
PutMethod put = null;
String uriString = null;
try{
Uri requestUri = client.getBaseUri();
Uri.Builder uriBuilder = requestUri.buildUpon();
uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH.substring(1));
uriBuilder.appendEncodedPath(Long.toString(mRemoteId));
uriString = uriBuilder.build().toString();
for (Pair<String, String> parameter : parametersToUpdate) {
if (put != null) {
put.releaseConnection();
}
put = new PutMethod(uriString);
put.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
put.setRequestEntity(new StringRequestEntity(
parameter.first + "=" + parameter.second,
ENTITY_CONTENT_TYPE,
ENTITY_CHARSET
));
status = client.executeMethod(put);
if (status == HttpStatus.SC_OK) {
String response = put.getResponseBodyAsString();
// Parse xml response
ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser(
new ShareXMLParser()
);
parser.setOwnCloudVersion(client.getOwnCloudVersion());
parser.setServerBaseUri(client.getBaseUri());
result = parser.parse(response);
} else {
result = new RemoteOperationResult(false, status, put.getResponseHeaders());
}
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Exception while updating remote share ", e);
if (put != null) {
put.releaseConnection();
}
} finally {
if (put != null) {
put.releaseConnection();
}
}
return result;
}
}

View File

@ -0,0 +1,83 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2015 ownCloud Inc.
* @author masensio
*
* 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.status;
/**
* Enum for Boolean Type in OCCapability parameters, with values:
* -1 - Unknown
* 0 - False
* 1 - True
*/
public enum CapabilityBooleanType {
UNKNOWN (-1),
FALSE (0),
TRUE (1);
private int value;
CapabilityBooleanType(int value)
{
this.value = value;
}
public int getValue() {
return value;
}
public static CapabilityBooleanType fromValue(int value)
{
switch (value)
{
case -1:
return UNKNOWN;
case 0:
return FALSE;
case 1:
return TRUE;
}
return null;
}
public static CapabilityBooleanType fromBooleanValue(boolean boolValue){
if (boolValue){
return TRUE;
} else {
return FALSE;
}
}
public boolean isUnknown(){
return getValue() == -1;
}
public boolean isFalse(){
return getValue() == 0;
}
public boolean isTrue(){
return getValue() == 1;
}
};

View File

@ -0,0 +1,281 @@
/* ownCloud Android Library is available under MIT license
* @author masensio
* 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.status;
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.JSONObject;
import java.util.ArrayList;
/**
* Get the Capabilities from the server
*
* Save in Result.getData in a OCCapability object
*/
public class GetRemoteCapabilitiesOperation extends RemoteOperation {
private static final String TAG = GetRemoteCapabilitiesOperation.class.getSimpleName();
// OCS Routes
private static final String OCS_ROUTE = "ocs/v1.php/cloud/capabilities";
// Arguments - names
private static final String PARAM_FORMAT = "format";
// Arguments - constant values
private static final String VALUE_FORMAT = "json";
// JSON Node names
private static final String NODE_OCS = "ocs";
private static final String NODE_META = "meta";
private static final String NODE_DATA = "data";
private static final String NODE_VERSION = "version";
private static final String NODE_CAPABILITIES = "capabilities";
private static final String NODE_CORE = "core";
private static final String NODE_FILES_SHARING = "files_sharing";
private static final String NODE_PUBLIC = "public";
private static final String NODE_PASSWORD = "password";
private static final String NODE_EXPIRE_DATE = "expire_date";
private static final String NODE_USER = "user";
private static final String NODE_FEDERATION = "federation";
private static final String NODE_FILES = "files";
private static final String PROPERTY_STATUS = "status";
private static final String PROPERTY_STATUSCODE = "statuscode";
private static final String PROPERTY_MESSAGE = "message";
private static final String PROPERTY_POLLINTERVAL = "pollinterval";
private static final String PROPERTY_MAJOR = "major";
private static final String PROPERTY_MINOR = "minor";
private static final String PROPERTY_MICRO = "micro";
private static final String PROPERTY_STRING = "string";
private static final String PROPERTY_EDITION = "edition";
private static final String PROPERTY_API_ENABLED = "api_enabled";
private static final String PROPERTY_ENABLED = "enabled";
private static final String PROPERTY_ENFORCED = "enforced";
private static final String PROPERTY_DAYS = "days";
private static final String PROPERTY_SEND_MAIL = "send_mail";
private static final String PROPERTY_UPLOAD = "upload";
private static final String PROPERTY_RESHARING = "resharing";
private static final String PROPERTY_OUTGOING = "outgoing";
private static final String PROPERTY_INCOMING = "incoming";
private static final String PROPERTY_BIGFILECHUNKING = "bigfilechunking";
private static final String PROPERTY_UNDELETE = "undelete";
private static final String PROPERTY_VERSIONING = "versioning";
/**
* Constructor
*
*/
public GetRemoteCapabilitiesOperation() {
}
@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); // avoid starting "/" in this method
uriBuilder.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT);
// 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 respMeta = respOCS.getJSONObject(NODE_META);
JSONObject respData = respOCS.getJSONObject(NODE_DATA);
// Read meta
boolean statusProp = respMeta.getString(PROPERTY_STATUS).equalsIgnoreCase("ok");
int statuscode = respMeta.getInt(PROPERTY_STATUSCODE);
String message = respMeta.getString(PROPERTY_MESSAGE);
if (statusProp) {
ArrayList<Object> data = new ArrayList<Object>(); // For result data
OCCapability capability = new OCCapability();
// Add Version
if (respData.has(NODE_VERSION)) {
JSONObject respVersion = respData.getJSONObject(NODE_VERSION);
capability.setVersionMayor(respVersion.getInt(PROPERTY_MAJOR));
capability.setVersionMinor(respVersion.getInt(PROPERTY_MINOR));
capability.setVersionMicro(respVersion.getInt(PROPERTY_MICRO));
capability.setVersionString(respVersion.getString(PROPERTY_STRING));
capability.setVersionEdition(respVersion.getString(PROPERTY_EDITION));
Log_OC.d(TAG, "*** Added " + NODE_VERSION);
}
// Capabilities Object
if (respData.has(NODE_CAPABILITIES)) {
JSONObject respCapabilities = respData.getJSONObject(NODE_CAPABILITIES);
// Add Core: pollinterval
if (respCapabilities.has(NODE_CORE)) {
JSONObject respCore = respCapabilities.getJSONObject(NODE_CORE);
capability.setCorePollinterval(respCore.getInt(PROPERTY_POLLINTERVAL));
Log_OC.d(TAG, "*** Added " + NODE_CORE);
}
// Add files_sharing: public, user, resharing
if (respCapabilities.has(NODE_FILES_SHARING)) {
JSONObject respFilesSharing = respCapabilities.getJSONObject(NODE_FILES_SHARING);
if (respFilesSharing.has(PROPERTY_API_ENABLED)) {
capability.setFilesSharingApiEnabled(CapabilityBooleanType.fromBooleanValue(
respFilesSharing.getBoolean(PROPERTY_API_ENABLED)));
}
if (respFilesSharing.has(NODE_PUBLIC)) {
JSONObject respPublic = respFilesSharing.getJSONObject(NODE_PUBLIC);
capability.setFilesSharingPublicEnabled(CapabilityBooleanType.fromBooleanValue(
respPublic.getBoolean(PROPERTY_ENABLED)));
if(respPublic.has(NODE_PASSWORD)) {
capability.setFilesSharingPublicPasswordEnforced(
CapabilityBooleanType.fromBooleanValue(
respPublic.getJSONObject(NODE_PASSWORD).getBoolean(PROPERTY_ENFORCED)));
}
if(respPublic.has(NODE_EXPIRE_DATE)){
JSONObject respExpireDate = respPublic.getJSONObject(NODE_EXPIRE_DATE);
capability.setFilesSharingPublicExpireDateEnabled(
CapabilityBooleanType.fromBooleanValue(
respExpireDate.getBoolean(PROPERTY_ENABLED)));
if (respExpireDate.has(PROPERTY_DAYS)) {
capability.setFilesSharingPublicExpireDateDays(
respExpireDate.getInt(PROPERTY_DAYS));
}
if (respExpireDate.has(PROPERTY_ENFORCED)) {
capability.setFilesSharingPublicExpireDateEnforced(
CapabilityBooleanType.fromBooleanValue(
respExpireDate.getBoolean(PROPERTY_ENFORCED)));
}
}
if (respPublic.has(PROPERTY_UPLOAD)){
capability.setFilesSharingPublicUpload(CapabilityBooleanType.fromBooleanValue(
respPublic.getBoolean(PROPERTY_UPLOAD)));
}
}
if (respFilesSharing.has(NODE_USER)) {
JSONObject respUser = respFilesSharing.getJSONObject(NODE_USER);
capability.setFilesSharingUserSendMail(CapabilityBooleanType.fromBooleanValue(
respUser.getBoolean(PROPERTY_SEND_MAIL)));
}
capability.setFilesSharingResharing(CapabilityBooleanType.fromBooleanValue(
respFilesSharing.getBoolean(PROPERTY_RESHARING)));
if (respFilesSharing.has(NODE_FEDERATION)) {
JSONObject respFederation = respFilesSharing.getJSONObject(NODE_FEDERATION);
capability.setFilesSharingFederationOutgoing(
CapabilityBooleanType.fromBooleanValue(respFederation.getBoolean(PROPERTY_OUTGOING)));
capability.setFilesSharingFederationIncoming(CapabilityBooleanType.fromBooleanValue(
respFederation.getBoolean(PROPERTY_INCOMING)));
}
Log_OC.d(TAG, "*** Added " + NODE_FILES_SHARING);
}
if (respCapabilities.has(NODE_FILES)) {
JSONObject respFiles = respCapabilities.getJSONObject(NODE_FILES);
// Add files
capability.setFilesBigFileChuncking(CapabilityBooleanType.fromBooleanValue(
respFiles.getBoolean(PROPERTY_BIGFILECHUNKING)));
if (respFiles.has(PROPERTY_UNDELETE)) {
capability.setFilesUndelete(CapabilityBooleanType.fromBooleanValue(
respFiles.getBoolean(PROPERTY_UNDELETE)));
}
capability.setFilesVersioning(CapabilityBooleanType.fromBooleanValue(
respFiles.getBoolean(PROPERTY_VERSIONING)));
Log_OC.d(TAG, "*** Added " + NODE_FILES);
}
}
// Result
data.add(capability);
result = new RemoteOperationResult(true, status, get.getResponseHeaders());
result.setData(data);
Log_OC.d(TAG, "*** Get Capabilities completed ");
} else {
result = new RemoteOperationResult(statusProp, statuscode, null);
Log_OC.e(TAG, "Failed response while getting capabilities from the server ");
Log_OC.e(TAG, "*** status: " + statusProp + "; message: " + message);
}
} else {
result = new RemoteOperationResult(false, status, get.getResponseHeaders());
String response = get.getResponseBodyAsString();
Log_OC.e(TAG, "Failed response while getting capabilities 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 capabilities", e);
} finally {
if (get != null) {
get.releaseConnection();
}
}
return result;
}
private boolean isSuccess(int status) {
return (status == HttpStatus.SC_OK);
}
}

View File

@ -103,9 +103,7 @@ public class GetRemoteStatusOperation extends RemoteOperation {
);
get.releaseConnection();
get = new GetMethod(redirectedLocation);
status = client.executeMethod(
get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT
);
status = client.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT);
mLatestResult = new RemoteOperationResult(
(status == HttpStatus.SC_OK),
status,

View File

@ -0,0 +1,291 @@
/* ownCloud Android Library is available under MIT license
* @author masensio
* 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.status;
/**
* Contains data of the Capabilities for an account, from the Capabilities API
*/
public class OCCapability {
private static final String TAG = OCCapability.class.getSimpleName();
private long mId;
private String mAccountName;
// Server version
private int mVersionMayor;
private int mVersionMinor;
private int mVersionMicro;
private String mVersionString;
private String mVersionEdition;
// Core PollInterval
private int mCorePollinterval;
// Files Sharing
private CapabilityBooleanType mFilesSharingApiEnabled;
private CapabilityBooleanType mFilesSharingPublicEnabled;
private CapabilityBooleanType mFilesSharingPublicPasswordEnforced;
private CapabilityBooleanType mFilesSharingPublicExpireDateEnabled;
private int mFilesSharingPublicExpireDateDays;
private CapabilityBooleanType mFilesSharingPublicExpireDateEnforced;
private CapabilityBooleanType mFilesSharingPublicSendMail;
private CapabilityBooleanType mFilesSharingPublicUpload;
private CapabilityBooleanType mFilesSharingUserSendMail;
private CapabilityBooleanType mFilesSharingResharing;
private CapabilityBooleanType mFilesSharingFederationOutgoing;
private CapabilityBooleanType mFilesSharingFederationIncoming;
// Files
private CapabilityBooleanType mFilesBigFileChuncking;
private CapabilityBooleanType mFilesUndelete;
private CapabilityBooleanType mFilesVersioning;
public OCCapability(){
mId = 0;
mAccountName = "";
mVersionMayor = 0;
mVersionMinor = 0;
mVersionMicro = 0;
mVersionString = "";
mVersionString = "";
mCorePollinterval = 0;
mFilesSharingApiEnabled = CapabilityBooleanType.UNKNOWN;
mFilesSharingPublicEnabled = CapabilityBooleanType.UNKNOWN;
mFilesSharingPublicPasswordEnforced = CapabilityBooleanType.UNKNOWN;
mFilesSharingPublicExpireDateEnabled = CapabilityBooleanType.UNKNOWN;
mFilesSharingPublicExpireDateDays = 0;
mFilesSharingPublicExpireDateEnforced = CapabilityBooleanType.UNKNOWN;
mFilesSharingPublicSendMail = CapabilityBooleanType.UNKNOWN;
mFilesSharingPublicUpload = CapabilityBooleanType.UNKNOWN;
mFilesSharingUserSendMail = CapabilityBooleanType.UNKNOWN;
mFilesSharingResharing = CapabilityBooleanType.UNKNOWN;
mFilesSharingFederationOutgoing = CapabilityBooleanType.UNKNOWN;
mFilesSharingFederationIncoming = CapabilityBooleanType.UNKNOWN;
mFilesBigFileChuncking = CapabilityBooleanType.UNKNOWN;
mFilesUndelete = CapabilityBooleanType.UNKNOWN;
mFilesVersioning = CapabilityBooleanType.UNKNOWN;
}
// Getters and Setters
public String getAccountName() {
return mAccountName;
}
public void setAccountName(String accountName) {
this.mAccountName = accountName;
}
public long getId() {
return mId;
}
public void setId(long id) {
this.mId = id;
}
public int getVersionMayor() {
return mVersionMayor;
}
public void setVersionMayor(int versionMayor) {
this.mVersionMayor = versionMayor;
}
public int getVersionMinor() {
return mVersionMinor;
}
public void setVersionMinor(int versionMinor) {
this.mVersionMinor = versionMinor;
}
public int getVersionMicro() {
return mVersionMicro;
}
public void setVersionMicro(int versionMicro) {
this.mVersionMicro = versionMicro;
}
public String getVersionString() {
return mVersionString;
}
public void setVersionString(String versionString) {
this.mVersionString = versionString;
}
public String getVersionEdition() {
return mVersionEdition;
}
public void setVersionEdition(String versionEdition) {
this.mVersionEdition = versionEdition;
}
public int getCorePollinterval() {
return mCorePollinterval;
}
public void setCorePollinterval(int corePollinterval) {
this.mCorePollinterval = corePollinterval;
}
public CapabilityBooleanType getFilesSharingApiEnabled() {
return mFilesSharingApiEnabled;
}
public void setFilesSharingApiEnabled(CapabilityBooleanType filesSharingApiEnabled) {
this.mFilesSharingApiEnabled = filesSharingApiEnabled;
}
public CapabilityBooleanType getFilesSharingPublicEnabled() {
return mFilesSharingPublicEnabled;
}
public void setFilesSharingPublicEnabled(CapabilityBooleanType filesSharingPublicEnabled) {
this.mFilesSharingPublicEnabled = filesSharingPublicEnabled;
}
public CapabilityBooleanType getFilesSharingPublicPasswordEnforced() {
return mFilesSharingPublicPasswordEnforced;
}
public void setFilesSharingPublicPasswordEnforced(CapabilityBooleanType filesSharingPublicPasswordEnforced) {
this.mFilesSharingPublicPasswordEnforced = filesSharingPublicPasswordEnforced;
}
public CapabilityBooleanType getFilesSharingPublicExpireDateEnabled() {
return mFilesSharingPublicExpireDateEnabled;
}
public void setFilesSharingPublicExpireDateEnabled(CapabilityBooleanType filesSharingPublicExpireDateEnabled) {
this.mFilesSharingPublicExpireDateEnabled = filesSharingPublicExpireDateEnabled;
}
public int getFilesSharingPublicExpireDateDays() {
return mFilesSharingPublicExpireDateDays;
}
public void setFilesSharingPublicExpireDateDays(int filesSharingPublicExpireDateDays) {
this.mFilesSharingPublicExpireDateDays = filesSharingPublicExpireDateDays;
}
public CapabilityBooleanType getFilesSharingPublicExpireDateEnforced() {
return mFilesSharingPublicExpireDateEnforced;
}
public void setFilesSharingPublicExpireDateEnforced(CapabilityBooleanType filesSharingPublicExpireDateEnforced) {
this.mFilesSharingPublicExpireDateEnforced = filesSharingPublicExpireDateEnforced;
}
public CapabilityBooleanType getFilesSharingPublicSendMail() {
return mFilesSharingPublicSendMail;
}
public void setFilesSharingPublicSendMail(CapabilityBooleanType filesSharingPublicSendMail) {
this.mFilesSharingPublicSendMail = filesSharingPublicSendMail;
}
public CapabilityBooleanType getFilesSharingPublicUpload() {
return mFilesSharingPublicUpload;
}
public void setFilesSharingPublicUpload(CapabilityBooleanType filesSharingPublicUpload) {
this.mFilesSharingPublicUpload = filesSharingPublicUpload;
}
public CapabilityBooleanType getFilesSharingUserSendMail() {
return mFilesSharingUserSendMail;
}
public void setFilesSharingUserSendMail(CapabilityBooleanType filesSharingUserSendMail) {
this.mFilesSharingUserSendMail = filesSharingUserSendMail;
}
public CapabilityBooleanType getFilesSharingResharing() {
return mFilesSharingResharing;
}
public void setFilesSharingResharing(CapabilityBooleanType filesSharingResharing) {
this.mFilesSharingResharing = filesSharingResharing;
}
public CapabilityBooleanType getFilesSharingFederationOutgoing() {
return mFilesSharingFederationOutgoing;
}
public void setFilesSharingFederationOutgoing(CapabilityBooleanType filesSharingFederationOutgoing) {
this.mFilesSharingFederationOutgoing = filesSharingFederationOutgoing;
}
public CapabilityBooleanType getFilesSharingFederationIncoming() {
return mFilesSharingFederationIncoming;
}
public void setFilesSharingFederationIncoming(CapabilityBooleanType filesSharingFederationIncoming) {
this.mFilesSharingFederationIncoming = filesSharingFederationIncoming;
}
public CapabilityBooleanType getFilesBigFileChuncking() {
return mFilesBigFileChuncking;
}
public void setFilesBigFileChuncking(CapabilityBooleanType filesBigFileChuncking) {
this.mFilesBigFileChuncking = filesBigFileChuncking;
}
public CapabilityBooleanType getFilesUndelete() {
return mFilesUndelete;
}
public void setFilesUndelete(CapabilityBooleanType filesUndelete) {
this.mFilesUndelete = filesUndelete;
}
public CapabilityBooleanType getFilesVersioning() {
return mFilesVersioning;
}
public void setFilesVersioning(CapabilityBooleanType filesVersioning) {
this.mFilesVersioning = filesVersioning;
}
}

View File

@ -39,6 +39,16 @@ public class OwnCloudVersion implements Comparable<OwnCloudVersion> {
public static final int MINIMUM_VERSION_FOR_SHARING_API = 0x05001B00; // 5.0.27
public static final int MINIMUM_VERSION_WITH_FORBIDDEN_CHARS = 0x08010000; // 8.1
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
public static final int MINIMUM_VERSION_CAPABILITIES_API = 0x08010000; // 8.1
private static final int MAX_DOTS = 3;
// format is in version
@ -121,5 +131,25 @@ public class OwnCloudVersion implements Comparable<OwnCloudVersion> {
return (mVersion >= MINIMUM_VERSION_FOR_SHARING_API);
}
public boolean isVersionWithForbiddenCharacters() {
return (mVersion >= MINIMUM_VERSION_WITH_FORBIDDEN_CHARS);
}
public boolean supportsRemoteThumbnails() {
return (mVersion >= MINIMUM_SERVER_VERSION_FOR_REMOTE_THUMBNAILS);
}
public boolean isAfter8Version(){
return (mVersion >= VERSION_8);
}
public boolean isSearchUsersSupported() {
return (mVersion >= MINIMUM_VERSION_FOR_SEARCHING_USERS);
}
public boolean isVersionWithCapabilitiesAPI(){
return (mVersion>= MINIMUM_VERSION_CAPABILITIES_API);
}
}

View File

@ -12,7 +12,7 @@ dependencies {
android {
compileSdkVersion 19
buildToolsVersion "20.0.0"
buildToolsVersion "22.0.1"
sourceSets {
main {
@ -45,4 +45,9 @@ android {
packagingOptions {
exclude 'META-INF/LICENSE.txt'
}
android {
lintOptions {
abortOnError false
}
}
}

View File

@ -0,0 +1,458 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 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 android.content.Context;
import android.net.Uri;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
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.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.resources.files.CopyRemoteFileOperation;
import com.owncloud.android.lib.test_project.R;
import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory;
import com.owncloud.android.lib.test_project.TestActivity;
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 java.io.File;
import java.security.GeneralSecurityException;
//import android.test.AndroidTestCase;
/**
* Class to test CopyRemoteFileOperation
* <p/>
* With this TestCase we are experimenting a bit to improve the test suite design, in two aspects:
* <p/>
* - 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.
* <p/>
* - 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.
*
* @author David A. Velasco
*/
//public class CopyFileTest extends AndroidTestCase {
public class CopyFileTest extends ActivityInstrumentationTestCase2<TestActivity> {
private static final String LOG_TAG = CopyFileTest.class.getCanonicalName();
/// Paths to files and folders in fixture
private static final String SRC_BASE_FOLDER = "/src/";
private static final String TARGET_BASE_FOLDER = "/target/";
private static final String NO_FILE = "nofile.txt";
private static final String FILE1 = "file1.txt";
private static final String FILE2 = "file2.txt";
private static final String FILE3 = "file3.txt";
private static final String FILE4 = "file4.txt";
private static final String FILE5 = "file5.txt";
private static final String FILE6 = "file6.txt";
private static final String FILE7 = "file7.txt";
private static final String EMPTY = "empty/";
private static final String NO_FOLDER = "nofolder/";
private static final String FOLDER1 = "folder1/";
private static final String FOLDER2 = "folder2/";
private static final String FOLDER3 = "folder3/";
private static final String FOLDER4 = "folder4/";
private static final String SRC_PATH_TO_FILE_1 = SRC_BASE_FOLDER + FILE1;
private static final String TARGET_PATH_TO_FILE_1 = TARGET_BASE_FOLDER + FILE1;
private static final String SRC_PATH_TO_FILE_2 = SRC_BASE_FOLDER + FILE2;
private static final String TARGET_PATH_TO_FILE_2_RENAMED =
TARGET_BASE_FOLDER + "renamed_" + FILE2;
private static final String SRC_PATH_TO_FILE_3 = SRC_BASE_FOLDER + FILE3;
private static final String SRC_PATH_TO_FILE_3_RENAMED = SRC_BASE_FOLDER + "renamed_" + FILE3;
private static final String SRC_PATH_TO_FILE_4 = SRC_BASE_FOLDER + FILE4;
private static final String SRC_PATH_TO_FILE_5 = SRC_BASE_FOLDER + FILE5;
private static final String SRC_PATH_TO_FILE_6 = SRC_BASE_FOLDER + FILE6;
private static final String SRC_PATH_TO_FILE_7 = SRC_BASE_FOLDER + FILE7;
private static final String SRC_PATH_TO_NON_EXISTENT_FILE = SRC_BASE_FOLDER + NO_FILE;
private static final String SRC_PATH_TO_EMPTY_FOLDER = SRC_BASE_FOLDER + EMPTY;
private static final String TARGET_PATH_TO_EMPTY_FOLDER = TARGET_BASE_FOLDER + EMPTY;
private static final String SRC_PATH_TO_FULL_FOLDER_1 = SRC_BASE_FOLDER + FOLDER1;
private static final String TARGET_PATH_TO_FULL_FOLDER_1 = TARGET_BASE_FOLDER + FOLDER1;
private static final String SRC_PATH_TO_FULL_FOLDER_2 = SRC_BASE_FOLDER + FOLDER2;
private static final String TARGET_PATH_TO_FULL_FOLDER_2_RENAMED =
TARGET_BASE_FOLDER + "renamed_" + FOLDER2;
private static final String SRC_PATH_TO_FULL_FOLDER_3 = SRC_BASE_FOLDER + FOLDER3;
private static final String SRC_PATH_TO_FULL_FOLDER_4 = SRC_BASE_FOLDER + FOLDER4;
private static final String SRC_PATH_TO_FULL_FOLDER_3_RENAMED =
SRC_BASE_FOLDER + "renamed_" + FOLDER3;
private static final String TARGET_PATH_RENAMED_WITH_INVALID_CHARS =
SRC_BASE_FOLDER + "renamed:??_" + FILE6;
private static final String TARGET_PATH_TO_ALREADY_EXISTENT_EMPTY_FOLDER_4 = TARGET_BASE_FOLDER
+ FOLDER4;
private static final String TARGET_PATH_TO_NON_EXISTENT_FILE = TARGET_BASE_FOLDER + NO_FILE;
private static final String TARGET_PATH_TO_FILE_5_INTO_NON_EXISTENT_FOLDER =
TARGET_BASE_FOLDER + NO_FOLDER + FILE5;
private static final String TARGET_PATH_TO_ALREADY_EXISTENT_FILE_7 = TARGET_BASE_FOLDER + FILE7;
private static final String[] FOLDERS_IN_FIXTURE = {
SRC_PATH_TO_EMPTY_FOLDER,
SRC_PATH_TO_FULL_FOLDER_1,
SRC_PATH_TO_FULL_FOLDER_1 + FOLDER1,
SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2,
SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FOLDER1,
SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FOLDER2,
SRC_PATH_TO_FULL_FOLDER_2,
SRC_PATH_TO_FULL_FOLDER_2 + FOLDER1,
SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2,
SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2 + FOLDER1,
SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2 + FOLDER2,
SRC_PATH_TO_FULL_FOLDER_3,
SRC_PATH_TO_FULL_FOLDER_3 + FOLDER1,
SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2,
SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER1,
SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER2,
SRC_PATH_TO_FULL_FOLDER_4,
SRC_PATH_TO_FULL_FOLDER_4 + FOLDER1,
SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2,
SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2 + FOLDER1,
SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2 + FOLDER2,
TARGET_BASE_FOLDER,
TARGET_PATH_TO_ALREADY_EXISTENT_EMPTY_FOLDER_4
};
private static final String[] FILES_IN_FIXTURE = {
SRC_PATH_TO_FILE_1,
SRC_PATH_TO_FILE_2,
SRC_PATH_TO_FILE_3,
SRC_PATH_TO_FILE_4,
SRC_PATH_TO_FILE_5,
SRC_PATH_TO_FULL_FOLDER_1 + FILE1,
SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FILE1,
SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FILE2,
SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FOLDER2 + FILE2,
SRC_PATH_TO_FULL_FOLDER_2 + FILE1,
SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2 + FILE1,
SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2 + FILE2,
SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2 + FOLDER2 + FILE2,
SRC_PATH_TO_FULL_FOLDER_3 + FILE1,
SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FILE1,
SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FILE2,
SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER2 + FILE2,
SRC_PATH_TO_FULL_FOLDER_4 + FILE1,
SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2 + FILE1,
SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2 + FILE2,
SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2 + FOLDER2 + FILE2,
TARGET_PATH_TO_ALREADY_EXISTENT_FILE_7
};
String mServerUri, mUser, mPass;
OwnCloudClient mClient = null;
public CopyFileTest() {
super(TestActivity.class);
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...");
RemoteOperationResult result = null;
for (String folderPath : FOLDERS_IN_FIXTURE) {
result = TestActivity.createFolder(folderPath, true, mClient);
if (!result.isSuccess()) {
Utils.logAndThrow(LOG_TAG, result);
}
}
File txtFile = TestActivity.extractAsset(
TestActivity.ASSETS__TEXT_FILE_NAME, getContext()
);
for (String filePath : FILES_IN_FIXTURE) {
result = TestActivity.uploadFile(
txtFile.getAbsolutePath(), filePath, "txt/plain", mClient
);
if (!result.isSuccess()) {
Utils.logAndThrow(LOG_TAG, result);
}
}
Log.v(LOG_TAG, "Remote fixture created.");
}
/**
* Test copy folder
*/
public void testCopyRemoteFileOperation() {
Log.v(LOG_TAG, "testCopyFolder in");
/// successful cases
// copy file
CopyRemoteFileOperation copyOperation = new CopyRemoteFileOperation(
SRC_PATH_TO_FILE_1,
TARGET_PATH_TO_FILE_1,
false
);
RemoteOperationResult result = copyOperation.execute(mClient);
assertTrue(result.isSuccess());
// copy & rename file, different location
copyOperation = new CopyRemoteFileOperation(
SRC_PATH_TO_FILE_2,
TARGET_PATH_TO_FILE_2_RENAMED,
false
);
result = copyOperation.execute(mClient);
assertTrue(result.isSuccess());
// copy & rename file, same location (rename file)
copyOperation = new CopyRemoteFileOperation(
SRC_PATH_TO_FILE_3,
SRC_PATH_TO_FILE_3_RENAMED,
false
);
result = copyOperation.execute(mClient);
assertTrue(result.isSuccess());
// copy empty folder
copyOperation = new CopyRemoteFileOperation(
SRC_PATH_TO_EMPTY_FOLDER,
TARGET_PATH_TO_EMPTY_FOLDER,
false
);
result = copyOperation.execute(mClient);
assertTrue(result.isSuccess());
// copy non-empty folder
copyOperation = new CopyRemoteFileOperation(
SRC_PATH_TO_FULL_FOLDER_1,
TARGET_PATH_TO_FULL_FOLDER_1,
false
);
result = copyOperation.execute(mClient);
assertTrue(result.isSuccess());
// copy & rename folder, different location
copyOperation = new CopyRemoteFileOperation(
SRC_PATH_TO_FULL_FOLDER_2,
TARGET_PATH_TO_FULL_FOLDER_2_RENAMED,
false
);
result = copyOperation.execute(mClient);
assertTrue(result.isSuccess());
// copy & rename folder, same location (rename folder)
copyOperation = new CopyRemoteFileOperation(
SRC_PATH_TO_FULL_FOLDER_3,
SRC_PATH_TO_FULL_FOLDER_3_RENAMED,
false
);
result = copyOperation.execute(mClient);
assertTrue(result.isSuccess());
// copy for nothing (success, but no interaction with network)
copyOperation = new CopyRemoteFileOperation(
SRC_PATH_TO_FILE_4,
SRC_PATH_TO_FILE_4,
false
);
result = copyOperation.execute(mClient);
assertTrue(result.isSuccess());
// copy overwriting
copyOperation = new CopyRemoteFileOperation(
SRC_PATH_TO_FULL_FOLDER_4,
TARGET_PATH_TO_ALREADY_EXISTENT_EMPTY_FOLDER_4,
true
);
result = copyOperation.execute(mClient);
assertTrue(result.isSuccess());
/// Failed cases
// file to copy does not exist
copyOperation = new CopyRemoteFileOperation(
SRC_PATH_TO_NON_EXISTENT_FILE,
TARGET_PATH_TO_NON_EXISTENT_FILE,
false
);
result = copyOperation.execute(mClient);
assertTrue(result.getCode() == ResultCode.FILE_NOT_FOUND);
// folder to copy into does no exist
copyOperation = new CopyRemoteFileOperation(
SRC_PATH_TO_FILE_5,
TARGET_PATH_TO_FILE_5_INTO_NON_EXISTENT_FOLDER,
false
);
result = copyOperation.execute(mClient);
assertTrue(result.getHttpCode() == HttpStatus.SC_CONFLICT);
// target location (renaming) has invalid characters
copyOperation = new CopyRemoteFileOperation(
SRC_PATH_TO_FILE_6,
TARGET_PATH_RENAMED_WITH_INVALID_CHARS,
false
);
result = copyOperation.execute(mClient);
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
// name collision
copyOperation = new CopyRemoteFileOperation(
SRC_PATH_TO_FILE_1,
TARGET_PATH_TO_ALREADY_EXISTENT_FILE_7,
false
);
result = copyOperation.execute(mClient);
assertTrue(result.getCode() == ResultCode.INVALID_OVERWRITE);
// copy a folder into a descendant
copyOperation = new CopyRemoteFileOperation(
SRC_BASE_FOLDER,
SRC_PATH_TO_EMPTY_FOLDER,
false
);
result = copyOperation.execute(mClient);
assertTrue(result.getCode() == ResultCode.INVALID_COPY_INTO_DESCENDANT);
}
@Override
protected void tearDown() throws Exception {
Log.v(LOG_TAG, "Deleting remote fixture...");
String[] mPathsToCleanUp = {
SRC_BASE_FOLDER,
TARGET_BASE_FOLDER
};
for (String path : mPathsToCleanUp) {
RemoteOperationResult removeResult =
TestActivity.removeFile(path, mClient);
if (!removeResult.isSuccess() && removeResult.getCode() != ResultCode.TIMEOUT) {
Utils.logAndThrow(LOG_TAG, removeResult);
}
}
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.");
}
}

View File

@ -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,8 +41,12 @@ 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 {
@ -47,6 +54,7 @@ public class CreateShareTest extends RemoteTest {
setActivityInitialTouchMode(false);
mActivity = getActivity();
mFullPath2FileToShare = mBaseFolderPath + FILE_TO_SHARE;
mFullPath2NonExistentFile = mBaseFolderPath + NON_EXISTENT_FILE;
File textFile = mActivity.extractAsset(TestActivity.ASSETS__TEXT_FILE_NAME);
RemoteOperationResult result = mActivity.uploadFile(
@ -59,9 +67,11 @@ public class CreateShareTest extends RemoteTest {
}
/**
* 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_FORBIDDEN,
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_FORBIDDEN,
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
);
}

View File

@ -0,0 +1,145 @@
/* ownCloud Android Library is available under MIT license
* @author masensio
* 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.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
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.status.GetRemoteCapabilitiesOperation;
import com.owncloud.android.lib.test_project.R;
import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory;
/**
* Class to test GetRemoteCapabilitiesOperation
*
*/
public class GetCapabilitiesTest extends RemoteTest {
private static final String LOG_TAG = GetCapabilitiesTest.class.getCanonicalName();
String mServerUri, mUser, mPass;
OwnCloudClient mClient = null;
public GetCapabilitiesTest() {
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.");
}
// Tests
/**
* Test get capabilities
*
* Requires OC server 8.1 or later
*/
public void testGetRemoteCapabilitiesOperation() {
// get capabilities
GetRemoteCapabilitiesOperation getCapabilitiesOperation = new GetRemoteCapabilitiesOperation();
RemoteOperationResult result = getCapabilitiesOperation.execute(mClient);
assertTrue(result.isSuccess());
assertTrue(result.getData() != null && result.getData().size() == 1);
}
@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.");
}
}

View File

@ -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() > 0);
try {
for (int i=0; i<result.getData().size(); 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++;
}
}
assertTrue(userCount > 0);
assertTrue(groupCount > 0);
} catch (JSONException e) {
AssertionFailedError afe = new AssertionFailedError(e.getLocalizedMessage());
afe.setStackTrace(e.getStackTrace());
throw afe;
}
// search for sharees including "ad" - expecting user "admin" & group "admin"
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 "bd" - expecting 0 results
getShareesOperation = new GetRemoteShareesOperation("bd", 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.");
}
}

View File

@ -135,7 +135,7 @@ public class OwnCloudClientTest extends AndroidTestCase {
client.setCredentials(credentials);
assertEquals("Bearer credentials not set", credentials, client.getCredentials());
credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials("samlSessionCookie=124");
credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials("user", "samlSessionCookie=124");
client.setCredentials(credentials);
assertEquals("SAML2 session credentials not set", credentials, client.getCredentials());

View File

@ -65,7 +65,7 @@ public class RemoveShareTest extends RemoteTest {
Utils.logAndThrow(LOG_TAG, result);
} else {
OCShare created = (OCShare) result.getData().get(0);
mShareId = created.getIdRemoteShared();
mShareId = created.getRemoteId();
}
}

View File

@ -0,0 +1,259 @@
/* 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.test_project.test;
import java.io.File;
import java.security.GeneralSecurityException;
import java.util.Calendar;
import junit.framework.AssertionFailedError;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
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.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.lib.resources.shares.RemoveRemoteShareOperation;
import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.lib.resources.shares.UpdateRemoteShareOperation;
import com.owncloud.android.lib.test_project.R;
import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory;
import com.owncloud.android.lib.test_project.TestActivity;
/**
* Class to test UpdateRemoteShareOperation
* with private shares
*
*/
public class UpdatePrivateShareTest extends RemoteTest {
private static final String LOG_TAG = UpdatePrivateShareTest.class.getCanonicalName();
/* File to share and update */
private static final String FILE_TO_SHARE = "/fileToShare.txt";
/* Folder to share and update */
private static final String FOLDER_TO_SHARE = "/folderToShare";
/* Sharees */
private static final String USER_SHAREE = "admin";
private static final String GROUP_SHAREE = "admin";
private String mFullPath2FileToShare;
private String mFullPath2FolderToShare;
private OCShare mFileShare;
private OCShare mFolderShare;
String mServerUri, mUser, mPass;
OwnCloudClient mClient = null;
public UpdatePrivateShareTest(){
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...");
// Upload the file
mFullPath2FileToShare = mBaseFolderPath + FILE_TO_SHARE;
File textFile = getActivity().extractAsset(TestActivity.ASSETS__TEXT_FILE_NAME);
RemoteOperationResult result = getActivity().uploadFile(
textFile.getAbsolutePath(),
mFullPath2FileToShare,
"txt/plain");
if (!result.isSuccess()) {
Utils.logAndThrow(LOG_TAG, result);
}
// Share the file privately with other user
result = getActivity().createShare(
mFullPath2FileToShare,
ShareType.USER,
USER_SHAREE,
false,
"",
OCShare.MAXIMUM_PERMISSIONS_FOR_FILE);
if (result.isSuccess()){
mFileShare = (OCShare) result.getData().get(0);
} else{
mFileShare = null;
}
// Create the folder
mFullPath2FolderToShare = mBaseFolderPath + FOLDER_TO_SHARE;
result = getActivity().createFolder(
mFullPath2FolderToShare,
true);
if (!result.isSuccess()) {
Utils.logAndThrow(LOG_TAG, result);
}
// Share the folder privately with a group
result = getActivity().createShare(
mFullPath2FolderToShare,
ShareType.GROUP,
GROUP_SHAREE,
false,
"",
OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER);
if (result.isSuccess()){
mFolderShare = (OCShare) result.getData().get(0);
} else{
mFolderShare = null;
}
Log.v(LOG_TAG, "Remote fixture created.");
}
public void testUpdateSharePermissions() {
Log.v(LOG_TAG, "testUpdateSharePermissions in");
if (mFileShare != null) {
/// successful tests
// Update Share permissions on a shared file
UpdateRemoteShareOperation updateShare = new UpdateRemoteShareOperation(
mFileShare.getRemoteId()
);
updateShare.setPermissions(OCShare.READ_PERMISSION_FLAG); // minimum permissions
RemoteOperationResult result = updateShare.execute(mClient);
assertTrue(result.isSuccess());
// Update Share permissions on a shared folder
updateShare = new UpdateRemoteShareOperation(mFolderShare.getRemoteId());
updateShare.setPermissions(OCShare.READ_PERMISSION_FLAG + OCShare.DELETE_PERMISSION_FLAG);
result = updateShare.execute(mClient);
assertTrue(result.isSuccess());
/// unsuccessful tests
// Update Share with invalid permissions
updateShare = new UpdateRemoteShareOperation(mFileShare.getRemoteId());
// greater than maximum value
updateShare.setPermissions(OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER + 1);
result = updateShare.execute(mClient);
assertFalse(result.isSuccess());
// Unshare the file before next unsuccessful tests
RemoveRemoteShareOperation unshare = new RemoveRemoteShareOperation(
(int) mFileShare.getRemoteId()
);
result = unshare.execute(mClient);
if (result.isSuccess()) {
// Update Share permissions on unknown share
UpdateRemoteShareOperation updateNoShare = new UpdateRemoteShareOperation(
mFileShare.getRemoteId()
);
updateShare.setPermissions(OCShare.READ_PERMISSION_FLAG); // minimum permissions
result = updateShare.execute(mClient);
assertFalse(result.isSuccess());
}
}
}
@Override
protected void tearDown() throws Exception {
Log.v(LOG_TAG, "Deleting remote fixture...");
if (mFullPath2FileToShare != null) {
RemoteOperationResult removeResult = getActivity().removeFile(mFullPath2FileToShare);
if (!removeResult.isSuccess() && removeResult.getCode() != ResultCode.TIMEOUT) {
Utils.logAndThrow(LOG_TAG, removeResult);
}
}
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.");
}
}

View File

@ -0,0 +1,243 @@
/* 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.test_project.test;
import java.io.File;
import java.security.GeneralSecurityException;
import java.util.Calendar;
import junit.framework.AssertionFailedError;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
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.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.lib.resources.shares.RemoveRemoteShareOperation;
import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.lib.resources.shares.UpdateRemoteShareOperation;
import com.owncloud.android.lib.test_project.R;
import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory;
import com.owncloud.android.lib.test_project.TestActivity;
/**
* Class to test UpdateRemoteShareOperation
* with public shares
*
*/
public class UpdatePublicShareTest extends RemoteTest {
private static final String LOG_TAG = UpdatePublicShareTest.class.getCanonicalName();
/* File to share and update.*/
private static final String FILE_TO_SHARE = "/fileToShare.txt";
// Data for tests
private static final String PASSWORD = "password";
private static final String PASS_SPECIAL_CHARS = "p@ssw<73>rd";
private String mFullPath2FileToShare;
private OCShare mShare;
String mServerUri, mUser, mPass;
OwnCloudClient mClient = null;
public UpdatePublicShareTest(){
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...");
// Upload the files
mFullPath2FileToShare = mBaseFolderPath + FILE_TO_SHARE;
File textFile = getActivity().extractAsset(TestActivity.ASSETS__TEXT_FILE_NAME);
RemoteOperationResult result = getActivity().uploadFile(
textFile.getAbsolutePath(),
mFullPath2FileToShare,
"txt/plain");
if (!result.isSuccess()) {
Utils.logAndThrow(LOG_TAG, result);
}
// Share the file with a public link
result = getActivity().createShare(
mFullPath2FileToShare,
ShareType.PUBLIC_LINK,
"",
false,
"",
1);
if (result.isSuccess()){
mShare = (OCShare) result.getData().get(0);
} else{
mShare = null;
}
Log.v(LOG_TAG, "Remote fixture created.");
}
public void testUpdatePublicShare() {
Log.v(LOG_TAG, "testUpdatePublicShare in");
if (mShare != null) {
// successful tests
// Update Share with password
UpdateRemoteShareOperation updateShare = new UpdateRemoteShareOperation(mShare.getRemoteId());
updateShare.setPassword(PASSWORD);
RemoteOperationResult result = updateShare.execute(mClient);
assertTrue(result.isSuccess());
// Update Share with password with special characters
updateShare = new UpdateRemoteShareOperation(mShare.getRemoteId());
updateShare.setPassword(PASS_SPECIAL_CHARS);
result = updateShare.execute(mClient);
assertTrue(result.isSuccess());
// Update Share with expiration date
updateShare = new UpdateRemoteShareOperation(mShare.getRemoteId());
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_MONTH, 7);
long expirationDateInMillis = calendar.getTimeInMillis() ;
updateShare.setExpirationDate(expirationDateInMillis);
result = updateShare.execute(mClient);
assertTrue(result.isSuccess());
// unsuccessful test
// Update Share with expiration date in the past
updateShare = new UpdateRemoteShareOperation(mShare.getRemoteId());
calendar.set(Calendar.YEAR, 2014);
expirationDateInMillis = calendar.getTimeInMillis() ;
updateShare.setExpirationDate(expirationDateInMillis);
result = updateShare.execute(mClient);
assertFalse(result.isSuccess());
// Unshare the file before the unsuccessful tests
RemoveRemoteShareOperation unshare = new RemoveRemoteShareOperation((int) mShare.getRemoteId());
result = unshare.execute(mClient);
if (result.isSuccess()) {
// Update Share with password on unknown share
UpdateRemoteShareOperation updateNoShare = new UpdateRemoteShareOperation(mShare.getRemoteId());
updateNoShare.setPassword(PASSWORD);
result = updateNoShare.execute(mClient);
assertFalse(result.isSuccess());
// Update Share with expiration date on unknown share
updateNoShare = new UpdateRemoteShareOperation(mShare.getRemoteId());
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_MONTH, 7);
expirationDateInMillis = cal.getTimeInMillis() ;
updateNoShare.setExpirationDate(expirationDateInMillis);
result = updateNoShare.execute(mClient);
assertFalse(result.isSuccess());
}
}
}
@Override
protected void tearDown() throws Exception {
Log.v(LOG_TAG, "Deleting remote fixture...");
if (mFullPath2FileToShare != null) {
RemoteOperationResult removeResult = getActivity().removeFile(mFullPath2FileToShare);
if (!removeResult.isSuccess() && removeResult.getCode() != ResultCode.TIMEOUT) {
Utils.logAndThrow(LOG_TAG, removeResult);
}
}
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.");
}
}