diff options
author | Raimund Schlüßler <raimund.schluessler@mailbox.org> | 2020-04-30 11:42:20 +0300 |
---|---|---|
committer | Raimund Schlüßler <raimund.schluessler@mailbox.org> | 2020-04-30 19:37:43 +0300 |
commit | fd1e90a244b963a33f7aa33a33c9d53f0966cc69 (patch) | |
tree | d50b05de4bdb0967c719b2b47d2508a82383a218 /src | |
parent | 740903e8838a044f5c548be7f4982da861b1f03d (diff) |
Allow sharing with circles
Signed-off-by: Raimund Schlüßler <raimund.schluessler@mailbox.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/components/AppNavigation/CalendarShare.vue | 161 | ||||
-rw-r--r-- | src/store/calendars.js | 19 |
2 files changed, 148 insertions, 32 deletions
diff --git a/src/components/AppNavigation/CalendarShare.vue b/src/components/AppNavigation/CalendarShare.vue index b3cf6fd8..c77dfb68 100644 --- a/src/components/AppNavigation/CalendarShare.vue +++ b/src/components/AppNavigation/CalendarShare.vue @@ -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 CalendarSharee from './CalendarSharee' import client from '../../services/cdav' -import Multiselect from '@nextcloud/vue/dist/Components/Multiselect' -import CalendarSharee from './CalendarSharee' -// import debounce from 'debounce' +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, + })) }, }, } diff --git a/src/store/calendars.js b/src/store/calendars.js index 65f72d76..c3f3f7ed 100644 --- a/src/store/calendars.js +++ b/src/store/calendars.js @@ -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 }) }, } |