Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 56fc0349 authored by Azul's avatar Azul
Browse files

Add setting for sync timeout

The setting is a string that can be formatted as anything that
[moment.duration](https://momentjs.com/docs/#/durations/creating/

)
can parse:
* 'hh:mm:ss'
* 'PT1M' (ISO 8601)

Any invalid setting or setting to less than a second
will lead to the calendar updates being disabled.

The setting is not exposed in the UI.
It's meant to be configured by server admins
to be able to adjust the timeout and prevent an overly high load.

Signed-off-by: default avatarAzul <azul@riseup.net>
parent a5661962
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@ class PublicViewController extends Controller {
		$defaultSkipPopover = $this->config->getAppValue($this->appName, 'skipPopover', 'yes');
		$defaultTimezone = $this->config->getAppValue($this->appName, 'timezone', 'automatic');
		$defaultSlotDuration = $this->config->getAppValue($this->appName, 'slotDuration', '00:30:00');
		$defaultSyncTimeout = $this->config->getAppValue($this->appName, 'syncTimeout', 'PT1M');
		$defaultShowTasks = $this->config->getAppValue($this->appName, 'showTasks', 'yes');

		$appVersion = $this->config->getAppValue($this->appName, 'installed_version', null);
@@ -135,6 +136,7 @@ class PublicViewController extends Controller {
		$this->initialStateService->provideInitialState($this->appName, 'timezone', $defaultTimezone);
		$this->initialStateService->provideInitialState($this->appName, 'slot_duration', $defaultSlotDuration);
		$this->initialStateService->provideInitialState($this->appName, 'show_tasks', $defaultShowTasks === 'yes');
		$this->initialStateService->provideInitialState($this->appName, 'sync_timeout', $defaultSyncTimeout);
		$this->initialStateService->provideInitialState($this->appName, 'tasks_enabled', false);

		return new TemplateResponse($this->appName, 'main', [
+2 −0
Original line number Diff line number Diff line
@@ -106,6 +106,7 @@ class ViewController extends Controller {
		$timezone = $this->config->getUserValue($this->userId, $this->appName, 'timezone', $defaultTimezone);
		$slotDuration = $this->config->getUserValue($this->userId, $this->appName, 'slotDuration', $defaultSlotDuration);
		$showTasks = $this->config->getUserValue($this->userId, $this->appName, 'showTasks', $defaultShowTasks) === 'yes';
		$syncTimeout = $this->config->getAppValue($this->appName, 'syncTimeout', 'PT1M');

		$talkEnabled = $this->appManager->isEnabledForUser('spreed');
		$tasksEnabled = $this->appManager->isEnabledForUser('tasks');
@@ -121,6 +122,7 @@ class ViewController extends Controller {
		$this->initialStateService->provideInitialState($this->appName, 'timezone', $timezone);
		$this->initialStateService->provideInitialState($this->appName, 'slot_duration', $slotDuration);
		$this->initialStateService->provideInitialState($this->appName, 'show_tasks', $showTasks);
		$this->initialStateService->provideInitialState($this->appName, 'sync_timeout', $syncTimeout);
		$this->initialStateService->provideInitialState($this->appName, 'tasks_enabled', $tasksEnabled);

		return new TemplateResponse($this->appName, 'main');
+14 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import { detectTimezone } from '../services/timezoneDetectionService'
import { setConfig as setCalendarJsConfig } from 'calendar-js'
import { setConfig } from '../services/settings.js'
import { logInfo } from '../utils/logger.js'
import moment from '@nextcloud/moment'

const state = {
	// env
@@ -38,6 +39,7 @@ const state = {
	showWeekNumbers: null,
	skipPopover: null,
	slotDuration: null,
	syncTimeout: null,
	tasksEnabled: false,
	timezone: 'automatic',
	// user-defined Nextcloud settings
@@ -126,11 +128,12 @@ const mutations = {
	 * @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 {String} data.syncTimeout The timeout between fetching updates from the server
	 * @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, { appVersion, eventLimit, firstRun, showWeekNumbers, showTasks, showWeekends, skipPopover, slotDuration, talkEnabled, tasksEnabled, timezone }) {
	loadSettingsFromServer(state, { appVersion, eventLimit, firstRun, showWeekNumbers, showTasks, showWeekends, skipPopover, slotDuration, syncTimeout, talkEnabled, tasksEnabled, timezone }) {
		logInfo(`
Initial settings:
	- AppVersion: ${appVersion}
@@ -141,6 +144,7 @@ Initial settings:
	- ShowWeekends: ${showWeekends}
	- SkipPopover: ${skipPopover}
	- SlotDuration: ${slotDuration}
	- SyncTimeout: ${syncTimeout}
	- TalkEnabled: ${talkEnabled}
	- TasksEnabled: ${tasksEnabled}
	- Timezone: ${timezone}
@@ -154,6 +158,7 @@ Initial settings:
		state.showWeekends = showWeekends
		state.skipPopover = skipPopover
		state.slotDuration = slotDuration
		state.syncTimeout = syncTimeout
		state.talkEnabled = talkEnabled
		state.tasksEnabled = tasksEnabled
		state.timezone = timezone
@@ -186,6 +191,14 @@ const getters = {
	getResolvedTimezone: (state) => state.timezone === 'automatic'
		? detectTimezone()
		: state.timezone,

	/**
	 * Gets the sync timeout in milliseconds.
	 *
	 * @param {Object} state The Vuex state
	 * @returns {Integer}
	 */
	getSyncTimeout: (state) => moment.duration(state.syncTimeout).asMilliseconds(),
}

const actions = {
+11 −9
Original line number Diff line number Diff line
@@ -184,15 +184,6 @@ export default {
				})
			}
		}, 1000 * 60)
		this.checkForUpdatesJob = setInterval(async() => {
			if (this.$route.name.startsWith('Public') || this.$route.name.startsWith('Embed')) {
				const tokens = this.$route.params.tokens.split('-')
				await this.$store.dispatch('syncPublicCalendars', { tokens })
			} else {
				await this.$store.dispatch('syncCalendars')
			}
		}, 1000 * 20)

	},
	destroy() {
		clearInterval(this.timeFrameCacheExpiryJob)
@@ -211,6 +202,7 @@ export default {
			tasksEnabled: loadState('calendar', 'tasks_enabled'),
			timezone: loadState('calendar', 'timezone'),
			showTasks: loadState('calendar', 'show_tasks'),
			syncTimeout: loadState('calendar', 'sync_timeout'),
		})
		this.$store.dispatch('initializeCalendarJsConfig')

@@ -255,6 +247,16 @@ export default {

			this.loadingCalendars = false
		}
		if (this.$store.getters.getSyncTimeout > 1000) {
			this.checkForUpdatesJob = setInterval(async() => {
				if (this.$route.name.startsWith('Public') || this.$route.name.startsWith('Embed')) {
					const tokens = this.$route.params.tokens.split('-')
					await this.$store.dispatch('syncPublicCalendars', { tokens })
				} else {
					await this.$store.dispatch('syncCalendars')
				}
			}, this.$store.getters.getSyncTimeout)
		}
	},
	async mounted() {
		if (this.timezone === 'automatic' && this.timezoneId === 'UTC') {
+32 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ describe('store/settings test suite', () => {
			showWeekNumbers: null,
			skipPopover: null,
			slotDuration: null,
			syncTimeout: null,
			tasksEnabled: false,
			timezone: 'automatic',
			momentLocale: 'en',
@@ -151,6 +152,7 @@ describe('store/settings test suite', () => {
			showWeekNumbers: null,
			skipPopover: null,
			slotDuration: null,
			syncTimeout: null,
			tasksEnabled: false,
			timezone: 'automatic',
			momentLocale: 'en',
@@ -166,6 +168,7 @@ describe('store/settings test suite', () => {
			showWeekends: true,
			skipPopover: true,
			slotDuration: '00:30:00',
			syncTimeout: 'PT1M',
			talkEnabled: false,
			tasksEnabled: true,
			timezone: 'Europe/Berlin',
@@ -185,6 +188,7 @@ Initial settings:
	- ShowWeekends: true
	- SkipPopover: true
	- SlotDuration: 00:30:00
	- SyncTimeout: PT1M
	- TalkEnabled: false
	- TasksEnabled: true
	- Timezone: Europe/Berlin
@@ -198,6 +202,7 @@ Initial settings:
			showWeekends: true,
			skipPopover: true,
			slotDuration: '00:30:00',
			syncTimeout: 'PT1M',
			talkEnabled: false,
			tasksEnabled: true,
			timezone: 'Europe/Berlin',
@@ -217,6 +222,7 @@ Initial settings:
			showWeekNumbers: null,
			skipPopover: null,
			slotDuration: null,
			syncTimeout: null,
			tasksEnabled: false,
			timezone: 'automatic',
			momentLocale: 'en',
@@ -237,6 +243,7 @@ Initial settings:
			showWeekNumbers: null,
			skipPopover: null,
			slotDuration: null,
			syncTimeout: null,
			tasksEnabled: false,
			timezone: 'automatic',
			momentLocale: 'de',
@@ -267,6 +274,31 @@ Initial settings:
		expect(detectTimezone).toHaveBeenCalledTimes(0)
	})

	it('should provide a getter for the sync timeout in milliseconds', () => {
		const state = {
			syncTimeout: '00:01:00'
		}

		expect(settingsStore.getters.getSyncTimeout(state)).toEqual(60 * 1000)
	})

	it('can parse sync timeouts in ISO 8601 format', () => {
		const state = {
			syncTimeout: 'PT1M'
		}

		expect(settingsStore.getters.getSyncTimeout(state)).toEqual(60 * 1000)
	})

	it('should handle invalid sync timeout gracefully', () => {
		const state = {
			syncTimeout: 'not a timeout at all'
		}

		// Check from Calendar.vue which will disable the updates:
		expect(settingsStore.getters.getSyncTimeout(state) > 1000).toBeFalsy()
	})

	it('should provide an action to toggle the birthday calendar - enabled to disabled', async () => {
		expect.assertions(3)

Loading