866 lines
27 KiB
JavaScript
866 lines
27 KiB
JavaScript
/**
|
|
* @copyright Copyright (c) 2019 Georg Ehrke
|
|
* @copyright Copyright (c) 2019 John Molakvoæ
|
|
* @copyright Copyright (c) 2019 Thomas Citharel
|
|
*
|
|
* @author Georg Ehrke <oc.list@georgehrke.com>
|
|
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
|
* @author Thomas Citharel <tcit@tcit.fr>
|
|
*
|
|
* @license GNU AGPL version 3 or any later version
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
import Vue from 'vue'
|
|
import {
|
|
createCalendar,
|
|
createSubscription,
|
|
findAllCalendars,
|
|
findPublicCalendarsByTokens,
|
|
} from '../services/caldavService.js'
|
|
import { mapCDavObjectToCalendarObject } from '../models/calendarObject'
|
|
import { dateFactory, getUnixTimestampFromDate } from '../utils/date.js'
|
|
import { getDefaultCalendarObject, mapDavCollectionToCalendar } from '../models/calendar'
|
|
import pLimit from 'p-limit'
|
|
import { uidToHexColor } from '../utils/color.js'
|
|
import { translate as t } from '@nextcloud/l10n'
|
|
import getTimezoneManager from '../services/timezoneDataProviderService.js'
|
|
import Timezone from 'calendar-js/src/timezones/timezone.js'
|
|
import CalendarComponent from 'calendar-js/src/components/calendarComponent.js'
|
|
import {
|
|
CALDAV_BIRTHDAY_CALENDAR,
|
|
IMPORT_STAGE_IMPORTING,
|
|
IMPORT_STAGE_PROCESSING,
|
|
} from '../models/consts.js'
|
|
|
|
const state = {
|
|
calendars: [],
|
|
calendarsById: {},
|
|
initialCalendarsLoaded: false,
|
|
}
|
|
|
|
const mutations = {
|
|
|
|
/**
|
|
* Adds calendar into state
|
|
*
|
|
* @param {Object} state the store data
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar calendar the calendar to add
|
|
*/
|
|
addCalendar(state, { calendar }) {
|
|
const object = getDefaultCalendarObject(calendar)
|
|
|
|
state.calendars.push(object)
|
|
Vue.set(state.calendarsById, object.id, object)
|
|
},
|
|
|
|
/**
|
|
* Deletes a calendar
|
|
*
|
|
* @param {Object} state the store data
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to delete
|
|
*/
|
|
deleteCalendar(state, { calendar }) {
|
|
state.calendars.splice(state.calendars.indexOf(calendar), 1)
|
|
Vue.delete(state.calendarsById, calendar.id)
|
|
},
|
|
|
|
/**
|
|
* Toggles a calendar's visibility
|
|
*
|
|
* @param {Object} state the store mutations
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to toggle
|
|
*/
|
|
toggleCalendarEnabled(state, { calendar }) {
|
|
state.calendarsById[calendar.id].enabled = !state.calendarsById[calendar.id].enabled
|
|
},
|
|
|
|
/**
|
|
* Renames a calendar
|
|
*
|
|
* @param {Object} state the store mutations
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to rename
|
|
* @param {String} data.newName the new name of the calendar
|
|
*/
|
|
renameCalendar(state, { calendar, newName }) {
|
|
state.calendarsById[calendar.id].displayName = newName
|
|
},
|
|
|
|
/**
|
|
* Changes calendar's color
|
|
*
|
|
* @param {Object} state the store mutations
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to rename
|
|
* @param {String} data.newColor the new color of the calendar
|
|
*/
|
|
changeCalendarColor(state, { calendar, newColor }) {
|
|
state.calendarsById[calendar.id].color = newColor
|
|
},
|
|
|
|
/**
|
|
* Changes calendar's order
|
|
*
|
|
* @param {Object} state the store mutations
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to rename
|
|
* @param {String} data.newOrder the new order of the calendar
|
|
*/
|
|
changeCalendarOrder(state, { calendar, newOrder }) {
|
|
state.calendarsById[calendar.id].order = newOrder
|
|
},
|
|
|
|
/**
|
|
* Adds multiple calendar-objects to calendar
|
|
*
|
|
* @param {Object} state the store mutations
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar The calendar to append objects to
|
|
* @param {String[]} data.calendarObjectIds The calendar object ids to append
|
|
*/
|
|
appendCalendarObjectsToCalendar(state, { calendar, calendarObjectIds }) {
|
|
for (const calendarObjectId of calendarObjectIds) {
|
|
if (state.calendarsById[calendar.id].calendarObjects.indexOf(calendarObjectId) === -1) {
|
|
state.calendarsById[calendar.id].calendarObjects.push(calendarObjectId)
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Adds calendar-object to calendar
|
|
*
|
|
* @param {Object} state the store mutations
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar The calendar to append objects to
|
|
* @param {String} data.calendarObjectId The calendar object id to append
|
|
*/
|
|
addCalendarObjectToCalendar(state, { calendar, calendarObjectId }) {
|
|
if (state.calendarsById[calendar.id].calendarObjects.indexOf(calendarObjectId) === -1) {
|
|
state.calendarsById[calendar.id].calendarObjects.push(calendarObjectId)
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Removes calendar-object from calendar
|
|
*
|
|
* @param {Object} state the store mutations
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar The calendar to delete objects from
|
|
* @param {String} data.calendarObjectId The calendar object ids to delete
|
|
*/
|
|
deleteCalendarObjectFromCalendar(state, { calendar, calendarObjectId }) {
|
|
const index = state.calendarsById[calendar.id].calendarObjects.indexOf(calendarObjectId)
|
|
|
|
if (index !== -1) {
|
|
state.calendarsById[calendar.id].calendarObjects.slice(index, 1)
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Adds fetched time-range to calendar
|
|
*
|
|
* @param {Object} state the store mutations
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar The calendar to append a time-range to
|
|
* @param {Number} data.fetchedTimeRangeId The time-range-id to append
|
|
*/
|
|
addFetchedTimeRangeToCalendar(state, { calendar, fetchedTimeRangeId }) {
|
|
state.calendarsById[calendar.id].fetchedTimeRanges.push(fetchedTimeRangeId)
|
|
|
|
},
|
|
|
|
/**
|
|
* Removes fetched time-range from calendar
|
|
*
|
|
* @param {Object} state the store mutations
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar The calendar to remove a time-range from
|
|
* @param {Number} data.fetchedTimeRangeId The time-range-id to remove
|
|
*/
|
|
deleteFetchedTimeRangeFromCalendar(state, { calendar, fetchedTimeRangeId }) {
|
|
const index = state.calendarsById[calendar.id].fetchedTimeRanges.indexOf(fetchedTimeRangeId)
|
|
|
|
if (index !== -1) {
|
|
state.calendarsById[calendar.id].fetchedTimeRanges.slice(index, 1)
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Shares calendar with a user or group
|
|
*
|
|
* @param {Object} state the store data
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar
|
|
* @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 ?
|
|
*/
|
|
shareCalendar(state, { calendar, user, displayName, uri, isGroup, isCircle }) {
|
|
const newSharee = {
|
|
displayName,
|
|
id: user,
|
|
writeable: false,
|
|
isGroup,
|
|
isCircle,
|
|
uri,
|
|
}
|
|
state.calendarsById[calendar.id].shares.push(newSharee)
|
|
},
|
|
|
|
/**
|
|
* Removes Sharee from calendar shares list
|
|
*
|
|
* @param {Object} state the store data
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar
|
|
* @param {string} data.uri the sharee uri
|
|
*/
|
|
unshareCalendar(state, { calendar, uri }) {
|
|
calendar = state.calendars.find(search => search.id === calendar.id)
|
|
const shareIndex = calendar.shares.findIndex(sharee => sharee.uri === uri)
|
|
calendar.shares.splice(shareIndex, 1)
|
|
},
|
|
|
|
/**
|
|
* Toggles sharee's writable permission
|
|
*
|
|
* @param {Object} state the store data
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar
|
|
* @param {string} data.uri the sharee uri
|
|
*/
|
|
toggleCalendarShareWritable(state, { calendar, uri }) {
|
|
calendar = state.calendars.find(search => search.id === calendar.id)
|
|
const sharee = calendar.shares.find(sharee => sharee.uri === uri)
|
|
sharee.writeable = !sharee.writeable
|
|
},
|
|
|
|
/**
|
|
* Publishes a calendar calendar
|
|
*
|
|
* @param {Object} state the store data
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to publish
|
|
* @param {String} data.publishURL published URL of calendar
|
|
*/
|
|
publishCalendar(state, { calendar, publishURL }) {
|
|
calendar = state.calendars.find(search => search.id === calendar.id)
|
|
calendar.publishURL = publishURL
|
|
},
|
|
|
|
/**
|
|
* Unpublishes a calendar
|
|
*
|
|
* @param {Object} state the store data
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to unpublish
|
|
*/
|
|
unpublishCalendar(state, { calendar }) {
|
|
calendar = state.calendars.find(search => search.id === calendar.id)
|
|
calendar.publishURL = null
|
|
},
|
|
|
|
/**
|
|
* Marks initial loading of calendars as complete
|
|
*
|
|
* @param {Object} state the store data
|
|
*/
|
|
initialCalendarsLoaded(state) {
|
|
state.initialCalendarsLoaded = true
|
|
},
|
|
|
|
/**
|
|
* Marks a calendar as loading
|
|
*
|
|
* @param {Object} state the store data
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to mark as loading
|
|
*/
|
|
markCalendarAsLoading(state, { calendar }) {
|
|
state.calendarsById[calendar.id].loading = true
|
|
},
|
|
|
|
/**
|
|
* Marks a calendar as finished loading
|
|
*
|
|
* @param {Object} state the store data
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to mark as finished loading
|
|
*/
|
|
markCalendarAsNotLoading(state, { calendar }) {
|
|
state.calendarsById[calendar.id].loading = false
|
|
},
|
|
}
|
|
|
|
const getters = {
|
|
|
|
/**
|
|
* List of sorted calendars and subscriptions
|
|
*
|
|
* @param {Object} state the store data
|
|
* @param {Object} store the store
|
|
* @param {Object} rootState the rootState
|
|
* @returns {Array}
|
|
*/
|
|
sortedCalendarsSubscriptions(state, store, rootState) {
|
|
return state.calendars
|
|
.filter(calendar => calendar.supportsEvents || (rootState.settings.showTasks && calendar.supportsTasks))
|
|
.sort((a, b) => a.order - b.order)
|
|
},
|
|
|
|
/**
|
|
* List of sorted calendars
|
|
*
|
|
* @param {Object} state the store data
|
|
* @returns {Array}
|
|
*/
|
|
sortedCalendars(state) {
|
|
return state.calendars
|
|
.filter(calendar => calendar.supportsEvents)
|
|
.filter(calendar => !calendar.readOnly)
|
|
.sort((a, b) => a.order - b.order)
|
|
},
|
|
|
|
/**
|
|
* List of sorted subscriptions
|
|
*
|
|
* @param {Object} state the store data
|
|
* @returns {Array}
|
|
*/
|
|
sortedSubscriptions(state) {
|
|
return state.calendars
|
|
.filter(calendar => calendar.supportsEvents)
|
|
.filter(calendar => calendar.readOnly)
|
|
.sort((a, b) => a.order - b.order)
|
|
},
|
|
|
|
/**
|
|
* List of enabled calendars and subscriptions
|
|
*
|
|
* @param {Object} state the store data
|
|
* @param {Object} store the store
|
|
* @param {Object} rootState the rootState
|
|
* @returns {Array}
|
|
*/
|
|
enabledCalendars(state, store, rootState) {
|
|
return state.calendars
|
|
.filter(calendar => calendar.supportsEvents || (rootState.settings.showTasks && calendar.supportsTasks))
|
|
.filter(calendar => calendar.enabled)
|
|
},
|
|
|
|
/**
|
|
* Gets a calendar by it's Id
|
|
*
|
|
* @param {Object} state the store data
|
|
* @returns {function({String}): {Object}}
|
|
*/
|
|
getCalendarById: (state) => (calendarId) => state.calendarsById[calendarId],
|
|
|
|
/**
|
|
* Gets the contact's birthday calendar or null
|
|
*
|
|
* @param {Object} state the store data
|
|
* @returns {Object|null}
|
|
*/
|
|
getBirthdayCalendar: (state) => {
|
|
for (const calendar of state.calendars) {
|
|
const url = calendar.url.slice(0, -1)
|
|
const lastSlash = url.lastIndexOf('/')
|
|
const uri = url.substr(lastSlash + 1)
|
|
|
|
if (uri === CALDAV_BIRTHDAY_CALENDAR) {
|
|
return calendar
|
|
}
|
|
}
|
|
|
|
return null
|
|
},
|
|
|
|
/**
|
|
* Whether or not a birthday calendar exists
|
|
*
|
|
* @param {Object} state The Vuex state
|
|
* @param {Object} getters the vuex getters
|
|
* @returns {boolean}
|
|
*/
|
|
hasBirthdayCalendar: (state, getters) => {
|
|
return !!getters.getBirthdayCalendar
|
|
},
|
|
|
|
/**
|
|
*
|
|
* @param {Object} state the store data
|
|
* @param {Object} getters the store getters
|
|
* @returns {function({Boolean}, {Boolean}, {Boolean}): {Object}[]}
|
|
*/
|
|
sortedCalendarFilteredByComponents: (state, getters) => (vevent, vjournal, vtodo) => {
|
|
return getters.sortedCalendars.filter((calendar) => {
|
|
if (vevent && !calendar.supportsEvents) {
|
|
return false
|
|
}
|
|
|
|
if (vjournal && !calendar.supportsJournals) {
|
|
return false
|
|
}
|
|
|
|
if (vtodo && !calendar.supportsTasks) {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
})
|
|
},
|
|
}
|
|
|
|
const actions = {
|
|
|
|
/**
|
|
* Retrieve and commit calendars
|
|
*
|
|
* @param {Object} context the store mutations
|
|
* @returns {Promise<Array>} the calendars
|
|
*/
|
|
async getCalendars({ commit, state, getters }) {
|
|
const calendars = await findAllCalendars()
|
|
calendars.map((calendar) => mapDavCollectionToCalendar(calendar, getters.getCurrentUserPrincipal)).forEach(calendar => {
|
|
commit('addCalendar', { calendar })
|
|
})
|
|
|
|
commit('initialCalendarsLoaded')
|
|
return state.calendars
|
|
},
|
|
|
|
/**
|
|
*
|
|
* @param {Object} vuex The destructuring object for vuex
|
|
* @param {Function} vuex.commit The Vuex commit function
|
|
* @param {Object} vuex.state The Vuex state Object
|
|
* @param {Object} data The data destructuring object
|
|
* @param {String[]} data.tokens The tokens to load
|
|
* @returns {Promise<Object[]>}
|
|
*/
|
|
async getPublicCalendars({ commit, state, getters }, { tokens }) {
|
|
const calendars = findPublicCalendarsByTokens(tokens)
|
|
const calendarObjects = []
|
|
for (const davCalendar of calendars) {
|
|
const calendar = mapDavCollectionToCalendar(davCalendar)
|
|
commit('addCalendar', { calendar })
|
|
calendarObjects.push(calendar)
|
|
}
|
|
|
|
commit('initialCalendarsLoaded')
|
|
return calendarObjects
|
|
},
|
|
|
|
/**
|
|
* Append a new calendar to array of existing calendars
|
|
*
|
|
* @param {Object} context the store mutations
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.displayName The name of the new calendar
|
|
* @param {Object} data.color The color of the new calendar
|
|
* @param {Object} data.order The order of the new calendar
|
|
* @param {String[]=} data.components The supported components of the calendar
|
|
* @param {String=} data.timezone The timezoneId
|
|
* @returns {Promise}
|
|
*/
|
|
async appendCalendar(context, { displayName, color, order, components = ['VEVENT'], timezone = null }) {
|
|
if (timezone === null) {
|
|
timezone = context.getters.getResolvedTimezone
|
|
}
|
|
|
|
let timezoneIcs = null
|
|
const timezoneObject = getTimezoneManager().getTimezoneForId(timezone)
|
|
if (timezoneObject !== Timezone.utc && timezoneObject !== Timezone.floating) {
|
|
const calendar = CalendarComponent.fromEmpty()
|
|
calendar.addComponent(timezoneObject.toTimezoneComponent())
|
|
timezoneIcs = calendar.toICS(false)
|
|
}
|
|
|
|
const response = await createCalendar(displayName, color, components, order, timezoneIcs)
|
|
const calendar = mapDavCollectionToCalendar(response, context.getters.getCurrentUserPrincipal)
|
|
context.commit('addCalendar', { calendar })
|
|
},
|
|
|
|
/**
|
|
* Append a new subscription to array of existing calendars
|
|
*
|
|
* @param {Object} context the store mutations
|
|
* @param {Object} data destructuring object
|
|
* @param {String} data.displayName Name of new subscription
|
|
* @param {String} data.color Color of new subscription
|
|
* @param {String} data.order Order of new subscription
|
|
* @param {String} data.source Source of new subscription
|
|
* @returns {Promise}
|
|
*/
|
|
async appendSubscription(context, { displayName, color, order, source }) {
|
|
const response = await createSubscription(displayName, color, source, order)
|
|
const calendar = mapDavCollectionToCalendar(response, context.getters.getCurrentUserPrincipal)
|
|
context.commit('addCalendar', { calendar })
|
|
},
|
|
|
|
/**
|
|
* Delete a calendar
|
|
*
|
|
* @param {Object} context the store mutations Current context
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to delete
|
|
* @returns {Promise}
|
|
*/
|
|
async deleteCalendar(context, { calendar }) {
|
|
await calendar.dav.delete()
|
|
context.commit('deleteCalendar', { calendar })
|
|
},
|
|
|
|
/**
|
|
* Toggle whether a calendar is enabled
|
|
*
|
|
* @param {Object} context the store mutations Current context
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to modify
|
|
* @returns {Promise}
|
|
*/
|
|
async toggleCalendarEnabled(context, { calendar }) {
|
|
context.commit('markCalendarAsLoading', { calendar })
|
|
calendar.dav.enabled = !calendar.dav.enabled
|
|
|
|
try {
|
|
await calendar.dav.update()
|
|
context.commit('markCalendarAsNotLoading', { calendar })
|
|
context.commit('toggleCalendarEnabled', { calendar })
|
|
} catch (error) {
|
|
context.commit('markCalendarAsNotLoading', { calendar })
|
|
throw error
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Rename a calendar
|
|
*
|
|
* @param {Object} context the store mutations Current context
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to modify
|
|
* @param {String} data.newName the new name of the calendar
|
|
* @returns {Promise}
|
|
*/
|
|
async renameCalendar(context, { calendar, newName }) {
|
|
calendar.dav.displayname = newName
|
|
|
|
await calendar.dav.update()
|
|
context.commit('renameCalendar', { calendar, newName })
|
|
},
|
|
|
|
/**
|
|
* Change a calendar's color
|
|
*
|
|
* @param {Object} context the store mutations Current context
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to modify
|
|
* @param {String} data.newColor the new color of the calendar
|
|
* @returns {Promise}
|
|
*/
|
|
async changeCalendarColor(context, { calendar, newColor }) {
|
|
calendar.dav.color = newColor
|
|
|
|
await calendar.dav.update()
|
|
context.commit('changeCalendarColor', { calendar, newColor })
|
|
},
|
|
|
|
/**
|
|
* Change a calendar's order
|
|
*
|
|
* @param {Object} context the store mutations Current context
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to modify
|
|
* @param {String} data.newOrder the new order of the calendar
|
|
* @returns {Promise}
|
|
*/
|
|
async changeCalendarOrder(context, { calendar, newOrder }) {
|
|
calendar.dav.order = newOrder
|
|
|
|
await calendar.dav.update()
|
|
context.commit('changeCalendarOrder', { calendar, newOrder })
|
|
},
|
|
|
|
/**
|
|
* Change order of multiple calendars
|
|
*
|
|
* @param {Object} context the store mutations Current context
|
|
* @param {Array} new order of calendars
|
|
*/
|
|
async changeMultipleCalendarOrders(context, { calendars }) {
|
|
// TODO - implement me
|
|
// TODO - extract new order from order of calendars in array
|
|
// send proppatch to all calendars
|
|
// limit number of requests similar to import
|
|
},
|
|
|
|
/**
|
|
* Share calendar with User or Group
|
|
*
|
|
* @param {Object} context the store mutations Current context
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to share
|
|
* @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 ?
|
|
*/
|
|
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, isCircle })
|
|
},
|
|
|
|
/**
|
|
* Toggle permissions of calendar Sharees writeable rights
|
|
*
|
|
* @param {Object} context the store mutations Current context
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to change
|
|
* @param {string} data.uri the sharing principalScheme uri
|
|
*/
|
|
async toggleCalendarShareWritable(context, { calendar, uri }) {
|
|
const sharee = calendar.shares.find(sharee => sharee.uri === uri)
|
|
await calendar.dav.share(uri, !sharee.writeable)
|
|
context.commit('toggleCalendarShareWritable', { calendar, uri })
|
|
},
|
|
|
|
/**
|
|
* Remove sharee from calendar
|
|
*
|
|
* @param {Object} context the store mutations Current context
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to change
|
|
* @param {string} data.uri the sharing principalScheme uri
|
|
*/
|
|
async unshareCalendar(context, { calendar, uri }) {
|
|
await calendar.dav.unshare(uri)
|
|
context.commit('unshareCalendar', { calendar, uri })
|
|
},
|
|
|
|
/**
|
|
* Publish a calendar
|
|
*
|
|
* @param {Object} context the store mutations Current context
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to change
|
|
* @returns {Promise<void>}
|
|
*/
|
|
async publishCalendar(context, { calendar }) {
|
|
await calendar.dav.publish()
|
|
const publishURL = calendar.dav.publishURL
|
|
context.commit('publishCalendar', { calendar, publishURL })
|
|
},
|
|
|
|
/**
|
|
* Unpublish a calendar
|
|
*
|
|
* @param {Object} context the store mutations Current context
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to change
|
|
* @returns {Promise<void>}
|
|
*/
|
|
async unpublishCalendar(context, { calendar }) {
|
|
await calendar.dav.unpublish()
|
|
context.commit('unpublishCalendar', { calendar })
|
|
},
|
|
|
|
/**
|
|
* Retrieve the events of the specified calendar
|
|
* and commit the results
|
|
*
|
|
* @param {Object} context the store mutations
|
|
* @param {Object} data destructuring object
|
|
* @param {Object} data.calendar the calendar to get events from
|
|
* @param {Date} data.from the date to start querying events from
|
|
* @param {Date} data.to the last date to query events from
|
|
* @returns {Promise<void>}
|
|
*/
|
|
async getEventsFromCalendarInTimeRange(context, { calendar, from, to }) {
|
|
context.commit('markCalendarAsLoading', { calendar })
|
|
const response = await calendar.dav.findByTypeInTimeRange('VEVENT', from, to)
|
|
let responseTodo = []
|
|
if (context.rootState.settings.showTasks) {
|
|
responseTodo = await calendar.dav.findByTypeInTimeRange('VTODO', from, to)
|
|
}
|
|
context.commit('addTimeRange', {
|
|
calendarId: calendar.id,
|
|
from: getUnixTimestampFromDate(from),
|
|
to: getUnixTimestampFromDate(to),
|
|
lastFetched: getUnixTimestampFromDate(dateFactory()),
|
|
calendarObjectIds: [],
|
|
})
|
|
const insertId = context.getters.getLastTimeRangeInsertId
|
|
context.commit('addFetchedTimeRangeToCalendar', {
|
|
calendar,
|
|
fetchedTimeRangeId: insertId,
|
|
})
|
|
|
|
const calendarObjects = []
|
|
const calendarObjectIds = []
|
|
for (const r of response.concat(responseTodo)) {
|
|
const calendarObject = mapCDavObjectToCalendarObject(r, calendar.id)
|
|
calendarObjects.push(calendarObject)
|
|
calendarObjectIds.push(calendarObject.id)
|
|
}
|
|
|
|
context.commit('appendCalendarObjects', { calendarObjects })
|
|
context.commit('appendCalendarObjectsToCalendar', { calendar, calendarObjectIds })
|
|
context.commit('appendCalendarObjectIdsToTimeFrame', {
|
|
timeRangeId: insertId,
|
|
calendarObjectIds,
|
|
})
|
|
|
|
context.commit('markCalendarAsNotLoading', { calendar })
|
|
return context.rootState.fetchedTimeRanges.lastTimeRangeInsertId
|
|
},
|
|
|
|
/**
|
|
* Retrieve one object
|
|
*
|
|
* @param {Object} context the store mutations
|
|
* @param {Object} data destructuring object
|
|
* @param {String} data.objectId Id of the object to fetch
|
|
* @returns {Promise<CalendarObject>}
|
|
*/
|
|
async getEventByObjectId(context, { objectId }) {
|
|
// TODO - we should still check if the calendar-object is up to date
|
|
// - Just send head and compare etags
|
|
if (context.getters.getCalendarObjectById(objectId)) {
|
|
return Promise.resolve(context.getters.getCalendarObjectById(objectId))
|
|
}
|
|
|
|
// This might throw an exception, but we will leave it up to the methods
|
|
// calling this action to properly handle it
|
|
const objectPath = atob(objectId)
|
|
const lastSlashIndex = objectPath.lastIndexOf('/')
|
|
const calendarPath = objectPath.substr(0, lastSlashIndex + 1)
|
|
const objectFileName = objectPath.substr(lastSlashIndex + 1)
|
|
|
|
const calendarId = btoa(calendarPath)
|
|
if (!context.state.calendarsById[calendarId]) {
|
|
return Promise.reject(new Error(''))
|
|
}
|
|
|
|
const calendar = context.state.calendarsById[calendarId]
|
|
const vObject = await calendar.dav.find(objectFileName)
|
|
const calendarObject = mapCDavObjectToCalendarObject(vObject, calendar.id)
|
|
context.commit('appendCalendarObject', { calendarObject })
|
|
context.commit('addCalendarObjectToCalendar', {
|
|
calendar: {
|
|
id: calendarId,
|
|
},
|
|
calendarObjectId: calendarObject.id,
|
|
})
|
|
|
|
return calendarObject
|
|
},
|
|
|
|
/**
|
|
* Import events into calendar
|
|
*
|
|
* @param {Object} context the store mutations
|
|
*/
|
|
async importEventsIntoCalendar(context) {
|
|
context.commit('changeStage', IMPORT_STAGE_IMPORTING)
|
|
|
|
// Create a copy
|
|
const files = context.rootState.importFiles.importFiles.slice()
|
|
|
|
let totalCount = 0
|
|
for (const file of files) {
|
|
totalCount += file.parser.getItemCount()
|
|
|
|
const calendarId = context.rootState.importFiles.importCalendarRelation[file.id]
|
|
if (calendarId === 'new') {
|
|
const displayName = file.parser.getName() || t('calendar', 'Imported {filename}', {
|
|
filename: file.name,
|
|
})
|
|
const color = file.parser.getColor() || uidToHexColor(displayName)
|
|
const components = []
|
|
if (file.parser.containsVEvents()) {
|
|
components.push('VEVENT')
|
|
}
|
|
if (file.parser.containsVJournals()) {
|
|
components.push('VJOURNAL')
|
|
}
|
|
if (file.parser.containsVTodos()) {
|
|
components.push('VTODO')
|
|
}
|
|
|
|
try {
|
|
const response = await createCalendar(displayName, color, components, 0)
|
|
const calendar = mapDavCollectionToCalendar(response, context.getters.getCurrentUserPrincipal)
|
|
context.commit('addCalendar', { calendar })
|
|
context.commit('setCalendarForFileId', {
|
|
fileId: file.id,
|
|
calendarId: calendar.id,
|
|
})
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
}
|
|
|
|
context.commit('setTotal', totalCount)
|
|
|
|
const limit = pLimit(3)
|
|
const requests = []
|
|
|
|
for (const file of files) {
|
|
const calendarId = context.rootState.importFiles.importCalendarRelation[file.id]
|
|
const calendar = context.getters.getCalendarById(calendarId)
|
|
|
|
for (const item of file.parser.getItemIterator()) {
|
|
requests.push(limit(async() => {
|
|
const ics = item.toICS()
|
|
|
|
let davObject
|
|
try {
|
|
davObject = await calendar.dav.createVObject(ics)
|
|
} catch (error) {
|
|
context.commit('incrementDenied')
|
|
console.error(error)
|
|
return
|
|
}
|
|
|
|
const calendarObject = mapCDavObjectToCalendarObject(davObject, calendarId)
|
|
context.commit('appendCalendarObject', { calendarObject })
|
|
context.commit('addCalendarObjectToCalendar', {
|
|
calendar,
|
|
calendarObjectId: calendarObject.id,
|
|
})
|
|
context.commit('addCalendarObjectIdToAllTimeRangesOfCalendar', {
|
|
calendarId: calendar.id,
|
|
calendarObjectId: calendarObject.id,
|
|
})
|
|
context.commit('incrementAccepted')
|
|
}))
|
|
}
|
|
}
|
|
|
|
await Promise.all(requests)
|
|
context.commit('changeStage', IMPORT_STAGE_PROCESSING)
|
|
},
|
|
}
|
|
|
|
export default { state, mutations, getters, actions }
|