Skip to content

Commit

Permalink
Merge pull request #150 from nextcloud/fileVersioning
Browse files Browse the repository at this point in the history
Add support for file versions
  • Loading branch information
AndyScherzinger authored Jun 15, 2018
2 parents 8cdae45 + f325385 commit 060285b
Show file tree
Hide file tree
Showing 4 changed files with 326 additions and 0 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ dependencies {
implementation 'org.parceler:parceler-api:1.1.6'
annotationProcessor 'org.parceler:parceler:1.1.6'
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.0'
implementation "com.android.support:support-annotations:27.1.1"
}

android {
Expand Down
17 changes: 17 additions & 0 deletions src/com/owncloud/android/lib/common/network/WebdavUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,23 @@ public static DavPropertyNameSet getTrashbinPropSet() {
return propSet;
}

/**
* Builds a DavPropertyNameSet with properties for versions
* @return
*/
public static DavPropertyNameSet getFileVersionPropSet() {
DavPropertyNameSet propSet = new DavPropertyNameSet();
propSet.add(DavPropertyName.GETCONTENTTYPE);
propSet.add(DavPropertyName.RESOURCETYPE);
propSet.add(DavPropertyName.GETCONTENTLENGTH);
propSet.add(DavPropertyName.GETLASTMODIFIED);
propSet.add(DavPropertyName.CREATIONDATE);
propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_REMOTE_ID, Namespace.getNamespace(WebdavEntry.NAMESPACE_OC));
propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_SIZE, Namespace.getNamespace(WebdavEntry.NAMESPACE_OC));

return propSet;
}

/**
*
* @param rawEtag
Expand Down
156 changes: 156 additions & 0 deletions src/com/owncloud/android/lib/resources/files/FileVersion.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2018 Nextcloud GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* 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.os.Parcel;
import android.os.Parcelable;

import com.owncloud.android.lib.common.network.WebdavEntry;

/**
* Contains the data of a versioned file from a WebDavEntry.
*
* @author Tobias Kaminsky
*/
public class FileVersion implements Parcelable, ServerFileInterface {

/**
* Generated - should be refreshed every time the class changes!!
*/
private static final long serialVersionUID = 3130865437811248455L;

public static final String DIRECTORY = "DIR";

private String mimeType;
private long length;
private long modifiedTimestamp;
private String remoteId;

@Override
public boolean getIsFavorite() {
return false;
}

@Override
public String getFileName() {
return String.valueOf(modifiedTimestamp / 1000);
}

public String getMimeType() {
return mimeType;
}

@Override
public String getRemotePath() {
return "";
}

@Override
public String getRemoteId() {
return remoteId;
}

public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}

public long getFileLength() {
return length;
}

public void setFileLength(long length) {
this.length = length;
}

public boolean isFolder() {
return mimeType != null && mimeType.equals(DIRECTORY);
}

public boolean isHidden() {
return getFileName().startsWith(".");
}

public void setModifiedTimestamp(long modifiedTimestamp) {
this.modifiedTimestamp = modifiedTimestamp;
}

public long getModifiedTimestamp() {
return modifiedTimestamp;
}

public FileVersion(String fileId, WebdavEntry we) {
remoteId = fileId;
setMimeType(we.contentType());

if (isFolder()) {
setFileLength(we.size());
} else {
setFileLength(we.contentLength());
}

setModifiedTimestamp(we.modifiedTimestamp());
}

/**
* Parcelable Methods
*/
public static final Creator<FileVersion> CREATOR = new Creator<FileVersion>() {
@Override
public FileVersion createFromParcel(Parcel source) {
return new FileVersion(source);
}

@Override
public FileVersion[] newArray(int size) {
return new FileVersion[size];
}
};


/**
* Reconstruct from parcel
*
* @param source The source parcel
*/
protected FileVersion(Parcel source) {
readFromParcel(source);
}

public void readFromParcel(Parcel source) {
mimeType = source.readString();
length = source.readLong();
}

@Override
public int describeContents() {
return this.hashCode();
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mimeType);
dest.writeLong(length);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2018 Nextcloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* 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.support.annotation.NonNull;

import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.WebdavEntry;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;

import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavConstants;
import org.apache.jackrabbit.webdav.MultiStatus;
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;

import java.util.ArrayList;

/**
* Remote operation performing the read of remote trashbin folder on Nextcloud server.
*
* @author Tobias Kaminsky
*/

public class ReadFileVersionsOperation extends RemoteOperation {

private static final String TAG = ReadFileVersionsOperation.class.getSimpleName();

private String fileId;
private String userId;
private ArrayList<Object> versions;

/**
* Constructor
*
* @param fileId FileId of the file.
*/
public ReadFileVersionsOperation(@NonNull String fileId, @NonNull String userId) {
this.fileId = fileId;
this.userId = userId;
}

/**
* Performs the read operation.
*
* @param client Client object to communicate with the remote ownCloud server.
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
PropFindMethod query = null;

try {
// remote request
if (userId.isEmpty()) {
throw new IllegalArgumentException("UserId may not be empty!");
}

String uri = client.getNewWebdavUri(false) + "/versions/" + userId + "/versions/" + fileId;
DavPropertyNameSet propSet = WebdavUtils.getFileVersionPropSet();

query = new PropFindMethod(uri, propSet, DavConstants.DEPTH_1);
int status = client.executeMethod(query);

// check and process response
boolean isSuccess = (status == HttpStatus.SC_MULTI_STATUS || status == HttpStatus.SC_OK);

if (isSuccess) {
// get data from remote folder
MultiStatus dataInServer = query.getResponseBodyAsMultiStatus();
readData(dataInServer, client);

// Result of the operation
result = new RemoteOperationResult(true, query);
// Add data to the result
if (result.isSuccess()) {
result.setData(versions);
}
} else {
// synchronization failed
client.exhaustResponse(query.getResponseBodyAsStream());
result = new RemoteOperationResult(false, query);
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
} finally {
if (query != null)
query.releaseConnection(); // let the connection available for other methods

if (result == null) {
result = new RemoteOperationResult(new Exception("unknown error"));
Log_OC.e(TAG, "Synchronized file with id " + fileId + ": failed");
} else {
if (result.isSuccess()) {
Log_OC.i(TAG, "Synchronized file with id " + fileId + ": " + result.getLogMessage());
} else {
if (result.isException()) {
Log_OC.e(TAG, "Synchronized with id " + fileId + ": " + result.getLogMessage(),
result.getException());
} else {
Log_OC.w(TAG, "Synchronized with id " + fileId + ": " + result.getLogMessage());
}
}
}
}

return result;
}

/**
* Read the data retrieved from the server about the file versions.
*
* @param remoteData Full response got from the server with the version data.
* @param client Client instance to the remote server where the data were retrieved.
*/
private void readData(MultiStatus remoteData, OwnCloudClient client) {
versions = new ArrayList<>();

// parse data from remote folder
String splitElement = client.getNewWebdavUri(false).getPath();

// loop to update every child
for (int i = 1; i < remoteData.getResponses().length; ++i) {
versions.add(new FileVersion(fileId, new WebdavEntry(remoteData.getResponses()[i], splitElement)));
}
}
}

0 comments on commit 060285b

Please sign in to comment.