Skip to content

Commit 1ade346

Browse files
Merge pull request #14412 from nextcloud/feature/file_download_limits
Support Files Download Limits
2 parents a32e4c6 + a3ab2f4 commit 1ade346

23 files changed

Lines changed: 719 additions & 203 deletions

app/schemas/com.nextcloud.client.database.NextcloudDatabase/86.json

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"formatVersion": 1,
33
"database": {
44
"version": 86,
5-
"identityHash": "a657c5557784ebaff12f7709fc3fd6dd",
5+
"identityHash": "277489b9d4a6ee84f96d09dea39591ba",
66
"entities": [
77
{
88
"tableName": "arbitrary_data",
@@ -44,7 +44,7 @@
4444
},
4545
{
4646
"tableName": "capabilities",
47-
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `assistant` INTEGER, `account` TEXT, `version_mayor` INTEGER, `version_minor` INTEGER, `version_micro` INTEGER, `version_string` TEXT, `version_edition` TEXT, `extended_support` INTEGER, `core_pollinterval` INTEGER, `sharing_api_enabled` INTEGER, `sharing_public_enabled` INTEGER, `sharing_public_password_enforced` INTEGER, `sharing_public_expire_date_enabled` INTEGER, `sharing_public_expire_date_days` INTEGER, `sharing_public_expire_date_enforced` INTEGER, `sharing_public_send_mail` INTEGER, `sharing_public_upload` INTEGER, `sharing_user_send_mail` INTEGER, `sharing_resharing` INTEGER, `sharing_federation_outgoing` INTEGER, `sharing_federation_incoming` INTEGER, `files_bigfilechunking` INTEGER, `files_undelete` INTEGER, `files_versioning` INTEGER, `external_links` INTEGER, `server_name` TEXT, `server_color` TEXT, `server_text_color` TEXT, `server_element_color` TEXT, `server_slogan` TEXT, `server_logo` TEXT, `background_url` TEXT, `end_to_end_encryption` INTEGER, `end_to_end_encryption_keys_exist` INTEGER, `end_to_end_encryption_api_version` TEXT, `activity` INTEGER, `background_default` INTEGER, `background_plain` INTEGER, `richdocument` INTEGER, `richdocument_mimetype_list` TEXT, `richdocument_direct_editing` INTEGER, `richdocument_direct_templates` INTEGER, `richdocument_optional_mimetype_list` TEXT, `sharing_public_ask_for_optional_password` INTEGER, `richdocument_product_name` TEXT, `direct_editing_etag` TEXT, `user_status` INTEGER, `user_status_supports_emoji` INTEGER, `etag` TEXT, `files_locking_version` TEXT, `groupfolders` INTEGER, `drop_account` INTEGER, `security_guard` INTEGER, `forbidden_filename_characters` INTEGER, `forbidden_filenames` INTEGER, `forbidden_filename_extensions` INTEGER, `forbidden_filename_basenames` INTEGER, `recommendation` INTEGER)",
47+
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `assistant` INTEGER, `account` TEXT, `version_mayor` INTEGER, `version_minor` INTEGER, `version_micro` INTEGER, `version_string` TEXT, `version_edition` TEXT, `extended_support` INTEGER, `core_pollinterval` INTEGER, `sharing_api_enabled` INTEGER, `sharing_public_enabled` INTEGER, `sharing_public_password_enforced` INTEGER, `sharing_public_expire_date_enabled` INTEGER, `sharing_public_expire_date_days` INTEGER, `sharing_public_expire_date_enforced` INTEGER, `sharing_public_send_mail` INTEGER, `sharing_public_upload` INTEGER, `sharing_user_send_mail` INTEGER, `sharing_resharing` INTEGER, `sharing_federation_outgoing` INTEGER, `sharing_federation_incoming` INTEGER, `files_bigfilechunking` INTEGER, `files_undelete` INTEGER, `files_versioning` INTEGER, `external_links` INTEGER, `server_name` TEXT, `server_color` TEXT, `server_text_color` TEXT, `server_element_color` TEXT, `server_slogan` TEXT, `server_logo` TEXT, `background_url` TEXT, `end_to_end_encryption` INTEGER, `end_to_end_encryption_keys_exist` INTEGER, `end_to_end_encryption_api_version` TEXT, `activity` INTEGER, `background_default` INTEGER, `background_plain` INTEGER, `richdocument` INTEGER, `richdocument_mimetype_list` TEXT, `richdocument_direct_editing` INTEGER, `richdocument_direct_templates` INTEGER, `richdocument_optional_mimetype_list` TEXT, `sharing_public_ask_for_optional_password` INTEGER, `richdocument_product_name` TEXT, `direct_editing_etag` TEXT, `user_status` INTEGER, `user_status_supports_emoji` INTEGER, `etag` TEXT, `files_locking_version` TEXT, `groupfolders` INTEGER, `drop_account` INTEGER, `security_guard` INTEGER, `forbidden_filename_characters` INTEGER, `forbidden_filenames` INTEGER, `forbidden_filename_extensions` INTEGER, `forbidden_filename_basenames` INTEGER, `files_download_limit` INTEGER, `files_download_limit_default` INTEGER, `recommendation` INTEGER)",
4848
"fields": [
4949
{
5050
"fieldPath": "id",
@@ -394,6 +394,18 @@
394394
"affinity": "INTEGER",
395395
"notNull": false
396396
},
397+
{
398+
"fieldPath": "filesDownloadLimit",
399+
"columnName": "files_download_limit",
400+
"affinity": "INTEGER",
401+
"notNull": false
402+
},
403+
{
404+
"fieldPath": "filesDownloadLimitDefault",
405+
"columnName": "files_download_limit_default",
406+
"affinity": "INTEGER",
407+
"notNull": false
408+
},
397409
{
398410
"fieldPath": "recommendation",
399411
"columnName": "recommendation",
@@ -851,7 +863,7 @@
851863
},
852864
{
853865
"tableName": "ocshares",
854-
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `file_source` INTEGER, `item_source` INTEGER, `share_type` INTEGER, `shate_with` TEXT, `path` TEXT, `permissions` INTEGER, `shared_date` INTEGER, `expiration_date` INTEGER, `token` TEXT, `shared_with_display_name` TEXT, `is_directory` INTEGER, `user_id` TEXT, `id_remote_shared` INTEGER, `owner_share` TEXT, `is_password_protected` INTEGER, `note` TEXT, `hide_download` INTEGER, `share_link` TEXT, `share_label` TEXT)",
866+
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `file_source` INTEGER, `item_source` INTEGER, `share_type` INTEGER, `shate_with` TEXT, `path` TEXT, `permissions` INTEGER, `shared_date` INTEGER, `expiration_date` INTEGER, `token` TEXT, `shared_with_display_name` TEXT, `is_directory` INTEGER, `user_id` TEXT, `id_remote_shared` INTEGER, `owner_share` TEXT, `is_password_protected` INTEGER, `note` TEXT, `hide_download` INTEGER, `share_link` TEXT, `share_label` TEXT, `download_limit_limit` INTEGER, `download_limit_count` INTEGER)",
855867
"fields": [
856868
{
857869
"fieldPath": "id",
@@ -972,6 +984,18 @@
972984
"columnName": "share_label",
973985
"affinity": "TEXT",
974986
"notNull": false
987+
},
988+
{
989+
"fieldPath": "downloadLimitLimit",
990+
"columnName": "download_limit_limit",
991+
"affinity": "INTEGER",
992+
"notNull": false
993+
},
994+
{
995+
"fieldPath": "downloadLimitCount",
996+
"columnName": "download_limit_count",
997+
"affinity": "INTEGER",
998+
"notNull": false
975999
}
9761000
],
9771001
"primaryKey": {
@@ -1301,7 +1325,7 @@
13011325
"views": [],
13021326
"setupQueries": [
13031327
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
1304-
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a657c5557784ebaff12f7709fc3fd6dd')"
1328+
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '277489b9d4a6ee84f96d09dea39591ba')"
13051329
]
13061330
}
13071331
}
24.5 KB
Loading

