Cleanup and tests for some Stores
Signed-off-by: Georg Ehrke <developer@georgehrke.com>
This commit is contained in:
parent
0931c6cdff
commit
e2237b6ba0
|
@ -45,7 +45,7 @@
|
|||
|
||||
<script>
|
||||
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
|
||||
import client from '../../../services/caldavService.js'
|
||||
import { findPrincipalsByDisplayName } from '../../../services/caldavService.js'
|
||||
import HttpClient from '@nextcloud/axios'
|
||||
import debounce from 'debounce'
|
||||
import { generateOcsUrl } from '@nextcloud/router'
|
||||
|
@ -140,7 +140,7 @@ export default {
|
|||
async findShareesFromDav(query, hiddenPrincipals, hiddenUrls) {
|
||||
let results
|
||||
try {
|
||||
results = await client.principalPropertySearchByDisplayname(query)
|
||||
results = await findPrincipalsByDisplayName(query)
|
||||
} catch (error) {
|
||||
return []
|
||||
}
|
||||
|
|
|
@ -116,8 +116,13 @@ import {
|
|||
import SettingsImportSection from './Settings/SettingsImportSection.vue'
|
||||
import SettingsTimezoneSelect from './Settings/SettingsTimezoneSelect.vue'
|
||||
|
||||
import client from '../../services/caldavService.js'
|
||||
import { getCurrentUserPrincipal } from '../../services/caldavService.js'
|
||||
import ShortcutOverview from './Settings/ShortcutOverview.vue'
|
||||
import {
|
||||
IMPORT_STAGE_DEFAULT,
|
||||
IMPORT_STAGE_IMPORTING,
|
||||
IMPORT_STAGE_PROCESSING,
|
||||
} from '../../models/consts.js'
|
||||
|
||||
export default {
|
||||
name: 'Settings',
|
||||
|
@ -169,13 +174,13 @@ export default {
|
|||
return this.$store.state.importFiles.importFiles
|
||||
},
|
||||
showUploadButton() {
|
||||
return this.$store.state.importState.importState.stage === 'default'
|
||||
return this.$store.state.importState.importState.stage === IMPORT_STAGE_DEFAULT
|
||||
},
|
||||
showImportModal() {
|
||||
return this.$store.state.importState.importState.stage === 'processing'
|
||||
return this.$store.state.importState.importState.stage === IMPORT_STAGE_PROCESSING
|
||||
},
|
||||
showProgressBar() {
|
||||
return this.$store.state.importState.importState.stage === 'importing'
|
||||
return this.$store.state.importState.importState.stage === IMPORT_STAGE_IMPORTING
|
||||
},
|
||||
settingsTitle() {
|
||||
return this.$t('calendar', 'Settings & import').replace(/&/g, '&')
|
||||
|
@ -324,7 +329,7 @@ export default {
|
|||
*/
|
||||
async copyAppleCalDAV() {
|
||||
const rootURL = generateRemoteUrl('dav')
|
||||
const url = new URL(client.currentUserPrincipal.principalUrl, rootURL)
|
||||
const url = new URL(getCurrentUserPrincipal().principalUrl, rootURL)
|
||||
|
||||
try {
|
||||
await this.$copyText(url)
|
||||
|
|
|
@ -60,6 +60,12 @@ import {
|
|||
showWarning,
|
||||
showError,
|
||||
} from '@nextcloud/dialogs'
|
||||
import {
|
||||
IMPORT_STAGE_AWAITING_USER_SELECT,
|
||||
IMPORT_STAGE_DEFAULT,
|
||||
IMPORT_STAGE_IMPORTING,
|
||||
IMPORT_STAGE_PROCESSING,
|
||||
} from '../../../models/consts.js'
|
||||
|
||||
export default {
|
||||
name: 'SettingsImportSection',
|
||||
|
@ -94,7 +100,7 @@ export default {
|
|||
* @returns {Boolean}
|
||||
*/
|
||||
allowUploadOfFiles() {
|
||||
return this.stage === 'default'
|
||||
return this.stage === IMPORT_STAGE_DEFAULT
|
||||
},
|
||||
/**
|
||||
* Whether or not to display the import modal
|
||||
|
@ -102,7 +108,7 @@ export default {
|
|||
* @returns {Boolean}
|
||||
*/
|
||||
showImportModal() {
|
||||
return this.stage === 'awaitingUserSelect'
|
||||
return this.stage === IMPORT_STAGE_AWAITING_USER_SELECT
|
||||
},
|
||||
/**
|
||||
* Whether or not to display progress bar
|
||||
|
@ -110,7 +116,7 @@ export default {
|
|||
* @returns {Boolean}
|
||||
*/
|
||||
showProgressBar() {
|
||||
return this.stage === 'importing'
|
||||
return this.stage === IMPORT_STAGE_IMPORTING
|
||||
},
|
||||
/**
|
||||
* Unique identifier for the input field.
|
||||
|
@ -149,7 +155,7 @@ export default {
|
|||
* @param {Event} event The change-event of the input-field
|
||||
*/
|
||||
async processFiles(event) {
|
||||
this.$store.commit('changeStage', 'processing')
|
||||
this.$store.commit('changeStage', IMPORT_STAGE_PROCESSING)
|
||||
let addedFiles = false
|
||||
|
||||
for (const file of event.target.files) {
|
||||
|
@ -225,7 +231,7 @@ export default {
|
|||
return
|
||||
}
|
||||
|
||||
this.$store.commit('changeStage', 'awaitingUserSelect')
|
||||
this.$store.commit('changeStage', IMPORT_STAGE_AWAITING_USER_SELECT)
|
||||
},
|
||||
/**
|
||||
* Import all events into the calendars
|
||||
|
|
|
@ -34,7 +34,7 @@ import {
|
|||
} from 'vuex'
|
||||
|
||||
import TimezoneSelect from '../../Shared/TimezoneSelect.vue'
|
||||
import detectTimezone from '../../../services/timezoneDetectionService.js'
|
||||
import { detectTimezone } from '../../../services/timezoneDetectionService.js'
|
||||
import {
|
||||
showInfo,
|
||||
} from '@nextcloud/dialogs'
|
||||
|
|
|
@ -81,7 +81,7 @@
|
|||
<script>
|
||||
import Avatar from '@nextcloud/vue/dist/Components/Avatar'
|
||||
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
|
||||
import client from '../../../services/caldavService.js'
|
||||
import { findPrincipalsByDisplayName } from '../../../services/caldavService.js'
|
||||
import HttpClient from '@nextcloud/axios'
|
||||
import debounce from 'debounce'
|
||||
import { linkTo } from '@nextcloud/router'
|
||||
|
@ -209,7 +209,7 @@ export default {
|
|||
async findAttendeesFromDAV(query) {
|
||||
let results
|
||||
try {
|
||||
results = await client.principalPropertySearchByDisplayname(query)
|
||||
results = await findPrincipalsByDisplayName(query)
|
||||
} catch (error) {
|
||||
console.debug(error)
|
||||
return []
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
import getTimezoneManager from '../services/timezoneDataProviderService.js'
|
||||
import { createFreeBusyRequest } from 'calendar-js'
|
||||
import DateTimeValue from 'calendar-js/src/values/dateTimeValue.js'
|
||||
import client from '../services/caldavService.js'
|
||||
import { findSchedulingOutbox } from '../services/caldavService.js'
|
||||
import freeBusyEventSourceFunction from './freeBusyEventSourceFunction.js'
|
||||
import logger from '../utils/logger.js'
|
||||
// import AttendeeProperty from 'calendar-js/src/properties/attendeeProperty.js'
|
||||
|
@ -60,8 +60,7 @@ export default function(id, organizer, attendees) {
|
|||
|
||||
let outbox
|
||||
try {
|
||||
const outboxes = await client.calendarHomes[0].findAllScheduleOutboxes()
|
||||
outbox = outboxes[0]
|
||||
outbox = await findSchedulingOutbox()
|
||||
} catch (error) {
|
||||
failureCallback(error)
|
||||
return
|
||||
|
|
|
@ -38,6 +38,13 @@ const PRINCIPAL_PREFIX_CIRCLE = 'principal:principals/circles/'
|
|||
const PRINCIPAL_PREFIX_CALENDAR_RESOURCE = 'principal:principals/calendar-resources/'
|
||||
const PRINCIPAL_PREFIX_CALENDAR_ROOM = 'principal:principals/calendar-rooms/'
|
||||
|
||||
const CALDAV_BIRTHDAY_CALENDAR = 'contact_birthdays'
|
||||
|
||||
const IMPORT_STAGE_DEFAULT = 'default'
|
||||
const IMPORT_STAGE_IMPORTING = 'importing'
|
||||
const IMPORT_STAGE_AWAITING_USER_SELECT = 'awaitingUserSelect'
|
||||
const IMPORT_STAGE_PROCESSING = 'processing'
|
||||
|
||||
export {
|
||||
COMPONENT_NAME_EVENT,
|
||||
COMPONENT_NAME_JOURNAL,
|
||||
|
@ -55,4 +62,9 @@ export {
|
|||
PRINCIPAL_PREFIX_CIRCLE,
|
||||
PRINCIPAL_PREFIX_CALENDAR_RESOURCE,
|
||||
PRINCIPAL_PREFIX_CALENDAR_ROOM,
|
||||
CALDAV_BIRTHDAY_CALENDAR,
|
||||
IMPORT_STAGE_DEFAULT,
|
||||
IMPORT_STAGE_IMPORTING,
|
||||
IMPORT_STAGE_AWAITING_USER_SELECT,
|
||||
IMPORT_STAGE_PROCESSING,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 Georg Ehrke
|
||||
* @copyright Copyright (c) 2020 Georg Ehrke
|
||||
*
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
*
|
||||
|
@ -22,30 +22,211 @@
|
|||
import DavClient from 'cdav-library'
|
||||
import { generateRemoteUrl } from '@nextcloud/router'
|
||||
import { getRequestToken } from '@nextcloud/auth'
|
||||
import { CALDAV_BIRTHDAY_CALENDAR } from '../models/consts.js'
|
||||
|
||||
function xhrProvider() {
|
||||
const headers = {
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'requesttoken': getRequestToken(),
|
||||
'X-NC-CalDAV-Webcal-Caching': 'On',
|
||||
let client = null
|
||||
const getClient = () => {
|
||||
if (client) {
|
||||
return client
|
||||
}
|
||||
const xhr = new XMLHttpRequest()
|
||||
const oldOpen = xhr.open
|
||||
|
||||
// override open() method to add headers
|
||||
xhr.open = function() {
|
||||
const result = oldOpen.apply(this, arguments)
|
||||
for (const name in headers) {
|
||||
xhr.setRequestHeader(name, headers[name])
|
||||
client = new DavClient({
|
||||
rootUrl: generateRemoteUrl('dav'),
|
||||
}, () => {
|
||||
const headers = {
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'requesttoken': getRequestToken(),
|
||||
'X-NC-CalDAV-Webcal-Caching': 'On',
|
||||
}
|
||||
const xhr = new XMLHttpRequest()
|
||||
const oldOpen = xhr.open
|
||||
|
||||
// override open() method to add headers
|
||||
xhr.open = function() {
|
||||
const result = oldOpen.apply(this, arguments)
|
||||
for (const name in headers) {
|
||||
xhr.setRequestHeader(name, headers[name])
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
OC.registerXHRForErrorProcessing(xhr) // eslint-disable-line no-undef
|
||||
return xhr
|
||||
})
|
||||
|
||||
OC.registerXHRForErrorProcessing(xhr) // eslint-disable-line no-undef
|
||||
return xhr
|
||||
return getClient()
|
||||
}
|
||||
|
||||
export default new DavClient({
|
||||
rootUrl: generateRemoteUrl('dav'),
|
||||
}, xhrProvider)
|
||||
/**
|
||||
* Initializes the client for use in the user-view
|
||||
*/
|
||||
const initializeClientForUserView = async() => {
|
||||
await getClient().connect({ enableCalDAV: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the client for use in the public/embed-view
|
||||
*/
|
||||
const initializeClientForPublicView = async() => {
|
||||
await getClient()._createPublicCalendarHome()
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all calendars from the server
|
||||
*
|
||||
* @returns {Promise<Calendar[]>}
|
||||
*/
|
||||
const findAllCalendars = () => {
|
||||
return getClient().calendarHomes[0].findAllCalendars()
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch public calendars by their token
|
||||
*
|
||||
* @param {String[]} tokens List of tokens
|
||||
* @returns {Promise<Calendar[]>}
|
||||
*/
|
||||
const findPublicCalendarsByTokens = async(tokens) => {
|
||||
const findPromises = []
|
||||
|
||||
for (const token of tokens) {
|
||||
const promise = getClient().publicCalendarHome
|
||||
.find(token)
|
||||
.catch(() => null) // Catch outdated tokens
|
||||
|
||||
findPromises.push(promise)
|
||||
}
|
||||
|
||||
const calendars = await Promise.all(findPromises)
|
||||
return calendars.filter((calendar) => calendar !== null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all scheduling inboxes
|
||||
*
|
||||
* Nitpick detail: Technically, we shouldn't be querying all scheduling inboxes
|
||||
* in the calendar-home and just take the first one, but rather query the
|
||||
* "CALDAV:schedule-inbox-URL" property on the principal URL and take that one.
|
||||
* However, it doesn't make any difference for the Nextcloud CalDAV server
|
||||
* and saves us extraneous requests here.
|
||||
*
|
||||
* https://tools.ietf.org/html/rfc6638#section-2.2.1
|
||||
*
|
||||
* @returns {Promise<ScheduleInbox[]>}
|
||||
*/
|
||||
const findSchedulingInbox = async() => {
|
||||
const inboxes = await getClient().calendarHomes[0].findAllScheduleInboxes()
|
||||
return inboxes[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all scheduling outboxes
|
||||
*
|
||||
* Nitpick detail: Technically, we shouldn't be querying all scheduling outboxes
|
||||
* in the calendar-home and just take the first one, but rather query the
|
||||
* "CALDAV:schedule-outbox-URL" property on the principal URL and take that one.
|
||||
* However, it doesn't make any difference for the Nextcloud CalDAV server
|
||||
* and saves us extraneous requests here.
|
||||
*
|
||||
* https://tools.ietf.org/html/rfc6638#section-2.1.1
|
||||
*
|
||||
* @returns {Promise<ScheduleOutbox>}
|
||||
*/
|
||||
const findSchedulingOutbox = async() => {
|
||||
const outboxes = await getClient().calendarHomes[0].findAllScheduleOutboxes()
|
||||
return outboxes[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a calendar
|
||||
*
|
||||
* @param {String} displayName Visible name
|
||||
* @param {String} color Color
|
||||
* @param {String[]} components Supported component set
|
||||
* @param {Number} order Order of calendar in list
|
||||
* @param {String} timezoneIcs ICS representation of timezone
|
||||
* @returns {Promise<Calendar>}
|
||||
*/
|
||||
const createCalendar = async(displayName, color, components, order, timezoneIcs) => {
|
||||
return getClient().calendarHomes[0].createCalendarCollection(displayName, color, components, order, timezoneIcs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a subscription
|
||||
*
|
||||
* This function does not return a subscription, but a cached calendar
|
||||
*
|
||||
* @param {String} displayName Visible name
|
||||
* @param {String} color Color
|
||||
* @param {String} source Link to WebCAL Source
|
||||
* @param {Number} order Order of calendar in list
|
||||
* @returns {Promise<Calendar>}
|
||||
*/
|
||||
const createSubscription = async(displayName, color, source, order) => {
|
||||
return getClient().calendarHomes[0].createSubscribedCollection(displayName, color, source, order)
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the birthday calendar
|
||||
*
|
||||
* @returns {Promise<Calendar>}
|
||||
*/
|
||||
const enableBirthdayCalendar = async() => {
|
||||
await getClient().calendarHomes[0].enableBirthdayCalendar()
|
||||
return getBirthdayCalendar()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the birthday calendar
|
||||
*
|
||||
* @returns {Promise<Calendar>}
|
||||
*/
|
||||
const getBirthdayCalendar = async() => {
|
||||
return getClient().calendarHomes[0].find(CALDAV_BIRTHDAY_CALENDAR)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Current User Principal
|
||||
*
|
||||
* @returns {Principal}
|
||||
*/
|
||||
const getCurrentUserPrincipal = () => {
|
||||
return getClient().currentUserPrincipal
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds calendar principals by displayname
|
||||
*
|
||||
* @param {String} query The search-term
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const findPrincipalsByDisplayName = async(query) => {
|
||||
return getClient().principalPropertySearchByDisplayname(query)
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds one principal by it's URL
|
||||
*
|
||||
* @param {String} url The principal-url
|
||||
* @returns {Promise<Principal>}
|
||||
*/
|
||||
const findPrincipalByUrl = async(url) => {
|
||||
return getClient().findPrincipal(url)
|
||||
}
|
||||
|
||||
export {
|
||||
initializeClientForUserView,
|
||||
initializeClientForPublicView,
|
||||
findAllCalendars,
|
||||
findPublicCalendarsByTokens,
|
||||
findSchedulingInbox,
|
||||
findSchedulingOutbox,
|
||||
createCalendar,
|
||||
createSubscription,
|
||||
enableBirthdayCalendar,
|
||||
getBirthdayCalendar,
|
||||
getCurrentUserPrincipal,
|
||||
findPrincipalsByDisplayName,
|
||||
findPrincipalByUrl,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2020 Georg Ehrke
|
||||
*
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
*
|
||||
* @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 HttpClient from '@nextcloud/axios'
|
||||
import { getLinkToConfig } from '../utils/settings.js'
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String} key Config-key to set
|
||||
* @param {String|Number|Boolean} value Config-value to set
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const setConfig = async(key, value) => {
|
||||
await HttpClient.post(getLinkToConfig(key), { value })
|
||||
}
|
||||
|
||||
export {
|
||||
setConfig,
|
||||
}
|
|
@ -26,7 +26,7 @@ import jstz from 'jstz'
|
|||
*
|
||||
* @returns {String} Current timezone of user
|
||||
*/
|
||||
export default () => {
|
||||
const detectTimezone = () => {
|
||||
const determinedTimezone = jstz.determine()
|
||||
if (!determinedTimezone) {
|
||||
return 'UTC'
|
||||
|
@ -39,3 +39,8 @@ export default () => {
|
|||
|
||||
return timezoneName
|
||||
}
|
||||
|
||||
export default detectTimezone
|
||||
export {
|
||||
detectTimezone,
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ export default function(router, store) {
|
|||
|
||||
const date = getDateFromFirstdayParam(router.currentRoute.params.firstDay)
|
||||
const view = router.currentRoute.params.view
|
||||
const locale = mutation.payload
|
||||
const { locale } = mutation.payload
|
||||
|
||||
updateTitle(date, view, locale)
|
||||
})
|
||||
|
|
|
@ -24,7 +24,12 @@
|
|||
*
|
||||
*/
|
||||
import Vue from 'vue'
|
||||
import client from '../services/caldavService.js'
|
||||
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'
|
||||
|
@ -34,6 +39,11 @@ 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: [],
|
||||
|
@ -375,7 +385,7 @@ const getters = {
|
|||
const lastSlash = url.lastIndexOf('/')
|
||||
const uri = url.substr(lastSlash + 1)
|
||||
|
||||
if (uri === 'contact_birthdays') {
|
||||
if (uri === CALDAV_BIRTHDAY_CALENDAR) {
|
||||
return calendar
|
||||
}
|
||||
}
|
||||
|
@ -383,6 +393,17 @@ const getters = {
|
|||
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
|
||||
|
@ -417,7 +438,7 @@ const actions = {
|
|||
* @returns {Promise<Array>} the calendars
|
||||
*/
|
||||
async getCalendars({ commit, state, getters }) {
|
||||
const calendars = await client.calendarHomes[0].findAllCalendars()
|
||||
const calendars = await findAllCalendars()
|
||||
calendars.map((calendar) => mapDavCollectionToCalendar(calendar, getters.getCurrentUserPrincipal)).forEach(calendar => {
|
||||
commit('addCalendar', { calendar })
|
||||
})
|
||||
|
@ -436,26 +457,9 @@ const actions = {
|
|||
* @returns {Promise<Object[]>}
|
||||
*/
|
||||
async getPublicCalendars({ commit, state, getters }, { tokens }) {
|
||||
const findPromises = []
|
||||
|
||||
for (const token of tokens) {
|
||||
const promise = client.publicCalendarHome
|
||||
.find(token)
|
||||
.catch(() => null) // Catch outdated tokens
|
||||
|
||||
findPromises.push(promise)
|
||||
}
|
||||
|
||||
const calendars = await Promise.all(findPromises)
|
||||
const existingCalendars = []
|
||||
for (const calendar of calendars) {
|
||||
if (calendar !== null) {
|
||||
existingCalendars.push(calendar)
|
||||
}
|
||||
}
|
||||
|
||||
const calendars = findPublicCalendarsByTokens(tokens)
|
||||
const calendarObjects = []
|
||||
for (const davCalendar of existingCalendars) {
|
||||
for (const davCalendar of calendars) {
|
||||
const calendar = mapDavCollectionToCalendar(davCalendar)
|
||||
commit('addCalendar', { calendar })
|
||||
calendarObjects.push(calendar)
|
||||
|
@ -490,7 +494,7 @@ const actions = {
|
|||
timezoneIcs = calendar.toICS(false)
|
||||
}
|
||||
|
||||
const response = await client.calendarHomes[0].createCalendarCollection(displayName, color, components, order, timezoneIcs)
|
||||
const response = await createCalendar(displayName, color, components, order, timezoneIcs)
|
||||
const calendar = mapDavCollectionToCalendar(response, context.getters.getCurrentUserPrincipal)
|
||||
context.commit('addCalendar', { calendar })
|
||||
},
|
||||
|
@ -507,7 +511,7 @@ const actions = {
|
|||
* @returns {Promise}
|
||||
*/
|
||||
async appendSubscription(context, { displayName, color, order, source }) {
|
||||
const response = await client.calendarHomes[0].createSubscribedCollection(displayName, color, source, order)
|
||||
const response = await createSubscription(displayName, color, source, order)
|
||||
const calendar = mapDavCollectionToCalendar(response, context.getters.getCurrentUserPrincipal)
|
||||
context.commit('addCalendar', { calendar })
|
||||
},
|
||||
|
@ -776,7 +780,7 @@ const actions = {
|
|||
* @param {Object} context the store mutations
|
||||
*/
|
||||
async importEventsIntoCalendar(context) {
|
||||
context.commit('changeStage', 'importing')
|
||||
context.commit('changeStage', IMPORT_STAGE_IMPORTING)
|
||||
|
||||
// Create a copy
|
||||
const files = context.rootState.importFiles.importFiles.slice()
|
||||
|
@ -803,7 +807,7 @@ const actions = {
|
|||
}
|
||||
|
||||
try {
|
||||
const response = await client.calendarHomes[0].createCalendarCollection(displayName, color, components, 0)
|
||||
const response = await createCalendar(displayName, color, components, 0)
|
||||
const calendar = mapDavCollectionToCalendar(response, context.getters.getCurrentUserPrincipal)
|
||||
context.commit('addCalendar', { calendar })
|
||||
context.commit('setCalendarForFileId', {
|
||||
|
@ -854,7 +858,7 @@ const actions = {
|
|||
}
|
||||
|
||||
await Promise.all(requests)
|
||||
context.commit('changeStage', 'default')
|
||||
context.commit('changeStage', IMPORT_STAGE_PROCESSING)
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -28,25 +28,6 @@ const state = {
|
|||
|
||||
const mutations = {
|
||||
|
||||
/**
|
||||
* Append multiple contacts to the store
|
||||
*
|
||||
* @param {Object} state The store data
|
||||
* @param {Object} data The destructuring object
|
||||
* @param {Object[]} data.contacts List of contacts to add
|
||||
*/
|
||||
appendContacts(state, { contacts = [] }) {
|
||||
for (const contact of contacts) {
|
||||
if (state.contacts.indexOf(contact) === -1) {
|
||||
state.contacts.push(contact)
|
||||
}
|
||||
|
||||
for (const email of contact.emails) {
|
||||
Vue.set(state.contactByEMail, email, contact)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Append a single contact to the store
|
||||
*
|
||||
|
@ -60,7 +41,12 @@ const mutations = {
|
|||
}
|
||||
|
||||
for (const email of contact.emails) {
|
||||
Vue.set(state.contactByEMail, email, contact)
|
||||
// In the unlikely case that multiple contacts
|
||||
// share the same email address, we will just follow
|
||||
// first come, first served.
|
||||
if (state.contactByEMail[email] === undefined) {
|
||||
Vue.set(state.contactByEMail, email, contact)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -72,7 +58,7 @@ const mutations = {
|
|||
* @param {Object} data.contact The contact to remove from the store
|
||||
*/
|
||||
removeContact(state, { contact }) {
|
||||
for (const email of contact.email) {
|
||||
for (const email of contact.emails) {
|
||||
if (state.contactByEMail[email] === contact) {
|
||||
Vue.delete(state.contactByEMail, email)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 Georg Ehrke
|
||||
* @copyright Copyright (c) 2020 Georg Ehrke
|
||||
*
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
*
|
||||
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
const state = {
|
||||
minimumDate: '1970-01-01T00:00:00Z',
|
||||
maximumDate: '2036-12-31T23:59:59Z',
|
||||
maximumDate: '2037-12-31T23:59:59Z',
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
|
@ -30,11 +30,13 @@ const mutations = {
|
|||
* Initialize restrictions imposed by CalDAV server
|
||||
*
|
||||
* @param {Object} state The Vuex state
|
||||
* @param {Object} davRestrictions The full settings object
|
||||
* @param {Object} data The destructuring object
|
||||
* @param {String} data.minimumDate The minimum-date allowed by the CalDAV server
|
||||
* @param {String} data.maximumDate The maximum-date allowed by the CalDAV server
|
||||
*/
|
||||
loadDavRestrictionsFromServer(state, davRestrictions) {
|
||||
state.minimumDate = davRestrictions.minimumDate
|
||||
state.maximumDate = davRestrictions.maximumDate
|
||||
loadDavRestrictionsFromServer(state, { minimumDate, maximumDate }) {
|
||||
state.minimumDate = minimumDate
|
||||
state.maximumDate = maximumDate
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 Team Popcorn <teampopcornberlin@gmail.com>
|
||||
* @copyright Copyright (c) 2019 Georg Ehrke
|
||||
* @copyright Copyright (c) 2020 Georg Ehrke
|
||||
*
|
||||
* @author Team Popcorn <teampopcornberlin@gmail.com>
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
|
@ -59,23 +59,6 @@ const mutations = {
|
|||
Vue.set(state.importFilesById, file.id, file)
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes one file from state
|
||||
*
|
||||
* @param {Object} state The vuex state
|
||||
* @param {Object} data The destructuring object
|
||||
* @param {Number} data.fileId Id of the file to remove
|
||||
*/
|
||||
removeFile(state, { fileId }) {
|
||||
const object = state.importFilesById[fileId]
|
||||
const index = state.importFiles.indexOf(object)
|
||||
|
||||
if (index !== 1) {
|
||||
state.importFiles.slice(index, 1)
|
||||
Vue.delete(state.importFilesById, fileId)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets a calendar for the file
|
||||
*
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 Team Popcorn <teampopcornberlin@gmail.com>
|
||||
* @copyright Copyright (c) 2019 Georg Ehrke
|
||||
* @copyright Copyright (c) 2020 Georg Ehrke
|
||||
*
|
||||
* @author Team Popcorn <teampopcornberlin@gmail.com>
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
|
@ -21,12 +21,13 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
import { IMPORT_STAGE_DEFAULT } from '../models/consts.js'
|
||||
|
||||
const state = {
|
||||
total: 0,
|
||||
accepted: 0,
|
||||
denied: 0,
|
||||
stage: 'default',
|
||||
stage: IMPORT_STAGE_DEFAULT,
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
|
@ -53,7 +54,7 @@ const mutations = {
|
|||
* Set the total number of calendar-objects
|
||||
*
|
||||
* @param {Object} state the store data
|
||||
* @param {string} total the total number of calendar-objects to import
|
||||
* @param {Number} total the total number of calendar-objects to import
|
||||
*/
|
||||
setTotal(state, total) {
|
||||
state.total = total
|
||||
|
@ -63,7 +64,7 @@ const mutations = {
|
|||
* Change stage to the indicated one
|
||||
*
|
||||
* @param {Object} state the store data
|
||||
* @param {string} stage the name of the stage ('default', 'importing', 'parsing', 'done')
|
||||
* @param {String} stage the name of the stage, see /src/models/consts.js
|
||||
*/
|
||||
changeStage(state, stage) {
|
||||
state.stage = stage
|
||||
|
@ -78,7 +79,7 @@ const mutations = {
|
|||
state.total = 0
|
||||
state.accepted = 0
|
||||
state.denied = 0
|
||||
state.stage = 'default'
|
||||
state.stage = IMPORT_STAGE_DEFAULT
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,15 @@
|
|||
*
|
||||
*/
|
||||
import Vue from 'vue'
|
||||
import client from '../services/caldavService.js'
|
||||
import {
|
||||
findPrincipalByUrl,
|
||||
getCurrentUserPrincipal,
|
||||
} from '../services/caldavService.js'
|
||||
import logger from '../utils/logger.js'
|
||||
import { getDefaultPrincipalObject, mapDavToPrincipal } from '../models/principal'
|
||||
import {
|
||||
getDefaultPrincipalObject,
|
||||
mapDavToPrincipal,
|
||||
} from '../models/principal'
|
||||
|
||||
const state = {
|
||||
principals: [],
|
||||
|
@ -112,7 +118,7 @@ const actions = {
|
|||
return
|
||||
}
|
||||
|
||||
const principal = await client.findPrincipal(url)
|
||||
const principal = await findPrincipalByUrl(url)
|
||||
if (!principal) {
|
||||
// TODO - handle error
|
||||
return
|
||||
|
@ -130,7 +136,7 @@ const actions = {
|
|||
* @returns {Promise<void>}
|
||||
*/
|
||||
async fetchCurrentUserPrincipal(context) {
|
||||
const currentUserPrincipal = client.currentUserPrincipal
|
||||
const currentUserPrincipal = getCurrentUserPrincipal()
|
||||
if (!currentUserPrincipal) {
|
||||
// TODO - handle error
|
||||
return
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 Georg Ehrke
|
||||
* @copyright Copyright (c) 2020 Georg Ehrke
|
||||
*
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
*
|
||||
|
@ -19,26 +19,29 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
import HttpClient from '@nextcloud/axios'
|
||||
import client from '../services/caldavService.js'
|
||||
import { getLinkToConfig } from '../utils/settings.js'
|
||||
import { enableBirthdayCalendar } from '../services/caldavService.js'
|
||||
import { mapDavCollectionToCalendar } from '../models/calendar'
|
||||
import detectTimezone from '../services/timezoneDetectionService'
|
||||
import { setConfig } from 'calendar-js'
|
||||
import { detectTimezone } from '../services/timezoneDetectionService'
|
||||
import { setConfig as setCalendarJsConfig } from 'calendar-js'
|
||||
import { setConfig } from '../services/settings.js'
|
||||
import { logInfo } from '../utils/logger.js'
|
||||
|
||||
const state = {
|
||||
// env
|
||||
appVersion: null,
|
||||
eventLimit: null,
|
||||
firstRun: null,
|
||||
momentLocale: 'en',
|
||||
talkEnabled: false,
|
||||
// user-defined calendar settings
|
||||
eventLimit: null,
|
||||
showTasks: null,
|
||||
showWeekends: null,
|
||||
showWeekNumbers: null,
|
||||
skipPopover: null,
|
||||
slotDuration: null,
|
||||
talkEnabled: false,
|
||||
tasksEnabled: false,
|
||||
timezone: null,
|
||||
timezone: 'automatic',
|
||||
// user-defined Nextcloud settings
|
||||
momentLocale: 'en',
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
|
@ -114,48 +117,64 @@ const mutations = {
|
|||
* Initialize settings
|
||||
*
|
||||
* @param {Object} state The Vuex state
|
||||
* @param {Object} settings The full settings object
|
||||
* @param {Object} data The destructuring object
|
||||
* @param {String} data.appVersion The version of the Nextcloud app
|
||||
* @param {Boolean} data.eventLimit Whether or not to limit number of visible events in grid view
|
||||
* @param {Boolean} data.firstRun Whether or not this is the first run
|
||||
* @param {Boolean} data.showWeekNumbers Whether or not to show week numbers
|
||||
* @param {Boolean} data.showTasks Whether or not to display tasks with a due-date
|
||||
* @param {Boolean} data.showWeekends Whether or not to display weekends
|
||||
* @param {Boolean} data.skipPopover Whether or not to skip the simple event popover
|
||||
* @param {String} data.slotDuration The duration of one slot in the agendaView
|
||||
* @param {Boolean} data.talkEnabled Whether or not the talk app is enabled
|
||||
* @param {Boolean} data.tasksEnabled Whether ot not the tasks app is enabled
|
||||
* @param {String} data.timezone The timezone to view the calendar in. Either an Olsen timezone or "automatic"
|
||||
*/
|
||||
loadSettingsFromServer(state, settings) {
|
||||
console.debug('Initial settings:', settings)
|
||||
loadSettingsFromServer(state, { appVersion, eventLimit, firstRun, showWeekNumbers, showTasks, showWeekends, skipPopover, slotDuration, talkEnabled, tasksEnabled, timezone }) {
|
||||
logInfo(`
|
||||
Initial settings:
|
||||
- AppVersion: ${appVersion}
|
||||
- EventLimit: ${eventLimit}
|
||||
- FirstRun: ${firstRun}
|
||||
- ShowWeekNumbers: ${showWeekNumbers}
|
||||
- ShowTasks: ${showTasks}
|
||||
- ShowWeekends: ${showWeekends}
|
||||
- SkipPopover: ${skipPopover}
|
||||
- SlotDuration: ${slotDuration}
|
||||
- TalkEnabled: ${talkEnabled}
|
||||
- TasksEnabled: ${tasksEnabled}
|
||||
- Timezone: ${timezone}
|
||||
`)
|
||||
|
||||
state.appVersion = settings.appVersion
|
||||
state.eventLimit = settings.eventLimit
|
||||
state.firstRun = settings.firstRun
|
||||
state.showWeekNumbers = settings.showWeekNumbers
|
||||
state.showTasks = settings.showTasks
|
||||
state.showWeekends = settings.showWeekends
|
||||
state.skipPopover = settings.skipPopover
|
||||
state.slotDuration = settings.slotDuration
|
||||
state.talkEnabled = settings.talkEnabled
|
||||
state.tasksEnabled = settings.tasksEnabled
|
||||
state.timezone = settings.timezone
|
||||
state.appVersion = appVersion
|
||||
state.eventLimit = eventLimit
|
||||
state.firstRun = firstRun
|
||||
state.showWeekNumbers = showWeekNumbers
|
||||
state.showTasks = showTasks
|
||||
state.showWeekends = showWeekends
|
||||
state.skipPopover = skipPopover
|
||||
state.slotDuration = slotDuration
|
||||
state.talkEnabled = talkEnabled
|
||||
state.tasksEnabled = tasksEnabled
|
||||
state.timezone = timezone
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the name of the moment.js locale to be used
|
||||
*
|
||||
* @param {Object} state The Vuex state
|
||||
* @param {String} locale The moment.js locale to be used
|
||||
* @param {Object} data The destructuring object
|
||||
* @param {String} data.locale The moment.js locale to be used
|
||||
*/
|
||||
setMomentLocale(state, locale) {
|
||||
setMomentLocale(state, { locale }) {
|
||||
logInfo(`Updated moment locale: ${locale}`)
|
||||
|
||||
state.momentLocale = locale
|
||||
},
|
||||
}
|
||||
|
||||
const getters = {
|
||||
|
||||
/**
|
||||
* 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
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the resolved timezone.
|
||||
* If the timezone is set to automatic, it returns the user's current timezone
|
||||
|
@ -174,33 +193,37 @@ const actions = {
|
|||
/**
|
||||
* Updates the user's setting for visibility of birthday calendar
|
||||
*
|
||||
* @param {Object} context The Vuex context
|
||||
* @param {Object} vuex The Vuex destructuring object
|
||||
* @param {Object} vuex.getters The Vuex Getters
|
||||
* @param {Function} vuex.commit The Vuex commit Function
|
||||
* @param {Function} vuex.dispatch The Vuex dispatch Function
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async toggleBirthdayCalendarEnabled(context) {
|
||||
if (context.getters.hasBirthdayCalendar) {
|
||||
const calendar = context.getters.getBirthdayCalendar
|
||||
return context.dispatch('deleteCalendar', { calendar })
|
||||
async toggleBirthdayCalendarEnabled({ getters, commit, dispatch }) {
|
||||
if (getters.hasBirthdayCalendar) {
|
||||
const calendar = getters.getBirthdayCalendar
|
||||
await dispatch('deleteCalendar', { calendar })
|
||||
} else {
|
||||
await client.calendarHomes[0].enableBirthdayCalendar()
|
||||
const davCalendar = await client.calendarHomes[0].find('contact_birthdays')
|
||||
const davCalendar = await enableBirthdayCalendar()
|
||||
const calendar = mapDavCollectionToCalendar(davCalendar)
|
||||
context.commit('addCalendar', { calendar })
|
||||
commit('addCalendar', { calendar })
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the user's setting for event limit
|
||||
*
|
||||
* @param {Object} context The Vuex context
|
||||
* @param {Object} vuex The Vuex destructuring object
|
||||
* @param {Object} vuex.state The Vuex state
|
||||
* @param {Function} vuex.commit The Vuex commit Function
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async toggleEventLimitEnabled(context) {
|
||||
const newState = !context.state.eventLimit
|
||||
async toggleEventLimitEnabled({ state, commit }) {
|
||||
const newState = !state.eventLimit
|
||||
const value = newState ? 'yes' : 'no'
|
||||
|
||||
await HttpClient.post(getLinkToConfig('eventLimit'), { value })
|
||||
context.commit('toggleEventLimitEnabled')
|
||||
await setConfig('eventLimit', value)
|
||||
commit('toggleEventLimitEnabled')
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -209,12 +232,12 @@ const actions = {
|
|||
* @param {Object} context The Vuex context
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async togglePopoverEnabled(context) {
|
||||
const newState = !context.state.skipPopover
|
||||
async togglePopoverEnabled({ state, commit }) {
|
||||
const newState = !state.skipPopover
|
||||
const value = newState ? 'yes' : 'no'
|
||||
|
||||
await HttpClient.post(getLinkToConfig('skipPopover'), { value })
|
||||
context.commit('togglePopoverEnabled')
|
||||
await setConfig('skipPopover', value)
|
||||
commit('togglePopoverEnabled')
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -223,94 +246,96 @@ const actions = {
|
|||
* @param {Object} context The Vuex context
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async toggleWeekendsEnabled(context) {
|
||||
const newState = !context.state.showWeekends
|
||||
async toggleWeekendsEnabled({ state, commit }) {
|
||||
const newState = !state.showWeekends
|
||||
const value = newState ? 'yes' : 'no'
|
||||
|
||||
await HttpClient.post(getLinkToConfig('showWeekends'), { value })
|
||||
context.commit('toggleWeekendsEnabled')
|
||||
await setConfig('showWeekends', value)
|
||||
commit('toggleWeekendsEnabled')
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the user's setting for visibility of tasks
|
||||
*
|
||||
* @param {Object} context The Vuex context
|
||||
* @param {Object} vuex The Vuex destructuring object
|
||||
* @param {Object} vuex.state The Vuex state
|
||||
* @param {Function} vuex.commit The Vuex commit Function
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async toggleTasksEnabled(context) {
|
||||
const newState = !context.state.showTasks
|
||||
async toggleTasksEnabled({ state, commit }) {
|
||||
const newState = !state.showTasks
|
||||
const value = newState ? 'yes' : 'no'
|
||||
|
||||
await HttpClient.post(getLinkToConfig('showTasks'), { value })
|
||||
context.commit('toggleTasksEnabled')
|
||||
context.commit('clearFetchedTimeRanges')
|
||||
context.commit('incrementModificationCount')
|
||||
await setConfig('showTasks', value)
|
||||
commit('toggleTasksEnabled')
|
||||
commit('clearFetchedTimeRanges')
|
||||
commit('incrementModificationCount')
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the user's setting for visibility of week numbers
|
||||
*
|
||||
* @param {Object} context The Vuex context
|
||||
* @param {Object} vuex The Vuex destructuring object
|
||||
* @param {Object} vuex.state The Vuex state
|
||||
* @param {Function} vuex.commit The Vuex commit Function
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async toggleWeekNumberEnabled(context) {
|
||||
const newState = !context.state.showWeekNumbers
|
||||
async toggleWeekNumberEnabled({ state, commit }) {
|
||||
const newState = !state.showWeekNumbers
|
||||
const value = newState ? 'yes' : 'no'
|
||||
|
||||
await HttpClient.post(getLinkToConfig('showWeekNr'), { value })
|
||||
context.commit('toggleWeekNumberEnabled')
|
||||
await setConfig('showWeekNr', value)
|
||||
commit('toggleWeekNumberEnabled')
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the view to be used as initial view when opening
|
||||
* the calendar app again
|
||||
*
|
||||
* @param {Object} context The Vuex context
|
||||
* @param {Object} context The Vuex destructuring object
|
||||
* @param {Object} data The destructuring object
|
||||
* @param {String} data.initialView New view to be used as initial view
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async setInitialView(context, { initialView }) {
|
||||
await HttpClient.post(getLinkToConfig('view'), {
|
||||
value: initialView,
|
||||
})
|
||||
await setConfig('view', initialView)
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the user's preferred slotDuration
|
||||
*
|
||||
* @param {Object} context The Vuex context
|
||||
* @param {Object} vuex The Vuex destructuring object
|
||||
* @param {Object} vuex.state The Vuex state
|
||||
* @param {Function} vuex.commit The Vuex commit Function
|
||||
* @param {Object} data The destructuring object
|
||||
* @param {String} data.slotDuration The new slot duration
|
||||
*/
|
||||
async setSlotDuration(context, { slotDuration }) {
|
||||
if (context.state.slotDuration === slotDuration) {
|
||||
async setSlotDuration({ state, commit }, { slotDuration }) {
|
||||
if (state.slotDuration === slotDuration) {
|
||||
return
|
||||
}
|
||||
|
||||
await HttpClient.post(getLinkToConfig('slotDuration'), {
|
||||
value: slotDuration,
|
||||
})
|
||||
context.commit('setSlotDuration', { slotDuration })
|
||||
await setConfig('slotDuration', slotDuration)
|
||||
commit('setSlotDuration', { slotDuration })
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the user's timezone
|
||||
*
|
||||
* @param {Object} context The Vuex context
|
||||
* @param {Object} vuex The Vuex destructuring object
|
||||
* @param {Object} vuex.state The Vuex state
|
||||
* @param {Function} vuex.commit The Vuex commit Function
|
||||
* @param {Object} data The destructuring object
|
||||
* @param {String} data.timezoneId The new timezone
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async setTimezone(context, { timezoneId }) {
|
||||
if (context.state.timezone === timezoneId) {
|
||||
async setTimezone({ state, commit }, { timezoneId }) {
|
||||
if (state.timezone === timezoneId) {
|
||||
return
|
||||
}
|
||||
|
||||
await HttpClient.post(getLinkToConfig('timezone'), {
|
||||
value: timezoneId,
|
||||
})
|
||||
context.commit('setTimezone', { timezoneId })
|
||||
await setConfig('timezone', timezoneId)
|
||||
commit('setTimezone', { timezoneId })
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -320,8 +345,8 @@ const actions = {
|
|||
* @param {Object} vuex.state The Vuex state
|
||||
*/
|
||||
initializeCalendarJsConfig({ state }) {
|
||||
setConfig('PRODID', `-//IDN nextcloud.com//Calendar app ${state.appVersion}//EN`)
|
||||
setConfig('property-list-significant-change', [
|
||||
setCalendarJsConfig('PRODID', `-//IDN nextcloud.com//Calendar app ${state.appVersion}//EN`)
|
||||
setCalendarJsConfig('property-list-significant-change', [
|
||||
'SUMMARY',
|
||||
'LOCATION',
|
||||
'DESCRIPTION',
|
||||
|
|
|
@ -20,17 +20,67 @@
|
|||
*
|
||||
*/
|
||||
import { getLoggerBuilder } from '@nextcloud/logger'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
|
||||
const builder = getLoggerBuilder()
|
||||
const user = getCurrentUser()
|
||||
const logger = getLoggerBuilder()
|
||||
.setApp('calendar')
|
||||
.detectUser()
|
||||
.build()
|
||||
|
||||
builder.setApp('calendar')
|
||||
if (user) {
|
||||
builder.setUid('authenticated:' + user.uid)
|
||||
} else {
|
||||
builder.setUid('unauthenticated')
|
||||
/**
|
||||
* Logs a debug message
|
||||
*
|
||||
* @param {String} message The message to log
|
||||
* @param {Object=} context Additional context if needed
|
||||
*/
|
||||
const logDebug = (message, context = {}) => {
|
||||
logger.debug(message, context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an error message
|
||||
*
|
||||
* @param {String} message The message to log
|
||||
* @param {Object=} context Additional context if needed
|
||||
*/
|
||||
const logError = (message, context = {}) => {
|
||||
logger.error(message, context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a fatal message
|
||||
*
|
||||
* @param {String} message The message to log
|
||||
* @param {Object=} context Additional context if needed
|
||||
*/
|
||||
const logFatal = (message, context = {}) => {
|
||||
logger.fatal(message, context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an info message
|
||||
*
|
||||
* @param {String} message The message to log
|
||||
* @param {Object=} context Additional context if needed
|
||||
*/
|
||||
const logInfo = (message, context = {}) => {
|
||||
logger.info(message, context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a warn message
|
||||
*
|
||||
* @param {String} message The message to log
|
||||
* @param {Object=} context Additional context if needed
|
||||
*/
|
||||
const logWarn = (message, context = {}) => {
|
||||
logger.warn(message, context)
|
||||
}
|
||||
|
||||
const logger = builder.build()
|
||||
export default logger
|
||||
export {
|
||||
logDebug,
|
||||
logError,
|
||||
logFatal,
|
||||
logInfo,
|
||||
logWarn,
|
||||
}
|
||||
|
|
|
@ -98,7 +98,10 @@ import AppContent from '@nextcloud/vue/dist/Components/AppContent'
|
|||
import Content from '@nextcloud/vue/dist/Components/Content'
|
||||
import debounce from 'debounce'
|
||||
import { uidToHexColor } from '../utils/color.js'
|
||||
import client from '../services/caldavService.js'
|
||||
import {
|
||||
initializeClientForPublicView,
|
||||
initializeClientForUserView,
|
||||
} from '../services/caldavService.js'
|
||||
import {
|
||||
dateFactory,
|
||||
getUnixTimestampFromDate,
|
||||
|
@ -311,7 +314,7 @@ export default {
|
|||
this.$store.dispatch('initializeCalendarJsConfig')
|
||||
|
||||
if (this.$route.name.startsWith('Public') || this.$route.name.startsWith('Embed')) {
|
||||
client._createPublicCalendarHome()
|
||||
await initializeClientForPublicView()
|
||||
const tokens = this.$route.params.tokens.split('-')
|
||||
const calendars = await this.$store.dispatch('getPublicCalendars', { tokens })
|
||||
this.loadingCalendars = false
|
||||
|
@ -320,7 +323,7 @@ export default {
|
|||
this.showEmptyCalendarScreen = true
|
||||
}
|
||||
} else {
|
||||
await client.connect({ enableCalDAV: true })
|
||||
await initializeClientForUserView()
|
||||
await this.$store.dispatch('fetchCurrentUserPrincipal')
|
||||
const calendars = await this.$store.dispatch('getCalendars')
|
||||
const owners = []
|
||||
|
@ -438,8 +441,8 @@ export default {
|
|||
* @returns {Promise<void>}
|
||||
*/
|
||||
async loadMomentLocale() {
|
||||
const momentLocale = await loadMomentLocalization()
|
||||
this.$store.commit('setMomentLocale', momentLocale)
|
||||
const locale = await loadMomentLocalization()
|
||||
this.$store.commit('setMomentLocale', { locale })
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2020 Georg Ehrke
|
||||
*
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
*
|
||||
* @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 HttpClient from '@nextcloud/axios'
|
||||
import { getLinkToConfig } from '../../../../src/utils/settings.js'
|
||||
import {setConfig} from "../../../../src/services/settings.js";
|
||||
|
||||
jest.mock('@nextcloud/axios')
|
||||
jest.mock('../../../../src/utils/settings.js')
|
||||
|
||||
describe('Test suite: Settings service (services/settings.js)', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
HttpClient.post.mockClear()
|
||||
getLinkToConfig.mockClear()
|
||||
})
|
||||
|
||||
it('should provide a setConfig method', () => {
|
||||
getLinkToConfig.mockReturnValueOnce('url-to-config-key')
|
||||
|
||||
setConfig('key42', 'value1337')
|
||||
|
||||
expect(getLinkToConfig).toHaveBeenCalledTimes(1)
|
||||
expect(getLinkToConfig).toHaveBeenNthCalledWith(1, 'key42')
|
||||
|
||||
expect(HttpClient.post).toHaveBeenCalledTimes(1)
|
||||
expect(HttpClient.post).toHaveBeenNthCalledWith(1, 'url-to-config-key', {
|
||||
value: 'value1337'
|
||||
})
|
||||
})
|
||||
|
||||
})
|
|
@ -165,7 +165,7 @@ describe('services/windowTitleService', () => {
|
|||
|
||||
store.subscribe.mock.calls[0][0]({
|
||||
type: 'setMomentLocale',
|
||||
payload: 'momentLocaleFromPayload'
|
||||
payload: { locale: 'momentLocaleFromPayload' }
|
||||
})
|
||||
|
||||
expect(document.title).toEqual('formatted date range - Standard Nextcloud title')
|
||||
|
|
|
@ -19,11 +19,125 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
import contactsStore from '../../../../src/store/contacts.js'
|
||||
|
||||
describe('store/contacts test suite', () => {
|
||||
|
||||
it('should be true', () => {
|
||||
expect(true).toEqual(true)
|
||||
it('should provide a default state', () => {
|
||||
expect(contactsStore.state.contacts).toEqual([])
|
||||
expect(contactsStore.state.contactByEMail).toEqual({})
|
||||
})
|
||||
|
||||
it('should provide a mutation to add a contact', () => {
|
||||
const state = {
|
||||
contacts: [],
|
||||
contactByEMail: {},
|
||||
}
|
||||
|
||||
const contact1 = {
|
||||
name: 'John Doe',
|
||||
emails: ['john.doe@example.com'],
|
||||
}
|
||||
const contact2 = {
|
||||
name: 'Jane Doe',
|
||||
emails: ['jane.doe@example.com'],
|
||||
}
|
||||
const contact3 = {
|
||||
name: 'John Doe Doppelgänger',
|
||||
emails: [
|
||||
'john.doe@example.com',
|
||||
'john.doe.doppelganger@example.com',
|
||||
],
|
||||
}
|
||||
|
||||
contactsStore.mutations.appendContact(state, { contact: contact1 })
|
||||
contactsStore.mutations.appendContact(state, { contact: contact2 })
|
||||
contactsStore.mutations.appendContact(state, { contact: contact3 })
|
||||
|
||||
// It should not add the same again:
|
||||
contactsStore.mutations.appendContact(state, { contact: contact1 })
|
||||
|
||||
expect(state.contacts).toEqual([
|
||||
contact1,
|
||||
contact2,
|
||||
contact3,
|
||||
])
|
||||
|
||||
expect(state.contactByEMail).toEqual({
|
||||
'john.doe@example.com': contact1,
|
||||
'jane.doe@example.com': contact2,
|
||||
'john.doe.doppelganger@example.com': contact3,
|
||||
})
|
||||
})
|
||||
|
||||
it('should provide a mutation to remove a contact - existing', () => {
|
||||
const contact1 = {
|
||||
name: 'John Doe',
|
||||
emails: ['john.doe@example.com'],
|
||||
}
|
||||
const contact2 = {
|
||||
name: 'Jane Doe',
|
||||
emails: ['jane.doe@example.com'],
|
||||
}
|
||||
|
||||
const state = {
|
||||
contacts: [
|
||||
contact1,
|
||||
contact2,
|
||||
],
|
||||
contactByEMail: {
|
||||
'john.doe@example.com': contact1,
|
||||
'jane.doe@example.com': contact2,
|
||||
},
|
||||
}
|
||||
|
||||
contactsStore.mutations.removeContact(state, { contact: contact1 })
|
||||
|
||||
expect(state.contacts).toEqual([
|
||||
contact2,
|
||||
])
|
||||
|
||||
expect(state.contactByEMail).toEqual({
|
||||
'jane.doe@example.com': contact2,
|
||||
})
|
||||
})
|
||||
|
||||
it('should provide a mutation to remove a contact - non-existing', () => {
|
||||
const contact1 = {
|
||||
name: 'John Doe',
|
||||
emails: ['john.doe@example.com'],
|
||||
}
|
||||
const contact2 = {
|
||||
name: 'Jane Doe',
|
||||
emails: ['jane.doe@example.com'],
|
||||
}
|
||||
|
||||
const state = {
|
||||
contacts: [
|
||||
contact1,
|
||||
contact2,
|
||||
],
|
||||
contactByEMail: {
|
||||
'john.doe@example.com': contact1,
|
||||
'jane.doe@example.com': contact2,
|
||||
},
|
||||
}
|
||||
|
||||
const unknownContact = {
|
||||
name: 'Foo Bar',
|
||||
emails: ['foo.bar@example.com'],
|
||||
}
|
||||
|
||||
contactsStore.mutations.removeContact(state, { contact: unknownContact })
|
||||
|
||||
expect(state.contacts).toEqual([
|
||||
contact1,
|
||||
contact2,
|
||||
])
|
||||
|
||||
expect(state.contactByEMail).toEqual({
|
||||
'john.doe@example.com': contact1,
|
||||
'jane.doe@example.com': contact2,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -19,11 +19,35 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
import davRestrictionsStore from '../../../../src/store/davRestrictions.js'
|
||||
|
||||
describe('store/davRestrictions test suite', () => {
|
||||
|
||||
it('should be true', () => {
|
||||
expect(true).toEqual(true)
|
||||
it('should provide a default state', () => {
|
||||
// Minimum Date should be the start of Unix-Date
|
||||
expect(davRestrictionsStore.state.minimumDate).toEqual('1970-01-01T00:00:00Z')
|
||||
|
||||
// Maximum Date should prevent the Year 2038 problem
|
||||
expect(davRestrictionsStore.state.maximumDate).toEqual('2037-12-31T23:59:59Z')
|
||||
})
|
||||
|
||||
it('should provide a mutation to set the default value', () => {
|
||||
const state = {
|
||||
minimumDate: '1970-01-01T00:00:00Z',
|
||||
maximumDate: '2037-12-31T23:59:59Z',
|
||||
otherProp: 'foo',
|
||||
}
|
||||
|
||||
davRestrictionsStore.mutations.loadDavRestrictionsFromServer(state, {
|
||||
minimumDate: '2010-01-01T00:00:00Z',
|
||||
maximumDate: '2019-12-31T23:59:59Z',
|
||||
})
|
||||
|
||||
expect(state).toEqual({
|
||||
minimumDate: '2010-01-01T00:00:00Z',
|
||||
maximumDate: '2019-12-31T23:59:59Z',
|
||||
otherProp: 'foo',
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 Georg Ehrke
|
||||
* @copyright Copyright (c) 2020 Georg Ehrke
|
||||
*
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
*
|
||||
|
@ -19,11 +19,124 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
import importFilesStore from '../../../../src/store/importFiles.js'
|
||||
|
||||
describe('store/importFiles test suite', () => {
|
||||
|
||||
it('should be true', () => {
|
||||
expect(true).toEqual(true)
|
||||
it('should provide a default state', () => {
|
||||
expect(importFilesStore.state).toEqual({
|
||||
lastFileInsertId: -1,
|
||||
importFiles: [],
|
||||
importFilesById: {},
|
||||
importCalendarRelation: {},
|
||||
})
|
||||
})
|
||||
|
||||
it('should provide a mutation to add a file', () => {
|
||||
const state = {
|
||||
lastFileInsertId: 41,
|
||||
importFiles: [],
|
||||
importFilesById: {},
|
||||
}
|
||||
|
||||
const file1 = {
|
||||
contents: 'BEGIN:VCALENDAR...',
|
||||
lastModified: 1590151056,
|
||||
name: 'file-1.ics',
|
||||
parser: {},
|
||||
size: 1337,
|
||||
type: 'text/calendar',
|
||||
}
|
||||
const file2 = {
|
||||
contents: '{}',
|
||||
lastModified: 1590151056,
|
||||
name: 'file-2.ics',
|
||||
parser: {},
|
||||
size: 42,
|
||||
type: 'application/json+calendar',
|
||||
}
|
||||
|
||||
importFilesStore.mutations.addFile(state, file1)
|
||||
importFilesStore.mutations.addFile(state, file2)
|
||||
|
||||
expect(state.importFiles).toEqual([
|
||||
{
|
||||
...file1,
|
||||
id: 42,
|
||||
}, {
|
||||
...file2,
|
||||
id: 43,
|
||||
}
|
||||
])
|
||||
|
||||
expect(state.importFilesById[42]).toEqual({
|
||||
...file1,
|
||||
id: 42,
|
||||
})
|
||||
expect(state.importFilesById[43]).toEqual({
|
||||
...file2,
|
||||
id: 43,
|
||||
})
|
||||
})
|
||||
|
||||
it('should provide a mutation to set a calendarId for a file', () => {
|
||||
const state = {
|
||||
importCalendarRelation: {},
|
||||
}
|
||||
|
||||
importFilesStore.mutations.setCalendarForFileId(state, { fileId: 0, calendarId: 'CALENDAR-ID-1' })
|
||||
importFilesStore.mutations.setCalendarForFileId(state, { fileId: 42, calendarId: 'CALENDAR-ID-1' })
|
||||
|
||||
expect(state.importCalendarRelation).toEqual({
|
||||
0: 'CALENDAR-ID-1',
|
||||
42: 'CALENDAR-ID-1',
|
||||
})
|
||||
})
|
||||
|
||||
it('should provide a mutation to remove all files', () => {
|
||||
const file1 = {
|
||||
id: 0,
|
||||
contents: 'BEGIN:VCALENDAR...',
|
||||
lastModified: 1590151056,
|
||||
name: 'file-1.ics',
|
||||
parser: {},
|
||||
size: 1337,
|
||||
type: 'text/calendar',
|
||||
}
|
||||
const file2 = {
|
||||
id: 1,
|
||||
contents: '{}',
|
||||
lastModified: 1590151056,
|
||||
name: 'file-2.ics',
|
||||
parser: {},
|
||||
size: 42,
|
||||
type: 'application/json+calendar',
|
||||
}
|
||||
|
||||
const state = {
|
||||
lastFileInsertId: 1,
|
||||
importFiles: [
|
||||
file1,
|
||||
file2,
|
||||
],
|
||||
importFilesById: {
|
||||
0: file1,
|
||||
1: file2,
|
||||
},
|
||||
importCalendarRelation: {
|
||||
0: 'CALENDAR-ID-1',
|
||||
1: 'CALENDAR-ID-1',
|
||||
},
|
||||
}
|
||||
|
||||
importFilesStore.mutations.removeAllFiles(state)
|
||||
|
||||
expect(state).toEqual({
|
||||
lastFileInsertId: 1,
|
||||
importFiles: [],
|
||||
importFilesById: {},
|
||||
importCalendarRelation: {},
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
|
|
@ -19,11 +19,89 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
import importStateStore from '../../../../src/store/importState.js'
|
||||
import {
|
||||
IMPORT_STAGE_AWAITING_USER_SELECT,
|
||||
IMPORT_STAGE_DEFAULT,
|
||||
IMPORT_STAGE_IMPORTING,
|
||||
IMPORT_STAGE_PROCESSING
|
||||
} from "../../../../src/models/consts.js";
|
||||
|
||||
describe('store/importState test suite', () => {
|
||||
|
||||
it('should be true', () => {
|
||||
expect(true).toEqual(true)
|
||||
it('should provide a default state', () => {
|
||||
expect(importStateStore.state).toEqual({
|
||||
total: 0,
|
||||
accepted: 0,
|
||||
denied: 0,
|
||||
stage: IMPORT_STAGE_DEFAULT,
|
||||
})
|
||||
})
|
||||
|
||||
it('should provide a mutation to increment the amount of accepted imports', () => {
|
||||
const state = {
|
||||
accepted: 5,
|
||||
}
|
||||
|
||||
importStateStore.mutations.incrementAccepted(state)
|
||||
|
||||
expect(state.accepted).toEqual(6)
|
||||
})
|
||||
|
||||
it('should provide a mutation to increment the amount of rejected imports', () => {
|
||||
const state = {
|
||||
denied: 41,
|
||||
}
|
||||
|
||||
importStateStore.mutations.incrementDenied(state)
|
||||
|
||||
expect(state.denied).toEqual(42)
|
||||
})
|
||||
|
||||
it('should provide a mutation to increment the total amount of objects', () => {
|
||||
const state = {
|
||||
total: 5,
|
||||
}
|
||||
|
||||
importStateStore.mutations.setTotal(state, 1337)
|
||||
|
||||
expect(state.total).toEqual(1337)
|
||||
})
|
||||
|
||||
it('should provide a mutation to change the stage of the import', () => {
|
||||
const state = {
|
||||
stage: null,
|
||||
}
|
||||
|
||||
importStateStore.mutations.changeStage(state, IMPORT_STAGE_DEFAULT)
|
||||
expect(state.stage).toEqual(IMPORT_STAGE_DEFAULT)
|
||||
|
||||
importStateStore.mutations.changeStage(state, IMPORT_STAGE_PROCESSING)
|
||||
expect(state.stage).toEqual(IMPORT_STAGE_PROCESSING)
|
||||
|
||||
importStateStore.mutations.changeStage(state, IMPORT_STAGE_IMPORTING)
|
||||
expect(state.stage).toEqual(IMPORT_STAGE_IMPORTING)
|
||||
|
||||
importStateStore.mutations.changeStage(state, IMPORT_STAGE_AWAITING_USER_SELECT)
|
||||
expect(state.stage).toEqual(IMPORT_STAGE_AWAITING_USER_SELECT)
|
||||
})
|
||||
|
||||
it('should provide a mutation to reset the state', () => {
|
||||
const state = {
|
||||
stage: IMPORT_STAGE_AWAITING_USER_SELECT,
|
||||
total: 1337,
|
||||
accepted: 42,
|
||||
denied: 500,
|
||||
}
|
||||
|
||||
importStateStore.mutations.resetState(state)
|
||||
|
||||
expect(state).toEqual({
|
||||
total: 0,
|
||||
accepted: 0,
|
||||
denied: 0,
|
||||
stage: IMPORT_STAGE_DEFAULT,
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
|
|
@ -19,11 +19,568 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
import settingsStore from '../../../../src/store/settings.js'
|
||||
import { enableBirthdayCalendar } from '../../../../src/services/caldavService.js'
|
||||
import { mapDavCollectionToCalendar } from '../../../../src/models/calendar.js'
|
||||
import { detectTimezone } from '../../../../src/services/timezoneDetectionService.js'
|
||||
import { setConfig as setCalendarJsConfig } from 'calendar-js'
|
||||
import { setConfig } from '../../../../src/services/settings.js'
|
||||
import { logInfo } from '../../../../src/utils/logger.js'
|
||||
|
||||
jest.mock('../../../../src/services/caldavService.js')
|
||||
jest.mock('../../../../src/models/calendar.js')
|
||||
jest.mock('../../../../src/services/timezoneDetectionService.js')
|
||||
jest.mock('calendar-js')
|
||||
jest.mock('../../../../src/services/settings.js')
|
||||
jest.mock('../../../../src/utils/logger.js')
|
||||
|
||||
describe('store/settings test suite', () => {
|
||||
|
||||
it('should be true', () => {
|
||||
expect(true).toEqual(true)
|
||||
beforeEach(() => {
|
||||
enableBirthdayCalendar.mockClear()
|
||||
mapDavCollectionToCalendar.mockClear()
|
||||
detectTimezone.mockClear()
|
||||
setCalendarJsConfig.mockClear()
|
||||
setConfig.mockClear()
|
||||
logInfo.mockClear()
|
||||
})
|
||||
|
||||
it('should provide a default state', () => {
|
||||
expect(settingsStore.state).toEqual({
|
||||
appVersion: null,
|
||||
firstRun: null,
|
||||
talkEnabled: false,
|
||||
eventLimit: null,
|
||||
showTasks: null,
|
||||
showWeekends: null,
|
||||
showWeekNumbers: null,
|
||||
skipPopover: null,
|
||||
slotDuration: null,
|
||||
tasksEnabled: false,
|
||||
timezone: 'automatic',
|
||||
momentLocale: 'en',
|
||||
})
|
||||
})
|
||||
|
||||
it('should provide a mutation to toggle the eventLimit setting', () => {
|
||||
const state = {
|
||||
eventLimit: false,
|
||||
}
|
||||
|
||||
settingsStore.mutations.toggleEventLimitEnabled(state)
|
||||
expect(state.eventLimit).toEqual(true)
|
||||
|
||||
settingsStore.mutations.toggleEventLimitEnabled(state)
|
||||
expect(state.eventLimit).toEqual(false)
|
||||
})
|
||||
|
||||
it('should provide a mutation to toggle the popover setting', () => {
|
||||
const state = {
|
||||
skipPopover: false,
|
||||
}
|
||||
|
||||
settingsStore.mutations.togglePopoverEnabled(state)
|
||||
expect(state.skipPopover).toEqual(true)
|
||||
|
||||
settingsStore.mutations.togglePopoverEnabled(state)
|
||||
expect(state.skipPopover).toEqual(false)
|
||||
})
|
||||
|
||||
it('should provide a mutation to toggle the task setting', () => {
|
||||
const state = {
|
||||
showTasks: false,
|
||||
}
|
||||
|
||||
settingsStore.mutations.toggleTasksEnabled(state)
|
||||
expect(state.showTasks).toEqual(true)
|
||||
|
||||
settingsStore.mutations.toggleTasksEnabled(state)
|
||||
expect(state.showTasks).toEqual(false)
|
||||
})
|
||||
|
||||
it('should provide a mutation to toggle the weekends setting', () => {
|
||||
const state = {
|
||||
showWeekends: false,
|
||||
}
|
||||
|
||||
settingsStore.mutations.toggleWeekendsEnabled(state)
|
||||
expect(state.showWeekends).toEqual(true)
|
||||
|
||||
settingsStore.mutations.toggleWeekendsEnabled(state)
|
||||
expect(state.showWeekends).toEqual(false)
|
||||
})
|
||||
|
||||
it('should provide a mutation to toggle the week-number setting', () => {
|
||||
const state = {
|
||||
showWeekNumbers: false,
|
||||
}
|
||||
|
||||
settingsStore.mutations.toggleWeekNumberEnabled(state)
|
||||
expect(state.showWeekNumbers).toEqual(true)
|
||||
|
||||
settingsStore.mutations.toggleWeekNumberEnabled(state)
|
||||
expect(state.showWeekNumbers).toEqual(false)
|
||||
})
|
||||
|
||||
it('should provide a mutation to set the slot duration setting', () => {
|
||||
const state = {
|
||||
slotDuration: 'previousValue',
|
||||
}
|
||||
|
||||
settingsStore.mutations.setSlotDuration(state, { slotDuration: '00:30:00' })
|
||||
expect(state.slotDuration).toEqual('00:30:00')
|
||||
})
|
||||
|
||||
it('should provide a mutation to set the timezone setting', () => {
|
||||
const state = {
|
||||
timezone: 'previousValue',
|
||||
}
|
||||
|
||||
settingsStore.mutations.setTimezone(state, { timezoneId: 'Europe/Berlin' })
|
||||
expect(state.timezone).toEqual('Europe/Berlin')
|
||||
})
|
||||
|
||||
it('should provide a mutation to set the settings initially', () => {
|
||||
const state = {
|
||||
appVersion: null,
|
||||
firstRun: null,
|
||||
talkEnabled: false,
|
||||
eventLimit: null,
|
||||
showTasks: null,
|
||||
showWeekends: null,
|
||||
showWeekNumbers: null,
|
||||
skipPopover: null,
|
||||
slotDuration: null,
|
||||
tasksEnabled: false,
|
||||
timezone: 'automatic',
|
||||
momentLocale: 'en',
|
||||
otherProp: 'bar',
|
||||
}
|
||||
|
||||
const settings = {
|
||||
appVersion: '2.1.0',
|
||||
eventLimit: false,
|
||||
firstRun: true,
|
||||
showWeekNumbers: true,
|
||||
showTasks: false,
|
||||
showWeekends: true,
|
||||
skipPopover: true,
|
||||
slotDuration: '00:30:00',
|
||||
talkEnabled: false,
|
||||
tasksEnabled: true,
|
||||
timezone: 'Europe/Berlin',
|
||||
otherUnknownSetting: 'foo',
|
||||
}
|
||||
|
||||
settingsStore.mutations.loadSettingsFromServer(state, settings)
|
||||
|
||||
expect(logInfo).toHaveBeenCalledTimes(1)
|
||||
expect(logInfo).toHaveBeenNthCalledWith(1, `
|
||||
Initial settings:
|
||||
- AppVersion: 2.1.0
|
||||
- EventLimit: false
|
||||
- FirstRun: true
|
||||
- ShowWeekNumbers: true
|
||||
- ShowTasks: false
|
||||
- ShowWeekends: true
|
||||
- SkipPopover: true
|
||||
- SlotDuration: 00:30:00
|
||||
- TalkEnabled: false
|
||||
- TasksEnabled: true
|
||||
- Timezone: Europe/Berlin
|
||||
`)
|
||||
expect(state).toEqual({
|
||||
appVersion: '2.1.0',
|
||||
eventLimit: false,
|
||||
firstRun: true,
|
||||
showWeekNumbers: true,
|
||||
showTasks: false,
|
||||
showWeekends: true,
|
||||
skipPopover: true,
|
||||
slotDuration: '00:30:00',
|
||||
talkEnabled: false,
|
||||
tasksEnabled: true,
|
||||
timezone: 'Europe/Berlin',
|
||||
momentLocale: 'en',
|
||||
otherProp: 'bar',
|
||||
})
|
||||
})
|
||||
|
||||
it('should provide a mutation to set the resolved moment locale', () => {
|
||||
const state = {
|
||||
appVersion: null,
|
||||
firstRun: null,
|
||||
talkEnabled: false,
|
||||
eventLimit: null,
|
||||
showTasks: null,
|
||||
showWeekends: null,
|
||||
showWeekNumbers: null,
|
||||
skipPopover: null,
|
||||
slotDuration: null,
|
||||
tasksEnabled: false,
|
||||
timezone: 'automatic',
|
||||
momentLocale: 'en',
|
||||
otherProp: 'bar',
|
||||
}
|
||||
|
||||
settingsStore.mutations.setMomentLocale(state, { locale: 'de' })
|
||||
expect(logInfo).toHaveBeenCalledTimes(1)
|
||||
expect(logInfo).toHaveBeenNthCalledWith(1, `Updated moment locale: de`)
|
||||
|
||||
expect(state).toEqual({
|
||||
appVersion: null,
|
||||
firstRun: null,
|
||||
talkEnabled: false,
|
||||
eventLimit: null,
|
||||
showTasks: null,
|
||||
showWeekends: null,
|
||||
showWeekNumbers: null,
|
||||
skipPopover: null,
|
||||
slotDuration: null,
|
||||
tasksEnabled: false,
|
||||
timezone: 'automatic',
|
||||
momentLocale: 'de',
|
||||
otherProp: 'bar',
|
||||
})
|
||||
})
|
||||
|
||||
it('should provide a getter the get the resolved timezone - automatic', () => {
|
||||
const state = {
|
||||
timezone: 'automatic'
|
||||
}
|
||||
|
||||
detectTimezone
|
||||
.mockReturnValueOnce('Europe/Berlin')
|
||||
|
||||
expect(settingsStore.getters.getResolvedTimezone(state)).toEqual('Europe/Berlin')
|
||||
|
||||
expect(detectTimezone).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('should provide a getter the get the resolved timezone - non-automatic', () => {
|
||||
const state = {
|
||||
timezone: 'Europe/Berlin'
|
||||
}
|
||||
|
||||
expect(settingsStore.getters.getResolvedTimezone(state)).toEqual('Europe/Berlin')
|
||||
|
||||
expect(detectTimezone).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
|
||||
it('should provide an action to toggle the birthday calendar - enabled to disabled', async () => {
|
||||
expect.assertions(3)
|
||||
|
||||
const getters = {
|
||||
hasBirthdayCalendar: true,
|
||||
getBirthdayCalendar: {
|
||||
id: 'contact_birthdays'
|
||||
}
|
||||
}
|
||||
const commit = jest.fn()
|
||||
const dispatch = jest.fn()
|
||||
|
||||
dispatch.mockResolvedValueOnce()
|
||||
|
||||
await settingsStore.actions.toggleBirthdayCalendarEnabled({ getters, commit, dispatch })
|
||||
|
||||
expect(dispatch).toHaveBeenCalledTimes(1)
|
||||
expect(dispatch).toHaveBeenNthCalledWith(1, 'deleteCalendar', { calendar: getters.getBirthdayCalendar })
|
||||
expect(commit).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
|
||||
it('should provide an action to toggle the birthday calendar - disabled to enabled', async () => {
|
||||
expect.assertions(5)
|
||||
|
||||
const getters = {
|
||||
hasBirthdayCalendar: false,
|
||||
getBirthdayCalendar: null,
|
||||
}
|
||||
const commit = jest.fn()
|
||||
const dispatch = jest.fn()
|
||||
|
||||
const davCalendar = {
|
||||
davCalendar: true
|
||||
}
|
||||
enableBirthdayCalendar.mockResolvedValueOnce(davCalendar)
|
||||
|
||||
const calendar = {
|
||||
id: 'new-birthday-calendar'
|
||||
}
|
||||
mapDavCollectionToCalendar.mockReturnValueOnce(calendar)
|
||||
|
||||
await settingsStore.actions.toggleBirthdayCalendarEnabled({ getters, commit, dispatch })
|
||||
|
||||
expect(enableBirthdayCalendar).toHaveBeenCalledTimes(1)
|
||||
expect(mapDavCollectionToCalendar).toHaveBeenCalledTimes(1)
|
||||
expect(mapDavCollectionToCalendar).toHaveBeenNthCalledWith(1, davCalendar)
|
||||
expect(commit).toHaveBeenCalledTimes(1)
|
||||
expect(commit).toHaveBeenNthCalledWith(1, 'addCalendar', { calendar })
|
||||
|
||||
})
|
||||
|
||||
it('should provide an action to toggle the event limit setting - false to true', async () => {
|
||||
expect.assertions(4)
|
||||
|
||||
const state = {
|
||||
eventLimit: false,
|
||||
}
|
||||
const commit = jest.fn()
|
||||
|
||||
setConfig.mockReturnValueOnce()
|
||||
|
||||
await settingsStore.actions.toggleEventLimitEnabled({ state, commit })
|
||||
expect(setConfig).toHaveBeenCalledTimes(1)
|
||||
expect(setConfig).toHaveBeenNthCalledWith(1, 'eventLimit', 'yes')
|
||||
expect(commit).toHaveBeenCalledTimes(1)
|
||||
expect(commit).toHaveBeenNthCalledWith(1, 'toggleEventLimitEnabled')
|
||||
})
|
||||
|
||||
it('should provide an action to toggle the event limit setting - true to false', async () => {
|
||||
expect.assertions(4)
|
||||
|
||||
const state = {
|
||||
eventLimit: true,
|
||||
}
|
||||
const commit = jest.fn()
|
||||
|
||||
setConfig.mockReturnValueOnce()
|
||||
|
||||
await settingsStore.actions.toggleEventLimitEnabled({ state, commit })
|
||||
expect(setConfig).toHaveBeenCalledTimes(1)
|
||||
expect(setConfig).toHaveBeenNthCalledWith(1, 'eventLimit', 'no')
|
||||
expect(commit).toHaveBeenCalledTimes(1)
|
||||
expect(commit).toHaveBeenNthCalledWith(1, 'toggleEventLimitEnabled')
|
||||
|
||||
})
|
||||
|
||||
it('should provide an action to toggle the popover setting - false to true', async () => {
|
||||
expect.assertions(4)
|
||||
|
||||
const state = {
|
||||
skipPopover: false,
|
||||
}
|
||||
const commit = jest.fn()
|
||||
|
||||
setConfig.mockReturnValueOnce()
|
||||
|
||||
await settingsStore.actions.togglePopoverEnabled({ state, commit })
|
||||
expect(setConfig).toHaveBeenCalledTimes(1)
|
||||
expect(setConfig).toHaveBeenNthCalledWith(1, 'skipPopover', 'yes')
|
||||
expect(commit).toHaveBeenCalledTimes(1)
|
||||
expect(commit).toHaveBeenNthCalledWith(1, 'togglePopoverEnabled')
|
||||
})
|
||||
|
||||
it('should provide an action to toggle the popover setting - true to false', async () => {
|
||||
expect.assertions(4)
|
||||
|
||||
const state = {
|
||||
skipPopover: true,
|
||||
}
|
||||
const commit = jest.fn()
|
||||
|
||||
setConfig.mockReturnValueOnce()
|
||||
|
||||
await settingsStore.actions.togglePopoverEnabled({ state, commit })
|
||||
expect(setConfig).toHaveBeenCalledTimes(1)
|
||||
expect(setConfig).toHaveBeenNthCalledWith(1, 'skipPopover', 'no')
|
||||
expect(commit).toHaveBeenCalledTimes(1)
|
||||
expect(commit).toHaveBeenNthCalledWith(1, 'togglePopoverEnabled')
|
||||
})
|
||||
|
||||
it('should provide an action to toggle the weekends setting - false to true', async () => {
|
||||
expect.assertions(4)
|
||||
|
||||
const state = {
|
||||
showWeekends: false,
|
||||
}
|
||||
const commit = jest.fn()
|
||||
|
||||
setConfig.mockReturnValueOnce()
|
||||
|
||||
await settingsStore.actions.toggleWeekendsEnabled({ state, commit })
|
||||
expect(setConfig).toHaveBeenCalledTimes(1)
|
||||
expect(setConfig).toHaveBeenNthCalledWith(1, 'showWeekends', 'yes')
|
||||
expect(commit).toHaveBeenCalledTimes(1)
|
||||
expect(commit).toHaveBeenNthCalledWith(1, 'toggleWeekendsEnabled')
|
||||
})
|
||||
|
||||
it('should provide an action to toggle the weekends setting - true to false', async () => {
|
||||
expect.assertions(4)
|
||||
|
||||
const state = {
|
||||
showWeekends: true,
|
||||
}
|
||||
const commit = jest.fn()
|
||||
|
||||
setConfig.mockReturnValueOnce()
|
||||
|
||||
await settingsStore.actions.toggleWeekendsEnabled({ state, commit })
|
||||
expect(setConfig).toHaveBeenCalledTimes(1)
|
||||
expect(setConfig).toHaveBeenNthCalledWith(1, 'showWeekends', 'no')
|
||||
expect(commit).toHaveBeenCalledTimes(1)
|
||||
expect(commit).toHaveBeenNthCalledWith(1, 'toggleWeekendsEnabled')
|
||||
})
|
||||
|
||||
it('should provide an action to toggle the week-number setting - false to true', async () => {
|
||||
expect.assertions(4)
|
||||
|
||||
const state = {
|
||||
showWeekNumbers: false,
|
||||
}
|
||||
const commit = jest.fn()
|
||||
|
||||
setConfig.mockReturnValueOnce()
|
||||
|
||||
await settingsStore.actions.toggleWeekNumberEnabled({ state, commit })
|
||||
expect(setConfig).toHaveBeenCalledTimes(1)
|
||||
expect(setConfig).toHaveBeenNthCalledWith(1, 'showWeekNr', 'yes')
|
||||
expect(commit).toHaveBeenCalledTimes(1)
|
||||
expect(commit).toHaveBeenNthCalledWith(1, 'toggleWeekNumberEnabled')
|
||||
})
|
||||
|
||||
it('should provide an action to toggle the week-number setting - true to false', async () => {
|
||||
expect.assertions(4)
|
||||
|
||||
const state = {
|
||||
showWeekNumbers: true,
|
||||
}
|
||||
const commit = jest.fn()
|
||||
|
||||
setConfig.mockReturnValueOnce()
|
||||
|
||||
await settingsStore.actions.toggleWeekNumberEnabled({ state, commit })
|
||||
expect(setConfig).toHaveBeenCalledTimes(1)
|
||||
expect(setConfig).toHaveBeenNthCalledWith(1, 'showWeekNr', 'no')
|
||||
expect(commit).toHaveBeenCalledTimes(1)
|
||||
expect(commit).toHaveBeenNthCalledWith(1, 'toggleWeekNumberEnabled')
|
||||
})
|
||||
|
||||
it('should provide an action to toggle the tasks-enabled setting - false to true', async () => {
|
||||
expect.assertions(6)
|
||||
|
||||
const state = {
|
||||
showTasks: false,
|
||||
}
|
||||
const commit = jest.fn()
|
||||
|
||||
setConfig.mockReturnValueOnce()
|
||||
|
||||
await settingsStore.actions.toggleTasksEnabled({ state, commit })
|
||||
expect(setConfig).toHaveBeenCalledTimes(1)
|
||||
expect(setConfig).toHaveBeenNthCalledWith(1, 'showTasks', 'yes')
|
||||
expect(commit).toHaveBeenCalledTimes(3)
|
||||
expect(commit).toHaveBeenNthCalledWith(1, 'toggleTasksEnabled')
|
||||
expect(commit).toHaveBeenNthCalledWith(2, 'clearFetchedTimeRanges')
|
||||
expect(commit).toHaveBeenNthCalledWith(3, 'incrementModificationCount')
|
||||
})
|
||||
|
||||
it('should provide an action to toggle the tasks-enabled setting - true to false', async () => {
|
||||
expect.assertions(6)
|
||||
|
||||
const state = {
|
||||
showTasks: true,
|
||||
}
|
||||
const commit = jest.fn()
|
||||
|
||||
setConfig.mockReturnValueOnce()
|
||||
|
||||
await settingsStore.actions.toggleTasksEnabled({ state, commit })
|
||||
expect(setConfig).toHaveBeenCalledTimes(1)
|
||||
expect(setConfig).toHaveBeenNthCalledWith(1, 'showTasks', 'no')
|
||||
expect(commit).toHaveBeenCalledTimes(3)
|
||||
expect(commit).toHaveBeenNthCalledWith(1, 'toggleTasksEnabled')
|
||||
expect(commit).toHaveBeenNthCalledWith(2, 'clearFetchedTimeRanges')
|
||||
expect(commit).toHaveBeenNthCalledWith(3, 'incrementModificationCount')
|
||||
})
|
||||
|
||||
it('should provide an action to set the last used view', async () => {
|
||||
expect.assertions(2)
|
||||
|
||||
setConfig.mockReturnValueOnce()
|
||||
|
||||
await settingsStore.actions.setInitialView({}, { initialView: 'agendaDay' })
|
||||
expect(setConfig).toHaveBeenCalledTimes(1)
|
||||
expect(setConfig).toHaveBeenNthCalledWith(1, 'view', 'agendaDay')
|
||||
})
|
||||
|
||||
it('should provide an action to set the slot duration setting - same value', async () => {
|
||||
expect.assertions(2)
|
||||
|
||||
const state = {
|
||||
slotDuration: '00:15:00'
|
||||
}
|
||||
const commit = jest.fn()
|
||||
|
||||
await settingsStore.actions.setSlotDuration({ state, commit }, { slotDuration: '00:15:00' })
|
||||
|
||||
expect(setConfig).toHaveBeenCalledTimes(0)
|
||||
expect(commit).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
|
||||
it('should provide an action to set the slot duration setting - different value', async () => {
|
||||
expect.assertions(4)
|
||||
|
||||
const state = {
|
||||
slotDuration: '00:15:00'
|
||||
}
|
||||
const commit = jest.fn()
|
||||
|
||||
setConfig.mockResolvedValueOnce()
|
||||
|
||||
await settingsStore.actions.setSlotDuration({ state, commit }, { slotDuration: '00:30:00' })
|
||||
|
||||
expect(setConfig).toHaveBeenCalledTimes(1)
|
||||
expect(setConfig).toHaveBeenNthCalledWith(1, 'slotDuration', '00:30:00')
|
||||
expect(commit).toHaveBeenCalledTimes(1)
|
||||
expect(commit).toHaveBeenNthCalledWith(1, 'setSlotDuration', { slotDuration: '00:30:00' })
|
||||
})
|
||||
|
||||
it('should provide an action to set the timezone setting - same value', async () => {
|
||||
expect.assertions(2)
|
||||
|
||||
const state = {
|
||||
timezone: 'automatic'
|
||||
}
|
||||
const commit = jest.fn()
|
||||
|
||||
await settingsStore.actions.setTimezone({ state, commit }, { timezoneId: 'automatic' })
|
||||
|
||||
expect(setConfig).toHaveBeenCalledTimes(0)
|
||||
expect(commit).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
|
||||
it('should provide an action to set the timezone setting - different value', async () => {
|
||||
expect.assertions(4)
|
||||
|
||||
const state = {
|
||||
timezone: 'automatic'
|
||||
}
|
||||
const commit = jest.fn()
|
||||
|
||||
setConfig.mockResolvedValueOnce()
|
||||
|
||||
await settingsStore.actions.setTimezone({ state, commit }, { timezoneId: 'Europe/Berlin' })
|
||||
|
||||
expect(setConfig).toHaveBeenCalledTimes(1)
|
||||
expect(setConfig).toHaveBeenNthCalledWith(1, 'timezone', 'Europe/Berlin')
|
||||
expect(commit).toHaveBeenCalledTimes(1)
|
||||
expect(commit).toHaveBeenNthCalledWith(1, 'setTimezone', { timezoneId: 'Europe/Berlin' })
|
||||
})
|
||||
|
||||
it('should provide an action to initialize the calendar-js config', () => {
|
||||
const state = {
|
||||
appVersion: '2.3.4'
|
||||
}
|
||||
|
||||
settingsStore.actions.initializeCalendarJsConfig({ state })
|
||||
|
||||
expect(setCalendarJsConfig).toHaveBeenCalledTimes(2)
|
||||
expect(setCalendarJsConfig).toHaveBeenNthCalledWith(1, 'PRODID', '-//IDN nextcloud.com//Calendar app 2.3.4//EN')
|
||||
expect(setCalendarJsConfig).toHaveBeenNthCalledWith(2, 'property-list-significant-change', [
|
||||
'SUMMARY',
|
||||
'LOCATION',
|
||||
'DESCRIPTION',
|
||||
])
|
||||
})
|
||||
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue