/* * server component for the TimeLimit App * Copyright (C) 2019 - 2022 Jonas Lochmann * * 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, version 3 of the License. * * 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 . */ import { UpdateTimelimitRuleAction } from '../../../../action' import { Cache } from '../cache' import { MissingRuleException, MissingCategoryException } from '../exception/missing-item' import { CanNotModifyOtherUsersBySelfLimitationException, CanNotRelaxRestrictionsSelfLimitException } from '../exception/self-limit' export async function dispatchUpdateTimelimitRule ({ action, cache, fromChildSelfLimitAddChildUserId }: { action: UpdateTimelimitRuleAction cache: Cache fromChildSelfLimitAddChildUserId: string | null }) { const ruleEntry = await cache.database.timelimitRule.findOne({ where: { familyId: cache.familyId, ruleId: action.ruleId }, transaction: cache.transaction }) if (!ruleEntry) { throw new MissingRuleException() } if (fromChildSelfLimitAddChildUserId != null) { const categoryEntryUnsafe = await cache.database.category.findOne({ where: { familyId: cache.familyId, categoryId: ruleEntry.categoryId }, transaction: cache.transaction, attributes: ['childId'] }) if (!categoryEntryUnsafe) { throw new MissingCategoryException() } const categoryEntry = { childId: categoryEntryUnsafe.childId } if (fromChildSelfLimitAddChildUserId !== categoryEntry.childId) { throw new CanNotModifyOtherUsersBySelfLimitationException() } const wasSessionDurationLimitationEnabled = ruleEntry.sessionPauseMilliseconds > 0 && ruleEntry.sessionDurationMilliseconds > 0 const countOldAffectedDays = Array(7) .fill(0) .reduce((sum, _, index) => sum + ((ruleEntry.dayMaskAsBitmask >> index) & 1), 0) const isAtLeastAsStrictAsPreviously = action.maximumTimeInMillis <= ruleEntry.maximumTimeInMillis && (action.dayMask & ruleEntry.dayMaskAsBitmask) === ruleEntry.dayMaskAsBitmask && (action.applyToExtraTimeUsage || !ruleEntry.applyToExtraTimeUsage) && action.start <= ruleEntry.startMinuteOfDay && action.end >= ruleEntry.endMinuteOfDay && (!wasSessionDurationLimitationEnabled || ( action.sessionDurationMilliseconds <= ruleEntry.sessionDurationMilliseconds && action.sessionPauseMilliseconds >= ruleEntry.sessionPauseMilliseconds )) && (!action.perDay || ruleEntry.perDay || countOldAffectedDays <= 1) if (!isAtLeastAsStrictAsPreviously) { throw new CanNotRelaxRestrictionsSelfLimitException() } } ruleEntry.applyToExtraTimeUsage = action.applyToExtraTimeUsage ruleEntry.dayMaskAsBitmask = action.dayMask ruleEntry.maximumTimeInMillis = action.maximumTimeInMillis ruleEntry.startMinuteOfDay = action.start ruleEntry.endMinuteOfDay = action.end ruleEntry.sessionDurationMilliseconds = action.sessionDurationMilliseconds ruleEntry.sessionPauseMilliseconds = action.sessionPauseMilliseconds ruleEntry.perDay = action.perDay ? 1 : 0 await ruleEntry.save({ transaction: cache.transaction }) cache.categoriesWithModifiedTimeLimitRules.add(ruleEntry.categoryId) cache.incrementTriggeredSyncLevel(2) }