app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import androidx.test.espresso.matcher.ViewMatchers.withText
2222
import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultBaseUtils.matchesCheckNames
2323
import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils.matchesViews
2424
import com.google.android.material.floatingactionbutton.FloatingActionButton
25+
import com.nextcloud.android.lib.resources.files.FileDownloadLimit
2526
import com.nextcloud.test.RetryTestRule
2627
import com.nextcloud.test.TestActivity
2728
import com.owncloud.android.AbstractIT
@@ -93,6 +94,51 @@ class FileDetailSharingFragmentIT : AbstractIT() {
9394
show(file)
9495
}
9596

97+
@Test
98+
@ScreenshotTest
99+
fun listSharesDownloadLimit() {
100+
OCShare(file.decryptedRemotePath).apply {
101+
remoteId = 1
102+
shareType = ShareType.PUBLIC_LINK
103+
token = "AAAAAAAAAAAAAAA"
104+
activity.storageManager.saveShare(this)
105+
}
106+
107+
OCShare(file.decryptedRemotePath).apply {
108+
remoteId = 2
109+
shareType = ShareType.PUBLIC_LINK
110+
token = "BBBBBBBBBBBBBBB"
111+
fileDownloadLimit = FileDownloadLimit("BBBBBBBBBBBBBBB", 0, 0)
112+
activity.storageManager.saveShare(this)
113+
}
114+
115+
OCShare(file.decryptedRemotePath).apply {
116+
remoteId = 3
117+
shareType = ShareType.PUBLIC_LINK
118+
token = "CCCCCCCCCCCCCCC"
119+
fileDownloadLimit = FileDownloadLimit("CCCCCCCCCCCCCCC", 10, 0)
120+
activity.storageManager.saveShare(this)
121+
}
122+
123+
OCShare(file.decryptedRemotePath).apply {
124+
remoteId = 4
125+
shareType = ShareType.PUBLIC_LINK
126+
token = "DDDDDDDDDDDDDDD"
127+
fileDownloadLimit = FileDownloadLimit("DDDDDDDDDDDDDDD", 10, 5)
128+
activity.storageManager.saveShare(this)
129+
}
130+
131+
OCShare(file.decryptedRemotePath).apply {
132+
remoteId = 5
133+
shareType = ShareType.PUBLIC_LINK
134+
token = "FFFFFFFFFFFFFFF"
135+
fileDownloadLimit = FileDownloadLimit("FFFFFFFFFFFFFFF", 10, 10)
136+
activity.storageManager.saveShare(this)
137+
}
138+
139+
show(file)
140+
}
141+
96142
/**
97143
* Use same values as {@link OCFileListFragmentStaticServerIT showSharedFiles }
98144
*/

