260 lines
6.6 KiB
JavaScript
260 lines
6.6 KiB
JavaScript
/**
|
|
* @copyright Copyright (c) 2019 Georg Ehrke
|
|
*
|
|
* @author Georg Ehrke <oc.list@georgehrke.com>
|
|
* @author Richard Steinmetz <richard@steinmetz.cloud>
|
|
*
|
|
* @license AGPL-3.0-or-later
|
|
*
|
|
* 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 { AttendeeProperty, Property } from '@nextcloud/calendar-js'
|
|
import { translate as t } from '@nextcloud/l10n'
|
|
|
|
/**
|
|
* Get the factor for a given unit
|
|
*
|
|
* @param {string} unit The name of the unit to get the factor of
|
|
* @return {number}
|
|
*/
|
|
export function getFactorForAlarmUnit(unit) {
|
|
switch (unit) {
|
|
case 'seconds':
|
|
return 1
|
|
|
|
case 'minutes':
|
|
return 60
|
|
|
|
case 'hours':
|
|
return 60 * 60
|
|
|
|
case 'days':
|
|
return 24 * 60 * 60
|
|
|
|
case 'weeks':
|
|
return 7 * 24 * 60 * 60
|
|
|
|
default:
|
|
return 1
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the amount of days / weeks, unit from total seconds
|
|
*
|
|
* @param {number} totalSeconds Total amount of seconds
|
|
* @return {{amount: number, unit: string}}
|
|
*/
|
|
export function getAmountAndUnitForTimedEvents(totalSeconds) {
|
|
// Before or after the event is handled somewhere else,
|
|
// so make sure totalSeconds is positive
|
|
totalSeconds = Math.abs(totalSeconds)
|
|
|
|
// Handle the special case of 0, so we don't show 0 weeks
|
|
if (totalSeconds === 0) {
|
|
return {
|
|
amount: 0,
|
|
unit: 'minutes',
|
|
}
|
|
}
|
|
|
|
if (totalSeconds % (7 * 24 * 60 * 60) === 0) {
|
|
return {
|
|
amount: totalSeconds / (7 * 24 * 60 * 60),
|
|
unit: 'weeks',
|
|
}
|
|
}
|
|
if (totalSeconds % (24 * 60 * 60) === 0) {
|
|
return {
|
|
amount: totalSeconds / (24 * 60 * 60),
|
|
unit: 'days',
|
|
}
|
|
}
|
|
if (totalSeconds % (60 * 60) === 0) {
|
|
return {
|
|
amount: totalSeconds / (60 * 60),
|
|
unit: 'hours',
|
|
}
|
|
}
|
|
if (totalSeconds % (60) === 0) {
|
|
return {
|
|
amount: totalSeconds / (60),
|
|
unit: 'minutes',
|
|
}
|
|
}
|
|
|
|
return {
|
|
amount: totalSeconds,
|
|
unit: 'seconds',
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the total amount of seconds based on amount and unit for timed events
|
|
*
|
|
* @param {number} amount Amount of unit
|
|
* @param {string} unit Minutes/Hours/Days/Weeks
|
|
* @param {boolean=} isBefore Whether the reminder is before or after the event
|
|
* @return {number}
|
|
*/
|
|
export function getTotalSecondsFromAmountAndUnitForTimedEvents(amount, unit, isBefore = true) {
|
|
return amount * getFactorForAlarmUnit(unit) * (isBefore ? -1 : 1)
|
|
}
|
|
|
|
/**
|
|
* Gets the amount of days / weeks, unit, hours and minutes from total seconds
|
|
*
|
|
* @param {number} totalSeconds Total amount of seconds
|
|
* @return {{amount: *, unit: *, hours: *, minutes: *}}
|
|
*/
|
|
export function getAmountHoursMinutesAndUnitForAllDayEvents(totalSeconds) {
|
|
const dayFactor = getFactorForAlarmUnit('days')
|
|
const hourFactor = getFactorForAlarmUnit('hours')
|
|
const minuteFactor = getFactorForAlarmUnit('minutes')
|
|
const isNegative = totalSeconds < 0
|
|
totalSeconds = Math.abs(totalSeconds)
|
|
|
|
let dayPart = Math.floor(totalSeconds / dayFactor)
|
|
const hourPart = totalSeconds % dayFactor
|
|
|
|
if (hourPart !== 0) {
|
|
if (isNegative) {
|
|
dayPart++
|
|
}
|
|
}
|
|
|
|
let amount = 0
|
|
let unit = null
|
|
if (dayPart === 0) {
|
|
unit = 'days'
|
|
} else if (dayPart % 7 === 0) {
|
|
amount = dayPart / 7
|
|
unit = 'weeks'
|
|
} else {
|
|
amount = dayPart
|
|
unit = 'days'
|
|
}
|
|
|
|
let hours = Math.floor(hourPart / hourFactor)
|
|
const minutePart = hourPart % hourFactor
|
|
let minutes = Math.floor(minutePart / minuteFactor)
|
|
|
|
if (isNegative) {
|
|
hours = 24 - hours
|
|
|
|
if (minutes !== 0) {
|
|
hours--
|
|
minutes = 60 - minutes
|
|
}
|
|
}
|
|
|
|
return {
|
|
amount,
|
|
unit,
|
|
hours,
|
|
minutes,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the total amount of seconds for all-day events
|
|
*
|
|
* @param {number} amount amount of unit
|
|
* @param {number} hours Time of reminder
|
|
* @param {number} minutes Time of reminder
|
|
* @param {string} unit days/weeks
|
|
* @return {number}
|
|
*/
|
|
export function getTotalSecondsFromAmountHourMinutesAndUnitForAllDayEvents(amount, hours, minutes, unit) {
|
|
if (unit === 'weeks') {
|
|
amount *= 7
|
|
unit = 'days'
|
|
}
|
|
|
|
// 0 is on the same day of the all-day event => positive
|
|
// 1 ... n before the event is negative
|
|
const isNegative = amount > 0
|
|
|
|
if (isNegative) {
|
|
// If it's negative, we need to subtract one day
|
|
amount--
|
|
// Convert days to seconds
|
|
amount *= getFactorForAlarmUnit(unit)
|
|
|
|
let invertedHours = 24 - hours
|
|
let invertedMinutes = 0
|
|
|
|
if (minutes !== 0) {
|
|
invertedHours--
|
|
invertedMinutes = 60 - minutes
|
|
}
|
|
|
|
amount += (invertedHours * getFactorForAlarmUnit('hours'))
|
|
amount += (invertedMinutes * getFactorForAlarmUnit('minutes'))
|
|
|
|
amount *= -1
|
|
} else {
|
|
// Convert days to seconds
|
|
amount *= getFactorForAlarmUnit('days')
|
|
|
|
amount += (hours * getFactorForAlarmUnit('hours'))
|
|
amount += (minutes * getFactorForAlarmUnit('minutes'))
|
|
}
|
|
|
|
return amount
|
|
}
|
|
|
|
/**
|
|
* Propagate data from an event component to all EMAIL alarm components.
|
|
* An alarm component must contain a description, summary and all attendees to be notified.
|
|
* We don't have a separate UI for maintaining attendees of an alarm, so we just copy them from the event.
|
|
*
|
|
* https://www.rfc-editor.org/rfc/rfc5545#section-3.6.6
|
|
*
|
|
* @param {AbstractRecurringComponent} eventComponent
|
|
*/
|
|
export function updateAlarms(eventComponent) {
|
|
for (const alarmComponent of eventComponent.getAlarmIterator()) {
|
|
if (alarmComponent.action !== 'EMAIL' && alarmComponent.action !== 'DISPLAY') {
|
|
continue
|
|
}
|
|
|
|
alarmComponent.deleteAllProperties('SUMMARY')
|
|
const summaryProperty = eventComponent.getFirstProperty('SUMMARY')
|
|
if (summaryProperty) {
|
|
alarmComponent.addProperty(summaryProperty.clone())
|
|
} else {
|
|
const defaultSummary = t('calendar', 'Untitled event')
|
|
alarmComponent.addProperty(new Property('SUMMARY', defaultSummary))
|
|
}
|
|
|
|
if (!alarmComponent.hasProperty('DESCRIPTION')) {
|
|
const defaultDescription = t('calendar', 'This is an event reminder.')
|
|
alarmComponent.addProperty(new Property('DESCRIPTION', defaultDescription))
|
|
}
|
|
|
|
alarmComponent.deleteAllProperties('ATTENDEE')
|
|
for (const attendee of eventComponent.getAttendeeIterator()) {
|
|
if (['RESOURCE', 'ROOM'].includes(attendee.userType)) {
|
|
continue
|
|
}
|
|
|
|
// Only copy the email address (value) of the attendee
|
|
alarmComponent.addProperty(new AttendeeProperty('ATTENDEE', attendee.value))
|
|
}
|
|
}
|
|
}
|