From 017ae9d4282847bf86e3385c5f614e6b4461e3c9 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Thu, 6 Oct 2022 15:05:25 +0200 Subject: [PATCH 1/3] use dav4jvm search and proppatch Signed-off-by: tobiasKaminsky --- gradle/verification-metadata.xml | 24 + library/build.gradle | 3 +- ...ashboardGetWidgetItemsRemoteOperationIT.kt | 19 +- .../DashboardListWidgetsRemoteOperationIT.kt | 12 +- .../DirectEditingObtainRemoteOperationIT.kt | 3 +- ...irectEditingOpenFileRemoteOperationIT.java | 8 +- .../files/ToggleFileLockRemoteOperationIT.kt | 13 +- .../GetGroupfoldersRemoteOperationIT.kt | 9 +- .../SearchProvidersRemoteOperationIT.kt | 19 +- .../search/UnifiedSearchRemoteOperationIT.kt | 28 +- .../GenerateAppPasswordRemoteOperationIT.java | 21 +- ...rkspaceDirectEditingRemoteOperationIT.java | 4 +- .../users/GetActivitiesRemoteOperationIT.kt | 9 +- .../users/GetUserInfoRemoteOperationIT.kt | 12 +- .../java/com/owncloud/android/AbstractIT.java | 29 +- .../java/com/owncloud/android/CopyFileIT.java | 4 +- .../CreateFolderRemoteOperationIT.java | 46 +- .../com/owncloud/android/DeleteFileIT.java | 8 +- .../java/com/owncloud/android/FileIT.java | 165 ++-- .../GetCapabilitiesRemoteOperationIT.java | 63 +- .../accounts/ExternalLinksOperationIT.kt | 21 +- .../lib/common/operations/GetSharesIT.java | 24 +- .../lib/resources/assistant/AssistantIT.kt | 16 +- .../comments/CommentFileRemoteOperationIT.kt | 14 +- .../e2ee/UpdateMetadataRemoteOperationIT.java | 12 +- .../files/CheckEtagRemoteOperationIT.kt | 11 +- .../files/ReadFileRemoteOperationIT.kt | 62 +- .../ReadFileVersionsRemoteOperationIT.kt | 18 +- .../files/ReadFolderRemoteOperationIT.kt | 73 +- .../files/SearchRemoteOperationIT.java | 123 ++- .../files/UploadFileRemoteOperationIT.kt | 17 +- .../ChunkedFileUploadRemoteOperationIT.kt | 3 +- .../resources/notifications/NotificationIT.kt | 17 +- .../shares/CreateShareRemoteOperationIT.kt | 6 +- .../shares/GetShareesRemoteOperationIT.kt | 25 + .../shares/GetSharesRemoteOperationIT.java | 32 +- .../lib/resources/shares/ShareXMLParserIT.kt | 8 +- .../shares/UpdateShareRemoteOperationIT.kt | 37 +- .../tags/GetTagsRemoteOperationIT.kt | 11 +- .../ReadTrashbinFolderRemoteOperationIT.kt | 8 +- .../users/AppTokenRemoteOperationIT.kt | 11 +- .../users/SetUserInfoRemoteOperationIT.java | 6 +- .../android/lib/resources/users/StatusIT.kt | 22 +- .../GetGroupfoldersRemoteOperation.kt | 2 +- .../profile/GetHoverCardRemoteOperation.kt | 2 +- .../GenerateAppPasswordRemoteOperation.java | 28 +- .../java/com/nextcloud/common/DavMethod.kt | 29 + .../java/com/nextcloud/common/DavResponse.kt | 39 + .../common/NextcloudAuthenticator.kt | 50 ++ .../com/nextcloud/common/NextcloudClient.kt | 17 +- .../com/nextcloud/common/OkHttpMethodBase.kt | 4 - .../nextcloud/common/UserAgentInterceptor.kt | 30 + .../nextcloud/extensions/ArrayExtensions.kt | 26 + .../extensions/ParcelableExtensions.kt | 29 + .../com/nextcloud/operations/MkColMethod.kt | 48 ++ .../com/nextcloud/operations/MoveMethod.kt | 50 ++ .../nextcloud/operations/PropFindMethod.kt | 62 ++ .../nextcloud/operations/PropFindResult.kt | 23 + .../nextcloud/operations/PropPatchMethod.kt | 44 ++ .../com/nextcloud/operations/PutMethod.kt | 5 +- .../accounts/ExternalLinksOperation.java | 72 +- .../lib/common/network/ExtendedProperties.kt | 60 ++ .../android/lib/common/network/WebdavEntry.kt | 207 ++--- .../lib/common/network/WebdavUtils.java | 261 ------ .../android/lib/common/network/WebdavUtils.kt | 286 +++++++ .../common/operations/RemoteOperation.java | 23 +- .../operations/RemoteOperationResult.java | 741 ------------------ .../operations/RemoteOperationResult.kt | 625 +++++++++++++++ .../lib/common/utils/WebDavFileUtils.java | 62 -- .../lib/common/utils/WebDavFileUtils.kt | 180 +++++ .../GetActivitiesRemoteOperation.java | 102 +-- .../assistant/GetTaskListRemoteOperation.kt | 8 +- .../assistant/GetTaskTypesRemoteOperation.kt | 8 +- .../comments/CommentFileRemoteOperation.java | 4 +- .../MarkCommentsAsReadRemoteOperation.java | 73 -- .../MarkCommentsAsReadRemoteOperation.kt | 29 + .../e2ee/StoreMetadataV2RemoteOperation.kt | 2 +- .../e2ee/ToggleEncryptionRemoteOperation.java | 29 +- .../e2ee/UpdateMetadataV2RemoteOperation.kt | 2 +- .../files/CheckEtagRemoteOperation.java | 90 --- .../files/CheckEtagRemoteOperation.kt | 44 ++ .../ChunkedFileUploadRemoteOperation.java | 39 +- .../files/CreateFolderRemoteOperation.java | 125 --- .../files/CreateFolderRemoteOperation.kt | 102 +++ .../files/DownloadFileRemoteOperation.java | 4 +- .../files/LinkLivePhotoRemoteOperation.kt | 51 +- ...cSearchMethod.java => NCSearchMethod.java} | 79 +- .../files/ReadFileRemoteOperation.java | 61 +- .../ReadFileVersionsRemoteOperation.java | 23 +- .../files/ReadFolderRemoteOperation.java | 91 +-- .../files/RemoveFileRemoteOperation.java | 29 +- .../files/SearchRemoteOperation.java | 175 +++-- .../files/ToggleFavoriteRemoteOperation.java | 63 +- .../lib/resources/files/model/FileLockType.kt | 2 +- .../lib/resources/files/model/RemoteFile.kt | 110 +-- .../resources/files/webdav/NCCreationTime.kt | 33 + .../lib/resources/files/webdav/NCEncrypted.kt | 43 + .../lib/resources/files/webdav/NCEtag.kt | 35 + .../lib/resources/files/webdav/NCFavorite.kt | 43 + .../files/webdav/NCGetLastModified.kt | 38 + .../lib/resources/files/webdav/NCHidden.kt | 43 + .../lib/resources/files/webdav/NCLock.kt | 43 + .../lib/resources/files/webdav/NCLockOwner.kt | 43 + .../files/webdav/NCLockOwnerDisplayName.kt | 43 + .../files/webdav/NCLockOwnerEditor.kt | 43 + .../resources/files/webdav/NCLockOwnerType.kt | 44 ++ .../lib/resources/files/webdav/NCLockTime.kt | 33 + .../resources/files/webdav/NCLockTimeout.kt | 43 + .../lib/resources/files/webdav/NCLockToken.kt | 43 + .../resources/files/webdav/NCMetadataGPS.kt | 46 ++ .../files/webdav/NCMetadataLivePhoto.kt | 43 + .../files/webdav/NCMetadataPhotosGPS.kt | 63 ++ .../files/webdav/NCMetadataPhotosSize.kt | 63 ++ .../resources/files/webdav/NCMetadataSize.kt | 46 ++ .../lib/resources/files/webdav/NCMountType.kt | 39 + .../lib/resources/files/webdav/NCNote.kt | 43 + .../resources/files/webdav/NCPermissions.kt | 43 + .../lib/resources/files/webdav/NCPreview.kt | 43 + .../resources/files/webdav/NCRichWorkspace.kt | 43 + .../lib/resources/files/webdav/NCSharees.kt | 120 +++ .../lib/resources/files/webdav/NCTags.kt | 111 +++ .../files/webdav/NCTrashbinDeletionTime.kt | 43 + .../files/webdav/NCTrashbinFilename.kt | 43 + .../files/webdav/NCTrashbinLocation.kt | 43 + .../resources/files/webdav/NCUploadTime.kt | 43 + .../files/webdav/OCCommentsUnread.kt | 43 + .../resources/files/webdav/OCDisplayName.kt | 43 + .../lib/resources/files/webdav/OCId.kt | 43 + .../lib/resources/files/webdav/OCLocalId.kt | 43 + .../files/webdav/OCOwnerDisplayName.kt | 43 + .../lib/resources/files/webdav/OCOwnerId.kt | 43 + .../lib/resources/files/webdav/OCSize.kt | 43 + .../GetSharesForFileRemoteOperation.java | 8 +- .../ShareToRemoteOperationResultParser.java | 8 +- .../lib/resources/shares/ShareXMLParser.java | 2 +- .../GetCapabilitiesRemoteOperation.java | 91 +-- .../tags/CreateTagRemoteOperation.kt | 21 +- .../resources/tags/GetTagsRemoteOperation.kt | 64 +- .../ReadTrashbinFolderRemoteOperation.java | 7 +- .../RemoveTrashbinFileRemoteOperation.java | 14 +- .../RestoreTrashbinFileRemoteOperation.java | 16 +- .../GetServerPublicKeyRemoteOperation.kt | 2 +- .../users/GetUserAvatarRemoteOperation.java | 2 +- .../users/SendCSRRemoteOperation.java | 11 +- 144 files changed, 4721 insertions(+), 2697 deletions(-) create mode 100644 library/src/androidTest/java/com/owncloud/android/lib/resources/shares/GetShareesRemoteOperationIT.kt create mode 100644 library/src/main/java/com/nextcloud/common/DavMethod.kt create mode 100644 library/src/main/java/com/nextcloud/common/DavResponse.kt create mode 100644 library/src/main/java/com/nextcloud/common/NextcloudAuthenticator.kt create mode 100644 library/src/main/java/com/nextcloud/common/UserAgentInterceptor.kt create mode 100644 library/src/main/java/com/nextcloud/extensions/ArrayExtensions.kt create mode 100644 library/src/main/java/com/nextcloud/extensions/ParcelableExtensions.kt create mode 100644 library/src/main/java/com/nextcloud/operations/MkColMethod.kt create mode 100644 library/src/main/java/com/nextcloud/operations/MoveMethod.kt create mode 100644 library/src/main/java/com/nextcloud/operations/PropFindMethod.kt create mode 100644 library/src/main/java/com/nextcloud/operations/PropFindResult.kt create mode 100644 library/src/main/java/com/nextcloud/operations/PropPatchMethod.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/common/network/ExtendedProperties.kt delete mode 100644 library/src/main/java/com/owncloud/android/lib/common/network/WebdavUtils.java create mode 100644 library/src/main/java/com/owncloud/android/lib/common/network/WebdavUtils.kt delete mode 100644 library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java create mode 100644 library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.kt delete mode 100644 library/src/main/java/com/owncloud/android/lib/common/utils/WebDavFileUtils.java create mode 100644 library/src/main/java/com/owncloud/android/lib/common/utils/WebDavFileUtils.kt delete mode 100644 library/src/main/java/com/owncloud/android/lib/resources/comments/MarkCommentsAsReadRemoteOperation.java create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/comments/MarkCommentsAsReadRemoteOperation.kt delete mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/CheckEtagRemoteOperation.java create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/CheckEtagRemoteOperation.kt delete mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/CreateFolderRemoteOperation.java create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/CreateFolderRemoteOperation.kt rename library/src/main/java/com/owncloud/android/lib/resources/files/{NcSearchMethod.java => NCSearchMethod.java} (88%) create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCCreationTime.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCEncrypted.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCEtag.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCFavorite.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCGetLastModified.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCHidden.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLock.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwner.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwnerDisplayName.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwnerEditor.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwnerType.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockTime.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockTimeout.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockToken.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataGPS.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataLivePhoto.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataPhotosGPS.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataPhotosSize.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataSize.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMountType.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCNote.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCPermissions.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCPreview.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCRichWorkspace.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCSharees.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTags.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTrashbinDeletionTime.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTrashbinFilename.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTrashbinLocation.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCUploadTime.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCCommentsUnread.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCDisplayName.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCId.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCLocalId.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCOwnerDisplayName.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCOwnerId.kt create mode 100644 library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCSize.kt diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 673f7f9ec..ad80007a8 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -3696,6 +3696,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/library/build.gradle b/library/build.gradle index 69e99e42a..9b93479b2 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -61,8 +61,7 @@ configurations { dependencies { implementation 'org.apache.jackrabbit:jackrabbit-webdav:2.13.5' api 'com.squareup.okhttp3:okhttp:5.0.0-alpha.12' - implementation 'com.github.bitfireAT:dav4jvm:2.2.1' - // in transition phase, we use old and new libs + api 'com.github.bitfireAT:dav4jvm:2b414984a82f57248f6d519a328e93862b471316' // in transition phase, we use old and new libs implementation group: 'com.google.code.gson', name: 'gson', version: '2.11.0' implementation 'androidx.annotation:annotation:1.9.0' compileOnly 'com.google.code.findbugs:annotations:3.0.1u2' diff --git a/library/src/androidTest/java/com/nextcloud/android/lib/resources/dashboard/DashboardGetWidgetItemsRemoteOperationIT.kt b/library/src/androidTest/java/com/nextcloud/android/lib/resources/dashboard/DashboardGetWidgetItemsRemoteOperationIT.kt index a2e9aed38..971639cf1 100644 --- a/library/src/androidTest/java/com/nextcloud/android/lib/resources/dashboard/DashboardGetWidgetItemsRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/nextcloud/android/lib/resources/dashboard/DashboardGetWidgetItemsRemoteOperationIT.kt @@ -9,6 +9,7 @@ package com.nextcloud.android.lib.resources.dashboard import com.owncloud.android.AbstractIT import com.owncloud.android.lib.resources.files.CreateFolderRemoteOperation +import com.owncloud.android.lib.resources.files.RemoveFileRemoteOperation import com.owncloud.android.lib.resources.shares.CreateShareRemoteOperation import com.owncloud.android.lib.resources.shares.OCShare import com.owncloud.android.lib.resources.shares.ShareType @@ -22,11 +23,13 @@ class DashboardGetWidgetItemsRemoteOperationIT : AbstractIT() { // only on NC25+ testOnlyOnServer(NextcloudVersion.nextcloud_25) + val folderPath = "/testFolder" + // create folder to have some content - assertTrue(CreateFolderRemoteOperation("/testFolder", false).execute(client2).isSuccess) + assertTrue(CreateFolderRemoteOperation(folderPath, false).execute(nextcloudClient2).isSuccess) assertTrue( CreateShareRemoteOperation( - "/testFolder", + folderPath, ShareType.USER, client.userId, false, @@ -37,17 +40,19 @@ class DashboardGetWidgetItemsRemoteOperationIT : AbstractIT() { ) val widgetId = "activity" - val result = - DashboardGetWidgetItemsRemoteOperation(widgetId, LIMIT_SIZE).execute(nextcloudClient) + val result = DashboardGetWidgetItemsRemoteOperation(widgetId, LIMIT_SIZE).execute(nextcloudClient) assertTrue(result.isSuccess) - assertTrue(result.resultData[widgetId]?.isNotEmpty() ?: false) + assertTrue(result.resultData?.get(widgetId)?.isNotEmpty() ?: false) - val firstResult = result.resultData[widgetId]?.get(0) + val firstResult = result.resultData?.get(widgetId)?.get(0) assertTrue(firstResult?.title?.isNotEmpty() == true) assertTrue(firstResult?.subtitle != null) assertTrue(firstResult?.link?.isNotEmpty() == true) assertTrue(firstResult?.iconUrl?.isNotEmpty() == true) + + // remove folder + assertTrue(RemoveFileRemoteOperation(folderPath).execute(nextcloudClient2).isSuccess) } @Test @@ -57,7 +62,7 @@ class DashboardGetWidgetItemsRemoteOperationIT : AbstractIT() { DashboardGetWidgetItemsRemoteOperation(widgetId, LIMIT_SIZE).execute(nextcloudClient) assertTrue(result.isSuccess) - assertTrue(result.resultData.isEmpty()) + assertTrue(result.resultData?.isEmpty() ?: false) } companion object { diff --git a/library/src/androidTest/java/com/nextcloud/android/lib/resources/dashboard/DashboardListWidgetsRemoteOperationIT.kt b/library/src/androidTest/java/com/nextcloud/android/lib/resources/dashboard/DashboardListWidgetsRemoteOperationIT.kt index fce4bdf27..699e3ff79 100644 --- a/library/src/androidTest/java/com/nextcloud/android/lib/resources/dashboard/DashboardListWidgetsRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/nextcloud/android/lib/resources/dashboard/DashboardListWidgetsRemoteOperationIT.kt @@ -22,14 +22,14 @@ class DashboardListWidgetsRemoteOperationIT : AbstractIT() { val result = DashboardListWidgetsRemoteOperation().execute(nextcloudClient) assertTrue(result.isSuccess) - assertTrue(result.resultData.isNotEmpty()) + assertTrue(result.resultData?.isNotEmpty() ?: false) - assertTrue(result.resultData["recommendations"]?.buttons?.getOrNull(0) == null) + assertTrue(result.resultData?.get("recommendations")?.buttons?.getOrNull(0) == null) - assertEquals(1, result.resultData["activity"]?.buttons?.size) - assertTrue(result.resultData["activity"]?.buttons?.getOrNull(0)?.type == DashBoardButtonType.MORE) - assertTrue(result.resultData["activity"]?.roundIcons == false) + assertEquals(1, result.resultData?.get("activity")?.buttons?.size) + assertTrue(result.resultData?.get("activity")?.buttons?.getOrNull(0)?.type == DashBoardButtonType.MORE) + assertTrue(result.resultData?.get("activity")?.roundIcons == false) - assertTrue(result.resultData["user_status"]?.roundIcons == true) + assertTrue(result.resultData?.get("user_status")?.roundIcons == true) } } diff --git a/library/src/androidTest/java/com/nextcloud/android/lib/resources/directediting/DirectEditingObtainRemoteOperationIT.kt b/library/src/androidTest/java/com/nextcloud/android/lib/resources/directediting/DirectEditingObtainRemoteOperationIT.kt index 4fccbcda2..d840aaeef 100644 --- a/library/src/androidTest/java/com/nextcloud/android/lib/resources/directediting/DirectEditingObtainRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/nextcloud/android/lib/resources/directediting/DirectEditingObtainRemoteOperationIT.kt @@ -19,8 +19,9 @@ class DirectEditingObtainRemoteOperationIT : AbstractIT() { fun testGetAll() { val result = DirectEditingObtainRemoteOperation().run(nextcloudClient) assertTrue(result.isSuccess) + assertNotNull(result.resultData) - val (editors, creators) = result.resultData + val (editors, creators) = result.resultData!! assertTrue(editors.containsKey("text")) val textEditor = editors["text"] diff --git a/library/src/androidTest/java/com/nextcloud/android/lib/resources/directediting/DirectEditingOpenFileRemoteOperationIT.java b/library/src/androidTest/java/com/nextcloud/android/lib/resources/directediting/DirectEditingOpenFileRemoteOperationIT.java index 9f23bf3a7..8ab25db2c 100644 --- a/library/src/androidTest/java/com/nextcloud/android/lib/resources/directediting/DirectEditingOpenFileRemoteOperationIT.java +++ b/library/src/androidTest/java/com/nextcloud/android/lib/resources/directediting/DirectEditingOpenFileRemoteOperationIT.java @@ -34,7 +34,7 @@ public void openFile() throws IOException { 1464818400 ).execute(client).isSuccess()); - TestCase.assertTrue(new ReadFileRemoteOperation(remotePath).execute(client).isSuccess()); + TestCase.assertTrue(new ReadFileRemoteOperation(remotePath).execute(nextcloudClient).isSuccess()); // open file RemoteOperationResult result = new DirectEditingOpenFileRemoteOperation(remotePath, "text") @@ -58,7 +58,7 @@ public void openFileWithSpecialChars() throws IOException { 1464818400 ).execute(client).isSuccess()); - TestCase.assertTrue(new ReadFileRemoteOperation(remotePath).execute(client).isSuccess()); + TestCase.assertTrue(new ReadFileRemoteOperation(remotePath).execute(nextcloudClient).isSuccess()); // open file RemoteOperationResult result = new DirectEditingOpenFileRemoteOperation(remotePath, "text") @@ -82,7 +82,7 @@ public void openFileWithSpecialChars2() throws IOException { 1464818400 ).execute(client).isSuccess()); - TestCase.assertTrue(new ReadFileRemoteOperation(remotePath).execute(client).isSuccess()); + TestCase.assertTrue(new ReadFileRemoteOperation(remotePath).execute(nextcloudClient).isSuccess()); // open file RemoteOperationResult result = new DirectEditingOpenFileRemoteOperation(remotePath, "text") @@ -98,7 +98,7 @@ public void openFileWithSpecialChars2() throws IOException { public void openNonExistingFile() { String remotePath = "/nonExisting.md"; - TestCase.assertFalse(new ReadFileRemoteOperation(remotePath).execute(client).isSuccess()); + TestCase.assertFalse(new ReadFileRemoteOperation(remotePath).execute(nextcloudClient).isSuccess()); // open file RemoteOperationResult result = new DirectEditingOpenFileRemoteOperation(remotePath, "text") diff --git a/library/src/androidTest/java/com/nextcloud/android/lib/resources/files/ToggleFileLockRemoteOperationIT.kt b/library/src/androidTest/java/com/nextcloud/android/lib/resources/files/ToggleFileLockRemoteOperationIT.kt index 235c6c1c3..8d1b4db1f 100644 --- a/library/src/androidTest/java/com/nextcloud/android/lib/resources/files/ToggleFileLockRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/nextcloud/android/lib/resources/files/ToggleFileLockRemoteOperationIT.kt @@ -13,9 +13,11 @@ import com.owncloud.android.lib.resources.files.UploadFileRemoteOperation import com.owncloud.android.lib.resources.files.model.FileLockType import com.owncloud.android.lib.resources.files.model.RemoteFile import com.owncloud.android.lib.resources.status.NextcloudVersion.Companion.nextcloud_24 +import okhttp3.internal.http.HTTP_NOT_IMPLEMENTED import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue +import org.junit.Assume.assumeTrue import org.junit.Test class ToggleFileLockRemoteOperationIT : AbstractIT() { @@ -32,21 +34,24 @@ class ToggleFileLockRemoteOperationIT : AbstractIT() { UploadFileRemoteOperation(filePath, remotePath, "text/markdown", 1464818400) .execute(client).isSuccess ) - val initialFile = - ReadFileRemoteOperation(remotePath).execute(client).singleData as RemoteFile + val initialFile = ReadFileRemoteOperation(remotePath).execute(nextcloudClient).resultData as RemoteFile assertFalse("File shouldn't be locked", initialFile.isLocked) // lock file val lockResult = ToggleFileLockRemoteOperation(toLock = true, remotePath).execute(nextcloudClient) + + // check if file locking is enabled (files_lock app needs to be installed) + assumeTrue(lockResult.httpCode != HTTP_NOT_IMPLEMENTED) + assertTrue("File lock failed", lockResult.isSuccess) - val lockFile = ReadFileRemoteOperation(remotePath).execute(client).singleData as RemoteFile + val lockFile = ReadFileRemoteOperation(remotePath).execute(nextcloudClient).resultData as RemoteFile assertTrue("File should be locked", lockFile.isLocked) assertEquals("Wrong lock type", FileLockType.MANUAL, lockFile.lockType) // unlock again val unlockResult = ToggleFileLockRemoteOperation(toLock = false, remotePath).execute(nextcloudClient) assertTrue("File unlock failed", unlockResult.isSuccess) - val unlockFile = ReadFileRemoteOperation(remotePath).execute(client).singleData as RemoteFile + val unlockFile = ReadFileRemoteOperation(remotePath).execute(nextcloudClient).resultData as RemoteFile assertFalse("File shouldn't be locked", unlockFile.isLocked) } } diff --git a/library/src/androidTest/java/com/nextcloud/android/lib/resources/groupfolders/GetGroupfoldersRemoteOperationIT.kt b/library/src/androidTest/java/com/nextcloud/android/lib/resources/groupfolders/GetGroupfoldersRemoteOperationIT.kt index eee4c57ff..18949d096 100644 --- a/library/src/androidTest/java/com/nextcloud/android/lib/resources/groupfolders/GetGroupfoldersRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/nextcloud/android/lib/resources/groupfolders/GetGroupfoldersRemoteOperationIT.kt @@ -9,7 +9,6 @@ package com.nextcloud.android.lib.resources.groupfolders import com.owncloud.android.AbstractIT import com.owncloud.android.lib.resources.status.GetCapabilitiesRemoteOperation -import com.owncloud.android.lib.resources.status.OCCapability import org.junit.Assert.assertEquals import org.junit.Assume.assumeTrue import org.junit.Test @@ -17,12 +16,12 @@ import org.junit.Test class GetGroupfoldersRemoteOperationIT : AbstractIT() { @Test fun getGroupfolders() { - val capability = GetCapabilitiesRemoteOperation().execute(client).singleData as OCCapability + val capability = GetCapabilitiesRemoteOperation().execute(nextcloudClient).resultData - assumeTrue(capability.groupfolders.isTrue) + assumeTrue(capability?.groupfolders?.isTrue == true) val map = GetGroupfoldersRemoteOperation().execute(nextcloudClient).resultData - assertEquals(1, map.size) - assertEquals("groupfolder", map["1"]?.mountPoint) + assertEquals(1, map?.size) + assertEquals("groupfolder", map?.get("1")?.mountPoint) } } diff --git a/library/src/androidTest/java/com/nextcloud/android/lib/resources/search/SearchProvidersRemoteOperationIT.kt b/library/src/androidTest/java/com/nextcloud/android/lib/resources/search/SearchProvidersRemoteOperationIT.kt index f1f6c9ebf..ddd582c3c 100644 --- a/library/src/androidTest/java/com/nextcloud/android/lib/resources/search/SearchProvidersRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/nextcloud/android/lib/resources/search/SearchProvidersRemoteOperationIT.kt @@ -9,7 +9,6 @@ package com.nextcloud.android.lib.resources.search import com.owncloud.android.AbstractIT import com.owncloud.android.lib.resources.status.GetCapabilitiesRemoteOperation -import com.owncloud.android.lib.resources.status.OCCapability import com.owncloud.android.lib.resources.status.OwnCloudVersion import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull @@ -28,22 +27,18 @@ class SearchProvidersRemoteOperationIT : AbstractIT() { assertTrue(result.isSuccess) val providers = result.resultData - - assertTrue(providers.eTag.isNotBlank()) - assertTrue(providers.providers.isNotEmpty()) - assertNotNull(providers.providers.find { it.name == "Files" }) - assertNull(providers.providers.find { it.name == "RandomSearchProvider" }) + assertTrue(providers?.eTag?.isNotBlank() == true) + assertNotNull(providers?.providers) + assertTrue(providers?.providers?.isNotEmpty() == true) + assertNotNull(providers?.providers?.find { it.name == "Files" }) + assertNull(providers?.providers?.find { it.name == "RandomSearchProvider" }) } @Test fun getSearchProvidersOnOldServer() { // only on < NC20 - val ocCapability = - GetCapabilitiesRemoteOperation() - .execute(nextcloudClient).singleData as OCCapability - assumeTrue( - ocCapability.version.isOlderThan(OwnCloudVersion.nextcloud_20) - ) + val ocCapability = GetCapabilitiesRemoteOperation().execute(nextcloudClient).resultData + assumeTrue(ocCapability?.version?.isOlderThan(OwnCloudVersion.nextcloud_20) == true) val result = nextcloudClient.execute(UnifiedSearchProvidersRemoteOperation()) assertFalse(result.isSuccess) diff --git a/library/src/androidTest/java/com/nextcloud/android/lib/resources/search/UnifiedSearchRemoteOperationIT.kt b/library/src/androidTest/java/com/nextcloud/android/lib/resources/search/UnifiedSearchRemoteOperationIT.kt index 5f78c913c..449079d57 100644 --- a/library/src/androidTest/java/com/nextcloud/android/lib/resources/search/UnifiedSearchRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/nextcloud/android/lib/resources/search/UnifiedSearchRemoteOperationIT.kt @@ -10,7 +10,6 @@ package com.nextcloud.android.lib.resources.search import com.owncloud.android.AbstractIT import com.owncloud.android.lib.resources.files.CreateFolderRemoteOperation import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation -import com.owncloud.android.lib.resources.files.model.RemoteFile import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull @@ -36,28 +35,25 @@ class UnifiedSearchRemoteOperationIT : AbstractIT() { fun filesSearchEmptyResult() { val result = UnifiedSearchRemoteOperation("files", "test").execute(nextcloudClient) assertTrue(result.isSuccess) - - val data = result.resultData - assertTrue(data.entries.isEmpty()) + assertNotNull(result.resultData) + assertTrue(result.resultData?.entries?.isEmpty() == true) } @Test fun filesSearch() { val remotePath = "/testFolder" - assertTrue(CreateFolderRemoteOperation(remotePath, true).execute(client).isSuccess) - val remoteFile = - ReadFileRemoteOperation(remotePath) - .execute(client).data[0] as RemoteFile - val fileId = remoteFile.localId + assertTrue(CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient).isSuccess) + val remoteFile = ReadFileRemoteOperation(remotePath).execute(nextcloudClient).resultData + val fileId = remoteFile?.localId val result = UnifiedSearchRemoteOperation("files", "test").execute(nextcloudClient) assertTrue(result.isSuccess) val data = result.resultData - assertEquals("Files", data.name) - assertTrue(data.entries.isNotEmpty()) + assertEquals("Files", data?.name) + assertTrue(data?.entries?.isNotEmpty() == true) - val firstResult = data.entries.find { it.title == "testFolder" } + val firstResult = data?.entries?.find { it.title == "testFolder" } assertNotNull(firstResult) assertEquals(remotePath, firstResult?.remotePath()) @@ -66,14 +62,14 @@ class UnifiedSearchRemoteOperationIT : AbstractIT() { @Test fun filesSearchWhitespace() { - assertTrue(CreateFolderRemoteOperation("/test Folder/", true).execute(client).isSuccess) + assertTrue(CreateFolderRemoteOperation("/test Folder/", true).execute(nextcloudClient).isSuccess) val result = UnifiedSearchRemoteOperation("files", "test").execute(nextcloudClient) assertTrue(result.isSuccess) val data = result.resultData - assertTrue(data.name == "Files") - assertTrue(data.entries.isNotEmpty()) - assertNotNull(data.entries.find { it.title == "test Folder" }) + assertTrue(data?.name == "Files") + assertTrue(data?.entries?.isNotEmpty() == true) + assertNotNull(data?.entries?.find { it.title == "test Folder" }) } } diff --git a/library/src/androidTest/java/com/nextcloud/android/lib/resources/users/GenerateAppPasswordRemoteOperationIT.java b/library/src/androidTest/java/com/nextcloud/android/lib/resources/users/GenerateAppPasswordRemoteOperationIT.java index f220d3fc4..93e4bbf23 100644 --- a/library/src/androidTest/java/com/nextcloud/android/lib/resources/users/GenerateAppPasswordRemoteOperationIT.java +++ b/library/src/androidTest/java/com/nextcloud/android/lib/resources/users/GenerateAppPasswordRemoteOperationIT.java @@ -14,36 +14,35 @@ import android.text.TextUtils; import com.owncloud.android.AbstractIT; -import com.owncloud.android.lib.common.OwnCloudBasicCredentials; -import com.owncloud.android.lib.common.OwnCloudCredentials; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.resources.files.ReadFolderRemoteOperation; import org.junit.Test; +import okhttp3.Credentials; + public class GenerateAppPasswordRemoteOperationIT extends AbstractIT { @Test public void generateAppPassword() { GenerateAppPasswordRemoteOperation sut = new GenerateAppPasswordRemoteOperation(); - RemoteOperationResult result = sut.execute(client); + RemoteOperationResult result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); - String appPassword = (String) result.getSingleData(); + String appPassword = result.getResultData(); assertFalse(TextUtils.isEmpty(appPassword)); - OwnCloudCredentials oldOwnCloudCredentials = client.getCredentials(); - OwnCloudCredentials newOwnCloudCredentials = new OwnCloudBasicCredentials(oldOwnCloudCredentials.getUsername(), - appPassword); + String clientCredentials = nextcloudClient.getCredentials(); + String newClientCredentials = Credentials.basic(nextcloudClient.getUserId(), appPassword); - assertNotEquals(oldOwnCloudCredentials, newOwnCloudCredentials); + assertNotEquals(clientCredentials, newClientCredentials); - client.setCredentials(newOwnCloudCredentials); + nextcloudClient.setCredentials(newClientCredentials); - assertTrue(new ReadFolderRemoteOperation("/").execute(client).isSuccess()); + assertTrue(new ReadFolderRemoteOperation("/").execute(nextcloudClient).isSuccess()); // using app password to generate new password should fail - assertFalse(new GenerateAppPasswordRemoteOperation().execute(client).isSuccess()); + assertFalse(new GenerateAppPasswordRemoteOperation().execute(nextcloudClient).isSuccess()); } } diff --git a/library/src/androidTest/java/com/nextcloud/android/lib/richWorkspace/RichWorkspaceDirectEditingRemoteOperationIT.java b/library/src/androidTest/java/com/nextcloud/android/lib/richWorkspace/RichWorkspaceDirectEditingRemoteOperationIT.java index 8d4d2f8c3..3dd186119 100644 --- a/library/src/androidTest/java/com/nextcloud/android/lib/richWorkspace/RichWorkspaceDirectEditingRemoteOperationIT.java +++ b/library/src/androidTest/java/com/nextcloud/android/lib/richWorkspace/RichWorkspaceDirectEditingRemoteOperationIT.java @@ -39,7 +39,7 @@ public void getEditLinkForRoot() { public void getEditLinkForFolder() { String path = "/workspace/sub1/"; - assertTrue(new CreateFolderRemoteOperation(path, true).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); RemoteOperationResult result = new RichWorkspaceDirectEditingRemoteOperation(path).execute(client); assertTrue(result.isSuccess()); @@ -56,7 +56,7 @@ public void reuseExistingFile() throws IOException { String filePath = folder + "Readme.md"; File txtFile = getFile(ASSETS__TEXT_FILE_NAME); - assertTrue(new CreateFolderRemoteOperation(folder, true).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation(folder, true).execute(nextcloudClient).isSuccess()); RemoteOperationResult uploadResult = new UploadFileRemoteOperation( txtFile.getAbsolutePath(), diff --git a/library/src/androidTest/java/com/nextcloud/lib/resources/users/GetActivitiesRemoteOperationIT.kt b/library/src/androidTest/java/com/nextcloud/lib/resources/users/GetActivitiesRemoteOperationIT.kt index 0b1be6245..97631e8ff 100644 --- a/library/src/androidTest/java/com/nextcloud/lib/resources/users/GetActivitiesRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/nextcloud/lib/resources/users/GetActivitiesRemoteOperationIT.kt @@ -9,8 +9,8 @@ package com.nextcloud.lib.resources.users import com.owncloud.android.AbstractIT import com.owncloud.android.lib.resources.activities.GetActivitiesRemoteOperation -import com.owncloud.android.lib.resources.activities.model.Activity import com.owncloud.android.lib.resources.files.CreateFolderRemoteOperation +import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue import org.junit.Test @@ -18,13 +18,14 @@ class GetActivitiesRemoteOperationIT : AbstractIT() { @Test fun getActivities() { // set-up, create a folder so there is an activity - assertTrue(CreateFolderRemoteOperation("/test/123/1", true).execute(client).isSuccess) + assertTrue(CreateFolderRemoteOperation("/test/123/1", true).execute(nextcloudClient).isSuccess) val result = nextcloudClient.execute(GetActivitiesRemoteOperation()) assertTrue(result.isSuccess) + assertNotNull(result.resultData) - val activities = result.data[0] as ArrayList - val lastGiven = result.data[1] as Integer + val activities = result.resultData!!.first + val lastGiven = result.resultData!!.second assertTrue(activities.isNotEmpty()) assertTrue(lastGiven > 0) diff --git a/library/src/androidTest/java/com/nextcloud/lib/resources/users/GetUserInfoRemoteOperationIT.kt b/library/src/androidTest/java/com/nextcloud/lib/resources/users/GetUserInfoRemoteOperationIT.kt index edda2244a..4617888ab 100644 --- a/library/src/androidTest/java/com/nextcloud/lib/resources/users/GetUserInfoRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/nextcloud/lib/resources/users/GetUserInfoRemoteOperationIT.kt @@ -24,9 +24,9 @@ class GetUserInfoRemoteOperationIT : AbstractIT() { assertTrue(userInfoResult.isSuccess) val userInfo = userInfoResult.resultData - assertEquals("User One", userInfo.displayName) - assertEquals("user1", userInfo.id) - assertEquals(GetUserInfoRemoteOperation.SPACE_UNLIMITED, userInfo.quota?.quota) + assertEquals("User One", userInfo?.displayName) + assertEquals("user1", userInfo?.id) + assertEquals(GetUserInfoRemoteOperation.SPACE_UNLIMITED, userInfo?.quota?.quota) } @Test @@ -36,9 +36,9 @@ class GetUserInfoRemoteOperationIT : AbstractIT() { assertTrue(userInfoResult.isSuccess) val userInfo = userInfoResult.resultData - assertEquals("User Two", userInfo.displayName) - assertEquals("user2", userInfo.id) - assertEquals(QUOTA_1GB, userInfo.quota?.quota) + assertEquals("User Two", userInfo?.displayName) + assertEquals("user2", userInfo?.id) + assertEquals(QUOTA_1GB, userInfo?.quota?.quota) } @After diff --git a/library/src/androidTest/java/com/owncloud/android/AbstractIT.java b/library/src/androidTest/java/com/owncloud/android/AbstractIT.java index 629747cce..38a322066 100644 --- a/library/src/androidTest/java/com/owncloud/android/AbstractIT.java +++ b/library/src/androidTest/java/com/owncloud/android/AbstractIT.java @@ -9,6 +9,7 @@ import static junit.framework.TestCase.assertTrue; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; @@ -53,6 +54,7 @@ import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.util.List; import okhttp3.Credentials; @@ -70,6 +72,7 @@ public abstract class AbstractIT { public static OwnCloudClient client; public static OwnCloudClient client2; protected static NextcloudClient nextcloudClient; + protected static NextcloudClient nextcloudClient2; protected static Context context; protected static Uri url; @@ -109,6 +112,10 @@ public static void beforeAll() throws InterruptedException, String credentials = Credentials.basic(loginName, password); nextcloudClient = new NextcloudClient(url, userId, credentials, context); + String userId2 = loginName2; // for test same as userId + String credentials2 = Credentials.basic(loginName2, password2); + nextcloudClient2 = new NextcloudClient(url, userId2, credentials2, context); + waitForServer(client, url); testConnection(); } @@ -259,17 +266,16 @@ public static File extractAsset(String fileName, Context context) throws IOExcep @After public void after() { - removeOnClient(client); - removeOnClient(client2); + removeOnClient(nextcloudClient); + removeOnClient(nextcloudClient2); } - private void removeOnClient(OwnCloudClient client) { - RemoteOperationResult result = new ReadFolderRemoteOperation("/").execute(client); + private void removeOnClient(NextcloudClient client) { + RemoteOperationResult> result = new ReadFolderRemoteOperation("/").execute(client); assertTrue(result.getLogMessage(), result.isSuccess()); + assertNotNull(result.getResultData()); - for (Object object : result.getData()) { - RemoteFile remoteFile = (RemoteFile) object; - + for (RemoteFile remoteFile : result.getResultData()) { if (!"/".equals(remoteFile.getRemotePath()) && remoteFile.getMountType() != WebdavEntry.MountType.GROUP) { if (remoteFile.isEncrypted()) { @@ -277,12 +283,12 @@ private void removeOnClient(OwnCloudClient client) { remoteFile.getLocalId(), remoteFile.getRemotePath(), false) - .execute(client) + .execute(nextcloudClient) .isSuccess()); } assertTrue("Failed to remove " + remoteFile.getRemotePath(), - new RemoveFileRemoteOperation(remoteFile.getRemotePath()).execute(client).isSuccess()); + new RemoveFileRemoteOperation(remoteFile.getRemotePath()).execute(nextcloudClient).isSuccess()); } } @@ -315,9 +321,8 @@ protected void longSleep() { } protected void testOnlyOnServer(OwnCloudVersion version) { - OCCapability ocCapability = (OCCapability) new GetCapabilitiesRemoteOperation() - .execute(nextcloudClient) - .getSingleData(); + OCCapability ocCapability = new GetCapabilitiesRemoteOperation().execute(nextcloudClient).getResultData(); + assumeTrue(ocCapability != null); assumeTrue(ocCapability.getVersion().isNewerOrEqual(version)); } } diff --git a/library/src/androidTest/java/com/owncloud/android/CopyFileIT.java b/library/src/androidTest/java/com/owncloud/android/CopyFileIT.java index 7995043b1..18058a873 100644 --- a/library/src/androidTest/java/com/owncloud/android/CopyFileIT.java +++ b/library/src/androidTest/java/com/owncloud/android/CopyFileIT.java @@ -160,7 +160,7 @@ public void createFixtures() throws Exception { RemoteOperationResult result; for (String folderPath : FOLDERS_IN_FIXTURE) { - result = new CreateFolderRemoteOperation(folderPath, true).execute(client); + result = new CreateFolderRemoteOperation(folderPath, true).execute(nextcloudClient); assertTrue("Error creating folder" + folderPath + ": " + result, result.isSuccess()); } @@ -186,7 +186,7 @@ public void deleteFixtures() { String[] folders = new String[]{SRC_BASE_FOLDER, TARGET_BASE_FOLDER}; for (String folder : folders) { - RemoteOperationResult result = new RemoveFileRemoteOperation(folder).execute(client); + RemoteOperationResult result = new RemoveFileRemoteOperation(folder).execute(nextcloudClient); assertTrue("Error removing folder " + folder + ": " + result, result.isSuccess()); } diff --git a/library/src/androidTest/java/com/owncloud/android/CreateFolderRemoteOperationIT.java b/library/src/androidTest/java/com/owncloud/android/CreateFolderRemoteOperationIT.java index a8ed202c8..304b9c387 100644 --- a/library/src/androidTest/java/com/owncloud/android/CreateFolderRemoteOperationIT.java +++ b/library/src/androidTest/java/com/owncloud/android/CreateFolderRemoteOperationIT.java @@ -7,7 +7,9 @@ */ package com.owncloud.android; +import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import com.nextcloud.test.RandomStringGenerator; @@ -56,27 +58,45 @@ public void setUp() { public void testCreateFolder() { String remotePath = mFullPath2FolderBase; mCreatedFolderPaths.add(remotePath); - RemoteOperationResult result = new CreateFolderRemoteOperation(remotePath, true).execute(client); + RemoteOperationResult result = new CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient); assertTrue(result.isSuccess()); // Create Subfolder remotePath = mFullPath2FolderBase + FOLDER_PATH_BASE; mCreatedFolderPaths.add(remotePath); - result = new CreateFolderRemoteOperation(remotePath, true).execute(client); + result = new CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient); assertTrue(result.isSuccess()); } + /** + * Test duplicate Folder + */ + @Test + public void testCreateDuplicateFolder() { + String remotePath = mFullPath2FolderBase + "duplicateFolder"; + mCreatedFolderPaths.add(remotePath); + RemoteOperationResult result = new CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient); + assertTrue(result.isSuccess()); + + // Create folder again + remotePath = mFullPath2FolderBase + "duplicateFolder"; + mCreatedFolderPaths.add(remotePath); + result = new CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient); + assertFalse(result.isSuccess()); + assertEquals(FOLDER_ALREADY_EXISTS, result.getCode()); + } + @Test public void testFileID() { String remotePath = mFullPath2FolderBase + "/" + RandomStringGenerator.make(TAG_LENGTH); mCreatedFolderPaths.add(remotePath); - RemoteOperationResult result = new CreateFolderRemoteOperation(remotePath, true).execute(client); + RemoteOperationResult result = new CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient); assertTrue(result.isSuccess()); - RemoteOperationResult readResult = new ReadFileRemoteOperation(remotePath).execute(client); + RemoteOperationResult readResult = new ReadFileRemoteOperation(remotePath).execute(nextcloudClient); assertTrue(readResult.isSuccess()); - String remoteId = ((RemoteFile) readResult.getData().get(0)).getRemoteId(); + String remoteId = readResult.getResultData().getRemoteId(); assertEquals(result.getResultData(), remoteId); } @@ -87,31 +107,31 @@ public void testFileID() { @Test public void testCreateFolderSpecialCharactersOnNewVersion() { String remotePath = mFullPath2FolderBase + "_<"; - RemoteOperationResult result = new CreateFolderRemoteOperation(remotePath, true).execute(client); + RemoteOperationResult result = new CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient); assertTrue("Remote path: " + remotePath, result.isSuccess()); remotePath = mFullPath2FolderBase + "_>"; - result = new CreateFolderRemoteOperation(remotePath, true).execute(client); + result = new CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient); assertTrue("Remote path: " + remotePath, result.isSuccess()); remotePath = mFullPath2FolderBase + "_:"; - result = new CreateFolderRemoteOperation(remotePath, true).execute(client); + result = new CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient); assertTrue("Remote path: " + remotePath, result.isSuccess()); remotePath = mFullPath2FolderBase + "_\""; - result = new CreateFolderRemoteOperation(remotePath, true).execute(client); + result = new CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient); assertTrue("Remote path: " + remotePath, result.isSuccess()); remotePath = mFullPath2FolderBase + "_|"; - result = new CreateFolderRemoteOperation(remotePath, true).execute(client); + result = new CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient); assertTrue("Remote path: " + remotePath, result.isSuccess()); remotePath = mFullPath2FolderBase + "_?"; - result = new CreateFolderRemoteOperation(remotePath, true).execute(client); + result = new CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient); assertTrue("Remote path: " + remotePath, result.isSuccess()); remotePath = mFullPath2FolderBase + "_*"; - result = new CreateFolderRemoteOperation(remotePath, true).execute(client); + result = new CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient); assertTrue("Remote path: " + remotePath, result.isSuccess()); } @@ -127,7 +147,7 @@ public void tearDown() { RemoteOperationResult result = existenceCheckOperation.execute(client); if (result.isSuccess()) { - removeResult = new RemoveFileRemoteOperation(path).execute(client); + removeResult = new RemoveFileRemoteOperation(path).execute(nextcloudClient); assertTrue("Error removing folder " + path + ":" + removeResult, removeResult.isSuccess()); } diff --git a/library/src/androidTest/java/com/owncloud/android/DeleteFileIT.java b/library/src/androidTest/java/com/owncloud/android/DeleteFileIT.java index 9c264ceb4..d43d9bbe7 100644 --- a/library/src/androidTest/java/com/owncloud/android/DeleteFileIT.java +++ b/library/src/androidTest/java/com/owncloud/android/DeleteFileIT.java @@ -38,7 +38,7 @@ public void setUp() throws Exception { mFullPath2Folder = baseFolderPath + FOLDER_PATH; mFullPath2File = baseFolderPath + FILE_PATH; - RemoteOperationResult result = new CreateFolderRemoteOperation(mFullPath2Folder, true).execute(client); + RemoteOperationResult result = new CreateFolderRemoteOperation(mFullPath2Folder, true).execute(nextcloudClient); assertTrue("Error creating folder" + mFullPath2Folder + ": " + result, result.isSuccess()); File textFile = getFile(ASSETS__TEXT_FILE_NAME); @@ -56,7 +56,7 @@ public void setUp() throws Exception { */ @Test public void testRemoveFolder() { - RemoteOperationResult result = new RemoveFileRemoteOperation(mFullPath2Folder).execute(client); + RemoteOperationResult result = new RemoveFileRemoteOperation(mFullPath2Folder).execute(nextcloudClient); assertTrue(result.isSuccess()); } @@ -65,13 +65,13 @@ public void testRemoveFolder() { */ @Test public void testRemoveFile() { - RemoteOperationResult result = new RemoveFileRemoteOperation(mFullPath2File).execute(client); + RemoteOperationResult result = new RemoveFileRemoteOperation(mFullPath2File).execute(nextcloudClient); assertTrue(result.isSuccess()); } @After public void deleteFixtures() { - RemoteOperationResult result = new RemoveFileRemoteOperation(baseFolderPath).execute(client); + RemoteOperationResult result = new RemoveFileRemoteOperation(baseFolderPath).execute(nextcloudClient); assertTrue("Error removing folder " + baseFolderPath + ": " + result, result.isSuccess()); } diff --git a/library/src/androidTest/java/com/owncloud/android/FileIT.java b/library/src/androidTest/java/com/owncloud/android/FileIT.java index 2cadacc7c..cd0fffa67 100644 --- a/library/src/androidTest/java/com/owncloud/android/FileIT.java +++ b/library/src/androidTest/java/com/owncloud/android/FileIT.java @@ -9,6 +9,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.net.Uri; @@ -29,6 +30,7 @@ import org.junit.Test; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -40,13 +42,14 @@ public void testCreateFolderSuccess() { String path = "/testFolder/"; // create folder - assertTrue(new CreateFolderRemoteOperation(path, true).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); // verify folder - assertTrue(new ReadFolderRemoteOperation(path).execute(client).isSuccess()); + assertTrue(new ReadFolderRemoteOperation(path).execute(nextcloudClient).isSuccess()); + assertTrue(new ReadFolderRemoteOperation(path).execute(nextcloudClient).isSuccess()); // remove folder - assertTrue(new RemoveFileRemoteOperation(path).execute(client).isSuccess()); + assertTrue(new RemoveFileRemoteOperation(path).execute(nextcloudClient).isSuccess()); } @Test @@ -54,13 +57,13 @@ public void testCreateFolderFailure() { String path = "/testFolder/"; // create folder - assertTrue(new CreateFolderRemoteOperation(path, true).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); // create folder a second time will fail - assertFalse(new CreateFolderRemoteOperation(path, true).execute(client).isSuccess()); + assertFalse(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); // remove folder - assertTrue(new RemoveFileRemoteOperation(path).execute(client).isSuccess()); + assertTrue(new RemoveFileRemoteOperation(path).execute(nextcloudClient).isSuccess()); } @Test @@ -68,46 +71,48 @@ public void testCreateNonExistingSubFolder() { String path = "/testFolder/1/2/3/4/5/"; String top = "/testFolder/"; - assertTrue(new CreateFolderRemoteOperation(path, true).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); // verify folder - assertTrue(new ReadFolderRemoteOperation(path).execute(client).isSuccess()); + assertTrue(new ReadFolderRemoteOperation(path).execute(nextcloudClient).isSuccess()); // remove folder - assertTrue(new RemoveFileRemoteOperation(top).execute(client).isSuccess()); + assertTrue(new RemoveFileRemoteOperation(top).execute(nextcloudClient).isSuccess()); } @Test public void testCreateFolderWithWrongURL() { String path = "/testFolder/"; - Uri uri = client.getBaseUri(); - client.setBaseUri(Uri.parse(uri.toString() + "/remote.php/dav/files/")); + Uri uri = nextcloudClient.getBaseUri(); + assertNotNull(uri); + nextcloudClient.setBaseUri(Uri.parse(uri + "/remote.php/dav/files/")); // create folder - assertFalse(new CreateFolderRemoteOperation(path, true).execute(client).isSuccess()); + assertFalse(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); - client.setBaseUri(uri); + nextcloudClient.setBaseUri(uri); } @Test public void testZeroSharees() { // create & verify folder String path = "/testFolder/"; - assertTrue(new CreateFolderRemoteOperation(path, true).execute(client).isSuccess()); - assertTrue(new ReadFolderRemoteOperation(path).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); + assertTrue(new ReadFolderRemoteOperation(path).execute(nextcloudClient).isSuccess()); // verify - RemoteOperationResult result = new ReadFolderRemoteOperation("/").execute(client); + RemoteOperationResult> result = new ReadFolderRemoteOperation("/").execute(nextcloudClient); assertTrue(result.isSuccess()); - RemoteFile parentFolder = (RemoteFile) result.getData().get(0); - assertEquals("/", parentFolder.getRemotePath()); + List resultData = result.getResultData(); + assertNotNull(resultData); + assertEquals("/", resultData.get(0).getRemotePath()); - for (int i = 1; i < result.getData().size(); i++) { - RemoteFile child = (RemoteFile) result.getData().get(i); - - if (path.equals(child.getRemotePath())) { - assertEquals(0, child.getSharees().length); + for (RemoteFile remoteFile : resultData) { + if (path.equals(remoteFile.getRemotePath())) { + assertNotNull(remoteFile.getSharees()); + assertEquals(0, remoteFile.getSharees().length); + break; } } } @@ -116,8 +121,8 @@ public void testZeroSharees() { public void testShareViaLinkSharees() { // create & verify folder String path = "/testFolder/"; - assertTrue(new CreateFolderRemoteOperation(path, true).execute(client).isSuccess()); - assertTrue(new ReadFolderRemoteOperation(path).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); + assertTrue(new ReadFolderRemoteOperation(path).execute(nextcloudClient).isSuccess()); // share folder assertTrue(new CreateShareRemoteOperation(path, @@ -129,33 +134,32 @@ public void testShareViaLinkSharees() { .execute(client).isSuccess()); // verify - RemoteOperationResult result = new ReadFolderRemoteOperation("/").execute(client); + RemoteOperationResult> result = new ReadFolderRemoteOperation(path).execute(nextcloudClient); assertTrue(result.isSuccess()); - RemoteFile parentFolder = (RemoteFile) result.getData().get(0); - assertEquals("/", parentFolder.getRemotePath()); - - for (int i = 1; i < result.getData().size(); i++) { - RemoteFile child = (RemoteFile) result.getData().get(i); + List resultData = result.getResultData(); + assertNotNull(resultData); + assertEquals(path, resultData.get(0).getRemotePath()); - if (path.equals(child.getRemotePath())) { - assertEquals(0, child.getSharees().length); - } - } + ShareeUser[] sharees = resultData.get(0).getSharees(); + assertNotNull(sharees); + assertEquals(0, sharees.length); } @Test public void testShareToGroupSharees() { // create & verify folder String path = "/testFolder/"; - assertTrue(new CreateFolderRemoteOperation(path, true).execute(client).isSuccess()); - assertTrue(new ReadFolderRemoteOperation(path).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); + assertTrue(new ReadFolderRemoteOperation(path).execute(nextcloudClient).isSuccess()); ShareeUser sharee = new ShareeUser("users", "", ShareType.GROUP); // only on NC26+ - OCCapability ocCapability = (OCCapability) new GetCapabilitiesRemoteOperation() - .execute(nextcloudClient).getSingleData(); + OCCapability ocCapability = new GetCapabilitiesRemoteOperation().execute(nextcloudClient).getResultData(); + + assertNotNull(ocCapability); + if (ocCapability.getVersion().isNewerOrEqual(NextcloudVersion.nextcloud_26)) { sharee.setDisplayName("users"); } @@ -170,18 +174,18 @@ public void testShareToGroupSharees() { .execute(client).isSuccess()); // verify - RemoteOperationResult result = new ReadFolderRemoteOperation("/").execute(client); + RemoteOperationResult> result = new ReadFolderRemoteOperation("/").execute(nextcloudClient); assertTrue(result.isSuccess()); - RemoteFile parentFolder = (RemoteFile) result.getData().get(0); - assertEquals("/", parentFolder.getRemotePath()); - - for (int i = 1; i < result.getData().size(); i++) { - RemoteFile child = (RemoteFile) result.getData().get(i); + List resultData = result.getResultData(); + assertNotNull(resultData); + assertEquals("/", resultData.get(0).getRemotePath()); - if (path.equals(child.getRemotePath())) { - assertEquals(1, child.getSharees().length); - assertEquals(sharee, child.getSharees()[0]); + for (RemoteFile remoteFile : resultData) { + if (path.equals(remoteFile.getRemotePath())) { + assertNotNull(remoteFile.getSharees()); + assertEquals(1, remoteFile.getSharees().length); + assertEquals(sharee, remoteFile.getSharees()[0]); } } } @@ -190,8 +194,8 @@ public void testShareToGroupSharees() { public void testOneSharees() { // create & verify folder String path = "/testFolder/"; - assertTrue(new CreateFolderRemoteOperation(path, true).execute(client).isSuccess()); - assertTrue(new ReadFolderRemoteOperation(path).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); + assertTrue(new ReadFolderRemoteOperation(path).execute(nextcloudClient).isSuccess()); ShareeUser sharee = new ShareeUser("user1", "User One", ShareType.USER); @@ -205,18 +209,18 @@ public void testOneSharees() { .execute(client).isSuccess()); // verify - RemoteOperationResult result = new ReadFolderRemoteOperation("/").execute(client); + RemoteOperationResult> result = new ReadFolderRemoteOperation("/").execute(nextcloudClient); assertTrue(result.isSuccess()); - RemoteFile parentFolder = (RemoteFile) result.getData().get(0); - assertEquals("/", parentFolder.getRemotePath()); + List resultData = result.getResultData(); + assertNotNull(resultData); + assertEquals("/", resultData.get(0).getRemotePath()); - for (int i = 1; i < result.getData().size(); i++) { - RemoteFile child = (RemoteFile) result.getData().get(i); - - if (path.equals(child.getRemotePath())) { - assertEquals(1, child.getSharees().length); - assertEquals(sharee, child.getSharees()[0]); + for (RemoteFile remoteFile : resultData) { + if (path.equals(remoteFile.getRemotePath())) { + assertNotNull(remoteFile.getSharees()); + assertEquals(1, remoteFile.getSharees().length); + assertEquals(sharee, remoteFile.getSharees()[0]); } } } @@ -225,8 +229,8 @@ public void testOneSharees() { public void testTwoShareesOnParent() { // create & verify folder String path = "/testFolder/"; - assertTrue(new CreateFolderRemoteOperation(path, true).execute(client).isSuccess()); - assertTrue(new ReadFolderRemoteOperation(path).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); + assertTrue(new ReadFolderRemoteOperation(path).execute(nextcloudClient).isSuccess()); List sharees = new ArrayList<>(); sharees.add(new ShareeUser("user1", "User One", ShareType.USER)); @@ -250,21 +254,19 @@ public void testTwoShareesOnParent() { .execute(client).isSuccess()); // verify - RemoteOperationResult result = new ReadFolderRemoteOperation("/").execute(client); + RemoteOperationResult> result = new ReadFolderRemoteOperation("/").execute(nextcloudClient); assertTrue(result.isSuccess()); - RemoteFile parentFolder = (RemoteFile) result.getData().get(0); - assertEquals("/", parentFolder.getRemotePath()); - - for (int i = 1; i < result.getData().size(); i++) { - RemoteFile child = (RemoteFile) result.getData().get(i); + List resultData = result.getResultData(); + assertNotNull(resultData); + assertEquals("/", resultData.get(0).getRemotePath()); - if (path.equals(child.getRemotePath())) { - assertEquals(2, child.getSharees().length); + for (RemoteFile remoteFile : resultData) { + if (path.equals(remoteFile.getRemotePath())) { + assertNotNull(remoteFile.getSharees()); + assertEquals(2, remoteFile.getSharees().length); - for (ShareeUser user : child.getSharees()) { - assertTrue(sharees.contains(user)); - } + assertTrue(sharees.containsAll(Arrays.asList(remoteFile.getSharees()))); } } } @@ -273,8 +275,8 @@ public void testTwoShareesOnParent() { public void testTwoSharees() { // create & verify folder String path = "/testFolder/"; - assertTrue(new CreateFolderRemoteOperation(path, true).execute(client).isSuccess()); - assertTrue(new ReadFolderRemoteOperation(path).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); + assertTrue(new ReadFolderRemoteOperation(path).execute(nextcloudClient).isSuccess()); List sharees = new ArrayList<>(); sharees.add(new ShareeUser("user1", "User One", ShareType.USER)); @@ -298,11 +300,14 @@ public void testTwoSharees() { .execute(client).isSuccess()); // verify - RemoteOperationResult result = new ReadFolderRemoteOperation(path).execute(client); + RemoteOperationResult> result = new ReadFolderRemoteOperation(path).execute(nextcloudClient); assertTrue(result.isSuccess()); + assertNotNull(result.getResultData()); - RemoteFile folder = (RemoteFile) result.getData().get(0); + RemoteFile folder = result.getResultData().get(0); + assertNotNull(folder); assertEquals(path, folder.getRemotePath()); + assertNotNull(folder.getSharees()); assertEquals(2, folder.getSharees().length); for (ShareeUser user : folder.getSharees()) { @@ -314,14 +319,16 @@ public void testTwoSharees() { public void testLocalID() { // create & verify folder String path = "/testFolder/"; - assertTrue(new CreateFolderRemoteOperation(path, true).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); - RemoteOperationResult result = new ReadFolderRemoteOperation(path).execute(client); + RemoteOperationResult> result = new ReadFolderRemoteOperation(path).execute(nextcloudClient); assertTrue(result.isSuccess()); + assertNotNull(result.getResultData()); - RemoteFile folder = (RemoteFile) result.getData().get(0); + RemoteFile folder = result.getResultData().get(0); // we do this only here for testing, this might not work on large installations + assertNotNull(folder.getRemoteId()); int localId = Integer.parseInt(folder.getRemoteId().substring(0, 8).replaceAll("^0*", "")); assertEquals(folder.getLocalId(), localId); diff --git a/library/src/androidTest/java/com/owncloud/android/GetCapabilitiesRemoteOperationIT.java b/library/src/androidTest/java/com/owncloud/android/GetCapabilitiesRemoteOperationIT.java index 5445234be..e1416b203 100644 --- a/library/src/androidTest/java/com/owncloud/android/GetCapabilitiesRemoteOperationIT.java +++ b/library/src/androidTest/java/com/owncloud/android/GetCapabilitiesRemoteOperationIT.java @@ -9,6 +9,13 @@ */ package com.owncloud.android; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.resources.status.CapabilityBooleanType; import com.owncloud.android.lib.resources.status.E2EVersion; @@ -19,13 +26,6 @@ import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - /** * Class to test GetRemoteCapabilitiesOperation */ @@ -36,28 +36,26 @@ public class GetCapabilitiesRemoteOperationIT extends AbstractIT { @Test public void testGetRemoteCapabilitiesOperation() { // get capabilities - RemoteOperationResult result = new GetCapabilitiesRemoteOperation().execute(client); + RemoteOperationResult result = new GetCapabilitiesRemoteOperation().execute(nextcloudClient); assertTrue(result.isSuccess()); - assertTrue(result.getData() != null && result.getData().size() == 1); - - OCCapability capability = (OCCapability) result.getData().get(0); - checkCapability(capability, client.getUserId()); + assertNotNull(result.getResultData()); + checkCapability(result.getResultData(), client.getUserId()); } @Test public void testGetRemoteCapabilitiesOperationEtag() { // get capabilities - RemoteOperationResult result = new GetCapabilitiesRemoteOperation().execute(client); + RemoteOperationResult result = new GetCapabilitiesRemoteOperation().execute(nextcloudClient); assertTrue(result.isSuccess()); - assertTrue(result.getData() != null && result.getData().size() == 1); + assertNotNull(result.getResultData()); - OCCapability capability = (OCCapability) result.getData().get(0); + OCCapability capability = result.getResultData(); - RemoteOperationResult resultEtag = new GetCapabilitiesRemoteOperation(capability).execute(client); + RemoteOperationResult resultEtag = new GetCapabilitiesRemoteOperation(capability).execute(nextcloudClient); assertTrue(resultEtag.isSuccess()); - assertTrue(resultEtag.getData() != null && resultEtag.getData().size() == 1); + assertNotNull(resultEtag.getResultData()); - OCCapability sameCapability = (OCCapability) resultEtag.getData().get(0); + OCCapability sameCapability = resultEtag.getResultData(); if (capability.getVersion().isNewerOrEqual(OwnCloudVersion.nextcloud_19)) { assertEquals(capability, sameCapability); @@ -74,28 +72,27 @@ public void testGetRemoteCapabilitiesOperationEtag() { @Test public void testGetRemoteCapabilitiesOperationWithNextcloudClient() { // get capabilities - RemoteOperationResult result = new GetCapabilitiesRemoteOperation().execute(nextcloudClient); + RemoteOperationResult result = new GetCapabilitiesRemoteOperation().execute(nextcloudClient); assertTrue(result.isSuccess()); - assertTrue(result.getData() != null && result.getData().size() == 1); - - OCCapability capability = (OCCapability) result.getData().get(0); - checkCapability(capability, client.getUserId()); + assertNotNull(result.getResultData()); + checkCapability(result.getResultData(), client.getUserId()); } @Test public void testGetRemoteCapabilitiesOperationEtagWithNextcloudClient() { // get capabilities - RemoteOperationResult result = new GetCapabilitiesRemoteOperation().execute(nextcloudClient); + RemoteOperationResult result = new GetCapabilitiesRemoteOperation().execute(nextcloudClient); assertTrue(result.isSuccess()); - assertTrue(result.getData() != null && result.getData().size() == 1); + assertNotNull(result.getResultData()); - OCCapability capability = (OCCapability) result.getData().get(0); + OCCapability capability = result.getResultData(); - RemoteOperationResult resultEtag = new GetCapabilitiesRemoteOperation(capability).execute(nextcloudClient); + RemoteOperationResult resultEtag = new GetCapabilitiesRemoteOperation(capability) + .execute(nextcloudClient); assertTrue(resultEtag.isSuccess()); - assertTrue(resultEtag.getData() != null && resultEtag.getData().size() == 1); - OCCapability sameCapability = (OCCapability) resultEtag.getData().get(0); + OCCapability sameCapability = resultEtag.getResultData(); + assertNotNull(sameCapability); if (capability.getVersion().isNewerOrEqual(OwnCloudVersion.nextcloud_19)) { assertEquals(capability, sameCapability); @@ -134,6 +131,7 @@ private void checkCapability(OCCapability capability, String userId) { // groupfolder if (capability.getVersion().isNewerOrEqual(NextcloudVersion.nextcloud_27)) { + // groupfolder only set up for user "test" if (userId.equals("test")) { assertTrue(capability.getGroupfolders().isTrue()); } else { @@ -145,11 +143,8 @@ private void checkCapability(OCCapability capability, String userId) { // assistant if (capability.getVersion().isNewerOrEqual(NextcloudVersion.nextcloud_28)) { - if (userId.equals("test")) { - assertTrue(capability.getAssistant().isTrue()); - } else { - assertFalse(capability.getAssistant().isFalse()); - } + // Nextcloud assistant needs to be set up for this to work + assertTrue(capability.getAssistant().isTrue()); } // e2e diff --git a/library/src/androidTest/java/com/owncloud/android/lib/common/accounts/ExternalLinksOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/common/accounts/ExternalLinksOperationIT.kt index 28f3c89bd..d1cfdec66 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/common/accounts/ExternalLinksOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/common/accounts/ExternalLinksOperationIT.kt @@ -8,24 +8,29 @@ package com.owncloud.android.lib.common.accounts import com.owncloud.android.AbstractIT -import com.owncloud.android.lib.common.ExternalLink +import com.owncloud.android.lib.common.operations.RemoteOperationResult import junit.framework.Assert.assertEquals import junit.framework.Assert.assertTrue +import org.junit.Assume.assumeTrue import org.junit.Test class ExternalLinksOperationIT : AbstractIT() { @Test fun retrieveExternalLinks() { - val result = ExternalLinksOperation().execute(client) + val result = ExternalLinksOperation().execute(nextcloudClient) + + // check if external sites app (external) is installed + assumeTrue(result.code != RemoteOperationResult.ResultCode.NOT_AVAILABLE) + assertTrue(result.isSuccess) - val data = result.data as ArrayList - assertEquals(2, data.size) + val data = result.resultData + assertEquals(2, data?.size) - assertEquals("Nextcloud", data[0].name) - assertEquals("https://www.nextcloud.com", data[0].url) + assertEquals("Nextcloud", data?.get(0)?.name) + assertEquals("https://www.nextcloud.com", data?.get(0)?.url) - assertEquals("Forum", data[1].name) - assertEquals("https://help.nextcloud.com", data[1].url) + assertEquals("Forum", data?.get(1)?.name) + assertEquals("https://help.nextcloud.com", data?.get(1)?.url) } } diff --git a/library/src/androidTest/java/com/owncloud/android/lib/common/operations/GetSharesIT.java b/library/src/androidTest/java/com/owncloud/android/lib/common/operations/GetSharesIT.java index 5a8061708..aa77886fd 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/common/operations/GetSharesIT.java +++ b/library/src/androidTest/java/com/owncloud/android/lib/common/operations/GetSharesIT.java @@ -14,6 +14,7 @@ import com.owncloud.android.AbstractIT; import com.owncloud.android.lib.resources.files.CreateFolderRemoteOperation; import com.owncloud.android.lib.resources.shares.CreateShareRemoteOperation; +import com.owncloud.android.lib.resources.shares.GetSharesForFileRemoteOperation; import com.owncloud.android.lib.resources.shares.GetSharesRemoteOperation; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; @@ -30,7 +31,8 @@ public class GetSharesIT extends AbstractIT { @Test public void testGetShares() { - assertTrue(new CreateFolderRemoteOperation("/1/", true).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation("/0/", true).execute(nextcloudClient).isSuccess()); + assertTrue(new CreateFolderRemoteOperation("/1/", true).execute(nextcloudClient).isSuccess()); assertTrue(new CreateShareRemoteOperation("/1/", ShareType.PUBLIC_LINK, "", @@ -38,7 +40,7 @@ public void testGetShares() { "", 1).execute(client).isSuccess()); - assertTrue(new CreateFolderRemoteOperation("/2/", true).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation("/2/", true).execute(nextcloudClient).isSuccess()); assertTrue(new CreateShareRemoteOperation("/2/", ShareType.PUBLIC_LINK, "", @@ -46,10 +48,18 @@ public void testGetShares() { "", 1).execute(client).isSuccess()); - RemoteOperationResult> result = new GetSharesRemoteOperation().execute(client); - assertTrue(result.isSuccess()); - assertEquals(2, result.getResultData().size()); - assertEquals("/1/", result.getResultData().get(0).getPath()); - assertEquals("/2/", result.getResultData().get(1).getPath()); + RemoteOperationResult> resultAll = new GetSharesRemoteOperation().execute(client); + assertTrue(resultAll.isSuccess()); + assertEquals(2, resultAll.getResultData().size()); + assertEquals("/1/", resultAll.getResultData().get(0).getPath()); + assertEquals("/2/", resultAll.getResultData().get(1).getPath()); + + RemoteOperationResult> result0 = new GetSharesForFileRemoteOperation("/0/", true, false).execute(client); + assertTrue(result0.isSuccess()); + assertEquals(0, result0.getResultData().size()); + + RemoteOperationResult> result2 = new GetSharesForFileRemoteOperation("/1/", true, false).execute(client); + assertTrue(result2.isSuccess()); + assertEquals(1, result2.getResultData().size()); } } diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/assistant/AssistantIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/assistant/AssistantIT.kt index 33213bac0..e024829e3 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/assistant/AssistantIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/assistant/AssistantIT.kt @@ -11,6 +11,7 @@ package com.owncloud.android.lib.resources.assistant import com.owncloud.android.AbstractIT import com.owncloud.android.lib.resources.status.NextcloudVersion import junit.framework.TestCase.assertEquals +import junit.framework.TestCase.assertNotNull import junit.framework.TestCase.assertTrue import org.junit.Before import org.junit.Test @@ -26,15 +27,15 @@ class AssistantIT : AbstractIT() { val result = GetTaskTypesRemoteOperation().execute(nextcloudClient) assertTrue(result.isSuccess) - val taskTypes = result.resultData.types - assertTrue(taskTypes.isNotEmpty()) + val taskTypes = result.resultData?.types + assertTrue(taskTypes?.isNotEmpty() == true) } @Test fun testGetTaskList() { var result = GetTaskListRemoteOperation("assistant").execute(nextcloudClient) assertTrue(result.isSuccess) - assertTrue(result.resultData.tasks.isEmpty()) + assertTrue(result.resultData?.tasks?.isEmpty() == true) // create one task val input = "Give me some random output for test purpose" @@ -44,8 +45,8 @@ class AssistantIT : AbstractIT() { result = GetTaskListRemoteOperation("assistant").execute(nextcloudClient) assertTrue(result.isSuccess) - val taskList = result.resultData.tasks - assertTrue(taskList.isNotEmpty()) + val taskList = result.resultData?.tasks + assertTrue(taskList?.isNotEmpty() == true) } @Test @@ -57,8 +58,9 @@ class AssistantIT : AbstractIT() { var result = GetTaskListRemoteOperation("assistant").execute(nextcloudClient) assertTrue(result.isSuccess) + assertNotNull(result.resultData) - val tasks = result.resultData.tasks + val tasks = result.resultData!!.tasks val countBefore = tasks.size // delete @@ -67,6 +69,6 @@ class AssistantIT : AbstractIT() { result = GetTaskListRemoteOperation("assistant").execute(nextcloudClient) assertTrue(result.isSuccess) - assertEquals(countBefore - 1, result.resultData.tasks.size) + assertEquals(countBefore - 1, result.resultData?.tasks?.size) } } diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/comments/CommentFileRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/comments/CommentFileRemoteOperationIT.kt index 0a3ed54ef..0fc10cd9e 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/comments/CommentFileRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/comments/CommentFileRemoteOperationIT.kt @@ -10,8 +10,8 @@ package com.owncloud.android.lib.resources.comments import com.owncloud.android.AbstractIT import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation import com.owncloud.android.lib.resources.files.UploadFileRemoteOperation -import com.owncloud.android.lib.resources.files.model.RemoteFile -import junit.framework.Assert.assertTrue +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertTrue import org.junit.Test class CommentFileRemoteOperationIT : AbstractIT() { @@ -24,18 +24,20 @@ class CommentFileRemoteOperationIT : AbstractIT() { .execute(client).isSuccess ) - val readResult = ReadFileRemoteOperation(remotePath).execute(client) - val remoteFile = readResult.data.get(0) as RemoteFile + val readResult = ReadFileRemoteOperation(remotePath).execute(nextcloudClient) + val remoteFile = readResult.resultData + + assertNotNull(remoteFile) assertTrue( - CommentFileRemoteOperation("test", remoteFile.localId) + CommentFileRemoteOperation("test", remoteFile!!.localId) .execute(nextcloudClient) .isSuccess ) assertTrue( MarkCommentsAsReadRemoteOperation(remoteFile.localId) - .execute(client) + .execute(nextcloudClient) .isSuccess ) } diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperationIT.java b/library/src/androidTest/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperationIT.java index c30d7c13e..18a510982 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperationIT.java +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperationIT.java @@ -34,8 +34,8 @@ public void uploadAndModifyV1() { // create folder String folder = "/" + RandomStringGenerator.make(20) + "/"; - assertTrue(new CreateFolderRemoteOperation(folder, true).execute(client).isSuccess()); - RemoteFile remoteFolder = (RemoteFile) new ReadFileRemoteOperation(folder).execute(client).getSingleData(); + assertTrue(new CreateFolderRemoteOperation(folder, true).execute(nextcloudClient).isSuccess()); + RemoteFile remoteFolder = (RemoteFile) new ReadFileRemoteOperation(folder).execute(nextcloudClient).getResultData(); assertNotNull(remoteFolder); @@ -43,7 +43,7 @@ public void uploadAndModifyV1() { assertTrue(new ToggleEncryptionRemoteOperation(remoteFolder.getLocalId(), remoteFolder.getRemotePath(), true) - .execute(client) + .execute(nextcloudClient) .isSuccess()); // Lock @@ -102,8 +102,8 @@ public void uploadAndModifyV2() { // create folder String folder = "/" + RandomStringGenerator.make(20) + "/"; - assertTrue(new CreateFolderRemoteOperation(folder, true).execute(client).isSuccess()); - RemoteFile remoteFolder = (RemoteFile) new ReadFileRemoteOperation(folder).execute(client).getSingleData(); + assertTrue(new CreateFolderRemoteOperation(folder, true).execute(nextcloudClient).isSuccess()); + RemoteFile remoteFolder = (RemoteFile) new ReadFileRemoteOperation(folder).execute(nextcloudClient).getSingleData(); assertNotNull(remoteFolder); @@ -111,7 +111,7 @@ public void uploadAndModifyV2() { assertTrue(new ToggleEncryptionRemoteOperation(remoteFolder.getLocalId(), remoteFolder.getRemotePath(), true) - .execute(client) + .execute(nextcloudClient) .isSuccess()); // Lock diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/CheckEtagRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/CheckEtagRemoteOperationIT.kt index 948486c74..4fd7f0360 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/CheckEtagRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/CheckEtagRemoteOperationIT.kt @@ -9,7 +9,6 @@ package com.owncloud.android.lib.resources.files import com.owncloud.android.AbstractIT import com.owncloud.android.lib.common.operations.RemoteOperationResult -import com.owncloud.android.lib.resources.files.model.RemoteFile import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test @@ -25,14 +24,14 @@ class CheckEtagRemoteOperationIT : AbstractIT() { .execute(client).isSuccess ) - val readResult = ReadFileRemoteOperation(remotePath).execute(client) - val remoteFile = readResult.data[0] as RemoteFile - val eTag = remoteFile.etag + val readResult = ReadFileRemoteOperation(remotePath).execute(nextcloudClient) + val remoteFile = readResult.resultData + val eTag = remoteFile?.etag - var eTagResult = CheckEtagRemoteOperation(remotePath, eTag).execute(client) + var eTagResult = CheckEtagRemoteOperation(remotePath, eTag).execute(nextcloudClient) assertEquals(RemoteOperationResult.ResultCode.ETAG_UNCHANGED, eTagResult.code) - eTagResult = CheckEtagRemoteOperation(remotePath, "wrongEtag").execute(client) + eTagResult = CheckEtagRemoteOperation(remotePath, "wrongEtag").execute(nextcloudClient) assertEquals(RemoteOperationResult.ResultCode.ETAG_CHANGED, eTagResult.code) } } diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/ReadFileRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/ReadFileRemoteOperationIT.kt index 026b4083e..1c1fd918a 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/ReadFileRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/ReadFileRemoteOperationIT.kt @@ -12,12 +12,11 @@ import com.owncloud.android.lib.common.OwnCloudClientManagerFactory import com.owncloud.android.lib.resources.e2ee.ToggleEncryptionRemoteOperation import com.owncloud.android.lib.resources.files.model.GeoLocation import com.owncloud.android.lib.resources.files.model.ImageDimension -import com.owncloud.android.lib.resources.files.model.RemoteFile import com.owncloud.android.lib.resources.status.GetCapabilitiesRemoteOperation import com.owncloud.android.lib.resources.status.NextcloudVersion import com.owncloud.android.lib.resources.status.OCCapability import org.junit.Assert.assertEquals -import org.junit.Assert.assertFalse +import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue import org.junit.Test @@ -26,12 +25,12 @@ class ReadFileRemoteOperationIT : AbstractIT() { fun readRemoteFolder() { val remotePath = "/test/" - assertTrue(CreateFolderRemoteOperation(remotePath, true).execute(client).isSuccess) + assertTrue(CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient).isSuccess) - val result = ReadFileRemoteOperation(remotePath).execute(client) + val result = ReadFileRemoteOperation(remotePath).execute(nextcloudClient) assertTrue(result.isSuccess) - assertEquals(remotePath, (result.data[0] as RemoteFile).remotePath) + assertEquals(remotePath, result.resultData?.remotePath) } @Test @@ -57,26 +56,26 @@ class ReadFileRemoteOperationIT : AbstractIT() { LinkLivePhotoRemoteOperation( livePhotoPath, movieFilePath - ).execute(client).isSuccess + ).execute(nextcloudClient).isSuccess ) assertTrue( LinkLivePhotoRemoteOperation( movieFilePath, livePhotoPath - ).execute(client).isSuccess + ).execute(nextcloudClient).isSuccess ) - val movieFileResult = ReadFileRemoteOperation(movieFilePath).execute(client) + val movieFileResult = ReadFileRemoteOperation(movieFilePath).execute(nextcloudClient) assertTrue(movieFileResult.isSuccess) - val movieRemoteFile = movieFileResult.data[0] as RemoteFile + val movieRemoteFile = movieFileResult.resultData - val livePhotoResult = ReadFileRemoteOperation(livePhotoPath).execute(client) + val livePhotoResult = ReadFileRemoteOperation(livePhotoPath).execute(nextcloudClient) assertTrue(livePhotoResult.isSuccess) - val livePhotoRemoteFile = livePhotoResult.data[0] as RemoteFile + val livePhotoRemoteFile = livePhotoResult.resultData - assertEquals(livePhotoRemoteFile.livePhoto, movieRemoteFile.remotePath) - assertTrue(movieRemoteFile.hidden) + assertEquals(livePhotoRemoteFile?.livePhoto, movieRemoteFile?.remotePath) + assertTrue(movieRemoteFile?.hidden == true) } @Test @@ -89,10 +88,10 @@ class ReadFileRemoteOperationIT : AbstractIT() { .execute(client).isSuccess ) - val result = ReadFileRemoteOperation(remotePath).execute(client) + val result = ReadFileRemoteOperation(remotePath).execute(nextcloudClient) assertTrue(result.isSuccess) - assertEquals(remotePath, (result.data[0] as RemoteFile).remotePath) + assertEquals(remotePath, result.resultData?.remotePath) } @Test @@ -105,27 +104,27 @@ class ReadFileRemoteOperationIT : AbstractIT() { .execute(client).isSuccess ) - val result = ReadFileRemoteOperation(remotePath).execute(client) + val result = ReadFileRemoteOperation(remotePath).execute(nextcloudClient) assertTrue(result.isSuccess) - val remoteFile = result.data[0] as RemoteFile + val remoteFile = result.resultData @Suppress("Detekt.MagicNumber") - assertEquals(ImageDimension(451f, 529f), remoteFile.imageDimension) + assertEquals(ImageDimension(451f, 529f), remoteFile?.imageDimension) testOnlyOnServer(NextcloudVersion.nextcloud_27) val ocCapability = GetCapabilitiesRemoteOperation() .execute(nextcloudClient) - .singleData as OCCapability + .resultData as OCCapability if (ocCapability.version.majorVersionNumber == NextcloudVersion.nextcloud_27.majorVersionNumber) { @Suppress("Detekt.MagicNumber") - assertEquals(GeoLocation(49.99679166666667, 8.67198611111111), remoteFile.geoLocation) + assertEquals(GeoLocation(49.99679166666667, 8.67198611111111), remoteFile?.geoLocation) } else { @Suppress("Detekt.MagicNumber") - assertEquals(GeoLocation(49.996791666667, 8.6719861111111), remoteFile.geoLocation) + assertEquals(GeoLocation(49.996791666667, 8.6719861111111), remoteFile?.geoLocation) } } @@ -137,28 +136,29 @@ class ReadFileRemoteOperationIT : AbstractIT() { // and blocks all other clients, e.g. 3rd party apps using this lib OwnCloudClientManagerFactory.setUserAgent("Mozilla/5.0 (Android) Nextcloud-android/3.13.0") - assertTrue(CreateFolderRemoteOperation(remotePath, true).execute(client).isSuccess) - - var result = ReadFileRemoteOperation(remotePath).execute(client) - val remoteFile = result.data[0] as RemoteFile + assertTrue(CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient).isSuccess) + var result = ReadFileRemoteOperation(remotePath).execute(nextcloudClient) assertTrue(result.isSuccess) - assertFalse(remoteFile.isEncrypted) - assertEquals(remotePath, remoteFile.remotePath) + + val remoteFile = result.resultData + assertNotNull(remoteFile) + assertTrue(remoteFile?.isEncrypted == false) + assertEquals(remotePath, remoteFile?.remotePath) // mark as encrypted assertTrue( ToggleEncryptionRemoteOperation( - remoteFile.localId, + remoteFile!!.localId, remotePath, true ) - .execute(client) + .execute(nextcloudClient) .isSuccess ) // re-read - result = ReadFileRemoteOperation(remotePath).execute(client) - assertEquals(true, (result.data[0] as RemoteFile).isEncrypted) + result = ReadFileRemoteOperation(remotePath).execute(nextcloudClient) + assertTrue(result.resultData?.isEncrypted == true) } } diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/ReadFileVersionsRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/ReadFileVersionsRemoteOperationIT.kt index c01d1938f..9cad351a2 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/ReadFileVersionsRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/ReadFileVersionsRemoteOperationIT.kt @@ -8,11 +8,11 @@ package com.owncloud.android.lib.resources.files import com.owncloud.android.AbstractIT -import com.owncloud.android.lib.resources.files.model.RemoteFile import com.owncloud.android.lib.resources.status.GetCapabilitiesRemoteOperation import com.owncloud.android.lib.resources.status.NextcloudVersion import com.owncloud.android.lib.resources.status.OCCapability import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue import org.junit.Test import java.io.FileWriter @@ -34,21 +34,22 @@ class ReadFileVersionsRemoteOperationIT : AbstractIT() { assertTrue("Error uploading file $filePath: $uploadResult", uploadResult.isSuccess) - var remoteFile = ReadFileRemoteOperation(filePath).execute(client).data[0] as RemoteFile + var remoteFile = ReadFileRemoteOperation(filePath).execute(nextcloudClient).resultData + assertNotNull(remoteFile) - var sutResult = ReadFileVersionsRemoteOperation(remoteFile.localId).execute(client) + var sutResult = ReadFileVersionsRemoteOperation(remoteFile!!.localId).execute(client) assertTrue(sutResult.isSuccess) var versionCount = 0 val ocCapability = GetCapabilitiesRemoteOperation() - .execute(nextcloudClient).singleData as OCCapability + .execute(nextcloudClient).resultData as OCCapability if (ocCapability.version.isNewerOrEqual(NextcloudVersion.nextcloud_26)) { // with NC26+ we always have a starting version versionCount++ } - assertEquals(versionCount, sutResult.data.size) + assertEquals(versionCount, sutResult.resultData?.size) // modify file to have a version FileWriter(txtFile).apply { @@ -68,13 +69,14 @@ class ReadFileVersionsRemoteOperationIT : AbstractIT() { assertTrue("Error uploading file $filePath: $uploadResult", uploadResult.isSuccess) - remoteFile = ReadFileRemoteOperation(filePath).execute(client).data[0] as RemoteFile + remoteFile = ReadFileRemoteOperation(filePath).execute(nextcloudClient).resultData + assertNotNull(remoteFile) - sutResult = ReadFileVersionsRemoteOperation(remoteFile.localId).execute(client) + sutResult = ReadFileVersionsRemoteOperation(remoteFile!!.localId).execute(client) assertTrue(sutResult.isSuccess) versionCount++ - assertEquals(versionCount, sutResult.data.size) + assertEquals(versionCount, sutResult.resultData?.size) } } diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/ReadFolderRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/ReadFolderRemoteOperationIT.kt index 710fe668c..1c8710510 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/ReadFolderRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/ReadFolderRemoteOperationIT.kt @@ -9,12 +9,12 @@ package com.owncloud.android.lib.resources.files import com.nextcloud.test.RandomStringGenerator import com.owncloud.android.AbstractIT -import com.owncloud.android.lib.resources.files.model.RemoteFile import com.owncloud.android.lib.resources.status.NextcloudVersion import com.owncloud.android.lib.resources.tags.CreateTagRemoteOperation import com.owncloud.android.lib.resources.tags.GetTagsRemoteOperation import com.owncloud.android.lib.resources.tags.PutTagRemoteOperation import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue import org.junit.Test @@ -27,7 +27,7 @@ class ReadFolderRemoteOperationIT : AbstractIT() { fun readRemoteFolderWithContent() { val remotePath = "/test/" - assertTrue(CreateFolderRemoteOperation(remotePath, true).execute(client).isSuccess) + assertTrue(CreateFolderRemoteOperation(remotePath, true).execute(nextcloudClient).isSuccess) // create file val filePath = createFile("text") @@ -36,65 +36,80 @@ class ReadFolderRemoteOperationIT : AbstractIT() { .execute(client).isSuccess ) - var result = ReadFolderRemoteOperation(remotePath).execute(client) + var result = ReadFolderRemoteOperation(remotePath).execute(nextcloudClient) assertTrue(result.isSuccess) - assertEquals(2, result.data.size) + assertEquals(2, result.resultData?.size) // tag testing only on NC27+ testOnlyOnServer(NextcloudVersion.nextcloud_27) // Folder - var remoteFolder = result.data[0] as RemoteFile - assertEquals(remotePath, remoteFolder.remotePath) - assertEquals(0, remoteFolder.tags?.size) + var remoteFolder = result.resultData?.get(0) + assertEquals(remotePath, remoteFolder?.remotePath) + assertEquals(0, remoteFolder?.tags?.size) // File - var remoteFile = result.data[1] as RemoteFile - assertEquals(remotePath + "1.txt", remoteFile.remotePath) - assertEquals(0, remoteFile.tags?.size) + var remoteFile = result.resultData?.get(1) + assertNotNull(remoteFile) + assertEquals(remotePath + "1.txt", remoteFile?.remotePath) + assertEquals(0, remoteFile?.tags?.size) // create tag - val tag1 = "a" + RandomStringGenerator.make(TAG_LENGTH) - val tag2 = "b" + RandomStringGenerator.make(TAG_LENGTH) - assertTrue(CreateTagRemoteOperation(tag1).execute(nextcloudClient).isSuccess) - assertTrue(CreateTagRemoteOperation(tag2).execute(nextcloudClient).isSuccess) + val tag1name = RandomStringGenerator.make(TAG_LENGTH) + val tag2name = RandomStringGenerator.make(TAG_LENGTH) + assertTrue(CreateTagRemoteOperation(tag1name).execute(nextcloudClient).isSuccess) + assertTrue(CreateTagRemoteOperation(tag2name).execute(nextcloudClient).isSuccess) // list tags - val tags = GetTagsRemoteOperation().execute(client).resultData + val tags = GetTagsRemoteOperation().execute(nextcloudClient).resultData + assertNotNull(tags) + + // extract and check tags + val tag1 = + tags?.firstOrNull { tag -> + tag.name == tag1name + } + assertNotNull(tag1) + + val tag2 = + tags?.firstOrNull { tag -> + tag.name == tag2name + } + assertNotNull(tag2) // add tag assertTrue( PutTagRemoteOperation( - tags[0].id, - remoteFile.localId + tag1!!.id, + remoteFile!!.localId ).execute(nextcloudClient).isSuccess ) + assertTrue( PutTagRemoteOperation( - tags[1].id, + tag2!!.id, remoteFile.localId ).execute(nextcloudClient).isSuccess ) // check again - result = ReadFolderRemoteOperation(remotePath).execute(client) + result = ReadFolderRemoteOperation(remotePath).execute(nextcloudClient) assertTrue(result.isSuccess) - assertEquals(2, result.data.size) + assertEquals(2, result.resultData?.size) // Folder - remoteFolder = result.data[0] as RemoteFile - assertEquals(remotePath, remoteFolder.remotePath) - assertEquals(0, remoteFolder.tags?.size) + remoteFolder = result.resultData?.get(0) + assertEquals(remotePath, remoteFolder?.remotePath) + assertEquals(0, remoteFolder?.tags?.size) // File - remoteFile = result.data[1] as RemoteFile - assertEquals(remotePath + "1.txt", remoteFile.remotePath) - assertEquals(2, remoteFile.tags?.size) + remoteFile = result.resultData?.get(1) + assertEquals(remotePath + "1.txt", remoteFile?.remotePath) + assertEquals(2, remoteFile?.tags?.size) - remoteFile.tags?.sort() - assertEquals(tag1, remoteFile.tags?.get(0)) - assertEquals(tag2, remoteFile.tags?.get(1)) + // check that tags are set correctly + assertTrue(remoteFile?.tags?.contentEquals(arrayOf(tag1name, tag2name)) == true) } } diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/SearchRemoteOperationIT.java b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/SearchRemoteOperationIT.java index f16c50e8d..6f88239d6 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/SearchRemoteOperationIT.java +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/SearchRemoteOperationIT.java @@ -8,6 +8,7 @@ package com.owncloud.android.lib.resources.files; import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNotNull; import static junit.framework.TestCase.assertTrue; import android.net.Uri; @@ -15,9 +16,9 @@ import androidx.test.platform.app.InstrumentationRegistry; +import com.nextcloud.common.NextcloudClient; +import com.nextcloud.common.OkHttpCredentialsUtil; import com.owncloud.android.AbstractIT; -import com.owncloud.android.lib.common.OwnCloudBasicCredentials; -import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.resources.files.model.RemoteFile; @@ -37,9 +38,9 @@ public class SearchRemoteOperationIT extends AbstractIT { @BeforeClass public static void beforeClass() { - capability = (OCCapability) new GetCapabilitiesRemoteOperation(null) - .execute(client) - .getSingleData(); + capability = new GetCapabilitiesRemoteOperation(null) + .execute(nextcloudClient) + .getResultData(); } @Test @@ -49,28 +50,34 @@ public void testSearchByFileIdEmpty() { false, capability); - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); assertEquals(0, result.getResultData().size()); } @Test public void testSearchByFileIdSuccess() { - assertTrue(new CreateFolderRemoteOperation("/test/", true).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation("/test/", true).execute(nextcloudClient).isSuccess()); - RemoteOperationResult readFile = new ReadFileRemoteOperation("/test/").execute(client); + RemoteOperationResult readFile = new ReadFileRemoteOperation("/test/").execute(nextcloudClient); assertTrue(readFile.isSuccess()); - RemoteFile remoteFile = ((RemoteFile) readFile.getSingleData()); + RemoteFile remoteFile = readFile.getResultData(); + assertNotNull(remoteFile); + SearchRemoteOperation sut = new SearchRemoteOperation(String.valueOf(remoteFile.getLocalId()), SearchRemoteOperation.SearchType.FILE_ID_SEARCH, false, capability); - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); - assertEquals(1, result.getResultData().size()); - assertEquals("/test/", result.getResultData().get(0).getRemotePath()); + + List remoteFileList = result.getResultData(); + assertNotNull(remoteFileList); + + assertEquals(1, remoteFileList.size()); + assertEquals("/test/", remoteFileList.get(0).getRemotePath()); } @Test @@ -87,7 +94,7 @@ public void testFileSearchEmpty() throws IOException { false, capability); - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); assertEquals(0, result.getResultData().size()); } @@ -106,7 +113,7 @@ public void testFileSearchEverything() throws IOException { false, capability); - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); assertEquals(11, result.getResultData().size()); } @@ -125,7 +132,7 @@ public void testFileSearchSuccess() throws IOException { false, capability); - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); assertEquals(1, result.getResultData().size()); RemoteFile remoteFile = result.getResultData().get(0); assertEquals("/image5.jpg", remoteFile.getRemotePath()); @@ -137,7 +144,7 @@ public void noFavorites() { SearchRemoteOperation.SearchType.FAVORITE_SEARCH, false, capability); - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); assertTrue(result.getResultData().isEmpty()); } @@ -145,22 +152,43 @@ public void noFavorites() { @Test public void oneFavorite() { String path = "/testFolder/"; + String path2 = "/testFolder2/"; // create folder, make it favorite - new CreateFolderRemoteOperation(path, true).execute(client); - assertTrue(new ToggleFavoriteRemoteOperation(true, path).execute(client).isSuccess()); + new CreateFolderRemoteOperation(path, true).execute(nextcloudClient); + new CreateFolderRemoteOperation(path2, true).execute(nextcloudClient); + assertTrue(new ToggleFavoriteRemoteOperation(true, path).execute(nextcloudClient).isSuccess()); + assertTrue(new ToggleFavoriteRemoteOperation(true, path2).execute(nextcloudClient).isSuccess()); SearchRemoteOperation sut = new SearchRemoteOperation("", SearchRemoteOperation.SearchType.FAVORITE_SEARCH, false, capability); - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); // test assertTrue(result.isSuccess()); - assertEquals(1, result.getResultData().size()); + assertEquals(2, result.getResultData().size()); + RemoteFile remoteFile = result.getResultData().get(0); assertEquals(path, remoteFile.getRemotePath()); + + RemoteFile remoteFile2 = result.getResultData().get(1); + assertEquals(path2, remoteFile2.getRemotePath()); + + // unfavorite + assertTrue(new ToggleFavoriteRemoteOperation(false, path).execute(nextcloudClient).isSuccess()); + assertTrue(new ToggleFavoriteRemoteOperation(false, path2).execute(nextcloudClient).isSuccess()); + + // test + sut = new SearchRemoteOperation("", + SearchRemoteOperation.SearchType.FAVORITE_SEARCH, + false, + capability); + result = sut.execute(nextcloudClient); + + assertTrue(result.isSuccess()); + assertEquals(0, result.getResultData().size()); } @Test @@ -182,14 +210,14 @@ public void favoriteFiles() throws IOException { ); // test user: favorite it - assertTrue(new ToggleFavoriteRemoteOperation(true, sharedRemotePath).execute(client).isSuccess()); + assertTrue(new ToggleFavoriteRemoteOperation(true, sharedRemotePath).execute(nextcloudClient).isSuccess()); String filePath = createFile("favoriteImage.jpg"); String remotePath = "/favoriteImage.jpg"; assertTrue(new UploadFileRemoteOperation(filePath, remotePath, "image/jpg", RANDOM_MTIME) .execute(client).isSuccess()); - assertTrue(new ToggleFavoriteRemoteOperation(true, remotePath).execute(client).isSuccess()); + assertTrue(new ToggleFavoriteRemoteOperation(true, remotePath).execute(nextcloudClient).isSuccess()); SearchRemoteOperation sut = new SearchRemoteOperation("", SearchRemoteOperation.SearchType.FAVORITE_SEARCH, @@ -232,7 +260,7 @@ public void testRecentlyModifiedSearch() throws IOException { false, capability); - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); assertEquals(4, result.getResultData().size()); @@ -247,7 +275,7 @@ public void testPhotoSearchNoFiles() { false, capability); - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); assertTrue(result.getResultData().isEmpty()); } @@ -266,7 +294,7 @@ public void testPhotoSearch() throws IOException { false, capability); - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); assertEquals(1, result.getResultData().size()); } @@ -290,14 +318,14 @@ public void testPhotoSearchLimit() throws IOException { false, capability); - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); assertEquals(10, result.getResultData().size()); // limit to 5 sut.setLimit(5); - result = sut.execute(client); + result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); assertEquals(5, result.getResultData().size()); } @@ -321,13 +349,13 @@ public void testPhotoSearchTimestamps() throws IOException { capability); // get all - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); assertEquals(10, result.getResultData().size()); // limit to timestamp 5 sut.setTimestamp(1464818405); - result = sut.execute(client); + result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); assertEquals(5, result.getResultData().size()); } @@ -353,14 +381,14 @@ public void testPhotoSearchLimitDates() throws IOException { capability); // get all - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); assertEquals(10, result.getResultData().size()); // limit to greater than start / less than end date sut.setStartDate(randomUnixTimestamp + 2L); sut.setEndDate(randomUnixTimestamp + 6L); - result = sut.execute(client); + result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); assertEquals(3, result.getResultData().size()); } @@ -384,7 +412,7 @@ public void testPhotoSearchLimitAndTimestamp() throws IOException { false, capability); - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); assertEquals(10, result.getResultData().size()); @@ -392,7 +420,7 @@ public void testPhotoSearchLimitAndTimestamp() throws IOException { sut.setLimit(5); sut.setTimestamp(120000); - result = sut.execute(client); + result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); assertEquals(2, result.getResultData().size()); } @@ -418,7 +446,7 @@ public void testGallerySearch() throws IOException { false, capability); - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); assertEquals(11, result.getResultData().size()); } @@ -436,16 +464,22 @@ public void showOnlyFolders() throws IOException { true, capability); - RemoteOperationResult> result = sut.execute(client); + RemoteOperationResult> result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); - assertEquals(1, result.getResultData().size()); - assertTrue(new CreateFolderRemoteOperation("/folder/", false).execute(client).isSuccess()); + List remoteFileList = result.getResultData(); + assertNotNull(remoteFileList); + assertEquals(1, remoteFileList.size()); + + assertTrue(new CreateFolderRemoteOperation("/folder/", false).execute(nextcloudClient).isSuccess()); - result = sut.execute(client); + result = sut.execute(nextcloudClient); assertTrue(result.isSuccess()); - assertEquals(2, result.getResultData().size()); - assertEquals("/folder/", result.getResultData().get(0).getRemotePath()); + + remoteFileList = result.getResultData(); + assertNotNull(remoteFileList); + assertEquals(2, remoteFileList.size()); + assertEquals("/folder/", remoteFileList.get(0).getRemotePath()); } @Test @@ -453,9 +487,12 @@ public void testSearchWithAtInUsername() { Bundle arguments = InstrumentationRegistry.getArguments(); Uri url = Uri.parse(arguments.getString("TEST_SERVER_URL")); - OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(url, context, true); - client.setCredentials(new OwnCloudBasicCredentials("test@test", "test")); - client.setUserId("test@test"); // for test same as userId + NextcloudClient client = OwnCloudClientFactory.createNextcloudClient( + url, + "test@test", + OkHttpCredentialsUtil.basic("test@test", "test"), + context, + true); SearchRemoteOperation sut = new SearchRemoteOperation("", SearchRemoteOperation.SearchType.FILE_SEARCH, diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperationIT.kt index 8376af46c..3f38d3fbf 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperationIT.kt @@ -10,7 +10,6 @@ package com.owncloud.android.lib.resources.files import android.os.Build import com.owncloud.android.AbstractIT import com.owncloud.android.lib.common.utils.Log_OC -import com.owncloud.android.lib.resources.files.model.RemoteFile import junit.framework.TestCase.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue @@ -53,12 +52,13 @@ class UploadFileRemoteOperationIT : AbstractIT() { assertTrue(uploadResult.isSuccess) // ReadFileRemoteOperation - var result = ReadFileRemoteOperation(remotePath).execute(client) + val result = ReadFileRemoteOperation(remotePath).execute(nextcloudClient) assertTrue(result.isSuccess) - var remoteFile = result.data[0] as RemoteFile + var remoteFile = result.resultData + assertNotNull(remoteFile) - assertEquals(remotePath, remoteFile.remotePath) + assertEquals(remotePath, remoteFile!!.remotePath) assertEquals(creationTimestamp, remoteFile.creationTimestamp) assertEquals(uploadResult.resultData, remoteFile.etag) assertTrue( @@ -67,12 +67,13 @@ class UploadFileRemoteOperationIT : AbstractIT() { ) // ReadFolderRemoteOperation - result = ReadFolderRemoteOperation(remotePath).execute(client) - assertTrue(result.isSuccess) + val resultFolder = ReadFolderRemoteOperation(remotePath).execute(nextcloudClient) + assertTrue(resultFolder.isSuccess) - remoteFile = result.data[0] as RemoteFile + remoteFile = resultFolder.resultData?.get(0) + assertNotNull(remoteFile) - assertEquals(remotePath, remoteFile.remotePath) + assertEquals(remotePath, remoteFile!!.remotePath) assertEquals(creationTimestamp, remoteFile.creationTimestamp) assertTrue( uploadTimestamp - TIME_OFFSET < remoteFile.uploadTimestamp || diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/webdav/ChunkedFileUploadRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/webdav/ChunkedFileUploadRemoteOperationIT.kt index 31f834e3d..48291fd79 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/webdav/ChunkedFileUploadRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/webdav/ChunkedFileUploadRemoteOperationIT.kt @@ -7,6 +7,7 @@ */ package com.owncloud.android.lib.resources.files.webdav +import com.nextcloud.extensions.toLegacyPropset import com.owncloud.android.AbstractIT import com.owncloud.android.lib.common.network.WebdavEntry import com.owncloud.android.lib.common.network.WebdavUtils @@ -139,7 +140,7 @@ class ChunkedFileUploadRemoteOperationIT : AbstractIT() { private fun getRemoteSize(remotePath: String): Long { val davPath = client.filesDavUri.toString() + "/" + WebdavUtils.encodePath(remotePath) - val propFindMethod = PropFindMethod(davPath, WebdavUtils.getFilePropSet(), 0) + val propFindMethod = PropFindMethod(davPath, WebdavUtils.PROPERTYSETS.FILE.toLegacyPropset(), 0) client.executeMethod(propFindMethod) assert(propFindMethod.succeeded()) diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/notifications/NotificationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/notifications/NotificationIT.kt index ba34b46fb..909e1ee1a 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/notifications/NotificationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/notifications/NotificationIT.kt @@ -9,6 +9,7 @@ package com.owncloud.android.lib.resources.notifications import com.owncloud.android.AbstractIT import junit.framework.TestCase.assertEquals +import junit.framework.TestCase.assertNotNull import junit.framework.TestCase.assertTrue import org.junit.Test @@ -18,18 +19,20 @@ class NotificationIT : AbstractIT() { // get all val all = GetNotificationsRemoteOperation().execute(nextcloudClient) assertTrue(all.isSuccess) + assertNotNull(all.resultData) - val count = all.resultData.size + val count = all.resultData!!.size // get one - val firstNotification = all.resultData[0] - val first = GetNotificationRemoteOperation(firstNotification.notificationId).execute(nextcloudClient) + val firstNotification = all.resultData?.get(0) + assertNotNull(firstNotification) + val first = GetNotificationRemoteOperation(firstNotification!!.notificationId).execute(nextcloudClient) assertTrue(first.isSuccess) - assertEquals(firstNotification.message, first.resultData.message) + assertEquals(firstNotification.message, first.resultData?.message) // delete one assertTrue( - DeleteNotificationRemoteOperation(first.resultData.notificationId) + DeleteNotificationRemoteOperation(first.resultData!!.notificationId) .execute(nextcloudClient) .isSuccess ) @@ -38,7 +41,7 @@ class NotificationIT : AbstractIT() { val all2 = GetNotificationsRemoteOperation().execute(nextcloudClient) assertTrue(all2.isSuccess) - assertEquals(count - 1, all2.resultData.size) + assertEquals(count - 1, all2.resultData?.size) // delete all assertTrue(DeleteAllNotificationsRemoteOperation().execute(nextcloudClient).isSuccess) @@ -47,6 +50,6 @@ class NotificationIT : AbstractIT() { val all3 = GetNotificationsRemoteOperation().execute(nextcloudClient) assertTrue(all3.isSuccess) - assertEquals(0, all3.resultData.size) + assertEquals(0, all3.resultData?.size) } } diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt index 06bfbe701..2a6d2d7ba 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt @@ -36,7 +36,7 @@ class CreateShareRemoteOperationIT : AbstractIT() { CreateFolderRemoteOperation( "/share/", true - ).execute(client).isSuccess + ).execute(nextcloudClient).isSuccess ) // share folder to user "admin" @@ -54,8 +54,8 @@ class CreateShareRemoteOperationIT : AbstractIT() { junit.framework.Assert.assertTrue(sut.isSuccess) - val share = sut.resultData[0] + val share = sut.resultData?.get(0) - assertEquals(note, share.note) + assertEquals(note, share?.note) } } diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/GetShareesRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/GetShareesRemoteOperationIT.kt new file mode 100644 index 000000000..5c4ddf88b --- /dev/null +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/GetShareesRemoteOperationIT.kt @@ -0,0 +1,25 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Your Name + * SPDX-License-Identifier: MIT + */ +package com.owncloud.android.lib.resources.shares + +import com.owncloud.android.AbstractIT +import junit.framework.TestCase.assertEquals +import junit.framework.TestCase.assertTrue +import org.junit.Test + +class GetShareesRemoteOperationIT : AbstractIT() { + companion object { + const val PER_PAGE = 50 + } + + @Test + fun getSharees() { + val sut = GetShareesRemoteOperation("admin", 1, PER_PAGE).execute(client) + assertTrue(sut.isSuccess) + assertEquals(2, sut.resultData?.size) + } +} diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/GetSharesRemoteOperationIT.java b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/GetSharesRemoteOperationIT.java index 58ed2ac25..242059a3a 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/GetSharesRemoteOperationIT.java +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/GetSharesRemoteOperationIT.java @@ -17,6 +17,7 @@ import androidx.test.platform.app.InstrumentationRegistry; +import com.nextcloud.common.NextcloudClient; import com.owncloud.android.AbstractIT; import com.owncloud.android.lib.common.OwnCloudBasicCredentials; import com.owncloud.android.lib.common.OwnCloudClient; @@ -34,15 +35,15 @@ import java.util.List; +import okhttp3.Credentials; + public class GetSharesRemoteOperationIT extends AbstractIT { @Test public void searchSharedFiles() { - assertTrue(new CreateFolderRemoteOperation("/shareToAdmin/", true).execute(client).isSuccess()); - assertTrue(new CreateFolderRemoteOperation("/shareToGroup/", true).execute(client).isSuccess()); - assertTrue(new CreateFolderRemoteOperation("/shareViaLink/", true).execute(client).isSuccess()); -// assertTrue(new CreateFolderRemoteOperation("/shareViaMail/", true).execute(client).isSuccess()); - assertTrue(new CreateFolderRemoteOperation("/noShare/", true).execute(client).isSuccess()); - //assertTrue(new CreateFolderRemoteOperation("/shareToCircle/", true).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation("/shareToAdmin/", true).execute(nextcloudClient).isSuccess()); + assertTrue(new CreateFolderRemoteOperation("/shareToGroup/", true).execute(nextcloudClient).isSuccess()); + assertTrue(new CreateFolderRemoteOperation("/shareViaLink/", true).execute(nextcloudClient).isSuccess()); + assertTrue(new CreateFolderRemoteOperation("/noShare/", true).execute(nextcloudClient).isSuccess()); GetSharesRemoteOperation sut = new GetSharesRemoteOperation(); @@ -167,7 +168,7 @@ public void sharedWithMe() { // share folder to user "admin" - assertTrue(new CreateFolderRemoteOperation("/shareToAdmin/", true).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation("/shareToAdmin/", true).execute(nextcloudClient).isSuccess()); assertTrue(new CreateShareRemoteOperation("/shareToAdmin/", ShareType.USER, "admin", @@ -193,8 +194,11 @@ public void sharedWithMe() { clientUser1.setCredentials(new OwnCloudBasicCredentials(loginName, password)); clientUser1.setUserId(loginName); // for test same as userId + String credentials = Credentials.basic(loginName, password); + NextcloudClient nextcloudClientUser1 = new NextcloudClient(url, loginName, credentials, context); + // share folder to previous user - assertTrue(new CreateFolderRemoteOperation("/shareToUser/", true).execute(clientUser1).isSuccess()); + assertTrue(new CreateFolderRemoteOperation("/shareToUser/", true).execute(nextcloudClientUser1).isSuccess()); assertTrue(new CreateShareRemoteOperation("/shareToUser/", ShareType.USER, client.getCredentials().getUsername(), @@ -217,7 +221,7 @@ public void favorites() { testOnlyOnServer(NextcloudVersion.nextcloud_25); // share folder to user "admin" - assertTrue(new CreateFolderRemoteOperation("/shareToAdminNoFavorite/", true).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation("/shareToAdminNoFavorite/", true).execute(nextcloudClient).isSuccess()); RemoteOperationResult> createResult = new CreateShareRemoteOperation("/shareToAdminNoFavorite/", ShareType.USER, "admin", @@ -230,7 +234,7 @@ public void favorites() { assertTrue(createResult.isSuccess()); String path = "/shareToAdminFavorite/"; - assertTrue(new CreateFolderRemoteOperation(path, true).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); // favorite it TestCase.assertTrue(new ToggleFavoriteRemoteOperation(true, path).execute(client).isSuccess()); @@ -259,7 +263,7 @@ public void noFavorite() { // only on NC25+ testOnlyOnServer(NextcloudVersion.nextcloud_25); - assertTrue(new CreateFolderRemoteOperation("/shareToAdminNoFavorite/", true).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation("/shareToAdminNoFavorite/", true).execute(nextcloudClient).isSuccess()); // share folder to user "admin" RemoteOperationResult> createResult = new CreateShareRemoteOperation("/shareToAdminNoFavorite/", @@ -281,12 +285,12 @@ public void noFavorite() { @Test public void favorite() { // only on NC25+ - OCCapability ocCapability = (OCCapability) new GetCapabilitiesRemoteOperation() - .execute(nextcloudClient).getSingleData(); + OCCapability ocCapability = new GetCapabilitiesRemoteOperation().execute(nextcloudClient).getResultData(); + assumeTrue(ocCapability != null); assumeTrue(ocCapability.getVersion().isNewerOrEqual(NextcloudVersion.nextcloud_25)); String path = "/shareToAdminFavorite/"; - assertTrue(new CreateFolderRemoteOperation(path, true).execute(client).isSuccess()); + assertTrue(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); // favorite it TestCase.assertTrue(new ToggleFavoriteRemoteOperation(true, path).execute(client).isSuccess()); diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/ShareXMLParserIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/ShareXMLParserIT.kt index 8bf51023e..824c05197 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/ShareXMLParserIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/ShareXMLParserIT.kt @@ -73,8 +73,8 @@ class ShareXMLParserIT { val sut = ShareToRemoteOperationResultParser(ShareXMLParser()) val shares = sut.parse(xml) - assertEquals(1, shares.resultData.size) - assertTrue(shares.resultData[0].isFavorite) + assertEquals(1, shares.resultData?.size) + assertTrue(shares.resultData?.get(0)?.isFavorite == true) } @Test @@ -7375,7 +7375,7 @@ class ShareXMLParserIT { val sut = ShareToRemoteOperationResultParser(ShareXMLParser()) val shares = sut.parse(xml) - assertEquals(201, shares.resultData.size) - assertEquals(21, shares.resultData.count { ocShare -> ocShare.isFavorite }) + assertEquals(201, shares.resultData?.size) + assertEquals(21, shares.resultData?.count { ocShare -> ocShare.isFavorite }) } } diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperationIT.kt index 368d9dc59..47916351a 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperationIT.kt @@ -15,6 +15,7 @@ import com.owncloud.android.lib.resources.status.NextcloudVersion import com.owncloud.android.lib.resources.status.OCCapability import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse +import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue import org.junit.Test @@ -45,7 +46,7 @@ class UpdateShareRemoteOperationIT : AbstractIT() { } private fun testUpdateNote(note: String) { - assertTrue(CreateFolderRemoteOperation("/note/", true).execute(client).isSuccess) + assertTrue(CreateFolderRemoteOperation("/note/", true).execute(nextcloudClient).isSuccess) // share folder to user "admin" val createOperationResult = @@ -61,8 +62,9 @@ class UpdateShareRemoteOperationIT : AbstractIT() { ).execute(client) assertTrue(createOperationResult.isSuccess) + assertNotNull(createOperationResult.resultData) - val share = createOperationResult.resultData[0] + val share = createOperationResult.resultData!![0] val sut = UpdateShareRemoteOperation(share.remoteId) sut.setNote(note) @@ -72,18 +74,19 @@ class UpdateShareRemoteOperationIT : AbstractIT() { // verify val getShareOperationResult = GetShareRemoteOperation(share.remoteId).execute(client) assertTrue(getShareOperationResult.isSuccess) + assertNotNull(getShareOperationResult.resultData) - val updatedShare = getShareOperationResult.resultData[0] + val updatedShare = getShareOperationResult.resultData!![0] assertEquals(note, updatedShare.note) - assertTrue(RemoveFileRemoteOperation("/note/").execute(client).isSuccess) + assertTrue(RemoveFileRemoteOperation("/note/").execute(nextcloudClient).isSuccess) } @Test fun updateLabel() { val label = "test & test" - assertTrue(CreateFolderRemoteOperation("/label/", true).execute(client).isSuccess) + assertTrue(CreateFolderRemoteOperation("/label/", true).execute(nextcloudClient).isSuccess) // share folder via public link val createOperationResult = @@ -97,8 +100,9 @@ class UpdateShareRemoteOperationIT : AbstractIT() { ).execute(client) assertTrue(createOperationResult.isSuccess) + assertNotNull(createOperationResult.resultData) - val share = createOperationResult.resultData[0] + val share = createOperationResult.resultData!![0] val sut = UpdateShareRemoteOperation(share.remoteId) sut.setLabel(label) @@ -108,19 +112,20 @@ class UpdateShareRemoteOperationIT : AbstractIT() { // verify val getShareOperationResult = GetShareRemoteOperation(share.remoteId).execute(client) assertTrue(getShareOperationResult.isSuccess) + assertNotNull(getShareOperationResult.resultData) - val updatedShare = getShareOperationResult.resultData[0] + val updatedShare = getShareOperationResult.resultData!![0] assertEquals(label, updatedShare.label) - assertTrue(RemoveFileRemoteOperation("/label/").execute(client).isSuccess) + assertTrue(RemoveFileRemoteOperation("/label/").execute(nextcloudClient).isSuccess) } @Test @Suppress("MaxLineLength") fun invalidPassword() { val folder = "/invalidPassword/" - assertTrue(CreateFolderRemoteOperation(folder, true).execute(client).isSuccess) + assertTrue(CreateFolderRemoteOperation(folder, true).execute(nextcloudClient).isSuccess) // share folder via public link val createOperationResult = @@ -134,8 +139,9 @@ class UpdateShareRemoteOperationIT : AbstractIT() { ).execute(client) assertTrue(createOperationResult.isSuccess) + assertNotNull(createOperationResult.resultData) - val share = createOperationResult.resultData[0] + val share = createOperationResult.resultData!![0] val sut = UpdateShareRemoteOperation(share.remoteId) sut.setPassword("1") @@ -145,7 +151,7 @@ class UpdateShareRemoteOperationIT : AbstractIT() { val capabilityResult = GetCapabilitiesRemoteOperation().execute(nextcloudClient) assertTrue(capabilityResult.isSuccess) - val capability = capabilityResult.singleData as OCCapability + val capability = capabilityResult.resultData as OCCapability when { capability.version.isNewerOrEqual(NextcloudVersion.nextcloud_22) -> { @@ -164,13 +170,13 @@ class UpdateShareRemoteOperationIT : AbstractIT() { } } - assertTrue(RemoveFileRemoteOperation(folder).execute(client).isSuccess) + assertTrue(RemoveFileRemoteOperation(folder).execute(nextcloudClient).isSuccess) } @Test fun validPassword() { val folder = "/validPassword/" - assertTrue(CreateFolderRemoteOperation(folder, true).execute(client).isSuccess) + assertTrue(CreateFolderRemoteOperation(folder, true).execute(nextcloudClient).isSuccess) // share folder via public link val createOperationResult = @@ -184,13 +190,14 @@ class UpdateShareRemoteOperationIT : AbstractIT() { ).execute(client) assertTrue(createOperationResult.isSuccess) + assertNotNull(createOperationResult.resultData) - val share = createOperationResult.resultData[0] + val share = createOperationResult.resultData!![0] val sut = UpdateShareRemoteOperation(share.remoteId) sut.setPassword("arnservcvcbtp234") assertTrue(sut.execute(client).isSuccess) - assertTrue(RemoveFileRemoteOperation(folder).execute(client).isSuccess) + assertTrue(RemoveFileRemoteOperation(folder).execute(nextcloudClient).isSuccess) } } diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/tags/GetTagsRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/tags/GetTagsRemoteOperationIT.kt index 7abdd576b..220bc204f 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/tags/GetTagsRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/tags/GetTagsRemoteOperationIT.kt @@ -10,6 +10,7 @@ package com.owncloud.android.lib.resources.tags import com.nextcloud.test.RandomStringGenerator import com.owncloud.android.AbstractIT import junit.framework.TestCase.assertEquals +import junit.framework.TestCase.assertNotNull import junit.framework.TestCase.assertTrue import org.junit.Test @@ -20,10 +21,11 @@ class GetTagsRemoteOperationIT : AbstractIT() { @Test fun list() { - var sut = GetTagsRemoteOperation().execute(client) + var sut = GetTagsRemoteOperation().execute(nextcloudClient) assertTrue(sut.isSuccess) + assertNotNull(sut.resultData) - val count = sut.resultData.size + val count = sut.resultData?.size assertTrue( CreateTagRemoteOperation(RandomStringGenerator.make(TAG_LENGTH)) @@ -31,8 +33,9 @@ class GetTagsRemoteOperationIT : AbstractIT() { .isSuccess ) - sut = GetTagsRemoteOperation().execute(client) + sut = GetTagsRemoteOperation().execute(nextcloudClient) assertTrue(sut.isSuccess) - assertEquals(count + 1, sut.resultData.size) + + assertEquals(count?.plus(1), sut.resultData?.size) } } diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/trashbin/ReadTrashbinFolderRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/trashbin/ReadTrashbinFolderRemoteOperationIT.kt index d631b5bf0..369ce11cb 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/trashbin/ReadTrashbinFolderRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/trashbin/ReadTrashbinFolderRemoteOperationIT.kt @@ -21,7 +21,7 @@ class ReadTrashbinFolderRemoteOperationIT : AbstractIT() { val sut = ReadTrashbinFolderRemoteOperation("/") - assertEquals(0, sut.execute(client).resultData.size) + assertEquals(0, sut.execute(client).resultData?.size) val fileName = "trashbinFile.txt" val filePath = createFile(fileName) @@ -41,13 +41,13 @@ class ReadTrashbinFolderRemoteOperationIT : AbstractIT() { // delete file assertTrue( RemoveFileRemoteOperation(remotePath) - .execute(client) + .execute(nextcloudClient) .isSuccess ) val result = sut.execute(client) - assertEquals(1, result.resultData.size) - assertEquals(fileName, result.resultData[0].fileName) + assertEquals(1, result.resultData?.size) + assertEquals(fileName, result.resultData?.get(0)?.fileName) } } diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/users/AppTokenRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/users/AppTokenRemoteOperationIT.kt index 53802ec18..4e5934306 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/users/AppTokenRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/users/AppTokenRemoteOperationIT.kt @@ -10,6 +10,7 @@ package com.owncloud.android.lib.resources.users import androidx.test.platform.app.InstrumentationRegistry import com.owncloud.android.AbstractIT import junit.framework.Assert.assertFalse +import junit.framework.Assert.assertNotNull import junit.framework.Assert.assertTrue import okhttp3.Credentials.basic import org.junit.Test @@ -27,7 +28,7 @@ class AppTokenRemoteOperationIT : AbstractIT() { val password: String? = arguments.getString("TEST_SERVER_PASSWORD") val newPassword = result.resultData - assertTrue(newPassword.isNotBlank()) + assertTrue(newPassword?.isNotBlank() == true) assertTrue(password != newPassword) } @@ -44,7 +45,8 @@ class AppTokenRemoteOperationIT : AbstractIT() { val password: String = arguments.getString("TEST_SERVER_PASSWORD", "") val newPassword = result.resultData - assertTrue(newPassword.isNotBlank()) + assertNotNull(newPassword) + assertTrue(newPassword!!.isNotBlank()) assertTrue(password != newPassword) // second use this app token to check @@ -52,7 +54,7 @@ class AppTokenRemoteOperationIT : AbstractIT() { val result2 = sut.execute(nextcloudClient) assertTrue(result2.isSuccess) - assertTrue(result2.resultData.isEmpty()) + assertTrue(result2.resultData?.isEmpty() == true) } @Test @@ -70,7 +72,8 @@ class AppTokenRemoteOperationIT : AbstractIT() { val newPassword = result.resultData - assertTrue(newPassword.isNotBlank()) + assertNotNull(newPassword) + assertTrue(newPassword!!.isNotBlank()) assertTrue(password != newPassword) nextcloudClient.credentials = basic(username, newPassword) diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/users/SetUserInfoRemoteOperationIT.java b/library/src/androidTest/java/com/owncloud/android/lib/resources/users/SetUserInfoRemoteOperationIT.java index d5a39aa99..e7f4c8b2d 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/users/SetUserInfoRemoteOperationIT.java +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/users/SetUserInfoRemoteOperationIT.java @@ -10,6 +10,7 @@ package com.owncloud.android.lib.resources.users; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import com.owncloud.android.AbstractIT; @@ -64,9 +65,10 @@ public void testSetDisplayName() { @Test public void testSetPhone() { - RemoteOperationResult result = new GetCapabilitiesRemoteOperation().execute(nextcloudClient); + RemoteOperationResult result = new GetCapabilitiesRemoteOperation().execute(nextcloudClient); assertTrue(result.isSuccess()); - OCCapability ocCapability = (OCCapability) result.getSingleData(); + OCCapability ocCapability = result.getResultData(); + assertNotNull(ocCapability); RemoteOperationResult userInfo = new GetUserInfoRemoteOperation().execute(nextcloudClient); assertTrue(userInfo.isSuccess()); diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/users/StatusIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/users/StatusIT.kt index 2f11844ff..566f9c995 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/users/StatusIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/users/StatusIT.kt @@ -31,7 +31,7 @@ class StatusIT : AbstractIT() { assertTrue("GetStatusRemoteOperation failed: " + result.logMessage, result.isSuccess) val status = result.resultData - assertTrue(status.message.isNullOrBlank()) + assertTrue(status?.message.isNullOrBlank()) } @Test @@ -40,7 +40,7 @@ class StatusIT : AbstractIT() { val result0 = SetStatusRemoteOperation(StatusType.ONLINE).execute(nextcloudClient) assertTrue("SetStatusRemoteOperation failed: " + result0.logMessage, result0.isSuccess) - for (statusType in StatusType.values()) { + for (statusType in StatusType.entries) { val result1 = GetStatusRemoteOperation().run(nextcloudClient) assertTrue("GetStatusRemoteOperation failed: " + result1.logMessage, result1.isSuccess) @@ -51,7 +51,7 @@ class StatusIT : AbstractIT() { assertTrue("GetStatusRemoteOperation failed: " + result3.logMessage, result3.isSuccess) val status = result3.resultData - assertEquals(statusType, status.status) + assertEquals(statusType, status?.status) } val result2 = SetStatusRemoteOperation(StatusType.AWAY).run(nextcloudClient) @@ -69,7 +69,7 @@ class StatusIT : AbstractIT() { ) val statusesList = result.resultData - assertTrue(statusesList.isNotEmpty()) + assertTrue(statusesList?.isNotEmpty() == true) } @Test @@ -94,12 +94,12 @@ class StatusIT : AbstractIT() { result.isSuccess ) - val statusesList: ArrayList = result.resultData - val newCustomStatusMessage = statusesList[2] + val statusesList = result.resultData + val newCustomStatusMessage = statusesList?.get(2) val clearAt = System.currentTimeMillis() / SECOND_IN_MILLIS + HOUR_IN_MINUTES result = - SetPredefinedCustomStatusMessageRemoteOperation(newCustomStatusMessage.id, clearAt) + SetPredefinedCustomStatusMessageRemoteOperation(newCustomStatusMessage?.id, clearAt) .execute(nextcloudClient) assertTrue( "SetPredefinedCustomStatusMessageRemoteOperation failed: " + result.logMessage, @@ -111,7 +111,7 @@ class StatusIT : AbstractIT() { assertTrue("GetStatusRemoteOperation failed: " + newResult.logMessage, newResult.isSuccess) val status = newResult.resultData - assertEquals(newCustomStatusMessage.message, status.message) + assertEquals(newCustomStatusMessage?.message, status?.message) } @Test @@ -136,8 +136,8 @@ class StatusIT : AbstractIT() { assertTrue("GetStatusRemoteOperation failed: " + resultGet.logMessage, resultGet.isSuccess) val status = resultGet.resultData - assertEquals(message, status.message) - assertEquals(statusIcon, status.icon) - assertEquals(clearAt, status.clearAt) + assertEquals(message, status?.message) + assertEquals(statusIcon, status?.icon) + assertEquals(clearAt, status?.clearAt) } } diff --git a/library/src/main/java/com/nextcloud/android/lib/resources/groupfolders/GetGroupfoldersRemoteOperation.kt b/library/src/main/java/com/nextcloud/android/lib/resources/groupfolders/GetGroupfoldersRemoteOperation.kt index c7b870f81..aa070ee30 100644 --- a/library/src/main/java/com/nextcloud/android/lib/resources/groupfolders/GetGroupfoldersRemoteOperation.kt +++ b/library/src/main/java/com/nextcloud/android/lib/resources/groupfolders/GetGroupfoldersRemoteOperation.kt @@ -41,7 +41,7 @@ class GetGroupfoldersRemoteOperation : if (map != null) { result = RemoteOperationResult(true, getMethod) - result.setResultData(map) + result.resultData = map } else { result = RemoteOperationResult(false, getMethod) } diff --git a/library/src/main/java/com/nextcloud/android/lib/resources/profile/GetHoverCardRemoteOperation.kt b/library/src/main/java/com/nextcloud/android/lib/resources/profile/GetHoverCardRemoteOperation.kt index 8f7526308..0e63662b4 100644 --- a/library/src/main/java/com/nextcloud/android/lib/resources/profile/GetHoverCardRemoteOperation.kt +++ b/library/src/main/java/com/nextcloud/android/lib/resources/profile/GetHoverCardRemoteOperation.kt @@ -39,7 +39,7 @@ class GetHoverCardRemoteOperation(private val userId: String) : OCSRemoteOperati if (hoverCard != null) { result = RemoteOperationResult(true, getMethod) - result.setResultData(hoverCard) + result.resultData = hoverCard } else { result = RemoteOperationResult(false, getMethod) } diff --git a/library/src/main/java/com/nextcloud/android/lib/resources/users/GenerateAppPasswordRemoteOperation.java b/library/src/main/java/com/nextcloud/android/lib/resources/users/GenerateAppPasswordRemoteOperation.java index 39648d8d2..13f2638ef 100644 --- a/library/src/main/java/com/nextcloud/android/lib/resources/users/GenerateAppPasswordRemoteOperation.java +++ b/library/src/main/java/com/nextcloud/android/lib/resources/users/GenerateAppPasswordRemoteOperation.java @@ -7,13 +7,13 @@ */ package com.nextcloud.android.lib.resources.users; -import com.owncloud.android.lib.common.OwnCloudClient; +import com.nextcloud.common.NextcloudClient; +import com.nextcloud.operations.GetMethod; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.OCSRemoteOperation; import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.methods.GetMethod; import org.json.JSONObject; /** @@ -21,10 +21,8 @@ */ -public class GenerateAppPasswordRemoteOperation extends OCSRemoteOperation { +public class GenerateAppPasswordRemoteOperation extends OCSRemoteOperation { private static final String TAG = GenerateAppPasswordRemoteOperation.class.getSimpleName(); - private static final int SYNC_READ_TIMEOUT = 40000; - private static final int SYNC_CONNECTION_TIMEOUT = 5000; private static final String DIRECT_ENDPOINT = "/ocs/v2.php/core/getapppassword"; // JSON node names @@ -32,17 +30,14 @@ public class GenerateAppPasswordRemoteOperation extends OCSRemoteOperation { private static final String NODE_DATA = "data"; private static final String NODE_APPPASSWORD = "apppassword"; - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result; + public RemoteOperationResult run(NextcloudClient client) { + RemoteOperationResult result; GetMethod getMethod = null; try { - getMethod = new GetMethod(client.getBaseUri() + DIRECT_ENDPOINT + JSON_FORMAT); + getMethod = new GetMethod(client.getBaseUri() + DIRECT_ENDPOINT + JSON_FORMAT, true); - // remote request - getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE); - - int status = client.executeMethod(getMethod, SYNC_READ_TIMEOUT, SYNC_CONNECTION_TIMEOUT); + int status = client.execute(getMethod); if (status == HttpStatus.SC_OK) { String response = getMethod.getResponseBodyAsString(); @@ -50,14 +45,13 @@ protected RemoteOperationResult run(OwnCloudClient client) { JSONObject respJSON = new JSONObject(response); String password = respJSON.getJSONObject(NODE_OCS).getJSONObject(NODE_DATA).getString(NODE_APPPASSWORD); - result = new RemoteOperationResult(true, getMethod); - result.setSingleData(password); + result = new RemoteOperationResult<>(true, getMethod); + result.setResultData(password); } else { - result = new RemoteOperationResult(false, getMethod); - client.exhaustResponse(getMethod.getResponseBodyAsStream()); + result = new RemoteOperationResult<>(false, getMethod); } } catch (Exception e) { - result = new RemoteOperationResult(e); + result = new RemoteOperationResult<>(e); Log_OC.e(TAG, "Generate app password failed: " + result.getLogMessage(), result.getException()); } finally { diff --git a/library/src/main/java/com/nextcloud/common/DavMethod.kt b/library/src/main/java/com/nextcloud/common/DavMethod.kt new file mode 100644 index 000000000..4c2b2a970 --- /dev/null +++ b/library/src/main/java/com/nextcloud/common/DavMethod.kt @@ -0,0 +1,29 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2023-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-FileCopyrightText: 2023 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ +package com.nextcloud.common + +import android.net.Uri +import com.owncloud.android.lib.common.network.WebdavUtils +import okhttp3.HttpUrl +import okhttp3.OkHttpClient + +abstract class DavMethod(private val httpUrl: HttpUrl) { + fun execute(nextcloudClient: NextcloudClient): T { + // register custom property + WebdavUtils.registerCustomFactories() + + return apply(nextcloudClient.disabledRedirectClient(), httpUrl, nextcloudClient.filesDavUri) + } + + abstract fun apply( + client: OkHttpClient, + httpUrl: HttpUrl, + filesDavUri: Uri + ): T +} diff --git a/library/src/main/java/com/nextcloud/common/DavResponse.kt b/library/src/main/java/com/nextcloud/common/DavResponse.kt new file mode 100644 index 000000000..1e33cabc0 --- /dev/null +++ b/library/src/main/java/com/nextcloud/common/DavResponse.kt @@ -0,0 +1,39 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ +package com.nextcloud.common + +import okhttp3.Headers +import okhttp3.internal.http.StatusLine + +/** + * Encapsulates essential data returned as responses from various DAV calls. + */ +data class DavResponse( + var success: Boolean = false, + var status: StatusLine? = null, + var headers: Headers? = null +) { + /** + * Return value of specified header. + * + * Simple helper to aid with nullability when called from Java. + * + * @param key name of header to get + * @return value of header or `null` when header is not set + */ + fun getHeader(key: String): String? = headers?.get(key) + + /** + * Return value of status code. + * + * Simple helper to aid with nullability when called from Java. + * + * @return HTTP status code or `0` if not set. + */ + fun getStatusCode(): Int = status?.code ?: 0 +} diff --git a/library/src/main/java/com/nextcloud/common/NextcloudAuthenticator.kt b/library/src/main/java/com/nextcloud/common/NextcloudAuthenticator.kt new file mode 100644 index 000000000..139fd5e4e --- /dev/null +++ b/library/src/main/java/com/nextcloud/common/NextcloudAuthenticator.kt @@ -0,0 +1,50 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2022 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ +package com.nextcloud.common + +import okhttp3.Authenticator +import okhttp3.Request +import okhttp3.Response +import okhttp3.Route + +class NextcloudAuthenticator(private val credentials: String) : Authenticator { + @Suppress("ReturnCount") + override fun authenticate( + route: Route?, + response: Response + ): Request? { + val authenticatorType = "Authorization" + + if (response.request.header(authenticatorType) != null) { + return null + } + + var countedResponse: Response? = response + + var attemptsCount = 0 + + countedResponse = countedResponse?.priorResponse + + while (countedResponse != null) { + attemptsCount++ + if (attemptsCount == MAX_ATTEMPTS) { + return null + } + + countedResponse = countedResponse.priorResponse + } + + return response.request.newBuilder() + .header(authenticatorType, credentials) + .build() + } + + companion object { + const val MAX_ATTEMPTS = 3 + } +} diff --git a/library/src/main/java/com/nextcloud/common/NextcloudClient.kt b/library/src/main/java/com/nextcloud/common/NextcloudClient.kt index 2f4e5c6d4..9130e9a78 100644 --- a/library/src/main/java/com/nextcloud/common/NextcloudClient.kt +++ b/library/src/main/java/com/nextcloud/common/NextcloudClient.kt @@ -60,7 +60,7 @@ class NextcloudClient private constructor( companion object { @JvmStatic - val TAG = NextcloudClient::class.java.simpleName + val TAG: String = NextcloudClient::class.java.simpleName private fun createDefaultClient(context: Context): OkHttpClient { val trustManager = AdvancedX509TrustManager(NetworkUtils.getKnownServersStore(context)) @@ -81,6 +81,8 @@ class NextcloudClient private constructor( Log_OC.d(this, "Proxy settings: $proxyHost:$proxyPort") } + val userAgentInterceptor = UserAgentInterceptor() + return OkHttpClient.Builder() .cookieJar(CookieJar.NO_COOKIES) .connectTimeout(DEFAULT_CONNECTION_TIMEOUT_LONG, TimeUnit.MILLISECONDS) @@ -93,6 +95,7 @@ class NextcloudClient private constructor( .hostnameVerifier { _: String?, _: SSLSession? -> true } .fastFallback(true) .proxy(proxy) + .addInterceptor(userAgentInterceptor) .build() } } @@ -135,6 +138,18 @@ class NextcloudClient private constructor( return httpStatus } + fun execute(method: DavMethod): T { + return method.execute(this) + } + + fun disabledRedirectClient(): OkHttpClient { + return client + .newBuilder() + .followRedirects(false) + .authenticator(NextcloudAuthenticator(credentials)) + .build() + } + internal fun execute(request: Request): ResponseOrError { return try { val response = client.newCall(request).execute() diff --git a/library/src/main/java/com/nextcloud/common/OkHttpMethodBase.kt b/library/src/main/java/com/nextcloud/common/OkHttpMethodBase.kt index 7e396748a..346785a0e 100644 --- a/library/src/main/java/com/nextcloud/common/OkHttpMethodBase.kt +++ b/library/src/main/java/com/nextcloud/common/OkHttpMethodBase.kt @@ -9,7 +9,6 @@ */ package com.nextcloud.common -import com.owncloud.android.lib.common.OwnCloudClientManagerFactory import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.utils.Log_OC import okhttp3.Headers @@ -30,7 +29,6 @@ abstract class OkHttpMethodBase( ) { companion object { const val UNKNOWN_STATUS_CODE: Int = -1 - const val USER_AGENT = "User-Agent" const val AUTHORIZATION = "Authorization" } @@ -123,7 +121,6 @@ abstract class OkHttpMethodBase( val temp = requestBuilder.url(buildQueryParameter()) requestHeaders[AUTHORIZATION] = nextcloudClient.credentials - requestHeaders[USER_AGENT] = OwnCloudClientManagerFactory.getUserAgent() requestHeaders.forEach { (name, value) -> temp.header(name, value) } if (useOcsApiRequestHeader) { @@ -150,7 +147,6 @@ abstract class OkHttpMethodBase( fun execute(client: PlainClient): Int { val temp = requestBuilder.url(buildQueryParameter()) - requestHeaders[USER_AGENT] = OwnCloudClientManagerFactory.getUserAgent() requestHeaders.forEach { (name, value) -> temp.header(name, value) } applyType(temp) diff --git a/library/src/main/java/com/nextcloud/common/UserAgentInterceptor.kt b/library/src/main/java/com/nextcloud/common/UserAgentInterceptor.kt new file mode 100644 index 000000000..488f3265b --- /dev/null +++ b/library/src/main/java/com/nextcloud/common/UserAgentInterceptor.kt @@ -0,0 +1,30 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.nextcloud.common + +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory +import okhttp3.Interceptor +import okhttp3.Response + +/** + * Interceptor for [okhttp3.Request]s. + * + * Adds user agent derived from [OwnCloudClientManagerFactory.getUserAgent] to every request. + */ +class UserAgentInterceptor : Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + val userAgent = OwnCloudClientManagerFactory.getUserAgent() + val request = + chain.request() + .newBuilder() + .header("User-Agent", userAgent) + .build() + return chain.proceed(request) + } +} diff --git a/library/src/main/java/com/nextcloud/extensions/ArrayExtensions.kt b/library/src/main/java/com/nextcloud/extensions/ArrayExtensions.kt new file mode 100644 index 000000000..8b8bd8d80 --- /dev/null +++ b/library/src/main/java/com/nextcloud/extensions/ArrayExtensions.kt @@ -0,0 +1,26 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ +package com.nextcloud.extensions + +import at.bitfire.dav4jvm.Property +import org.apache.jackrabbit.webdav.property.DavPropertyName +import org.apache.jackrabbit.webdav.property.DavPropertyNameSet +import org.apache.jackrabbit.webdav.xml.Namespace + +/** + * Returns DavPropertyNameSet for given array of Property.Name. + * + * remove - only intended as a transitional aid + */ +fun Array.toLegacyPropset(): DavPropertyNameSet { + val propertySet = DavPropertyNameSet() + for (property in this) { + propertySet.add(DavPropertyName.create(property.name, Namespace.getNamespace(property.namespace))) + } + return propertySet +} diff --git a/library/src/main/java/com/nextcloud/extensions/ParcelableExtensions.kt b/library/src/main/java/com/nextcloud/extensions/ParcelableExtensions.kt new file mode 100644 index 000000000..9383160ca --- /dev/null +++ b/library/src/main/java/com/nextcloud/extensions/ParcelableExtensions.kt @@ -0,0 +1,29 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ +package com.nextcloud.extensions + +import android.os.Build +import android.os.Parcel + +@Suppress("DEPRECATION", "UNCHECKED_CAST") +inline fun Parcel.readParcelableArrayCompat(type: Class): Array? { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + this.readParcelableArray(type::class.java.classLoader, this::class.java) + } else { + this.readParcelableArray(type::class.java.classLoader) + } as? Array +} + +@Suppress("DEPRECATION") +inline fun Parcel.readSerializableCompat(type: Class): T { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + this.readSerializable(type::class.java.classLoader, this::class.java) as T + } else { + this.readSerializable() as T + } +} diff --git a/library/src/main/java/com/nextcloud/operations/MkColMethod.kt b/library/src/main/java/com/nextcloud/operations/MkColMethod.kt new file mode 100644 index 000000000..6c3f340b8 --- /dev/null +++ b/library/src/main/java/com/nextcloud/operations/MkColMethod.kt @@ -0,0 +1,48 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ +package com.nextcloud.operations + +import android.net.Uri +import at.bitfire.dav4jvm.DavResource +import com.nextcloud.common.DavMethod +import com.nextcloud.common.DavResponse +import okhttp3.Headers.Companion.toHeaders +import okhttp3.HttpUrl +import okhttp3.OkHttpClient +import okhttp3.Response +import okhttp3.internal.http.StatusLine + +class MkColMethod(httpUrl: HttpUrl) : DavMethod(httpUrl) { + private val headers = mutableMapOf() + + override fun apply( + client: OkHttpClient, + httpUrl: HttpUrl, + filesDavUri: Uri + ): DavResponse { + val result = DavResponse() + + DavResource(client, httpUrl).mkCol( + xmlBody = null, + headers = headers.toHeaders() + ) { response: Response -> + result.success = response.isSuccessful + result.status = StatusLine.get(response) + result.headers = response.headers + } + + return result + } + + fun addRequestHeader( + key: String, + value: String + ) { + headers[key] = value + } +} diff --git a/library/src/main/java/com/nextcloud/operations/MoveMethod.kt b/library/src/main/java/com/nextcloud/operations/MoveMethod.kt new file mode 100644 index 000000000..0f0847f18 --- /dev/null +++ b/library/src/main/java/com/nextcloud/operations/MoveMethod.kt @@ -0,0 +1,50 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ +package com.nextcloud.operations + +import android.net.Uri +import at.bitfire.dav4jvm.DavResource +import com.nextcloud.common.DavMethod +import com.nextcloud.common.DavResponse +import okhttp3.HttpUrl +import okhttp3.OkHttpClient +import okhttp3.internal.http.StatusLine + +class MoveMethod( + httpUrl: HttpUrl, + private val destination: HttpUrl, + private val forceOverwrite: Boolean = false +) : DavMethod(httpUrl) { + private val headers = mutableMapOf() + + override fun apply( + client: OkHttpClient, + httpUrl: HttpUrl, + filesDavUri: Uri + ): DavResponse { + val result = DavResponse() + + DavResource(client, httpUrl).move( + destination = destination, + overwrite = forceOverwrite + ) { response -> + result.success = response.isSuccessful + result.status = StatusLine.get(response) + result.headers = response.headers + } + + return result + } + + fun addRequestHeader( + key: String, + value: String + ) { + headers[key] = value + } +} diff --git a/library/src/main/java/com/nextcloud/operations/PropFindMethod.kt b/library/src/main/java/com/nextcloud/operations/PropFindMethod.kt new file mode 100644 index 000000000..c95ecc84e --- /dev/null +++ b/library/src/main/java/com/nextcloud/operations/PropFindMethod.kt @@ -0,0 +1,62 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2023-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-FileCopyrightText: 2023 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.nextcloud.operations + +import android.net.Uri +import at.bitfire.dav4jvm.DavResource +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.Response +import com.nextcloud.common.DavMethod +import com.owncloud.android.lib.common.network.WebdavUtils +import com.owncloud.android.lib.common.utils.WebDavFileUtils +import okhttp3.HttpUrl +import okhttp3.OkHttpClient + +class PropFindMethod + @JvmOverloads + constructor( + httpUrl: HttpUrl, + private val propertySet: Array = WebdavUtils.PROPERTYSETS.ALL, + private val depth: Int = 1 + ) : DavMethod(httpUrl) { + override fun apply( + client: OkHttpClient, + httpUrl: HttpUrl, + filesDavUri: Uri + ): PropFindResult { + val result = PropFindResult() + + @Suppress("SpreadOperator") + DavResource(client, httpUrl).propfind( + depth, + *propertySet + ) { response: Response, hrefRelation: Response.HrefRelation? -> + result.davResponse.success = response.isSuccess() + response.status?.let { status -> + result.davResponse.status = status + } + + when (hrefRelation) { + Response.HrefRelation.MEMBER -> + result.children.add( + WebDavFileUtils.parseResponse(response, filesDavUri) + ) + + Response.HrefRelation.SELF, Response.HrefRelation.OTHER -> + result.root = + WebDavFileUtils.parseResponse(response, filesDavUri) + + else -> {} + } + } + + return result + } + } diff --git a/library/src/main/java/com/nextcloud/operations/PropFindResult.kt b/library/src/main/java/com/nextcloud/operations/PropFindResult.kt new file mode 100644 index 000000000..9e73e7d92 --- /dev/null +++ b/library/src/main/java/com/nextcloud/operations/PropFindResult.kt @@ -0,0 +1,23 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2023-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-FileCopyrightText: 2023 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.nextcloud.operations + +import com.nextcloud.common.DavResponse +import com.owncloud.android.lib.resources.files.model.RemoteFile + +data class PropFindResult( + val davResponse: DavResponse = DavResponse(), + var root: RemoteFile = RemoteFile(), + val children: MutableList = mutableListOf() +) { + fun getContent(): List { + return listOf(root) + children + } +} diff --git a/library/src/main/java/com/nextcloud/operations/PropPatchMethod.kt b/library/src/main/java/com/nextcloud/operations/PropPatchMethod.kt new file mode 100644 index 000000000..96b5b3442 --- /dev/null +++ b/library/src/main/java/com/nextcloud/operations/PropPatchMethod.kt @@ -0,0 +1,44 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ +package com.nextcloud.operations + +import android.net.Uri +import at.bitfire.dav4jvm.DavResource +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.Response +import com.nextcloud.common.DavMethod +import com.nextcloud.common.DavResponse +import okhttp3.HttpUrl +import okhttp3.OkHttpClient + +class PropPatchMethod + @JvmOverloads + constructor( + httpUrl: HttpUrl, + private val setProperties: Map = emptyMap(), + private val removeProperties: List = emptyList() + ) : DavMethod(httpUrl) { + override fun apply( + client: OkHttpClient, + httpUrl: HttpUrl, + filesDavUri: Uri + ): DavResponse { + val result = DavResponse() + DavResource( + client, + httpUrl + ).proppatch(setProperties, removeProperties) { response: Response, hrefRelation: Response.HrefRelation? -> + result.success = response.isSuccess() + response.status?.let { status -> + result.status = status + } + } + + return result + } + } diff --git a/library/src/main/java/com/nextcloud/operations/PutMethod.kt b/library/src/main/java/com/nextcloud/operations/PutMethod.kt index 61567f566..5298e147a 100644 --- a/library/src/main/java/com/nextcloud/operations/PutMethod.kt +++ b/library/src/main/java/com/nextcloud/operations/PutMethod.kt @@ -10,6 +10,7 @@ package com.nextcloud.operations import com.nextcloud.common.OkHttpMethodBase import okhttp3.Request import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody /** * HTTP PUT method that uses OkHttp with new NextcloudClient @@ -20,8 +21,6 @@ class PutMethod( val body: RequestBody? = null ) : OkHttpMethodBase(uri, useOcsApiRequestHeader) { override fun applyType(temp: Request.Builder) { - body?.let { - temp.put(it) - } + temp.put(body ?: "".toRequestBody()) } } diff --git a/library/src/main/java/com/owncloud/android/lib/common/accounts/ExternalLinksOperation.java b/library/src/main/java/com/owncloud/android/lib/common/accounts/ExternalLinksOperation.java index 4d07dae77..0c10ee450 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/accounts/ExternalLinksOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/common/accounts/ExternalLinksOperation.java @@ -7,9 +7,9 @@ */ package com.owncloud.android.lib.common.accounts; +import com.nextcloud.common.NextcloudClient; import com.owncloud.android.lib.common.ExternalLink; import com.owncloud.android.lib.common.ExternalLinkType; -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; @@ -17,18 +17,18 @@ import com.owncloud.android.lib.resources.status.OCCapability; import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.NameValuePair; -import org.apache.commons.httpclient.methods.GetMethod; import org.json.JSONArray; import org.json.JSONObject; import java.util.ArrayList; +import java.util.List; +import java.util.Map; /** * gets external links provided by 'external' app */ -public class ExternalLinksOperation extends RemoteOperation { +public class ExternalLinksOperation extends RemoteOperation> { private static final String TAG = ExternalLinksOperation.class.getSimpleName(); @@ -48,24 +48,23 @@ public class ExternalLinksOperation extends RemoteOperation { @Override - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result = null; - int status = -1; - GetMethod get = null; + public RemoteOperationResult> run(NextcloudClient client) { + RemoteOperationResult> result; + int status; + com.nextcloud.operations.GetMethod get = null; String ocsUrl = client.getBaseUri() + OCS_ROUTE_EXTERNAL_LINKS; try { // check capabilities - RemoteOperation getCapabilities = new GetCapabilitiesRemoteOperation(); - RemoteOperationResult capabilitiesResult = getCapabilities.execute(client); - OCCapability capability = (OCCapability) capabilitiesResult.getData().get(0); + RemoteOperation getCapabilities = new GetCapabilitiesRemoteOperation(); + RemoteOperationResult capabilitiesResult = getCapabilities.execute(client); + OCCapability capability = capabilitiesResult.getResultData(); - if (capability.getExternalLinks().isTrue()) { + if (capability != null && capability.getExternalLinks().isTrue()) { - get = new GetMethod(ocsUrl); - get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE); - get.setQueryString(new NameValuePair[]{new NameValuePair("format", "json")}); - status = client.executeMethod(get); + get = new com.nextcloud.operations.GetMethod(ocsUrl, true); + get.setQueryString(Map.of("format", "json")); + status = client.execute(get); if (isSuccess(status)) { String response = get.getResponseBodyAsString(); @@ -74,34 +73,25 @@ protected RemoteOperationResult run(OwnCloudClient client) { // parse JSONArray links = new JSONObject(response).getJSONObject(NODE_OCS).getJSONArray(NODE_DATA); - ArrayList resultLinks = new ArrayList<>(); + ArrayList resultLinks = new ArrayList<>(); for (int i = 0; i < links.length(); i++) { JSONObject link = links.getJSONObject(i); if (link != null) { - Integer id = link.getInt(NODE_ID); + int id = link.getInt(NODE_ID); String iconUrl = link.getString(NODE_ICON); String language = ""; if (link.has(NODE_LANGUAGE)) { language = link.getString(NODE_LANGUAGE); } - ExternalLinkType type; - switch (link.getString(NODE_TYPE)) { - case "link": - type = ExternalLinkType.LINK; - break; - case "settings": - type = ExternalLinkType.SETTINGS; - break; - case "quota": - type = ExternalLinkType.QUOTA; - break; - default: - type = ExternalLinkType.UNKNOWN; - break; - } + ExternalLinkType type = switch (link.getString(NODE_TYPE)) { + case "link" -> ExternalLinkType.LINK; + case "settings" -> ExternalLinkType.SETTINGS; + case "quota" -> ExternalLinkType.QUOTA; + default -> ExternalLinkType.UNKNOWN; + }; String name = link.getString(NODE_NAME); @@ -117,26 +107,22 @@ protected RemoteOperationResult run(OwnCloudClient client) { } } - result = new RemoteOperationResult(true, status, get.getResponseHeaders()); - result.setData(resultLinks); + result = new RemoteOperationResult<>(true, get); + result.setResultData(resultLinks); } else { - result = new RemoteOperationResult(false, status, get.getResponseHeaders()); + result = new RemoteOperationResult<>(false, get); String response = get.getResponseBodyAsString(); Log_OC.e(TAG, "Failed response while getting external links "); - if (response != null) { - Log_OC.e(TAG, "*** status code: " + status + " ; response message: " + response); - } else { - Log_OC.e(TAG, "*** status code: " + status); - } + Log_OC.e(TAG, "*** status code: " + status + " ; response message: " + response); } } else { - result = new RemoteOperationResult(RemoteOperationResult.ResultCode.NOT_AVAILABLE); + result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.NOT_AVAILABLE); Log_OC.d(TAG, "External links disabled"); } } catch (Exception e) { - result = new RemoteOperationResult(e); + result = new RemoteOperationResult<>(e); Log_OC.e(TAG, "Exception while getting external links ", e); } finally { if (get != null) { diff --git a/library/src/main/java/com/owncloud/android/lib/common/network/ExtendedProperties.kt b/library/src/main/java/com/owncloud/android/lib/common/network/ExtendedProperties.kt new file mode 100644 index 000000000..130964f2f --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/common/network/ExtendedProperties.kt @@ -0,0 +1,60 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ +package com.owncloud.android.lib.common.network + +import at.bitfire.dav4jvm.Property + +enum class ExtendedProperties(val value: String, val namespace: String) { + CREATION_TIME("creation_time", WebdavUtils.NAMESPACE_NC), + COMMENTS_READ_MARKER("readMarker", WebdavUtils.NAMESPACE_NC), + DISPLAY_NAME("display-name", WebdavUtils.NAMESPACE_OC), + FAVORITE("favorite", WebdavUtils.NAMESPACE_OC), + HAS_PREVIEW("has-preview", WebdavUtils.NAMESPACE_NC), + HIDDEN("hidden", WebdavUtils.NAMESPACE_NC), + IS_ENCRYPTED("is-encrypted", WebdavUtils.NAMESPACE_NC), + LOCK("lock", WebdavUtils.NAMESPACE_NC), + LOCK_OWNER("lock-owner", WebdavUtils.NAMESPACE_NC), + LOCK_OWNER_DISPLAY_NAME("lock-owner-displayname", WebdavUtils.NAMESPACE_NC), + LOCK_OWNER_EDITOR("lock-owner-editor", WebdavUtils.NAMESPACE_NC), + LOCK_OWNER_TYPE("lock-owner-type", WebdavUtils.NAMESPACE_NC), + LOCK_TIME("lock-time", WebdavUtils.NAMESPACE_NC), + LOCK_TIMEOUT("lock-timeout", WebdavUtils.NAMESPACE_NC), + LOCK_TOKEN("lock-token", WebdavUtils.NAMESPACE_NC), + + @Deprecated("Removed with v28. Use METADATA_PHOTOS_GPS instead.") + METADATA_GPS("file-metadata-gps", WebdavUtils.NAMESPACE_NC), + METADATA_LIVE_PHOTO("metadata-files-live-photo", WebdavUtils.NAMESPACE_NC), + METADATA_PHOTOS_GPS("metadata-photos-gps", WebdavUtils.NAMESPACE_NC), + METADATA_PHOTOS_SIZE("metadata-photos-size", WebdavUtils.NAMESPACE_NC), + + @Deprecated("Removed with v28. Use METADATA_PHOTOS_SIZE instead.") + METADATA_SIZE("file-metadata-size", WebdavUtils.NAMESPACE_NC), + MOUNT_TYPE("mount-type", WebdavUtils.NAMESPACE_NC), + NAME_LOCAL_ID("fileid", WebdavUtils.NAMESPACE_OC), + NAME_PERMISSIONS("permissions", WebdavUtils.NAMESPACE_OC), + NAME_REMOTE_ID("id", WebdavUtils.NAMESPACE_OC), + NAME_SIZE("size", WebdavUtils.NAMESPACE_OC), + NOTE("note", WebdavUtils.NAMESPACE_NC), + OWNER_DISPLAY_NAME("owner-display-name", WebdavUtils.NAMESPACE_OC), + OWNER_ID("owner-id", WebdavUtils.NAMESPACE_OC), + RICH_WORKSPACE("rich-workspace", WebdavUtils.NAMESPACE_NC), + SHAREES("sharees", WebdavUtils.NAMESPACE_NC), + SHAREES_DISPLAY_NAME("display-name", WebdavUtils.NAMESPACE_NC), + SHAREES_ID("id", WebdavUtils.NAMESPACE_NC), + SHAREES_SHARE_TYPE("type", WebdavUtils.NAMESPACE_NC), + SYSTEM_TAGS("system-tags", WebdavUtils.NAMESPACE_NC), + TRASHBIN_DELETION_TIME("trashbin-deletion-time", WebdavUtils.NAMESPACE_NC), + TRASHBIN_FILENAME("trashbin-filename", WebdavUtils.NAMESPACE_NC), + TRASHBIN_ORIGINAL_LOCATION("trashbin-original-location", WebdavUtils.NAMESPACE_NC), + UNREAD_COMMENTS("comments-unread", WebdavUtils.NAMESPACE_OC), + UPLOAD_TIME("upload_time", WebdavUtils.NAMESPACE_NC); + + fun toPropertyName(): Property.Name { + return Property.Name(namespace, value) + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/common/network/WebdavEntry.kt b/library/src/main/java/com/owncloud/android/lib/common/network/WebdavEntry.kt index 39076cd26..63f6b51a6 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/network/WebdavEntry.kt +++ b/library/src/main/java/com/owncloud/android/lib/common/network/WebdavEntry.kt @@ -29,7 +29,7 @@ import org.w3c.dom.Element import java.math.BigDecimal @Suppress("Detekt.TooGenericExceptionCaught") // legacy code -class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { +class WebdavEntry(ms: MultiStatusResponse, splitElement: String) { var name: String? = null private set var path: String? = null @@ -68,7 +68,7 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { var unreadCommentsCount = 0 var isHasPreview = false var note = "" - var sharees = arrayOfNulls(0) + var sharees = arrayOf() var richWorkspace: String? = null var isLocked = false private set @@ -86,7 +86,7 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { private set var lockToken: String? = null private set - var tags = arrayOfNulls(0) + var tags = arrayOf() var imageDimension: ImageDimension? = null var geoLocation: GeoLocation? = null var hidden = false @@ -104,8 +104,6 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { init { resetData() - val ocNamespace = Namespace.getNamespace(NAMESPACE_OC) - val ncNamespace = Namespace.getNamespace(NAMESPACE_NC) if (ms.status.isNotEmpty()) { uri = ms.href path = @@ -132,12 +130,8 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { val contentType = prop.value as String? // dvelasco: some builds of ownCloud server 4.0.x added a trailing ';' // to the MIME type ; if looks fixed, but let's be cautious - if (contentType != null) { - if (contentType.contains(";")) { - this.contentType = contentType.substring(0, contentType.indexOf(";")) - } else { - this.contentType = contentType - } + contentType?.let { + this.contentType = it.substringBefore(";") } } @@ -147,7 +141,7 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { if (prop != null) { val value = prop.value if (value != null) { - contentType = "DIR" // a specific attribute would be better, + contentType = DIR_TYPE // a specific attribute would be better, // but this is enough; // unless while we have no reason to distinguish // MIME types for folders @@ -168,7 +162,7 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } // {NS:} creation_time - prop = propSet[EXTENDED_PROPERTY_CREATION_TIME, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.CREATION_TIME) if (prop != null) { createTimestamp = try { @@ -179,7 +173,7 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } // {NS:} upload_time - prop = propSet[EXTENDED_PROPERTY_UPLOAD_TIME, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.UPLOAD_TIME) if (prop != null) { uploadTimestamp = try { @@ -225,31 +219,31 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } // OC permissions property - prop = propSet[EXTENDED_PROPERTY_NAME_PERMISSIONS, ocNamespace] + prop = getDavProp(propSet, ExtendedProperties.NAME_PERMISSIONS) if (prop != null && prop.value != null) { permissions = prop.value.toString() } // OC remote id property - prop = propSet[EXTENDED_PROPERTY_NAME_REMOTE_ID, ocNamespace] + prop = getDavProp(propSet, ExtendedProperties.NAME_REMOTE_ID) if (prop != null) { remoteId = prop.value.toString() } // OC remote id property - prop = propSet[EXTENDED_PROPERTY_NAME_LOCAL_ID, ocNamespace] + prop = getDavProp(propSet, ExtendedProperties.NAME_LOCAL_ID) if (prop != null) { localId = (prop.value as String).toLong() } // OC size property - prop = propSet[EXTENDED_PROPERTY_NAME_SIZE, ocNamespace] + prop = getDavProp(propSet, ExtendedProperties.NAME_SIZE) if (prop != null) { size = (prop.value as String).toLong() } // OC favorite property - prop = propSet[EXTENDED_PROPERTY_FAVORITE, ocNamespace] + prop = getDavProp(propSet, ExtendedProperties.FAVORITE) isFavorite = if (prop != null) { val favoriteValue = prop.value as String @@ -259,7 +253,7 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } // NC encrypted property - prop = propSet[EXTENDED_PROPERTY_IS_ENCRYPTED, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.IS_ENCRYPTED) isEncrypted = if (prop != null) { val encryptedValue = prop.value as String @@ -269,7 +263,7 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } // NC mount-type property - prop = propSet[EXTENDED_PROPERTY_MOUNT_TYPE, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.MOUNT_TYPE) mountType = if (prop != null) { when (prop.value) { @@ -290,7 +284,7 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } // OC owner-id property - prop = propSet[EXTENDED_PROPERTY_OWNER_ID, ocNamespace] + prop = getDavProp(propSet, ExtendedProperties.OWNER_ID) ownerId = if (prop != null) { prop.value as String @@ -299,7 +293,7 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } // OC owner-display-name property - prop = propSet[EXTENDED_PROPERTY_OWNER_DISPLAY_NAME, ocNamespace] + prop = getDavProp(propSet, ExtendedProperties.OWNER_DISPLAY_NAME) ownerDisplayName = if (prop != null) { prop.value as String @@ -308,7 +302,7 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } // OC unread comments property - prop = propSet[EXTENDED_PROPERTY_UNREAD_COMMENTS, ocNamespace] + prop = getDavProp(propSet, ExtendedProperties.UNREAD_COMMENTS) unreadCommentsCount = if (prop != null) { Integer.valueOf(prop.value.toString()) @@ -317,7 +311,7 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } // NC has preview property - prop = propSet[EXTENDED_PROPERTY_HAS_PREVIEW, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.HAS_PREVIEW) isHasPreview = if (prop != null) { java.lang.Boolean.valueOf(prop.value.toString()) @@ -326,32 +320,32 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } // NC trashbin-original-location - prop = propSet[TRASHBIN_ORIGINAL_LOCATION, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.TRASHBIN_ORIGINAL_LOCATION) if (prop != null) { trashbinOriginalLocation = prop.value.toString() } // NC trashbin-filename - prop = propSet[TRASHBIN_FILENAME, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.TRASHBIN_FILENAME) if (prop != null) { trashbinFilename = prop.value.toString() } // NC trashbin-deletion-time - prop = propSet[TRASHBIN_DELETION_TIME, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.TRASHBIN_DELETION_TIME) if (prop != null) { trashbinDeletionTimestamp = (prop.value as String).toLong() } // NC note property - prop = propSet[EXTENDED_PROPERTY_NOTE, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.NOTE) if (prop != null && prop.value != null) { note = prop.value.toString() } // NC rich-workspace property // can be null if rich-workspace is disabled for this user - prop = propSet[EXTENDED_PROPERTY_RICH_WORKSPACE, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.RICH_WORKSPACE) richWorkspace = if (prop != null) { if (prop.value != null) { @@ -364,14 +358,13 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } // NC sharees property - prop = propSet[EXTENDED_PROPERTY_SHAREES, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.SHAREES) if (prop != null && prop.value != null) { if (prop.value is ArrayList<*>) { val list = prop.value as ArrayList<*> - val tempList: MutableList = ArrayList() - for (i in list.indices) { - val element = list[i] as Element - val user = createShareeUser(element) + val tempList: MutableList = ArrayList() + for (element in list) { + val user = createShareeUser(element as Element) if (user != null) { tempList.add(user) } @@ -387,7 +380,7 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } } - prop = propSet[EXTENDED_PROPERTY_SYSTEM_TAGS, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.SYSTEM_TAGS) if (prop != null && prop.value != null) { if (prop.value is ArrayList<*>) { val list = prop.value as ArrayList<*> @@ -409,10 +402,10 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } // NC metadata size property - prop = propSet[EXTENDED_PROPERTY_METADATA_PHOTOS_SIZE, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.METADATA_SIZE) imageDimension = if (prop == null) { - prop = propSet[EXTENDED_PROPERTY_METADATA_SIZE, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.METADATA_SIZE) gson.fromDavProperty(prop) } else { val xmlData = prop.value as? ArrayList<*> @@ -422,16 +415,16 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { if (width != null && height != null) { ImageDimension(width, height) } else { - prop = propSet[EXTENDED_PROPERTY_METADATA_SIZE, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.METADATA_SIZE) gson.fromDavProperty(prop) } } // NC metadata gps property - prop = propSet[EXTENDED_PROPERTY_METADATA_PHOTOS_GPS, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.METADATA_PHOTOS_GPS) geoLocation = if (prop == null) { - prop = propSet[EXTENDED_PROPERTY_METADATA_GPS, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.METADATA_GPS) gson.fromDavProperty(prop) } else { val xmlData = prop.value as? ArrayList<*> @@ -441,19 +434,19 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { if (latitude != null && longitude != null) { GeoLocation(latitude, longitude) } else { - prop = propSet[EXTENDED_PROPERTY_METADATA_GPS, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.METADATA_GPS) gson.fromDavProperty(prop) } } // NC metadata live photo property: - prop = propSet[EXTENDED_PROPERTY_METADATA_LIVE_PHOTO, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.METADATA_LIVE_PHOTO) if (prop != null && prop.value != null) { livePhoto = prop.value.toString() } // NC has hidden property - prop = propSet[EXTENDED_PROPERTY_HIDDEN, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.HIDDEN) hidden = if (prop != null) { java.lang.Boolean.valueOf(prop.value.toString()) @@ -461,25 +454,22 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { false } - parseLockProperties(ncNamespace, propSet) + parseLockProperties(propSet) } else { Log_OC.e("WebdavEntry", "General error, no status for webdav response") } } - private fun parseLockProperties( - ncNamespace: Namespace, - propSet: DavPropertySet - ) { + private fun parseLockProperties(propSet: DavPropertySet) { // file locking - var prop: DavProperty<*>? = propSet[EXTENDED_PROPERTY_LOCK, ncNamespace] + var prop = getDavProp(propSet, ExtendedProperties.LOCK) isLocked = if (prop != null && prop.value != null) { "1" == prop.value as String } else { false } - prop = propSet[EXTENDED_PROPERTY_LOCK_OWNER_TYPE, ncNamespace] + prop = getDavProp(propSet, ExtendedProperties.LOCK_OWNER_TYPE) lockOwnerType = if (prop != null && prop.value != null) { val value: Int = (prop.value as String).toInt() @@ -487,35 +477,16 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } else { null } - lockOwnerId = parseStringProp(propSet, EXTENDED_PROPERTY_LOCK_OWNER, ncNamespace) - lockOwnerDisplayName = - parseStringProp(propSet, EXTENDED_PROPERTY_LOCK_OWNER_DISPLAY_NAME, ncNamespace) - lockOwnerEditor = parseStringProp(propSet, EXTENDED_PROPERTY_LOCK_OWNER_EDITOR, ncNamespace) - lockTimestamp = parseLongProp(propSet, EXTENDED_PROPERTY_LOCK_TIME, ncNamespace) - lockTimeout = parseLongProp(propSet, EXTENDED_PROPERTY_LOCK_TIMEOUT, ncNamespace) - lockToken = parseStringProp(propSet, EXTENDED_PROPERTY_LOCK_TOKEN, ncNamespace) - } - - private fun parseStringProp( - propSet: DavPropertySet, - propName: String, - namespace: Namespace - ): String? { - val prop = propSet[propName, namespace] - return if (prop != null && prop.value != null) { - prop.value as String - } else { - null - } + lockOwnerId = parseStringProp(getDavProp(propSet, ExtendedProperties.LOCK_OWNER)) + lockOwnerDisplayName = parseStringProp(getDavProp(propSet, ExtendedProperties.LOCK_OWNER_DISPLAY_NAME)) + lockOwnerEditor = parseStringProp(getDavProp(propSet, ExtendedProperties.LOCK_OWNER_EDITOR)) + lockTimestamp = parseStringProp(getDavProp(propSet, ExtendedProperties.LOCK_TIME))?.toLong() ?: 0L + lockTimeout = parseStringProp(getDavProp(propSet, ExtendedProperties.LOCK_TIMEOUT))?.toLong() ?: 0L + lockToken = parseStringProp(getDavProp(propSet, ExtendedProperties.LOCK_TOKEN)) } - private fun parseLongProp( - propSet: DavPropertySet, - propName: String, - namespace: Namespace - ): Long { - val stringValue = parseStringProp(propSet, propName, namespace) - return stringValue?.toLong() ?: 0L + private fun parseStringProp(prop: DavProperty<*>?): String? { + return prop?.value as String? } private fun createShareeUser(element: Element): ShareeUser? { @@ -535,7 +506,11 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } private fun extractDisplayName(element: Element): String { - val displayName = element.getElementsByTagNameNS(NAMESPACE_NC, SHAREES_DISPLAY_NAME).item(0) + val displayName = + element.getElementsByTagNameNS( + ExtendedProperties.SHAREES_DISPLAY_NAME.namespace, + ExtendedProperties.SHAREES_DISPLAY_NAME.value + ).item(0) return if (displayName != null && displayName.firstChild != null) { displayName.firstChild.nodeValue } else { @@ -544,7 +519,11 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } private fun extractUserId(element: Element): String { - val userId = element.getElementsByTagNameNS(NAMESPACE_NC, SHAREES_ID).item(0) + val userId = + element.getElementsByTagNameNS( + ExtendedProperties.SHAREES_ID.namespace, + ExtendedProperties.SHAREES_ID.value + ).item(0) return if (userId != null && userId.firstChild != null) { userId.firstChild.nodeValue } else { @@ -553,7 +532,11 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } private fun extractShareType(element: Element): ShareType { - val shareType = element.getElementsByTagNameNS(NAMESPACE_NC, SHAREES_SHARE_TYPE).item(0) + val shareType = + element.getElementsByTagNameNS( + ExtendedProperties.SHAREES_SHARE_TYPE.namespace, + ExtendedProperties.SHAREES_SHARE_TYPE.value + ).item(0) if (shareType != null && shareType.firstChild != null) { val value = shareType.firstChild.nodeValue.toInt() return ShareType.fromValue(value) @@ -566,7 +549,7 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { } val isDirectory: Boolean - get() = "DIR" == contentType + get() = DIR_TYPE == contentType private fun resetData() { permissions = null @@ -585,54 +568,24 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) { isHasPreview = false } + /** + * Return dav property for given extended property via propSet. + * + * remove - only intended as a transitional aid + */ + private fun getDavProp( + propSet: DavPropertySet, + extendedProperty: ExtendedProperties + ): DavProperty<*>? { + return propSet[extendedProperty.value, Namespace.getNamespace(extendedProperty.namespace)] + } + companion object { private val TAG = WebdavEntry::class.java.simpleName - const val NAMESPACE_OC = "http://owncloud.org/ns" - const val NAMESPACE_NC = "http://nextcloud.org/ns" - const val EXTENDED_PROPERTY_NAME_PERMISSIONS = "permissions" - const val EXTENDED_PROPERTY_NAME_LOCAL_ID = "fileid" - const val EXTENDED_PROPERTY_NAME_REMOTE_ID = "id" - const val EXTENDED_PROPERTY_NAME_SIZE = "size" - const val EXTENDED_PROPERTY_FAVORITE = "favorite" - const val EXTENDED_PROPERTY_IS_ENCRYPTED = "is-encrypted" - const val EXTENDED_PROPERTY_MOUNT_TYPE = "mount-type" - const val EXTENDED_PROPERTY_OWNER_ID = "owner-id" - const val EXTENDED_PROPERTY_OWNER_DISPLAY_NAME = "owner-display-name" - const val EXTENDED_PROPERTY_UNREAD_COMMENTS = "comments-unread" - const val EXTENDED_PROPERTY_HAS_PREVIEW = "has-preview" - const val EXTENDED_PROPERTY_NOTE = "note" - const val EXTENDED_PROPERTY_SHAREES = "sharees" - const val EXTENDED_PROPERTY_RICH_WORKSPACE = "rich-workspace" - const val EXTENDED_PROPERTY_CREATION_TIME = "creation_time" - const val EXTENDED_PROPERTY_UPLOAD_TIME = "upload_time" - const val EXTENDED_PROPERTY_LOCK = "lock" - const val EXTENDED_PROPERTY_LOCK_OWNER_TYPE = "lock-owner-type" - const val EXTENDED_PROPERTY_LOCK_OWNER = "lock-owner" - const val EXTENDED_PROPERTY_LOCK_OWNER_DISPLAY_NAME = "lock-owner-displayname" - const val EXTENDED_PROPERTY_LOCK_OWNER_EDITOR = "lock-owner-editor" - const val EXTENDED_PROPERTY_LOCK_TIME = "lock-time" - const val EXTENDED_PROPERTY_LOCK_TIMEOUT = "lock-timeout" - const val EXTENDED_PROPERTY_LOCK_TOKEN = "lock-token" - const val EXTENDED_PROPERTY_SYSTEM_TAGS = "system-tags" - - // v27 - const val EXTENDED_PROPERTY_METADATA_SIZE = "file-metadata-size" - const val EXTENDED_PROPERTY_METADATA_GPS = "file-metadata-gps" - - const val EXTENDED_PROPERTY_HIDDEN = "hidden" - const val EXTENDED_PROPERTY_METADATA_LIVE_PHOTO = "metadata-files-live-photo" - - const val EXTENDED_PROPERTY_METADATA_PHOTOS_SIZE = "metadata-photos-size" - const val EXTENDED_PROPERTY_METADATA_PHOTOS_GPS = "metadata-photos-gps" - const val TRASHBIN_FILENAME = "trashbin-filename" - const val TRASHBIN_ORIGINAL_LOCATION = "trashbin-original-location" - const val TRASHBIN_DELETION_TIME = "trashbin-deletion-time" - const val SHAREES_DISPLAY_NAME = "display-name" - const val SHAREES_ID = "id" - const val SHAREES_SHARE_TYPE = "type" - const val PROPERTY_QUOTA_USED_BYTES = "quota-used-bytes" - const val PROPERTY_QUOTA_AVAILABLE_BYTES = "quota-available-bytes" private const val IS_ENCRYPTED = "1" private const val CODE_PROP_NOT_FOUND = 404 + const val PROPERTY_QUOTA_USED_BYTES = "quota-used-bytes" + const val PROPERTY_QUOTA_AVAILABLE_BYTES = "quota-available-bytes" + const val DIR_TYPE = "DIR" } } diff --git a/library/src/main/java/com/owncloud/android/lib/common/network/WebdavUtils.java b/library/src/main/java/com/owncloud/android/lib/common/network/WebdavUtils.java deleted file mode 100644 index 0fb9c5362..000000000 --- a/library/src/main/java/com/owncloud/android/lib/common/network/WebdavUtils.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Nextcloud Android Library - * - * SPDX-FileCopyrightText: 2018-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2023 Alper Ozturk - * SPDX-FileCopyrightText: 2022 Álvaro Brey - * SPDX-FileCopyrightText: 2018-2022 Tobias Kaminsky - * SPDX-FileCopyrightText: 2014-2015 ownCloud Inc. - * SPDX-FileCopyrightText: 2015 masensio - * SPDX-FileCopyrightText: 2014-2015 David A. Velasco - * SPDX-FileCopyrightText: 2012 2012 Bartosz Przybylski - * SPDX-License-Identifier: MIT - */ -package com.owncloud.android.lib.common.network; - -import android.net.Uri; - -import androidx.annotation.Nullable; - -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; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -public class WebdavUtils { - private static final SimpleDateFormat DATETIME_FORMATS[] = { - new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US), - new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), - new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'", Locale.US), - new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US), - new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US), - new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), - new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US), - new SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.US) - }; - - public static @Nullable - Date parseResponseDate(String date) { - Date returnDate; - SimpleDateFormat format; - for (int i = 0; i < DATETIME_FORMATS.length; ++i) { - try { - format = DATETIME_FORMATS[i]; - synchronized (format) { - returnDate = format.parse(date); - } - return returnDate; - } catch (ParseException e) { - // this is not the format - } - } - return null; - } - - /** - * Encodes a path according to URI RFC 2396. - * - * If the received path doesn't start with "/", the method adds it. - * - * @param remoteFilePath Path - * @return Encoded path according to RFC 2396, always starting with "/" - */ - public static String encodePath(String remoteFilePath) { - String encodedPath = Uri.encode(remoteFilePath, "/"); - if (!encodedPath.startsWith("/")) - encodedPath = "/" + encodedPath; - return encodedPath; - } - - /** - * Builds a DavPropertyNameSet with all prop - * For using instead of DavConstants.PROPFIND_ALL_PROP - * @return - */ - public static DavPropertyNameSet getAllPropSet() { - Namespace ocNamespace = Namespace.getNamespace(WebdavEntry.NAMESPACE_OC); - Namespace ncNamespace = Namespace.getNamespace(WebdavEntry.NAMESPACE_NC); - DavPropertyNameSet propSet = new DavPropertyNameSet(); - propSet.add(DavPropertyName.DISPLAYNAME); - propSet.add(DavPropertyName.GETCONTENTTYPE); - propSet.add(DavPropertyName.RESOURCETYPE); - propSet.add(DavPropertyName.GETCONTENTLENGTH); - propSet.add(DavPropertyName.GETLASTMODIFIED); - propSet.add(DavPropertyName.CREATIONDATE); - propSet.add(DavPropertyName.GETETAG); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_PERMISSIONS, ocNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_LOCAL_ID, ocNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_REMOTE_ID, ocNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_SIZE, ocNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_FAVORITE, ocNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_IS_ENCRYPTED, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_MOUNT_TYPE, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_OWNER_ID, ocNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_OWNER_DISPLAY_NAME, ocNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_UNREAD_COMMENTS, ocNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_HAS_PREVIEW, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_NOTE, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_SHAREES, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_RICH_WORKSPACE, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_CREATION_TIME, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_UPLOAD_TIME, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_OWNER_TYPE, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_OWNER, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_OWNER_DISPLAY_NAME, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_OWNER_EDITOR, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_TIME, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_TIMEOUT, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_TOKEN, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_SYSTEM_TAGS, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_SIZE, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_GPS, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_PHOTOS_SIZE, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_PHOTOS_GPS, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_LIVE_PHOTO, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_HIDDEN, ncNamespace); - - return propSet; - } - - /** - * Builds a DavPropertyNameSet with properties for files - * @return - */ - public static DavPropertyNameSet getFilePropSet() { - Namespace ocNamespace = Namespace.getNamespace(WebdavEntry.NAMESPACE_OC); - Namespace ncNamespace = Namespace.getNamespace(WebdavEntry.NAMESPACE_NC); - - DavPropertyNameSet propSet = new DavPropertyNameSet(); - propSet.add(DavPropertyName.DISPLAYNAME); - propSet.add(DavPropertyName.GETCONTENTTYPE); - propSet.add(DavPropertyName.RESOURCETYPE); - propSet.add(DavPropertyName.GETCONTENTLENGTH); - propSet.add(DavPropertyName.GETLASTMODIFIED); - propSet.add(DavPropertyName.CREATIONDATE); - propSet.add(DavPropertyName.GETETAG); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_PERMISSIONS, ocNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_LOCAL_ID, ocNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_REMOTE_ID, ocNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_SIZE, ocNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_FAVORITE, ocNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_HAS_PREVIEW, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_SHAREES, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_CREATION_TIME, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_UPLOAD_TIME, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_OWNER_TYPE, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_OWNER, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_OWNER_DISPLAY_NAME, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_OWNER_EDITOR, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_TIME, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_TIMEOUT, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_TOKEN, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_IS_ENCRYPTED, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_SYSTEM_TAGS, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_SIZE, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_GPS, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_PHOTOS_SIZE, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_PHOTOS_GPS, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_LIVE_PHOTO, ncNamespace); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_HIDDEN, ncNamespace); - - return propSet; - } - - /** - * Builds a DavPropertyNameSet with properties for trashbin - * @return - */ - public static DavPropertyNameSet getTrashbinPropSet() { - DavPropertyNameSet propSet = new DavPropertyNameSet(); - propSet.add(DavPropertyName.RESOURCETYPE); - propSet.add(DavPropertyName.GETCONTENTTYPE); - propSet.add(DavPropertyName.GETCONTENTLENGTH); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_SIZE, Namespace.getNamespace(WebdavEntry.NAMESPACE_OC)); - propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_REMOTE_ID, Namespace.getNamespace(WebdavEntry.NAMESPACE_OC)); - propSet.add(WebdavEntry.TRASHBIN_FILENAME, Namespace.getNamespace(WebdavEntry.NAMESPACE_NC)); - propSet.add(WebdavEntry.TRASHBIN_ORIGINAL_LOCATION, Namespace.getNamespace(WebdavEntry.NAMESPACE_NC)); - propSet.add(WebdavEntry.TRASHBIN_DELETION_TIME, Namespace.getNamespace(WebdavEntry.NAMESPACE_NC)); - - 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; - } - - /** - * Builds a DavPropertyNameSet with properties for chunks - */ - public static DavPropertyNameSet getChunksPropSet() { - DavPropertyNameSet propSet = new DavPropertyNameSet(); - propSet.add(DavPropertyName.GETCONTENTTYPE); - propSet.add(DavPropertyName.RESOURCETYPE); - propSet.add(DavPropertyName.GETCONTENTLENGTH); - - 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; - } - -} diff --git a/library/src/main/java/com/owncloud/android/lib/common/network/WebdavUtils.kt b/library/src/main/java/com/owncloud/android/lib/common/network/WebdavUtils.kt new file mode 100644 index 000000000..5000636c2 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/common/network/WebdavUtils.kt @@ -0,0 +1,286 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.common.network + +import android.net.Uri +import at.bitfire.dav4jvm.PropertyRegistry.register +import at.bitfire.dav4jvm.property.webdav.CreationDate +import at.bitfire.dav4jvm.property.webdav.DisplayName +import at.bitfire.dav4jvm.property.webdav.GetContentLength +import at.bitfire.dav4jvm.property.webdav.GetContentType +import at.bitfire.dav4jvm.property.webdav.ResourceType +import com.google.gson.Gson +import com.owncloud.android.lib.resources.files.webdav.NCCreationTime +import com.owncloud.android.lib.resources.files.webdav.NCEncrypted +import com.owncloud.android.lib.resources.files.webdav.NCEtag +import com.owncloud.android.lib.resources.files.webdav.NCFavorite +import com.owncloud.android.lib.resources.files.webdav.NCGetLastModified +import com.owncloud.android.lib.resources.files.webdav.NCHidden +import com.owncloud.android.lib.resources.files.webdav.NCLock +import com.owncloud.android.lib.resources.files.webdav.NCLockOwner +import com.owncloud.android.lib.resources.files.webdav.NCLockOwnerDisplayName +import com.owncloud.android.lib.resources.files.webdav.NCLockOwnerEditor +import com.owncloud.android.lib.resources.files.webdav.NCLockOwnerType +import com.owncloud.android.lib.resources.files.webdav.NCLockTime +import com.owncloud.android.lib.resources.files.webdav.NCLockTimeout +import com.owncloud.android.lib.resources.files.webdav.NCLockToken +import com.owncloud.android.lib.resources.files.webdav.NCMetadataGPS +import com.owncloud.android.lib.resources.files.webdav.NCMetadataLivePhoto +import com.owncloud.android.lib.resources.files.webdav.NCMetadataPhotosGPS +import com.owncloud.android.lib.resources.files.webdav.NCMetadataPhotosSize +import com.owncloud.android.lib.resources.files.webdav.NCMetadataSize +import com.owncloud.android.lib.resources.files.webdav.NCMountType +import com.owncloud.android.lib.resources.files.webdav.NCNote +import com.owncloud.android.lib.resources.files.webdav.NCPermissions +import com.owncloud.android.lib.resources.files.webdav.NCPreview +import com.owncloud.android.lib.resources.files.webdav.NCRichWorkspace +import com.owncloud.android.lib.resources.files.webdav.NCSharees +import com.owncloud.android.lib.resources.files.webdav.NCTags +import com.owncloud.android.lib.resources.files.webdav.NCTrashbinDeletionTime +import com.owncloud.android.lib.resources.files.webdav.NCTrashbinFilename +import com.owncloud.android.lib.resources.files.webdav.NCTrashbinLocation +import com.owncloud.android.lib.resources.files.webdav.NCUploadTime +import com.owncloud.android.lib.resources.files.webdav.OCCommentsUnread +import com.owncloud.android.lib.resources.files.webdav.OCDisplayName +import com.owncloud.android.lib.resources.files.webdav.OCId +import com.owncloud.android.lib.resources.files.webdav.OCLocalId +import com.owncloud.android.lib.resources.files.webdav.OCOwnerDisplayName +import com.owncloud.android.lib.resources.files.webdav.OCOwnerId +import com.owncloud.android.lib.resources.files.webdav.OCSize +import org.apache.commons.httpclient.HttpMethod +import java.text.ParseException +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale + +object WebdavUtils { + const val NAMESPACE_OC = "http://owncloud.org/ns" + const val NAMESPACE_NC = "http://nextcloud.org/ns" + + internal val gson = Gson() + + private val DATETIME_FORMATS = + arrayOf( + SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US), + SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), + SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'", Locale.US), + SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US), + SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US), + SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), + SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US), + SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.US) + ) + + object PROPERTYSETS { + val ALL = + arrayOf( + DisplayName.NAME, + GetContentType.NAME, + ResourceType.NAME, + GetContentLength.NAME, + NCGetLastModified.NAME, + CreationDate.NAME, + NCEtag.NAME, + NCPermissions.NAME, + OCLocalId.NAME, + OCId.NAME, + OCSize.NAME, + NCFavorite.NAME, + NCEncrypted.NAME, + NCMountType.NAME, + OCOwnerId.NAME, + OCOwnerDisplayName.NAME, + OCCommentsUnread.NAME, + NCPreview.NAME, + NCNote.NAME, + NCSharees.NAME, + NCRichWorkspace.NAME, + NCCreationTime.NAME, + NCUploadTime.NAME, + NCLock.NAME, + NCLockOwnerType.NAME, + NCLockOwner.NAME, + NCLockOwnerDisplayName.NAME, + NCLockOwnerEditor.NAME, + NCLockTime.NAME, + NCLockTimeout.NAME, + NCLockToken.NAME, + NCTags.NAME, + NCMetadataSize.NAME, + NCMetadataGPS.NAME, + NCMetadataSize.NAME, + NCMetadataPhotosSize.NAME, + NCMetadataPhotosGPS.NAME, + NCMetadataLivePhoto.NAME, + NCHidden.NAME + ) + + val FILE = + arrayOf( + DisplayName.NAME, + GetContentType.NAME, + ResourceType.NAME, + GetContentLength.NAME, + NCGetLastModified.NAME, + CreationDate.NAME, + NCEtag.NAME, + NCPermissions.NAME, + OCLocalId.NAME, + OCId.NAME, + OCSize.NAME, + NCFavorite.NAME, + NCPreview.NAME, + NCSharees.NAME, + NCCreationTime.NAME, + NCUploadTime.NAME, + NCLock.NAME, + NCLockOwnerType.NAME, + NCLockOwner.NAME, + NCLockOwnerDisplayName.NAME, + NCLockOwnerEditor.NAME, + NCLockTime.NAME, + NCLockTimeout.NAME, + NCLockToken.NAME, + NCEncrypted.NAME, + NCTags.NAME, + NCMetadataSize.NAME, + NCMetadataGPS.NAME, + NCMetadataPhotosSize.NAME, + NCMetadataPhotosGPS.NAME, + NCMetadataLivePhoto.NAME, + NCHidden.NAME + ) + + val TRASHBIN = + arrayOf( + ResourceType.NAME, + GetContentType.NAME, + GetContentLength.NAME, + OCSize.NAME, + OCId.NAME, + NCTrashbinFilename.NAME, + NCTrashbinLocation.NAME, + NCTrashbinDeletionTime.NAME + ) + + val FILE_VERSION = + arrayOf( + GetContentType.NAME, + ResourceType.NAME, + GetContentLength.NAME, + NCGetLastModified.NAME, + CreationDate.NAME, + OCId.NAME, + OCSize.NAME + ) + + val CHUNK = + arrayOf( + GetContentType.NAME, + ResourceType.NAME, + GetContentLength.NAME + ) + } + + fun parseResponseDate(date: String?): Date? { + for (format in DATETIME_FORMATS) { + try { + date?.let { return format.parse(it) } + } catch (e: ParseException) { + // wrong format + } + } + return null + } + + /** + * Encodes a path according to URI RFC 2396. + * + * + * If the received path doesn't start with "/", the method adds it. + * + * @param remoteFilePath Path + * @return Encoded path according to RFC 2396, always starting with "/" + */ + fun encodePath(remoteFilePath: String?): String { + val encodedPath = Uri.encode(remoteFilePath, "/") + if (!encodedPath.startsWith("/")) { + return "/$encodedPath" + } + return encodedPath + } + + fun parseEtag(etag: String?): String { + if (etag.isNullOrEmpty()) { + return "" + } + return etag.removeSuffix("-gzip").removeSurrounding("\"") + } + + fun getEtagFromResponse(method: HttpMethod): String { + var 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") + } + if (eTag != null) { + return parseEtag(eTag.value) + } + return "" + } + + fun registerCustomFactories() { + val list = + listOf( + NCCreationTime.Factory(), + NCEncrypted.Factory(), + NCEtag.Factory(), + NCFavorite.Factory(), + NCGetLastModified.Factory(), + NCHidden.Factory(), + NCLock.Factory(), + NCLockOwnerDisplayName.Factory(), + NCLockOwnerEditor.Factory(), + NCLockOwner.Factory(), + NCLockOwnerType.Factory(), + NCLockTime.Factory(), + NCLockTimeout.Factory(), + NCLockToken.Factory(), + NCMetadataGPS.Factory(), + NCMetadataLivePhoto.Factory(), + NCMetadataPhotosGPS.Factory(), + NCMetadataPhotosSize.Factory(), + NCMetadataSize.Factory(), + NCMountType.Factory(), + NCNote.Factory(), + NCPermissions.Factory(), + NCPreview.Factory(), + NCRichWorkspace.Factory(), + NCSharees.Factory(), + NCTags.Factory(), + NCTrashbinDeletionTime.Factory(), + NCTrashbinFilename.Factory(), + NCTrashbinLocation.Factory(), + NCUploadTime.Factory(), + OCCommentsUnread.Factory(), + OCDisplayName.Factory(), + OCId.Factory(), + OCLocalId.Factory(), + OCOwnerDisplayName.Factory(), + OCOwnerId.Factory(), + OCSize.Factory() + ) + register(list) + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperation.java index 5ba1e4836..5f9ad06ab 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperation.java @@ -285,17 +285,21 @@ public Thread execute(Account account, Context context, mContext = context.getApplicationContext(); mCallerActivity = null; mClient = null; // the client instance will be created from - // mAccount and mContext in the runnerThread to create below - + // mAccount and mContext in the runnerThread to create below + mListener = listener; - + mListenerHandler = listenerHandler; - + Thread runnerThread = new Thread(this); runnerThread.start(); return runnerThread; } + public OwnCloudClient getClient() { + return mClient; + } + /** * This is a transitional wrapper around * {@link #execute(Account, Context, OnRemoteOperationListener, Handler)} @@ -432,15 +436,4 @@ public void run() { }); } } - - - /** - * Returns the current client instance to access the remote server. - * - * @return Current client instance to access the remote server. - */ - public final OwnCloudClient getClient() { - return mClient; - } - } diff --git a/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java deleted file mode 100644 index 48453ee4f..000000000 --- a/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ /dev/null @@ -1,741 +0,0 @@ -/* - * Nextcloud Android Library - * - * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2022 Álvaro Brey - * SPDX-FileCopyrightText: 2019-2021 Tobias Kaminsky - * SPDX-FileCopyrightText: 2017 Andy Scherzinger - * SPDX-FileCopyrightText: 2014-2016 ownCloud Inc. - * SPDX-FileCopyrightText: 2015 masensio - * SPDX-FileCopyrightText: 2014 David A. Velasco - * SPDX-FileCopyrightText: 2014 Jorge Antonio Diaz-Benito Soriano - * SPDX-FileCopyrightText: 2014-2016 Juan Carlos González Cabrero - * SPDX-FileCopyrightText: 2014 jabarros - * SPDX-License-Identifier: MIT - */ -package com.owncloud.android.lib.common.operations; - -import android.accounts.Account; -import android.accounts.AccountsException; -import android.os.Build; -import android.system.ErrnoException; -import android.system.OsConstants; - -import com.nextcloud.common.OkHttpMethodBase; -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 com.owncloud.android.lib.resources.files.CreateLocalFileException; - -import org.apache.commons.httpclient.ConnectTimeoutException; -import org.apache.commons.httpclient.Header; -import org.apache.commons.httpclient.HttpException; -import org.apache.commons.httpclient.HttpMethod; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.jackrabbit.webdav.DavException; -import org.json.JSONException; - -import java.io.ByteArrayInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.net.ConnectException; -import java.net.MalformedURLException; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Locale; - -import javax.net.ssl.SSLException; - -import okhttp3.Headers; - - -/** - * The result of a remote operation required to an ownCloud server. - *

- * Provides a common classification of remote operation results for all the application. - * - * @author David A. Velasco - */ -public class RemoteOperationResult implements Serializable { - - // Generated - should be refreshed every time the class changes!! - private static final long serialVersionUID = -4325446958558896222L; - private static final String TAG = RemoteOperationResult.class.getSimpleName(); - private static final String HEADER_WWW_AUTHENTICATE = "www-authenticate"; - private static final String HEADER_LOCATION = "location"; - - public enum ResultCode { - OK, - OK_SSL, - OK_NO_SSL, - UNHANDLED_HTTP_CODE, - UNAUTHORIZED, - FILE_NOT_FOUND, - INSTANCE_NOT_CONFIGURED, - UNKNOWN_ERROR, - WRONG_CONNECTION, - TIMEOUT, - INCORRECT_ADDRESS, - HOST_NOT_AVAILABLE, - NO_NETWORK_CONNECTION, - SSL_ERROR, - SSL_RECOVERABLE_PEER_UNVERIFIED, - BAD_OC_VERSION, - CANCELLED, - INVALID_LOCAL_FILE_NAME, - INVALID_OVERWRITE, - CONFLICT, - OAUTH2_ERROR, - SYNC_CONFLICT, - LOCAL_STORAGE_FULL, - LOCAL_STORAGE_NOT_MOVED, - LOCAL_STORAGE_NOT_COPIED, - OAUTH2_ERROR_ACCESS_DENIED, - QUOTA_EXCEEDED, - ACCOUNT_NOT_FOUND, - ACCOUNT_EXCEPTION, - ACCOUNT_NOT_NEW, - ACCOUNT_NOT_THE_SAME, - INVALID_CHARACTER_IN_NAME, - SHARE_NOT_FOUND, - LOCAL_STORAGE_NOT_REMOVED, - FORBIDDEN, - SHARE_FORBIDDEN, - OK_REDIRECT_TO_NON_SECURE_CONNECTION, - INVALID_MOVE_INTO_DESCENDANT, - INVALID_COPY_INTO_DESCENDANT, - PARTIAL_MOVE_DONE, - PARTIAL_COPY_DONE, - SHARE_WRONG_PARAMETER, - WRONG_SERVER_RESPONSE, - INVALID_CHARACTER_DETECT_IN_SERVER, - DELAYED_FOR_WIFI, - DELAYED_FOR_CHARGING, - LOCAL_FILE_NOT_FOUND, - NOT_AVAILABLE, - MAINTENANCE_MODE, - LOCK_FAILED, - DELAYED_IN_POWER_SAVE_MODE, - ACCOUNT_USES_STANDARD_PASSWORD, - METADATA_NOT_FOUND, - OLD_ANDROID_API, - UNTRUSTED_DOMAIN, - ETAG_CHANGED, - ETAG_UNCHANGED, - VIRUS_DETECTED, - FOLDER_ALREADY_EXISTS, - CANNOT_CREATE_FILE, - LOCKED - } - - private boolean mSuccess = false; - private int mHttpCode = -1; - private String mHttpPhrase = null; - private Exception mException = null; - private ResultCode mCode = ResultCode.UNKNOWN_ERROR; - private String message; - private String mRedirectedLocation; - private ArrayList mAuthenticateHeaders = new ArrayList<>(); - private String mLastPermanentLocation = null; - - private ArrayList mData; - private T resultData; - - /** - * Public constructor from result code. - *

- * To be used when the caller takes the responsibility of interpreting the result of a {@link RemoteOperation} - * - * @param code {@link ResultCode} decided by the caller. - */ - 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 || code == ResultCode.ETAG_CHANGED || - code == ResultCode.ETAG_UNCHANGED); - mData = null; - } - - private RemoteOperationResult(boolean success, int httpCode) { - mSuccess = success; - mHttpCode = httpCode; - - if (success) { - mCode = ResultCode.OK; - - } else if (httpCode > 0) { - switch (httpCode) { - case HttpStatus.SC_UNAUTHORIZED: - mCode = ResultCode.UNAUTHORIZED; - break; - case HttpStatus.SC_NOT_FOUND: - mCode = ResultCode.FILE_NOT_FOUND; - break; - case HttpStatus.SC_INTERNAL_SERVER_ERROR: - mCode = ResultCode.INSTANCE_NOT_CONFIGURED; - break; - case HttpStatus.SC_CONFLICT: - mCode = ResultCode.CONFLICT; - break; - case HttpStatus.SC_INSUFFICIENT_STORAGE: - mCode = ResultCode.QUOTA_EXCEEDED; - break; - case HttpStatus.SC_FORBIDDEN: - mCode = ResultCode.FORBIDDEN; - break; - case HttpStatus.SC_SERVICE_UNAVAILABLE: - mCode = ResultCode.MAINTENANCE_MODE; - break; - case HttpStatus.SC_LOCKED: - mCode = ResultCode.LOCKED; - break; - default: - mCode = ResultCode.UNHANDLED_HTTP_CODE; - Log_OC.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " + httpCode); - } - } - } - - public RemoteOperationResult(boolean success, int httpCode, Header[] headers) { - this(success, httpCode); - - if (headers != null) { - for (Header header : headers) { - if (HEADER_LOCATION.equals(header.getName().toLowerCase(Locale.US))) { - mRedirectedLocation = header.getValue(); - - } else if (HEADER_WWW_AUTHENTICATE.equals(header.getName().toLowerCase(Locale.US))) { - mAuthenticateHeaders.add(header.getValue()); - } - } - } - if (isIdPRedirection()) { - mCode = ResultCode.UNAUTHORIZED; // overrides default ResultCode.UNKNOWN - } - } - - 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: - try { - InputStream is = new ByteArrayInputStream(bodyResponse.getBytes()); - ExceptionParser xmlParser = new ExceptionParser(is); - if (xmlParser.isInvalidCharacterException()) { - 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 constructor from exception. - *

- * To be used when an exception prevented the end of the {@link RemoteOperation}. - *

- * Determines a {@link ResultCode} depending on the type of the exception. - * - * @param e Exception that interrupted the {@link RemoteOperation} - */ - public RemoteOperationResult(Exception e) { - mException = e; - - if (e instanceof OperationCancelledException) { - mCode = ResultCode.CANCELLED; - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && e instanceof ErrnoException && ((ErrnoException) e).errno == OsConstants.ENOTCONN) { - mCode = ResultCode.NO_NETWORK_CONNECTION; - } else if (e instanceof ConnectException) { - mCode = ResultCode.HOST_NOT_AVAILABLE; - } else if (e instanceof SocketException) { - mCode = ResultCode.WRONG_CONNECTION; - } else if (e instanceof SocketTimeoutException) { - mCode = ResultCode.TIMEOUT; - } else if (e instanceof ConnectTimeoutException) { - mCode = ResultCode.TIMEOUT; - } else if (e instanceof MalformedURLException) { - mCode = ResultCode.INCORRECT_ADDRESS; - } else if (e instanceof UnknownHostException) { - mCode = ResultCode.HOST_NOT_AVAILABLE; - } else if (e instanceof AccountNotFoundException) { - mCode = ResultCode.ACCOUNT_NOT_FOUND; - } else if (e instanceof AccountsException) { - mCode = ResultCode.ACCOUNT_EXCEPTION; - } else if (e instanceof SSLException || e instanceof RuntimeException) { - CertificateCombinedException se = getCertificateCombinedException(e); - if (se != null) { - mException = se; - if (se.isRecoverable()) { - mCode = ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED; - } - } else if (e instanceof RuntimeException) { - mCode = ResultCode.HOST_NOT_AVAILABLE; - - } else { - mCode = ResultCode.SSL_ERROR; - } - } else if (e instanceof FileNotFoundException) { - mCode = ResultCode.LOCAL_FILE_NOT_FOUND; - } else if (e instanceof CreateLocalFileException) { - if (((CreateLocalFileException) e).isCausedByInvalidPath()) { - mCode = ResultCode.INVALID_LOCAL_FILE_NAME; - } else { - mCode = ResultCode.CANNOT_CREATE_FILE; - } - } else { - mCode = ResultCode.UNKNOWN_ERROR; - } - } - - public RemoteOperationResult(boolean success, OkHttpMethodBase httpMethod) { - this(success, httpMethod.getStatusCode(), httpMethod.getStatusText(), httpMethod.getResponseHeaders()); - } - - /** - * Public constructor from separate elements of an HTTP or DAV response. - *

- * To be used when the result needs to be interpreted from the response of an HTTP/DAV method. - *

- * Determines a {@link ResultCode} from the already executed method received as a parameter. Generally, - * will depend on the HTTP code and HTTP response headers received. In some cases will inspect also the - * response body. - * - * @param success The operation was considered successful or not. - * @param httpMethod HTTP/DAV method already executed which response will be examined to interpret the - * result. - */ - public RemoteOperationResult(boolean success, HttpMethod httpMethod) { - this(success, httpMethod.getStatusCode(), httpMethod.getStatusText(), httpMethod.getResponseHeaders()); - - if (mHttpCode == HttpStatus.SC_BAD_REQUEST || mHttpCode == HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE) { - try { - String bodyResponse = httpMethod.getResponseBodyAsString(); - - if (bodyResponse != null && bodyResponse.length() > 0) { - InputStream is = new ByteArrayInputStream(bodyResponse.getBytes()); - ExceptionParser xmlParser = new ExceptionParser(is); - - if (xmlParser.isInvalidCharacterException()) { - mCode = ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER; - } - if (xmlParser.isVirusException()) { - mCode = ResultCode.VIRUS_DETECTED; - } - - mHttpPhrase = xmlParser.getMessage(); - } - } catch (Exception e) { - Log_OC.w(TAG, "Error reading exception from server: " + e.getMessage()); - // mCode stays as set in this(success, httpCode, headers) - } - } - } - - /** - * Public constructor from separate elements of an HTTP or DAV response. - *

- * To be used when the result needs to be interpreted from HTTP response elements that could come from - * different requests (WARNING: black magic, try to avoid). - *

- * If all the fields come from the same HTTP/DAV response, {@link #RemoteOperationResult(boolean, HttpMethod)} - * should be used instead. - *

- * Determines a {@link ResultCode} depending on the HTTP code and HTTP response headers received. - * - * @param success The operation was considered successful or not. - * @param httpCode HTTP status code returned by an HTTP/DAV method. - * @param httpPhrase HTTP status line phrase returned by an HTTP/DAV method - * @param httpHeaders HTTP response header returned by an HTTP/DAV method - */ - public RemoteOperationResult(boolean success, int httpCode, String httpPhrase, Header[] httpHeaders) { - this(success, httpCode, httpPhrase); - if (httpHeaders != null) { - Header current; - for (Header httpHeader : httpHeaders) { - current = httpHeader; - if (HEADER_WWW_AUTHENTICATE.equals(current.getName().toLowerCase(Locale.US))) { - mAuthenticateHeaders.add(current.getValue()); - } else if (HEADER_LOCATION.equals(current.getName().toLowerCase(Locale.US)) && mAuthenticateHeaders.isEmpty()) { - mRedirectedLocation = current.getValue(); - } - } - } - if (isIdPRedirection()) { - mCode = ResultCode.UNAUTHORIZED; // overrides default ResultCode.UNKNOWN - } - } - - /** - * Public constructor from separate elements of an HTTP or DAV response. - *

- * To be used when the result needs to be interpreted from HTTP response elements that could come from - * different requests (WARNING: black magic, try to avoid). - *

- * If all the fields come from the same HTTP/DAV response, {@link #RemoteOperationResult(boolean, HttpMethod)} - * should be used instead. - *

- * Determines a {@link ResultCode} depending on the HTTP code and HTTP response headers received. - * - * @param success The operation was considered successful or not. - * @param httpCode HTTP status code returned by an HTTP/DAV method. - * @param httpPhrase HTTP status line phrase returned by an HTTP/DAV method - * @param httpHeaders HTTP response header returned by an HTTP/DAV method - */ - public RemoteOperationResult(boolean success, - int httpCode, - String httpPhrase, - Headers httpHeaders) { - this(success, httpCode, httpPhrase); - - String location = httpHeaders.get(HEADER_LOCATION); - if (location != null) { - mRedirectedLocation = location; - } - - String auth = httpHeaders.get(HEADER_WWW_AUTHENTICATE); - if (auth != null) { - mAuthenticateHeaders.add(auth); - } - - if (isIdPRedirection()) { - mCode = ResultCode.UNAUTHORIZED; // overrides default ResultCode.UNKNOWN - } - } - - /** - * Private constructor for results built interpreting a HTTP or DAV response. - *

- * Determines a {@link ResultCode} depending of the type of the exception. - * - * @param success Operation was successful or not. - * @param httpCode HTTP status code returned by the HTTP/DAV method. - * @param httpPhrase HTTP status line phrase returned by the HTTP/DAV method - */ - private RemoteOperationResult(boolean success, int httpCode, String httpPhrase) { - mSuccess = success; - mHttpCode = httpCode; - mHttpPhrase = httpPhrase; - - if (success) { - mCode = ResultCode.OK; - - } else if (httpCode > 0) { - switch (httpCode) { - case HttpStatus.SC_UNAUTHORIZED: // 401 - mCode = ResultCode.UNAUTHORIZED; - break; - case HttpStatus.SC_FORBIDDEN: // 403 - mCode = ResultCode.FORBIDDEN; - break; - case HttpStatus.SC_NOT_FOUND: // 404 - mCode = ResultCode.FILE_NOT_FOUND; - break; - case HttpStatus.SC_CONFLICT: // 409 - mCode = ResultCode.CONFLICT; - break; - case HttpStatus.SC_LOCKED: // 423 - mCode = ResultCode.LOCKED; - break; - case HttpStatus.SC_INTERNAL_SERVER_ERROR: // 500 - mCode = ResultCode.INSTANCE_NOT_CONFIGURED; // assuming too much... - break; - case HttpStatus.SC_SERVICE_UNAVAILABLE: // 503 - mCode = ResultCode.MAINTENANCE_MODE; - break; - case HttpStatus.SC_INSUFFICIENT_STORAGE: // 507 - mCode = ResultCode.QUOTA_EXCEEDED; - break; - default: - mCode = ResultCode.UNHANDLED_HTTP_CODE; // UNKNOWN ERROR - Log_OC.d(TAG, - "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " - + mHttpCode + " " + mHttpPhrase); - } - } - } - - /** - * @deprecated use setResultData() instead - */ - @Deprecated - public void setData(ArrayList files) { - mData = files; - } - - /** - * @deprecated use setResultData() instead - */ - @Deprecated - public void setSingleData(Object object) { - mData = new ArrayList<>(Collections.singletonList(object)); - } - - public void setResultData(T object) { - resultData = object; - } - - public T getResultData() { - if (!mSuccess) { - throw new RuntimeException("Accessing result data after operation failed!"); - } - return resultData; - } - - /** - * @deprecated use getResultData() instead - */ - @Deprecated - public ArrayList getData() { - if (!mSuccess) { - throw new RuntimeException("Accessing result data after operation failed!"); - } - if (mData != null) { - return mData; - } else if (resultData instanceof ArrayList) { - return (ArrayList) resultData; - } else { - return null; - } - } - - /** - * @deprecated use getResultData() instead - */ - @Deprecated - public Object getSingleData() { - if (!mSuccess) { - throw new RuntimeException("Accessing result data after operation failed!"); - } - return mData.get(0); - } - - public boolean isSuccess() { - return mSuccess; - } - - public boolean isCancelled() { - return mCode == ResultCode.CANCELLED; - } - - public int getHttpCode() { - return mHttpCode; - } - - public String getHttpPhrase() { - return mHttpPhrase; - } - - public ResultCode getCode() { - return mCode; - } - - public Exception getException() { - return mException; - } - - public boolean isSslRecoverableException() { - return mCode == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED; - } - - public boolean isRedirectToNonSecureConnection() { - return mCode == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION; - } - - private CertificateCombinedException getCertificateCombinedException(Exception e) { - CertificateCombinedException result = null; - if (e instanceof CertificateCombinedException) { - return (CertificateCombinedException) e; - } - Throwable cause = mException.getCause(); - Throwable previousCause = null; - while (cause != null && cause != previousCause && - !(cause instanceof CertificateCombinedException)) { - previousCause = cause; - cause = cause.getCause(); - } - if (cause instanceof CertificateCombinedException) { - result = (CertificateCombinedException) cause; - } - return result; - } - - public String getLogMessage() { - - if (mException != null) { - if (mException instanceof OperationCancelledException) { - return "Operation cancelled by the caller"; - - } else if (mException instanceof SocketException) { - return "Socket exception"; - - } else if (mException instanceof SocketTimeoutException) { - return "Socket timeout exception"; - - } else if (mException instanceof ConnectTimeoutException) { - return "Connect timeout exception"; - - } else if (mException instanceof MalformedURLException) { - return "Malformed URL exception"; - - } else if (mException instanceof UnknownHostException) { - return "Unknown host exception"; - - } else if (mException instanceof CertificateCombinedException) { - if (((CertificateCombinedException) mException).isRecoverable()) - return "SSL recoverable exception"; - else - return "SSL exception"; - - } else if (mException instanceof SSLException) { - return "SSL exception"; - - } else if (mException instanceof DavException) { - return "Unexpected WebDAV exception"; - - } else if (mException instanceof HttpException) { - return "HTTP violation"; - - } else if (mException instanceof IOException) { - return "Unrecovered transport exception"; - - } else if (mException instanceof AccountNotFoundException) { - Account failedAccount = - ((AccountNotFoundException) mException).getFailedAccount(); - return mException.getMessage() + " (" + - (failedAccount != null ? failedAccount.name : "NULL") + ")"; - - } else if (mException instanceof AccountsException) { - return "Exception while using account"; - - } else if (mException instanceof JSONException) { - return "JSON exception"; - - } else { - return "Unexpected exception"; - } - } - - if (mCode == ResultCode.INSTANCE_NOT_CONFIGURED) { - return "The Nextcloud server is not configured!"; - - } else if (mCode == ResultCode.NO_NETWORK_CONNECTION) { - return "No network connection"; - - } else if (mCode == ResultCode.BAD_OC_VERSION) { - return "No valid Nextcloud version was found at the server"; - - } else if (mCode == ResultCode.LOCAL_STORAGE_FULL) { - return "Local storage full"; - - } else if (mCode == ResultCode.LOCAL_STORAGE_NOT_MOVED) { - return "Error while moving file to final directory"; - - } else if (mCode == ResultCode.ACCOUNT_NOT_NEW) { - return "Account already existing when creating a new one"; - - } 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"; - } else if (mCode == ResultCode.LOCKED) { - return "File is currently locked by another user or process"; - } - - return "Operation finished with HTTP status code " + mHttpCode + " (" + - (isSuccess() ? "success" : "fail") + ")"; - - } - - public boolean isServerFail() { - return (mHttpCode >= HttpStatus.SC_INTERNAL_SERVER_ERROR); - } - - public boolean isException() { - return (mException != null); - } - - public boolean isTemporalRedirection() { - return (mHttpCode == 302 || mHttpCode == 307); - } - - public String getRedirectedLocation() { - return mRedirectedLocation; - } - - public final boolean isIdPRedirection() { - return (mRedirectedLocation != null && - (mRedirectedLocation.toUpperCase(Locale.US).contains("SAML") || - mRedirectedLocation.toLowerCase(Locale.US).contains("wayf"))); - } - - /** - * Checks if is a non https connection - * - * @return boolean true/false - */ - public boolean isNonSecureRedirection() { - return (mRedirectedLocation != null && !(mRedirectedLocation.toLowerCase(Locale.US).startsWith("https://"))); - } - - public ArrayList getAuthenticateHeaders() { - return mAuthenticateHeaders; - } - - public String getLastPermanentLocation() { - return mLastPermanentLocation; - } - - public void setLastPermanentLocation(String lastPermanentLocation) { - mLastPermanentLocation = lastPermanentLocation; - } - - public void setMessage(String message) { - this.message = message; - } - - /** - * Message that is returned by server, e.g. password policy violation on ocs share api - * - * @return message that can be shown to user - */ - public String getMessage() { - return message; - } - - @Override - public String toString() { - return "RemoteOperationResult{" + - "mSuccess=" + mSuccess + - ", mHttpCode=" + mHttpCode + - ", mHttpPhrase='" + mHttpPhrase + '\'' + - ", mException=" + mException + - ", mCode=" + mCode + - ", message='" + message + '\'' + - ", getLogMessage='" + getLogMessage() + '\'' + - '}'; - } -} diff --git a/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.kt b/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.kt new file mode 100644 index 000000000..7af58ae0c --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.kt @@ -0,0 +1,625 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2022 Álvaro Brey + * SPDX-FileCopyrightText: 2019-2021 Tobias Kaminsky + * SPDX-FileCopyrightText: 2017 Andy Scherzinger + * SPDX-FileCopyrightText: 2014-2016 ownCloud Inc. + * SPDX-FileCopyrightText: 2015 masensio + * SPDX-FileCopyrightText: 2014 David A. Velasco + * SPDX-FileCopyrightText: 2014 Jorge Antonio Diaz-Benito Soriano + * SPDX-FileCopyrightText: 2014-2016 Juan Carlos González Cabrero + * SPDX-FileCopyrightText: 2014 jabarros + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.common.operations + +import android.accounts.AccountsException +import android.os.Build +import android.system.ErrnoException +import android.system.OsConstants +import com.nextcloud.common.DavResponse +import com.nextcloud.common.OkHttpMethodBase +import com.owncloud.android.lib.common.accounts.AccountUtils +import com.owncloud.android.lib.common.network.CertificateCombinedException +import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.resources.files.CreateLocalFileException +import okhttp3.Headers +import okhttp3.internal.http.HTTP_MOVED_TEMP +import okhttp3.internal.http.HTTP_TEMP_REDIRECT +import org.apache.commons.httpclient.ConnectTimeoutException +import org.apache.commons.httpclient.Header +import org.apache.commons.httpclient.HttpException +import org.apache.commons.httpclient.HttpMethod +import org.apache.commons.httpclient.HttpStatus +import org.apache.jackrabbit.webdav.DavException +import org.json.JSONException +import java.io.ByteArrayInputStream +import java.io.FileNotFoundException +import java.io.IOException +import java.io.InputStream +import java.io.Serial +import java.io.Serializable +import java.net.ConnectException +import java.net.MalformedURLException +import java.net.SocketException +import java.net.SocketTimeoutException +import java.net.UnknownHostException +import javax.net.ssl.SSLException + +/** + * The result of a remote operation required to an ownCloud server. + * + * + * Provides a common classification of remote operation results for all the application. + * + * @author David A. Velasco + */ +class RemoteOperationResult : Serializable { + enum class ResultCode { + OK, + OK_SSL, + OK_NO_SSL, + UNHANDLED_HTTP_CODE, + UNAUTHORIZED, + FILE_NOT_FOUND, + INSTANCE_NOT_CONFIGURED, + UNKNOWN_ERROR, + WRONG_CONNECTION, + TIMEOUT, + INCORRECT_ADDRESS, + HOST_NOT_AVAILABLE, + NO_NETWORK_CONNECTION, + SSL_ERROR, + SSL_RECOVERABLE_PEER_UNVERIFIED, + BAD_OC_VERSION, + CANCELLED, + INVALID_LOCAL_FILE_NAME, + INVALID_OVERWRITE, + CONFLICT, + OAUTH2_ERROR, + SYNC_CONFLICT, + LOCAL_STORAGE_FULL, + LOCAL_STORAGE_NOT_MOVED, + LOCAL_STORAGE_NOT_COPIED, + OAUTH2_ERROR_ACCESS_DENIED, + QUOTA_EXCEEDED, + ACCOUNT_NOT_FOUND, + ACCOUNT_EXCEPTION, + ACCOUNT_NOT_NEW, + ACCOUNT_NOT_THE_SAME, + INVALID_CHARACTER_IN_NAME, + SHARE_NOT_FOUND, + LOCAL_STORAGE_NOT_REMOVED, + FORBIDDEN, + SHARE_FORBIDDEN, + OK_REDIRECT_TO_NON_SECURE_CONNECTION, + INVALID_MOVE_INTO_DESCENDANT, + INVALID_COPY_INTO_DESCENDANT, + PARTIAL_MOVE_DONE, + PARTIAL_COPY_DONE, + SHARE_WRONG_PARAMETER, + WRONG_SERVER_RESPONSE, + INVALID_CHARACTER_DETECT_IN_SERVER, + DELAYED_FOR_WIFI, + DELAYED_FOR_CHARGING, + LOCAL_FILE_NOT_FOUND, + NOT_AVAILABLE, + MAINTENANCE_MODE, + LOCK_FAILED, + DELAYED_IN_POWER_SAVE_MODE, + ACCOUNT_USES_STANDARD_PASSWORD, + METADATA_NOT_FOUND, + OLD_ANDROID_API, + UNTRUSTED_DOMAIN, + ETAG_CHANGED, + ETAG_UNCHANGED, + VIRUS_DETECTED, + FOLDER_ALREADY_EXISTS, + CANNOT_CREATE_FILE, + LOCKED + } + + var isSuccess = false + private set + var httpCode = -1 + private set + var httpPhrase: String? = null + private set + var exception: Exception? = null + private set + var code = ResultCode.UNKNOWN_ERROR + private set + var lastPermanentLocation: String? = null + + /** + * Message that is returned by server, e.g. password policy violation on ocs share api + * @return message that can be shown to user + */ + @JvmField + var message: String? = null + var redirectedLocation: String? = null + private set + val authenticateHeaders = ArrayList() + private var mData: ArrayList? = null + + @Suppress("TooGenericExceptionThrown") + var resultData: T? = null + get() { + if (isSuccess) { + return field + } + throw RuntimeException("Accessing result data after operation failed!") + } + + /** + * Public constructor from result code. + * + * + * To be used when the caller takes the responsibility of interpreting the result of a [RemoteOperation] + * + * @param code [ResultCode] decided by the caller. + */ + constructor(code: ResultCode) { + this.code = code + isSuccess = code in + listOf( + ResultCode.OK, + ResultCode.OK_SSL, + ResultCode.OK_NO_SSL, + ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION, + ResultCode.ETAG_CHANGED, + ResultCode.ETAG_UNCHANGED + ) + mData = null + } + + private constructor(success: Boolean, httpCode: Int) { + isSuccess = success + this.httpCode = httpCode + if (success) { + this.code = ResultCode.OK + } else if (httpCode > 0) { + this.code = + when (httpCode) { + HttpStatus.SC_UNAUTHORIZED -> ResultCode.UNAUTHORIZED + HttpStatus.SC_NOT_FOUND -> ResultCode.FILE_NOT_FOUND + HttpStatus.SC_INTERNAL_SERVER_ERROR -> ResultCode.INSTANCE_NOT_CONFIGURED + HttpStatus.SC_CONFLICT -> ResultCode.CONFLICT + HttpStatus.SC_INSUFFICIENT_STORAGE -> ResultCode.QUOTA_EXCEEDED + HttpStatus.SC_FORBIDDEN -> ResultCode.FORBIDDEN + HttpStatus.SC_SERVICE_UNAVAILABLE -> ResultCode.MAINTENANCE_MODE + HttpStatus.SC_LOCKED -> ResultCode.LOCKED + else -> { + Log_OC.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: $httpCode") + ResultCode.UNHANDLED_HTTP_CODE + } + } + } + } + + constructor(success: Boolean, bodyResponse: String, httpCode: Int) { + isSuccess = success + this.httpCode = httpCode + if (success) { + this.code = ResultCode.OK + } else if (httpCode > 0) { + if (httpCode == HttpStatus.SC_BAD_REQUEST) { + try { + val inputStream: InputStream = ByteArrayInputStream(bodyResponse.toByteArray()) + val xmlParser = ExceptionParser(inputStream) + if (xmlParser.isInvalidCharacterException) { + this.code = ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER + } + } catch (e: IOException) { + this.code = ResultCode.UNHANDLED_HTTP_CODE + Log_OC.e(TAG, "Exception reading exception from server", e) + } + } else { + this.code = ResultCode.UNHANDLED_HTTP_CODE + Log_OC.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: $httpCode") + } + } + } + + /** + * Public constructor from exception. + * + * + * To be used when an exception prevented the end of the [RemoteOperation]. + * + * + * Determines a [ResultCode] depending on the type of the exception. + * + * @param e Exception that interrupted the [RemoteOperation] + */ + constructor(e: Exception?) { + exception = e + if (e is OperationCancelledException) { + this.code = ResultCode.CANCELLED + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && + e is ErrnoException && e.errno == OsConstants.ENOTCONN + ) { + this.code = ResultCode.NO_NETWORK_CONNECTION + } else if (e is ConnectException) { + this.code = ResultCode.HOST_NOT_AVAILABLE + } else if (e is SocketException) { + this.code = ResultCode.WRONG_CONNECTION + } else if (e is SocketTimeoutException) { + this.code = ResultCode.TIMEOUT + } else if (e is ConnectTimeoutException) { + this.code = ResultCode.TIMEOUT + } else if (e is MalformedURLException) { + this.code = ResultCode.INCORRECT_ADDRESS + } else if (e is UnknownHostException) { + this.code = ResultCode.HOST_NOT_AVAILABLE + } else if (e is AccountUtils.AccountNotFoundException) { + this.code = ResultCode.ACCOUNT_NOT_FOUND + } else if (e is AccountsException) { + this.code = ResultCode.ACCOUNT_EXCEPTION + } else if (e is SSLException || e is RuntimeException) { + val certificateCombinedException = getCertificateCombinedException(e) + if (certificateCombinedException != null) { + exception = certificateCombinedException + if (certificateCombinedException.isRecoverable) { + this.code = ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED + } + } else if (e is RuntimeException) { + this.code = ResultCode.HOST_NOT_AVAILABLE + } else { + this.code = ResultCode.SSL_ERROR + } + } else if (e is FileNotFoundException) { + this.code = ResultCode.LOCAL_FILE_NOT_FOUND + } else if (e is CreateLocalFileException) { + if (e.isCausedByInvalidPath()) { + this.code = ResultCode.INVALID_LOCAL_FILE_NAME + } else { + this.code = ResultCode.CANNOT_CREATE_FILE + } + } else { + this.code = ResultCode.UNKNOWN_ERROR + } + } + + constructor(success: Boolean, httpMethod: OkHttpMethodBase) : this( + success, + httpMethod.getStatusCode(), + httpMethod.getStatusText(), + httpMethod.getResponseHeaders() + ) + + /** + * Create RemoteOperationResult from given [DavResponse]. + * + * Assumes "HTTP/1.1 200 OK" if status of [davResponse] is null. + * + * @param davResponse response received from remote dav operation + */ + constructor(davResponse: DavResponse) : this( + davResponse.success, + davResponse.getStatusCode(), + davResponse.status?.message ?: "HTTP/1.1 200 OK", + davResponse.headers ?: Headers.headersOf() + ) + + /** + * Public constructor from separate elements of an HTTP or DAV response. + * + * + * To be used when the result needs to be interpreted from the response of an HTTP/DAV method. + * + * + * Determines a [ResultCode] from the already executed method received as a parameter. Generally, + * will depend on the HTTP code and HTTP response headers received. In some cases will inspect also the + * response body. + * + * @param success The operation was considered successful or not. + * @param httpMethod HTTP/DAV method already executed which response will be examined to interpret the + * result. + */ + constructor(success: Boolean, httpMethod: HttpMethod) : this( + success, + httpMethod.statusCode, + httpMethod.statusText, + httpMethod.responseHeaders + ) { + if (httpCode == HttpStatus.SC_BAD_REQUEST || httpCode == HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE) { + try { + val bodyResponse = httpMethod.responseBodyAsString + if (!bodyResponse.isNullOrEmpty()) { + val inputStream: InputStream = ByteArrayInputStream(bodyResponse.toByteArray()) + val xmlParser = ExceptionParser(inputStream) + if (xmlParser.isInvalidCharacterException) { + this.code = ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER + } + if (xmlParser.isVirusException) { + this.code = ResultCode.VIRUS_DETECTED + } + httpPhrase = xmlParser.message + } + } catch (e: IOException) { + Log_OC.w(TAG, "Error reading exception from server: " + e.message) + // mCode stays as set in this(success, httpCode, headers) + } + } + } + + /** + * Public constructor from separate elements of an HTTP or DAV response. + * + * + * To be used when the result needs to be interpreted from HTTP response elements that could come from + * different requests (WARNING: black magic, try to avoid). + * + * + * If all the fields come from the same HTTP/DAV response, [.RemoteOperationResult] + * should be used instead. + * + * + * Determines a [ResultCode] depending on the HTTP code and HTTP response headers received. + * + * @param success The operation was considered successful or not. + * @param httpCode HTTP status code returned by an HTTP/DAV method. + * @param httpPhrase HTTP status line phrase returned by an HTTP/DAV method + * @param httpHeaders HTTP response header returned by an HTTP/DAV method + */ + constructor( + success: Boolean, + httpCode: Int, + httpPhrase: String, + httpHeaders: Array
? + ) : this(success, httpCode, httpPhrase) { + if (httpHeaders != null) { + for (httpHeader in httpHeaders) { + if (HEADER_WWW_AUTHENTICATE == httpHeader.name.lowercase()) { + authenticateHeaders.add(httpHeader.value) + } else if (HEADER_LOCATION == httpHeader.name.lowercase() && authenticateHeaders.isEmpty()) { + redirectedLocation = httpHeader.value + } + } + } + if (isIdPRedirection) { + this.code = ResultCode.UNAUTHORIZED // overrides default ResultCode.UNKNOWN + } + } + + constructor(success: Boolean, httpCode: Int, headers: Array
?) : this( + success, + httpCode + ) { + if (headers != null) { + for (header in headers) { + if (HEADER_LOCATION == header.name.lowercase()) { + redirectedLocation = header.value + } else if (HEADER_WWW_AUTHENTICATE == header.name.lowercase()) { + authenticateHeaders.add(header.value) + } + } + } + if (isIdPRedirection) { + this.code = ResultCode.UNAUTHORIZED // overrides default ResultCode.UNKNOWN + } + } + + /** + * Public constructor from separate elements of an HTTP or DAV response. + * + * + * To be used when the result needs to be interpreted from HTTP response elements that could come from + * different requests (WARNING: black magic, try to avoid). + * + * + * If all the fields come from the same HTTP/DAV response, [.RemoteOperationResult] + * should be used instead. + * + * + * Determines a [ResultCode] depending on the HTTP code and HTTP response headers received. + * + * @param success The operation was considered successful or not. + * @param httpCode HTTP status code returned by an HTTP/DAV method. + * @param httpPhrase HTTP status line phrase returned by an HTTP/DAV method + * @param httpHeaders HTTP response header returned by an HTTP/DAV method + */ + constructor( + success: Boolean, + httpCode: Int, + httpPhrase: String, + httpHeaders: Headers + ) : this(success, httpCode, httpPhrase) { + val location = httpHeaders[HEADER_LOCATION] + if (location != null) { + redirectedLocation = location + } + val auth = httpHeaders[HEADER_WWW_AUTHENTICATE] + if (auth != null) { + authenticateHeaders.add(auth) + } + if (isIdPRedirection) { + this.code = ResultCode.UNAUTHORIZED // overrides default ResultCode.UNKNOWN + } + } + + /** + * Private constructor for results built interpreting a HTTP or DAV response. + * + * + * Determines a [ResultCode] depending of the type of the exception. + * + * @param success Operation was successful or not. + * @param httpCode HTTP status code returned by the HTTP/DAV method. + * @param httpPhrase HTTP status line phrase returned by the HTTP/DAV method + */ + private constructor(success: Boolean, httpCode: Int, httpPhrase: String) { + isSuccess = success + this.httpCode = httpCode + this.httpPhrase = httpPhrase + if (success) { + this.code = ResultCode.OK + } else if (httpCode > 0) { + when (httpCode) { + HttpStatus.SC_UNAUTHORIZED -> // 401 + this.code = ResultCode.UNAUTHORIZED + + HttpStatus.SC_FORBIDDEN -> // 403 + this.code = ResultCode.FORBIDDEN + + HttpStatus.SC_NOT_FOUND -> // 404 + this.code = ResultCode.FILE_NOT_FOUND + + HttpStatus.SC_CONFLICT -> // 409 + this.code = ResultCode.CONFLICT + + HttpStatus.SC_LOCKED -> // 423 + this.code = ResultCode.LOCKED + + HttpStatus.SC_INTERNAL_SERVER_ERROR -> // 500 + this.code = ResultCode.INSTANCE_NOT_CONFIGURED + + HttpStatus.SC_SERVICE_UNAVAILABLE -> // 503 + this.code = ResultCode.MAINTENANCE_MODE + + HttpStatus.SC_INSUFFICIENT_STORAGE -> // 507 + this.code = ResultCode.QUOTA_EXCEEDED + + else -> { + this.code = ResultCode.UNHANDLED_HTTP_CODE // UNKNOWN ERROR + Log_OC.d( + TAG, + "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: ${this.httpCode} ${this.httpPhrase}" + ) + } + } + } + } + + @get:Deprecated("use getResultData() instead") + @set:Deprecated("use setResultData() instead") + @Suppress("TooGenericExceptionThrown") + var data: java.util.ArrayList? + get() { + if (!isSuccess) { + throw RuntimeException("Accessing result data after operation failed!") + } + return if (mData != null) { + mData + } else if (resultData is ArrayList<*>) { + resultData as ArrayList<*>? + } else { + null + } + } + set(files) { + mData = files as ArrayList? + } + + @get:Deprecated("use getResultData() instead") + @set:Deprecated("use setResultData() instead") + @Suppress("TooGenericExceptionThrown") + var singleData: Any + get() { + if (!isSuccess) { + throw RuntimeException("Accessing result data after operation failed!") + } + return mData!![0] + } + set(data) { + mData = ArrayList(listOf(data)) + } + + val isCancelled = code == ResultCode.CANCELLED + + val isSslRecoverableException = code == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED + + val isRedirectToNonSecureConnection = code == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION + + private fun getCertificateCombinedException(e: Exception): CertificateCombinedException? { + var result: CertificateCombinedException? = null + if (e is CertificateCombinedException) { + return e + } + var cause = exception!!.cause + var previousCause: Throwable? = null + while (cause != null && cause !== previousCause && + cause !is CertificateCombinedException + ) { + previousCause = cause + cause = cause.cause + } + if (cause is CertificateCombinedException) { + result = cause + } + return result + } + + val logMessage: String + get() { + exception?.let { exception -> + return when (exception) { + is OperationCancelledException -> "Operation cancelled by the caller" + is SocketException -> "Socket exception" + is SocketTimeoutException -> "Socket timeout exception" + is ConnectTimeoutException -> "Connect timeout exception" + is MalformedURLException -> "Malformed URL exception" + is UnknownHostException -> "Unknown host exception" + is CertificateCombinedException -> + if (exception.isRecoverable) "SSL recoverable exception" else "SSL exception" + is SSLException -> "SSL exception" + is DavException -> "Unexpected WebDAV exception" + is HttpException -> "HTTP violation" + is IOException -> "Unrecovered transport exception" + is AccountUtils.AccountNotFoundException -> + "${exception.message} (${exception.failedAccount?.name ?: "NULL"})" + is AccountsException -> "Exception while using account" + is JSONException -> "JSON exception" + else -> "Unexpected exception" + } + } + return when (code) { + ResultCode.INSTANCE_NOT_CONFIGURED -> "The Nextcloud server is not configured!" + ResultCode.NO_NETWORK_CONNECTION -> "No network connection" + ResultCode.BAD_OC_VERSION -> "No valid Nextcloud version was found at the server" + ResultCode.LOCAL_STORAGE_FULL -> "Local storage full" + ResultCode.LOCAL_STORAGE_NOT_MOVED -> "Error while moving file to final directory" + ResultCode.ACCOUNT_NOT_NEW -> "Account already existing when creating a new one" + ResultCode.ACCOUNT_NOT_THE_SAME -> "Authenticated with a different account than the one updating" + ResultCode.INVALID_CHARACTER_IN_NAME -> "The file name contains an forbidden character" + ResultCode.FILE_NOT_FOUND -> "Local file does not exist" + ResultCode.SYNC_CONFLICT -> "Synchronization conflict" + else -> "Operation finished with HTTP status code $httpCode (${if (isSuccess) "success" else "fail"})" + } + } + + val isServerFail = httpCode >= HttpStatus.SC_INTERNAL_SERVER_ERROR + + val isException = exception != null + + val isTemporalRedirection = httpCode == HTTP_MOVED_TEMP || httpCode == HTTP_TEMP_REDIRECT + + val isIdPRedirection = + redirectedLocation != null && + ( + redirectedLocation!!.uppercase().contains("SAML") || + redirectedLocation!!.lowercase().contains("wayf") + ) + + /** + * Checks if is a non https connection + */ + val isNonSecureRedirection = redirectedLocation != null && !redirectedLocation!!.lowercase().startsWith("https://") + + override fun toString(): String = + "RemoteOperationResult{mSuccess=$isSuccess, mHttpCode=$httpCode," + "mHttpPhrase='$httpPhrase', " + + "mException=$exception, mCode=${this.code}, message='$message', getLogMessage='$logMessage'}" + + companion object { + // Generated - should be refreshed every time the class changes!! + @Serial + private val serialVersionUID = -4325446958558896222L + private val TAG = RemoteOperationResult::class.java.simpleName + private const val HEADER_WWW_AUTHENTICATE = "www-authenticate" + private const val HEADER_LOCATION = "location" + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/common/utils/WebDavFileUtils.java b/library/src/main/java/com/owncloud/android/lib/common/utils/WebDavFileUtils.java deleted file mode 100644 index bb19408b8..000000000 --- a/library/src/main/java/com/owncloud/android/lib/common/utils/WebDavFileUtils.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Nextcloud Android Library - * - * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2017 Mario Danic - * SPDX-License-Identifier: MIT - */ -package com.owncloud.android.lib.common.utils; - -import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.network.WebdavEntry; -import com.owncloud.android.lib.resources.files.model.RemoteFile; - -import org.apache.jackrabbit.webdav.MultiStatus; -import org.apache.jackrabbit.webdav.MultiStatusResponse; - -import java.util.ArrayList; - -/** - * WebDav helper. - */ -public class WebDavFileUtils { - - /** - * Read the data retrieved from the server about the contents of the target folder - * - * @param remoteData Full response got from the server with the data of the target - * folder and its direct children. - * @param client Client instance to the remote server where the data were - * retrieved. - * @return content of the target folder - */ - public ArrayList readData(MultiStatus remoteData, - OwnCloudClient client, - boolean isReadFolderOperation, - boolean isSearchOperation) { - ArrayList mFolderAndFiles = new ArrayList<>(); - - WebdavEntry we; - int start = 1; - - if (isReadFolderOperation) { - we = new WebdavEntry(remoteData.getResponses()[0], - client.getFilesDavUri().getEncodedPath()); - mFolderAndFiles.add(new RemoteFile(we)); - } else { - start = 0; - } - - // loop to update every child - RemoteFile remoteFile; - MultiStatusResponse[] responses = remoteData.getResponses(); - for (int i = start; i < responses.length; i++) { - /// new OCFile instance with the data from the server - we = new WebdavEntry(responses[i], client.getFilesDavUri().getEncodedPath()); - remoteFile = new RemoteFile(we); - mFolderAndFiles.add(remoteFile); - } - - return mFolderAndFiles; - } -} diff --git a/library/src/main/java/com/owncloud/android/lib/common/utils/WebDavFileUtils.kt b/library/src/main/java/com/owncloud/android/lib/common/utils/WebDavFileUtils.kt new file mode 100644 index 000000000..f4f2af608 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/common/utils/WebDavFileUtils.kt @@ -0,0 +1,180 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2017 Mario Danic + * SPDX-License-Identifier: MIT + */ +package com.owncloud.android.lib.common.utils + +import android.net.Uri +import at.bitfire.dav4jvm.Response +import at.bitfire.dav4jvm.property.webdav.DisplayName +import at.bitfire.dav4jvm.property.webdav.GetContentLength +import at.bitfire.dav4jvm.property.webdav.GetContentType +import at.bitfire.dav4jvm.property.webdav.ResourceType +import com.owncloud.android.lib.common.network.WebdavEntry +import com.owncloud.android.lib.resources.files.model.RemoteFile +import com.owncloud.android.lib.resources.files.webdav.NCCreationTime +import com.owncloud.android.lib.resources.files.webdav.NCEncrypted +import com.owncloud.android.lib.resources.files.webdav.NCEtag +import com.owncloud.android.lib.resources.files.webdav.NCFavorite +import com.owncloud.android.lib.resources.files.webdav.NCGetLastModified +import com.owncloud.android.lib.resources.files.webdav.NCHidden +import com.owncloud.android.lib.resources.files.webdav.NCLock +import com.owncloud.android.lib.resources.files.webdav.NCLockOwner +import com.owncloud.android.lib.resources.files.webdav.NCLockOwnerDisplayName +import com.owncloud.android.lib.resources.files.webdav.NCLockOwnerEditor +import com.owncloud.android.lib.resources.files.webdav.NCLockOwnerType +import com.owncloud.android.lib.resources.files.webdav.NCLockTime +import com.owncloud.android.lib.resources.files.webdav.NCLockTimeout +import com.owncloud.android.lib.resources.files.webdav.NCLockToken +import com.owncloud.android.lib.resources.files.webdav.NCMetadataGPS +import com.owncloud.android.lib.resources.files.webdav.NCMetadataLivePhoto +import com.owncloud.android.lib.resources.files.webdav.NCMetadataPhotosGPS +import com.owncloud.android.lib.resources.files.webdav.NCMetadataPhotosSize +import com.owncloud.android.lib.resources.files.webdav.NCMetadataSize +import com.owncloud.android.lib.resources.files.webdav.NCMountType +import com.owncloud.android.lib.resources.files.webdav.NCNote +import com.owncloud.android.lib.resources.files.webdav.NCPermissions +import com.owncloud.android.lib.resources.files.webdav.NCPreview +import com.owncloud.android.lib.resources.files.webdav.NCRichWorkspace +import com.owncloud.android.lib.resources.files.webdav.NCSharees +import com.owncloud.android.lib.resources.files.webdav.NCTags +import com.owncloud.android.lib.resources.files.webdav.NCTrashbinDeletionTime +import com.owncloud.android.lib.resources.files.webdav.NCTrashbinFilename +import com.owncloud.android.lib.resources.files.webdav.NCTrashbinLocation +import com.owncloud.android.lib.resources.files.webdav.NCUploadTime +import com.owncloud.android.lib.resources.files.webdav.OCCommentsUnread +import com.owncloud.android.lib.resources.files.webdav.OCDisplayName +import com.owncloud.android.lib.resources.files.webdav.OCId +import com.owncloud.android.lib.resources.files.webdav.OCLocalId +import com.owncloud.android.lib.resources.files.webdav.OCOwnerDisplayName +import com.owncloud.android.lib.resources.files.webdav.OCOwnerId +import com.owncloud.android.lib.resources.files.webdav.OCSize +import org.apache.jackrabbit.webdav.MultiStatus +import java.net.URLDecoder + +/** + * WebDav helper. + */ +object WebDavFileUtils { + /** + * Read the data retrieved from the server about the contents of the target folder + * + * @param remoteData Full response got from the server with the data of the target + * folder and its direct children. + * @param filesDavUri uri to files webdav uri + * @return content of the target folder + */ + fun readData( + remoteData: MultiStatus, + filesDavUri: Uri, + isReadFolderOperation: Boolean, + isSearchOperation: Boolean + ): ArrayList { + val mFolderAndFiles = ArrayList() + var we: WebdavEntry + var start = 1 + if (isReadFolderOperation) { + we = + WebdavEntry( + remoteData.responses[0], + filesDavUri.encodedPath!! + ) + mFolderAndFiles.add(RemoteFile(we)) + } else { + start = 0 + } + + // loop to update every child + var remoteFile: RemoteFile + val responses = remoteData.responses + for (i in start until responses.size) { + // / new OCFile instance with the data from the server + we = WebdavEntry(responses[i], filesDavUri.encodedPath!!) + remoteFile = RemoteFile(we) + mFolderAndFiles.add(remoteFile) + } + return mFolderAndFiles + } + + fun readData( + responses: List, + filesDavUri: Uri + ): ArrayList { + val list = ArrayList() + for (response in responses) { + list.add(parseResponse(response, filesDavUri)) + } + return list + } + + fun parseResponse( + response: Response, + filesDavUri: Uri + ): RemoteFile { + val remoteFile = RemoteFile() + + val path = URLDecoder.decode(response.href.toString().substringAfter(filesDavUri.toString()), "UTF-8") + + for (property in response.properties) { + when (property) { + is DisplayName -> remoteFile.name = property.displayName ?: "" + is GetContentLength -> remoteFile.length = property.contentLength + is GetContentType -> remoteFile.mimeType = (property.type ?: "").toString() + is ResourceType -> + if (property.types.contains(ResourceType.COLLECTION)) { + remoteFile.mimeType = WebdavEntry.DIR_TYPE + } + + is NCCreationTime -> remoteFile.creationTimestamp = property.creationTime + is NCEncrypted -> remoteFile.isEncrypted = property.encrypted + is NCEtag -> remoteFile.etag = property.etag + is NCFavorite -> remoteFile.isFavorite = property.favorite + is NCGetLastModified -> remoteFile.modifiedTimestamp = property.lastModified + is NCHidden -> remoteFile.hidden = property.hidden + is NCLock -> remoteFile.isLocked = property.locked + is NCLockOwner -> remoteFile.lockOwner = property.lockOwner + is NCLockOwnerDisplayName -> remoteFile.lockOwnerDisplayName = property.lockOwnerDisplayName + is NCLockOwnerEditor -> remoteFile.lockOwnerEditor = property.lockOwnerEditor + is NCLockOwnerType -> remoteFile.lockType = property.lockOwnerType + is NCLockTime -> remoteFile.lockTimestamp = property.lockTime + is NCLockTimeout -> remoteFile.lockTimeout = property.lockTimeout + is NCLockToken -> remoteFile.lockToken = property.lockToken + is NCMetadataGPS -> remoteFile.geoLocation = property.geoLocation + is NCMetadataLivePhoto -> remoteFile.livePhoto = property.livePhoto + is NCMetadataPhotosGPS -> remoteFile.geoLocation = property.geoLocation + is NCMetadataPhotosSize -> remoteFile.imageDimension = property.imageDimension + is NCMetadataSize -> remoteFile.imageDimension = property.imageDimension + is NCMountType -> remoteFile.mountType = property.mountType + is NCNote -> remoteFile.note = property.note + is NCPermissions -> remoteFile.permissions = property.permissions + is NCPreview -> remoteFile.isHasPreview = property.preview + is NCRichWorkspace -> remoteFile.richWorkspace = property.richWorkspace + is NCSharees -> remoteFile.sharees = property.sharees + is NCTags -> remoteFile.tags = property.tags + is NCTrashbinDeletionTime -> { /* TODO */ } + is NCTrashbinFilename -> { /* TODO */ } + is NCTrashbinLocation -> { /* TODO */ } + is NCUploadTime -> remoteFile.uploadTimestamp = property.uploadTime + is OCCommentsUnread -> remoteFile.unreadCommentsCount = property.commentsCount + is OCDisplayName -> remoteFile.name = property.displayName + is OCId -> remoteFile.remoteId = property.id + is OCLocalId -> remoteFile.localId = property.localId + is OCOwnerDisplayName -> remoteFile.ownerDisplayName = property.ownerDisplayName ?: "" + is OCOwnerId -> remoteFile.ownerId = property.ownerId ?: "" + is OCSize -> remoteFile.size = property.size + } + } + + remoteFile.remotePath = path + + // displayName not set - get from path + if (remoteFile.name.isEmpty()) { + remoteFile.name = path.substringAfterLast("/") + } + + return remoteFile + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/activities/GetActivitiesRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/activities/GetActivitiesRemoteOperation.java index 423126dbd..d79aa6c52 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/activities/GetActivitiesRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/activities/GetActivitiesRemoteOperation.java @@ -17,7 +17,6 @@ import com.google.gson.reflect.TypeToken; import com.nextcloud.common.NextcloudClient; import com.nextcloud.operations.GetMethod; -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; @@ -27,9 +26,7 @@ import com.owncloud.android.lib.resources.activities.models.PreviewObject; import com.owncloud.android.lib.resources.activities.models.PreviewObjectAdapter; -import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.NameValuePair; import java.io.IOException; import java.lang.reflect.Type; @@ -37,12 +34,14 @@ import java.util.HashMap; import java.util.List; +import kotlin.Pair; + /** * Provides the remote activities from the server handling the following data structure * accessible via the activities endpoint at {@value OCS_ROUTE_V12_AND_UP}, specified at * {@link "https://github.com/nextcloud/activity/blob/master/docs/endpoint-v2.md"}. */ -public class GetActivitiesRemoteOperation extends RemoteOperation { +public class GetActivitiesRemoteOperation extends RemoteOperation, Integer>> { private static final String TAG = GetActivitiesRemoteOperation.class.getSimpleName(); @@ -75,8 +74,8 @@ public GetActivitiesRemoteOperation(int lastGiven) { } @Override - public RemoteOperationResult run(NextcloudClient client) { - RemoteOperationResult result; + public RemoteOperationResult, Integer>> run(NextcloudClient client) { + RemoteOperationResult, Integer>> result; int status; GetMethod get = null; ArrayList activities; @@ -120,102 +119,19 @@ public RemoteOperationResult run(NextcloudClient client) { } Log_OC.d(TAG, "Successful response: " + response); - result = new RemoteOperationResult(true, get); + result = new RemoteOperationResult<>(true, get); // Parse the response activities = parseResult(response); - ArrayList data = new ArrayList<>(); - data.add(activities); - data.add(lastGiven); - result.setData(data); + result.setResultData(new Pair<>(activities, lastGiven)); } else { - result = new RemoteOperationResult(false, get); + result = new RemoteOperationResult<>(false, get); Log_OC.e(TAG, "Failed response while getting user activities"); Log_OC.e(TAG, "*** status code: " + status + " ; response message: " + response); } } catch (IOException e) { Log_OC.e(TAG, "Error getting user activities", e); - return new RemoteOperationResult(e); - } finally { - if (get != null) { - get.releaseConnection(); - } - } - - return result; - } - - @Override - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result; - int status; - org.apache.commons.httpclient.methods.GetMethod get = null; - ArrayList activities; - String url = client.getBaseUri() + OCS_ROUTE_V12_AND_UP; - - // add filter for fileId, if available - if (fileId > 0) { - url = url + "/filter"; - } - - Log_OC.d(TAG, "URL: " + url); - - try { - get = new org.apache.commons.httpclient.methods.GetMethod(url); - get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE); - - ArrayList parameters = new ArrayList<>(); - parameters.add(new NameValuePair("format", "json")); - parameters.add(new NameValuePair("previews", "true")); - - if (lastGiven != -1) { - parameters.add(new NameValuePair("since", String.valueOf(lastGiven))); - } - - if (fileId > 0) { - parameters.add(new NameValuePair("sort", "desc")); - parameters.add(new NameValuePair("object_type", "files")); - parameters.add(new NameValuePair("object_id", String.valueOf(fileId))); - } - - get.setQueryString(parameters.toArray(new NameValuePair[]{})); - - status = client.executeMethod(get); - String response = get.getResponseBodyAsString(); - - Header nextPageHeader = get.getResponseHeader("X-Activity-Last-Given"); - if (nextPageHeader != null) { - lastGiven = Integer.parseInt(nextPageHeader.getValue()); - } else { - lastGiven = -1; - } - - if (isSuccess(status)) { - Log_OC.d(TAG, "Successful response: " + response); - result = new RemoteOperationResult(true, status, get.getResponseHeaders()); - // Parse the response - if (response == null) { - activities = new ArrayList<>(); - } else { - activities = parseResult(response); - } - - ArrayList data = new ArrayList<>(); - data.add(activities); - data.add(lastGiven); - result.setData(data); - } else { - result = new RemoteOperationResult(false, status, get.getResponseHeaders()); - Log_OC.e(TAG, "Failed response while getting user activities "); - if (response != null) { - Log_OC.e(TAG, "*** status code: " + status + " ; response message: " + response); - } else { - Log_OC.e(TAG, "*** status code: " + status); - } - } - } catch (IOException e) { - result = new RemoteOperationResult(e); - Log_OC.e(TAG, "Exception while getting remote activities", e); + return new RemoteOperationResult<>(e); } finally { if (get != null) { get.releaseConnection(); diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/GetTaskListRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/GetTaskListRemoteOperation.kt index 9f7501fbb..1003d5cff 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/GetTaskListRemoteOperation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/GetTaskListRemoteOperation.kt @@ -18,10 +18,10 @@ import com.owncloud.android.lib.resources.OCSRemoteOperation import com.owncloud.android.lib.resources.assistant.model.TaskList import org.apache.commons.httpclient.HttpStatus -class GetTaskListRemoteOperation(private val appId: String) : OCSRemoteOperation() { +class GetTaskListRemoteOperation(private val appId: String) : OCSRemoteOperation() { @Suppress("TooGenericExceptionCaught") - override fun run(client: NextcloudClient): RemoteOperationResult { - var result: RemoteOperationResult + override fun run(client: NextcloudClient): RemoteOperationResult { + var result: RemoteOperationResult var getMethod: GetMethod? = null try { getMethod = @@ -34,7 +34,7 @@ class GetTaskListRemoteOperation(private val appId: String) : OCSRemoteOperation object : TypeToken>() {} )?.ocs?.data result = RemoteOperationResult(true, getMethod) - result.setResultData(taskTypes) + result.resultData = taskTypes } else { result = RemoteOperationResult(false, getMethod) } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/GetTaskTypesRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/GetTaskTypesRemoteOperation.kt index aad05a3bc..03c40e430 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/GetTaskTypesRemoteOperation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/GetTaskTypesRemoteOperation.kt @@ -18,10 +18,10 @@ import com.owncloud.android.lib.resources.OCSRemoteOperation import com.owncloud.android.lib.resources.assistant.model.TaskTypes import org.apache.commons.httpclient.HttpStatus -class GetTaskTypesRemoteOperation : OCSRemoteOperation() { +class GetTaskTypesRemoteOperation : OCSRemoteOperation() { @Suppress("TooGenericExceptionCaught") - override fun run(client: NextcloudClient): RemoteOperationResult { - var result: RemoteOperationResult + override fun run(client: NextcloudClient): RemoteOperationResult { + var result: RemoteOperationResult var getMethod: GetMethod? = null try { getMethod = @@ -34,7 +34,7 @@ class GetTaskTypesRemoteOperation : OCSRemoteOperation() { object : TypeToken>() {} )?.ocs?.data result = RemoteOperationResult(true, getMethod) - result.setResultData(taskTypes) + result.resultData = taskTypes } else { result = RemoteOperationResult(false, getMethod) } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/comments/CommentFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/comments/CommentFileRemoteOperation.java index e037f8486..18fb76632 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/comments/CommentFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/comments/CommentFileRemoteOperation.java @@ -57,7 +57,8 @@ public RemoteOperationResult run(NextcloudClient client) { RemoteOperationResult result; try { // request body - JSONRequestBody jsonRequestBody = new JSONRequestBody(ACTOR_ID, client.getUserId()); + JSONRequestBody jsonRequestBody = new JSONRequestBody(); + jsonRequestBody.put(ACTOR_ID, client.getUserId()); jsonRequestBody.put(ACTOR_TYPE, ACTOR_TYPE_VALUE); jsonRequestBody.put(VERB, VERB_VALUE); jsonRequestBody.put(MESSAGE, message); @@ -67,7 +68,6 @@ public RemoteOperationResult run(NextcloudClient client) { postMethod = new PostMethod(url, false, jsonRequestBody.get()); int status = client.execute(postMethod); - result = new RemoteOperationResult<>(status == HttpStatus.SC_CREATED, postMethod); } catch (IOException e) { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/comments/MarkCommentsAsReadRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/comments/MarkCommentsAsReadRemoteOperation.java deleted file mode 100644 index 34a2930c7..000000000 --- a/library/src/main/java/com/owncloud/android/lib/resources/comments/MarkCommentsAsReadRemoteOperation.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Nextcloud Android Library - * - * SPDX-FileCopyrightText: 2018-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2018 Tobias Kaminsky - * SPDX-License-Identifier: MIT - */ -package com.owncloud.android.lib.resources.comments; - -import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.network.WebdavEntry; -import com.owncloud.android.lib.common.operations.RemoteOperation; -import com.owncloud.android.lib.common.operations.RemoteOperationResult; - -import org.apache.commons.httpclient.HttpStatus; -import org.apache.jackrabbit.webdav.client.methods.PropPatchMethod; -import org.apache.jackrabbit.webdav.property.DavPropertyNameSet; -import org.apache.jackrabbit.webdav.property.DavPropertySet; -import org.apache.jackrabbit.webdav.property.DefaultDavProperty; -import org.apache.jackrabbit.webdav.xml.Namespace; - -import java.io.IOException; - -/** - * Mark all comments for a file as read - */ -public class MarkCommentsAsReadRemoteOperation extends RemoteOperation { - private static final String COMMENTS_URL = "/comments/files/"; - - private final long fileId; - - public MarkCommentsAsReadRemoteOperation(long fileId) { - this.fileId = fileId; - } - - @Override - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result; - PropPatchMethod propPatchMethod = null; - - DavPropertySet newProps = new DavPropertySet(); - DavPropertyNameSet removeProperties = new DavPropertyNameSet(); - - DefaultDavProperty readMarkerProperty = new DefaultDavProperty<>("oc:readMarker", "", - Namespace.getNamespace(WebdavEntry.NAMESPACE_OC)); - newProps.add(readMarkerProperty); - - String commentsPath = client.getCommentsUri(fileId); - - try { - propPatchMethod = new PropPatchMethod(commentsPath, newProps, removeProperties); - int status = client.executeMethod(propPatchMethod); - - boolean isSuccess = status == HttpStatus.SC_NO_CONTENT || status == HttpStatus.SC_OK || - status == HttpStatus.SC_MULTI_STATUS; - - if (isSuccess) { - result = new RemoteOperationResult(true, status, propPatchMethod.getResponseHeaders()); - } else { - client.exhaustResponse(propPatchMethod.getResponseBodyAsStream()); - result = new RemoteOperationResult(false, status, propPatchMethod.getResponseHeaders()); - } - } catch (IOException e) { - result = new RemoteOperationResult(e); - } finally { - if (propPatchMethod != null) { - propPatchMethod.releaseConnection(); - } - } - - return result; - } -} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/comments/MarkCommentsAsReadRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/comments/MarkCommentsAsReadRemoteOperation.kt new file mode 100644 index 000000000..752cb2c91 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/comments/MarkCommentsAsReadRemoteOperation.kt @@ -0,0 +1,29 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2018-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-FileCopyrightText: 2018 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ +package com.owncloud.android.lib.resources.comments + +import com.nextcloud.common.NextcloudClient +import com.owncloud.android.lib.common.network.ExtendedProperties +import com.owncloud.android.lib.common.operations.RemoteOperation +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import okhttp3.HttpUrl.Companion.toHttpUrl + +/** + * Mark all comments for a file as read + */ +class MarkCommentsAsReadRemoteOperation(private val fileId: Long) : RemoteOperation() { + override fun run(client: NextcloudClient): RemoteOperationResult { + val url = client.getCommentsUri(fileId).toHttpUrl() + val readMarkerProperty = mapOf(Pair(ExtendedProperties.COMMENTS_READ_MARKER.toPropertyName(), "")) + val propPatchMethod = com.nextcloud.operations.PropPatchMethod(url, setProperties = readMarkerProperty) + val response = client.execute(propPatchMethod) + + return RemoteOperationResult(response) + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/e2ee/StoreMetadataV2RemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/e2ee/StoreMetadataV2RemoteOperation.kt index 85be51a80..f5e0dff19 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/e2ee/StoreMetadataV2RemoteOperation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/e2ee/StoreMetadataV2RemoteOperation.kt @@ -52,7 +52,7 @@ class StoreMetadataV2RemoteOperation( .getJSONObject(NODE_DATA) .getString(NODE_META_DATA) result = RemoteOperationResult(true, postMethod) - result.setResultData(metadata) + result.resultData = metadata } else { result = RemoteOperationResult(false, postMethod) Log.e( diff --git a/library/src/main/java/com/owncloud/android/lib/resources/e2ee/ToggleEncryptionRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/e2ee/ToggleEncryptionRemoteOperation.java index d6720a75f..0232e1e60 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/e2ee/ToggleEncryptionRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/e2ee/ToggleEncryptionRemoteOperation.java @@ -7,16 +7,19 @@ */ package com.owncloud.android.lib.resources.e2ee; -import com.owncloud.android.lib.common.OwnCloudClient; +import com.nextcloud.common.NextcloudClient; +import com.nextcloud.common.OkHttpMethodBase; +import com.nextcloud.operations.DeleteMethod; +import com.nextcloud.operations.PutMethod; 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 com.owncloud.android.lib.resources.files.ReadFolderRemoteOperation; +import com.owncloud.android.lib.resources.files.model.RemoteFile; -import org.apache.commons.httpclient.HttpMethodBase; import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.methods.DeleteMethod; -import org.apache.commons.httpclient.methods.PutMethod; + +import java.util.List; /** @@ -26,8 +29,6 @@ public class ToggleEncryptionRemoteOperation extends RemoteOperation { private static final String TAG = ToggleEncryptionRemoteOperation.class.getSimpleName(); - private static final int SYNC_READ_TIMEOUT = 40000; - private static final int SYNC_CONNECTION_TIMEOUT = 5000; private static final String ENCRYPTED_URL = "/ocs/v2.php/apps/end_to_end_encryption/api/v1/encrypted/"; private final long localId; @@ -47,38 +48,36 @@ public ToggleEncryptionRemoteOperation(long localId, String remotePath, boolean * @param client Client object */ @Override - protected RemoteOperationResult run(OwnCloudClient client) { + public RemoteOperationResult run(NextcloudClient client) { RemoteOperationResult result; - HttpMethodBase method = null; + OkHttpMethodBase method = null; ReadFolderRemoteOperation remoteFolderOperation = new ReadFolderRemoteOperation(remotePath); - RemoteOperationResult remoteFolderOperationResult = remoteFolderOperation.execute(client); + RemoteOperationResult> remoteFolderOperationResult = remoteFolderOperation.execute(client); // Abort if not empty // Result has always the folder and maybe children, so size == 1 is ok - if (remoteFolderOperationResult.isSuccess() && remoteFolderOperationResult.getData().size() > 1) { + if (remoteFolderOperationResult.isSuccess() && remoteFolderOperationResult.getResultData() != null && remoteFolderOperationResult.getResultData().size() > 1) { return new RemoteOperationResult<>(false, "Non empty", HttpStatus.SC_FORBIDDEN); } try { String url = client.getBaseUri() + ENCRYPTED_URL + localId; if (encryption) { - method = new PutMethod(url); + method = new PutMethod(url, true, null); } else { - method = new DeleteMethod(url); + method = new DeleteMethod(url, true); } // remote request - method.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE); method.addRequestHeader(CONTENT_TYPE, FORM_URLENCODED); - int status = client.executeMethod(method, SYNC_READ_TIMEOUT, SYNC_CONNECTION_TIMEOUT); + int status = client.execute(method); if (status == HttpStatus.SC_OK) { result = new RemoteOperationResult<>(true, method); } else { result = new RemoteOperationResult<>(false, method); - client.exhaustResponse(method.getResponseBodyAsStream()); } } catch (Exception e) { result = new RemoteOperationResult<>(e); diff --git a/library/src/main/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataV2RemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataV2RemoteOperation.kt index c8d6e5b14..8a4492eea 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataV2RemoteOperation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataV2RemoteOperation.kt @@ -74,7 +74,7 @@ class UpdateMetadataV2RemoteOperation( .getJSONObject(NODE_DATA) .getString(NODE_META_DATA) result = RemoteOperationResult(true, putMethod) - result.setResultData(metadata) + result.resultData = metadata } else { result = RemoteOperationResult(false, putMethod) Log.e( diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/CheckEtagRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/CheckEtagRemoteOperation.java deleted file mode 100644 index 51f9dd33d..000000000 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/CheckEtagRemoteOperation.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Nextcloud Android Library - * - * SPDX-FileCopyrightText: 2018-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2018 Tobias Kaminsky - * SPDX-License-Identifier: MIT - */ -package com.owncloud.android.lib.resources.files; - -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.common.utils.Log_OC; - -import org.apache.commons.httpclient.HttpStatus; -import org.apache.jackrabbit.webdav.DavException; -import org.apache.jackrabbit.webdav.MultiStatusResponse; -import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; -import org.apache.jackrabbit.webdav.property.DavPropertyName; -import org.apache.jackrabbit.webdav.property.DavPropertyNameSet; - -import java.io.IOException; -import java.util.ArrayList; - -/** - * Check if file is up to date, by checking only eTag - */ -public class CheckEtagRemoteOperation extends RemoteOperation { - - private static final int SYNC_READ_TIMEOUT = 40000; - private static final int SYNC_CONNECTION_TIMEOUT = 5000; - private static final String TAG = CheckEtagRemoteOperation.class.getSimpleName(); - - private String path; - private String expectedEtag; - - public CheckEtagRemoteOperation(String path, String expectedEtag) { - this.path = path; - this.expectedEtag = expectedEtag; - } - - - @Override - protected RemoteOperationResult run(OwnCloudClient client) { - PropFindMethod propfind = null; - - try { - DavPropertyNameSet propSet = new DavPropertyNameSet(); - propSet.add(DavPropertyName.GETETAG); - - propfind = new PropFindMethod(client.getFilesDavUri(path), - propSet, - 0); - int status = client.executeMethod(propfind, SYNC_READ_TIMEOUT, SYNC_CONNECTION_TIMEOUT); - - if (status == HttpStatus.SC_MULTI_STATUS || status == HttpStatus.SC_OK) { - MultiStatusResponse resp = propfind.getResponseBodyAsMultiStatus().getResponses()[0]; - - String etag = WebdavUtils.parseEtag((String) resp.getProperties(HttpStatus.SC_OK) - .get(DavPropertyName.GETETAG).getValue()); - - if (etag.equals(expectedEtag)) { - return new RemoteOperationResult(ResultCode.ETAG_UNCHANGED); - } else { - RemoteOperationResult result = new RemoteOperationResult(ResultCode.ETAG_CHANGED); - - ArrayList list = new ArrayList<>(); - list.add(etag); - result.setData(list); - - return result; - } - } - - if (status == HttpStatus.SC_NOT_FOUND) { - return new RemoteOperationResult(ResultCode.FILE_NOT_FOUND); - } - } catch (DavException | IOException e) { - Log_OC.e(TAG, "Error while retrieving eTag"); - } finally { - if (propfind != null) { - propfind.releaseConnection(); - } - } - - return new RemoteOperationResult(ResultCode.ETAG_CHANGED); - } -} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/CheckEtagRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/CheckEtagRemoteOperation.kt new file mode 100644 index 000000000..9021bcd46 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/CheckEtagRemoteOperation.kt @@ -0,0 +1,44 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2018-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2018 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ +package com.owncloud.android.lib.resources.files + +import com.nextcloud.common.NextcloudClient +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.files.webdav.NCEtag +import okhttp3.HttpUrl.Companion.toHttpUrl +import org.apache.commons.httpclient.HttpStatus + +/** + * Check if file is up to date, by checking only eTag + */ +class CheckEtagRemoteOperation(private val path: String, private val expectedEtag: String?) : + RemoteOperation() { + override fun run(client: NextcloudClient): RemoteOperationResult { + val url = client.getFilesDavUri(path).toHttpUrl() + val propertySet = arrayOf(NCEtag.NAME) + val propFindMethod = com.nextcloud.operations.PropFindMethod(url, propertySet, 0) + val propFindResult = client.execute(propFindMethod) + + return if (propFindResult.davResponse.success) { + val etag = propFindResult.root.etag + if (etag == expectedEtag) { + RemoteOperationResult(ResultCode.ETAG_UNCHANGED) + } else { + val result = RemoteOperationResult(ResultCode.ETAG_CHANGED) + result.resultData = etag + result + } + } else if (propFindResult.davResponse.getStatusCode() == HttpStatus.SC_NOT_FOUND) { + RemoteOperationResult(ResultCode.FILE_NOT_FOUND) + } else { + RemoteOperationResult(ResultCode.ETAG_CHANGED) + } + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java index 818c4e0e4..545e7d025 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java @@ -8,6 +8,7 @@ import android.text.TextUtils; +import com.nextcloud.extensions.ArrayExtensionsKt; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.network.ChunkFromFileChannelRequestEntity; import com.owncloud.android.lib.common.network.ProgressiveDataTransfer; @@ -128,8 +129,8 @@ protected static Chunk calcNextChunk(long fileSize, int chunkId, long startByte, } @Override - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result; + protected RemoteOperationResult run(OwnCloudClient client) { + RemoteOperationResult result; DefaultHttpMethodRetryHandler oldRetryHandler = (DefaultHttpMethodRetryHandler) client.getParams() .getParameter(HttpMethodParams.RETRY_HANDLER); File file = new File(localPath); @@ -151,7 +152,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { uploadFolderUri = client.getUploadUri() + "/" + client.getUserId() + "/" + FileUtils.md5Sum(file); - destinationUri = client.getDavUri() + "/files/" + client.getUserId() + WebdavUtils.encodePath(remotePath); + destinationUri = client.getDavUri() + "/files/" + client.getUserId() + WebdavUtils.INSTANCE.encodePath(remotePath); // create folder MkColMethod createFolder = new MkColMethod(uploadFolderUri); @@ -161,14 +162,16 @@ protected RemoteOperationResult run(OwnCloudClient client) { client.executeMethod(createFolder, 30000, 5000); // list chunks - PropFindMethod listChunks = new PropFindMethod(uploadFolderUri, - WebdavUtils.getChunksPropSet(), - DavConstants.DEPTH_1); + PropFindMethod listChunks = new PropFindMethod( + uploadFolderUri, + ArrayExtensionsKt.toLegacyPropset(WebdavUtils.PROPERTYSETS.INSTANCE.getCHUNK()), + DavConstants.DEPTH_1 + ); client.executeMethod(listChunks); if (!listChunks.succeeded()) { - return new RemoteOperationResult(listChunks.succeeded(), listChunks); + return new RemoteOperationResult<>(listChunks.succeeded(), listChunks); } MultiStatus dataInServer = listChunks.getResponseBodyAsMultiStatus(); @@ -198,13 +201,13 @@ protected RemoteOperationResult run(OwnCloudClient client) { // determine size of next chunk Chunk chunk = calcNextChunk(file.length(), ++lastId, nextByte, chunkSize); - RemoteOperationResult chunkResult = uploadChunk(client, chunk); + RemoteOperationResult chunkResult = uploadChunk(client, chunk); if (!chunkResult.isSuccess()) { return chunkResult; } if (cancellationRequested.get()) { - return new RemoteOperationResult(new OperationCancelledException()); + return new RemoteOperationResult<>(new OperationCancelledException()); } nextByte += chunk.getLength(); @@ -227,22 +230,22 @@ protected RemoteOperationResult run(OwnCloudClient client) { final int DO_NOT_CHANGE_DEFAULT = -1; int moveResult = client.executeMethod(moveMethod, calculateAssembleTimeout(file), DO_NOT_CHANGE_DEFAULT); - result = new RemoteOperationResult(isSuccess(moveResult), moveMethod); + result = new RemoteOperationResult<>(isSuccess(moveResult), moveMethod); } catch (Exception e) { if (putMethod != null && putMethod.isAborted()) { if (cancellationRequested.get() && cancellationReason != null) { - result = new RemoteOperationResult(cancellationReason); + result = new RemoteOperationResult<>(cancellationReason); } else { - result = new RemoteOperationResult(new OperationCancelledException()); + result = new RemoteOperationResult<>(new OperationCancelledException()); } } else if (moveMethod != null && moveMethod.isAborted()) { if (cancellationRequested.get() && cancellationReason != null) { - result = new RemoteOperationResult(cancellationReason); + result = new RemoteOperationResult<>(cancellationReason); } else { - result = new RemoteOperationResult(new OperationCancelledException()); + result = new RemoteOperationResult<>(new OperationCancelledException()); } } else { - result = new RemoteOperationResult(e); + result = new RemoteOperationResult<>(e); } } finally { if (disableRetries) { @@ -253,9 +256,9 @@ protected RemoteOperationResult run(OwnCloudClient client) { return result; } - private RemoteOperationResult uploadChunk(OwnCloudClient client, Chunk chunk) throws IOException { + private RemoteOperationResult uploadChunk(OwnCloudClient client, Chunk chunk) throws IOException { int status; - RemoteOperationResult result; + RemoteOperationResult result; FileChannel channel = null; RandomAccessFile raf = null; @@ -293,7 +296,7 @@ private RemoteOperationResult uploadChunk(OwnCloudClient client, Chunk chunk) th status = client.executeMethod(putMethod); - result = new RemoteOperationResult(isSuccess(status), putMethod); + result = new RemoteOperationResult<>(isSuccess(status), putMethod); client.exhaustResponse(putMethod.getResponseBodyAsStream()); Log_OC.d(TAG, diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/CreateFolderRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/CreateFolderRemoteOperation.java deleted file mode 100644 index 328378d88..000000000 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/CreateFolderRemoteOperation.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Nextcloud Android Library - * - * SPDX-FileCopyrightText: 2015 ownCloud Inc. - * SPDX-License-Identifier: MIT - */ -package com.owncloud.android.lib.resources.files; - -import android.text.TextUtils; - -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.Header; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.jackrabbit.webdav.client.methods.MkColMethod; - - -/** - * Remote operation performing the creation of a new folder in the ownCloud server. - * - * @author David A. Velasco - * @author masensio - */ -public class CreateFolderRemoteOperation extends RemoteOperation { - - private static final String TAG = CreateFolderRemoteOperation.class.getSimpleName(); - - private static final int READ_TIMEOUT = 30000; - private static final int CONNECTION_TIMEOUT = 5000; - - - private boolean createFullPath; - private String remotePath; - private String token; - - /** - * 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. - */ - public CreateFolderRemoteOperation(String remotePath, boolean createFullPath) { - this.remotePath = remotePath; - this.createFullPath = createFullPath; - } - - public CreateFolderRemoteOperation(String remotePath, boolean createFullPath, String token) { - this(remotePath, createFullPath); - this.token = token; - } - - /** - * Performs the operation - * - * @param client Client object to communicate with the remote ownCloud server. - */ - @Override - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result; - - result = createFolder(client); - if (!result.isSuccess() && createFullPath && - RemoteOperationResult.ResultCode.CONFLICT == result.getCode() && - !"/".equals(remotePath)) { // this must already exists - result = createParentFolder(FileUtils.getParentPath(remotePath), client); - if (result.isSuccess()) { - result = createFolder(client); // second (and last) try - } - } - - return result; - } - - - private RemoteOperationResult createFolder(OwnCloudClient client) { - RemoteOperationResult result; - MkColMethod mkCol = null; - try { - mkCol = new MkColMethod(client.getFilesDavUri(remotePath)); - - if (!TextUtils.isEmpty(token)) { - mkCol.addRequestHeader(E2E_TOKEN, token); - } - - client.executeMethod(mkCol, READ_TIMEOUT, CONNECTION_TIMEOUT); - - if (HttpStatus.SC_METHOD_NOT_ALLOWED == mkCol.getStatusCode()) { - result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS); - } else { - result = new RemoteOperationResult<>(mkCol.succeeded(), mkCol); - Header fileIdHeader = mkCol.getResponseHeader("OC-FileId"); - - if (fileIdHeader != null) { - String fileId = fileIdHeader.getValue(); - - result.setResultData(fileId); - } else { - result.setResultData(null); - } - } - - Log_OC.d(TAG, "Create directory " + remotePath + ": " + result.getLogMessage()); - client.exhaustResponse(mkCol.getResponseBodyAsStream()); - } catch (Exception e) { - result = new RemoteOperationResult<>(e); - Log_OC.e(TAG, "Create directory " + remotePath + ": " + result.getLogMessage(), e); - - } finally { - if (mkCol != null) - mkCol.releaseConnection(); - } - return result; - } - - private RemoteOperationResult createParentFolder(String parentPath, OwnCloudClient client) { - RemoteOperation operation = new CreateFolderRemoteOperation(parentPath, createFullPath); - return operation.execute(client); - } - - -} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/CreateFolderRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/CreateFolderRemoteOperation.kt new file mode 100644 index 000000000..3e9232575 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/CreateFolderRemoteOperation.kt @@ -0,0 +1,102 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2015 ownCloud Inc. + * SPDX-License-Identifier: MIT + */ +package com.owncloud.android.lib.resources.files + +import at.bitfire.dav4jvm.exception.ConflictException +import at.bitfire.dav4jvm.exception.HttpException +import com.nextcloud.common.NextcloudClient +import com.nextcloud.operations.MkColMethod +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 okhttp3.HttpUrl +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.internal.http.HTTP_BAD_METHOD + +/** + * Remote operation performing the creation of a new folder in the ownCloud server. + * + * @author David A. Velasco + * @author masensio + */ +class CreateFolderRemoteOperation +/** + * Constructor + * + * @param remotePath full path to folder on the remote + * @param createFullPath create higher level directories + */ + @JvmOverloads + constructor( + private val remotePath: String, + private val createFullPath: Boolean, + private val token: String? = null + ) : RemoteOperation() { + /** + * Performs the operation + * + * @param client Client object to communicate with the remote ownCloud server. + */ + override fun run(client: NextcloudClient): RemoteOperationResult { + return createFolder(client) + } + + @Suppress("TooGenericExceptionCaught") + private fun createFolder(client: NextcloudClient): RemoteOperationResult { + var result: RemoteOperationResult + try { + val url: HttpUrl = client.getFilesDavUri(remotePath).toHttpUrl() + val mkCol = MkColMethod(url) + + if (token?.isNotEmpty() == true) { + mkCol.addRequestHeader(E2E_TOKEN, token) + } + + // will throw ConflictException if parent folder doesn't exist + // will throw HttpException if folder already exists + val response = client.execute(mkCol) + + result = RemoteOperationResult(response) + + val fileIdHeader = response.getHeader("OC-FileId") + result.resultData = fileIdHeader + + Log_OC.d(TAG, "Create directory " + remotePath + ": " + result.logMessage) + } catch (e: Exception) { + if (e is ConflictException && remotePath != "/") { + // parent directory doesn't exist - try to create it recursively + // do not attempt to create root + result = createParentFolder(remotePath, client) + + // check if parent directory/directories was/were created + // and create actual directory + if (result.isSuccess) { + result = createFolder(client) + } + } else if (e is HttpException && e.code == HTTP_BAD_METHOD) { + // specified directory already exists + result = RemoteOperationResult(RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS) + } else { + result = RemoteOperationResult(e) + Log_OC.e(TAG, "Create directory " + remotePath + ": " + result.logMessage, e) + } + } + return result + } + + private fun createParentFolder( + filePath: String, + nextcloudClient: NextcloudClient + ): RemoteOperationResult { + val parentPath = FileUtils.getParentPath(filePath) + return CreateFolderRemoteOperation(parentPath, createFullPath).execute(nextcloudClient) + } + + companion object { + private val TAG = CreateFolderRemoteOperation::class.java.getSimpleName() + } + } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java index b5de6ebf9..488c43b8c 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java @@ -142,13 +142,13 @@ private int downloadFile(OwnCloudClient client, File targetFile) throws IOExcept modificationTime = getMethod.getResponseHeader("last-modified"); } if (modificationTime != null) { - Date d = WebdavUtils.parseResponseDate(modificationTime.getValue()); + Date d = WebdavUtils.INSTANCE.parseResponseDate(modificationTime.getValue()); modificationTimestamp = (d != null) ? d.getTime() : 0; } else { Log_OC.e(TAG, "Could not read modification time from response downloading " + remotePath); } - eTag = WebdavUtils.getEtagFromResponse(getMethod); + eTag = WebdavUtils.INSTANCE.getEtagFromResponse(getMethod); if (eTag.length() == 0) { Log_OC.e(TAG, "Could not read eTag from response downloading " + remotePath); } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/LinkLivePhotoRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/LinkLivePhotoRemoteOperation.kt index fdf2b4817..0783839c4 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/LinkLivePhotoRemoteOperation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/LinkLivePhotoRemoteOperation.kt @@ -2,22 +2,17 @@ * Nextcloud Android Library * * SPDX-FileCopyrightText: 2018-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> * SPDX-FileCopyrightText: 2018 Tobias Kaminsky * SPDX-License-Identifier: MIT */ package com.owncloud.android.lib.resources.files -import com.owncloud.android.lib.common.OwnCloudClient -import com.owncloud.android.lib.common.network.WebdavEntry +import com.nextcloud.common.NextcloudClient +import com.owncloud.android.lib.common.network.ExtendedProperties import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult -import org.apache.commons.httpclient.HttpStatus -import org.apache.jackrabbit.webdav.client.methods.PropPatchMethod -import org.apache.jackrabbit.webdav.property.DavPropertyNameSet -import org.apache.jackrabbit.webdav.property.DavPropertySet -import org.apache.jackrabbit.webdav.property.DefaultDavProperty -import org.apache.jackrabbit.webdav.xml.Namespace -import java.io.IOException +import okhttp3.HttpUrl.Companion.toHttpUrl /** * Links live photos @@ -26,38 +21,12 @@ class LinkLivePhotoRemoteOperation( private val path: String, private val linkedFileName: String ) : RemoteOperation() { - @Deprecated("Deprecated in Java") - override fun run(client: OwnCloudClient): RemoteOperationResult { - var result: RemoteOperationResult - lateinit var propPatchMethod: PropPatchMethod - val newProps = DavPropertySet() - val removeProperties = DavPropertyNameSet() - val readMarkerProperty = - DefaultDavProperty( - "nc:metadata-files-live-photo", - linkedFileName, - Namespace.getNamespace(WebdavEntry.NAMESPACE_NC) - ) - newProps.add(readMarkerProperty) + override fun run(client: NextcloudClient): RemoteOperationResult { + val url = client.getFilesDavUri(path).toHttpUrl() + val metadataLiveProperty = mapOf(Pair(ExtendedProperties.METADATA_LIVE_PHOTO.toPropertyName(), linkedFileName)) + val propPatchMethod = com.nextcloud.operations.PropPatchMethod(url, setProperties = metadataLiveProperty) + val response = client.execute(propPatchMethod) - val commentsPath = client.getFilesDavUri(path) - try { - propPatchMethod = PropPatchMethod(commentsPath, newProps, removeProperties) - val status = client.executeMethod(propPatchMethod) - val isSuccess = - status == HttpStatus.SC_NO_CONTENT || status == HttpStatus.SC_OK || status == HttpStatus.SC_MULTI_STATUS - result = - if (isSuccess) { - RemoteOperationResult(true, status, propPatchMethod.responseHeaders) - } else { - client.exhaustResponse(propPatchMethod.responseBodyAsStream) - RemoteOperationResult(false, status, propPatchMethod.responseHeaders) - } - } catch (e: IOException) { - result = RemoteOperationResult(e) - } finally { - propPatchMethod.releaseConnection() - } - return result + return RemoteOperationResult(response) } } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/NcSearchMethod.java b/library/src/main/java/com/owncloud/android/lib/resources/files/NCSearchMethod.java similarity index 88% rename from library/src/main/java/com/owncloud/android/lib/resources/files/NcSearchMethod.java rename to library/src/main/java/com/owncloud/android/lib/resources/files/NCSearchMethod.java index 0e73c5c7b..eb7538603 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/NcSearchMethod.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/NCSearchMethod.java @@ -7,6 +7,9 @@ */ package com.owncloud.android.lib.resources.files; +import static com.owncloud.android.lib.common.network.WebdavUtils.NAMESPACE_NC; +import static com.owncloud.android.lib.common.network.WebdavUtils.NAMESPACE_OC; + import com.owncloud.android.lib.resources.status.NextcloudVersion; import com.owncloud.android.lib.resources.status.OCCapability; @@ -26,11 +29,7 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import static com.owncloud.android.lib.common.network.WebdavEntry.EXTENDED_PROPERTY_IS_ENCRYPTED; -import static com.owncloud.android.lib.common.network.WebdavEntry.NAMESPACE_NC; -import static com.owncloud.android.lib.common.network.WebdavEntry.NAMESPACE_OC; - -public class NcSearchMethod extends org.apache.jackrabbit.webdav.client.methods.SearchMethod { +public class NCSearchMethod extends org.apache.jackrabbit.webdav.client.methods.SearchMethod { private static final String HEADER_CONTENT_TYPE_VALUE = "text/xml"; private static final String DAV_NAMESPACE = "DAV:"; @@ -44,7 +43,7 @@ public class NcSearchMethod extends org.apache.jackrabbit.webdav.client.methods. private final Long endDate; @SuppressWarnings("PMD.ExcessiveParameterList") - public NcSearchMethod(String uri, + public NCSearchMethod(String uri, SearchInfo searchInfo, SearchRemoteOperation.SearchType searchType, String userId, @@ -68,6 +67,10 @@ public NcSearchMethod(String uri, setRequestBody(createQuery(searchInfo.getQuery())); } + public Document getDocumentQuery(SearchInfo searchInfo) { + return createQuery(searchInfo.getQuery()); + } + private Document createQuery(String searchQuery) { String internalSearchString = searchQuery; @@ -103,7 +106,7 @@ private Document createQuery(String searchQuery) { Element sizeElement = query.createElementNS(NAMESPACE_OC, "oc:size"); Element favoriteElement = query.createElementNS(NAMESPACE_OC, "oc:favorite"); Element previewElement = query.createElementNS(NAMESPACE_OC, "nc:has-preview"); - Element encryptedElement = query.createElementNS(NAMESPACE_NC, EXTENDED_PROPERTY_IS_ENCRYPTED); + Element encryptedElement = query.createElementNS(NAMESPACE_NC, "nc:is-encrypted"); if (searchType != SearchRemoteOperation.SearchType.GALLERY_SEARCH) { selectPropsElement.appendChild(displayNameElement); @@ -133,26 +136,12 @@ private Document createQuery(String searchQuery) { Text depthTextElement = query.createTextNode("infinity"); Element whereElement = query.createElementNS(DAV_NAMESPACE, "d:where"); Element folderElement; - Element equalsElement; - - switch (searchType) { - case FAVORITE_SEARCH: - case FILE_ID_SEARCH: - equalsElement = query.createElementNS(DAV_NAMESPACE, "d:eq"); - break; - - case RECENTLY_MODIFIED_SEARCH: - equalsElement = query.createElementNS(DAV_NAMESPACE, "d:gt"); - break; - - case GALLERY_SEARCH: - equalsElement = query.createElementNS(DAV_NAMESPACE, "d:or"); - break; - - default: - equalsElement = query.createElementNS(DAV_NAMESPACE, "d:like"); - break; - } + Element equalsElement = switch (searchType) { + case FAVORITE_SEARCH, FILE_ID_SEARCH -> query.createElementNS(DAV_NAMESPACE, "d:eq"); + case RECENTLY_MODIFIED_SEARCH -> query.createElementNS(DAV_NAMESPACE, "d:gt"); + case GALLERY_SEARCH -> query.createElementNS(DAV_NAMESPACE, "d:or"); + default -> query.createElementNS(DAV_NAMESPACE, "d:like"); + }; Element propElement = null; Element queryElement = null; @@ -165,29 +154,19 @@ private Document createQuery(String searchQuery) { propElement = query.createElementNS(DAV_NAMESPACE, "d:prop"); switch (searchType) { - case PHOTO_SEARCH: - queryElement = query.createElementNS(DAV_NAMESPACE, "d:getcontenttype"); - break; - - case FILE_SEARCH: - queryElement = query.createElementNS(DAV_NAMESPACE, "d:displayname"); - break; - - case FAVORITE_SEARCH: - queryElement = query.createElementNS(NAMESPACE_OC, "oc:favorite"); - break; - - case RECENTLY_MODIFIED_SEARCH: - queryElement = query.createElementNS(DAV_NAMESPACE, "d:getlastmodified"); - break; - - case FILE_ID_SEARCH: - queryElement = query.createElementNS(NAMESPACE_OC, "oc:fileid"); - break; - - default: - // no default - break; + case PHOTO_SEARCH -> + queryElement = query.createElementNS(DAV_NAMESPACE, "d:getcontenttype"); + case FILE_SEARCH -> + queryElement = query.createElementNS(DAV_NAMESPACE, "d:displayname"); + case FAVORITE_SEARCH -> + queryElement = query.createElementNS(NAMESPACE_OC, "oc:favorite"); + case RECENTLY_MODIFIED_SEARCH -> + queryElement = query.createElementNS(DAV_NAMESPACE, "d:getlastmodified"); + case FILE_ID_SEARCH -> + queryElement = query.createElementNS(NAMESPACE_OC, "oc:fileid"); + default -> { + } + // no default } literalElement = query.createElementNS(DAV_NAMESPACE, "d:literal"); diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/ReadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/ReadFileRemoteOperation.java index bf350ac93..31eb73410 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/ReadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/ReadFileRemoteOperation.java @@ -6,20 +6,15 @@ */ package com.owncloud.android.lib.resources.files; -import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.network.WebdavEntry; +import com.nextcloud.common.NextcloudClient; +import com.nextcloud.operations.PropFindResult; 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 com.owncloud.android.lib.resources.files.model.RemoteFile; -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 java.util.ArrayList; +import okhttp3.HttpUrl; /** @@ -29,13 +24,11 @@ * @author masensio */ -public class ReadFileRemoteOperation extends RemoteOperation { +public class ReadFileRemoteOperation extends RemoteOperation { private static final String TAG = ReadFileRemoteOperation.class.getSimpleName(); - private static final int SYNC_READ_TIMEOUT = 40000; - private static final int SYNC_CONNECTION_TIMEOUT = 5000; - private String mRemotePath; + private final String mRemotePath; /** @@ -53,49 +46,25 @@ public ReadFileRemoteOperation(String remotePath) { * @param client Client object to communicate with the remote ownCloud server. */ @Override - protected RemoteOperationResult run(OwnCloudClient client) { - PropFindMethod propfind = null; - RemoteOperationResult result = null; + public RemoteOperationResult run(NextcloudClient client) { + com.nextcloud.operations.PropFindMethod propFind; + RemoteOperationResult result; - /// take the duty of check the server for the current state of the file there try { // remote request - propfind = new PropFindMethod(client.getFilesDavUri(mRemotePath), - WebdavUtils.getFilePropSet(), // PropFind Properties - DavConstants.DEPTH_0); - int status; - status = client.executeMethod(propfind, SYNC_READ_TIMEOUT, SYNC_CONNECTION_TIMEOUT); - - boolean isSuccess = ( - status == HttpStatus.SC_MULTI_STATUS || - status == HttpStatus.SC_OK - ); - if (isSuccess) { - // Parse response - MultiStatus resp = propfind.getResponseBodyAsMultiStatus(); - WebdavEntry we = new WebdavEntry(resp.getResponses()[0], - client.getFilesDavUri().getEncodedPath()); - RemoteFile remoteFile = new RemoteFile(we); - ArrayList files = new ArrayList(); - files.add(remoteFile); + HttpUrl url = HttpUrl.get(client.getFilesDavUri(mRemotePath)); + propFind = new com.nextcloud.operations.PropFindMethod(url, WebdavUtils.PROPERTYSETS.INSTANCE.getFILE(), 0); + PropFindResult propFindResult = client.execute(propFind); - // Result of the operation - result = new RemoteOperationResult(true, propfind); - result.setData(files); - - } else { - result = new RemoteOperationResult(false, propfind); - client.exhaustResponse(propfind.getResponseBodyAsStream()); - } + result = new RemoteOperationResult<>(propFindResult.getDavResponse()); + result.setResultData(propFindResult.getRoot()); } catch (Exception e) { - result = new RemoteOperationResult(e); + result = new RemoteOperationResult<>(e); Log_OC.e(TAG, "Read file " + mRemotePath + " failed: " + result.getLogMessage(), result.getException()); - } finally { - if (propfind != null) - propfind.releaseConnection(); } + return result; } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/ReadFileVersionsRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/ReadFileVersionsRemoteOperation.java index c18a6beec..f73e2baec 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/ReadFileVersionsRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/ReadFileVersionsRemoteOperation.java @@ -7,6 +7,7 @@ */ package com.owncloud.android.lib.resources.files; +import com.nextcloud.extensions.ArrayExtensionsKt; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.network.WebdavEntry; import com.owncloud.android.lib.common.network.WebdavUtils; @@ -27,12 +28,12 @@ * Remote operation performing the read of remote versions on Nextcloud server. */ -public class ReadFileVersionsRemoteOperation extends RemoteOperation { +public class ReadFileVersionsRemoteOperation extends RemoteOperation> { private static final String TAG = ReadFileVersionsRemoteOperation.class.getSimpleName(); private final long localId; - private ArrayList versions; + private ArrayList versions; /** * Constructor @@ -49,13 +50,15 @@ public ReadFileVersionsRemoteOperation(long fileId) { * @param client Client object to communicate with the remote ownCloud server. */ @Override - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result = null; + protected RemoteOperationResult> run(OwnCloudClient client) { + RemoteOperationResult> result = null; PropFindMethod query = null; try { String uri = client.getDavUri() + "/versions/" + client.getUserId() + "/versions/" + localId; - DavPropertyNameSet propSet = WebdavUtils.getFileVersionPropSet(); + DavPropertyNameSet propSet = ArrayExtensionsKt.toLegacyPropset( + WebdavUtils.PROPERTYSETS.INSTANCE.getFILE_VERSION() + ); query = new PropFindMethod(uri, propSet, DavConstants.DEPTH_1); int status = client.executeMethod(query); @@ -69,24 +72,24 @@ protected RemoteOperationResult run(OwnCloudClient client) { readData(dataInServer, client); // Result of the operation - result = new RemoteOperationResult(true, query); + result = new RemoteOperationResult<>(true, query); // Add data to the result if (result.isSuccess()) { - result.setData(versions); + result.setResultData(versions); } } else { // synchronization failed client.exhaustResponse(query.getResponseBodyAsStream()); - result = new RemoteOperationResult(false, query); + result = new RemoteOperationResult<>(false, query); } } catch (Exception e) { - result = new RemoteOperationResult(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")); + result = new RemoteOperationResult<>(new Exception("unknown error")); Log_OC.e(TAG, "Synchronized file with id " + localId + ": failed"); } else { if (result.isSuccess()) { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/ReadFolderRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/ReadFolderRemoteOperation.java index c4a67c424..9a024656f 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/ReadFolderRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/ReadFolderRemoteOperation.java @@ -6,20 +6,17 @@ */ package com.owncloud.android.lib.resources.files; -import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.network.WebdavEntry; +import com.nextcloud.common.NextcloudClient; +import com.nextcloud.operations.PropFindResult; 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 com.owncloud.android.lib.resources.files.model.RemoteFile; -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 java.util.List; -import java.util.ArrayList; +import okhttp3.HttpUrl; /** * Remote operation performing the read of remote file or folder in the ownCloud server. @@ -28,12 +25,11 @@ * @author masensio */ -public class ReadFolderRemoteOperation extends RemoteOperation { +public class ReadFolderRemoteOperation extends RemoteOperation> { private static final String TAG = ReadFolderRemoteOperation.class.getSimpleName(); - private String mRemotePath; - private ArrayList mFolderAndFiles; + private final String mRemotePath; /** * Constructor @@ -50,44 +46,22 @@ public ReadFolderRemoteOperation(String remotePath) { * @param client Client object to communicate with the remote ownCloud server. */ @Override - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result = null; - PropFindMethod query = null; + public RemoteOperationResult> run(NextcloudClient client) { + RemoteOperationResult> result = null; + com.nextcloud.operations.PropFindMethod propFind; try { // remote request - query = new PropFindMethod(client.getFilesDavUri(mRemotePath), - WebdavUtils.getAllPropSet(), // PropFind Properties - 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(mFolderAndFiles); - } - } else { - // synchronization failed - client.exhaustResponse(query.getResponseBodyAsStream()); - result = new RemoteOperationResult(false, query); - } + HttpUrl url = HttpUrl.get(client.getFilesDavUri(mRemotePath)); + propFind = new com.nextcloud.operations.PropFindMethod(url, WebdavUtils.PROPERTYSETS.INSTANCE.getALL(), 1); + PropFindResult propFindResult = client.execute(propFind); + result = new RemoteOperationResult<>(propFindResult.getDavResponse()); + result.setResultData(propFindResult.getContent()); } catch (Exception e) { - result = new RemoteOperationResult(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")); + result = new RemoteOperationResult<>(new Exception("unknown error")); Log_OC.e(TAG, "Synchronized " + mRemotePath + ": failed"); } else { if (result.isSuccess()) { @@ -102,38 +76,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { } } } - - return result; - } - - public boolean isMultiStatus(int status) { - return (status == HttpStatus.SC_MULTI_STATUS); - } - - /** - * Read the data retrieved from the server about the contents of the target folder - * - * @param remoteData Full response got from the server with the data of the target - * folder and its direct children. - * @param client Client instance to the remote server where the data were - * retrieved. - * @return - */ - private void readData(MultiStatus remoteData, OwnCloudClient client) { - mFolderAndFiles = new ArrayList<>(); - - // parse data from remote folder - WebdavEntry we = new WebdavEntry(remoteData.getResponses()[0], client.getFilesDavUri().getEncodedPath()); - mFolderAndFiles.add(new RemoteFile(we)); - - // loop to update every child - RemoteFile remoteFile; - for (int i = 1; i < remoteData.getResponses().length; ++i) { - /// new OCFile instance with the data from the server - we = new WebdavEntry(remoteData.getResponses()[i], client.getFilesDavUri().getEncodedPath()); - remoteFile = new RemoteFile(we); - mFolderAndFiles.add(remoteFile); - } + return result; } } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/RemoveFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/RemoveFileRemoteOperation.java index 42aaab3e7..5a8b285a0 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/RemoveFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/RemoveFileRemoteOperation.java @@ -6,13 +6,13 @@ */ package com.owncloud.android.lib.resources.files; -import com.owncloud.android.lib.common.OwnCloudClient; +import com.nextcloud.common.NextcloudClient; +import com.nextcloud.operations.DeleteMethod; 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.client.methods.DeleteMethod; +import okhttp3.internal.http.HttpStatusCodesKt; /** * Remote operation performing the removal of a remote file or folder in the ownCloud server. @@ -20,12 +20,9 @@ * @author David A. Velasco * @author masensio */ -public class RemoveFileRemoteOperation extends RemoteOperation { +public class RemoveFileRemoteOperation extends RemoteOperation { private static final String TAG = RemoveFileRemoteOperation.class.getSimpleName(); - private static final int REMOVE_READ_TIMEOUT = 30000; - private static final int REMOVE_CONNECTION_TIMEOUT = 5000; - private String mRemotePath; /** @@ -43,28 +40,28 @@ public RemoveFileRemoteOperation(String remotePath) { * @param client Client object to communicate with the remote ownCloud server. */ @Override - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result = null; + public RemoteOperationResult run(NextcloudClient client) { + RemoteOperationResult result; DeleteMethod delete = null; try { - delete = new DeleteMethod(client.getFilesDavUri(mRemotePath)); - int status = client.executeMethod(delete, REMOVE_READ_TIMEOUT, REMOVE_CONNECTION_TIMEOUT); + delete = new DeleteMethod(client.getFilesDavUri(mRemotePath), true); + int status = client.execute(delete); - delete.getResponseBodyAsString(); // exhaust the response, although not interesting - result = new RemoteOperationResult( - (delete.succeeded() || status == HttpStatus.SC_NOT_FOUND), + result = new RemoteOperationResult<>( + (delete.isSuccess() || status == HttpStatusCodesKt.HTTP_NOT_FOUND || status == HttpStatusCodesKt.HTTP_NO_CONTENT), delete ); Log_OC.i(TAG, "Remove " + mRemotePath + ": " + result.getLogMessage()); } catch (Exception e) { - result = new RemoteOperationResult(e); + result = new RemoteOperationResult<>(e); Log_OC.e(TAG, "Remove " + mRemotePath + ": " + result.getLogMessage(), e); } finally { - if (delete != null) + if (delete != null) { delete.releaseConnection(); + } } return result; diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/SearchRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/SearchRemoteOperation.java index 531947db7..3b2bf0c9d 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/SearchRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/SearchRemoteOperation.java @@ -7,6 +7,7 @@ */ package com.owncloud.android.lib.resources.files; +import com.nextcloud.common.NextcloudClient; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; @@ -19,10 +20,23 @@ import org.apache.jackrabbit.webdav.client.methods.OptionsMethod; import org.apache.jackrabbit.webdav.search.SearchInfo; import org.apache.jackrabbit.webdav.xml.Namespace; +import org.w3c.dom.Document; +import java.io.StringWriter; import java.util.ArrayList; import java.util.List; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import at.bitfire.dav4jvm.DavResource; +import at.bitfire.dav4jvm.Response; +import okhttp3.HttpUrl; + /** * Remote operation performing the search in the Nextcloud server. */ @@ -68,15 +82,15 @@ public SearchRemoteOperation(String query, public void setLimit(int limit) { this.limit = limit; } - + public void setTimestamp(long timestamp) { this.timestamp = timestamp; } - + public void setStartDate(Long startDate) { this.startDate = startDate; } - + public void setEndDate(Long endDate) { this.endDate = endDate; } @@ -84,60 +98,52 @@ public void setEndDate(Long endDate) { @Override protected RemoteOperationResult> run(OwnCloudClient client) { RemoteOperationResult> result; - NcSearchMethod searchMethod = null; + NCSearchMethod searchMethod = null; OptionsMethod optionsMethod; String webDavUrl = client.getDavUri().toString(); optionsMethod = new OptionsMethod(webDavUrl); try { - int optionsStatus = client.executeMethod(optionsMethod); - boolean isSearchSupported = optionsMethod.isAllowed("SEARCH"); - - if (isSearchSupported) { - searchMethod = new NcSearchMethod(webDavUrl, - new SearchInfo("NC", - Namespace.XMLNS_NAMESPACE, - searchQuery), - searchType, - getClient().getUserIdPlain(), - timestamp, - limit, - filterOutFiles, - capability, - startDate, - endDate); - - int status = client.executeMethod(searchMethod); - - // check and process response - boolean isSuccess = (status == HttpStatus.SC_MULTI_STATUS || status == HttpStatus.SC_OK); - - if (isSuccess) { - // get data from remote folder - MultiStatus dataInServer = searchMethod.getResponseBodyAsMultiStatus(); - WebDavFileUtils webDavFileUtils = new WebDavFileUtils(); - ArrayList mFolderAndFiles = webDavFileUtils.readData(dataInServer, - client, - false, - true); - - // Result of the operation - result = new RemoteOperationResult<>(true, status, searchMethod.getResponseHeaders()); - // Add data to the result - if (result.isSuccess()) { - result.setResultData(mFolderAndFiles); - } - } else { - // synchronization failed - client.exhaustResponse(searchMethod.getResponseBodyAsStream()); - result = new RemoteOperationResult<>(false, status, searchMethod.getResponseHeaders()); + searchMethod = new NCSearchMethod(webDavUrl, + new SearchInfo("NC", + Namespace.XMLNS_NAMESPACE, + searchQuery), + searchType, + client.getUserIdPlain(), + timestamp, + limit, + filterOutFiles, + capability, + startDate, + endDate); + + int status = client.executeMethod(searchMethod); + + // check and process response + boolean isSuccess = (status == HttpStatus.SC_MULTI_STATUS || status == HttpStatus.SC_OK); + + if (isSuccess) { + // get data from remote folder + MultiStatus dataInServer = searchMethod.getResponseBodyAsMultiStatus(); + ArrayList mFolderAndFiles = WebDavFileUtils.INSTANCE.readData( + dataInServer, + client.getFilesDavUri(), + false, + true + ); + + // Result of the operation + result = new RemoteOperationResult<>(true, status, searchMethod.getResponseHeaders()); + // Add data to the result + if (result.isSuccess()) { + result.setResultData(mFolderAndFiles); } } else { - client.exhaustResponse(optionsMethod.getResponseBodyAsStream()); - result = new RemoteOperationResult<>(false, optionsStatus, optionsMethod.getResponseHeaders()); + // synchronization failed + client.exhaustResponse(searchMethod.getResponseBodyAsStream()); + result = new RemoteOperationResult<>(false, status, searchMethod.getResponseHeaders()); } - } catch (Exception e) { result = new RemoteOperationResult<>(e); } finally { @@ -149,5 +155,78 @@ protected RemoteOperationResult> run(OwnCloudClient client) { } return result; } + + @Override + public RemoteOperationResult> run(NextcloudClient client) { + RemoteOperationResult> result; + NCSearchMethod searchMethod = null; + + String webDavUrl = client.getDavUri().toString(); + + SearchInfo searchInfo = new SearchInfo("NC", + Namespace.XMLNS_NAMESPACE, + searchQuery); + + try { + searchMethod = new NCSearchMethod(webDavUrl, + searchInfo, + searchType, + client.getUserIdPlain(), + timestamp, + limit, + filterOutFiles, + capability, + startDate, + endDate); + + Document searchDocument = searchMethod.getDocumentQuery(searchInfo); + String searchString = transformDocumentToString(searchDocument); + + ArrayList responses = new ArrayList<>(); + + new DavResource( + client.disabledRedirectClient(), + HttpUrl.get(client.getDavUri().toString())) + .search(searchString, (response, hrefRelation) -> responses.add(response)); + + // get data from remote folder + ArrayList list = new ArrayList<>(); + for (Response response : responses) { + list.add(WebDavFileUtils.INSTANCE.parseResponse(response, client.getFilesDavUri())); + } + + // Result of the operation + result = new RemoteOperationResult<>( + true, + HttpStatus.SC_OK, + searchMethod.getResponseHeaders()); + // Add data to the result + if (result.isSuccess()) { + result.setResultData(list); + } + } catch (Exception e) { + result = new RemoteOperationResult<>(e); + } finally { + if (searchMethod != null) { + searchMethod.releaseConnection(); // let the connection available for other methods + } + } + return result; + } + + public String transformDocumentToString(Document document) throws TransformerException { + TransformerFactory tf = TransformerFactory.newInstance(); + + // java.lang.IllegalArgumentException: Not supported: http://javax.xml.XMLConstants/feature/secure-processing + //tf.setAttribute(XMLConstants.FEATURE_SECURE_PROCESSING, true); + + Transformer trans = tf.newTransformer(); + trans.setOutputProperty(OutputKeys.INDENT, "yes"); + + StringWriter sw = new StringWriter(); + trans.transform(new DOMSource(document), new StreamResult(sw)); + + return sw.toString(); + } } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/ToggleFavoriteRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/ToggleFavoriteRemoteOperation.java index 2e1b43089..86073737f 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/ToggleFavoriteRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/ToggleFavoriteRemoteOperation.java @@ -9,10 +9,13 @@ import android.net.Uri; +import com.nextcloud.common.DavResponse; +import com.nextcloud.common.NextcloudClient; 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.resources.files.webdav.NCFavorite; import org.apache.commons.httpclient.HttpStatus; import org.apache.jackrabbit.webdav.client.methods.PropPatchMethod; @@ -22,13 +25,20 @@ import org.apache.jackrabbit.webdav.xml.Namespace; import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import at.bitfire.dav4jvm.Property; +import okhttp3.HttpUrl; /** * Favorite or unfavorite a file. */ -public class ToggleFavoriteRemoteOperation extends RemoteOperation { - private boolean makeItFavorited; - private String filePath; +public class ToggleFavoriteRemoteOperation extends RemoteOperation { + private final boolean makeItFavorited; + private final String filePath; public ToggleFavoriteRemoteOperation(boolean makeItFavorited, String filePath) { this.makeItFavorited = makeItFavorited; @@ -36,8 +46,8 @@ public ToggleFavoriteRemoteOperation(boolean makeItFavorited, String filePath) { } @Override - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result = null; + protected RemoteOperationResult run(OwnCloudClient client) { + RemoteOperationResult result; PropPatchMethod propPatchMethod = null; DavPropertySet newProps = new DavPropertySet(); @@ -45,10 +55,10 @@ protected RemoteOperationResult run(OwnCloudClient client) { if (makeItFavorited) { DefaultDavProperty favoriteProperty = new DefaultDavProperty<>("oc:favorite", "1", - Namespace.getNamespace(WebdavEntry.NAMESPACE_OC)); + Namespace.getNamespace(WebdavUtils.NAMESPACE_OC)); newProps.add(favoriteProperty); } else { - removeProperties.add("oc:favorite", Namespace.getNamespace(WebdavEntry.NAMESPACE_OC)); + removeProperties.add("oc:favorite", Namespace.getNamespace(WebdavUtils.NAMESPACE_OC)); } String webDavUrl = client.getDavUri().toString(); @@ -62,14 +72,14 @@ protected RemoteOperationResult run(OwnCloudClient client) { boolean isSuccess = (status == HttpStatus.SC_MULTI_STATUS || status == HttpStatus.SC_OK); if (isSuccess) { - result = new RemoteOperationResult(true, status, propPatchMethod.getResponseHeaders()); + result = new RemoteOperationResult<>(true, status, propPatchMethod.getResponseHeaders()); } else { client.exhaustResponse(propPatchMethod.getResponseBodyAsStream()); - result = new RemoteOperationResult(false, status, propPatchMethod.getResponseHeaders()); + result = new RemoteOperationResult<>(false, status, propPatchMethod.getResponseHeaders()); } } catch (IOException e) { - result = new RemoteOperationResult(e); - } finally { + result = new RemoteOperationResult<>(e); + } finally { if (propPatchMethod != null) { propPatchMethod.releaseConnection(); // let the connection available for other methods } @@ -77,4 +87,33 @@ protected RemoteOperationResult run(OwnCloudClient client) { return result; } + + @Override + public RemoteOperationResult run(NextcloudClient client) { + RemoteOperationResult result; + + Map setProperties = new HashMap<>(); + List removeProperties = new ArrayList<>(); + + if (makeItFavorited) { + setProperties.put(NCFavorite.NAME, "1"); + } else { + removeProperties.add(NCFavorite.NAME); + } + + HttpUrl url = HttpUrl.get(client.getFilesDavUri(filePath)); + + com.nextcloud.operations.PropPatchMethod propPatchMethod = new com.nextcloud.operations.PropPatchMethod(url, + setProperties, removeProperties); + + DavResponse response = client.execute(propPatchMethod); + + if (response.getSuccess()) { + result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.OK); + } else { + result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE); + } + + return result; + } } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/model/FileLockType.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/model/FileLockType.kt index cb40b2626..790a0e54a 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/model/FileLockType.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/model/FileLockType.kt @@ -14,6 +14,6 @@ enum class FileLockType(val value: Int) { companion object { @JvmStatic - fun fromValue(v: Int): FileLockType? = values().firstOrNull { it.value == v } + fun fromValue(v: Int): FileLockType? = entries.firstOrNull { it.value == v } } } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/model/RemoteFile.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/model/RemoteFile.kt index 8edea5fe4..7da5aaab8 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/model/RemoteFile.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/model/RemoteFile.kt @@ -8,6 +8,8 @@ package com.owncloud.android.lib.resources.files.model import android.os.Parcel import android.os.Parcelable +import com.nextcloud.extensions.readParcelableArrayCompat +import com.nextcloud.extensions.readSerializableCompat import com.owncloud.android.lib.common.network.WebdavEntry import com.owncloud.android.lib.common.network.WebdavEntry.MountType import com.owncloud.android.lib.resources.files.FileUtils @@ -20,7 +22,7 @@ import java.io.Serializable * * @author masensio */ -class RemoteFile : Parcelable, Serializable { +class RemoteFile() : Parcelable, Serializable { var remotePath: String? = null var mimeType: String? = null var length: Long = 0 @@ -29,18 +31,19 @@ class RemoteFile : Parcelable, Serializable { var uploadTimestamp: Long = 0 var etag: String? = null var permissions: String? = null - var localId: Long = 0 + var localId: Long = -1 var remoteId: String? = null var size: Long = 0 var isFavorite = false var isEncrypted = false var mountType: MountType? = null - var ownerId: String? = null - var ownerDisplayName: String? = null + var ownerId: String = "" + var ownerDisplayName: String = "" var unreadCommentsCount = 0 var isHasPreview = false - var note: String? = null - var sharees: Array? = null + var name: String = "" + var note: String = "" + var sharees: Array? = null var richWorkspace: String? = null var isLocked = false var lockType: FileLockType? = null @@ -50,16 +53,12 @@ class RemoteFile : Parcelable, Serializable { var lockOwnerEditor: String? = null var lockTimeout: Long = 0 var lockToken: String? = null - var tags: Array? = null + var tags: Array? = null var imageDimension: ImageDimension? = null var geoLocation: GeoLocation? = null var hidden = false var livePhoto: String? = null - constructor() { - resetData() - } - /** * Create new [RemoteFile] with given path. * @@ -68,8 +67,7 @@ class RemoteFile : Parcelable, Serializable { * * @param path The remote path of the file. */ - constructor(path: String?) { - resetData() + constructor(path: String?) : this() { require(!(path.isNullOrEmpty() || !path.startsWith(FileUtils.PATH_SEPARATOR))) { "Trying to create a OCFile with a non valid remote path: $path" } @@ -90,8 +88,9 @@ class RemoteFile : Parcelable, Serializable { isFavorite = we.isFavorite isEncrypted = we.isEncrypted mountType = we.mountType - ownerId = we.ownerId - ownerDisplayName = we.ownerDisplayName + ownerId = we.ownerId ?: "" + ownerDisplayName = we.ownerDisplayName ?: "" + name = we.name ?: "" note = we.note unreadCommentsCount = we.unreadCommentsCount isHasPreview = we.isHasPreview @@ -112,76 +111,45 @@ class RemoteFile : Parcelable, Serializable { hidden = we.hidden } - /** - * Used internally. Reset all file properties - */ - private fun resetData() { - remotePath = null - mimeType = null - length = 0 - creationTimestamp = 0 - modifiedTimestamp = 0 - etag = null - permissions = null - localId = -1 - remoteId = null - size = 0 - isFavorite = false - isEncrypted = false - ownerId = "" - ownerDisplayName = "" - note = "" - isLocked = false - lockOwner = null - lockType = null - lockOwnerDisplayName = null - lockOwnerEditor = null - lockTimestamp = 0 - lockTimeout = 0 - lockToken = null - tags = null - hidden = false - livePhoto = null - } - /** * Reconstruct from parcel * * @param source The source parcel */ - private constructor(source: Parcel) { + private constructor(source: Parcel) : this() { readFromParcel(source) } private fun readFromParcel(source: Parcel) { - remotePath = source.readString() - mimeType = source.readString() - length = source.readLong() creationTimestamp = source.readLong() - modifiedTimestamp = source.readLong() etag = source.readString() - permissions = source.readString() - localId = source.readLong() - remoteId = source.readString() - size = source.readLong() - isFavorite = source.readString().toBoolean() + hidden = source.readInt() == 1 isEncrypted = source.readString().toBoolean() - mountType = source.readSerializable() as MountType? - ownerId = source.readString() - ownerDisplayName = source.readString() + isFavorite = source.readString().toBoolean() isHasPreview = source.readString().toBoolean() - note = source.readString() - source.readParcelableArray(ShareeUser::class.java.classLoader) isLocked = source.readInt() == 1 - lockType = fromValue(source.readInt()) - lockOwner = source.readString() + length = source.readLong() + livePhoto = source.readString() + localId = source.readLong() lockOwnerDisplayName = source.readString() lockOwnerEditor = source.readString() - lockTimestamp = source.readLong() + lockOwner = source.readString() lockTimeout = source.readLong() + lockTimestamp = source.readLong() lockToken = source.readString() - livePhoto = source.readString() - hidden = source.readInt() == 1 + lockType = fromValue(source.readInt()) + mimeType = source.readString() + modifiedTimestamp = source.readLong() + mountType = source.readSerializableCompat(MountType::class.java) + name = source.readString() ?: "" + note = source.readString() ?: "" + ownerDisplayName = source.readString() ?: "" + ownerId = source.readString() ?: "" + permissions = source.readString() + remoteId = source.readString() + remotePath = source.readString() + sharees = source.readParcelableArrayCompat(ShareeUser::class.java) + size = source.readLong() } override fun describeContents(): Int { @@ -208,6 +176,7 @@ class RemoteFile : Parcelable, Serializable { dest.writeString(ownerId) dest.writeString(ownerDisplayName) dest.writeString(isHasPreview.toString()) + dest.writeString(name) dest.writeString(note) dest.writeParcelableArray(sharees, 0) dest.writeInt(if (isLocked) 1 else 0) @@ -222,6 +191,13 @@ class RemoteFile : Parcelable, Serializable { dest.writeInt(if (hidden) 1 else 0) } + /** + * Check whether RemoteFile is a directory. + * + * @return `true`, iff RemoteFile is directory. + */ + fun isDirectory() = mimeType == WebdavEntry.DIR_TYPE + companion object { /** * Generated - should be refreshed every time the class changes!! diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCCreationTime.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCCreationTime.kt new file mode 100644 index 000000000..092c28f67 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCCreationTime.kt @@ -0,0 +1,33 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser + +class NCCreationTime private constructor(val creationTime: Long) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + XmlUtils.readText(parser)?.let { date -> + return NCCreationTime(date.toLong()) + } + return NCCreationTime(0) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.CREATION_TIME.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCEncrypted.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCEncrypted.kt new file mode 100644 index 000000000..a9e2971ce --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCEncrypted.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2022 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCEncrypted private constructor(val encrypted: Boolean) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = XmlUtils.readText(parser) + if (!text.isNullOrEmpty()) { + return NCEncrypted("1" == text) + } + } catch (e: IOException) { + Log.e("NCEncrypted", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCEncrypted", "failed to create property", e) + } + return NCEncrypted(false) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.IS_ENCRYPTED.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCEtag.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCEtag.kt new file mode 100644 index 000000000..33d12c6a9 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCEtag.kt @@ -0,0 +1,35 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2022 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils +import at.bitfire.dav4jvm.property.webdav.NS_WEBDAV +import com.owncloud.android.lib.common.network.WebdavUtils +import org.xmlpull.v1.XmlPullParser + +class NCEtag private constructor(val etag: String?) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): NCEtag { + // + XmlUtils.readText(parser)?.let { rawEtag -> + return NCEtag(WebdavUtils.parseEtag(rawEtag)) + } + return NCEtag(null) + } + } + + companion object { + @JvmField + val NAME = Property.Name(NS_WEBDAV, "getetag") + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCFavorite.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCFavorite.kt new file mode 100644 index 000000000..dd608fba5 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCFavorite.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2022 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCFavorite private constructor(val favorite: Boolean) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return NCFavorite("1" == text) + } + } catch (e: IOException) { + Log.e("OCFavorite", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("OCFavorite", "failed to create property", e) + } + return NCFavorite(false) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.FAVORITE.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCGetLastModified.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCGetLastModified.kt new file mode 100644 index 000000000..c0ff0137d --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCGetLastModified.kt @@ -0,0 +1,38 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2023-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2023 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils +import at.bitfire.dav4jvm.property.webdav.NS_WEBDAV +import com.owncloud.android.lib.common.network.WebdavUtils +import org.xmlpull.v1.XmlPullParser + +class NCGetLastModified private constructor(val lastModified: Long) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): NCGetLastModified { + // + XmlUtils.readText(parser)?.let { rawDate -> + val date = WebdavUtils.parseResponseDate(rawDate) + if (date != null) { + return NCGetLastModified(date.time) + } + } + return NCGetLastModified(0) + } + } + + companion object { + @JvmField + val NAME = Property.Name(NS_WEBDAV, "getlastmodified") + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCHidden.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCHidden.kt new file mode 100644 index 000000000..a8e77d24c --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCHidden.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCHidden private constructor(val hidden: Boolean) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = XmlUtils.readText(parser) + if (!text.isNullOrEmpty()) { + return NCHidden("true" == text) + } + } catch (e: IOException) { + Log.e("NCEncrypted", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCEncrypted", "failed to create property", e) + } + return NCHidden(false) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.HIDDEN.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLock.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLock.kt new file mode 100644 index 000000000..374a3e24b --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLock.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCLock private constructor(val locked: Boolean) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = XmlUtils.readText(parser) + if (!text.isNullOrEmpty()) { + return NCLock("1" == text) + } + } catch (e: IOException) { + Log.e("NCEncrypted", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCEncrypted", "failed to create property", e) + } + return NCLock(false) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.LOCK.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwner.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwner.kt new file mode 100644 index 000000000..82ca6d9c4 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwner.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCLockOwner private constructor(val lockOwner: String?) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return NCLockOwner(text) + } + } catch (e: IOException) { + Log.e("NCLockOwner", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCLockOwner", "failed to create property", e) + } + return NCLockOwner(null) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.LOCK_OWNER.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwnerDisplayName.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwnerDisplayName.kt new file mode 100644 index 000000000..f26e8a496 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwnerDisplayName.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCLockOwnerDisplayName private constructor(val lockOwnerDisplayName: String) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return NCLockOwnerDisplayName(text) + } + } catch (e: IOException) { + Log.e("NCOwnerDisplayName", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCOwnerDisplayName", "failed to create property", e) + } + return NCLockOwnerDisplayName("") + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.LOCK_OWNER_DISPLAY_NAME.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwnerEditor.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwnerEditor.kt new file mode 100644 index 000000000..c4690905b --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwnerEditor.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCLockOwnerEditor private constructor(val lockOwnerEditor: String?) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return NCLockOwnerEditor(text) + } + } catch (e: IOException) { + Log.e("NCLockOwnerEditor", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCLockOwnerEditor", "failed to create property", e) + } + return NCLockOwnerEditor(null) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.LOCK_OWNER_EDITOR.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwnerType.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwnerType.kt new file mode 100644 index 000000000..d8b2bee7e --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockOwnerType.kt @@ -0,0 +1,44 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import com.owncloud.android.lib.resources.files.model.FileLockType +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCLockOwnerType private constructor(val lockOwnerType: FileLockType?) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return NCLockOwnerType(FileLockType.fromValue(text.toInt())) + } + } catch (e: IOException) { + Log.e("NCLockOwnerType", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCLockOwnerType", "failed to create property", e) + } + return NCLockOwnerType(null) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.LOCK_OWNER_TYPE.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockTime.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockTime.kt new file mode 100644 index 000000000..40e2dbf7e --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockTime.kt @@ -0,0 +1,33 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser + +class NCLockTime private constructor(val lockTime: Long) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + XmlUtils.readText(parser)?.let { date -> + return NCLockTime(date.toLong()) + } + return NCLockTime(0) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.LOCK_TIME.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockTimeout.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockTimeout.kt new file mode 100644 index 000000000..ff228a8f3 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockTimeout.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCLockTimeout private constructor(val lockTimeout: Long) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return NCLockTimeout(text.toLong()) + } + } catch (e: IOException) { + Log.e("NCLockTimeout", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCLockTimeout", "failed to create property", e) + } + return NCLockTimeout(0) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.LOCK_TIMEOUT.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockToken.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockToken.kt new file mode 100644 index 000000000..d1f19de13 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCLockToken.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCLockToken private constructor(val lockToken: String?) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return NCLockToken(text) + } + } catch (e: IOException) { + Log.e("NCLockToken", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCLockToken", "failed to create property", e) + } + return NCLockToken(null) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.LOCK_TOKEN.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataGPS.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataGPS.kt new file mode 100644 index 000000000..117a38e90 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataGPS.kt @@ -0,0 +1,46 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils +import com.google.gson.Gson +import com.owncloud.android.lib.common.network.ExtendedProperties +import com.owncloud.android.lib.resources.files.model.GeoLocation +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCMetadataGPS private constructor(val geoLocation: GeoLocation?) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = XmlUtils.readText(parser) + if (!text.isNullOrEmpty()) { + val geoLocation = Gson().fromJson(text, GeoLocation::class.java) + return NCMetadataGPS(geoLocation) + } + } catch (e: IOException) { + Log.e("NCMetadataGPS", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCMetadataGPS", "failed to create property", e) + } + return NCMetadataGPS(null) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.METADATA_GPS.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataLivePhoto.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataLivePhoto.kt new file mode 100644 index 000000000..8c0793039 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataLivePhoto.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCMetadataLivePhoto private constructor(val livePhoto: String?) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return NCMetadataLivePhoto(text) + } + } catch (e: IOException) { + Log.e("NCOwnerDisplayName", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCOwnerDisplayName", "failed to create property", e) + } + return NCMetadataLivePhoto(null) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.METADATA_LIVE_PHOTO.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataPhotosGPS.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataPhotosGPS.kt new file mode 100644 index 000000000..77eac884c --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataPhotosGPS.kt @@ -0,0 +1,63 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.propertyName +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import com.owncloud.android.lib.resources.files.model.GeoLocation +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCMetadataPhotosGPS private constructor(val geoLocation: GeoLocation) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + return NCMetadataPhotosGPS(parseText(parser)) + } + + @Suppress("NestedBlockDepth") + private fun parseText(parser: XmlPullParser): GeoLocation { + var latitude = 0.0 + var longitude = 0.0 + + val depth = parser.depth + var eventType = parser.eventType + + try { + while (eventType != XmlPullParser.END_TAG || parser.depth != depth) { + if (eventType != XmlPullParser.TEXT) { + when (parser.propertyName().name) { + "latitude" -> readText(parser)?.let { latitude = it.toDouble() } + "longitude" -> readText(parser)?.let { longitude = it.toDouble() } + } + } + + eventType = parser.next() + } + } catch (e: IOException) { + Log.e("NCMetadataPhotosGPS", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCMetadataPhotosGPS", "failed to create property", e) + } + + return GeoLocation(latitude, longitude) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.METADATA_PHOTOS_GPS.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataPhotosSize.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataPhotosSize.kt new file mode 100644 index 000000000..359e97fad --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataPhotosSize.kt @@ -0,0 +1,63 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.propertyName +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import com.owncloud.android.lib.resources.files.model.ImageDimension +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCMetadataPhotosSize private constructor(val imageDimension: ImageDimension) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + return NCMetadataPhotosSize(parseText(parser)) + } + + @Suppress("NestedBlockDepth") + private fun parseText(parser: XmlPullParser): ImageDimension { + var width = 0.0f + var height = 0.0f + + val depth = parser.depth + var eventType = parser.eventType + + try { + while (eventType != XmlPullParser.END_TAG || parser.depth != depth) { + if (eventType != XmlPullParser.TEXT) { + when (parser.propertyName().name) { + "width" -> readText(parser)?.let { width = it.toFloat() } + "height" -> readText(parser)?.let { height = it.toFloat() } + } + } + + eventType = parser.next() + } + } catch (e: IOException) { + Log.e("NCMetadataPhotosSize", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCMetadataPhotosSize", "failed to create property", e) + } + + return ImageDimension(width, height) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.METADATA_PHOTOS_SIZE.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataSize.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataSize.kt new file mode 100644 index 000000000..a1d33ecea --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMetadataSize.kt @@ -0,0 +1,46 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils +import com.google.gson.Gson +import com.owncloud.android.lib.common.network.ExtendedProperties +import com.owncloud.android.lib.resources.files.model.ImageDimension +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCMetadataSize private constructor(val imageDimension: ImageDimension?) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = XmlUtils.readText(parser) + if (!text.isNullOrEmpty()) { + val imageDimension = Gson().fromJson(text, ImageDimension::class.java) + return NCMetadataSize(imageDimension) + } + } catch (e: IOException) { + Log.e("NCMetadataSize", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCMetadataSize", "failed to create property", e) + } + return NCMetadataSize(null) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.METADATA_SIZE.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMountType.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMountType.kt new file mode 100644 index 000000000..dfe013830 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCMountType.kt @@ -0,0 +1,39 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2022 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils +import com.owncloud.android.lib.common.network.ExtendedProperties +import com.owncloud.android.lib.common.network.WebdavEntry +import org.xmlpull.v1.XmlPullParser + +class NCMountType private constructor(val mountType: WebdavEntry.MountType) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): NCMountType { + // (#PCDATA) > + val type = XmlUtils.readText(parser) + return NCMountType( + when (type) { + "external" -> WebdavEntry.MountType.EXTERNAL + "group" -> WebdavEntry.MountType.GROUP + else -> WebdavEntry.MountType.INTERNAL + } + ) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.MOUNT_TYPE.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCNote.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCNote.kt new file mode 100644 index 000000000..19953a506 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCNote.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCNote private constructor(val note: String) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return NCNote(text) + } + } catch (e: IOException) { + Log.e("NCNote", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCNote", "failed to create property", e) + } + return NCNote("") + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.NOTE.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCPermissions.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCPermissions.kt new file mode 100644 index 000000000..5b35cb4ff --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCPermissions.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCPermissions private constructor(val permissions: String?) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = XmlUtils.readText(parser) + if (!text.isNullOrEmpty()) { + return NCPermissions(text) + } + } catch (e: IOException) { + Log.e("NCPermissions", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCPermissions", "failed to create property", e) + } + return NCPermissions(null) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.NAME_PERMISSIONS.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCPreview.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCPreview.kt new file mode 100644 index 000000000..14ca5d257 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCPreview.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2022 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCPreview private constructor(val preview: Boolean) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return NCPreview(text.toBoolean()) + } + } catch (e: IOException) { + Log.e("NCPreview", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCPreview", "failed to create property", e) + } + return NCPreview(false) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.HAS_PREVIEW.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCRichWorkspace.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCRichWorkspace.kt new file mode 100644 index 000000000..e3722bbf4 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCRichWorkspace.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2022 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCRichWorkspace private constructor(val richWorkspace: String?) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): NCRichWorkspace { + try { + val text = XmlUtils.readText(parser) + if (!text.isNullOrEmpty()) { + return NCRichWorkspace(text) + } + } catch (e: IOException) { + Log.e("NCRichWorkspace", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCRichWorkspace", "failed to create property", e) + } + return NCRichWorkspace(null) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.RICH_WORKSPACE.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCSharees.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCSharees.kt new file mode 100644 index 000000000..b91bc7a4a --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCSharees.kt @@ -0,0 +1,120 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2022 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import androidx.annotation.VisibleForTesting +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.propertyName +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import com.owncloud.android.lib.resources.shares.ShareType +import com.owncloud.android.lib.resources.shares.ShareeUser +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCSharees private constructor(val sharees: Array) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): NCSharees { + // NC sharees property + readArrayNode(parser).let { sharees -> + return NCSharees(sharees.toTypedArray()) + } + } + + @Throws(IOException::class, XmlPullParserException::class) + @VisibleForTesting + fun readArrayNode(parser: XmlPullParser): List { + var list: List = emptyList() + + val depth = parser.depth + var eventType = parser.eventType + while (eventType != XmlPullParser.END_TAG || parser.depth != depth) { + if (eventType != XmlPullParser.TEXT) { + list = readNCSharees(parser) + } + if (parser.eventType == XmlPullParser.END_TAG && parser.depth == depth) { + return list + } + + eventType = parser.next() + } + + return list + } + + private fun readNCSharees(parser: XmlPullParser): List { + val list: ArrayList = ArrayList() + + val depth = parser.depth + var eventType = parser.eventType + while (eventType != XmlPullParser.END_TAG || parser.depth != depth) { + if (eventType == XmlPullParser.START_TAG && parser.depth == depth + 1) { + // only add non-null users + readNCSharee(parser)?.let { list.add(it) } + } + + eventType = parser.next() + } + + return list + } + + private fun readNCSharee(parser: XmlPullParser): ShareeUser? { + val depth = parser.depth + var eventType = parser.eventType + + var userId: String? = null + var displayName: String? = null + var shareType: ShareType? = null + + while (eventType != XmlPullParser.END_TAG || parser.depth != depth) { + if (eventType != XmlPullParser.TEXT) { + when (parser.propertyName()) { + ExtendedProperties.SHAREES_ID.toPropertyName() -> { + userId = readText(parser) + } + + ExtendedProperties.SHAREES_DISPLAY_NAME.toPropertyName() -> { + displayName = readText(parser) + } + + ExtendedProperties.SHAREES_SHARE_TYPE.toPropertyName() -> { + shareType = ShareType.fromValue(readText(parser)?.toInt() ?: 0) + } + } + } + + eventType = parser.next() + } + + // check that user is an actual sharee - e.g. exclude link shares + + val isSupportedShareType = + ShareType.EMAIL == shareType || + ShareType.FEDERATED == shareType || + ShareType.GROUP == shareType || + ShareType.ROOM == shareType + + return if (userId.isNullOrEmpty() || (displayName.isNullOrEmpty() && !isSupportedShareType)) { + null + } else { + ShareeUser(userId, displayName, shareType) + } + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.SHAREES.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTags.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTags.kt new file mode 100644 index 000000000..801eba8a9 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTags.kt @@ -0,0 +1,111 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2022 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.text.TextUtils +import androidx.annotation.VisibleForTesting +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.propertyName +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import com.owncloud.android.lib.resources.shares.ShareType +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCTags private constructor(val tags: Array) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): NCTags { + // NC sharees property + readArrayNode(parser).let { sharees -> + return NCTags(sharees.toTypedArray()) + } + } + + @Throws(IOException::class, XmlPullParserException::class) + @VisibleForTesting + fun readArrayNode(parser: XmlPullParser): List { + var list: List = emptyList() + + val depth = parser.depth + var eventType = parser.eventType + while (!(eventType == XmlPullParser.END_TAG && parser.depth == depth)) { + if (eventType != XmlPullParser.TEXT) { + list = readNCSharees(parser) + } + if (parser.eventType == XmlPullParser.END_TAG && parser.depth == depth) { + return list + } + + eventType = parser.next() + } + + return list + } + + private fun readNCSharees(parser: XmlPullParser): List { + val list: ArrayList = ArrayList() + + val depth = parser.depth + var eventType = parser.eventType + while (!(eventType == XmlPullParser.END_TAG && parser.depth == depth)) { + if (eventType == XmlPullParser.START_TAG && parser.depth == depth + 1) { + list.add(readNCSharee(parser)) + } + + eventType = parser.next() + } + + return list + } + + private fun readNCSharee(parser: XmlPullParser): String { + val depth = parser.depth + var eventType = parser.eventType + + var userId: String? = null + var displayName: String? = null + var shareType: ShareType? = null + + while (!(eventType == XmlPullParser.END_TAG && parser.depth == depth)) { + if (eventType != XmlPullParser.TEXT) { + when (parser.propertyName().toString()) { + "http://nextcloud.org/ns:id" -> { + userId = readText(parser) + } + + "http://nextcloud.org/ns:display-name" -> { + displayName = readText(parser) + } + + "http://nextcloud.org/ns:type" -> { + shareType = + ShareType.fromValue(readText(parser)?.toInt() ?: 0) + } + } + } + + if (!TextUtils.isEmpty(parser.text)) { + return parser.text + } + eventType = parser.next() + } + + return "" + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.SYSTEM_TAGS.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTrashbinDeletionTime.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTrashbinDeletionTime.kt new file mode 100644 index 000000000..0a07b3464 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTrashbinDeletionTime.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCTrashbinDeletionTime private constructor(val deletionTime: Long) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = XmlUtils.readText(parser) + if (!text.isNullOrEmpty()) { + return NCTrashbinDeletionTime(text.toLong()) + } + } catch (e: IOException) { + Log.e("NCTrashbinDeletionTime", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCTrashbinDeletionTime", "failed to create property", e) + } + return NCTrashbinDeletionTime(0) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.TRASHBIN_DELETION_TIME.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTrashbinFilename.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTrashbinFilename.kt new file mode 100644 index 000000000..0173436f2 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTrashbinFilename.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCTrashbinFilename private constructor(val originalLocation: String?) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return NCTrashbinFilename(text) + } + } catch (e: IOException) { + Log.e("NCTrashbinFilename", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCTrashbinFilename", "failed to create property", e) + } + return NCTrashbinFilename(null) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.TRASHBIN_FILENAME.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTrashbinLocation.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTrashbinLocation.kt new file mode 100644 index 000000000..dfa541065 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCTrashbinLocation.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCTrashbinLocation private constructor(val originalLocation: String?) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return NCTrashbinLocation(text) + } + } catch (e: IOException) { + Log.e("NCTrashbinLocation", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCTrashbinLocation", "failed to create property", e) + } + return NCTrashbinLocation(null) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.TRASHBIN_ORIGINAL_LOCATION.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCUploadTime.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCUploadTime.kt new file mode 100644 index 000000000..cd3260c10 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/NCUploadTime.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class NCUploadTime private constructor(val uploadTime: Long) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = XmlUtils.readText(parser) + if (!text.isNullOrEmpty()) { + return NCUploadTime(text.toLong()) + } + } catch (e: IOException) { + Log.e("NCUploadTime", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("NCUploadTime", "failed to create property", e) + } + return NCUploadTime(0) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.UPLOAD_TIME.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCCommentsUnread.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCCommentsUnread.kt new file mode 100644 index 000000000..82589edd6 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCCommentsUnread.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class OCCommentsUnread private constructor(val commentsCount: Int) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return OCCommentsUnread(text.toInt()) + } + } catch (e: IOException) { + Log.e("OCCommentsUnread", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("OCCommentsUnread", "failed to create property", e) + } + return OCCommentsUnread(0) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.UNREAD_COMMENTS.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCDisplayName.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCDisplayName.kt new file mode 100644 index 000000000..467ee3248 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCDisplayName.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class OCDisplayName private constructor(val displayName: String) : Property { + class Factory : PropertyFactory { + override fun getName(): Property.Name = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return OCDisplayName(text) + } + } catch (e: IOException) { + Log.e("OCDisplayName", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("OCDisplayName", "failed to create property", e) + } + return OCDisplayName("") + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.DISPLAY_NAME.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCId.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCId.kt new file mode 100644 index 000000000..58603af62 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCId.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2022 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class OCId private constructor(val id: String?) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return OCId(text) + } + } catch (e: IOException) { + Log.e("OCId", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("OCId", "failed to create property", e) + } + return OCId(null) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.NAME_REMOTE_ID.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCLocalId.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCLocalId.kt new file mode 100644 index 000000000..73c12aa69 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCLocalId.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2022 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class OCLocalId private constructor(val localId: Long) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return OCLocalId(text.toLong()) + } + } catch (e: IOException) { + Log.e("OCLocalId", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("OCLocalId", "failed to create property", e) + } + return OCLocalId(0) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.NAME_LOCAL_ID.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCOwnerDisplayName.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCOwnerDisplayName.kt new file mode 100644 index 000000000..559c4bec8 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCOwnerDisplayName.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2022 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class OCOwnerDisplayName private constructor(val ownerDisplayName: String?) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return OCOwnerDisplayName(text) + } + } catch (e: IOException) { + Log.e("OCOwnerDisplayName", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("OCOwnerDisplayName", "failed to create property", e) + } + return OCOwnerDisplayName(null) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.OWNER_DISPLAY_NAME.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCOwnerId.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCOwnerId.kt new file mode 100644 index 000000000..258d7e9f0 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCOwnerId.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2022 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class OCOwnerId private constructor(val ownerId: String?) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return OCOwnerId(text) + } + } catch (e: IOException) { + Log.e("OCOwnerId", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("OCOwnerId", "failed to create property", e) + } + return OCOwnerId(null) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.OWNER_ID.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCSize.kt b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCSize.kt new file mode 100644 index 000000000..b7137e085 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/webdav/OCSize.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2022 Tobias Kaminsky + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.files.webdav + +import android.util.Log +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyFactory +import at.bitfire.dav4jvm.XmlUtils.readText +import com.owncloud.android.lib.common.network.ExtendedProperties +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +class OCSize private constructor(val size: Long) : Property { + class Factory : PropertyFactory { + override fun getName() = NAME + + override fun create(parser: XmlPullParser): Property { + try { + val text = readText(parser) + if (!text.isNullOrEmpty()) { + return OCSize(text.toLong()) + } + } catch (e: IOException) { + Log.e("OCSize", "failed to create property", e) + } catch (e: XmlPullParserException) { + Log.e("OCSize", "failed to create property", e) + } + return OCSize(0) + } + } + + companion object { + @JvmField + val NAME = ExtendedProperties.NAME_SIZE.toPropertyName() + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/GetSharesForFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/shares/GetSharesForFileRemoteOperation.java index b579e65ba..c023cb007 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/GetSharesForFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/GetSharesForFileRemoteOperation.java @@ -19,12 +19,14 @@ import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.methods.GetMethod; +import java.util.List; + /** * 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. */ -public class GetSharesForFileRemoteOperation extends RemoteOperation { +public class GetSharesForFileRemoteOperation extends RemoteOperation> { private static final String TAG = GetSharesForFileRemoteOperation.class.getSimpleName(); @@ -54,8 +56,8 @@ public GetSharesForFileRemoteOperation(String remoteFilePath, boolean reshares, } @Override - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result = null; + protected RemoteOperationResult> run(OwnCloudClient client) { + RemoteOperationResult> result; int status = -1; GetMethod get = null; diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareToRemoteOperationResultParser.java b/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareToRemoteOperationResultParser.java index cfe57a75d..b11614034 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareToRemoteOperationResultParser.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareToRemoteOperationResultParser.java @@ -91,16 +91,16 @@ public RemoteOperationResult> parse(String serverResponse) { } else if (shareXmlParser.isWrongParameter()) { result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.SHARE_WRONG_PARAMETER); - result.setMessage(shareXmlParser.getMessage()); + result.message = shareXmlParser.getMessage(); } else if (shareXmlParser.isNotFound()) { result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND); - result.setMessage(shareXmlParser.getMessage()); + result.message = shareXmlParser.getMessage(); } else if (shareXmlParser.isForbidden()) { result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.SHARE_FORBIDDEN); - result.setMessage(shareXmlParser.getMessage()); + result.message = shareXmlParser.getMessage(); } else { result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE); - result.setMessage(shareXmlParser.getMessage()); + result.message = shareXmlParser.getMessage(); } } catch (XmlPullParserException e) { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java b/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java index ad7d08c49..2fa8d2121 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.java @@ -346,7 +346,7 @@ private void readElement(XmlPullParser parser, ArrayList shares) case NODE_EXPIRATION: String expirationValue = readNode(parser, NODE_EXPIRATION); if (expirationValue.length() > 0) { - Date date = WebdavUtils.parseResponseDate(expirationValue); + Date date = WebdavUtils.INSTANCE.parseResponseDate(expirationValue); if (date != null) { share.setExpirationDate(date.getTime()); } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/status/GetCapabilitiesRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/status/GetCapabilitiesRemoteOperation.java index acd225b18..b2f178d57 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/status/GetCapabilitiesRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/status/GetCapabilitiesRemoteOperation.java @@ -15,12 +15,10 @@ import com.nextcloud.common.NextcloudClient; import com.nextcloud.operations.GetMethod; -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.Header; import org.apache.commons.httpclient.HttpStatus; import org.json.JSONArray; import org.json.JSONException; @@ -34,7 +32,7 @@ * * Save in Result.getData in a OCCapability object */ -public class GetCapabilitiesRemoteOperation extends RemoteOperation { +public class GetCapabilitiesRemoteOperation extends RemoteOperation { private static final String TAG = GetCapabilitiesRemoteOperation.class.getSimpleName(); @@ -176,8 +174,8 @@ public GetCapabilitiesRemoteOperation(OCCapability currentCapability) { } @Override - public RemoteOperationResult run(NextcloudClient client) { - RemoteOperationResult result; + public RemoteOperationResult run(NextcloudClient client) { + RemoteOperationResult result; int status; GetMethod get = null; @@ -199,8 +197,8 @@ public RemoteOperationResult run(NextcloudClient client) { if (isNotModified(status)) { Log_OC.d(TAG, "Capabilities not modified"); - result = new RemoteOperationResult(true, get); - result.setSingleData(currentCapability); + result = new RemoteOperationResult<>(true, get); + result.setResultData(currentCapability); Log_OC.d(TAG, "*** Get Capabilities completed "); } else if (isSuccess(status)) { @@ -215,85 +213,16 @@ public RemoteOperationResult run(NextcloudClient client) { } // Result - result = new RemoteOperationResult(true, get); - result.setSingleData(capability); + result = new RemoteOperationResult<>(true, get); + result.setResultData(capability); } else { - result = new RemoteOperationResult(false, get); + result = new RemoteOperationResult<>(false, get); 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 (JSONException | IOException e) { - result = new RemoteOperationResult(e); - Log_OC.e(TAG, "Exception while getting capabilities", e); - - } finally { - if (get != null) { - get.releaseConnection(); - } - } - return result; - } - - @Override - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result; - int status; - org.apache.commons.httpclient.methods.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 org.apache.commons.httpclient.methods.GetMethod(uriBuilder.build().toString()); - get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE); - - if (null != currentCapability && !"".equals(currentCapability.getEtag())) { - get.addRequestHeader(OCS_ETAG_HEADER, currentCapability.getEtag()); - } - - status = client.executeMethod(get); - - if (isNotModified(status)) { - Log_OC.d(TAG, "Capabilities not modified"); - - result = new RemoteOperationResult(true, get); - result.setSingleData(currentCapability); - - Log_OC.d(TAG, "*** Get Capabilities completed "); - } else if (isSuccess(status)) { - String response = get.getResponseBodyAsString(); - Log_OC.d(TAG, "Successful response: " + response); - - OCCapability capability = parseResponse(response); - - Header etag = get.getResponseHeader("ETag"); - if (etag != null) { - capability.setEtag(etag.getValue()); - } - - // Result - result = new RemoteOperationResult(true, get); - result.setSingleData(capability); - } else { - result = new RemoteOperationResult(false, get); - 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); - } + Log_OC.e(TAG, "*** status code: " + status + "; response message: " + response); } } catch (JSONException | IOException e) { - result = new RemoteOperationResult(e); + result = new RemoteOperationResult<>(e); Log_OC.e(TAG, "Exception while getting capabilities", e); } finally { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/tags/CreateTagRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/tags/CreateTagRemoteOperation.kt index 1684be0f0..7ee032d7a 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/tags/CreateTagRemoteOperation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/tags/CreateTagRemoteOperation.kt @@ -7,33 +7,22 @@ */ package com.owncloud.android.lib.resources.tags -import com.google.gson.Gson +import com.nextcloud.common.JSONRequestBody import com.nextcloud.common.NextcloudClient import com.nextcloud.operations.PostMethod import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult -import okhttp3.MediaType.Companion.toMediaTypeOrNull -import okhttp3.RequestBody import org.apache.commons.httpclient.HttpStatus class CreateTagRemoteOperation(val name: String) : RemoteOperation() { override fun run(client: NextcloudClient): RemoteOperationResult { - val map = HashMap() - map["name"] = name - - val json = Gson().toJson(map) - - val request = RequestBody.create("application/json".toMediaTypeOrNull(), json) - - val postMethod = PostMethod(client.baseUri.toString() + TAG_URL, true, request) + val requestBody = JSONRequestBody("name", name) + val postMethod = PostMethod(client.baseUri.toString() + TAG_URL, true, requestBody.get()) val status = postMethod.execute(client) + val isSuccess = status == HttpStatus.SC_CREATED - return if (status == HttpStatus.SC_CREATED) { - RemoteOperationResult(true, postMethod) - } else { - RemoteOperationResult(false, postMethod) - } + return RemoteOperationResult(isSuccess, postMethod) } companion object { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/tags/GetTagsRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/tags/GetTagsRemoteOperation.kt index 22577c82f..395897a1c 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/tags/GetTagsRemoteOperation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/tags/GetTagsRemoteOperation.kt @@ -2,67 +2,43 @@ * Nextcloud Android Library * * SPDX-FileCopyrightText: 2023-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> * SPDX-FileCopyrightText: 2023 Tobias Kaminsky * SPDX-License-Identifier: MIT */ package com.owncloud.android.lib.resources.tags -import com.owncloud.android.lib.common.OwnCloudClient -import com.owncloud.android.lib.common.network.WebdavEntry.Companion.EXTENDED_PROPERTY_NAME_REMOTE_ID -import com.owncloud.android.lib.common.network.WebdavEntry.Companion.NAMESPACE_OC -import com.owncloud.android.lib.common.network.WebdavEntry.Companion.SHAREES_DISPLAY_NAME +import com.nextcloud.common.NextcloudClient +import com.owncloud.android.lib.common.network.ExtendedProperties import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult -import org.apache.commons.httpclient.HttpStatus -import org.apache.jackrabbit.webdav.client.methods.PropFindMethod -import org.apache.jackrabbit.webdav.property.DavPropertyNameSet -import org.apache.jackrabbit.webdav.xml.Namespace +import okhttp3.HttpUrl.Companion.toHttpUrl class GetTagsRemoteOperation : RemoteOperation>() { @Deprecated("Deprecated in Java") - override fun run(client: OwnCloudClient): RemoteOperationResult> { - val ocNamespace = Namespace.getNamespace(NAMESPACE_OC) + override fun run(client: NextcloudClient): RemoteOperationResult> { + val url = (client.baseUri.toString() + TAG_URL).toHttpUrl() - val propSet = - DavPropertyNameSet().apply { - add(EXTENDED_PROPERTY_NAME_REMOTE_ID, ocNamespace) - add(SHAREES_DISPLAY_NAME, ocNamespace) - } - - val propFindMethod = - PropFindMethod( - client.baseUri.toString() + TAG_URL, - propSet, - 1 + val propertySet = + arrayOf( + ExtendedProperties.NAME_REMOTE_ID.toPropertyName(), + ExtendedProperties.DISPLAY_NAME.toPropertyName() ) - val status = client.executeMethod(propFindMethod) - - return if (status == HttpStatus.SC_MULTI_STATUS) { - val response = propFindMethod.responseBodyAsMultiStatus.responses - - val result = mutableListOf() - response.forEach { - if (it.getProperties(HttpStatus.SC_OK).contentSize > 0) { - val id = - it.getProperties(HttpStatus.SC_OK) - .get(EXTENDED_PROPERTY_NAME_REMOTE_ID, ocNamespace).value as String - val name = - it.getProperties(HttpStatus.SC_OK) - .get(SHAREES_DISPLAY_NAME, ocNamespace).value as String + val propFindMethod = com.nextcloud.operations.PropFindMethod(url, propertySet, 1) + val propFindResult = client.execute(propFindMethod) + val result = RemoteOperationResult>(propFindResult.davResponse) - result.add(Tag(id, name)) + val tags = + propFindResult.children.mapNotNull { remoteFile -> + remoteFile.remoteId?.let { remoteId -> + Tag(remoteId, remoteFile.name) } } - RemoteOperationResult>(true, propFindMethod).apply { - resultData = result - } - } else { - RemoteOperationResult>(false, propFindMethod).apply { - resultData = emptyList() - } - } + result.resultData = tags + + return result } companion object { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/trashbin/ReadTrashbinFolderRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/trashbin/ReadTrashbinFolderRemoteOperation.java index 98948ab6a..dda34a745 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/trashbin/ReadTrashbinFolderRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/trashbin/ReadTrashbinFolderRemoteOperation.java @@ -7,6 +7,7 @@ */ package com.owncloud.android.lib.resources.trashbin; +import com.nextcloud.extensions.ArrayExtensionsKt; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.network.WebdavEntry; import com.owncloud.android.lib.common.network.WebdavUtils; @@ -55,9 +56,11 @@ public RemoteOperationResult> run(OwnCloudClient client) { try { String baseUri = client.getDavUri() + "/trashbin/" + client.getUserId() + "/trash"; - DavPropertyNameSet propSet = WebdavUtils.getTrashbinPropSet(); + DavPropertyNameSet propSet = ArrayExtensionsKt.toLegacyPropset( + WebdavUtils.PROPERTYSETS.INSTANCE.getTRASHBIN() + ); - query = new PropFindMethod(baseUri + WebdavUtils.encodePath(remotePath), propSet, DavConstants.DEPTH_1); + query = new PropFindMethod(baseUri + WebdavUtils.INSTANCE.encodePath(remotePath), propSet, DavConstants.DEPTH_1); int status = client.executeMethod(query); // check and process response diff --git a/library/src/main/java/com/owncloud/android/lib/resources/trashbin/RemoveTrashbinFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/trashbin/RemoveTrashbinFileRemoteOperation.java index d6b325998..14df65a22 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/trashbin/RemoveTrashbinFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/trashbin/RemoveTrashbinFileRemoteOperation.java @@ -19,13 +19,13 @@ /** * Remote operation performing the removal of a file in trashbin. */ -public class RemoveTrashbinFileRemoteOperation extends RemoteOperation { +public class RemoveTrashbinFileRemoteOperation extends RemoteOperation { private static final String TAG = RemoveTrashbinFileRemoteOperation.class.getSimpleName(); private static final int REMOVE_READ_TIMEOUT = 30000; private static final int REMOVE_CONNECTION_TIMEOUT = 5000; - private String remotePath; + private final String remotePath; /** * Constructor @@ -42,20 +42,20 @@ public RemoveTrashbinFileRemoteOperation(String remotePath) { * @param client Client object to communicate with the remote ownCloud server. */ @Override - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result; + protected RemoteOperationResult run(OwnCloudClient client) { + RemoteOperationResult result; DeleteMethod delete = null; try { - delete = new DeleteMethod(client.getDavUri() + WebdavUtils.encodePath(remotePath)); + delete = new DeleteMethod(client.getDavUri() + WebdavUtils.INSTANCE.encodePath(remotePath)); int status = client.executeMethod(delete, REMOVE_READ_TIMEOUT, REMOVE_CONNECTION_TIMEOUT); delete.getResponseBodyAsString(); // exhaust the response, although not interesting - result = new RemoteOperationResult((delete.succeeded() || status == HttpStatus.SC_NOT_FOUND), delete); + result = new RemoteOperationResult<>((delete.succeeded() || status == HttpStatus.SC_NOT_FOUND), delete); Log_OC.i(TAG, "Remove " + remotePath + ": " + result.getLogMessage()); } catch (Exception e) { - result = new RemoteOperationResult(e); + result = new RemoteOperationResult<>(e); Log_OC.e(TAG, "Remove " + remotePath + ": " + result.getLogMessage(), e); } finally { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/trashbin/RestoreTrashbinFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/trashbin/RestoreTrashbinFileRemoteOperation.java index a1455f5a6..2f3b1f4ce 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/trashbin/RestoreTrashbinFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/trashbin/RestoreTrashbinFileRemoteOperation.java @@ -24,14 +24,14 @@ /** * Restore a {@link TrashbinFile}. */ -public class RestoreTrashbinFileRemoteOperation extends RemoteOperation { +public class RestoreTrashbinFileRemoteOperation extends RemoteOperation { private static final String TAG = RestoreTrashbinFileRemoteOperation.class.getSimpleName(); private static final int RESTORE_READ_TIMEOUT = 30000; private static final int RESTORE_CONNECTION_TIMEOUT = 5000; - private String sourcePath; - private String fileName; + private final String sourcePath; + private final String fileName; /** * Constructor @@ -50,23 +50,23 @@ public RestoreTrashbinFileRemoteOperation(String sourcePath, String fileName) { * @param client Client object to communicate with the remote ownCloud server. */ @Override - protected RemoteOperationResult run(OwnCloudClient client) { + protected RemoteOperationResult run(OwnCloudClient client) { MoveMethod move = null; - RemoteOperationResult result; + RemoteOperationResult result; try { - String source = client.getDavUri() + WebdavUtils.encodePath(sourcePath); + String source = client.getDavUri() + WebdavUtils.INSTANCE.encodePath(sourcePath); String target = client.getDavUri() + "/trashbin/" + client.getUserId() + "/restore/" + Uri.encode(fileName); move = new MoveMethod(source, target, true); int status = client.executeMethod(move, RESTORE_READ_TIMEOUT, RESTORE_CONNECTION_TIMEOUT); - result = new RemoteOperationResult(isSuccess(status), move); + result = new RemoteOperationResult<>(isSuccess(status), move); client.exhaustResponse(move.getResponseBodyAsStream()); } catch (IOException e) { - result = new RemoteOperationResult(e); + result = new RemoteOperationResult<>(e); Log.e(TAG, "Restore trashbin file " + sourcePath + " failed: " + result.getLogMessage(), e); } finally { if (move != null) { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/users/GetServerPublicKeyRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/users/GetServerPublicKeyRemoteOperation.kt index 91abb7881..bc6926bf4 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/users/GetServerPublicKeyRemoteOperation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/users/GetServerPublicKeyRemoteOperation.kt @@ -38,7 +38,7 @@ class GetServerPublicKeyRemoteOperation : RemoteOperation() { val serverKey = respJSON.getJSONObject("ocs").getJSONObject("data").getString("public-key") result = RemoteOperationResult(true, getMethod) - result.setResultData(serverKey) + result.resultData = serverKey } else { result = RemoteOperationResult(false, getMethod) } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/users/GetUserAvatarRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/users/GetUserAvatarRemoteOperation.java index f3dffe20f..ee063ecb8 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/users/GetUserAvatarRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/users/GetUserAvatarRemoteOperation.java @@ -153,7 +153,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { private RemoteOperationResult createResult(GetMethod get, byte[] avatarData, String mimeType) throws IOException { // find out etag - String etag = WebdavUtils.getEtagFromResponse(get); + String etag = WebdavUtils.INSTANCE.getEtagFromResponse(get); if (etag.length() == 0) { Log_OC.w(TAG, "Could not read Etag from avatar"); } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/users/SendCSRRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/users/SendCSRRemoteOperation.java index b37d03c49..dad6e5e32 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/users/SendCSRRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/users/SendCSRRemoteOperation.java @@ -7,6 +7,7 @@ */ package com.owncloud.android.lib.resources.users; +import com.nextcloud.common.JSONRequestBody; import com.nextcloud.common.NextcloudClient; import com.nextcloud.operations.PostMethod; import com.owncloud.android.lib.common.operations.RemoteOperation; @@ -17,9 +18,6 @@ import java.net.HttpURLConnection; -import okhttp3.FormBody; -import okhttp3.RequestBody; - /** * Remote operation performing the storage of the public key for an user @@ -55,15 +53,12 @@ public RemoteOperationResult run(NextcloudClient client) { try { // remote request - RequestBody body = new FormBody - .Builder() - .add(CSR, csr) - .build(); + JSONRequestBody jsonRequestBody = new JSONRequestBody(CSR, csr); postMethod = new PostMethod( client.getBaseUri() + PUBLIC_KEY_URL + JSON_FORMAT, true, - body); + jsonRequestBody.get()); int status = client.execute(postMethod); From 0bb570a473a3fbee27fb44f0d4ff09c0d1a64241 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Thu, 31 Oct 2024 09:11:29 +0100 Subject: [PATCH 2/3] wip Signed-off-by: tobiasKaminsky --- ...rkspaceDirectEditingRemoteOperationIT.java | 26 +++++++++---------- .../e2ee/UpdateMetadataRemoteOperationIT.java | 18 ++++++------- ...WorkspaceDirectEditingRemoteOperation.java | 14 +++++----- .../operations/RemoteOperationResult.kt | 14 ---------- .../GetSharesForFileRemoteOperation.java | 4 +-- 5 files changed, 31 insertions(+), 45 deletions(-) diff --git a/library/src/androidTest/java/com/nextcloud/android/lib/richWorkspace/RichWorkspaceDirectEditingRemoteOperationIT.java b/library/src/androidTest/java/com/nextcloud/android/lib/richWorkspace/RichWorkspaceDirectEditingRemoteOperationIT.java index 3dd186119..b73a70928 100644 --- a/library/src/androidTest/java/com/nextcloud/android/lib/richWorkspace/RichWorkspaceDirectEditingRemoteOperationIT.java +++ b/library/src/androidTest/java/com/nextcloud/android/lib/richWorkspace/RichWorkspaceDirectEditingRemoteOperationIT.java @@ -7,9 +7,6 @@ */ package com.nextcloud.android.lib.richWorkspace; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - import android.webkit.URLUtil; import com.owncloud.android.AbstractIT; @@ -22,15 +19,18 @@ import java.io.File; import java.io.IOException; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + public class RichWorkspaceDirectEditingRemoteOperationIT extends AbstractIT { @Test public void getEditLinkForRoot() { - RemoteOperationResult result = new RichWorkspaceDirectEditingRemoteOperation("/").execute(client); + RemoteOperationResult result = new RichWorkspaceDirectEditingRemoteOperation("/").execute(client); assertTrue(result.isSuccess()); - assertNotNull(result.getSingleData()); + assertNotNull(result.getResultData()); - String url = (String) result.getSingleData(); + String url = result.getResultData(); assertTrue(URLUtil.isValidUrl(url)); } @@ -41,11 +41,11 @@ public void getEditLinkForFolder() { assertTrue(new CreateFolderRemoteOperation(path, true).execute(nextcloudClient).isSuccess()); - RemoteOperationResult result = new RichWorkspaceDirectEditingRemoteOperation(path).execute(client); + RemoteOperationResult result = new RichWorkspaceDirectEditingRemoteOperation(path).execute(client); assertTrue(result.isSuccess()); - assertNotNull(result.getSingleData()); + assertNotNull(result.getResultData()); - String url = (String) result.getSingleData(); + String url = result.getResultData(); assertTrue(URLUtil.isValidUrl(url)); } @@ -58,7 +58,7 @@ public void reuseExistingFile() throws IOException { assertTrue(new CreateFolderRemoteOperation(folder, true).execute(nextcloudClient).isSuccess()); - RemoteOperationResult uploadResult = new UploadFileRemoteOperation( + RemoteOperationResult uploadResult = new UploadFileRemoteOperation( txtFile.getAbsolutePath(), filePath, "txt/plain", @@ -67,11 +67,11 @@ public void reuseExistingFile() throws IOException { assertTrue("Error uploading file " + filePath + ": " + uploadResult, uploadResult.isSuccess()); - RemoteOperationResult result = new RichWorkspaceDirectEditingRemoteOperation(folder).execute(client); + RemoteOperationResult result = new RichWorkspaceDirectEditingRemoteOperation(folder).execute(client); assertTrue(result.isSuccess()); - assertNotNull(result.getSingleData()); + assertNotNull(result.getResultData()); - String url = (String) result.getSingleData(); + String url = result.getResultData(); assertTrue(URLUtil.isValidUrl(url)); } diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperationIT.java b/library/src/androidTest/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperationIT.java index 18a510982..bf46de45d 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperationIT.java +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperationIT.java @@ -7,11 +7,6 @@ */ package com.owncloud.android.lib.resources.e2ee; -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertNotNull; -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertFalse; - import android.text.TextUtils; import com.nextcloud.test.RandomStringGenerator; @@ -22,6 +17,11 @@ import com.owncloud.android.lib.resources.files.model.RemoteFile; import com.owncloud.android.lib.resources.status.OwnCloudVersion; +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNotNull; +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertFalse; + public class UpdateMetadataRemoteOperationIT extends AbstractIT { //@Test public void uploadAndModifyV1() { @@ -84,11 +84,11 @@ public void uploadAndModifyV1() { assertTrue(new UnlockFileRemoteOperation(remoteFolder.getLocalId(), token).execute(client).isSuccess()); // verify metadata - String retrievedMetadata2 = (String) new GetMetadataRemoteOperation(remoteFolder.getLocalId()) + MetadataResponse retrievedMetadata2 = new GetMetadataRemoteOperation(remoteFolder.getLocalId()) .execute(client) - .getSingleData(); + .getResultData(); - assertEquals(updatedMetadata, retrievedMetadata2); + assertEquals(updatedMetadata, retrievedMetadata2.getMetadata()); } //@Test @@ -103,7 +103,7 @@ public void uploadAndModifyV2() { // create folder String folder = "/" + RandomStringGenerator.make(20) + "/"; assertTrue(new CreateFolderRemoteOperation(folder, true).execute(nextcloudClient).isSuccess()); - RemoteFile remoteFolder = (RemoteFile) new ReadFileRemoteOperation(folder).execute(nextcloudClient).getSingleData(); + RemoteFile remoteFolder = new ReadFileRemoteOperation(folder).execute(nextcloudClient).getResultData(); assertNotNull(remoteFolder); diff --git a/library/src/main/java/com/nextcloud/android/lib/richWorkspace/RichWorkspaceDirectEditingRemoteOperation.java b/library/src/main/java/com/nextcloud/android/lib/richWorkspace/RichWorkspaceDirectEditingRemoteOperation.java index d798d0f22..b3d4003ed 100644 --- a/library/src/main/java/com/nextcloud/android/lib/richWorkspace/RichWorkspaceDirectEditingRemoteOperation.java +++ b/library/src/main/java/com/nextcloud/android/lib/richWorkspace/RichWorkspaceDirectEditingRemoteOperation.java @@ -25,7 +25,7 @@ * Get direct editing url for rich workspace */ -public class RichWorkspaceDirectEditingRemoteOperation extends RemoteOperation { +public class RichWorkspaceDirectEditingRemoteOperation extends RemoteOperation { private static final String TAG = RichWorkspaceDirectEditingRemoteOperation.class.getSimpleName(); private static final int SYNC_READ_TIMEOUT = 40000; private static final int SYNC_CONNECTION_TIMEOUT = 5000; @@ -38,8 +38,8 @@ public RichWorkspaceDirectEditingRemoteOperation(String path) { this.path = path; } - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result; + protected RemoteOperationResult run(OwnCloudClient client) { + RemoteOperationResult result; Utf8PostMethod postMethod = null; try { @@ -63,14 +63,14 @@ protected RemoteOperationResult run(OwnCloudClient client) { JSONObject respJSON = new JSONObject(response); String url = (String) respJSON.getJSONObject("ocs").getJSONObject("data").get("url"); - result = new RemoteOperationResult(true, postMethod); - result.setSingleData(url); + result = new RemoteOperationResult<>(true, postMethod); + result.setResultData(url); } else { - result = new RemoteOperationResult(false, postMethod); + result = new RemoteOperationResult<>(false, postMethod); client.exhaustResponse(postMethod.getResponseBodyAsStream()); } } catch (Exception e) { - result = new RemoteOperationResult(e); + result = new RemoteOperationResult<>(e); Log_OC.e(TAG, "Get edit url for rich workspace failed: " + result.getLogMessage(), result.getException()); } finally { diff --git a/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.kt b/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.kt index 7af58ae0c..cb8fa586c 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.kt +++ b/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.kt @@ -515,20 +515,6 @@ class RemoteOperationResult : Serializable { mData = files as ArrayList? } - @get:Deprecated("use getResultData() instead") - @set:Deprecated("use setResultData() instead") - @Suppress("TooGenericExceptionThrown") - var singleData: Any - get() { - if (!isSuccess) { - throw RuntimeException("Accessing result data after operation failed!") - } - return mData!![0] - } - set(data) { - mData = ArrayList(listOf(data)) - } - val isCancelled = code == ResultCode.CANCELLED val isSslRecoverableException = code == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/GetSharesForFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/shares/GetSharesForFileRemoteOperation.java index c023cb007..e5e8b2590 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/GetSharesForFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/GetSharesForFileRemoteOperation.java @@ -93,11 +93,11 @@ protected RemoteOperationResult> run(OwnCloudClient client) { } } else { - result = new RemoteOperationResult(false, get); + result = new RemoteOperationResult<>(false, get); } } catch (Exception e) { - result = new RemoteOperationResult(e); + result = new RemoteOperationResult<>(e); Log_OC.e(TAG, "Exception while getting shares", e); } finally { From 178752374a1560265f528709d40d2b90c4611087 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Thu, 31 Oct 2024 11:36:26 +0100 Subject: [PATCH 3/3] wip Signed-off-by: tobiasKaminsky --- .../shares/CreateShareRemoteOperationIT.kt | 13 +++--- .../operations/RemoteOperationResult.kt | 20 ---------- .../e2ee/StoreMetadataRemoteOperation.java | 18 ++++----- .../e2ee/UpdateMetadataRemoteOperation.java | 17 ++++---- .../GetSharesForFileRemoteOperation.java | 2 +- .../shares/UpdateShareRemoteOperation.java | 2 +- .../status/GetStatusRemoteOperation.java | 40 +++++++++---------- .../users/GetUserAvatarRemoteOperation.java | 23 +++++------ .../lib/sampleclient/MainActivity.java | 13 ++---- 9 files changed, 55 insertions(+), 93 deletions(-) diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt index 2a6d2d7ba..0ca2a3ef7 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/CreateShareRemoteOperationIT.kt @@ -11,10 +11,10 @@ import com.owncloud.android.AbstractIT import com.owncloud.android.lib.resources.files.CreateFolderRemoteOperation import com.owncloud.android.lib.resources.status.GetStatusRemoteOperation import com.owncloud.android.lib.resources.status.NextcloudVersion -import com.owncloud.android.lib.resources.status.OwnCloudVersion import org.junit.Assert import org.junit.Assert.assertEquals -import org.junit.Assume +import org.junit.Assert.assertTrue +import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Test @@ -22,10 +22,11 @@ class CreateShareRemoteOperationIT : AbstractIT() { @Before fun before() { val result = GetStatusRemoteOperation(context).execute(client) - Assert.assertTrue(result.isSuccess) - val data = result.data as ArrayList - val ownCloudVersion = data[0] as OwnCloudVersion - Assume.assumeTrue(ownCloudVersion.isNewerOrEqual(NextcloudVersion.nextcloud_24)) + assertTrue(result.isSuccess) + + val data = result.resultData + val ownCloudVersion = data?.first + assumeTrue(ownCloudVersion?.isNewerOrEqual(NextcloudVersion.nextcloud_24) == true) } @Test diff --git a/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.kt b/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.kt index cb8fa586c..05682f13a 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.kt +++ b/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.kt @@ -495,26 +495,6 @@ class RemoteOperationResult : Serializable { } } - @get:Deprecated("use getResultData() instead") - @set:Deprecated("use setResultData() instead") - @Suppress("TooGenericExceptionThrown") - var data: java.util.ArrayList? - get() { - if (!isSuccess) { - throw RuntimeException("Accessing result data after operation failed!") - } - return if (mData != null) { - mData - } else if (resultData is ArrayList<*>) { - resultData as ArrayList<*>? - } else { - null - } - } - set(files) { - mData = files as ArrayList? - } - val isCancelled = code == ResultCode.CANCELLED val isSslRecoverableException = code == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED diff --git a/library/src/main/java/com/owncloud/android/lib/resources/e2ee/StoreMetadataRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/e2ee/StoreMetadataRemoteOperation.java index 1c95b95d4..e5f210167 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/e2ee/StoreMetadataRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/e2ee/StoreMetadataRemoteOperation.java @@ -16,14 +16,12 @@ import org.apache.commons.httpclient.methods.Utf8PostMethod; import org.json.JSONObject; -import java.util.ArrayList; - /** * Remote operation to store the folder metadata */ -public class StoreMetadataRemoteOperation extends RemoteOperation { +public class StoreMetadataRemoteOperation extends RemoteOperation { private static final String TAG = StoreMetadataRemoteOperation.class.getSimpleName(); private static final int SYNC_READ_TIMEOUT = 40000; @@ -51,9 +49,9 @@ public StoreMetadataRemoteOperation(long fileId, String encryptedMetadataJson) { * @param client Client object */ @Override - protected RemoteOperationResult run(OwnCloudClient client) { + protected RemoteOperationResult run(OwnCloudClient client) { Utf8PostMethod postMethod = null; - RemoteOperationResult result; + RemoteOperationResult result; try { // remote request @@ -71,16 +69,14 @@ protected RemoteOperationResult run(OwnCloudClient client) { String metadata = (String) respJSON.getJSONObject(NODE_OCS).getJSONObject(NODE_DATA) .get(NODE_META_DATA); - result = new RemoteOperationResult(true, postMethod); - ArrayList keys = new ArrayList<>(); - keys.add(metadata); - result.setData(keys); + result = new RemoteOperationResult<>(true, postMethod); + result.setResultData(metadata); } else { - result = new RemoteOperationResult(false, postMethod); + result = new RemoteOperationResult<>(false, postMethod); client.exhaustResponse(postMethod.getResponseBodyAsStream()); } } catch (Exception e) { - result = new RemoteOperationResult(e); + result = new RemoteOperationResult<>(e); Log_OC.e(TAG, "Storing of metadata for folder " + fileId + " failed: " + result.getLogMessage(), result.getException()); } finally { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperation.java index 0ebe60f01..4fa21d5b2 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperation.java @@ -19,14 +19,13 @@ import org.json.JSONObject; import java.net.URLEncoder; -import java.util.ArrayList; /** * Remote operation to update the folder metadata */ -public class UpdateMetadataRemoteOperation extends RemoteOperation { +public class UpdateMetadataRemoteOperation extends RemoteOperation { private static final String TAG = UpdateMetadataRemoteOperation.class.getSimpleName(); private static final int SYNC_READ_TIMEOUT = 40000; @@ -56,9 +55,9 @@ public UpdateMetadataRemoteOperation(long fileId, String encryptedMetadataJson, * @param client Client object */ @Override - protected RemoteOperationResult run(OwnCloudClient client) { + protected RemoteOperationResult run(OwnCloudClient client) { PutMethod putMethod = null; - RemoteOperationResult result; + RemoteOperationResult result; try { // remote request @@ -85,16 +84,14 @@ protected RemoteOperationResult run(OwnCloudClient client) { String metadata = (String) respJSON.getJSONObject(NODE_OCS).getJSONObject(NODE_DATA) .get(NODE_META_DATA); - result = new RemoteOperationResult(true, putMethod); - ArrayList keys = new ArrayList<>(); - keys.add(metadata); - result.setData(keys); + result = new RemoteOperationResult<>(true, putMethod); + result.setResultData(metadata); } else { - result = new RemoteOperationResult(false, putMethod); + result = new RemoteOperationResult<>(false, putMethod); client.exhaustResponse(putMethod.getResponseBodyAsStream()); } } catch (Exception e) { - result = new RemoteOperationResult(e); + result = new RemoteOperationResult<>(e); Log_OC.e(TAG, "Storing of metadata for folder " + fileId + " failed: " + result.getLogMessage(), result.getException()); } finally { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/GetSharesForFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/shares/GetSharesForFileRemoteOperation.java index e5e8b2590..0b4142502 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/GetSharesForFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/GetSharesForFileRemoteOperation.java @@ -89,7 +89,7 @@ protected RemoteOperationResult> run(OwnCloudClient client) { result = parser.parse(response); if (result.isSuccess()) { - Log_OC.d(TAG, "Got " + result.getData().size() + " shares"); + Log_OC.d(TAG, "Got " + result.getResultData().size() + " shares"); } } else { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperation.java index 830a67724..c46a7b647 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/shares/UpdateShareRemoteOperation.java @@ -36,7 +36,7 @@ * * Allow updating several parameters, triggering a request to the server per parameter. */ -public class UpdateShareRemoteOperation extends RemoteOperation { +public class UpdateShareRemoteOperation extends RemoteOperation> { private static final String TAG = GetShareRemoteOperation.class.getSimpleName(); diff --git a/library/src/main/java/com/owncloud/android/lib/resources/status/GetStatusRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/status/GetStatusRemoteOperation.java index 423abcbe3..af4f130e2 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/status/GetStatusRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/status/GetStatusRemoteOperation.java @@ -14,6 +14,7 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.Uri; +import android.util.Pair; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; @@ -29,15 +30,13 @@ import org.json.JSONException; import org.json.JSONObject; -import java.util.ArrayList; - /** * Checks if the server is valid and if the server supports the Share API * * @author David A. Velasco * @author masensio */ -public class GetStatusRemoteOperation extends RemoteOperation { +public class GetStatusRemoteOperation extends RemoteOperation> { /** * Maximum time to wait for a response from the server when the connection is being tested, in MILLISECONDs. @@ -53,7 +52,7 @@ public class GetStatusRemoteOperation extends RemoteOperation { private static final String PROTOCOL_HTTP = "http://"; private static final int UNTRUSTED_DOMAIN_ERROR_CODE = 15; - private RemoteOperationResult mLatestResult; + private RemoteOperationResult> mLatestResult; private Context mContext; public GetStatusRemoteOperation(Context context) { @@ -74,7 +73,7 @@ private boolean tryConnection(OwnCloudClient client) { client.setFollowRedirects(false); boolean isRedirectToNonSecureConnection = false; int status = client.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT); - mLatestResult = new RemoteOperationResult((status == HttpStatus.SC_OK), get); + mLatestResult = new RemoteOperationResult<>((status == HttpStatus.SC_OK), get); String redirectedLocation = mLatestResult.getRedirectedLocation(); while (redirectedLocation != null && redirectedLocation.length() > 0 @@ -87,7 +86,7 @@ private boolean tryConnection(OwnCloudClient client) { get.releaseConnection(); get = new GetMethod(redirectedLocation); status = client.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT); - mLatestResult = new RemoteOperationResult((status == HttpStatus.SC_OK), get); + mLatestResult = new RemoteOperationResult<>((status == HttpStatus.SC_OK), get); redirectedLocation = mLatestResult.getRedirectedLocation(); } @@ -96,7 +95,7 @@ private boolean tryConnection(OwnCloudClient client) { if (status == HttpStatus.SC_OK) { JSONObject json = new JSONObject(response); if (!json.getBoolean(NODE_INSTALLED)) { - mLatestResult = new RemoteOperationResult( + mLatestResult = new RemoteOperationResult<>( RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); } else { boolean extendedSupport = false; @@ -108,24 +107,21 @@ private boolean tryConnection(OwnCloudClient client) { OwnCloudVersion ocVersion = new OwnCloudVersion(version); if (!ocVersion.isVersionValid()) { - mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.BAD_OC_VERSION); + mLatestResult = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.BAD_OC_VERSION); } else { // success if (isRedirectToNonSecureConnection) { - mLatestResult = new RemoteOperationResult( + mLatestResult = new RemoteOperationResult<>( RemoteOperationResult.ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION); } else { - mLatestResult = new RemoteOperationResult( + mLatestResult = new RemoteOperationResult<>( baseUrlSt.startsWith(PROTOCOL_HTTPS) ? RemoteOperationResult.ResultCode.OK_SSL : RemoteOperationResult.ResultCode.OK_NO_SSL ); } - ArrayList data = new ArrayList<>(); - data.add(ocVersion); - data.add(extendedSupport); - mLatestResult.setData(data); + mLatestResult.setResultData(new Pair<>(ocVersion, extendedSupport)); retval = true; } } @@ -134,22 +130,22 @@ private boolean tryConnection(OwnCloudClient client) { JSONObject json = new JSONObject(response); if (json.getInt("code") == UNTRUSTED_DOMAIN_ERROR_CODE) { - mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.UNTRUSTED_DOMAIN); + mLatestResult = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.UNTRUSTED_DOMAIN); } else { - mLatestResult = new RemoteOperationResult(false, status, get.getResponseHeaders()); + mLatestResult = new RemoteOperationResult<>(false, status, get.getResponseHeaders()); } } catch (JSONException e) { - mLatestResult = new RemoteOperationResult(false, status, get.getResponseHeaders()); + mLatestResult = new RemoteOperationResult<>(false, status, get.getResponseHeaders()); } } else { - mLatestResult = new RemoteOperationResult(false, status, get.getResponseHeaders()); + mLatestResult = new RemoteOperationResult<>(false, status, get.getResponseHeaders()); } } catch (JSONException e) { - mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); + mLatestResult = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); } catch (Exception e) { - mLatestResult = new RemoteOperationResult(e); + mLatestResult = new RemoteOperationResult<>(e); } finally { if (get != null) @@ -178,9 +174,9 @@ private boolean isOnline() { } @Override - protected RemoteOperationResult run(OwnCloudClient client) { + protected RemoteOperationResult> run(OwnCloudClient client) { if (!isOnline()) { - return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION); + return new RemoteOperationResult<>(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION); } String baseUriStr = client.getBaseUri().toString(); if (baseUriStr.startsWith(PROTOCOL_HTTP) || baseUriStr.startsWith(PROTOCOL_HTTPS)) { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/users/GetUserAvatarRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/users/GetUserAvatarRemoteOperation.java index ee063ecb8..6c6a970f3 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/users/GetUserAvatarRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/users/GetUserAvatarRemoteOperation.java @@ -24,12 +24,11 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; /** * Gets avatar about the user logged in, if available */ -public class GetUserAvatarRemoteOperation extends RemoteOperation { +public class GetUserAvatarRemoteOperation extends RemoteOperation { private static final String TAG = GetUserAvatarRemoteOperation.class.getSimpleName(); @@ -51,8 +50,8 @@ public GetUserAvatarRemoteOperation(int dimension, String currentEtag) { } @Override - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result = null; + protected RemoteOperationResult run(OwnCloudClient client) { + RemoteOperationResult result = null; GetMethod get = null; InputStream inputStream = null; BufferedInputStream bis = null; @@ -92,7 +91,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { Header contentType = get.getResponseHeader(CONTENT_TYPE); if (contentType == null || !contentType.getValue().startsWith("image")) { Log_OC.e(TAG, "Not an image, failing with no avatar"); - result = new RemoteOperationResult(RemoteOperationResult.ResultCode.FILE_NOT_FOUND); + result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.FILE_NOT_FOUND); return result; } mimeType = contentType.getValue(); @@ -115,12 +114,12 @@ protected RemoteOperationResult run(OwnCloudClient client) { result = createResult(get, bos.toByteArray(), mimeType); } else { - result = new RemoteOperationResult(false, get); + result = new RemoteOperationResult<>(false, get); client.exhaustResponse(get.getResponseBodyAsStream()); } } catch (Exception e) { - result = new RemoteOperationResult(e); + result = new RemoteOperationResult<>(e); Log_OC.e(TAG, "Exception while getting OC user avatar", e); } finally { @@ -151,18 +150,16 @@ protected RemoteOperationResult run(OwnCloudClient client) { return result; } - private RemoteOperationResult createResult(GetMethod get, byte[] avatarData, String mimeType) throws IOException { + private RemoteOperationResult createResult(GetMethod get, byte[] avatarData, String mimeType) throws IOException { // find out etag String etag = WebdavUtils.INSTANCE.getEtagFromResponse(get); - if (etag.length() == 0) { + if (etag.isEmpty()) { Log_OC.w(TAG, "Could not read Etag from avatar"); } - RemoteOperationResult result = new RemoteOperationResult(true, get); + RemoteOperationResult result = new RemoteOperationResult<>(true, get); ResultData resultData = new ResultData(avatarData, mimeType, etag); - ArrayList data = new ArrayList<>(); - data.add(resultData); - result.setData(data); + result.setResultData(resultData); return result; } diff --git a/sample_client/src/main/java/com/owncloud/android/lib/sampleclient/MainActivity.java b/sample_client/src/main/java/com/owncloud/android/lib/sampleclient/MainActivity.java index 6f2d36709..6c6e10b89 100644 --- a/sample_client/src/main/java/com/owncloud/android/lib/sampleclient/MainActivity.java +++ b/sample_client/src/main/java/com/owncloud/android/lib/sampleclient/MainActivity.java @@ -39,7 +39,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -198,7 +197,7 @@ public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationRe Log.e(TAG, result.getLogMessage(), result.getException()); } else if (operation instanceof ReadFolderRemoteOperation) { - onSuccessfulRefresh((ReadFolderRemoteOperation) operation, result); + onSuccessfulRefresh(result); } else if (operation instanceof UploadFileRemoteOperation) { onSuccessfulUpload((UploadFileRemoteOperation) operation, result); @@ -214,14 +213,10 @@ public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationRe } } - private void onSuccessfulRefresh(ReadFolderRemoteOperation operation, RemoteOperationResult result) { + private void onSuccessfulRefresh(RemoteOperationResult> result) { mFilesAdapter.clear(); - List files = new ArrayList(); - for (Object obj : result.getData()) { - files.add((RemoteFile) obj); - } - - Iterator it = files.iterator(); + + Iterator it = result.getResultData().iterator(); while (it.hasNext()) { mFilesAdapter.add(it.next()); }