app/src/main/java/com/nextcloud/client/database/entity/CapabilityEntity.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ data class CapabilityEntity(
131131
val forbiddenFileNameExtensions: Int?,
132132
@ColumnInfo(name = ProviderTableMeta.CAPABILITIES_FORBIDDEN_FORBIDDEN_FILENAME_BASE_NAMES)
133133
val forbiddenFilenameBaseNames: Int?,
134+
@ColumnInfo(name = ProviderTableMeta.CAPABILITIES_FILES_DOWNLOAD_LIMIT)
135+
val filesDownloadLimit: Int?,
136+
@ColumnInfo(name = ProviderTableMeta.CAPABILITIES_FILES_DOWNLOAD_LIMIT_DEFAULT)
137+
val filesDownloadLimitDefault: Int?,
134138
@ColumnInfo(name = ProviderTableMeta.CAPABILITIES_RECOMMENDATION)
135139
val recommendation: Int?
136140
)

app/src/main/java/com/nextcloud/client/database/entity/ShareEntity.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,9 @@ data class ShareEntity(
5454
@ColumnInfo(name = ProviderTableMeta.OCSHARES_SHARE_LINK)
5555
val shareLink: String?,
5656
@ColumnInfo(name = ProviderTableMeta.OCSHARES_SHARE_LABEL)
57-
val shareLabel: String?
57+
val shareLabel: String?,
58+
@ColumnInfo(name = ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_LIMIT)
59+
val downloadLimitLimit: Int?,
60+
@ColumnInfo(name = ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_COUNT)
61+
val downloadLimitCount: Int?
5862
)

