Skip to content

Commit

Permalink
Merge pull request #50694 from nextcloud/backport/50655/stable30
Browse files Browse the repository at this point in the history
[stable30] enh: Fix display default expire date, add tests & tiny refactors
  • Loading branch information
AndyScherzinger authored Feb 6, 2025
2 parents 3e93249 + baafbc4 commit e65409e
Show file tree
Hide file tree
Showing 15 changed files with 70 additions and 47 deletions.
34 changes: 18 additions & 16 deletions apps/files_sharing/lib/Controller/ShareAPIController.php
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ protected function formatShare(IShare $share, ?Node $recipientNode = null): arra
/** @var array{share_with_displayname: string, share_with_link: string, share_with?: string, token?: string} $roomShare */
$roomShare = $this->getRoomShareHelper()->formatShare($share);
$result = array_merge($result, $roomShare);
} catch (QueryException $e) {
} catch (ContainerExceptionInterface $e) {
}
} elseif ($share->getShareType() === IShare::TYPE_DECK) {
$result['share_with'] = $share->getSharedWith();
Expand All @@ -287,7 +287,7 @@ protected function formatShare(IShare $share, ?Node $recipientNode = null): arra
/** @var array{share_with: string, share_with_displayname: string, share_with_link: string} $deckShare */
$deckShare = $this->getDeckShareHelper()->formatShare($share);
$result = array_merge($result, $deckShare);
} catch (QueryException $e) {
} catch (ContainerExceptionInterface $e) {
}
} elseif ($share->getShareType() === IShare::TYPE_SCIENCEMESH) {
$result['share_with'] = $share->getSharedWith();
Expand All @@ -297,7 +297,7 @@ protected function formatShare(IShare $share, ?Node $recipientNode = null): arra
/** @var array{share_with: string, share_with_displayname: string, token: string} $scienceMeshShare */
$scienceMeshShare = $this->getSciencemeshShareHelper()->formatShare($share);
$result = array_merge($result, $scienceMeshShare);
} catch (QueryException $e) {
} catch (ContainerExceptionInterface $e) {
}
}

Expand Down Expand Up @@ -632,7 +632,9 @@ public function createShare(
$share = $this->setShareAttributes($share, $attributes);
}

