Skip to content

Commit 6da5897

Browse files
authored
Merge pull request #50192 from nextcloud/fix/files_sharing/sharing-entry-link-override-expiration-date
fix(files_sharing): Stop overwriting the share expiration date with the default expiration date
2 parents 0cad072 + ddd70c9 commit 6da5897

File tree

14 files changed

+160
-18
lines changed

14 files changed

+160
-18
lines changed

apps/files_sharing/src/components/SharingEntryLink.vue

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -590,10 +590,7 @@ export default {
590590
},
591591
},
592592
mounted() {
593-
if (this.share) {
594-
this.defaultExpirationDateEnabled = this.config.defaultExpirationDate instanceof Date
595-
this.share.expireDate = this.defaultExpirationDateEnabled ? this.formatDateToString(this.config.defaultExpirationDate) : ''
596-
}
593+
this.defaultExpirationDateEnabled = this.config.defaultExpirationDate instanceof Date
597594
},
598595
599596
methods: {

apps/files_sharing/src/mixins/SharesMixin.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ export default {
128128
return this.config.isDefaultExpireDateEnforced
129129
}
130130
if (this.isRemoteShare) {
131-
return this.config.isDefaultRemoteExpireDateEnforced
131+
return this.config.isDefaultRemoteExpireDateEnforced
132132
}
133133
return this.config.isDefaultInternalExpireDateEnforced
134134
},
@@ -209,9 +209,10 @@ export default {
209209
*
210210
* @param {Date} date
211211
*/
212-
onExpirationChange: debounce(function(date) {
212+
onExpirationChange(date) {
213213
this.share.expireDate = this.formatDateToString(new Date(date))
214-
}, 500),
214+
},
215+
215216
/**
216217
* Uncheck expire date
217218
* We need this method because @update:checked

apps/files_sharing/src/views/SharingDetailsTab.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@
144144
:value="new Date(share.expireDate ?? dateTomorrow)"
145145
:min="dateTomorrow"
146146
:max="maxExpirationDateEnforced"
147-
:hide-label="true"
147+
hide-label
148+
:label="t('files_sharing', 'Expiration date')"
148149
:placeholder="t('files_sharing', 'Expiration date')"
149150
type="date"
150151
@input="onExpirationChange" />

cypress/e2e/files_sharing/FilesSharingUtils.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export interface ShareSetting {
1212
share: boolean
1313
download: boolean
1414
note: string
15+
expiryDate: Date
1516
}
1617

1718
export function createShare(fileName: string, username: string, shareSettings: Partial<ShareSetting> = {}) {
@@ -31,15 +32,20 @@ export function createShare(fileName: string, username: string, shareSettings: P
3132
updateShare(fileName, 0, shareSettings)
3233
}
3334

35+
export function openSharingDetails(index: number) {
36+
cy.get('#app-sidebar-vue').within(() => {
37+
cy.get('[data-cy-files-sharing-share-actions]').eq(index).click()
38+
cy.get('[data-cy-files-sharing-share-permissions-bundle="custom"]').click()
39+
})
40+
}
41+
3442
export function updateShare(fileName: string, index: number, shareSettings: Partial<ShareSetting> = {}) {
3543
openSharingPanel(fileName)
44+
openSharingDetails(index)
3645

3746
cy.intercept({ times: 1, method: 'PUT', url: '**/apps/files_sharing/api/v1/shares/*' }).as('updateShare')
3847

3948
cy.get('#app-sidebar-vue').within(() => {
40-
cy.get('[data-cy-files-sharing-share-actions]').eq(index).click()
41-
cy.get('[data-cy-files-sharing-share-permissions-bundle="custom"]').click()
42-
4349
if (shareSettings.download !== undefined) {
4450
cy.get('[data-cy-files-sharing-share-permissions-checkbox="download"]').find('input').as('downloadCheckbox')
4551
if (shareSettings.download) {
@@ -89,10 +95,19 @@ export function updateShare(fileName: string, index: number, shareSettings: Part
8995
cy.findByRole('textbox', { name: /note to recipient/i }).type(shareSettings.note)
9096
}
9197

98+
if (shareSettings.expiryDate !== undefined) {
99+
cy.findByRole('checkbox', { name: /expiration date/i })
100+
.check({ force: true, scrollBehavior: 'nearest' })
101+
cy.get('#share-date-picker')
102+
.type(`${shareSettings.expiryDate.getFullYear()}-${String(shareSettings.expiryDate.getMonth() + 1).padStart(2, '0')}-${String(shareSettings.expiryDate.getDate()).padStart(2, '0')}`)
103+
}
104+
92105
cy.get('[data-cy-files-sharing-share-editor-action="save"]').click({ scrollBehavior: 'nearest' })
93106

94107
cy.wait('@updateShare')
95108
})
109+
// close all toasts
110+
cy.get('.toast-success').findAllByRole('button').click({ force: true, multiple: true })
96111
}
97112

98113
export function openSharingPanel(fileName: string) {
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*!
2+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import { User } from '@nextcloud/cypress'
7+
import { closeSidebar } from '../files/FilesUtils.ts'
8+
import { createShare, openSharingDetails, openSharingPanel, updateShare } from './FilesSharingUtils.ts'
9+
10+
describe('files_sharing: Expiry date', () => {
11+
const expectedDefaultDate = new Date(Date.now() + 2 * 24 * 60 * 60 * 1000)
12+
const expectedDefaultDateString = `${expectedDefaultDate.getFullYear()}-${String(expectedDefaultDate.getMonth() + 1).padStart(2, '0')}-${String(expectedDefaultDate.getDate()).padStart(2, '0')}`
13+
const fortnight = new Date(Date.now() + 14 * 24 * 60 * 60 * 1000)
14+
const fortnightString = `${fortnight.getFullYear()}-${String(fortnight.getMonth() + 1).padStart(2, '0')}-${String(fortnight.getDate()).padStart(2, '0')}`
15+
16+
let alice: User
17+
let bob: User
18+
19+
before(() => {
20+
// Ensure we have the admin setting setup for default dates with 2 days in the future
21+
cy.runOccCommand('config:app:set --value yes core shareapi_default_internal_expire_date')
22+
cy.runOccCommand('config:app:set --value 2 core shareapi_internal_expire_after_n_days')
23+
24+
cy.createRandomUser().then((user) => {
25+
alice = user
26+
cy.login(alice)
27+
})
28+
cy.createRandomUser().then((user) => {
29+
bob = user
30+
})
31+
})
32+
33+
after(() => {
34+
cy.runOccCommand('config:app:delete core shareapi_default_internal_expire_date')
35+
cy.runOccCommand('config:app:delete core shareapi_enforce_internal_expire_date')
36+
cy.runOccCommand('config:app:delete core shareapi_internal_expire_after_n_days')
37+
})
38+
39+
beforeEach(() => {
40+
cy.runOccCommand('config:app:delete core shareapi_enforce_internal_expire_date')
41+
})
42+
43+
it('See default expiry date is set and enforced', () => {
44+
// Enforce the date
45+
cy.runOccCommand('config:app:set --value yes core shareapi_enforce_internal_expire_date')
46+
const dir = 'defaultExpiryDateEnforced'
47+
prepareDirectory(dir)
48+
49+
validateExpiryDate(dir, expectedDefaultDateString)
50+
cy.findByRole('checkbox', { name: /expiration date/i })
51+
.should('be.checked')
52+
.and('be.disabled')
53+
})
54+
55+
it('See default expiry date is set also if not enforced', () => {
56+
const dir = 'defaultExpiryDate'
57+
prepareDirectory(dir)
58+
59+
validateExpiryDate(dir, expectedDefaultDateString)
60+
cy.findByRole('checkbox', { name: /expiration date/i })
61+
.should('be.checked')
62+
.and('not.be.disabled')
63+
.check({ force: true, scrollBehavior: 'nearest' })
64+
})
65+
66+
it('Can set custom expiry date', () => {
67+
const dir = 'customExpiryDate'
68+
prepareDirectory(dir)
69+
updateShare(dir, 0, { expiryDate: fortnight })
70+
validateExpiryDate(dir, fortnightString)
71+
})
72+
73+
it('Custom expiry date survives reload', () => {
74+
const dir = 'customExpiryDateReload'
75+
prepareDirectory(dir)
76+
updateShare(dir, 0, { expiryDate: fortnight })
77+
validateExpiryDate(dir, fortnightString)
78+
79+
cy.visit('/apps/files')
80+
validateExpiryDate(dir, fortnightString)
81+
})
82+
83+
/**
84+
* Regression test for https://github.com/nextcloud/server/pull/50192
85+
* Ensure that admin default settings do not always override the user set value.
86+
*/
87+
it('Custom expiry date survives unrelated update', () => {
88+
const dir = 'customExpiryUnrelatedChanges'
89+
prepareDirectory(dir)
90+
updateShare(dir, 0, { expiryDate: fortnight })
91+
validateExpiryDate(dir, fortnightString)
92+
93+
closeSidebar()
94+
updateShare(dir, 0, { note: 'Only note changed' })
95+
validateExpiryDate(dir, fortnightString)
96+
97+
cy.visit('/apps/files')
98+
validateExpiryDate(dir, fortnightString)
99+
})
100+
101+
/**
102+
* Prepare directory, login and share to bob
103+
*
104+
* @param name The directory name
105+
*/
106+
function prepareDirectory(name: string) {
107+
cy.mkdir(alice, `/${name}`)
108+
cy.login(alice)
109+
cy.visit('/apps/files')
110+
createShare(name, bob.userId)
111+
}
112+
113+
/**
114+
* Validate expiry date on a share
115+
*
116+
* @param filename The filename to validate
117+
* @param expectedDate The expected date in YYYY-MM-dd
118+
*/
119+
function validateExpiryDate(filename: string, expectedDate: string) {
120+
openSharingPanel(filename)
121+
openSharingDetails(0)
122+
123+
cy.get('#share-date-picker')
124+
.should('exist')
125+
.and('have.value', expectedDate)
126+
}
127+
128+
})

dist/467-467.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/467-467.js.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/467-467.js.map.license

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
467-467.js.license

dist/9701-9701.js

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)