Files
timelimit-server/src/function/sync/apply-actions/dispatch-app-logic-action/addusedtime.ts
T

162 lines
5.0 KiB
TypeScript

/*
* 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 <https://www.gnu.org/licenses/>.
*/
import { AddUsedTimeAction } from '../../../../action'
import { MinuteOfDay } from '../../../../util/minuteofday'
import { Cache } from '../cache'
import { IllegalStateException } from '../exception/illegal-state'
import { MissingCategoryException } from '../exception/missing-item'
export const getRoundedTimestamp = () => {
const now = Date.now()
return now - (now % (1000 * 60 * 60 * 24 * 2 /* 2 days */))
}
const dayLengthInMinutes = MinuteOfDay.LENGTH
const dayLengthInMs = dayLengthInMinutes * 1000 * 60
export async function dispatchAddUsedTime ({ action, cache }: {
deviceId: string
action: AddUsedTimeAction
cache: Cache
}) {
const roundedTimestamp = getRoundedTimestamp().toString(10)
const categoryEntryUnsafe = await cache.database.category.findOne({
where: {
familyId: cache.familyId,
categoryId: action.categoryId
},
transaction: cache.transaction,
attributes: [
'childId',
'parentCategoryId',
'extraTimeInMillis'
]
})
// verify that the category exists
if (!categoryEntryUnsafe) {
throw new MissingCategoryException()
}
const categoryEntry = {
childId: categoryEntryUnsafe.childId,
parentCategoryId: categoryEntryUnsafe.parentCategoryId,
extraTimeInMillis: categoryEntryUnsafe.extraTimeInMillis
}
const handleAddUsedTime = async ({ categoryId, currentExtraTime }: {
categoryId: string,
currentExtraTime: number
}) => {
if (action.timeToAdd !== 0) {
const oldItem = await cache.database.usedTime.findOne({
where: {
familyId: cache.familyId,
categoryId: action.categoryId,
dayOfEpoch: action.dayOfEpoch,
startMinuteOfDay: MinuteOfDay.MIN,
endMinuteOfDay: MinuteOfDay.MAX
},
transaction: cache.transaction
})
if (oldItem) {
const oldUsedTime = oldItem.usedTime
const newUsedTime = Math.max(0, Math.min(oldUsedTime + action.timeToAdd, dayLengthInMs))
const oldLastUpdate = parseInt(oldItem.lastUpdate, 10)
const newLastUpdate = parseInt(roundedTimestamp, 10)
if (oldUsedTime !== newUsedTime || oldLastUpdate !== newLastUpdate) {
const [updatedRows] = await cache.database.usedTime.update({
usedTime: newUsedTime,
lastUpdate: newLastUpdate.toString(10)
}, {
where: {
familyId: cache.familyId,
categoryId: action.categoryId,
dayOfEpoch: action.dayOfEpoch,
startMinuteOfDay: MinuteOfDay.MIN,
endMinuteOfDay: MinuteOfDay.MAX
},
transaction: cache.transaction
})
if (updatedRows === 0) {
throw new IllegalStateException({ staticMessage: 'could not update fetched row' })
}
}
} else {
await cache.database.usedTime.create({
familyId: cache.familyId,
categoryId: action.categoryId,
dayOfEpoch: action.dayOfEpoch,
usedTime: Math.max(0, Math.min(action.timeToAdd, dayLengthInMs)),
lastUpdate: roundedTimestamp,
startMinuteOfDay: MinuteOfDay.MIN,
endMinuteOfDay: MinuteOfDay.MAX
}, {
transaction: cache.transaction
})
}
}
if (action.extraTimeToSubtract !== 0) {
await cache.database.category.update({
extraTimeInMillis: Math.max(0, currentExtraTime - action.extraTimeToSubtract)
}, {
where: {
familyId: cache.familyId,
categoryId: categoryId
},
transaction: cache.transaction
})
cache.categoriesWithModifiedBaseData.add(categoryId)
}
cache.categoriesWithModifiedUsedTimes.add(categoryId)
}
await handleAddUsedTime({
categoryId: action.categoryId,
currentExtraTime: categoryEntry.extraTimeInMillis
})
if (categoryEntry.parentCategoryId !== '') {
const parentCategoryEntry = await cache.database.category.findOne({
where: {
familyId: cache.familyId,
categoryId: categoryEntry.parentCategoryId,
childId: categoryEntry.childId
},
transaction: cache.transaction
})
if (parentCategoryEntry) {
await handleAddUsedTime({
categoryId: categoryEntry.parentCategoryId,
currentExtraTime: parentCategoryEntry.extraTimeInMillis
})
}
}
cache.incrementTriggeredSyncLevel(1)
}