Skip to content

Commit

Permalink
[WIP] feat: Add download limit
Browse files Browse the repository at this point in the history
Signed-off-by: Christopher Ng <chrng8@gmail.com>
  • Loading branch information
Pytal committed Feb 22, 2024
1 parent 124c7c6 commit 318b3ce
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 0 deletions.
13 changes: 13 additions & 0 deletions apps/files_sharing/src/mixins/ShareDetails.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { Type as ShareTypes } from '@nextcloud/sharing'

import Share from '../models/Share.js'
import { getDownloadLimit } from '../services/DownloadLimitService.js'

export default {
methods: {
Expand All @@ -19,9 +22,19 @@ export default {
share = this.mapShareRequestToShareObject(shareRequestObject)
}

const isPublicShare = [
ShareTypes.SHARE_TYPE_LINK,
ShareTypes.SHARE_TYPE_EMAIL,
].includes(share.shareType ?? share.type)

const downloadLimit = (isPublicShare && share.token)
? await getDownloadLimit(share.token)
: null

const shareDetails = {
fileInfo: this.fileInfo,
share,
downloadLimit,
}

this.$emit('open-sharing-details', shareDetails)
Expand Down
49 changes: 49 additions & 0 deletions apps/files_sharing/src/services/DownloadLimitService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @copyright Copyright (c) 2021 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author Christopher Ng <chrng8@gmail.com>
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

import axios from '@nextcloud/axios'
import { generateOcsUrl } from '@nextcloud/router'

type Nullable<T> = null | T

export interface DownloadLimit {
limit: Nullable<number>
count: Nullable<number>
}

export const getDownloadLimit = async (token: string): Promise<DownloadLimit> => {
const response = await axios.get(generateOcsUrl('/apps/files_downloadlimit/api/v1/{token}/limit', { token }))
return response.data.ocs.data
}

export const setDownloadLimit = async (token: string, limit: number) => {
const response = await axios.put(generateOcsUrl('/apps/files_downloadlimit/api/v1/{token}/limit', { token }), {
limit,
})
return response.data.ocs.data
}

export const deleteDownloadLimit = async (token: string) => {
const response = await axios.delete(generateOcsUrl('/apps/files_downloadlimit/api/v1/{token}/limit', { token }))
return response.data.ocs.data
}
69 changes: 69 additions & 0 deletions apps/files_sharing/src/views/SharingDetailsTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,28 @@
:placeholder="t('files_sharing', 'Expiration date')"
type="date"
@input="onExpirationChange" />
<template v-if="isPublicShare && downloadLimitEnabled">
<NcCheckboxRadioSwitch :checked.sync="showDownloadLimit">
{{ t('files_sharing', 'Limit downloads') }}
</NcCheckboxRadioSwitch>
<NcNoteCard v-show="showDownloadLimit && showDownloadCount"
class="sharingTabDetailsView__count-note"
type="info">
{{ n('files_sharing', '1 download remaining', '{count} downloads remaining', initialDownloadLimit?.limit - downloadCount, { count: initialDownloadLimit?.limit - downloadCount }) }}
</NcNoteCard>
<NcTextField v-show="showDownloadLimit"
:label="t('settings', 'Set download limit')"
type="number"
min="1"
:value.sync="downloadLimit"
:helper-text="downloadLimitHelperText"
:error="Boolean(downloadLimitHelperText)" />
<NcNoteCard v-show="showDownloadLimit && !isNewShare"
class="sharingTabDetailsView__reset-note"
type="warning">
{{ t('files_sharing', 'Setting a new limit will reset the download count') }}
</NcNoteCard>
</template>
<NcCheckboxRadioSwitch v-if="isPublicShare"
:disabled="canChangeHideDownload"
:checked.sync="share.hideDownload"
Expand Down Expand Up @@ -215,9 +237,13 @@
<script>
import { getLanguage } from '@nextcloud/l10n'
import { getCapabilities } from '@nextcloud/capabilities'
import { showError } from '@nextcloud/dialogs'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcInputField from '@nextcloud/vue/dist/Components/NcInputField.js'
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'
import NcPasswordField from '@nextcloud/vue/dist/Components/NcPasswordField.js'
import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar.js'
import NcDateTimePickerNative from '@nextcloud/vue/dist/Components/NcDateTimePickerNative.js'
Expand All @@ -242,6 +268,7 @@ import Share from '../models/Share.js'
import ShareRequests from '../mixins/ShareRequests.js'
import ShareTypes from '../mixins/ShareTypes.js'
import SharesMixin from '../mixins/SharesMixin.js'
import { setDownloadLimit } from '../services/DownloadLimitService.js'
import {
ATOMIC_PERMISSIONS,
Expand All @@ -255,6 +282,8 @@ export default {
NcAvatar,
NcButton,
NcInputField,
NcTextField,
NcNoteCard,
NcPasswordField,
NcDateTimePickerNative,
NcCheckboxRadioSwitch,
Expand Down Expand Up @@ -286,6 +315,13 @@ export default {
type: Object,
required: true,
},
/**
* @type {import('../services/DownloadLimitService.js').DownloadLimit}
*/
initialDownloadLimit: {
type: Object,
default: null,
},
},
data() {
return {
Expand All @@ -299,6 +335,11 @@ export default {
isFirstComponentLoad: true,
test: false,
creating: false,
downloadLimitEnabled: getCapabilities()?.downloadlimit?.enabled && this.fileInfo.type === 'file',
showDownloadLimit: Boolean(this.initialDownloadLimit?.limit),
showDownloadCount: typeof this.initialDownloadLimit?.count === 'number',
downloadLimit: this.initialDownloadLimit?.limit ?? '',
downloadCount: typeof this.initialDownloadLimit?.count === 'number' ? this.initialDownloadLimit?.count : '',
}
},
Expand Down Expand Up @@ -651,6 +692,18 @@ export default {
}
return undefined
},
shouldUpdateDownloadLimit() {
return this.isPublicShare
&& this.downloadLimitEnabled
&& typeof this.downloadLimit === 'number'
&& this.initialDownloadLimit?.limit !== this.downloadLimit
},
downloadLimitHelperText() {
if (this.downloadLimit >= 1) {
return
}
return t('files_sharing', 'The minimum limit is 1')
},
},
watch: {
setCustomPermissions(isChecked) {
Expand Down Expand Up @@ -841,6 +894,14 @@ export default {
this.queueUpdate(...permissionsAndAttributes)
}
if (this.shouldUpdateDownloadLimit) {
try {
await setDownloadLimit(this.share.token, this.downloadLimit)
} catch (error) {
showError(t('files_sharing', 'Failed to set download limit'))
}
}
this.$emit('close-sharing-details')
},
/**
Expand Down Expand Up @@ -1062,6 +1123,14 @@ export default {
}
}
&__count-note {
margin-top: 4px;
}
&__reset-note {
margin-bottom: 8px;
}
&__delete {
>button:first-child {
color: rgb(223, 7, 7);
Expand Down
1 change: 1 addition & 0 deletions apps/files_sharing/src/views/SharingTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
<SharingDetailsTab v-if="showSharingDetailsView"
:file-info="shareDetailsData.fileInfo"
:share="shareDetailsData.share"
:initial-download-limit="shareDetailsData.downloadLimit"
@close-sharing-details="toggleShareDetailsView"
@add:share="addShare"
@remove:share="removeShare" />
Expand Down

0 comments on commit 318b3ce

Please sign in to comment.