Skip to content

Commit

Permalink
Implement people sharing for spaces
Browse files Browse the repository at this point in the history
  • Loading branch information
JammingBen committed Feb 28, 2022
1 parent b47acff commit 365225c
Show file tree
Hide file tree
Showing 16 changed files with 630 additions and 122 deletions.
11 changes: 11 additions & 0 deletions changelog/unreleased/enhancement-spaces-people-sharing
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Enhancement: Implement people sharing for spaces

Spaces can now be shared with other people. This change specifically includes:

* listing all members who have access to a space (possible for all space members)
* adding members to a space and giving them dedicated roles (possible for managers only)
* editing the role of members (possible for managers only)
* removing members from a space (possible for managers only)

https://github.com/owncloud/web/pull/?
https://github.com/owncloud/web/issues/6283
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@
/>
</div>
<div v-if="hasPeopleShares || hasLinkShares" class="oc-flex oc-flex-middle oc-mb-m">
<oc-icon v-if="hasPeopleShares" name="group" class="oc-mr-s" />
<oc-button
v-if="hasPeopleShares"
appearance="raw"
:aria-label="$gettext('Open the people panel')"
@click="expandPeoplePanel"
>
<oc-icon name="group" class="oc-mr-s" />
</oc-button>
<oc-icon v-if="hasLinkShares" name="link" class="oc-mr-s" />
<span class="oc-text-small" v-text="shareLabel" />
</div>
Expand All @@ -33,7 +40,7 @@
<tr>
<th scope="col" class="oc-pr-s" v-text="$gettext('Manager')" />
<td>
<span v-if="!loadOwnersTask.isRunning" v-text="ownerUsernames" />
<span v-text="ownerUsernames" />
</td>
</tr>
<tr>
Expand All @@ -50,11 +57,10 @@
import { ref } from '@vue/composition-api'
import Mixins from '../../../mixins'
import MixinResources from '../../../mixins/resources'
import { mapGetters } from 'vuex'
import { mapActions, mapGetters } from 'vuex'
import { useTask } from 'vue-concurrency'
import { buildWebDavSpacesPath } from '../../../helpers/resources'
import { useStore } from 'web-pkg/src/composables'
import { clientService } from 'web-pkg/src/services'
import { spaceManager } from '../../../helpers/share'
import SpaceQuota from '../../SpaceQuota.vue'
export default {
Expand All @@ -66,13 +72,8 @@ export default {
return $gettext('Details')
},
setup() {
const store = useStore()
const spaceImage = ref('')
const owners = ref([])
const graphClient = clientService.graphAuthenticated(
store.getters.configuration.server,
store.getters.getToken
)
const loadImageTask = useTask(function* (signal, ref) {
if (!ref.space?.spaceImageData) {
Expand All @@ -87,24 +88,14 @@ export default {
spaceImage.value = Buffer.from(fileContents).toString('base64')
})
const loadOwnersTask = useTask(function* (signal, ref) {
const promises = []
for (const userId of ref.ownerUserIds) {
promises.push(graphClient.users.getUser(userId))
}
if (promises.length > 0) {
yield Promise.all(promises).then((resolvedData) => {
resolvedData.forEach((response) => {
owners.value.push(response.data)
})
})
}
})
return { loadImageTask, loadOwnersTask, spaceImage, owners }
return { loadImageTask, spaceImage, owners }
},
computed: {
...mapGetters('Files', [
'highlightedFile',
'currentFileOutgoingCollaborators',
'currentFileOutgoingLinks'
]),
...mapGetters(['user']),
space() {
Expand All @@ -116,46 +107,31 @@ export default {
lastModifyDate() {
return this.formDateFromISO(this.space.mdate)
},
ownerUserIds() {
const permissions = this.space.spacePermissions?.filter((permission) =>
permission.roles.includes('manager')
)
if (!permissions.length) {
return []
}
const userIds = permissions.reduce((acc, item) => {
const ids = item.grantedTo.map((user) => user.user.id)
acc = acc.concat(ids)
return acc
}, [])
return [...new Set(userIds)]
},
ownerUsernames() {
const userId = this.user?.id
return this.owners
.map((owner) => {
if (owner.onPremisesSamAccountName === userId) {
return this.currentFileOutgoingCollaborators
.filter((share) => share.role.name === spaceManager.name)
.map((share) => {
if (share.collaborator.onPremisesSamAccountName === userId) {
return this.$gettextInterpolate(this.$gettext('%{displayName} (me)'), {
displayName: owner.displayName
displayName: share.collaborator.displayName
})
}
return owner.displayName
return share.collaborator.displayName
})
.join(', ')
},
hasPeopleShares() {
return false // @TODO
return this.currentFileOutgoingCollaborators.length > 1
},
hasLinkShares() {
return false // @TODO
return this.currentFileOutgoingLinks.length > 1
},
peopleShareCount() {
return 0 // @TODO
return this.currentFileOutgoingCollaborators.length
},
linkShareCount() {
return 0 // @TODO
return this.currentFileOutgoingLinks.length
},
shareLabel() {
let peopleString, linksString
Expand Down Expand Up @@ -203,7 +179,16 @@ export default {
},
mounted() {
this.loadImageTask.perform(this)
this.loadOwnersTask.perform(this)
},
methods: {
...mapActions('Files/sidebar', {
setSidebarPanel: 'setActivePanel',
closeSidebar: 'close'
}),
expandPeoplePanel() {
this.setSidebarPanel('space-share-item')
}
}
}
</script>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<template>
<div
:data-testid="`collaborator-${isUser ? 'user' : 'group'}-item-${share.collaborator.name}`"
class="files-collaborators-collaborator oc-flex oc-flex-middle oc-py-xs"
:data-testid="`collaborator-${isUser || isSpace ? 'user' : 'group'}-item-${
share.collaborator.name
}`"
class="files-collaborators-collaborator oc-flex oc-flex-middle oc-py-xs oc-flex-between"
>
<div class="oc-width-2-3 oc-flex oc-flex-middle" style="gap: 10px">
<avatar-image
v-if="isUser"
v-if="isUser || isSpace"
:userid="share.collaborator.name"
:user-name="share.collaborator.displayName"
:width="48"
Expand Down Expand Up @@ -64,7 +66,8 @@
:share-id="share.id"
:existing-permissions="share.customPermissions"
:existing-role="share.role"
:allow-share-permission="!isOcis"
:collaborator-name="share.collaborator.name"
:allow-share-permission="!isOcis || isSpace"
class="files-collaborators-collaborator-role"
@optionChange="shareRoleChanged"
/>
Expand All @@ -77,6 +80,9 @@
@removeShare="removeShare"
/>
</div>
<div v-else>
<span class="oc-mr-xs" v-text="share.role.label" />
</div>
</div>
</template>

Expand Down Expand Up @@ -126,6 +132,10 @@ export default {
return this.shareType === ShareTypes.user
},
isSpace() {
return this.shareType === ShareTypes.space
},
shareTypeText() {
return this.$gettext(this.shareType.label)
},
Expand All @@ -135,6 +145,11 @@ export default {
},
shareDisplayName() {
if (this.user.id === this.share.collaborator.name) {
return this.$gettextInterpolate(this.$gettext('%{collaboratorName} (me)'), {
collaboratorName: this.share.collaborator.displayName
})
}
return this.share.collaborator.displayName
},
Expand Down Expand Up @@ -243,7 +258,9 @@ export default {
saveShareChanges({ role, permissions, expirationDate }) {
const bitmask = role.hasCustomPermissions
? SharePermissions.permissionsToBitmask(permissions)
: SharePermissions.permissionsToBitmask(role.permissions(!this.isOcis))
: SharePermissions.permissionsToBitmask(
role.permissions(!this.isOcis || this.shareType === ShareTypes.space)
)
this.changeShare({
client: this.$client,
share: this.share,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
:class="collaboratorClass"
>
<avatar-image
v-if="isUser"
v-if="isUser || isSpace"
class="oc-mr-s"
:width="48"
:userid="item.value.shareWith"
Expand Down Expand Up @@ -67,6 +67,10 @@ export default {
return this.shareType === ShareTypes.user
},
isSpace() {
return this.shareType === ShareTypes.space
},
isGroup() {
return this.shareType === ShareTypes.group
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<div class="oc-flex oc-flex-middle oc-flex-between oc-mb-l">
<role-dropdown
:resource="highlightedFile"
:allow-share-permission="!isOcis"
:allow-share-permission="!isOcis || resourceIsSpace"
@optionChange="collaboratorRoleChanged"
/>
<expiration-datepicker
Expand Down Expand Up @@ -79,7 +79,12 @@ import AutocompleteItem from './AutocompleteItem.vue'
import RoleDropdown from '../RoleDropdown.vue'
import RecipientContainer from './RecipientContainer.vue'
import ExpirationDatepicker from './ExpirationDatepicker.vue'
import { PeopleShareRoles, SharePermissions, ShareTypes } from '../../../../helpers/share'
import {
PeopleShareRoles,
SharePermissions,
ShareTypes,
SpacePeopleShareRoles
} from '../../../../helpers/share'
export default {
name: 'InviteCollaboratorForm',
Expand Down Expand Up @@ -124,11 +129,20 @@ export default {
},
selectedCollaboratorsLabel() {
return this.$gettext('Invite')
},
resourceIsSpace() {
return this.highlightedFile.type === 'space'
}
},
mounted() {
this.fetchRecipients = debounce(this.fetchRecipients, 500)
this.selectedRole = PeopleShareRoles.list(this.highlightedFile.isFolder)[0]
if (this.resourceIsSpace) {
this.selectedRole = SpacePeopleShareRoles.all[0]
} else {
this.selectedRole = PeopleShareRoles.list(this.highlightedFile.isFolder)[0]
}
},
methods: {
Expand All @@ -142,9 +156,15 @@ export default {
1,
this.configuration.options.sharingRecipientsPerPage
)
const shareType = this.resourceIsSpace ? ShareTypes.space.value : ShareTypes.user.value
const users = recipients.exact.users
.concat(recipients.users)
.filter((user) => user.value.shareWith !== this.user.id)
.map((result) => {
// Inject the correct share type here as the response has always type "user"
return { ...result, value: { ...result.value, shareType } }
})
const groups = recipients.exact.groups.concat(recipients.groups)
const remotes = recipients.exact.remotes.concat(recipients.remotes)
Expand Down Expand Up @@ -229,15 +249,19 @@ export default {
saveQueue.add(() => {
const bitmask = this.selectedRole.hasCustomPermissions
? SharePermissions.permissionsToBitmask(this.customPermissions)
: SharePermissions.permissionsToBitmask(this.selectedRole.permissions(!this.isOcis))
: SharePermissions.permissionsToBitmask(
this.selectedRole.permissions(!this.isOcis || this.resourceIsSpace)
)
this.addShare({
client: this.$client,
path: this.highlightedFile.path,
$gettext: this.$gettext,
shareWith: collaborator.value.shareWith,
displayName: collaborator.label,
shareType: collaborator.value.shareType,
permissions: bitmask,
expirationDate: this.expirationDate
expirationDate: this.expirationDate,
spaceId: this.resourceIsSpace ? this.highlightedFile.id : null
})
})
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ export default {
formattedRecipient: {
name: this.recipient.label,
icon: this.getRecipientIcon(),
hasAvatar: this.recipient.value.shareType === ShareTypes.user.value,
hasAvatar:
this.recipient.value.shareType === ShareTypes.user.value ||
this.recipient.value.shareType === ShareTypes.space.value,
isLoadingAvatar: true
}
}
Expand All @@ -57,10 +59,7 @@ export default {
},
async created() {
if (
this.capabilities.files_sharing.user.profile_picture &&
this.recipient.value.shareType === ShareTypes.user.value
) {
if (this.capabilities.files_sharing.user.profile_picture && this.hasAvatar) {
try {
this.formattedRecipient.avatar = await avatarUrl({
server: this.configuration.server,
Expand Down
Loading

0 comments on commit 365225c

Please sign in to comment.