Skip to content

Commit

Permalink
feat: refresh calenders on remote changes
Browse files Browse the repository at this point in the history
Signed-off-by: Richard Steinmetz <richard@steinmetz.cloud>
  • Loading branch information
st3iny committed Jul 15, 2024
1 parent 6d9fde9 commit 6d1a23d
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 17 deletions.
10 changes: 10 additions & 0 deletions src/services/caldavService.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ const findAll = () => {
return getCalendarHome().findAllCalDAVCollectionsGrouped()
}

/**
* Fetch all calendars in the calendar home from the server
*
* @return {Promise<Calendar[]>}
*/
const findAllCalendars = () => {
return getCalendarHome().findAllCalendars()

Check warning on line 86 in src/services/caldavService.js

View check run for this annotation

Codecov / codecov/patch

src/services/caldavService.js#L86

Added line #L86 was not covered by tests
}

/**
* Fetch all subscriptions in the calendar home from the server
*/
Expand Down Expand Up @@ -252,6 +261,7 @@ export {
initializeClientForUserView,
initializeClientForPublicView,
findAll,
findAllCalendars,
findAllDeletedCalendars,
findPublicCalendarsByTokens,
findSchedulingInbox,
Expand Down
10 changes: 4 additions & 6 deletions src/store/calendarObjects.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,17 +296,15 @@ export default defineStore('calendarObjects', {
},

/**
* Adds an array of calendar-objects to the store
* Adds an array of calendar-objects to the store or update them if they already exist
*
* @param {object} data The destructuring object
* @param {object[]} data.calendarObjects Calendar-objects to add
*/
appendCalendarObjectsMutation({ calendarObjects = [] }) {
appendOrUpdateCalendarObjectsMutation({ calendarObjects = [] }) {

Check warning on line 304 in src/store/calendarObjects.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendarObjects.js#L304

Added line #L304 was not covered by tests
for (const calendarObject of calendarObjects) {
if (!this.calendarObjects[calendarObject.id]) {
/// TODO this.calendarObjects[calendarObject.id] = calendarObject
Vue.set(this.calendarObjects, calendarObject.id, calendarObject)
}
/// TODO this.calendarObjects[calendarObject.id] = calendarObject
Vue.set(this.calendarObjects, calendarObject.id, calendarObject)

Check warning on line 307 in src/store/calendarObjects.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendarObjects.js#L307

Added line #L307 was not covered by tests
}
},

Expand Down
36 changes: 34 additions & 2 deletions src/store/calendars.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export default defineStore('calendars', {
calendarsById: {},
initialCalendarsLoaded: false,
editCalendarModal: undefined,
syncTokens: new Map(),
}
},
getters: {
Expand Down Expand Up @@ -209,6 +210,21 @@ export default defineStore('calendars', {
})
}
},

/**
* Get the current sync token of a calendar or undefined it the calendar is not present
*
* @param {object} state The pinia state object
* @return {function({id: string}): string | undefined}
*/
getCalendarSyncToken: (state) => (calendar) => {
const existingCalendar = state.calendarsById[calendar.id]

Check warning on line 221 in src/store/calendars.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendars.js#L220-L221

Added lines #L220 - L221 were not covered by tests
if (!existingCalendar) {
return undefined

Check warning on line 223 in src/store/calendars.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendars.js#L223

Added line #L223 was not covered by tests
}

return state.syncTokens.get(calendar.id) ?? existingCalendar.dav.syncToken
},
},
actions: {
/**
Expand Down Expand Up @@ -359,6 +375,7 @@ export default defineStore('calendars', {
this.calendars.splice(this.calendars.indexOf(calendar), 1)
/// TODO this.calendarsById.delete(calendar.id)
Vue.delete(this.calendarsById, calendar.id)
this.syncTokens.delete(calendar.id)
},

/**
Expand Down Expand Up @@ -650,7 +667,7 @@ export default defineStore('calendars', {
}
}

calendarObjectsStore.appendCalendarObjectsMutation({ calendarObjects })
calendarObjectsStore.appendOrUpdateCalendarObjectsMutation({ calendarObjects })

Check warning on line 670 in src/store/calendars.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendars.js#L670

Added line #L670 was not covered by tests
for (const calendarObjectId of calendarObjectIds) {
if (this.calendarsById[calendar.id].calendarObjects.indexOf(calendarObjectId) === -1) {
this.calendarsById[calendar.id].calendarObjects.push(calendarObjectId)
Expand Down Expand Up @@ -858,7 +875,7 @@ export default defineStore('calendars', {
const index = this.calendarsById[calendar.id]?.fetchedTimeRanges.indexOf(fetchedTimeRangeId)

if (index !== -1) {
this.calendarsById[calendar.id].fetchedTimeRanges.slice(index, 1)
this.calendarsById[calendar.id].fetchedTimeRanges.splice(index, 1)

Check warning on line 878 in src/store/calendars.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendars.js#L878

Added line #L878 was not covered by tests
}
},

Expand Down Expand Up @@ -889,5 +906,20 @@ export default defineStore('calendars', {
this.calendarsById[calendar.id].calendarObjects.slice(index, 1)
}
},

/**
* Update the sync token of a given calendar locally
*
* @param {object} data destructuring object
* @param {{id: string}} data.calendar Calendar from the store
* @param {string} data.syncToken New sync token value
*/
updateCalendarSyncToken({ calendar, syncToken }) {

Check warning on line 917 in src/store/calendars.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendars.js#L917

Added line #L917 was not covered by tests
if (!this.getCalendarById(calendar.id)) {
return

Check warning on line 919 in src/store/calendars.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendars.js#L919

Added line #L919 was not covered by tests
}

this.syncTokens.set(calendar.id, syncToken)

Check warning on line 922 in src/store/calendars.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendars.js#L922

Added line #L922 was not covered by tests
},
},
})
11 changes: 3 additions & 8 deletions src/store/fetchedTimeRanges.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,9 @@ export default defineStore('fetchedTimeRanges', {
* @param {number} data.timeRangeId Id of time-range to remove
*/
removeTimeRange({ timeRangeId }) {
const obj = this.fetchedTimeRangesById[timeRangeId]
const index = this.fetchedTimeRanges.indexOf(obj)

if (index !== -1) {
this.fetchedTimeRanges.splice(index, 1)
/// TODO this.fetchedTimeRangesById.splice(timeRangeId, 1)
Vue.delete(this.fetchedTimeRangesById, timeRangeId)
}
Vue.delete(this.fetchedTimeRangesById, timeRangeId)
this.fetchedTimeRanges = this.fetchedTimeRanges
.filter((timeRange) => timeRange.id !== timeRangeId)

Check warning on line 99 in src/store/fetchedTimeRanges.js

View check run for this annotation

Codecov / codecov/patch

src/store/fetchedTimeRanges.js#L97-L99

Added lines #L97 - L99 were not covered by tests
},

/**
Expand Down
51 changes: 50 additions & 1 deletion src/views/Calendar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import EditSimple from './EditSimple.vue'
// Import CalDAV related methods
import {
findAllCalendars,
initializeClientForPublicView,
initializeClientForUserView,
} from '../services/caldavService.js'
Expand All @@ -99,10 +100,12 @@ import Trashbin from '../components/AppNavigation/CalendarList/Trashbin.vue'
import AppointmentConfigList from '../components/AppNavigation/AppointmentConfigList.vue'
import useFetchedTimeRangesStore from '../store/fetchedTimeRanges.js'
import useCalendarsStore from '../store/calendars.js'
import useCalendarObjectsStore from '../store/calendarObjects.js'
import usePrincipalsStore from '../store/principals.js'
import useSettingsStore from '../store/settings.js'
import useWidgetStore from '../store/widget.js'
import { mapStores, mapState } from 'pinia'
import { mapDavCollectionToCalendar } from '../models/calendar.js'
export default {
name: 'Calendar',
Expand Down Expand Up @@ -148,12 +151,20 @@ export default {
data() {
return {
loadingCalendars: true,
backgroundSyncJob: null,
timeFrameCacheExpiryJob: null,
showEmptyCalendarScreen: false,
}
},
computed: {
...mapStores(useFetchedTimeRangesStore, useCalendarsStore, usePrincipalsStore, useSettingsStore, useWidgetStore),
...mapStores(
useFetchedTimeRangesStore,

Check warning on line 161 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L161

Added line #L161 was not covered by tests
useCalendarsStore,
useCalendarObjectsStore,
usePrincipalsStore,

Check warning on line 164 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L164

Added line #L164 was not covered by tests
useSettingsStore,
useWidgetStore,

Check warning on line 166 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L166

Added line #L166 was not covered by tests
),
...mapState(useSettingsStore, {
timezoneId: 'getResolvedTimezone',
}),
Expand Down Expand Up @@ -208,6 +219,44 @@ export default {
},
},
created() {
this.backgroundSyncJob = setInterval(async () => {
const currentUserPrincipal = this.principalsStore.getCurrentUserPrincipal
const calendars = (await findAllCalendars())
.map((calendar) => mapDavCollectionToCalendar(calendar, currentUserPrincipal))
for (const calendar of calendars) {

Check warning on line 226 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L226

Added line #L226 was not covered by tests
const existingSyncToken = this.calendarsStore.getCalendarSyncToken(calendar)
if (!existingSyncToken && !this.calendarsStore.getCalendarById(calendar.id)) {
// New calendar!
logger.debug(`Adding new calendar ${calendar.url}`)
this.calendarsStore.addCalendarMutation({ calendar })
continue
}
if (calendar.dav.syncToken === existingSyncToken) {
continue

Check warning on line 236 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L236

Added line #L236 was not covered by tests
}

Check warning on line 238 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L238

Added line #L238 was not covered by tests
logger.debug(`Refetching calendar ${calendar.url} (syncToken changed)`)
const fetchedTimeRanges = this.fetchedTimeRangesStore
.getAllTimeRangesForCalendar(calendar.id)

Check warning on line 241 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L241

Added line #L241 was not covered by tests
for (const timeRange of fetchedTimeRanges) {
this.fetchedTimeRangesStore.removeTimeRange({

Check warning on line 243 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L243

Added line #L243 was not covered by tests
timeRangeId: timeRange.id,
})
this.calendarsStore.deleteFetchedTimeRangeFromCalendarMutation({
calendar,

Check warning on line 247 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L245-L247

Added lines #L245 - L247 were not covered by tests
fetchedTimeRangeId: timeRange.id,
})
}
this.calendarsStore.updateCalendarSyncToken({

Check warning on line 252 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L251-L252

Added lines #L251 - L252 were not covered by tests
calendar,
syncToken: calendar.dav.syncToken,
})
this.calendarObjectsStore.modificationCount++
}

Check warning on line 257 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L256-L257

Added lines #L256 - L257 were not covered by tests
}, 1000 * 30)

Check warning on line 259 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L259

Added line #L259 was not covered by tests
this.timeFrameCacheExpiryJob = setInterval(() => {
const timestamp = (getUnixTimestampFromDate(dateFactory()) - 60 * 10)
const timeRanges = this.fetchedTimeRangesStore.getAllTimeRangesOlderThan(timestamp)
Expand Down

0 comments on commit 6d1a23d

Please sign in to comment.