// Expire date
// Expire date checks
// Normally, null means no expiration date but we still set the default for backwards compatibility
// If the client sends an empty string, we set noExpirationDate to true
if ($expireDate !== null) {
if ($expireDate !== '') {
try {
Expand Down Expand Up @@ -746,7 +748,7 @@ public function createShare(
$share->setSharedWith($shareWith);
$share->setPermissions($permissions);
} elseif ($shareType === IShare::TYPE_CIRCLE) {
if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
if (!\OCP\Server::get(IAppManager::class)->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
throw new OCSNotFoundException($this->l->t('You cannot share to a Team if the app is not enabled'));
}

Expand All @@ -761,19 +763,19 @@ public function createShare(
} elseif ($shareType === IShare::TYPE_ROOM) {
try {
$this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate ?? '');
} catch (QueryException $e) {
} catch (ContainerExceptionInterface $e) {
throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$node->getPath()]));
}
} elseif ($shareType === IShare::TYPE_DECK) {
try {
$this->getDeckShareHelper()->createShare($share, $shareWith, $permissions, $expireDate ?? '');
} catch (QueryException $e) {
} catch (ContainerExceptionInterface $e) {
throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$node->getPath()]));
}
} elseif ($shareType === IShare::TYPE_SCIENCEMESH) {
try {
$this->getSciencemeshShareHelper()->createShare($share, $shareWith, $permissions, $expireDate ?? '');
} catch (QueryException $e) {
} catch (ContainerExceptionInterface $e) {
throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support ScienceMesh shares', [$node->getPath()]));
}
} else {
Expand Down Expand Up @@ -1765,10 +1767,10 @@ public function cleanup() {
* Returns the helper of ShareAPIController for room shares.
*
* If the Talk application is not enabled or the helper is not available
* a QueryException is thrown instead.
* a ContainerExceptionInterface is thrown instead.
*
* @return \OCA\Talk\Share\Helper\ShareAPIController
* @throws QueryException
* @throws ContainerExceptionInterface
*/
private function getRoomShareHelper() {
if (!$this->appManager->isEnabledForUser('spreed')) {
Expand All @@ -1782,10 +1784,10 @@ private function getRoomShareHelper() {
* Returns the helper of ShareAPIHelper for deck shares.
*
* If the Deck application is not enabled or the helper is not available
* a QueryException is thrown instead.
* a ContainerExceptionInterface is thrown instead.
*
* @return \OCA\Deck\Sharing\ShareAPIHelper
* @throws QueryException
* @throws ContainerExceptionInterface
*/
private function getDeckShareHelper() {
if (!$this->appManager->isEnabledForUser('deck')) {
Expand All @@ -1799,10 +1801,10 @@ private function getDeckShareHelper() {
* Returns the helper of ShareAPIHelper for sciencemesh shares.
*
* If the sciencemesh application is not enabled or the helper is not available
* a QueryException is thrown instead.
* a ContainerExceptionInterface is thrown instead.
*
* @return \OCA\Deck\Sharing\ShareAPIHelper
* @throws QueryException
* @throws ContainerExceptionInterface
*/
private function getSciencemeshShareHelper() {
if (!$this->appManager->isEnabledForUser('sciencemesh')) {
Expand Down Expand Up @@ -1935,7 +1937,7 @@ private function shareProviderResharingRights(string $userId, IShare $share, $no
return true;
}

if ($share->getShareType() === IShare::TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles')
if ($share->getShareType() === IShare::TYPE_CIRCLE && \OCP\Server::get(IAppManager::class)->isEnabledForUser('circles')
&& class_exists('\OCA\Circles\Api\v1\Circles')) {
$hasCircleId = (str_ends_with($share->getSharedWith(), ']'));
$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
Expand All @@ -1951,7 +1953,7 @@ private function shareProviderResharingRights(string $userId, IShare $share, $no
return true;
}
return false;
} catch (QueryException $e) {
} catch (ContainerExceptionInterface $e) {
return false;
}
}
Expand Down
17 changes: 13 additions & 4 deletions apps/files_sharing/src/components/SharingEntryLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,13 @@
:checked.sync="defaultExpirationDateEnabled"
:disabled="pendingEnforcedExpirationDate || saving"
class="share-link-expiration-date-checkbox"
@change="onDefaultExpirationDateEnabledChange">
@change="onExpirationDateToggleChange">
{{ config.isDefaultExpireDateEnforced ? t('files_sharing', 'Enable link expiration (enforced)') : t('files_sharing', 'Enable link expiration') }}
</NcActionCheckbox>

<!-- expiration date -->
<NcActionInput v-if="(pendingDefaultExpirationDate || pendingEnforcedExpirationDate) && defaultExpirationDateEnabled"
data-cy-files-sharing-expiration-date-input
class="share-link-expire-date"
:label="pendingEnforcedExpirationDate ? t('files_sharing', 'Enter expiration date (enforced)') : t('files_sharing', 'Enter expiration date')"
:disabled="saving"
Expand All @@ -100,7 +101,7 @@
type="date"
:min="dateTomorrow"
:max="maxExpirationDateEnforced"
@input="onExpirationChange /* let's not submit when picked, the user might want to still edit or copy the password */">
@change="expirationDateChanged($event)">
<template #icon>
<IconCalendarBlank :size="20" />
</template>
Expand Down Expand Up @@ -589,6 +590,9 @@ export default {
},
mounted() {
this.defaultExpirationDateEnabled = this.config.defaultExpirationDate instanceof Date
if (this.share && this.isNewShare) {
this.share.expireDate = this.defaultExpirationDateEnabled ? this.formatDateToString(this.config.defaultExpirationDate) : ''
}
},

methods: {
Expand Down Expand Up @@ -707,7 +711,7 @@ export default {
path,
shareType: ShareType.Link,
password: share.password,
expireDate: share.expireDate,
expireDate: share.expireDate ?? '',
attributes: JSON.stringify(this.fileInfo.shareAttributes),
// we do not allow setting the publicUpload
// before the share creation.
Expand Down Expand Up @@ -863,9 +867,14 @@ export default {
this.onPasswordSubmit()
this.onNoteSubmit()
},
onDefaultExpirationDateEnabledChange(enabled) {
onExpirationDateToggleChange(enabled) {
this.share.expireDate = enabled ? this.formatDateToString(this.config.defaultExpirationDate) : ''
},
expirationDateChanged(event) {
const date = event.target.value
this.onExpirationChange(date)
this.defaultExpirationDateEnabled = !!date
},

/**
* Cancel the share creation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

<script>
import { ShareType } from '@nextcloud/sharing'
import { subscribe, unsubscribe } from '@nextcloud/event-bus'
import DropdownIcon from 'vue-material-design-icons/TriangleSmallDown.vue'
import SharesMixin from '../mixins/SharesMixin.js'
import ShareDetails from '../mixins/ShareDetails.js'
Expand Down Expand Up @@ -145,7 +146,17 @@ export default {
created() {
this.selectedOption = this.preSelectedOption
},

mounted() {
subscribe('update:share', (share) => {
if (share.id === this.share.id) {
this.share.permissions = share.permissions
this.selectedOption = this.preSelectedOption
}
})
},
unmounted() {
unsubscribe('update:share')
},
methods: {
selectOption(optionLabel) {
this.selectedOption = optionLabel
Expand Down
16 changes: 5 additions & 11 deletions apps/files_sharing/src/mixins/SharesMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ export default {
monthFormat: 'MMM',
}
},
isNewShare() {
return !this.share.id
},
isFolder() {
return this.fileInfo.type === 'dir'
},
Expand Down Expand Up @@ -210,17 +213,8 @@ export default {
* @param {Date} date
*/
onExpirationChange(date) {
this.share.expireDate = this.formatDateToString(new Date(date))
},

/**
* Uncheck expire date
* We need this method because @update:checked
* is ran simultaneously as @uncheck, so
* so we cannot ensure data is up-to-date
*/
onExpirationDisable() {
this.share.expireDate = ''
const formattedDate = date ? this.formatDateToString(new Date(date)) : ''
this.share.expireDate = formattedDate
},

/**
Expand Down
4 changes: 1 addition & 3 deletions apps/files_sharing/src/views/SharingDetailsTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -526,9 +526,6 @@ export default {
isGroupShare() {
return this.share.type === ShareType.Group
},
isNewShare() {
return !this.share.id
},
allowsFileDrop() {
if (this.isFolder && this.config.isPublicUploadEnabled) {
if (this.share.type === ShareType.Link || this.share.type === ShareType.Email) {
Expand Down Expand Up @@ -921,6 +918,7 @@ export default {
this.$emit('add:share', this.share)
} else {
this.$emit('update:share', this.share)
emit('update:share', this.share)
this.queueUpdate(...permissionsAndAttributes)
}

Expand Down
19 changes: 14 additions & 5 deletions cypress/e2e/files_sharing/public-share/setup-public-share.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ export function setupData(user: User, shareName: string): void {
*/
function checkPasswordState(enforced: boolean, alwaysAskForPassword: boolean) {
if (enforced) {
cy.contains('Password protection (enforced)').should('exist')
cy.contains('Password protection (enforced)').should('exist')
} else if (alwaysAskForPassword) {
cy.contains('Password protection').should('exist')
cy.contains('Password protection').should('exist')
}
cy.contains('Enter a password')
.should('exist')
Expand All @@ -68,13 +68,22 @@ function checkPasswordState(enforced: boolean, alwaysAskForPassword: boolean) {
*/
function checkExpirationDateState(enforced: boolean, hasDefault: boolean) {
if (enforced) {
cy.contains('Enable link expiration (enforced)').should('exist')
cy.contains('Enable link expiration (enforced)').should('exist')
} else if (hasDefault) {
cy.contains('Enable link expiration').should('exist')
cy.contains('Enable link expiration').should('exist')
}
cy.contains('Enter expiration date')
.should('exist')
.and('not.be.disabled')
cy.get('input[data-cy-files-sharing-expiration-date-input]').should('exist')
cy.get('input[data-cy-files-sharing-expiration-date-input]')
.invoke('val')
.then((val) => {
const expectedDate = new Date()
expectedDate.setDate(expectedDate.getDate() + 2)
expect(new Date(val).toDateString()).to.eq(expectedDate.toDateString())
})

}

/**
Expand All @@ -90,7 +99,7 @@ export function createShare(context: ShareContext, shareName: string, options: S

cy.intercept('POST', '**/ocs/v2.php/apps/files_sharing/api/v1/shares').as('createShare')
cy.findByRole('button', { name: 'Create a new share link' }).click()
// Conduct optional checks based on the provided options
// Conduct optional checks based on the provided options
if (options) {
cy.get('.sharing-entry__actions').should('be.visible') // Wait for the dialog to open
checkPasswordState(options.enforcePassword ?? false, options.alwaysAskForPassword ?? false)
Expand Down
2 changes: 2 additions & 0 deletions dist/5661-5661.js

Large diffs are not rendered by default.

File renamed without changes.
1 change: 1 addition & 0 deletions dist/5661-5661.js.map

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/5661-5661.js.map.license
2 changes: 0 additions & 2 deletions dist/7797-7797.js

This file was deleted.

1 change: 0 additions & 1 deletion dist/7797-7797.js.map

This file was deleted.

1 change: 0 additions & 1 deletion dist/7797-7797.js.map.license

This file was deleted.

Loading

0 comments on commit e65409e

Please sign in to comment.