app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
import com.google.gson.Gson;
3434
import com.google.gson.JsonSyntaxException;
35+
import com.nextcloud.android.lib.resources.files.FileDownloadLimit;
3536
import com.nextcloud.client.account.User;
3637
import com.nextcloud.client.database.NextcloudDatabase;
3738
import com.nextcloud.client.database.dao.FileDao;
@@ -1556,6 +1557,15 @@ private ContentValues createContentValueForShare(OCShare share) {
15561557
contentValues.put(ProviderTableMeta.OCSHARES_SHARE_LINK, share.getShareLink());
15571558
contentValues.put(ProviderTableMeta.OCSHARES_SHARE_LABEL, share.getLabel());
15581559

1560+
FileDownloadLimit downloadLimit = share.getFileDownloadLimit();
1561+
if (downloadLimit != null) {
1562+
contentValues.put(ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_LIMIT, downloadLimit.getLimit());
1563+
contentValues.put(ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_COUNT, downloadLimit.getCount());
1564+
} else {
1565+
contentValues.putNull(ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_LIMIT);
1566+
contentValues.putNull(ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_COUNT);
1567+
}
1568+
15591569
return contentValues;
15601570
}
15611571

@@ -1569,7 +1579,8 @@ private OCShare createShareInstance(Cursor cursor) {
15691579
share.setPermissions(getInt(cursor, ProviderTableMeta.OCSHARES_PERMISSIONS));
15701580
share.setSharedDate(getLong(cursor, ProviderTableMeta.OCSHARES_SHARED_DATE));
15711581
share.setExpirationDate(getLong(cursor, ProviderTableMeta.OCSHARES_EXPIRATION_DATE));
1572-
share.setToken(getString(cursor, ProviderTableMeta.OCSHARES_TOKEN));
1582+
String token = getString(cursor, ProviderTableMeta.OCSHARES_TOKEN);
1583+
share.setToken(token);
15731584
share.setSharedWithDisplayName(getString(cursor, ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME));
15741585
share.setFolder(getInt(cursor, ProviderTableMeta.OCSHARES_IS_DIRECTORY) == 1);
15751586
share.setUserId(getString(cursor, ProviderTableMeta.OCSHARES_USER_ID));
@@ -1580,6 +1591,11 @@ private OCShare createShareInstance(Cursor cursor) {
15801591
share.setShareLink(getString(cursor, ProviderTableMeta.OCSHARES_SHARE_LINK));
15811592
share.setLabel(getString(cursor, ProviderTableMeta.OCSHARES_SHARE_LABEL));
15821593

1594+
FileDownloadLimit downloadLimit = new FileDownloadLimit(token,
1595+
getInt(cursor, ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_LIMIT),
1596+
getInt(cursor, ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_COUNT));
1597+
share.setFileDownloadLimit(downloadLimit);
1598+
15831599
return share;
15841600
}
15851601

@@ -2294,6 +2310,8 @@ private ContentValues createContentValues(String accountName, OCCapability capab
22942310
contentValues.put(ProviderTableMeta.CAPABILITIES_FORBIDDEN_FILENAMES, capability.getForbiddenFilenamesJson());
22952311
contentValues.put(ProviderTableMeta.CAPABILITIES_FORBIDDEN_FORBIDDEN_FILENAME_EXTENSIONS, capability.getForbiddenFilenameExtensionJson());
22962312
contentValues.put(ProviderTableMeta.CAPABILITIES_FORBIDDEN_FORBIDDEN_FILENAME_BASE_NAMES, capability.getForbiddenFilenameBaseNamesJson());
2313+
contentValues.put(ProviderTableMeta.CAPABILITIES_FILES_DOWNLOAD_LIMIT, capability.getFilesDownloadLimit().getValue());
2314+
contentValues.put(ProviderTableMeta.CAPABILITIES_FILES_DOWNLOAD_LIMIT_DEFAULT, capability.getFilesDownloadLimitDefault());
22972315

22982316
contentValues.put(ProviderTableMeta.CAPABILITIES_RECOMMENDATION, capability.getRecommendations().getValue());
22992317

@@ -2470,7 +2488,8 @@ private OCCapability createCapabilityInstance(Cursor cursor) {
24702488
capability.setForbiddenFilenamesJson(getString(cursor, ProviderTableMeta.CAPABILITIES_FORBIDDEN_FILENAMES));
24712489
capability.setForbiddenFilenameExtensionJson(getString(cursor, ProviderTableMeta.CAPABILITIES_FORBIDDEN_FORBIDDEN_FILENAME_EXTENSIONS));
24722490
capability.setForbiddenFilenameBaseNamesJson(getString(cursor, ProviderTableMeta.CAPABILITIES_FORBIDDEN_FORBIDDEN_FILENAME_BASE_NAMES));
2473-
2491+
capability.setFilesDownloadLimit(getBoolean(cursor, ProviderTableMeta.CAPABILITIES_FILES_DOWNLOAD_LIMIT));
2492+
capability.setFilesDownloadLimitDefault(getInt(cursor, ProviderTableMeta.CAPABILITIES_FILES_DOWNLOAD_LIMIT_DEFAULT));
24742493
capability.setRecommendations(getBoolean(cursor, ProviderTableMeta.CAPABILITIES_RECOMMENDATION));
24752494
}
24762495

app/src/main/java/com/owncloud/android/db/ProviderMeta.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ static public class ProviderTableMeta implements BaseColumns {
199199
public static final String OCSHARES_HIDE_DOWNLOAD = "hide_download";
200200
public static final String OCSHARES_SHARE_LINK = "share_link";
201201
public static final String OCSHARES_SHARE_LABEL = "share_label";
202+
public static final String OCSHARES_DOWNLOADLIMIT_LIMIT = "download_limit_limit";
203+
public static final String OCSHARES_DOWNLOADLIMIT_COUNT = "download_limit_count";
202204

203205
public static final String OCSHARES_DEFAULT_SORT_ORDER = OCSHARES_FILE_SOURCE
204206
+ " collate nocase asc";
@@ -268,6 +270,8 @@ static public class ProviderTableMeta implements BaseColumns {
268270
public static final String CAPABILITIES_FORBIDDEN_FILENAMES = "forbidden_filenames";
269271
public static final String CAPABILITIES_FORBIDDEN_FORBIDDEN_FILENAME_EXTENSIONS = "forbidden_filename_extensions";
270272
public static final String CAPABILITIES_FORBIDDEN_FORBIDDEN_FILENAME_BASE_NAMES = "forbidden_filename_basenames";
273+
public static final String CAPABILITIES_FILES_DOWNLOAD_LIMIT = "files_download_limit";
274+
public static final String CAPABILITIES_FILES_DOWNLOAD_LIMIT_DEFAULT = "files_download_limit_default";
271275

272276
//Columns of Uploads table
273277
public static final String UPLOADS_LOCAL_PATH = "local_path";
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Nextcloud - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2025 ZetaTom <70907959+zetatom@users.noreply.github.com>
5+
* SPDX-License-Identifier: AGPL-3.0-or-later
6+
*/
7+
8+
package com.owncloud.android.operations
9+
10+
import com.nextcloud.android.lib.resources.files.FileDownloadLimit
11+
import com.nextcloud.android.lib.resources.files.GetFilesDownloadLimitRemoteOperation
12+
import com.nextcloud.common.NextcloudClient
13+
import com.owncloud.android.datamodel.FileDataStorageManager
14+
import com.owncloud.android.lib.common.operations.RemoteOperationResult
15+
import com.owncloud.android.lib.resources.shares.OCShare
16+
import com.owncloud.android.operations.common.SyncOperation
17+
18+
class GetFilesDownloadLimitOperation(val share: OCShare, storageManager: FileDataStorageManager) : SyncOperation(
19+
storageManager
20+
) {
21+
override fun run(client: NextcloudClient): RemoteOperationResult<List<FileDownloadLimit>> {
22+
val token = share.token ?: return RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND)
23+
val operation = GetFilesDownloadLimitRemoteOperation(token)
24+
25+
val result = operation.execute(client)
26+
27+
return result
28+
}
29+
}

0 commit comments

Comments
 (0)