From 791451a53f74a2e8a27b60631e6b74d57c366f16 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Fri, 1 Jun 2018 13:10:33 +0200 Subject: [PATCH 1/3] Add support for file versions Signed-off-by: tobiasKaminsky --- build.gradle | 1 + .../lib/common/network/WebdavUtils.java | 17 ++ .../lib/resources/files/FileVersion.java | 158 ++++++++++++++++++ .../files/ReadFileVersionsOperation.java | 154 +++++++++++++++++ 4 files changed, 330 insertions(+) create mode 100644 src/com/owncloud/android/lib/resources/files/FileVersion.java create mode 100644 src/com/owncloud/android/lib/resources/files/ReadFileVersionsOperation.java diff --git a/build.gradle b/build.gradle index bb87aadb3..7faefee29 100644 --- a/build.gradle +++ b/build.gradle @@ -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 { diff --git a/src/com/owncloud/android/lib/common/network/WebdavUtils.java b/src/com/owncloud/android/lib/common/network/WebdavUtils.java index 7f5301fef..d979e0a8c 100644 --- a/src/com/owncloud/android/lib/common/network/WebdavUtils.java +++ b/src/com/owncloud/android/lib/common/network/WebdavUtils.java @@ -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 diff --git a/src/com/owncloud/android/lib/resources/files/FileVersion.java b/src/com/owncloud/android/lib/resources/files/FileVersion.java new file mode 100644 index 000000000..2f57b2980 --- /dev/null +++ b/src/com/owncloud/android/lib/resources/files/FileVersion.java @@ -0,0 +1,158 @@ +/* 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; + +import java.io.Serializable; + +/** + * Contains the data of a versioned file from a WebDavEntry. + * + * @author Tobias Kaminsky + */ +public class FileVersion implements Parcelable, Serializable, 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 CREATOR = new Creator() { + @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); + } +} diff --git a/src/com/owncloud/android/lib/resources/files/ReadFileVersionsOperation.java b/src/com/owncloud/android/lib/resources/files/ReadFileVersionsOperation.java new file mode 100644 index 000000000..417864fee --- /dev/null +++ b/src/com/owncloud/android/lib/resources/files/ReadFileVersionsOperation.java @@ -0,0 +1,154 @@ +/* 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 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.e(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 + WebdavEntry we; + String splitElement = client.getNewWebdavUri(false).getPath(); + + // loop to update every child + for (int i = 1; i < remoteData.getResponses().length; ++i) { + we = new WebdavEntry(remoteData.getResponses()[i], splitElement); + versions.add(new FileVersion(fileId, we)); + } + } +} From 736a7cfafe7a6a1c5906eaa5095b788dd7eee262 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Wed, 6 Jun 2018 16:38:15 +0200 Subject: [PATCH 2/3] changes due to CR Signed-off-by: tobiasKaminsky --- .../lib/resources/files/ReadFileVersionsOperation.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/com/owncloud/android/lib/resources/files/ReadFileVersionsOperation.java b/src/com/owncloud/android/lib/resources/files/ReadFileVersionsOperation.java index 417864fee..825bcbd10 100644 --- a/src/com/owncloud/android/lib/resources/files/ReadFileVersionsOperation.java +++ b/src/com/owncloud/android/lib/resources/files/ReadFileVersionsOperation.java @@ -123,7 +123,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { Log_OC.e(TAG, "Synchronized with id " + fileId + ": " + result.getLogMessage(), result.getException()); } else { - Log_OC.e(TAG, "Synchronized with id " + fileId + ": " + result.getLogMessage()); + Log_OC.w(TAG, "Synchronized with id " + fileId + ": " + result.getLogMessage()); } } } @@ -142,13 +142,11 @@ private void readData(MultiStatus remoteData, OwnCloudClient client) { versions = new ArrayList<>(); // parse data from remote folder - WebdavEntry we; String splitElement = client.getNewWebdavUri(false).getPath(); // loop to update every child for (int i = 1; i < remoteData.getResponses().length; ++i) { - we = new WebdavEntry(remoteData.getResponses()[i], splitElement); - versions.add(new FileVersion(fileId, we)); + versions.add(new FileVersion(fileId, new WebdavEntry(remoteData.getResponses()[i], splitElement))); } } } From f32538562891d034a721a953ce7eb0ac2833f87d Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Fri, 8 Jun 2018 11:20:17 +0200 Subject: [PATCH 3/3] remove serializable Signed-off-by: tobiasKaminsky --- src/com/owncloud/android/lib/resources/files/FileVersion.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/com/owncloud/android/lib/resources/files/FileVersion.java b/src/com/owncloud/android/lib/resources/files/FileVersion.java index 2f57b2980..f275aa43b 100644 --- a/src/com/owncloud/android/lib/resources/files/FileVersion.java +++ b/src/com/owncloud/android/lib/resources/files/FileVersion.java @@ -29,14 +29,12 @@ import com.owncloud.android.lib.common.network.WebdavEntry; -import java.io.Serializable; - /** * Contains the data of a versioned file from a WebDavEntry. * * @author Tobias Kaminsky */ -public class FileVersion implements Parcelable, Serializable, ServerFileInterface { +public class FileVersion implements Parcelable, ServerFileInterface { /** * Generated - should be refreshed every time the class changes!!