Skip to content

Commit f96bab9

Browse files
Merge pull request #16810 from nextcloud/fix/shared-file-list-metadata
fix(share-list-fragment): overriding metadata with wrong values
2 parents d2d8665 + b2bd4e1 commit f96bab9

5 files changed

Lines changed: 97 additions & 67 deletions

File tree

app/src/main/java/com/owncloud/android/ui/adapter/OCShareToOCFileConverter.kt

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import java.io.File
2121

2222
object OCShareToOCFileConverter {
2323
private const val MILLIS_PER_SECOND = 1000
24+
private val LINK_SHARE_TYPES = setOf(ShareType.PUBLIC_LINK, ShareType.EMAIL)
2425

2526
/**
2627
* Generates a list of incomplete [OCFile] from a list of [OCShare]. Retrieving OCFile directly by path may fail
@@ -33,21 +34,21 @@ object OCShareToOCFileConverter {
3334
*
3435
* Note: This works only for files shared *by* the user, not files shared *with* the user.
3536
*/
36-
fun buildOCFilesFromShares(shares: List<OCShare>): List<OCFile> = shares
37+
fun buildOCFilesFromShares(shares: List<OCShare>, storageManager: FileDataStorageManager): List<OCFile> = shares
3738
.filter { !it.path.isNullOrEmpty() }
3839
.groupBy { it.path!! }
3940
.filterKeys { path ->
4041
path.isNotEmpty() && path.startsWith(OCFile.PATH_SEPARATOR)
4142
}
4243
.map { (path, sharesForPath) ->
43-
buildOcFile(path, sharesForPath)
44+
buildOCFile(path, sharesForPath, storageManager)
4445
}
4546
.sortedByDescending { it.firstShareTimestamp }
4647

4748
suspend fun parseAndSaveShares(
4849
cachedFiles: List<OCFile>,
4950
data: List<Any>,
50-
storageManager: FileDataStorageManager?,
51+
storageManager: FileDataStorageManager,
5152
accountName: String
5253
): List<OCFile> = withContext(Dispatchers.IO) {
5354
if (data.isEmpty()) {
@@ -67,7 +68,7 @@ object OCShareToOCFileConverter {
6768
return@withContext cachedFiles
6869
}
6970

70-
val files = buildOCFilesFromShares(newShares)
71+
val files = buildOCFilesFromShares(newShares, storageManager)
7172
val baseSavePath = FileStorageUtils.getSavePath(accountName)
7273

7374
val newFiles = files.map { file ->
@@ -79,49 +80,49 @@ object OCShareToOCFileConverter {
7980
file.lastSyncDateForData = candidate.lastModified()
8081
}
8182
}
82-
storageManager?.saveFile(file)
83+
storageManager.saveFile(file)
8384
file
8485
}
8586

86-
storageManager?.saveShares(newShares, accountName)
87+
storageManager.saveShares(newShares, accountName)
8788
(cachedFiles + newFiles).distinctBy { it.remotePath }
8889
}
8990

90-
private fun buildOcFile(path: String, shares: List<OCShare>): OCFile {
91+
private fun buildOCFile(path: String, shares: List<OCShare>, storageManager: FileDataStorageManager): OCFile {
9192
require(shares.all { it.path == path })
92-
// common attributes
93+
9394
val firstShare = shares.first()
94-
val file = OCFile(path).apply {
95-
decryptedRemotePath = path
96-
ownerId = firstShare.userId
97-
ownerDisplayName = firstShare.ownerDisplayName
98-
isPreviewAvailable = firstShare.isHasPreview
99-
mimeType = firstShare.mimetype
100-
note = firstShare.note
101-
fileId = firstShare.fileSource
102-
remoteId = firstShare.remoteId.toString()
103-
// use first share timestamp as timestamp
104-
firstShareTimestamp = shares.minOf { it.sharedDate * MILLIS_PER_SECOND }
105-
// don't have file length or mod timestamp
106-
fileLength = -1
107-
modificationTimestamp = -1
108-
isFavorite = firstShare.isFavorite
109-
}
110-
if (shares.any { it.shareType in listOf(ShareType.PUBLIC_LINK, ShareType.EMAIL) }) {
111-
file.isSharedViaLink = true
112-
}
113-
if (shares.any { it.shareType !in listOf(ShareType.PUBLIC_LINK, ShareType.EMAIL) }) {
114-
file.isSharedWithSharee = true
115-
file.sharees = shares
116-
.filter { it.shareType != ShareType.PUBLIC_LINK && it.shareType != ShareType.EMAIL }
117-
.map {
118-
ShareeUser(
119-
userId = it.userId,
120-
displayName = it.sharedWithDisplayName,
121-
shareType = it.shareType
122-
)
123-
}
124-
}
95+
val firstShareTimestamp = shares.minOf { it.sharedDate * MILLIS_PER_SECOND }
96+
97+
val linkShares = shares.filter { it.shareType in LINK_SHARE_TYPES }
98+
val userShares = shares.filter { it.shareType !in LINK_SHARE_TYPES }
99+
100+
val file = (storageManager.getFileByDecryptedRemotePath(path) ?: newOCFile(path))
101+
102+
file.applyShareData(firstShare, firstShareTimestamp)
103+
104+
file.isSharedViaLink = linkShares.isNotEmpty()
105+
file.isSharedWithSharee = userShares.isNotEmpty()
106+
file.sharees = userShares.map { ShareeUser(it.userId, it.sharedWithDisplayName, it.shareType) }
107+
125108
return file
126109
}
110+
111+
private fun newOCFile(path: String) = OCFile(path).also {
112+
it.decryptedRemotePath = path
113+
it.fileLength = -1
114+
it.modificationTimestamp = -1
115+
}
116+
117+
private fun OCFile.applyShareData(firstShare: OCShare, firstShareTimestamp: Long) = apply {
118+
ownerId = firstShare.userId
119+
ownerDisplayName = firstShare.ownerDisplayName
120+
isPreviewAvailable = firstShare.isHasPreview
121+
mimeType = firstShare.mimetype
122+
note = firstShare.note
123+
fileId = firstShare.fileSource
124+
remoteId = firstShare.remoteId.toString()
125+
this.firstShareTimestamp = firstShareTimestamp
126+
isFavorite = firstShare.isFavorite
127+
}
127128
}

app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1970,7 +1970,17 @@ protected void handleSearchEvent(SearchEvent event) {
19701970
remoteOperation = getSearchRemoteOperation(currentUser, event);
19711971
}
19721972

1973-
searchTask = new OCFileListSearchTask(mContainerActivity, this, remoteOperation, currentUser, event, SharedListFragment.TASK_TIMEOUT, preferences);
1973+
var storageManager = mContainerActivity.getStorageManager();
1974+
if (storageManager == null) {
1975+
storageManager = new FileDataStorageManager(currentUser, requireContext().getContentResolver());
1976+
}
1977+
1978+
searchTask = new OCFileListSearchTask(this,
1979+
remoteOperation,
1980+
currentUser, event,
1981+
SharedListFragment.TASK_TIMEOUT,
1982+
preferences,
1983+
storageManager);
19741984
searchTask.execute();
19751985
}
19761986

