Skip to content

Commit

Permalink
updatePathsIfParentPathMatches
Browse files Browse the repository at this point in the history
Signed-off-by: alperozturk <[email protected]>
  • Loading branch information
alperozturk96 committed Aug 22, 2024
1 parent 8e37c1d commit 14e6b75
Show file tree
Hide file tree
Showing 7 changed files with 258 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Alper Ozturk <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package com.nextcloud.extensions

import androidx.test.ext.junit.runners.AndroidJUnit4
import com.nextcloud.client.database.entity.OfflineOperationEntity
import com.nextcloud.utils.extensions.getParentPathFromPath
import com.nextcloud.utils.extensions.updatePath
import com.nextcloud.utils.extensions.updatePathsIfParentPathMatches
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class OfflineOperationExtensionTests {

/*
private val entity = OfflineOperationEntity(
1,
null,
null,
OfflineOperationType.CreateFolder,
"/Folder/Folder2/Folder3/",
"Folder",
null
)
@Test
fun testGetParentPathFromPath() {
assert(entity.getParentPathFromPath() == "/Folder/")
}
@Test
fun testUpdatePath() {
assert(entity.updatePath("/MaxPa/") == "/MaxPa/Folder2/Folder3/")
}
@Test
fun testUpdatePathsIfParentPathMatches() {
entity.path = "/MaxPa/Folder2/Folder3/"
val oldPath = "/Folder/Folder2/Folder3/"
assert(entity.updatePathsIfParentPathMatches(oldPath, "/MaxPa/") == "/MaxPa/Folder2/Folder3/")
}
*/

@Test
fun testUpdatePathsIfParentPathMatches() {
val entity1 = OfflineOperationEntity(path = "/abc/def/file1/")
val entity2 = OfflineOperationEntity(path = "/xyz/file2/")

val updatedPath1 = entity1.updatePathsIfParentPathMatches(entity1.path, "/newAbc/")
val updatedPath2 = entity2.updatePathsIfParentPathMatches(entity2.path, "/newAbc/")

assertEquals("/newAbc/def/file1/", updatedPath1)
assertEquals("/newAbc/file2/", updatedPath2)
}

@Test
fun testUpdatePathsIfParentPathMatchesWithNullInputs() {
val entity = OfflineOperationEntity(path = "/abc/def/file/")

val result1 = entity.updatePathsIfParentPathMatches(null, "/newPath/")
val result2 = entity.updatePathsIfParentPathMatches("/oldPath/", null)

assertNull(result1)
assertNull(result2)
}

@Test
fun testUpdatePath() {
val entity = OfflineOperationEntity(path = "/abc/def/file/")
val newPath = entity.updatePath("/newAbc/")
assertEquals("/newAbc/def/file/", newPath)
}

@Test
fun testUpdatePathWithNullInput() {
val entity = OfflineOperationEntity(path = "/abc/def/file/")
val newPath = entity.updatePath(null)
assertNull(newPath)
}

@Test
fun testGetParentPathFromPath() {
val entity = OfflineOperationEntity(path = "/abc/def/file/")
val parentPath = entity.getParentPathFromPath()
assertEquals("/abc/", parentPath)
}

@Test
fun testGetParentPathFromPathWithRootPath() {
val entity = OfflineOperationEntity(path = "/")
val parentPath = entity.getParentPathFromPath()
assertEquals("//", parentPath)
}

@Test
fun testGetParentPathFromPathWithEmptyString() {
val entity = OfflineOperationEntity(path = "")
val parentPath = entity.getParentPathFromPath()
assertEquals("//", parentPath)
}

@Test
fun testGetParentPathFromPathWithNullPath() {
val entity = OfflineOperationEntity(path = null)
val parentPath = entity.getParentPathFromPath()
assertNull(parentPath)
}

@Test
fun testUpdatePathWithEmptyPath() {
val entity = OfflineOperationEntity(path = "")
val newPath = entity.updatePath("/newAbc/")
assertNull(newPath)
}

@Test
fun testUpdatePathsIfParentPathMatchesWithSingleDirectoryPath() {
val entity = OfflineOperationEntity(path = "/abc/")
val updatedPath = entity.updatePathsIfParentPathMatches(entity.path, "/newAbc/")
assertEquals("/newAbc/", updatedPath)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ abstract class FileUploaderIT : AbstractOnServerIT() {
private var uploadsStorageManager: UploadsStorageManager? = null

private val connectivityServiceMock: ConnectivityService = object : ConnectivityService {
override fun isNetworkAndServerAvailable(): Boolean {
return false
}

override fun isConnected(): Boolean {
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,7 @@ interface OfflineOperationDao {

@Query("SELECT * FROM offline_operations WHERE offline_operations_path = :path LIMIT 1")
fun getByPath(path: String): OfflineOperationEntity?

@Query("UPDATE offline_operations SET offline_operations_parent_path = :parentPath WHERE _id = :id")
fun updateParentPathById(id: Int, parentPath: String)
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,16 @@ class OfflineOperationsWorker(
Log_OC.d(TAG, "$logMessage path: ${operation.path}, type: ${operation.type}")

if (result.isSuccess) {
updateNextOperationsParentPaths(operations, operation)
fileDataStorageManager.offlineOperationDao.delete(operation)
fileDataStorageManager.offlineOperationDao.run {
operation.id?.let { id ->
operation.path?.let { path ->
updateParentPathById(operation.id, path)
}
}

delete(operation)
}

notificationManager.update(operations.size, currentOperationIndex, operation.filename ?: "")
} else {
val excludedErrorCodes = listOf(RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS)
Expand All @@ -125,23 +133,4 @@ class OfflineOperationsWorker(
}
}
}

private fun updateNextOperationsParentPaths(
operations: List<OfflineOperationEntity>,
currentOperation: OfflineOperationEntity
) {
operations.forEach { nextOperation ->
val nextOperationParentPath = getParentPath(nextOperation.path ?: "")
if (nextOperationParentPath == currentOperation.path) {
nextOperation.parentPath = currentOperation.path
fileDataStorageManager.offlineOperationDao.update(nextOperation)
}
}
}

private fun getParentPath(path: String): String {
val trimmedPath = path.trim('/')
val firstDir = trimmedPath.split('/').firstOrNull() ?: ""
return "/$firstDir/"
}
}
24 changes: 24 additions & 0 deletions app/src/main/java/com/nextcloud/utils/extensions/DateExtensions.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Alper Ozturk <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package com.nextcloud.utils.extensions

import android.annotation.SuppressLint
import java.text.SimpleDateFormat
import java.util.Date

enum class DateFormatPattern(val pattern: String) {
/**
* e.g. 10.11.2024 - 12:44
*/
FullDateWithHours("dd.MM.yyyy - HH:mm")
}

@SuppressLint("SimpleDateFormat")
fun Date.currentDateRepresentation(formatPattern: DateFormatPattern): String {
return SimpleDateFormat(formatPattern.pattern).format(this)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Alper Ozturk <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package com.nextcloud.utils.extensions

import com.nextcloud.client.database.dao.OfflineOperationDao
import com.nextcloud.client.database.entity.OfflineOperationEntity

fun OfflineOperationDao.updatePathsIfParentPathMatches(oldPath: String?, newTopDir: String?) {
if (oldPath.isNullOrEmpty() || newTopDir.isNullOrEmpty()) return

getAll().forEach {
val newPath = it.updatePathsIfParentPathMatches(oldPath, newTopDir)
if (newPath != it.path) {

// TODO add parent path so it can upload
it.path = newPath
update(it)
}
}
}

fun OfflineOperationEntity.updatePathsIfParentPathMatches(oldPath: String?, newTopDir: String?): String? {
if (oldPath.isNullOrEmpty() || newTopDir.isNullOrEmpty()) return null

val topDir = getParentPathFromPath()
val oldTopDir = oldPath.getParentPathFromPath()
return if (topDir == oldTopDir) {
updatePath(newTopDir)
} else {
path
}
}

fun OfflineOperationEntity.updatePath(newParentPath: String?): String? {
if (newParentPath.isNullOrEmpty() || path.isNullOrEmpty()) return null

val segments = path!!.trim('/').split('/').toMutableList()

if (segments.size == 1) {
return newParentPath
}

segments.removeAt(0)

return newParentPath + segments.joinToString(separator = "/") + "/"
}

fun OfflineOperationEntity.getParentPathFromPath(): String? {
return path?.getParentPathFromPath()
}

private fun String?.getParentPathFromPath(): String {
val trimmedPath = this?.trim('/')
val firstDir = trimmedPath?.split('/')?.firstOrNull() ?: ""
return "/$firstDir/"
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
import com.nextcloud.client.database.entity.FileEntity;
import com.nextcloud.client.database.entity.OfflineOperationEntity;
import com.nextcloud.model.OfflineOperationType;
import com.nextcloud.utils.extensions.DateExtensionsKt;
import com.nextcloud.utils.extensions.DateFormatPattern;
import com.nextcloud.utils.extensions.OfflineOperationExtensionsKt;
import com.owncloud.android.MainApp;
import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
import com.owncloud.android.lib.common.network.WebdavEntry;
Expand All @@ -65,7 +68,6 @@

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
Expand Down Expand Up @@ -133,7 +135,7 @@ OCFile getFileByDecryptedRemotePath(String path) {
return getFileByPath(ProviderTableMeta.FILE_PATH_DECRYPTED, path);
}

public void addCreateFolderOfflineOperation(String path, String filename, String parentPath, Long parentOCFileId) {
public OfflineOperationEntity addCreateFolderOfflineOperation(String path, String filename, String parentPath, Long parentOCFileId) {
OfflineOperationEntity entity = new OfflineOperationEntity();

entity.setFilename(filename);
Expand All @@ -148,6 +150,8 @@ public void addCreateFolderOfflineOperation(String path, String filename, String
OCFile file = new OCFile(path);
file.setMimeType(MimeType.DIRECTORY);
saveFileWithParent(file, MainApp.getAppContext());

return entity;
}

public void deleteOfflineOperation(OCFile file) {
Expand All @@ -164,13 +168,19 @@ public void renameCreateFolderOfflineOperation(OCFile file, String newFolderName
}

String newPath = parentFolder.getDecryptedRemotePath() + newFolderName + OCFile.PATH_SEPARATOR;
String oldPath = parentFolder.getDecryptedRemotePath() + file.getFileName() + OCFile.PATH_SEPARATOR;

String uploadedParentPath = null;
if (Objects.equals(parentFolder.getRemotePath(), OCFile.PATH_SEPARATOR)) {
uploadedParentPath = OCFile.PATH_SEPARATOR;
}

addCreateFolderOfflineOperation(newPath, newFolderName, uploadedParentPath, file.getParentId());
OfflineOperationEntity entity = addCreateFolderOfflineOperation(newPath, newFolderName, uploadedParentPath, file.getParentId());
String newTopDir = OfflineOperationExtensionsKt.getParentPathFromPath(entity);

if (newTopDir != null) {
OfflineOperationExtensionsKt.updatePathsIfParentPathMatches(offlineOperationDao, oldPath, newTopDir);
}
}

@SuppressLint("SimpleDateFormat")
Expand All @@ -181,16 +191,25 @@ public void keepOfflineOperationAndServerFile(OfflineOperationEntity entity) {
OCFile parentFolder = getFileById(parentOCFileId);
if (parentFolder == null) return;

SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy - HH:mm");
String currentDateTime = sdf.format(new Date());
DateFormatPattern formatPattern = DateFormatPattern.FullDateWithHours;
String currentDateTime = DateExtensionsKt.currentDateRepresentation(new Date(), formatPattern);

// Update path
String newFolderName = entity.getFilename() + " - " + currentDateTime;
String newPath = parentFolder.getDecryptedRemotePath() + newFolderName + OCFile.PATH_SEPARATOR;
String oldPath = entity.getPath();

entity.setPath(newPath);
entity.setFilename(newFolderName);

offlineOperationDao.update(entity);

String newTopDir = OfflineOperationExtensionsKt.getParentPathFromPath(entity);

if (newTopDir != null && oldPath != null) {
OfflineOperationExtensionsKt.updatePathsIfParentPathMatches(offlineOperationDao, oldPath, newTopDir);
}

// Update local DB
OCFile file = new OCFile(entity.getPath());
file.setMimeType(MimeType.DIRECTORY);
saveFileWithParent(file, MainApp.getAppContext());
Expand Down

0 comments on commit 14e6b75

Please sign in to comment.