Allow sharing with circles
Signed-off-by: Raimund Schlüßler <raimund.schluessler@mailbox.org>
This commit is contained in:
parent
740903e883
commit
fd1e90a244
|
@ -1,3 +1,5 @@
|
|||
@include icon-black-white('circle', 'tasks', 1);
|
||||
|
||||
/**
|
||||
* rules for app-navigation
|
||||
*/
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 57 57" width="64" height="64"><path d="M7 29A21 21 0 0 1 29 7m10 40a21 21 0 0 1-29-8m29-29a21 21 0 0 1 8 29" fill="none" stroke="#000" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><circle cx="29" cy="7" r="7"/><circle cx="39" cy="-10" r="7" transform="rotate(90)"/><circle cx="39" cy="-47" r="7" transform="rotate(90)"/></svg>
|
After Width: | Height: | Size: 400 B |
|
@ -34,6 +34,7 @@
|
|||
"@vue/test-utils": "^1.0.0-beta.33",
|
||||
"cdav-library": "github:nextcloud/cdav-library",
|
||||
"color-convert": "^2.0.1",
|
||||
"debounce": "^1.2.0",
|
||||
"ical.js": "~1.4.0",
|
||||
"jstimezonedetect": "",
|
||||
"linkify-it": "~2.2.0",
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
<!--
|
||||
@copyright Copyright (c) 2018 Team Popcorn <teampopcornberlin@gmail.com>
|
||||
@copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
|
||||
@copyright Copyright (c) 2019 Jakob Röhrl <jakob.roehrl@web.de>
|
||||
@copyright Copyright (c) 2020 Raimund Schlüßler <raimund.schluessler@mailbox.org>
|
||||
|
||||
@author Team Popcorn <teampopcornberlin@gmail.com>
|
||||
@author Georg Ehrke <oc.list@georgehrke.com>
|
||||
@author Jakob Röhrl <jakob.roehrl@web.de>
|
||||
@author Raimund Schlüßler <raimund.schluessler@mailbox.org>
|
||||
|
||||
@license GNU AGPL version 3 or any later version
|
||||
|
@ -39,7 +44,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
track-by="user"
|
||||
label="user"
|
||||
@search-change="findSharee"
|
||||
@input="shareCalendar" />
|
||||
@change="shareCalendar" />
|
||||
</li>
|
||||
<!-- list of user or groups calendar is shared with -->
|
||||
<CalendarSharee v-for="sharee in calendar.shares"
|
||||
|
@ -51,11 +56,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import client from '../../services/cdav'
|
||||
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
|
||||
|
||||
import CalendarSharee from './CalendarSharee'
|
||||
// import debounce from 'debounce'
|
||||
import client from '../../services/cdav'
|
||||
|
||||
import HttpClient from '@nextcloud/axios'
|
||||
import { generateOcsUrl } from '@nextcloud/router'
|
||||
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
|
||||
import debounce from 'debounce'
|
||||
|
||||
export default {
|
||||
name: 'CalendarShare',
|
||||
|
@ -95,48 +102,148 @@ export default {
|
|||
* Share calendar
|
||||
*
|
||||
* @param {Object} data destructuring object
|
||||
* @param {string} data.user the userId
|
||||
* @param {string} data.displayName the displayName
|
||||
* @param {string} data.uri the sharing principalScheme uri
|
||||
* @param {boolean} data.isGroup is this a group ?
|
||||
* @param {String} data.user the userId
|
||||
* @param {String} data.displayName the displayName
|
||||
* @param {String} data.uri the sharing principalScheme uri
|
||||
* @param {Boolean} data.isGroup is this a group ?
|
||||
* @param {Boolean} data.isCircle is this a circle?
|
||||
*/
|
||||
shareCalendar({ user, displayName, uri, isGroup }) {
|
||||
shareCalendar({ user, displayName, uri, isGroup, isCircle }) {
|
||||
const calendar = this.calendar
|
||||
uri = decodeURI(uri)
|
||||
user = decodeURI(user)
|
||||
this.$store.dispatch('shareCalendar', { calendar, user, displayName, uri, isGroup })
|
||||
this.$store.dispatch('shareCalendar', { calendar, user, displayName, uri, isGroup, isCircle })
|
||||
},
|
||||
|
||||
/**
|
||||
* Use the cdav client call to find matches to the query from the existing Users & Groups
|
||||
*
|
||||
* @param {string} query The query string
|
||||
* @param {String} query
|
||||
*/
|
||||
async findSharee(query) {
|
||||
findSharee: debounce(async function(query) {
|
||||
const hiddenPrincipalSchemes = []
|
||||
const hiddenUrls = []
|
||||
this.calendar.shares.forEach((share) => {
|
||||
hiddenPrincipalSchemes.push(share.uri)
|
||||
})
|
||||
if (this.$store.getters.getCurrentUserPrincipal) {
|
||||
hiddenUrls.push(this.$store.getters.getCurrentUserPrincipal.url)
|
||||
}
|
||||
if (this.calendar.owner) {
|
||||
hiddenUrls.push(this.calendar.owner)
|
||||
}
|
||||
|
||||
this.isLoading = true
|
||||
this.usersOrGroups = []
|
||||
|
||||
if (query.length > 0) {
|
||||
const results = await client.principalPropertySearchByDisplayname(query)
|
||||
this.usersOrGroups = results.reduce((list, result) => {
|
||||
if (['GROUP', 'INDIVIDUAL'].indexOf(result.calendarUserType) > -1
|
||||
&& !this.calendar.shares.some((share) => share.uri === result.principalScheme)) {
|
||||
const isGroup = result.calendarUserType === 'GROUP'
|
||||
list.push({
|
||||
user: result[isGroup ? 'groupId' : 'userId'],
|
||||
displayName: result.displayname,
|
||||
icon: isGroup ? 'icon-group' : 'icon-user',
|
||||
uri: result.principalScheme,
|
||||
isGroup,
|
||||
})
|
||||
}
|
||||
return list
|
||||
}, [])
|
||||
const davPromise = this.findShareesFromDav(query, hiddenPrincipalSchemes, hiddenUrls)
|
||||
const ocsPromise = this.findShareesFromCircles(query, hiddenPrincipalSchemes, hiddenUrls)
|
||||
|
||||
const [davResults, ocsResults] = await Promise.all([davPromise, ocsPromise])
|
||||
this.usersOrGroups = [
|
||||
...davResults,
|
||||
...ocsResults,
|
||||
]
|
||||
|
||||
this.isLoading = false
|
||||
this.inputGiven = true
|
||||
} else {
|
||||
this.inputGiven = false
|
||||
this.isLoading = false
|
||||
}
|
||||
}, 500),
|
||||
/**
|
||||
*
|
||||
* @param {String} query The search query
|
||||
* @param {String[]} hiddenPrincipals A list of principals to exclude from search results
|
||||
* @param {String[]} hiddenUrls A list of urls to exclude from search results
|
||||
* @returns {Promise<Object[]>}
|
||||
*/
|
||||
async findShareesFromDav(query, hiddenPrincipals, hiddenUrls) {
|
||||
let results
|
||||
try {
|
||||
results = await client.principalPropertySearchByDisplayname(query)
|
||||
} catch (error) {
|
||||
return []
|
||||
}
|
||||
|
||||
return results.reduce((list, result) => {
|
||||
if (hiddenPrincipals.includes(decodeURI(result.principalScheme))) {
|
||||
return list
|
||||
}
|
||||
if (hiddenUrls.includes(result.url)) {
|
||||
return list
|
||||
}
|
||||
|
||||
// Don't show resources and rooms
|
||||
if (!['GROUP', 'INDIVIDUAL'].includes(result.calendarUserType)) {
|
||||
return list
|
||||
}
|
||||
|
||||
const isGroup = result.calendarUserType === 'GROUP'
|
||||
list.push({
|
||||
user: result[isGroup ? 'groupId' : 'userId'],
|
||||
displayName: result.displayname,
|
||||
icon: isGroup ? 'icon-group' : 'icon-user',
|
||||
uri: result.principalScheme,
|
||||
isGroup,
|
||||
isCircle: false,
|
||||
isNoUser: isGroup,
|
||||
search: query,
|
||||
})
|
||||
return list
|
||||
}, [])
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {String} query The search query
|
||||
* @param {String[]} hiddenPrincipals A list of principals to exclude from search results
|
||||
* @param {String[]} hiddenUrls A list of urls to exclude from search results
|
||||
* @returns {Promise<Object[]>}
|
||||
*/
|
||||
async findShareesFromCircles(query, hiddenPrincipals, hiddenUrls) {
|
||||
let results
|
||||
try {
|
||||
results = await HttpClient.get(generateOcsUrl('apps/files_sharing/api/v1') + 'sharees', {
|
||||
params: {
|
||||
format: 'json',
|
||||
search: query,
|
||||
perPage: 200,
|
||||
itemType: 'principals',
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
return []
|
||||
}
|
||||
|
||||
if (results.data.ocs.meta.status === 'failure') {
|
||||
return []
|
||||
}
|
||||
let circles = []
|
||||
if (Array.isArray(results.data.ocs.data.circles)) {
|
||||
circles = circles.concat(results.data.ocs.data.circles)
|
||||
}
|
||||
if (Array.isArray(results.data.ocs.data.exact.circles)) {
|
||||
circles = circles.concat(results.data.ocs.data.exact.circles)
|
||||
}
|
||||
|
||||
if (circles.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
return circles.filter((circle) => {
|
||||
return !hiddenPrincipals.includes('principal:principals/circles/' + circle.value.shareWith)
|
||||
}).map(circle => ({
|
||||
user: circle.label,
|
||||
displayName: circle.label,
|
||||
icon: 'icon-circle',
|
||||
uri: 'principal:principals/circles/' + circle.value.shareWith,
|
||||
isGroup: false,
|
||||
isCircle: true,
|
||||
isNoUser: true,
|
||||
search: query,
|
||||
}))
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -127,14 +127,20 @@ export function mapDavCollectionToCalendar(calendar, currentUserPrincipal) {
|
|||
*/
|
||||
export function mapDavShareeToSharee(sharee) {
|
||||
const id = sharee.href.split('/').slice(-1)[0]
|
||||
const name = sharee['common-name']
|
||||
let name = sharee['common-name']
|
||||
? sharee['common-name']
|
||||
: id
|
||||
: sharee.href
|
||||
|
||||
if (sharee.href.startsWith('principal:principals/groups/') && name === sharee.href) {
|
||||
name = sharee.href.substr(28)
|
||||
}
|
||||
|
||||
return {
|
||||
displayName: name,
|
||||
id,
|
||||
writeable: sharee.access[0].endsWith('read-write'),
|
||||
isGroup: sharee.href.startsWith('principal:principals/groups/'),
|
||||
isCircle: sharee.href.startsWith('principal:principals/circles/'),
|
||||
uri: sharee.href,
|
||||
}
|
||||
}
|
||||
|
@ -391,14 +397,16 @@ const mutations = {
|
|||
* @param {String} data.displayName The displayName
|
||||
* @param {String} data.uri The sharing principalScheme uri
|
||||
* @param {Boolean} data.isGroup Is this a group ?
|
||||
* @param {Boolean} data.isCircle Is this a circle?
|
||||
*/
|
||||
shareCalendar(state, { calendar, user, displayName, uri, isGroup }) {
|
||||
shareCalendar(state, { calendar, user, displayName, uri, isGroup, isCircle }) {
|
||||
calendar = state.calendars.find(search => search.id === calendar.id)
|
||||
const newSharee = {
|
||||
displayName,
|
||||
id: user,
|
||||
writeable: false,
|
||||
isGroup,
|
||||
isCircle,
|
||||
uri,
|
||||
}
|
||||
if (!calendar.shares.some((share) => share.uri === uri)) {
|
||||
|
@ -686,11 +694,12 @@ const actions = {
|
|||
* @param {String} data.displayName The displayName
|
||||
* @param {String} data.uri The sharing principalScheme uri
|
||||
* @param {Boolean} data.isGroup Is this a group ?
|
||||
* @param {Boolean} data.isCircle Is this a circle?
|
||||
*/
|
||||
async shareCalendar(context, { calendar, user, displayName, uri, isGroup }) {
|
||||
async shareCalendar(context, { calendar, user, displayName, uri, isGroup, isCircle }) {
|
||||
// Share calendar with entered group or user
|
||||
await calendar.dav.share(uri)
|
||||
context.commit('shareCalendar', { calendar, user, displayName, uri, isGroup })
|
||||
context.commit('shareCalendar', { calendar, user, displayName, uri, isGroup, isCircle })
|
||||
},
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue