Skip to content

Commit

Permalink
feat: show link modal when password is enforced
Browse files Browse the repository at this point in the history
Show the full expanded link modal for creating quick links when a password is enforced.
  • Loading branch information
JammingBen committed Dec 1, 2023
1 parent 62b68ed commit f684724
Show file tree
Hide file tree
Showing 13 changed files with 340 additions and 394 deletions.
129 changes: 50 additions & 79 deletions packages/web-app-files/src/components/SideBar/Shares/FileLinks.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<create-quick-link
v-else-if="canCreateLinks"
:expiration-rules="expirationRules"
@create-public-link="checkLinkToCreate"
@create-public-link="addNewLink"
/>
<details-and-edit
v-if="quicklink"
Expand Down Expand Up @@ -124,8 +124,9 @@ import {
useCapabilityFilesSharingPublicPasswordEnforcedFor,
useAbility,
usePasswordPolicyService,
getDefaultLinkPermissions,
useExpirationRules
useExpirationRules,
useDefaultLinkPermissions,
useCreateLink
} from '@ownclouders/web-pkg'
import { shareViaLinkHelp, shareViaIndirectLinkHelp } from '../../../helpers/contextualHelpers'
import {
Expand All @@ -137,7 +138,6 @@ import {
Share,
SharePermissions
} from '@ownclouders/web-client/src/helpers/share'
import { showQuickLinkPasswordModal } from '@ownclouders/web-pkg'
import DetailsAndEdit from './Links/DetailsAndEdit.vue'
import NameAndCopy from './Links/NameAndCopy.vue'
import CreateQuickLink from './Links/CreateQuickLink.vue'
Expand All @@ -151,6 +151,7 @@ import {
import { isLocationSharesActive } from '@ownclouders/web-pkg'
import { useShares } from 'web-app-files/src/composables'
import { configurationManager } from '@ownclouders/web-pkg'
import { useGettext } from 'vue3-gettext'
export default defineComponent({
name: 'FileLinks',
Expand All @@ -161,11 +162,15 @@ export default defineComponent({
},
setup() {
const store = useStore()
const { $gettext } = useGettext()
const ability = useAbility()
const { can } = ability
const { expirationRules } = useExpirationRules()
const passwordPolicyService = usePasswordPolicyService()
const hasResharing = useCapabilityFilesSharingResharing()
const hasShareJail = useCapabilityShareJailEnabled()
const { defaultLinkPermissions } = useDefaultLinkPermissions()
const { createLink } = useCreateLink()
const space = inject<Ref<SpaceResource>>('space')
const resource = inject<Ref<Resource>>('resource')
Expand Down Expand Up @@ -221,14 +226,44 @@ export default defineComponent({
)
}
const showQuickLinkPasswordModal = (params = {}) => {
const modal = {
variation: 'passive',
title: $gettext('Set password'),
cancelText: $gettext('Cancel'),
confirmText: $gettext('Set'),
hasInput: true,
inputDescription: $gettext('Passwords for links are required.'),
inputPasswordPolicy: passwordPolicyService.getPolicy(),
inputGeneratePasswordMethod: () => passwordPolicyService.generatePassword(),
inputLabel: $gettext('Password'),
inputType: 'password',
onInput: () => store.dispatch('setModalInputErrorMessage', ''),
onPasswordChallengeCompleted: () => store.dispatch('setModalConfirmButtonDisabled', false),
onPasswordChallengeFailed: () => store.dispatch('setModalConfirmButtonDisabled', true),
onCancel: () => store.dispatch('hideModal'),
onConfirm: async (newPassword: string) => {
await createLink({
resource: unref(resource),
space: unref(space),
...params,
password: newPassword
})
return store.dispatch('hideModal')
}
}
return store.dispatch('createModal', modal)
}
return {
$store: store,
ability,
space,
resource,
incomingParentShare: inject<Share>('incomingParentShare'),
hasSpaces: useCapabilitySpacesEnabled(),
hasShareJail: useCapabilityShareJailEnabled(),
hasShareJail,
hasPublicLinkEditing: useCapabilityFilesSharingPublicCanEdit(),
hasPublicLinkContribute: useCapabilityFilesSharingPublicCanContribute(),
hasPublicLinkAliasSupport: useCapabilityFilesSharingPublicAlias(),
Expand All @@ -241,10 +276,12 @@ export default defineComponent({
canCreatePublicLinks,
canDeleteReadOnlyPublicLinkPassword,
configurationManager,
passwordPolicyService,
canCreateLinks,
canEditLink,
expirationRules
expirationRules,
createLink,
showQuickLinkPasswordModal,
defaultLinkPermissions
}
},
computed: {
Expand Down Expand Up @@ -380,37 +417,12 @@ export default defineComponent({
)
},
addNewLink() {
this.checkLinkToCreate({
link: {
name: this.$gettext('Link'),
permissions: getDefaultLinkPermissions({
ability: this.ability,
store: this.$store
}).toString(),
expiration: this.expirationRules.default,
password: false
}
})
},
checkLinkToCreate({ link }) {
const paramsToCreate = this.getParamsForLink(link)
if (this.isPasswordEnforcedFor(link)) {
showQuickLinkPasswordModal(
{
...this.$language,
store: this.$store,
passwordPolicyService: this.passwordPolicyService
},
(newPassword) => {
this.createLink({ params: { ...paramsToCreate, password: newPassword } })
}
)
} else {
this.createLink({ params: paramsToCreate })
addNewLink({ link }) {
if (this.isPasswordEnforcedFor({ permissions: this.defaultLinkPermissions })) {
return this.showQuickLinkPasswordModal(link)
}
return this.createLink({ resource: this.resource, space: this.space, ...link })
},
checkLinkToUpdate({ link }) {
Expand All @@ -424,16 +436,7 @@ export default defineComponent({
}
if (!link.password && !this.canDeletePublicLinkPassword(link)) {
showQuickLinkPasswordModal(
{
...this.$language,
store: this.$store,
passwordPolicyService: this.passwordPolicyService
},
(newPassword) => {
this.updatePublicLink({ params: { ...params, password: newPassword } })
}
)
this.showQuickLinkPasswordModal(params)
} else {
this.updatePublicLink({ params })
}
Expand Down Expand Up @@ -490,38 +493,6 @@ export default defineComponent({
}
},
async createLink({ params }) {
let path = this.resource.path
// sharing a share root from the share jail -> use resource name as path
if (this.hasShareJail && path === '/') {
path = `/${this.resource.name}`
}
try {
await this.addLink({
path,
client: this.$client,
storageId: this.resource.fileId || this.resource.id,
params
})
this.hideModal()
this.showMessage({
title: this.$gettext('Link was created successfully')
})
} catch (e) {
console.error(e)
// Human-readable error message is provided, for example when password is on banned list
if (e.statusCode === 400) {
return this.setModalInputErrorMessage(this.$gettext(e.message))
}
this.showErrorMessage({
title: this.$gettext('Failed to create link'),
error: e
})
}
},
async updatePublicLink({ params }) {
try {
await this.updateLink({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,10 @@
</template>

<script lang="ts">
import { defineComponent, PropType } from 'vue'
import {
useAbility,
getDefaultLinkPermissions,
useStore,
ExpirationRules
} from '@ownclouders/web-pkg'
import { defineComponent, PropType, unref } from 'vue'
import { useDefaultLinkPermissions } from '@ownclouders/web-pkg'
import { useGettext } from 'vue3-gettext'
import { ExpirationRules } from '@ownclouders/web-pkg'
export default defineComponent({
name: 'CreateQuickLink',
Expand All @@ -45,15 +41,14 @@ export default defineComponent({
},
emits: ['createPublicLink'],
setup(props, { emit }) {
const store = useStore()
const ability = useAbility()
const { defaultLinkPermissions } = useDefaultLinkPermissions()
const { $gettext } = useGettext()
const createQuickLink = () => {
const emitData = {
link: {
name: $gettext('Link'),
permissions: getDefaultLinkPermissions({ ability, store }).toString(),
permissions: unref(defaultLinkPermissions).toString(),
expiration: props.expirationRules.enforced ? props.expirationRules.default : null,
quicklink: true,
password: false
Expand Down
78 changes: 40 additions & 38 deletions packages/web-pkg/src/components/CreateLinkModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -154,18 +154,20 @@ import {
useCapabilityFilesSharingPublicCanContribute,
useCapabilityFilesSharingPublicCanEdit,
useCapabilityFilesSharingPublicPasswordEnforcedFor,
useClientService,
useLoadingService,
usePasswordPolicyService,
useStore,
useEmbedMode,
useExpirationRules
useExpirationRules,
useDefaultLinkPermissions,
useCreateLink
} from '../composables'
import { formatRelativeDateFromDateTime, getDefaultLinkPermissions } from '../helpers'
import { formatRelativeDateFromDateTime } from '../helpers'
import {
LinkShareRoles,
Share,
ShareRole,
SpaceResource,
linkRoleContributorFolder,
linkRoleEditorFolder,
linkRoleInternalFolder,
Expand All @@ -177,17 +179,22 @@ import { Resource } from '@ownclouders/web-client'
export default defineComponent({
name: 'CreatePublicLinksModal',
props: {
resources: { type: Array as PropType<Resource[]>, required: true }
resources: { type: Array as PropType<Resource[]>, required: true },
space: { type: Object as PropType<SpaceResource>, default: undefined },
isQuickLink: { type: Boolean, default: false },
showMessages: { type: Boolean, default: true },
callbackFn: { type: Function, default: undefined }
},
setup(props, { expose }) {
setup(props) {
const store = useStore()
const { $gettext, current: currentLanguage } = useGettext()
const clientService = useClientService()
const loadingService = useLoadingService()
const ability = useAbility()
const passwordPolicyService = usePasswordPolicyService()
const { isEnabled: isEmbedEnabled, postMessage } = useEmbedMode()
const { expirationRules } = useExpirationRules()
const { defaultLinkPermissions } = useDefaultLinkPermissions()
const { createLink } = useCreateLink()
const hasPublicLinkEditing = useCapabilityFilesSharingPublicCanEdit()
const hasPublicLinkContribute = useCapabilityFilesSharingPublicCanContribute()
Expand All @@ -202,7 +209,7 @@ export default defineComponent({
const password = reactive({ value: '', error: undefined })
const selectedRole = ref<ShareRole>(
LinkShareRoles.getByBitmask(getDefaultLinkPermissions({ ability, store }), unref(isFolder))
LinkShareRoles.getByBitmask(unref(defaultLinkPermissions), unref(isFolder))
) as Ref<ShareRole>
const selectedExpiry = ref<DateTime>()
Expand Down Expand Up @@ -261,29 +268,16 @@ export default defineComponent({
const createLinks = () => {
return loadingService.addTask(() =>
Promise.allSettled<Share>(
props.resources.map((resource) => {
const params = {
name: $gettext('Link'),
expireDate: unref(selectedExpiry),
password: unref(password).value,
props.resources.map((resource) =>
createLink({
resource,
space: props.space,
quicklink: props.isQuickLink,
permissions: unref(selectedRole).bitmask(false),
spaceRef: resource.fileId,
storageId: resource.fileId || resource.id
}
let path = resource.path
// sharing a share root from the share jail -> use resource name as path
if (resource.isReceivedShare() && path === '/') {
path = `/${resource.name}`
}
return store.dispatch('Files/addLink', {
path: resource.path,
client: clientService.owncloudSdk,
params,
storageId: resource.fileId || resource.id
password: unref(password).value,
expireDate: unref(selectedExpiry)
})
})
)
)
)
}
Expand All @@ -304,12 +298,14 @@ export default defineComponent({
(val): val is PromiseFulfilledResult<Share> => val.status === 'fulfilled'
)
if (succeeded.length) {
store.dispatch('showMessage', {
title:
succeeded.length > 1
? $gettext('Links have been created successfully')
: $gettext('Link has been created successfully')
})
if (props.showMessages) {
store.dispatch('showMessage', {
title:
succeeded.length > 1
? $gettext('Links have been created successfully')
: $gettext('Link has been created successfully')
})
}
if (unref(isEmbedEnabled)) {
postMessage<string[]>(
Expand All @@ -323,13 +319,19 @@ export default defineComponent({
if (failed.length) {
failed.forEach((error) => {
console.error(error)
store.dispatch('showErrorMessage', {
title: $gettext('Some links could not be created'),
error
})
if (props.showMessages) {
store.dispatch('showErrorMessage', {
title: $gettext('Some links could not be created'),
error
})
}
})
}
if (props.callbackFn) {
props.callbackFn(result)
}
return store.dispatch('hideModal')
}
Expand Down
Loading

0 comments on commit f684724

Please sign in to comment.