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

Merge pull request #98 from owncloud/share_with_password_and_expiration_time

Changes to support update of password and expiration time in public shares
This commit is contained in:
David A. Velasco 2015-11-25 09:28:32 +01:00
commit 9e5c44ddb5
8 changed files with 471 additions and 25 deletions

View File

@ -147,7 +147,7 @@ public class CreateRemoteShareOperation extends RemoteOperation {
// retrieve more info - POST only returns the index of the new share // retrieve more info - POST only returns the index of the new share
OCShare emptyShare = (OCShare) result.getData().get(0); OCShare emptyShare = (OCShare) result.getData().get(0);
GetRemoteShareOperation getInfo = new GetRemoteShareOperation( GetRemoteShareOperation getInfo = new GetRemoteShareOperation(
emptyShare.getIdRemoteShared() emptyShare.getRemoteId()
); );
result = getInfo.execute(client); result = getInfo.execute(client);
} }

View File

@ -61,7 +61,7 @@ public class OCShare implements Parcelable, Serializable {
private String mSharedWithDisplayName; private String mSharedWithDisplayName;
private boolean mIsFolder; private boolean mIsFolder;
private long mUserId; private long mUserId;
private long mIdRemoteShared; private long mRemoteId;
private String mShareLink; private String mShareLink;
public OCShare() { public OCShare() {
@ -86,17 +86,17 @@ public class OCShare implements Parcelable, Serializable {
mFileSource = 0; mFileSource = 0;
mItemSource = 0; mItemSource = 0;
mShareType = ShareType.NO_SHARED; mShareType = ShareType.NO_SHARED;
mShareWith = null; mShareWith = "";
mPath = null; mPath = "";
mPermissions = -1; mPermissions = -1;
mSharedDate = 0; mSharedDate = 0;
mExpirationDate = 0; mExpirationDate = 0;
mToken = null; mToken = "";
mSharedWithDisplayName = null; mSharedWithDisplayName = "";
mIsFolder = false; mIsFolder = false;
mUserId = -1; mUserId = -1;
mIdRemoteShared = -1; mRemoteId = -1;
mShareLink = null; mShareLink = "";
} }
/// Getters and Setters /// Getters and Setters
@ -138,7 +138,7 @@ public class OCShare implements Parcelable, Serializable {
} }
public void setShareWith(String shareWith) { public void setShareWith(String shareWith) {
this.mShareWith = shareWith; this.mShareWith = (shareWith != null) ? shareWith : "";
} }
public String getPath() { public String getPath() {
@ -146,7 +146,7 @@ public class OCShare implements Parcelable, Serializable {
} }
public void setPath(String path) { public void setPath(String path) {
this.mPath = path; this.mPath = (path != null) ? path : "";
} }
public int getPermissions() { public int getPermissions() {
@ -178,7 +178,7 @@ public class OCShare implements Parcelable, Serializable {
} }
public void setToken(String token) { public void setToken(String token) {
this.mToken = token; this.mToken = (token != null) ? token : "";
} }
public String getSharedWithDisplayName() { public String getSharedWithDisplayName() {
@ -186,7 +186,7 @@ public class OCShare implements Parcelable, Serializable {
} }
public void setSharedWithDisplayName(String sharedWithDisplayName) { public void setSharedWithDisplayName(String sharedWithDisplayName) {
this.mSharedWithDisplayName = sharedWithDisplayName; this.mSharedWithDisplayName = (sharedWithDisplayName != null) ? sharedWithDisplayName : "";
} }
public boolean isFolder() { public boolean isFolder() {
@ -205,12 +205,12 @@ public class OCShare implements Parcelable, Serializable {
this.mUserId = userId; this.mUserId = userId;
} }
public long getIdRemoteShared() { public long getRemoteId() {
return mIdRemoteShared; return mRemoteId;
} }
public void setIdRemoteShared(long idRemoteShared) { public void setIdRemoteShared(long remoteId) {
this.mIdRemoteShared = idRemoteShared; this.mRemoteId = remoteId;
} }
public String getShareLink() { public String getShareLink() {
@ -218,7 +218,11 @@ public class OCShare implements Parcelable, Serializable {
} }
public void setShareLink(String shareLink) { 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;
} }
/** /**
@ -264,7 +268,7 @@ public class OCShare implements Parcelable, Serializable {
mSharedWithDisplayName = source.readString(); mSharedWithDisplayName = source.readString();
mIsFolder = source.readInt() == 0; mIsFolder = source.readInt() == 0;
mUserId = source.readLong(); mUserId = source.readLong();
mIdRemoteShared = source.readLong(); mRemoteId = source.readLong();
mShareLink = source.readString(); mShareLink = source.readString();
} }
@ -290,7 +294,7 @@ public class OCShare implements Parcelable, Serializable {
dest.writeString(mSharedWithDisplayName); dest.writeString(mSharedWithDisplayName);
dest.writeInt(mIsFolder ? 1 : 0); dest.writeInt(mIsFolder ? 1 : 0);
dest.writeLong(mUserId); dest.writeLong(mUserId);
dest.writeLong(mIdRemoteShared); dest.writeLong(mRemoteId);
dest.writeString(mShareLink); dest.writeString(mShareLink);
} }

View File

@ -90,7 +90,8 @@ public class ShareToRemoteOperationResultParser {
resultData.add(share); resultData.add(share);
// build the share link if not in the response (only received when the share is created) // build the share link if not in the response (only received when the share is created)
if (share.getShareType() == ShareType.PUBLIC_LINK && if (share.getShareType() == ShareType.PUBLIC_LINK &&
share.getShareLink() == null && (share.getShareLink() == null ||
share.getShareLink().length() <= 0) &&
share.getToken().length() > 0 share.getToken().length() > 0
) { ) {
if (mServerBaseUri != null) { if (mServerBaseUri != null) {

View File

@ -82,7 +82,7 @@ public class ShareXMLParser {
private static final String TYPE_FOLDER = "folder"; private static final String TYPE_FOLDER = "folder";
private static final int SUCCESS = 100; private static final int SUCCESS = 100;
private static final int ERROR_WRONG_PARAMETER = 403; private static final int ERROR_WRONG_PARAMETER = 400;
private static final int ERROR_FORBIDDEN = 403; private static final int ERROR_FORBIDDEN = 403;
private static final int ERROR_NOT_FOUND = 404; private static final int ERROR_NOT_FOUND = 404;
@ -368,7 +368,7 @@ public class ShareXMLParser {
} }
private boolean isValidShare(OCShare share) { private boolean isValidShare(OCShare share) {
return (share.getIdRemoteShared() > -1); return (share.getRemoteId() > -1);
} }
private void fixPathForFolder(OCShare share) { private void fixPathForFolder(OCShare share) {

View File

@ -0,0 +1,200 @@
/* 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 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;
/**
* 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 public link.
* 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;
}
@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
/* TODO complete rest of parameters
if (mPermissions > 0) {
parametersToUpdate.add(new Pair("permissions", Integer.toString(mPermissions)));
}
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

@ -132,7 +132,7 @@ public class CreateShareTest extends RemoteTest {
31); 31);
assertFalse(result.isSuccess()); assertFalse(result.isSuccess());
assertEquals( assertEquals(
RemoteOperationResult.ResultCode.SHARE_WRONG_PARAMETER, RemoteOperationResult.ResultCode.SHARE_FORBIDDEN,
result.getCode() result.getCode()
); );
assertTrue( // error message from server as part of the result assertTrue( // error message from server as part of the result
@ -189,7 +189,7 @@ public class CreateShareTest extends RemoteTest {
31); 31);
assertFalse(result.isSuccess()); assertFalse(result.isSuccess());
assertEquals( assertEquals(
RemoteOperationResult.ResultCode.SHARE_WRONG_PARAMETER, RemoteOperationResult.ResultCode.SHARE_FORBIDDEN,
result.getCode() result.getCode()
); );
assertTrue( // error message from server as part of the result assertTrue( // error message from server as part of the result

View File

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

View File

@ -0,0 +1,241 @@
/* 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.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
*
*/
public class UpdateShareTest extends RemoteTest {
private static final String LOG_TAG = UpdateShareTest.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órd";
private String mFullPath2FileToShare;
private OCShare mShare;
String mServerUri, mUser, mPass;
OwnCloudClient mClient = null;
public UpdateShareTest(){
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
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 testUpdateRemoteShareOperation() {
Log.v(LOG_TAG, "testUpdateShare 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.");
}
}