app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,24 +44,19 @@ import java.lang.ref.WeakReference
4444
@Suppress("LongParameterList", "ReturnCount", "TooGenericExceptionCaught")
4545
@SuppressLint("NotifyDataSetChanged")
4646
class OCFileListSearchTask(
47-
containerActivity: FileFragment.ContainerActivity,
4847
fragment: OCFileListFragment,
4948
private val remoteOperation: RemoteOperation<List<Any>>,
5049
private val currentUser: User,
5150
private val event: SearchEvent,
5251
private val taskTimeout: Long,
53-
private val preferences: AppPreferences
52+
private val preferences: AppPreferences,
53+
private val storageManager: FileDataStorageManager
5454
) {
5555
companion object {
5656
private const val TAG = "OCFileListSearchTask"
5757
}
5858

59-
private val activityReference: WeakReference<FileFragment.ContainerActivity> = WeakReference(containerActivity)
6059
private val fragmentReference: WeakReference<OCFileListFragment> = WeakReference(fragment)
61-
62-
private val fileDataStorageManager: FileDataStorageManager?
63-
get() = activityReference.get()?.storageManager
64-
6560
private var job: Job? = null
6661

6762
@Suppress("TooGenericExceptionCaught", "DEPRECATION", "ReturnCount")
@@ -91,13 +86,13 @@ class OCFileListSearchTask(
9186
return@launch
9287
}
9388

94-
fragment.adapter.prepareForSearchData(fileDataStorageManager, fragment.currentSearchType)
89+
fragment.adapter.prepareForSearchData(storageManager, fragment.currentSearchType)
9590

9691
val newList = if (searchType == SearchType.SHARED_FILTER) {
9792
OCShareToOCFileConverter.parseAndSaveShares(
9893
sortedFilesInDb,
9994
result.resultData ?: listOf(),
100-
fileDataStorageManager,
95+
storageManager,
10196
currentUser.accountName
10297
)
10398
} else {
@@ -126,16 +121,14 @@ class OCFileListSearchTask(
126121

127122
fun isFinished(): Boolean = job?.isCompleted == true
128123

129-
private suspend fun loadCachedDbFiles(searchType: SearchRemoteOperation.SearchType): List<OCFile> {
130-
val storage = fileDataStorageManager ?: return emptyList()
131-
return if (searchType == SearchRemoteOperation.SearchType.SHARED_FILTER) {
132-
storage.fileDao
124+
private suspend fun loadCachedDbFiles(searchType: SearchRemoteOperation.SearchType): List<OCFile> =
125+
if (searchType == SearchRemoteOperation.SearchType.SHARED_FILTER) {
126+
storageManager.fileDao
133127
.getSharedFiles(currentUser.accountName)
134128
} else {
135-
storage.fileDao
129+
storageManager.fileDao
136130
.getFavoriteFiles(currentUser.accountName)
137-
}.mapNotNull { storage.createFileInstance(it) }
138-
}
131+
}.mapNotNull { storageManager.createFileInstance(it) }
139132

140133
@Suppress("DEPRECATION")
141134
private suspend fun fetchRemoteResults(): RemoteOperationResult<List<Any>>? {
@@ -202,7 +195,6 @@ class OCFileListSearchTask(
202195
@Suppress("DEPRECATION")
203196
private suspend fun parseAndSaveVirtuals(data: List<Any>, fragment: OCFileListFragment) =
204197
withContext(Dispatchers.IO) {
205-
val fileDataStorageManager = fileDataStorageManager ?: return@withContext
206198
val activity = fragment.activity ?: return@withContext
207199
val now = System.currentTimeMillis()
208200

@@ -219,16 +211,16 @@ class OCFileListSearchTask(
219211
val remoteFile = obj as? RemoteFile ?: continue
220212
var ocFile = FileStorageUtils.fillOCFile(remoteFile)
221213
FileStorageUtils.searchForLocalFileInDefaultPath(ocFile, currentUser.accountName)
222-
ocFile = fileDataStorageManager.saveFileWithParent(ocFile, activity)
223-
ocFile = handleEncryptionIfNeeded(ocFile, fileDataStorageManager, activity)
214+
ocFile = storageManager.saveFileWithParent(ocFile, activity)
215+
ocFile = handleEncryptionIfNeeded(ocFile, storageManager, activity)
224216

225217
if (fragment.currentSearchType != SearchType.GALLERY_SEARCH && ocFile.isFolder) {
226218
RefreshFolderOperation(
227219
ocFile,
228220
now,
229221
true,
230222
false,
231-
fileDataStorageManager,
223+
storageManager,
232224
currentUser,
233225
activity
234226
).execute(currentUser, activity)
@@ -253,7 +245,7 @@ class OCFileListSearchTask(
253245

254246
// Save timestamp + virtual entries
255247
preferences.setPhotoSearchTimestamp(System.currentTimeMillis())
256-
fileDataStorageManager.saveVirtuals(contentValuesList)
248+
storageManager.saveVirtuals(contentValuesList)
257249
}
258250

259251
@Suppress("DEPRECATION")

app/src/main/java/com/owncloud/android/ui/fragment/SharedListFragment.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,12 @@ class SharedListFragment :
7575
val fetchResult = ReadFileRemoteOperation(partialFile.remotePath).execute(user, context)
7676
if (fetchResult.isSuccess) {
7777
val remoteFile = (fetchResult.data[0] as RemoteFile).apply {
78-
val prevETag = mContainerActivity.storageManager.getFileByDecryptedRemotePath(remotePath)
78+
val existingFile = mContainerActivity.storageManager.getFileByDecryptedRemotePath(remotePath)
7979

8080
// Use previous eTag if exists to prevent break checkForChanges logic in RefreshFolderOperation.
8181
// Otherwise RefreshFolderOperation will show empty list
82-
prevETag?.etag?.let {
83-
etag = prevETag.etag
82+
existingFile?.etag?.let {
83+
etag = it
8484
}
8585
}
8686
val file = FileStorageUtils.fillOCFile(remoteFile)

app/src/test/java/com/owncloud/android/ui/adapter/OCShareToOCFileConverterTest.kt

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,40 @@
77
*/
88
package com.owncloud.android.ui.adapter
99

10+
import com.owncloud.android.datamodel.FileDataStorageManager
1011
import com.owncloud.android.lib.resources.shares.OCShare
1112
import com.owncloud.android.lib.resources.shares.ShareType
13+
import com.owncloud.android.ui.activity.ComponentsGetter
14+
import org.junit.After
1215
import org.junit.Assert.assertEquals
16+
import org.junit.Before
1317
import org.junit.Test
18+
import org.mockito.Mock
19+
import org.mockito.MockitoAnnotations
20+
import org.mockito.kotlin.doReturn
21+
import org.mockito.kotlin.whenever
1422

1523
class OCShareToOCFileConverterTest {
1624

25+
@Mock
26+
lateinit var storageManager: FileDataStorageManager
27+
28+
@Mock
29+
lateinit var transferServiceGetter: ComponentsGetter
30+
31+
private lateinit var mocks: AutoCloseable
32+
33+
@Before
34+
fun setUpMocks() {
35+
mocks = MockitoAnnotations.openMocks(this)
36+
whenever(transferServiceGetter.storageManager) doReturn storageManager
37+
}
38+
39+
@After
40+
fun tearDownMocks() {
41+
mocks.close()
42+
}
43+
1744
@Test
1845
fun testSingleOCShare() {
1946
val shares = listOf(
@@ -24,7 +51,7 @@ class OCShareToOCFileConverterTest {
2451
}
2552
)
2653

27-
val result = OCShareToOCFileConverter.buildOCFilesFromShares(shares)
54+
val result = OCShareToOCFileConverter.buildOCFilesFromShares(shares, storageManager)
2855

2956
assertEquals("Wrong file list size", 1, result.size)
3057
val ocFile = result[0]
@@ -56,7 +83,7 @@ class OCShareToOCFileConverterTest {
5683
}
5784
)
5885

59-
val result = OCShareToOCFileConverter.buildOCFilesFromShares(shares)
86+
val result = OCShareToOCFileConverter.buildOCFilesFromShares(shares, storageManager)
6087

6188
assertEquals("Wrong file list size", 1, result.size)
6289
val ocFile = result[0]
@@ -99,7 +126,7 @@ class OCShareToOCFileConverterTest {
99126
}
100127
)
101128

102-
val result = OCShareToOCFileConverter.buildOCFilesFromShares(shares)
129+
val result = OCShareToOCFileConverter.buildOCFilesFromShares(shares, storageManager)
103130

104131
assertEquals("Wrong file list size", 2, result.size)
105132

0 commit comments

Comments
 (0)