diff --git a/owncloud-android-library b/owncloud-android-library index 23a38a7fe6e..ea1f4ec33ee 160000 --- a/owncloud-android-library +++ b/owncloud-android-library @@ -1 +1 @@ -Subproject commit 23a38a7fe6e2f59d98062a1ac48f5a3a9e200543 +Subproject commit ea1f4ec33ee9531dee4c462d035a2ca0da01d112 diff --git a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/LocalDataSourceModule.kt b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/LocalDataSourceModule.kt index 93613af728c..c3aca696340 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/LocalDataSourceModule.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/LocalDataSourceModule.kt @@ -27,6 +27,9 @@ import com.owncloud.android.data.authentication.datasources.implementation.OCLoc import com.owncloud.android.data.capabilities.datasources.LocalCapabilitiesDataSource import com.owncloud.android.data.capabilities.datasources.implementation.OCLocalCapabilitiesDataSource import com.owncloud.android.data.capabilities.datasources.mapper.OCCapabilityMapper +import com.owncloud.android.data.files.datasources.LocalFileDataSource +import com.owncloud.android.data.files.datasources.implementation.OCLocalFileDataSource +import com.owncloud.android.data.files.datasources.mapper.OCFileMapper import com.owncloud.android.data.sharing.shares.datasources.LocalShareDataSource import com.owncloud.android.data.sharing.shares.datasources.implementation.OCLocalShareDataSource import com.owncloud.android.data.sharing.shares.datasources.mapper.OCShareMapper @@ -37,18 +40,21 @@ import org.koin.android.ext.koin.androidContext import org.koin.dsl.module val localDataSourceModule = module { - single { AccountManager.get(androidContext())} + single { AccountManager.get(androidContext()) } single { OwncloudDatabase.getDatabase(androidContext()).capabilityDao() } + single { OwncloudDatabase.getDatabase(androidContext()).fileDao() } single { OwncloudDatabase.getDatabase(androidContext()).shareDao() } single { OwncloudDatabase.getDatabase(androidContext()).userDao() } factory { OCCapabilityMapper() } + factory { OCFileMapper() } factory { OCShareMapper() } factory { UserQuotaMapper() } factory { OCLocalAuthenticationDataSource(androidContext(), get(), accountType) } factory { OCLocalCapabilitiesDataSource(get(), get()) } + factory { OCLocalFileDataSource(get(), get()) } factory { OCLocalShareDataSource(get(), get()) } factory { OCLocalUserDataSource(get(), get()) } } diff --git a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/RemoteDataSourceModule.kt b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/RemoteDataSourceModule.kt index a6ee427a519..ce898187d5b 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/RemoteDataSourceModule.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/RemoteDataSourceModule.kt @@ -29,6 +29,7 @@ import com.owncloud.android.data.capabilities.datasources.implementation.OCRemot import com.owncloud.android.data.capabilities.datasources.mapper.RemoteCapabilityMapper import com.owncloud.android.data.files.datasources.RemoteFileDataSource import com.owncloud.android.data.files.datasources.implementation.OCRemoteFileDataSource +import com.owncloud.android.data.files.datasources.mapper.RemoteFileMapper import com.owncloud.android.data.server.datasources.RemoteServerInfoDataSource import com.owncloud.android.data.server.datasources.implementation.OCRemoteServerInfoDataSource import com.owncloud.android.data.sharing.sharees.datasources.RemoteShareeDataSource @@ -71,7 +72,7 @@ val remoteDataSourceModule = module { factory { OCRemoteAuthenticationDataSource(androidContext(), get()) } factory { OCRemoteCapabilitiesDataSource(get(), get()) } - factory { OCRemoteFileDataSource(get()) } + factory { OCRemoteFileDataSource(get(), get()) } factory { OCRemoteServerInfoDataSource(get()) } factory { OCRemoteShareDataSource(get(), get()) } factory { OCRemoteShareeDataSource(get()) } @@ -80,6 +81,7 @@ val remoteDataSourceModule = module { ).toInt()) } factory { RemoteCapabilityMapper() } + factory { RemoteFileMapper() } factory { RemoteShareMapper() } factory { RemoteUserAvatarMapper() } factory { RemoteUserInfoMapper() } diff --git a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/RepositoryModule.kt b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/RepositoryModule.kt index 57d5f2e166a..1e00bce6c85 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/RepositoryModule.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/RepositoryModule.kt @@ -38,7 +38,7 @@ import org.koin.dsl.module val repositoryModule = module { factory { OCAuthenticationRepository(get(), get()) } factory { OCCapabilityRepository(get(), get()) } - factory { OCFileRepository(get()) } + factory { OCFileRepository(get(), get()) } factory { OCServerInfoRepository(get()) } factory { OCShareeRepository(get()) } factory { OCShareRepository(get(), get()) } diff --git a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/UseCaseModule.kt b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/UseCaseModule.kt index 3f0fbe5c3d1..16180dffc08 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/UseCaseModule.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/UseCaseModule.kt @@ -26,6 +26,7 @@ import com.owncloud.android.domain.authentication.usecases.SupportsOAuth2UseCase import com.owncloud.android.domain.capabilities.usecases.GetCapabilitiesAsLiveDataUseCase import com.owncloud.android.domain.capabilities.usecases.GetStoredCapabilitiesUseCase import com.owncloud.android.domain.capabilities.usecases.RefreshCapabilitiesFromServerAsyncUseCase +import com.owncloud.android.domain.files.RefreshFolderFromServerAsyncUseCase import com.owncloud.android.domain.server.usecases.GetServerInfoAsyncUseCase import com.owncloud.android.domain.sharing.sharees.GetShareesAsyncUseCase import com.owncloud.android.domain.sharing.shares.usecases.CreatePrivateShareAsyncUseCase @@ -54,6 +55,9 @@ val useCaseModule = module { factory { GetStoredCapabilitiesUseCase(get()) } factory { RefreshCapabilitiesFromServerAsyncUseCase(get()) } + // Files + factory { RefreshFolderFromServerAsyncUseCase(get()) } + // Sharing factory { GetShareesAsyncUseCase(get()) } factory { GetSharesAsLiveDataUseCase(get()) } diff --git a/owncloudApp/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/owncloudApp/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index fb0f8a4fbd2..7912533a304 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/owncloudApp/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -35,8 +35,8 @@ import com.owncloud.android.lib.common.operations.OperationCancelledException; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; -import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation; import com.owncloud.android.lib.resources.files.RemoteFile; +import com.owncloud.android.lib.resources.files.services.implementation.OCFileService; import com.owncloud.android.operations.common.SyncOperation; import com.owncloud.android.services.OperationsService; import com.owncloud.android.utils.FileStorageUtils; @@ -259,9 +259,8 @@ private RemoteOperationResult> fetchRemoteFolder(OwnCloudC if (mCancellationRequested.get()) { throw new OperationCancelledException(); } - - ReadRemoteFolderOperation readFolderOperation = new ReadRemoteFolderOperation(mRemotePath); - return readFolderOperation.execute(client); + OCFileService ocFileService = new OCFileService(client); + return ocFileService.refreshFolder(mRemotePath); } /** diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/viewmodels/drawer/DrawerViewModel.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/viewmodels/drawer/DrawerViewModel.kt index eb6e11d2b88..304246dda8f 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/viewmodels/drawer/DrawerViewModel.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/viewmodels/drawer/DrawerViewModel.kt @@ -21,12 +21,10 @@ package com.owncloud.android.presentation.viewmodels.drawer import android.accounts.Account -import android.accounts.AccountManager import android.content.Context import androidx.lifecycle.LiveData import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.ViewModel -import com.owncloud.android.MainApp import com.owncloud.android.authentication.AccountUtils import com.owncloud.android.domain.user.model.UserQuota import com.owncloud.android.domain.user.usecases.GetStoredQuotaUseCase diff --git a/owncloudData/schemas/com.owncloud.android.data.OwncloudDatabase/32.json b/owncloudData/schemas/com.owncloud.android.data.OwncloudDatabase/32.json new file mode 100644 index 00000000000..5272f4608fd --- /dev/null +++ b/owncloudData/schemas/com.owncloud.android.data.OwncloudDatabase/32.json @@ -0,0 +1,447 @@ +{ + "formatVersion": 1, + "database": { + "version": 32, + "identityHash": "89b7a96730784521dc5c2fea2bdf9e11", + "entities": [ + { + "tableName": "capabilities", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `account` TEXT, `version_mayor` INTEGER NOT NULL, `version_minor` INTEGER NOT NULL, `version_micro` INTEGER NOT NULL, `version_string` TEXT, `version_edition` TEXT, `core_pollinterval` INTEGER NOT NULL, `dav_chunking_version` TEXT NOT NULL, `sharing_api_enabled` INTEGER NOT NULL DEFAULT -1, `sharing_public_enabled` INTEGER NOT NULL DEFAULT -1, `sharing_public_password_enforced` INTEGER NOT NULL DEFAULT -1, `sharing_public_password_enforced_read_only` INTEGER NOT NULL DEFAULT -1, `sharing_public_password_enforced_read_write` INTEGER NOT NULL DEFAULT -1, `sharing_public_password_enforced_public_only` INTEGER NOT NULL DEFAULT -1, `sharing_public_expire_date_enabled` INTEGER NOT NULL DEFAULT -1, `sharing_public_expire_date_days` INTEGER NOT NULL, `sharing_public_expire_date_enforced` INTEGER NOT NULL DEFAULT -1, `sharing_public_upload` INTEGER NOT NULL DEFAULT -1, `sharing_public_multiple` INTEGER NOT NULL DEFAULT -1, `supports_upload_only` INTEGER NOT NULL DEFAULT -1, `sharing_resharing` INTEGER NOT NULL DEFAULT -1, `sharing_federation_outgoing` INTEGER NOT NULL DEFAULT -1, `sharing_federation_incoming` INTEGER NOT NULL DEFAULT -1, `files_bigfilechunking` INTEGER NOT NULL DEFAULT -1, `files_undelete` INTEGER NOT NULL DEFAULT -1, `files_versioning` INTEGER NOT NULL DEFAULT -1)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "accountName", + "columnName": "account", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "versionMayor", + "columnName": "version_mayor", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "versionMinor", + "columnName": "version_minor", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "versionMicro", + "columnName": "version_micro", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "versionString", + "columnName": "version_string", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "versionEdition", + "columnName": "version_edition", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "corePollInterval", + "columnName": "core_pollinterval", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "davChunkingVersion", + "columnName": "dav_chunking_version", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "filesSharingApiEnabled", + "columnName": "sharing_api_enabled", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicEnabled", + "columnName": "sharing_public_enabled", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicPasswordEnforced", + "columnName": "sharing_public_password_enforced", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicPasswordEnforcedReadOnly", + "columnName": "sharing_public_password_enforced_read_only", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicPasswordEnforcedReadWrite", + "columnName": "sharing_public_password_enforced_read_write", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicPasswordEnforcedUploadOnly", + "columnName": "sharing_public_password_enforced_public_only", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicExpireDateEnabled", + "columnName": "sharing_public_expire_date_enabled", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicExpireDateDays", + "columnName": "sharing_public_expire_date_days", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "filesSharingPublicExpireDateEnforced", + "columnName": "sharing_public_expire_date_enforced", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicUpload", + "columnName": "sharing_public_upload", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicMultiple", + "columnName": "sharing_public_multiple", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicSupportsUploadOnly", + "columnName": "supports_upload_only", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingResharing", + "columnName": "sharing_resharing", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingFederationOutgoing", + "columnName": "sharing_federation_outgoing", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingFederationIncoming", + "columnName": "sharing_federation_incoming", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesBigFileChunking", + "columnName": "files_bigfilechunking", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesUndelete", + "columnName": "files_undelete", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesVersioning", + "columnName": "files_versioning", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "files", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `owner` TEXT NOT NULL, `parentId` INTEGER, `length` INTEGER NOT NULL, `creationTimestamp` INTEGER NOT NULL, `modifiedTimestamp` INTEGER NOT NULL, `remotePath` TEXT NOT NULL, `mimeType` TEXT NOT NULL, `etag` TEXT NOT NULL, `permissions` TEXT NOT NULL, `remoteId` TEXT NOT NULL, `privateLink` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "owner", + "columnName": "owner", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "parentId", + "columnName": "parentId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "length", + "columnName": "length", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "creationTimestamp", + "columnName": "creationTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "modifiedTimestamp", + "columnName": "modifiedTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remotePath", + "columnName": "remotePath", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "mimeType", + "columnName": "mimeType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "etag", + "columnName": "etag", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "permissions", + "columnName": "permissions", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "privateLink", + "columnName": "privateLink", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "ocshares", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `file_source` TEXT NOT NULL, `item_source` TEXT NOT NULL, `share_type` INTEGER NOT NULL, `shate_with` TEXT, `path` TEXT NOT NULL, `permissions` INTEGER NOT NULL, `shared_date` INTEGER NOT NULL, `expiration_date` INTEGER NOT NULL, `token` TEXT, `shared_with_display_name` TEXT, `share_with_additional_info` TEXT, `is_directory` INTEGER NOT NULL, `user_id` INTEGER NOT NULL, `id_remote_shared` INTEGER NOT NULL, `owner_share` TEXT NOT NULL, `name` TEXT, `url` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "fileSource", + "columnName": "file_source", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "itemSource", + "columnName": "item_source", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shareType", + "columnName": "share_type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shareWith", + "columnName": "shate_with", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "permissions", + "columnName": "permissions", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sharedDate", + "columnName": "shared_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "expirationDate", + "columnName": "expiration_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "token", + "columnName": "token", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharedWithDisplayName", + "columnName": "shared_with_display_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharedWithAdditionalInfo", + "columnName": "share_with_additional_info", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isFolder", + "columnName": "is_directory", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "id_remote_shared", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "accountOwner", + "columnName": "owner_share", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "shareLink", + "columnName": "url", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "user_quotas", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountName` TEXT NOT NULL, `used` INTEGER NOT NULL, `available` INTEGER NOT NULL, PRIMARY KEY(`accountName`))", + "fields": [ + { + "fieldPath": "accountName", + "columnName": "accountName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "used", + "columnName": "used", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "available", + "columnName": "available", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "accountName" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '89b7a96730784521dc5c2fea2bdf9e11')" + ] + } +} \ No newline at end of file diff --git a/owncloudData/src/main/java/com/owncloud/android/data/OwncloudDatabase.kt b/owncloudData/src/main/java/com/owncloud/android/data/OwncloudDatabase.kt index 0f3d62bd7eb..dd7b0f91ebf 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/OwncloudDatabase.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/OwncloudDatabase.kt @@ -29,10 +29,13 @@ import androidx.room.RoomDatabase import androidx.room.migration.Migration import com.owncloud.android.data.capabilities.db.OCCapabilityDao import com.owncloud.android.data.capabilities.db.OCCapabilityEntity +import com.owncloud.android.data.files.db.FileDao +import com.owncloud.android.data.files.db.OCFileEntity import com.owncloud.android.data.migrations.MIGRATION_27_28 import com.owncloud.android.data.migrations.MIGRATION_28_29 import com.owncloud.android.data.migrations.MIGRATION_29_30 import com.owncloud.android.data.migrations.MIGRATION_30_31 +import com.owncloud.android.data.migrations.MIGRATION_31_32 import com.owncloud.android.data.sharing.shares.db.OCShareDao import com.owncloud.android.data.sharing.shares.db.OCShareEntity import com.owncloud.android.data.user.db.UserDao @@ -40,16 +43,18 @@ import com.owncloud.android.data.user.db.UserQuotaEntity @Database( entities = [ - OCShareEntity::class, OCCapabilityEntity::class, + OCFileEntity::class, + OCShareEntity::class, UserQuotaEntity::class ], version = ProviderMeta.DB_VERSION, exportSchema = true ) abstract class OwncloudDatabase : RoomDatabase() { - abstract fun shareDao(): OCShareDao abstract fun capabilityDao(): OCCapabilityDao + abstract fun fileDao(): FileDao + abstract fun shareDao(): OCShareDao abstract fun userDao(): UserDao companion object { @@ -60,7 +65,8 @@ abstract class OwncloudDatabase : RoomDatabase() { MIGRATION_27_28, MIGRATION_28_29, MIGRATION_29_30, - MIGRATION_30_31 + MIGRATION_30_31, + MIGRATION_31_32 ) fun getDatabase( diff --git a/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java b/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java index ac9c23ee1e1..aae0f145388 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java +++ b/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java @@ -31,7 +31,7 @@ public class ProviderMeta { public static final String DB_NAME = "filelist"; public static final String NEW_DB_NAME = "owncloud_database"; - public static final int DB_VERSION = 31; + public static final int DB_VERSION = 32; private ProviderMeta() { } @@ -39,6 +39,7 @@ private ProviderMeta() { static public class ProviderTableMeta implements BaseColumns { public static final String OCSHARES_TABLE_NAME = "ocshares"; public static final String CAPABILITIES_TABLE_NAME = "capabilities"; + public static final String FILES_TABLE_NAME = "files"; public static final String USER_QUOTAS_TABLE_NAME = "user_quotas"; // Columns of ocshares table diff --git a/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/LocalFileDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/LocalFileDataSource.kt new file mode 100644 index 00000000000..de5032f8078 --- /dev/null +++ b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/LocalFileDataSource.kt @@ -0,0 +1,26 @@ +/** + * ownCloud Android client application + * + * @author Abel García de Prada + * Copyright (C) 2020 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.owncloud.android.data.files.datasources + +import com.owncloud.android.domain.files.model.OCFile + +interface LocalFileDataSource { + fun saveFilesInFolder(listOfFiles: List, folder: OCFile) +} diff --git a/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/RemoteFileDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/RemoteFileDataSource.kt index e8102665183..458bd32573e 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/RemoteFileDataSource.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/RemoteFileDataSource.kt @@ -19,6 +19,10 @@ package com.owncloud.android.data.files.datasources +import com.owncloud.android.domain.files.model.OCFile + interface RemoteFileDataSource { fun checkPathExistence(path: String, checkUserCredentials: Boolean): Boolean + + fun refreshFolder(remotePath: String): List } diff --git a/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/implementation/OCLocalFileDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/implementation/OCLocalFileDataSource.kt new file mode 100644 index 00000000000..f02c16e6fcc --- /dev/null +++ b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/implementation/OCLocalFileDataSource.kt @@ -0,0 +1,41 @@ +/** + * ownCloud Android client application + * + * @author Abel García de Prada + * Copyright (C) 2020 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.data.files.datasources.implementation + +import com.owncloud.android.data.files.datasources.LocalFileDataSource +import com.owncloud.android.data.files.datasources.mapper.OCFileMapper +import com.owncloud.android.data.files.db.FileDao +import com.owncloud.android.domain.files.model.OCFile + +class OCLocalFileDataSource( + private val fileDao: FileDao, + private val ocFileMapper: OCFileMapper +) : LocalFileDataSource { + override fun saveFilesInFolder(listOfFiles: List, folder: OCFile) { + // Insert first folder container + // TODO: If it is root, add 0 as parent Id + val folderId = fileDao.mergeRemoteAndLocalFile(ocFileMapper.toEntity(folder)!!) + + // Then, insert files inside + listOfFiles.forEach { + // Add parent id to each file + fileDao.mergeRemoteAndLocalFile(ocFileMapper.toEntity(it)!!.apply { parentId = folderId }) + } + } +} diff --git a/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/implementation/OCRemoteFileDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/implementation/OCRemoteFileDataSource.kt index 0cc3f35d62b..8fca0003814 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/implementation/OCRemoteFileDataSource.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/implementation/OCRemoteFileDataSource.kt @@ -20,12 +20,19 @@ package com.owncloud.android.data.files.datasources.implementation import com.owncloud.android.data.files.datasources.RemoteFileDataSource +import com.owncloud.android.data.files.datasources.mapper.RemoteFileMapper +import com.owncloud.android.domain.files.model.OCFile import com.owncloud.android.lib.resources.files.services.FileService class OCRemoteFileDataSource( - private val fileService: FileService + private val fileService: FileService, + private val remoteFileMapper: RemoteFileMapper ) : RemoteFileDataSource { override fun checkPathExistence(path: String, checkUserCredentials: Boolean): Boolean = fileService.checkPathExistence(path = path, isUserLogged = checkUserCredentials).data + override fun refreshFolder(remotePath: String): List = + // Assert not null, service should return an empty list if no files there. + fileService.refreshFolder(remotePath).data.map { remoteFileMapper.toModel(it)!! } + } diff --git a/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/mapper/OCFileMapper.kt b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/mapper/OCFileMapper.kt new file mode 100644 index 00000000000..b8be407c2cf --- /dev/null +++ b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/mapper/OCFileMapper.kt @@ -0,0 +1,60 @@ +/** + * ownCloud Android client application + * + * @author Abel García de Prada + * Copyright (C) 2020 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.data.files.datasources.mapper + +import com.owncloud.android.data.files.db.OCFileEntity +import com.owncloud.android.domain.files.model.OCFile +import com.owncloud.android.domain.mappers.Mapper + +class OCFileMapper : Mapper { + override fun toModel(entity: OCFileEntity?): OCFile? = + entity?.let { + OCFile( + id = it.id, + parentId = it.parentId, + remotePath = it.remotePath, + owner = it.owner, + permissions = it.permissions, + remoteId = it.remoteId, + privateLink = it.privateLink, + creationTimestamp = it.creationTimestamp, + modifiedTimestamp = it.modifiedTimestamp, + etag = it.etag, + mimeType = it.mimeType, + length = it.length + ) + } + + override fun toEntity(model: OCFile?): OCFileEntity? = + model?.let { + OCFileEntity( + parentId = it.parentId, + remotePath = it.remotePath, + owner = it.owner, + permissions = it.permissions, + remoteId = it.remoteId, + privateLink = it.privateLink, + creationTimestamp = it.creationTimestamp, + modifiedTimestamp = it.modifiedTimestamp, + etag = it.etag, + mimeType = it.mimeType, + length = it.length + ) + } +} \ No newline at end of file diff --git a/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/mapper/RemoteFileMapper.kt b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/mapper/RemoteFileMapper.kt new file mode 100644 index 00000000000..2e20e6e8d0c --- /dev/null +++ b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/mapper/RemoteFileMapper.kt @@ -0,0 +1,45 @@ +/** + * ownCloud Android client application + * + * @author Abel García de Prada + * Copyright (C) 2020 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.data.files.datasources.mapper + +import com.owncloud.android.domain.files.model.OCFile +import com.owncloud.android.domain.mappers.RemoteMapper +import com.owncloud.android.lib.resources.files.RemoteFile + +class RemoteFileMapper : RemoteMapper { + override fun toModel(remote: RemoteFile?): OCFile? = + remote?.let { + OCFile( + owner = it.owner, + remoteId = it.remoteId, + remotePath = it.remotePath, + length = it.length, + creationTimestamp = it.creationTimestamp, + modifiedTimestamp = it.modifiedTimestamp, + mimeType = it.mimeType, + etag = it.etag, + permissions = it.permissions, + privateLink = it.privateLink + ) + } + + // Not needed + override fun toRemote(model: OCFile?): RemoteFile? = null + +} diff --git a/owncloudData/src/main/java/com/owncloud/android/data/files/db/FileDao.kt b/owncloudData/src/main/java/com/owncloud/android/data/files/db/FileDao.kt new file mode 100644 index 00000000000..b2bbce7be82 --- /dev/null +++ b/owncloudData/src/main/java/com/owncloud/android/data/files/db/FileDao.kt @@ -0,0 +1,83 @@ +/** + * ownCloud Android client application + * + * @author Abel García de Prada + * Copyright (C) 2020 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.data.files.db + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Transaction +import com.owncloud.android.data.ProviderMeta + +@Dao +abstract class FileDao { + + companion object { + private const val SELECT_FILE_WITH_ID = + "SELECT * " + + "FROM ${ProviderMeta.ProviderTableMeta.FILES_TABLE_NAME} " + + "WHERE id = :id" + + private const val SELECT_FILE_FROM_OWNER_WITH_REMOTE_ID = + "SELECT * " + + "FROM ${ProviderMeta.ProviderTableMeta.FILES_TABLE_NAME} " + + "WHERE owner = :owner " + + "AND remoteId = :remoteId" + + private const val DELETE_FILE_WITH_ID = + "DELETE FROM ${ProviderMeta.ProviderTableMeta.FILES_TABLE_NAME} " + + "WHERE id = :id" + } + + @Query(SELECT_FILE_WITH_ID) + abstract fun getFileWithId( + id: Long + ): OCFileEntity? + + @Query(SELECT_FILE_FROM_OWNER_WITH_REMOTE_ID) + abstract fun getFileFromOwnerAndRemoteId( + owner: String, + remoteId: String + ): OCFileEntity? + + @Insert(onConflict = OnConflictStrategy.REPLACE) + abstract fun insert(ocFileEntity: OCFileEntity): Long + + @Transaction + open fun mergeRemoteAndLocalFile( + ocFileEntity: OCFileEntity + ): Long { + val localFile: OCFileEntity? = getFileFromOwnerAndRemoteId( + owner = ocFileEntity.owner, + remoteId = ocFileEntity.remoteId + ) + if (localFile == null) { + return insert(ocFileEntity) + } else { + // TODO: Handle conflicts, we will replace for the moment + return insert(ocFileEntity.apply { + id = localFile.id + parentId = localFile.parentId + }) + } + } + + @Query(DELETE_FILE_WITH_ID) + abstract fun deleteFileWithId(id: Long) +} diff --git a/owncloudData/src/main/java/com/owncloud/android/data/files/db/OCFileEntity.kt b/owncloudData/src/main/java/com/owncloud/android/data/files/db/OCFileEntity.kt new file mode 100644 index 00000000000..ad0b3331fcc --- /dev/null +++ b/owncloudData/src/main/java/com/owncloud/android/data/files/db/OCFileEntity.kt @@ -0,0 +1,48 @@ +/** + * ownCloud Android client application + * + * @author Abel García de Prada + * Copyright (C) 2020 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.data.files.db + +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.owncloud.android.data.ProviderMeta + +@Entity( + tableName = ProviderMeta.ProviderTableMeta.FILES_TABLE_NAME +) +data class OCFileEntity( + var parentId: Long? = null, + val owner: String, + val remotePath: String, + val remoteId: String, + val length: Long, + val creationTimestamp: Long, + val modifiedTimestamp: Long, + val mimeType: String, + val etag: String, + val permissions: String, + val privateLink: String +) { + @PrimaryKey(autoGenerate = true) + var id: Long = 0 + + companion object { + const val PATH_SEPARATOR = "/" + const val ROOT_PATH = PATH_SEPARATOR + } +} diff --git a/owncloudData/src/main/java/com/owncloud/android/data/files/repository/OCFileRepository.kt b/owncloudData/src/main/java/com/owncloud/android/data/files/repository/OCFileRepository.kt index 3425348f6eb..c74363d52e8 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/files/repository/OCFileRepository.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/files/repository/OCFileRepository.kt @@ -19,12 +19,24 @@ package com.owncloud.android.data.files.repository +import com.owncloud.android.data.files.datasources.LocalFileDataSource import com.owncloud.android.data.files.datasources.RemoteFileDataSource import com.owncloud.android.domain.files.FileRepository +import com.owncloud.android.domain.files.model.OCFile class OCFileRepository( - private val remoteFileDataSource: RemoteFileDataSource + private val remoteFileDataSource: RemoteFileDataSource, + private val localFileDataSource: LocalFileDataSource ) : FileRepository { override fun checkPathExistence(path: String, userLogged: Boolean): Boolean = remoteFileDataSource.checkPathExistence(path, userLogged) + + override fun refreshFolder(remotePath: String) { + remoteFileDataSource.refreshFolder(remotePath).also { + localFileDataSource.saveFilesInFolder( + folder = it.first(), + listOfFiles = it.drop(1) + ) + } + } } diff --git a/owncloudData/src/main/java/com/owncloud/android/data/migrations/Migration_32.kt b/owncloudData/src/main/java/com/owncloud/android/data/migrations/Migration_32.kt new file mode 100644 index 00000000000..b2ce786573e --- /dev/null +++ b/owncloudData/src/main/java/com/owncloud/android/data/migrations/Migration_32.kt @@ -0,0 +1,29 @@ +/** + * ownCloud Android client application + * + * @author Abel García de Prada + * Copyright (C) 2020 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.data.migrations + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +val MIGRATION_31_32 = object : Migration(31, 32) { + override fun migrate(database: SupportSQLiteDatabase) { + //Nothing to migrate at the moment + } +} diff --git a/owncloudData/src/test/java/com/owncloud/android/data/file/datasource/OCRemoteFileDataSourceTest.kt b/owncloudData/src/test/java/com/owncloud/android/data/file/datasource/OCRemoteFileDataSourceTest.kt index 03617ec1325..027a4641b7d 100644 --- a/owncloudData/src/test/java/com/owncloud/android/data/file/datasource/OCRemoteFileDataSourceTest.kt +++ b/owncloudData/src/test/java/com/owncloud/android/data/file/datasource/OCRemoteFileDataSourceTest.kt @@ -20,6 +20,7 @@ package com.owncloud.android.data.file.datasource import com.owncloud.android.data.files.datasources.implementation.OCRemoteFileDataSource +import com.owncloud.android.data.files.datasources.mapper.RemoteFileMapper import com.owncloud.android.lib.resources.files.services.implementation.OCFileService import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.testutil.OC_SERVER_INFO @@ -37,10 +38,11 @@ class OCRemoteFileDataSourceTest { private lateinit var ocRemoteFileDataSource: OCRemoteFileDataSource private val ocFileService: OCFileService = mockk() + private val remoteFileMapper = RemoteFileMapper() @Before fun init() { - ocRemoteFileDataSource = OCRemoteFileDataSource(ocFileService) + ocRemoteFileDataSource = OCRemoteFileDataSource(ocFileService, remoteFileMapper) } @Test diff --git a/owncloudData/src/test/java/com/owncloud/android/data/file/repository/OCFileRepositoryTest.kt b/owncloudData/src/test/java/com/owncloud/android/data/file/repository/OCFileRepositoryTest.kt index ae2af1cfc05..70b67b6aaf3 100644 --- a/owncloudData/src/test/java/com/owncloud/android/data/file/repository/OCFileRepositoryTest.kt +++ b/owncloudData/src/test/java/com/owncloud/android/data/file/repository/OCFileRepositoryTest.kt @@ -19,24 +19,29 @@ package com.owncloud.android.data.file.repository -import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import com.owncloud.android.data.files.repository.OCFileRepository +import com.owncloud.android.data.files.datasources.LocalFileDataSource import com.owncloud.android.data.files.datasources.RemoteFileDataSource +import com.owncloud.android.data.files.repository.OCFileRepository import com.owncloud.android.domain.exceptions.NoConnectionWithServerException +import com.owncloud.android.testutil.OC_FILE import com.owncloud.android.testutil.OC_SERVER_INFO import io.mockk.every import io.mockk.mockk import io.mockk.verify -import org.junit.Rule import org.junit.Test class OCFileRepositoryTest { - @Rule - @JvmField - val instantExecutorRule = InstantTaskExecutorRule() private val remoteFileDataSource = mockk(relaxed = true) - private val ocFileRepository: OCFileRepository = OCFileRepository(remoteFileDataSource) + private val localFileDataSource = mockk(relaxed = true) + private val ocFileRepository: OCFileRepository = OCFileRepository(remoteFileDataSource, localFileDataSource) + + private val folderToFetch = OC_FILE + private val listOfFilesRetrieved = listOf( + folderToFetch, + OC_FILE.copy(remoteId = "one"), + OC_FILE.copy(remoteId = "two") + ) @Test fun checkPathExistenceExists() { @@ -51,7 +56,12 @@ class OCFileRepositoryTest { @Test(expected = NoConnectionWithServerException::class) fun checkPathExistenceExistsNoConnection() { - every { remoteFileDataSource.checkPathExistence(OC_SERVER_INFO.baseUrl, false) } throws NoConnectionWithServerException() + every { + remoteFileDataSource.checkPathExistence( + OC_SERVER_INFO.baseUrl, + false + ) + } throws NoConnectionWithServerException() ocFileRepository.checkPathExistence(OC_SERVER_INFO.baseUrl, false) @@ -59,4 +69,37 @@ class OCFileRepositoryTest { remoteFileDataSource.checkPathExistence(OC_SERVER_INFO.baseUrl, false) } } + + @Test + fun refreshFolderOk() { + every { + remoteFileDataSource.refreshFolder(folderToFetch.remotePath) + } returns listOfFilesRetrieved + + ocFileRepository.refreshFolder(folderToFetch.remotePath) + + verify(exactly = 1) { + remoteFileDataSource.refreshFolder(folderToFetch.remotePath) + localFileDataSource.saveFilesInFolder( + listOfFiles = listOfFilesRetrieved.drop(1), + folder = listOfFilesRetrieved.first() + ) + } + } + + @Test(expected = NoConnectionWithServerException::class) + fun refreshFolderNoConnection() { + every { + remoteFileDataSource.refreshFolder(folderToFetch.remotePath) + } throws NoConnectionWithServerException() + + ocFileRepository.refreshFolder(folderToFetch.remotePath) + + verify(exactly = 1) { + remoteFileDataSource.refreshFolder(OC_FILE.remotePath) + } + verify(exactly = 0) { + localFileDataSource.saveFilesInFolder(any(), any()) + } + } } diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/files/FileRepository.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/files/FileRepository.kt index 249b3bcbeca..9121e3fd3bb 100644 --- a/owncloudDomain/src/main/java/com/owncloud/android/domain/files/FileRepository.kt +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/files/FileRepository.kt @@ -19,6 +19,10 @@ package com.owncloud.android.domain.files +import com.owncloud.android.domain.files.model.OCFile + interface FileRepository { fun checkPathExistence(path: String, userLogged: Boolean): Boolean + + fun refreshFolder(remotePath: String) } diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/files/RefreshFolderFromServerAsyncUseCase.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/files/RefreshFolderFromServerAsyncUseCase.kt new file mode 100644 index 00000000000..9f913b6abb4 --- /dev/null +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/files/RefreshFolderFromServerAsyncUseCase.kt @@ -0,0 +1,31 @@ +/** + * ownCloud Android client application + * + * @author Abel García de Prada + * Copyright (C) 2020 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.domain.files + +import com.owncloud.android.domain.BaseUseCaseWithResult +import com.owncloud.android.domain.files.model.OCFile + +class RefreshFolderFromServerAsyncUseCase( + private val fileRepository: FileRepository +) : BaseUseCaseWithResult() { + override fun run(params: Params) = fileRepository.refreshFolder(params.remotePath) + + data class Params(val remotePath: String) + +} diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/files/model/OCFile.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/files/model/OCFile.kt new file mode 100644 index 00000000000..22e53c8e7db --- /dev/null +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/files/model/OCFile.kt @@ -0,0 +1,47 @@ +/** + * ownCloud Android client application + * + * @author David González Verdugo + * @author Abel García de Prada + * Copyright (C) 2020 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.owncloud.android.domain.files.model + +import android.os.Parcelable +import kotlinx.android.parcel.Parcelize + +//TODO: Add new attributes on demand. Let's try to perform a clean up :) +@Parcelize +data class OCFile( + val id: Long? = null, + val parentId: Long? = null, + val owner: String, + val length: Long, + val creationTimestamp: Long, + val modifiedTimestamp: Long, + val remotePath: String, + val mimeType: String, + val etag: String, + val permissions: String, + val remoteId: String, + val privateLink: String +) : Parcelable { + + companion object { + const val PATH_SEPARATOR = "/" + const val ROOT_PATH = PATH_SEPARATOR + } +} diff --git a/owncloudDomain/src/test/java/com/owncloud/android/domain/files/model/OCFileTest.kt b/owncloudDomain/src/test/java/com/owncloud/android/domain/files/model/OCFileTest.kt new file mode 100644 index 00000000000..a9e8f9da17d --- /dev/null +++ b/owncloudDomain/src/test/java/com/owncloud/android/domain/files/model/OCFileTest.kt @@ -0,0 +1,99 @@ +/** + * ownCloud Android client application + * + * @author Abel García de Prada + * Copyright (C) 2020 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.domain.files.model + +import com.owncloud.android.testutil.OC_ACCOUNT_NAME +import org.junit.Assert +import org.junit.Test + +class OCFileTest { + + @Test + fun testEqualsOk() { + val item1 = OCFile( + 122, + 123, + OC_ACCOUNT_NAME, + 123123123, + 0, + 1593510589000, + "/Photos", + "DIR", + "5efb0c13c688f", + "RDNVCK", + "00000003oci9p7er2hay", + "http://server.url/f/3" + ) + + val item2 = OCFile( + id = 122, + parentId = 123, + remotePath = "/Photos", + owner = OC_ACCOUNT_NAME, + permissions = "RDNVCK", + remoteId = "00000003oci9p7er2hay", + privateLink = "http://server.url/f/3", + creationTimestamp = 0, + modifiedTimestamp = 1593510589000, + etag = "5efb0c13c688f", + mimeType = "DIR", + length = 123123123 + ) + + + Assert.assertTrue(item1 == item2) + Assert.assertFalse(item1 === item2) + } + + @Test + fun testEqualsKo() { + val item1 = OCFile( + 123, + 122, + OC_ACCOUNT_NAME, + 123123123, + 0, + 1593510589000, + "/Photos", + "DIR", + "5efb0c13c688f", + "RDNVCK", + "00000003oci9p7er2hay", + "http://server.url/f/3" + ) + + val item2 = OCFile( + id = 122, + parentId = 123, + remotePath = "/Photos", + owner = OC_ACCOUNT_NAME, + permissions = "RDNVCK", + remoteId = "00000003oci9p7er2hay", + privateLink = "http://server.url/f/3", + creationTimestamp = 0, + modifiedTimestamp = 1593510589000, + etag = "5efb0c13c688f", + mimeType = "DIR", + length = 123123123 + ) + + Assert.assertFalse(item1 == item2) + Assert.assertFalse(item1 === item2) + } +} diff --git a/owncloudDomain/src/test/java/com/owncloud/android/domain/files/usecases/RefreshFolderFromServerAsyncUseCaseTest.kt b/owncloudDomain/src/test/java/com/owncloud/android/domain/files/usecases/RefreshFolderFromServerAsyncUseCaseTest.kt new file mode 100644 index 00000000000..57d3e28d76c --- /dev/null +++ b/owncloudDomain/src/test/java/com/owncloud/android/domain/files/usecases/RefreshFolderFromServerAsyncUseCaseTest.kt @@ -0,0 +1,60 @@ +/** + * ownCloud Android client application + * + * @author Abel García de Prada + * Copyright (C) 2020 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.domain.files.usecases + +import com.owncloud.android.domain.exceptions.UnauthorizedException +import com.owncloud.android.domain.files.FileRepository +import com.owncloud.android.domain.files.RefreshFolderFromServerAsyncUseCase +import io.mockk.every +import io.mockk.spyk +import io.mockk.verify +import org.junit.Assert +import org.junit.Test + +class RefreshFolderFromServerAsyncUseCaseTest { + private val fileRepository: FileRepository = spyk() + private val useCase = RefreshFolderFromServerAsyncUseCase(fileRepository) + private val useCaseParams = RefreshFolderFromServerAsyncUseCase.Params("/Photos") + + @Test + fun refreshFolderFromServerOk() { + val useCaseResult = useCase.execute(useCaseParams) + + Assert.assertTrue(useCaseResult.isSuccess) + Assert.assertFalse(useCaseResult.isError) + Assert.assertEquals(Unit, useCaseResult.getDataOrNull()) + + verify(exactly = 1) { fileRepository.refreshFolder(useCaseParams.remotePath) } + } + + @Test + fun refreshCapabilitiesFromServerWithUnauthorizedException() { + every { fileRepository.refreshFolder(any()) } throws UnauthorizedException() + + val useCaseResult = useCase.execute(useCaseParams) + + Assert.assertFalse(useCaseResult.isSuccess) + Assert.assertTrue(useCaseResult.isError) + + Assert.assertNull(useCaseResult.getDataOrNull()) + Assert.assertTrue(useCaseResult.getThrowableOrNull() is UnauthorizedException) + + verify(exactly = 1) { fileRepository.refreshFolder(useCaseParams.remotePath) } + } +} \ No newline at end of file diff --git a/owncloudTestUtil/src/main/java/com/owncloud/android/testutil/OCFile.kt b/owncloudTestUtil/src/main/java/com/owncloud/android/testutil/OCFile.kt new file mode 100644 index 00000000000..8d4cb51a812 --- /dev/null +++ b/owncloudTestUtil/src/main/java/com/owncloud/android/testutil/OCFile.kt @@ -0,0 +1,36 @@ +/** + * ownCloud Android client application + * + * @author Abel García de Prada + * Copyright (C) 2020 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.testutil + +import com.owncloud.android.domain.files.model.OCFile + +val OC_FILE = OCFile( + id = 122, + parentId = 123, + remotePath = "/Photos", + owner = OC_ACCOUNT_NAME, + permissions = "RDNVCK", + remoteId = "00000003oci9p7er2hay", + privateLink = "http://server.url/f/3", + creationTimestamp = 0, + modifiedTimestamp = 1593510589000, + etag = "5efb0c13c688f", + mimeType = "DIR", + length = 123123123 +) diff --git a/owncloudTestUtil/src/main/java/com/owncloud/android/testutil/OCServerInfo.kt b/owncloudTestUtil/src/main/java/com/owncloud/android/testutil/OCServerInfo.kt index 4a615bca124..2f33de6ce21 100644 --- a/owncloudTestUtil/src/main/java/com/owncloud/android/testutil/OCServerInfo.kt +++ b/owncloudTestUtil/src/main/java/com/owncloud/android/testutil/OCServerInfo.kt @@ -1,3 +1,21 @@ +/** + * ownCloud Android client application + * + * @author Abel García de Prada + * Copyright (C) 2020 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.owncloud.android.testutil import com.owncloud.android.domain.server.model.AuthenticationMethod