Skip to content

Commit

Permalink
feat(sharing): Wip
Browse files Browse the repository at this point in the history
Todo: Manage password and TTL deletion
  • Loading branch information
Merkur39 committed Jan 10, 2025
1 parent c80133d commit c7f254d
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 78 deletions.
2 changes: 2 additions & 0 deletions packages/cozy-sharing/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
"recipients": {
"you": "You",
"anyoneWithTheLink": "Anyone with the link",
"linkWithPassword": "Anyone with a password",
"expires": "Until %{date}",
"accessCount": "%{count} people have access"
},
"create-cozy": "Create |||| Create my cozy",
Expand Down
2 changes: 2 additions & 0 deletions packages/cozy-sharing/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
"recipients": {
"you": "Vous",
"anyoneWithTheLink": "N'importe qui avec le lien",
"linkWithPassword": "N'importe qui avec un mot de passe",
"expires": "Jusqu'au %{date}",
"accessCount": "%{count} personnes y ont accès"
},
"create-cozy": "Créer |||| Créer mon Cozy",
Expand Down
8 changes: 5 additions & 3 deletions packages/cozy-sharing/src/SharingProvider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -335,19 +335,21 @@ export class SharingProvider extends Component {
*
* @return {Array}
*/
updateDocumentPermissions = async (document, newVerbs) => {
updateDocumentPermissions = async (document, options) => {
const { verbs, expiresAt, password } = options
const permissions = getDocumentPermissions(this.state, document.id)

const responses = await Promise.all(
permissions.map(async permissionDocument => {
const updatedPermissions = permissionDocument.attributes.permissions
Object.keys(updatedPermissions).map(permType => {
updatedPermissions[permType].verbs = newVerbs
updatedPermissions[permType].verbs = verbs
})

const resp = await this.permissionCol.add(
permissionDocument,
updatedPermissions
updatedPermissions,
{ expiresAt, password }
)
this.dispatch(updateSharingLink(resp))
return resp
Expand Down
33 changes: 29 additions & 4 deletions packages/cozy-sharing/src/components/Recipient/LinkRecipient.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,39 @@ import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'

import LinkRecipientPermissions from './LinkRecipientPermissions'
import RecipientConfirm from './RecipientConfirm'
import {
checkIsPermissionHasPassword,
getPermissionExpiresDate
} from '../../helpers/permissions'
import { FADE_IN_DURATION } from '../../helpers/recipients'
import { useSharingContext } from '../../hooks/useSharingContext'
import styles from '../../styles/recipient.styl'

const LinkRecipient = props => {
const { t } = useI18n()
const { t, f, lang } = useI18n()
const { isMobile } = useBreakpoints()
const { getDocumentPermissions } = useSharingContext()

const { recipientConfirmationData, verifyRecipient, link, fadeIn } = props
const { recipientConfirmationData, verifyRecipient, link, fadeIn, document } =
props

const permissions = getDocumentPermissions(document._id)
const hasPassword = checkIsPermissionHasPassword(permissions)
const expiresDate = getPermissionExpiresDate(permissions)
const dateFormatted = f(
expiresDate,
lang === 'fr' ? 'dd/LL/yyyy' : 'LL/dd/yyyy'
)

const textPrimary = hasPassword
? t('Share.recipients.linkWithPassword')
: t('Share.recipients.anyoneWithTheLink')

const textSecondary = expiresDate
? t('Share.recipients.expires', {
date: dateFormatted
})
: link

const RightPart = recipientConfirmationData ? (
<RecipientConfirm
Expand All @@ -43,10 +68,10 @@ const LinkRecipient = props => {
<ListItemText
primary={
<Typography className="u-ellipsis" variant="body1">
{t('Share.recipients.anyoneWithTheLink')}
{textPrimary}
</Typography>
}
secondary={link}
secondary={textSecondary}
/>
{RightPart}
</ListItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ export const BoxPassword = ({
<TextField
inputRef={inputRef}
label={t('BoxPassword.label')}
// placeholder="****"
// InputLabelProps={{
// shrink: true
// }}
value={password}
error={displayHelper && !!helperText}
helperText={displayHelper && helperText}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import { addDays } from 'date-fns'
import PropTypes from 'prop-types'
import React, { useState } from 'react'

import { useClient } from 'cozy-client'
import { getSharingLink as makeSharingLink } from 'cozy-client/dist/models/sharing'
import { isMobile } from 'cozy-device-helper'
import { generateWebLink, useClient } from 'cozy-client'
import Button from 'cozy-ui/transpiled/react/Buttons'
import { ConfirmDialog } from 'cozy-ui/transpiled/react/CozyDialogs'
import Icon from 'cozy-ui/transpiled/react/Icon'
Expand All @@ -14,14 +12,17 @@ import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
import { ShareRestrictionContentModal } from './ShareRestrictionContentModal'
import {
copyToClipboard,
forwardFile,
updatePermissions,
makeTTL,
READ_ONLY_PERMS,
WRITE_PERMS,
revokePermissions
revokePermissions,
createPermissions
} from './helpers'
import { checkIsReadOnlyPermissions } from '../../helpers/permissions'
import {
checkIsPermissionHasExpiresDate,
checkIsPermissionHasPassword,
checkIsReadOnlyPermissions,
getPermissionExpiresDate
} from '../../helpers/permissions'
import { useSharingContext } from '../../hooks/useSharingContext'

const PASSWORD_MIN_LENGTH = 4
Expand All @@ -31,11 +32,8 @@ export const ShareRestrictionModal = ({ file, onClose }) => {
const { t } = useI18n()
const { showAlert } = useAlert()
const [password, setPassword] = useState('')
const [selectedDate, setSelectedDate] = useState(addDays(new Date(), 30))
const [isValidDate, setIsValidDate] = useState(true)
const [isValidPassword, setIsValidPassword] = useState(true)
const [dateToggle, setDateToggle] = useState(true)
const [passwordToggle, setPasswordToggle] = useState(false)
const [loading, setLoading] = useState(false)

const {
Expand All @@ -50,14 +48,22 @@ export const ShareRestrictionModal = ({ file, onClose }) => {
const hasSharingLink = getSharingLink(file._id) !== null
const permissions = getDocumentPermissions(file._id)
const isReadOnlyPermissions = checkIsReadOnlyPermissions(permissions)

const hasPassword = checkIsPermissionHasPassword(permissions)
const hasExpiresDate = checkIsPermissionHasExpiresDate(permissions)
const expiresDate = getPermissionExpiresDate(permissions)
const defaultDate = expiresDate
? new Date(expiresDate)
: addDays(new Date(), 30)

const [selectedDate, setSelectedDate] = useState(defaultDate)
const [dateToggle, setDateToggle] = useState(
permissions.length > 0 ? hasExpiresDate : true
)
const [passwordToggle, setPasswordToggle] = useState(hasPassword)
const [editingRights, setEditingRights] = useState(
isReadOnlyPermissions || permissions.length === 0 ? 'readOnly' : 'write'
)

const isDesktopOrMobileWithoutShareAPI =
(isMobile() && !navigator.share) || !isMobile()

const helperTextPassword = !isValidPassword
? t('ShareRestrictionModal.invalidPasswordMessage', {
smart_count: PASSWORD_MIN_LENGTH - password.length
Expand All @@ -73,41 +79,47 @@ export const ShareRestrictionModal = ({ file, onClose }) => {
setLoading(true)
// If the file is not shared, we create a new sharing link
if (!hasSharingLink) {
const verbs = editingRights === 'readOnly' ? READ_ONLY_PERMS : WRITE_PERMS
await shareByLink(file, { verbs })
const url = getSharingLink(file._id)
await copyToClipboard(url, { t, showAlert })
onClose()
return
}

await updatePermissions({
file,
t,
editingRights,
documentType,
updateDocumentPermissions,
showAlert
})

const ttl = makeTTL(dateToggle && selectedDate)
if (isDesktopOrMobileWithoutShareAPI) {
const url = await makeSharingLink(client, [file._id], {
const ttl = makeTTL(dateToggle && selectedDate)
const { data: perms } = await createPermissions({
file,
t,
ttl,
password
password,
editingRights,
documentType,
shareByLink,
showAlert
})
const url = generateWebLink({
cozyUrl: client.getStackClient().uri,
searchParams: [['sharecode', perms.attributes.shortcodes.code]],
pathname: '/public',
slug: 'drive',
subDomainType: client.capabilities.flat_subdomains ? 'flat' : 'nested'
})
await copyToClipboard(url, { t, showAlert })
onClose()
} else {
await forwardFile({
client,
const [{ data: perms }] = await updatePermissions({
file,
t,
ttl,
expiresAt: selectedDate,
password,
editingRights,
documentType,
updateDocumentPermissions,
showAlert
})
const url = generateWebLink({
cozyUrl: client.getStackClient().uri,
searchParams: [['sharecode', perms.attributes.shortcodes.code]],
pathname: '/public',
slug: 'drive',
subDomainType: client.capabilities.flat_subdomains ? 'flat' : 'nested'
})
await copyToClipboard(url, { t, showAlert })
onClose()
}
onClose()
}

const handleRevokeLink = async () => {
Expand Down
119 changes: 88 additions & 31 deletions packages/cozy-sharing/src/components/ShareRestrictionModal/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,51 @@ export const forwardFile = async ({
}
}

/**
* createPermissions - Create the permissions of a file
* @param {object} options
* @param {import('cozy-client/types/types').IOCozyFile} options.file File to update permissions
* @param {Function} options.t i18n function
* @param {Date|string} options.ttl - Time to live of the sharing link
* @param {string} options.password - Password
* @param {'readOnly'|'write'} options.editingRights - Editing rights
* @param {string} options.documentType - Type of the document
* @param {Function} options.shareByLink - Function to create permissions
* @param {Function} options.showAlert - Function to display an alert
*/
export const createPermissions = async ({
file,
t,
ttl,
password,
editingRights,
documentType,
shareByLink,
showAlert
}) => {
try {
const verbs = editingRights === 'readOnly' ? READ_ONLY_PERMS : WRITE_PERMS
return shareByLink(file, { verbs, ttl, password })
} catch (err) {
showAlert({
message: t(`${documentType}.share.shareByLink.permserror`),
severity: 'error',
variant: 'filled'
})
log.error(
"Error in 'readOnlyPermissionLink' function when trying to change permission",
err
)
}
}

/**
* updatePermissions - Updates the permissions of a file
* @param {object} options
* @param {import('cozy-client/types/types').IOCozyFile} options.file File to update permissions
* @param {Function} options.t i18n function
* @param {Date|string} options.expiresAt - Expiration date
* @param {string} options.password - Password
* @param {string} options.documentType - Type of the document
* @param {'readOnly'|'write'} options.editingRights - Editing rights
* @param {Function} options.updateDocumentPermissions - Function to update permissions
Expand All @@ -122,43 +162,60 @@ export const forwardFile = async ({
export const updatePermissions = async ({
file,
t,
expiresAt,
password,
editingRights,
documentType,
updateDocumentPermissions,
showAlert
}) => {
switch (editingRights) {
case 'readOnly':
try {
return updateDocumentPermissions(file, READ_ONLY_PERMS)
} catch (err) {
showAlert({
message: t(`${documentType}.share.shareByLink.permserror`),
severity: 'error',
variant: 'filled'
})
log.error(
"Error in 'readOnlyPermissionLink' function when trying to change permission",
err
)
}
break
case 'write':
try {
return updateDocumentPermissions(file, WRITE_PERMS)
} catch (err) {
showAlert({
message: t(`${documentType}.share.shareByLink.permserror`),
severity: 'error',
variant: 'filled'
})
log.error(
"Error in 'editPermissionLink' function when trying to change permission",
err
)
}
break
const verbs = editingRights === 'readOnly' ? READ_ONLY_PERMS : WRITE_PERMS
try {
return updateDocumentPermissions(file, { verbs, expiresAt, password })
} catch (err) {
showAlert({
message: t(`${documentType}.share.shareByLink.permserror`),
severity: 'error',
variant: 'filled'
})
log.error(
"Error in 'updateDocumentPermissions' function when trying to change permission",
err
)
}

// switch (editingRights) {
// case 'readOnly':
// try {
// return updateDocumentPermissions(file, READ_ONLY_PERMS)
// } catch (err) {
// showAlert({
// message: t(`${documentType}.share.shareByLink.permserror`),
// severity: 'error',
// variant: 'filled'
// })
// log.error(
// "Error in 'readOnlyPermissionLink' function when trying to change permission",
// err
// )
// }
// break
// case 'write':
// try {
// return updateDocumentPermissions(file, WRITE_PERMS)
// } catch (err) {
// showAlert({
// message: t(`${documentType}.share.shareByLink.permserror`),
// severity: 'error',
// variant: 'filled'
// })
// log.error(
// "Error in 'editPermissionLink' function when trying to change permission",
// err
// )
// }
// break
// }
}

/**
Expand Down
Loading

0 comments on commit c7f254d

Please sign in to comment.