Refactor exception usage

This commit is contained in:
Jonas Lochmann
2020-09-28 02:00:00 +02:00
parent d68b425e0e
commit 8d65c5d777
148 changed files with 2061 additions and 769 deletions
@@ -18,8 +18,11 @@
import * as Sequelize from 'sequelize'
import { AddCategoryAppsAction } from '../../../../action'
import { CategoryAppAttributes } from '../../../../database/categoryapp'
import { getCategoryWithParentCategories } from '../../../../util/category'
import { getCategoryWithParentCategories, GetParentCategoriesException } from '../../../../util/category'
import { Cache } from '../cache'
import { SourceUserNotFoundException } from '../exception/illegal-state'
import { MissingCategoryException } from '../exception/missing-item'
import { CanNotModifyOtherUsersBySelfLimitationException, SelfLimitationException } from '../exception/self-limit'
export async function dispatchAddCategoryApps ({ action, cache, fromChildSelfLimitAddChildUserId }: {
action: AddCategoryAppsAction
@@ -36,14 +39,14 @@ export async function dispatchAddCategoryApps ({ action, cache, fromChildSelfLim
})
if (!categoryEntryUnsafe) {
throw new Error('invalid category id')
throw new MissingCategoryException()
}
const { childId } = categoryEntryUnsafe
if (fromChildSelfLimitAddChildUserId !== null) {
if (childId !== fromChildSelfLimitAddChildUserId) {
throw new Error('can not add apps to other users')
throw new CanNotModifyOtherUsersBySelfLimitationException()
}
}
@@ -77,64 +80,74 @@ export async function dispatchAddCategoryApps ({ action, cache, fromChildSelfLim
}).map((item) => item.categoryId)
if (fromChildSelfLimitAddChildUserId !== null) {
const parentCategoriesOfTargetCategory = getCategoryWithParentCategories(categoriesOfSameChild, action.categoryId)
const userEntryUnsafe = await cache.database.user.findOne({
attributes: [ 'categoryForNotAssignedApps' ],
where: {
familyId: cache.familyId,
userId: fromChildSelfLimitAddChildUserId
},
transaction: cache.transaction
})
if (!userEntryUnsafe) {
throw new Error('illegal state')
}
const userEntry = { categoryForNotAssignedApps: userEntryUnsafe.categoryForNotAssignedApps }
const validatedDefaultCategoryId = categoriesOfSameChild.find((item) => item.categoryId === userEntry.categoryForNotAssignedApps)?.categoryId
const allowUnassignedElements = validatedDefaultCategoryId !== undefined &&
parentCategoriesOfTargetCategory.indexOf(validatedDefaultCategoryId) !== -1
const assertCanAddApp = async (packageName: string, isApp: boolean) => {
const categoryAppEntryUnsafe = await cache.database.categoryApp.findOne({
attributes: [ 'categoryId' ],
try {
const parentCategoriesOfTargetCategory = getCategoryWithParentCategories(categoriesOfSameChild, action.categoryId)
const userEntryUnsafe = await cache.database.user.findOne({
attributes: [ 'categoryForNotAssignedApps' ],
where: {
familyId: cache.familyId,
categoryId: {
[Sequelize.Op.in]: userCategoryIds
},
packageName: packageName
userId: fromChildSelfLimitAddChildUserId
},
transaction: cache.transaction
})
const categoryAppEntry = categoryAppEntryUnsafe ? { categoryId: categoryAppEntryUnsafe.categoryId } : null
if (!userEntryUnsafe) {
throw new SourceUserNotFoundException()
}
if (categoryAppEntry === null) {
if ((isApp && allowUnassignedElements) || (!isApp)) {
// allow
const userEntry = { categoryForNotAssignedApps: userEntryUnsafe.categoryForNotAssignedApps }
const validatedDefaultCategoryId = categoriesOfSameChild.find((item) => item.categoryId === userEntry.categoryForNotAssignedApps)?.categoryId
const allowUnassignedElements = validatedDefaultCategoryId !== undefined &&
parentCategoriesOfTargetCategory.indexOf(validatedDefaultCategoryId) !== -1
const assertCanAddApp = async (packageName: string, isApp: boolean) => {
const categoryAppEntryUnsafe = await cache.database.categoryApp.findOne({
attributes: [ 'categoryId' ],
where: {
familyId: cache.familyId,
categoryId: {
[Sequelize.Op.in]: userCategoryIds
},
packageName: packageName
},
transaction: cache.transaction
})
const categoryAppEntry = categoryAppEntryUnsafe ? { categoryId: categoryAppEntryUnsafe.categoryId } : null
if (categoryAppEntry === null) {
if ((isApp && allowUnassignedElements) || (!isApp)) {
// allow
} else {
throw new SelfLimitationException({
staticMessage: 'can not assign apps without category as child'
})
}
} else {
throw new Error('can not assign apps without category as child')
}
} else {
if (parentCategoriesOfTargetCategory.indexOf(categoryAppEntry.categoryId) !== -1) {
// allow
} else {
throw new Error('can not add app which is not contained in the parent category')
if (parentCategoriesOfTargetCategory.indexOf(categoryAppEntry.categoryId) !== -1) {
// allow
} else {
throw new SelfLimitationException({
staticMessage: 'can not add app which is not contained in the parent category as child'
})
}
}
}
}
for (let i = 0; i < action.packageNames.length; i++) {
const packageName = action.packageNames[i]
for (let i = 0; i < action.packageNames.length; i++) {
const packageName = action.packageNames[i]
if (packageName.indexOf(':') !== -1) {
await assertCanAddApp(packageName.substring(0, packageName.indexOf(':')), true)
await assertCanAddApp(packageName, false)
} else {
await assertCanAddApp(packageName, true)
if (packageName.indexOf(':') !== -1) {
await assertCanAddApp(packageName.substring(0, packageName.indexOf(':')), true)
await assertCanAddApp(packageName, false)
} else {
await assertCanAddApp(packageName, true)
}
}
} catch (ex) {
if (ex instanceof GetParentCategoriesException) {
throw new MissingCategoryException()
} else throw ex
}
}
@@ -18,6 +18,8 @@
import { AddCategoryNetworkIdAction } from '../../../../action'
import { maxNetworkIdsPerCategory } from '../../../../database/categorynetworkid'
import { Cache } from '../cache'
import { ApplyActionException } from '../exception/index'
import { MissingCategoryException } from '../exception/missing-item'
export async function dispatchAddCategoryNetworkId ({ action, cache }: {
action: AddCategoryNetworkIdAction
@@ -33,7 +35,7 @@ export async function dispatchAddCategoryNetworkId ({ action, cache }: {
})
if (!categoryEntryUnsafe) {
throw new Error('invalid category id for new rule')
throw new MissingCategoryException()
}
const count = await cache.database.categoryNetworkId.count({
@@ -45,7 +47,9 @@ export async function dispatchAddCategoryNetworkId ({ action, cache }: {
})
if (count + 1 > maxNetworkIdsPerCategory) {
throw new Error('category network limit reached')
throw new ApplyActionException({
staticMessage: 'can not add a category network id because the category network limit reached'
})
}
const hasOldItem = (await cache.database.categoryNetworkId.count({
@@ -58,7 +62,9 @@ export async function dispatchAddCategoryNetworkId ({ action, cache }: {
})) !== 0
if (hasOldItem) {
throw new Error('id already used')
throw new ApplyActionException({
staticMessage: 'can not add a category network id because the id is already used'
})
}
await cache.database.categoryNetworkId.create({
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -16,8 +16,10 @@
*/
import * as Sequelize from 'sequelize'
import { ChangeParentPasswordAction } from '../../../../action'
import { ChangeParentPasswordAction, InvalidChangeParentPasswordIntegrityException } from '../../../../action/changeparentpassword'
import { Cache } from '../cache'
import { ApplyActionException } from '../exception/index'
import { MissingUserException } from '../exception/missing-item'
export async function dispatchChangeParentPassword ({ action, cache }: {
action: ChangeParentPasswordAction
@@ -34,10 +36,17 @@ export async function dispatchChangeParentPassword ({ action, cache }: {
})
if (!parentEntry) {
throw new Error('parent entry not found')
throw new MissingUserException()
}
try {
action.assertIntegrityValid({ oldPasswordSecondHash: parentEntry.secondPasswordHash })
} catch (ex) {
if (ex instanceof InvalidChangeParentPasswordIntegrityException) {
throw new ApplyActionException({ staticMessage: 'invalid new password integrity' })
} else throw ex
}
action.assertIntegrityValid({ oldPasswordSecondHash: parentEntry.secondPasswordHash })
const newSecondPasswordHash = action.decryptSecondHash({ oldPasswordSecondHash: parentEntry.secondPasswordHash })
parentEntry.passwordHash = action.newPasswordFirstHash
@@ -18,6 +18,8 @@
import { CreateCategoryAction } from '../../../../action'
import { generateVersionId } from '../../../../util/token'
import { Cache } from '../cache'
import { MissingUserException } from '../exception/missing-item'
import { CanNotModifyOtherUsersBySelfLimitationException } from '../exception/self-limit'
export async function dispatchCreateCategory ({ action, cache, fromChildSelfLimitAddChildUserId }: {
action: CreateCategoryAction
@@ -26,7 +28,7 @@ export async function dispatchCreateCategory ({ action, cache, fromChildSelfLimi
}) {
if (fromChildSelfLimitAddChildUserId !== null) {
if (fromChildSelfLimitAddChildUserId !== action.childId) {
throw new Error('can not create categories for other child users')
throw new CanNotModifyOtherUsersBySelfLimitationException()
}
}
@@ -41,7 +43,7 @@ export async function dispatchCreateCategory ({ action, cache, fromChildSelfLimi
})
if (!childEntry) {
throw new Error('missing child for new category')
throw new MissingUserException()
}
const oldMaxSort: number = await cache.database.category.max('sort', {
@@ -17,6 +17,8 @@
import { CreateTimeLimitRuleAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingCategoryException } from '../exception/missing-item'
import { CanNotModifyOtherUsersBySelfLimitationException } from '../exception/self-limit'
export async function dispatchCreateTimeLimitRule ({ action, cache, fromChildSelfLimitAddChildUserId }: {
action: CreateTimeLimitRuleAction
@@ -33,12 +35,12 @@ export async function dispatchCreateTimeLimitRule ({ action, cache, fromChildSel
})
if (!categoryEntryUnsafe) {
throw new Error('invalid category id for new rule')
throw new MissingCategoryException()
}
if (fromChildSelfLimitAddChildUserId !== null) {
if (fromChildSelfLimitAddChildUserId !== categoryEntryUnsafe.childId) {
throw new Error('can not add rules for other users')
throw new CanNotModifyOtherUsersBySelfLimitationException()
}
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,15 +17,25 @@
import { DeleteCategoryAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingCategoryException } from '../exception/missing-item'
export async function dispatchDeleteCategory ({ action, cache }: {
action: DeleteCategoryAction
cache: Cache
}) {
// no version number needs to be updated
const { familyId, transaction } = cache
const { categoryId } = action
const categoryEntry = await cache.database.category.findOne({
where: {
familyId,
categoryId
},
transaction
})
if (!categoryEntry) { throw new MissingCategoryException() }
await cache.database.timelimitRule.destroy({
where: {
familyId,
@@ -75,4 +85,6 @@ export async function dispatchDeleteCategory ({ action, cache }: {
if (affectedUserRows !== 0) {
cache.invalidiateUserList = true
}
// no version number needs to be updated
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,6 +17,7 @@
import { DeleteTimeLimitRuleAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingRuleException } from '../exception/missing-item'
export async function dispatchDeleteTimeLimitRule ({ action, cache }: {
action: DeleteTimeLimitRuleAction
@@ -30,10 +31,12 @@ export async function dispatchDeleteTimeLimitRule ({ action, cache }: {
transaction: cache.transaction
})
if (ruleEntry) {
await ruleEntry.destroy({ transaction: cache.transaction })
cache.categoriesWithModifiedTimeLimitRules.push(ruleEntry.categoryId)
cache.areChangesImportant = true
if (!ruleEntry) {
throw new MissingRuleException()
}
await ruleEntry.destroy({ transaction: cache.transaction })
cache.categoriesWithModifiedTimeLimitRules.push(ruleEntry.categoryId)
cache.areChangesImportant = true
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,6 +17,7 @@
import { IgnoreManipulationAction } from '../../../../action'
import { Cache } from '../cache'
import { SourceDeviceNotFoundException } from '../exception/illegal-state'
export async function dispatchIgnoreManipulation ({ action, cache }: {
action: IgnoreManipulationAction
@@ -31,7 +32,7 @@ export async function dispatchIgnoreManipulation ({ action, cache }: {
})
if (deviceEntry === null) {
throw new Error('illegal state: missing device which dispatched the action')
throw new SourceDeviceNotFoundException()
}
if (action.ignoreDeviceAdminManipulation) {
@@ -18,13 +18,15 @@
import { IncrementCategoryExtraTimeAction } from '../../../../action'
import { CategoryModel } from '../../../../database/category'
import { Cache } from '../cache'
import { MissingCategoryException } from '../exception/missing-item'
import { PremiumVersionMissingException } from '../exception/premium'
export async function dispatchIncrementCategoryExtraTime ({ action, cache }: {
action: IncrementCategoryExtraTimeAction
cache: Cache
}) {
if (!cache.hasFullVersion) {
throw new Error('action requires full version')
throw new PremiumVersionMissingException()
}
async function handleCategory (category: CategoryModel) {
@@ -51,7 +53,7 @@ export async function dispatchIncrementCategoryExtraTime ({ action, cache }: {
})
if (!categoryEntry) {
throw new Error(`tried to add extra time to ${action.categoryId} but it does not exist`)
throw new MissingCategoryException()
}
await handleCategory(categoryEntry)
@@ -62,6 +62,8 @@ import {
UpdateUserLimitLoginCategory
} from '../../../../action'
import { Cache } from '../cache'
import { ActionObjectTypeNotHandledException } from '../exception/illegal-state'
import { ActionNotSupportedBySelfLimitationException } from '../exception/self-limit'
import { dispatchAddCategoryApps } from './addcategoryapps'
import { dispatchAddCategoryNetworkId } from './addcategorynetworkid'
import { dispatchAddUser } from './adduser'
@@ -129,7 +131,9 @@ export const dispatchParentAction = async ({ action, cache, parentUserId, source
return dispatchUpdateCategoryBlockedTimes({ action, cache, fromChildSelfLimitAddChildUserId })
}
if (fromChildSelfLimitAddChildUserId === null) {
if (fromChildSelfLimitAddChildUserId !== null) {
throw new ActionNotSupportedBySelfLimitationException()
} else {
if (action instanceof AddCategoryNetworkIdAction) {
return dispatchAddCategoryNetworkId({ action, cache })
} else if (action instanceof AddUserAction) {
@@ -202,8 +206,8 @@ export const dispatchParentAction = async ({ action, cache, parentUserId, source
return dispatchUpdateUserFlagsAction({ action, cache })
} else if (action instanceof UpdateUserLimitLoginCategory) {
return dispatchUpdateUserLimitLoginCategoryAction({ action, cache, parentUserId })
} else {
throw new ActionObjectTypeNotHandledException()
}
} else {
throw new Error('unsupported action type')
}
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -18,6 +18,7 @@
import * as Sequelize from 'sequelize'
import { RemoveCategoryAppsAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingItemException } from '../exception/missing-item'
export async function dispatchRemoveCategoryApps ({ action, cache }: {
action: RemoveCategoryAppsAction
@@ -35,7 +36,9 @@ export async function dispatchRemoveCategoryApps ({ action, cache }: {
})
if (affectedRows !== action.packageNames.length) {
throw new Error('could not delete as much entries as requested')
throw new MissingItemException({
staticMessage: 'could not remove all requested category app items'
})
}
cache.categoriesWithModifiedApps.push(action.categoryId)
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -21,6 +21,9 @@ import { difference } from 'lodash'
import * as Sequelize from 'sequelize'
import { RemoveUserAction } from '../../../../action'
import { Cache } from '../cache'
import { ApplyActionException } from '../exception/index'
import { ApplyActionIntegrityException } from '../exception/integrity'
import { MissingUserException } from '../exception/missing-item'
export async function dispatchRemoveUser ({ action, cache, parentUserId }: {
action: RemoveUserAction
@@ -36,7 +39,7 @@ export async function dispatchRemoveUser ({ action, cache, parentUserId }: {
})
if (!user) {
throw new Error('invalid user id')
throw new MissingUserException()
}
if (user.type === 'parent') {
@@ -45,7 +48,7 @@ export async function dispatchRemoveUser ({ action, cache, parentUserId }: {
}
if (parentUserId === action.userId) {
throw new Error('users can not delete themself')
throw new ApplyActionException({ staticMessage: 'users can not delete themself' })
}
const expectedIntegrityValue = createHash('sha512').update(
@@ -53,7 +56,7 @@ export async function dispatchRemoveUser ({ action, cache, parentUserId }: {
).digest('hex').substring(0, 16)
if (expectedIntegrityValue !== action.authentication) {
throw new Error('invalid authentication value')
throw new ApplyActionIntegrityException({ staticMessage: 'invalid authentication value for removing a user' })
}
if (user.mail !== '') {
@@ -69,7 +72,7 @@ export async function dispatchRemoveUser ({ action, cache, parentUserId }: {
})
if (usersWithLinkedMail <= 1) {
throw new Error('this user is the last one with a linked mail address')
throw new ApplyActionException({ staticMessage: 'this user is the last one with a linked mail address' })
}
}
@@ -93,7 +96,7 @@ export async function dispatchRemoveUser ({ action, cache, parentUserId }: {
const allOtherParentUserIds = allParentUserIds.filter((item) => item !== action.userId)
if (difference(allOtherParentUserIds, usersWithLimitLoginCategories).length === 0) {
throw new Error('can not delete the last user without limit login category')
throw new ApplyActionException({ staticMessage: 'can not delete the last user without limit login category' })
}
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,12 +17,26 @@
import { RenameChildAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingUserException } from '../exception/missing-item'
export async function dispatchRenameChild ({ action, cache }: {
action: RenameChildAction
cache: Cache
}) {
const [affectedRows] = await cache.database.user.update({
const oldItem = await cache.database.user.findOne({
where: {
familyId: cache.familyId,
userId: action.childId,
type: 'child'
},
transaction: cache.transaction
})
if (!oldItem) {
throw new MissingUserException()
}
await cache.database.user.update({
name: action.newName
}, {
where: {
@@ -33,10 +47,6 @@ export async function dispatchRenameChild ({ action, cache }: {
transaction: cache.transaction
})
if (affectedRows !== 1) {
throw new Error('can not update child name if child does not exist')
}
cache.invalidiateUserList = true
cache.doesUserExist.cache.set(action.childId, false)
}
@@ -17,6 +17,7 @@
import { ResetCategoryNetworkIdsAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingCategoryException } from '../exception/missing-item'
export async function dispatchResetCategoryNetworkIds ({ action, cache }: {
action: ResetCategoryNetworkIdsAction
@@ -32,7 +33,7 @@ export async function dispatchResetCategoryNetworkIds ({ action, cache }: {
})
if (!categoryEntryUnsafe) {
throw new Error('invalid category id for new rule')
throw new MissingCategoryException()
}
await cache.database.categoryNetworkId.destroy({
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,12 +17,26 @@
import { ResetParentBlockedTimesAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingUserException } from '../exception/missing-item'
export async function dispatchResetParentBlockedTimes ({ action, cache }: {
action: ResetParentBlockedTimesAction
cache: Cache
}) {
const [affectedRows] = await cache.database.user.update({
const oldItem = await cache.database.user.findOne({
where: {
familyId: cache.familyId,
userId: action.parentId,
type: 'parent'
},
transaction: cache.transaction
})
if (!oldItem) {
throw new MissingUserException()
}
await cache.database.user.update({
blockedTimes: ''
}, {
where: {
@@ -33,10 +47,6 @@ export async function dispatchResetParentBlockedTimes ({ action, cache }: {
transaction: cache.transaction
})
if (affectedRows === 0) {
throw new Error('invalid parent user id provided')
}
cache.invalidiateUserList = true
cache.areChangesImportant = true
}
@@ -17,16 +17,30 @@
import { SetCategoryExtraTimeAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingCategoryException } from '../exception/missing-item'
import { PremiumVersionMissingException } from '../exception/premium'
export async function dispatchSetCategoryExtraTime ({ action, cache }: {
action: SetCategoryExtraTimeAction
cache: Cache
}) {
if (!cache.hasFullVersion) {
throw new Error('action requires full version')
throw new PremiumVersionMissingException()
}
const [affectedRows] = await cache.database.category.update({
const oldItem = await cache.database.category.findOne({
where: {
familyId: cache.familyId,
categoryId: action.categoryId
},
transaction: cache.transaction
})
if (!oldItem) {
throw new MissingCategoryException()
}
await cache.database.category.update({
extraTimeInMillis: action.newExtraTime,
extraTimeDay: action.day
}, {
@@ -37,8 +51,6 @@ export async function dispatchSetCategoryExtraTime ({ action, cache }: {
transaction: cache.transaction
})
if (affectedRows !== 0) {
cache.categoriesWithModifiedBaseData.push(action.categoryId)
cache.areChangesImportant = true
}
cache.categoriesWithModifiedBaseData.push(action.categoryId)
cache.areChangesImportant = true
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,11 +17,26 @@
import { SetCategoryForUnassignedAppsAction } from '../../../../action'
import { Cache } from '../cache'
import { ApplyActionException } from '../exception/index'
import { MissingUserException } from '../exception/missing-item'
export async function dispatchSetCategoryForUnassignedApps ({ action, cache }: {
action: SetCategoryForUnassignedAppsAction
cache: Cache
}) {
const oldUserEntry = await cache.database.user.findOne({
where: {
familyId: cache.familyId,
userId: action.childId,
type: 'child'
},
transaction: cache.transaction
})
if (!oldUserEntry) {
throw new MissingUserException()
}
if (action.categoryId === '') {
// nothing to check
} else {
@@ -35,7 +50,9 @@ export async function dispatchSetCategoryForUnassignedApps ({ action, cache }: {
})
if (!categoryEntryUnsafe) {
throw new Error('can not set a category which does not exist as category for unassigned apps')
throw new ApplyActionException({
staticMessage: 'can not set a category which does not exist as category for unassigned apps'
})
}
const categoryEntry = {
@@ -43,11 +60,13 @@ export async function dispatchSetCategoryForUnassignedApps ({ action, cache }: {
}
if (categoryEntry.childId !== action.childId) {
throw new Error('can not set a category of one child as category for unassigned apps for an other child')
throw new ApplyActionException({
staticMessage: 'can not set a category of one child as category for unassigned apps for an other child'
})
}
}
const [affectedRows] = await cache.database.user.update({
await cache.database.user.update({
categoryForNotAssignedApps: action.categoryId
}, {
where: {
@@ -58,10 +77,6 @@ export async function dispatchSetCategoryForUnassignedApps ({ action, cache }: {
transaction: cache.transaction
})
if (affectedRows !== 1) {
throw new Error('could not find a child with matching id for setting the category for not assigned apps')
}
cache.invalidiateUserList = true
cache.areChangesImportant = true
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -18,6 +18,7 @@
import * as Sequelize from 'sequelize'
import { SetChildPasswordAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingUserException } from '../exception/missing-item'
export async function dispatchSetChildPassword ({ action, cache }: {
action: SetChildPasswordAction
@@ -34,7 +35,7 @@ export async function dispatchSetChildPassword ({ action, cache }: {
})
if (!childEntry) {
throw new Error('parent entry not found')
throw new MissingUserException()
}
childEntry.passwordHash = action.newPassword.hash
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,12 +17,25 @@
import { SetConsiderRebootManipulationAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingDeviceException } from '../exception/missing-item'
export async function dispatchSetConsiderRebootManipulation ({ action, cache }: {
action: SetConsiderRebootManipulationAction
cache: Cache
}) {
const [affectedRows] = await cache.database.device.update({
const oldDevice = await cache.database.device.findOne({
transaction: cache.transaction,
where: {
familyId: cache.familyId,
deviceId: action.deviceId
}
})
if (!oldDevice) {
throw new MissingDeviceException()
}
await cache.database.device.update({
considerRebootManipulation: action.enable
}, {
transaction: cache.transaction,
@@ -32,10 +45,6 @@ export async function dispatchSetConsiderRebootManipulation ({ action, cache }:
}
})
if (affectedRows === 0) {
throw new Error('did not find device to update consider reboot manipulation')
}
cache.invalidiateDeviceList = true
cache.areChangesImportant = true
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,6 +17,7 @@
import { SetDeviceDefaultUserAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingDeviceException, MissingUserException } from '../exception/missing-item'
export async function dispatchSetDeviceDefaultUser ({ action, cache }: {
action: SetDeviceDefaultUserAction
@@ -26,11 +27,23 @@ export async function dispatchSetDeviceDefaultUser ({ action, cache }: {
const doesUserExist = await cache.doesUserExist(action.defaultUserId)
if (!doesUserExist) {
throw new Error('can not set invalid user as default user')
throw new MissingUserException()
}
}
const [affectedRows] = await cache.database.device.update({
const oldDeviceItem = await cache.database.device.findOne({
transaction: cache.transaction,
where: {
familyId: cache.familyId,
deviceId: action.deviceId
}
})
if (!oldDeviceItem) {
throw new MissingDeviceException()
}
await cache.database.device.update({
defaultUserId: action.defaultUserId
}, {
transaction: cache.transaction,
@@ -40,10 +53,6 @@ export async function dispatchSetDeviceDefaultUser ({ action, cache }: {
}
})
if (affectedRows === 0) {
throw new Error('did not find device to update default user')
}
cache.invalidiateDeviceList = true
cache.areChangesImportant = true
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,12 +17,25 @@
import { SetDeviceDefaultUserTimeoutAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingDeviceException } from '../exception/missing-item'
export async function dispatchSetDeviceDefaultUserTimeout ({ action, cache }: {
action: SetDeviceDefaultUserTimeoutAction
cache: Cache
}) {
const [affectedRows] = await cache.database.device.update({
const oldDeviceItem = await cache.database.device.findOne({
transaction: cache.transaction,
where: {
familyId: cache.familyId,
deviceId: action.deviceId
}
})
if (!oldDeviceItem) {
throw new MissingDeviceException()
}
await cache.database.device.update({
defaultUserTimeout: action.timeout
}, {
transaction: cache.transaction,
@@ -32,10 +45,6 @@ export async function dispatchSetDeviceDefaultUserTimeout ({ action, cache }: {
}
})
if (affectedRows === 0) {
throw new Error('did not find device to update default user timeout')
}
cache.invalidiateDeviceList = true
cache.areChangesImportant = true
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,6 +17,7 @@
import { SetDeviceUserAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingDeviceException, MissingUserException } from '../exception/missing-item'
export async function dispatchSetDeviceUser ({ action, cache }: {
action: SetDeviceUserAction
@@ -26,11 +27,23 @@ export async function dispatchSetDeviceUser ({ action, cache }: {
const doesUserExist = await cache.doesUserExist(action.userId)
if (!doesUserExist) {
throw new Error('invalid user id provided')
throw new MissingUserException()
}
}
const [affectedRows] = await cache.database.device.update({
const oldDeviceItem = await cache.database.device.findOne({
where: {
familyId: cache.familyId,
deviceId: action.deviceId
},
transaction: cache.transaction
})
if (!oldDeviceItem) {
throw new MissingDeviceException()
}
await cache.database.device.update({
currentUserId: action.userId,
isUserKeptSignedIn: false
}, {
@@ -41,8 +54,6 @@ export async function dispatchSetDeviceUser ({ action, cache }: {
transaction: cache.transaction
})
if (affectedRows !== 0) {
cache.invalidiateDeviceList = true
cache.areChangesImportant = true
}
cache.invalidiateDeviceList = true
cache.areChangesImportant = true
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,6 +17,9 @@
import { SetKeepSignedInAction } from '../../../../action'
import { Cache } from '../cache'
import { SourceUserNotFoundException } from '../exception/illegal-state'
import { ApplyActionException } from '../exception/index'
import { MissingDeviceException } from '../exception/missing-item'
export async function dispatchSetKeepSignedIn ({ action, cache, parentUserId }: {
action: SetKeepSignedInAction
@@ -26,7 +29,7 @@ export async function dispatchSetKeepSignedIn ({ action, cache, parentUserId }:
const doesUserExist = await cache.doesUserExist(parentUserId)
if (!doesUserExist) {
throw new Error('invalid user id provided')
throw new SourceUserNotFoundException()
}
const deviceEntry = await cache.database.device.findOne({
@@ -38,12 +41,12 @@ export async function dispatchSetKeepSignedIn ({ action, cache, parentUserId }:
})
if (!deviceEntry) {
throw new Error('device does not exist')
throw new MissingDeviceException()
}
if (deviceEntry.currentUserId !== parentUserId) {
if (action.keepSignedIn) {
throw new Error('only the user itself can disable asking for the password')
throw new ApplyActionException({ staticMessage: 'only the user itself can disable asking for the password' })
}
}
@@ -16,8 +16,11 @@
*/
import { SetParentCategoryAction } from '../../../../action'
import { getCategoryWithParentCategories } from '../../../../util/category'
import { getCategoryWithParentCategories, GetParentCategoriesException } from '../../../../util/category'
import { Cache } from '../cache'
import { ApplyActionException } from '../exception/index'
import { MissingCategoryException } from '../exception/missing-item'
import { CanNotModifyOtherUsersBySelfLimitationException, SelfLimitationException } from '../exception/self-limit'
export async function dispatchSetParentCategory ({ action, cache, fromChildSelfLimitAddChildUserId }: {
action: SetParentCategoryAction
@@ -33,12 +36,12 @@ export async function dispatchSetParentCategory ({ action, cache, fromChildSelfL
})
if (!categoryEntry) {
throw new Error('tried to set parent category of non existent category')
throw new MissingCategoryException()
}
if (fromChildSelfLimitAddChildUserId !== null) {
if (categoryEntry.childId !== fromChildSelfLimitAddChildUserId) {
throw new Error('can not set parent category for other user')
throw new CanNotModifyOtherUsersBySelfLimitationException()
}
}
@@ -56,7 +59,7 @@ export async function dispatchSetParentCategory ({ action, cache, fromChildSelfL
}))
if (categoriesByUserId.find((item) => item.categoryId === action.parentCategory) === undefined) {
throw new Error('selected parent category does not exist')
throw new MissingCategoryException()
}
const childCategoryIds = new Set<string>()
@@ -80,16 +83,26 @@ export async function dispatchSetParentCategory ({ action, cache, fromChildSelfL
}
if (childCategoryIds.has(action.parentCategory) || action.parentCategory === action.categoryId) {
throw new Error('can not set a category as parent which is a child of the category')
throw new ApplyActionException({
staticMessage: 'can not set a category as parent which is a child of the category'
})
}
if (fromChildSelfLimitAddChildUserId !== null) {
const ownParentCategory = categoriesByUserId.find((item) => item.categoryId === categoryEntry.parentCategoryId)
const enableDueToLimitAddingWhenChild = ownParentCategory === undefined ||
getCategoryWithParentCategories(categoriesByUserId, action.parentCategory).indexOf(ownParentCategory.categoryId) !== -1
try {
const ownParentCategory = categoriesByUserId.find((item) => item.categoryId === categoryEntry.parentCategoryId)
const enableDueToLimitAddingWhenChild = ownParentCategory === undefined ||
getCategoryWithParentCategories(categoriesByUserId, action.parentCategory).indexOf(ownParentCategory.categoryId) !== -1
if (!enableDueToLimitAddingWhenChild) {
throw new Error('can not change parent categories in a way which reduces limits')
if (!enableDueToLimitAddingWhenChild) {
throw new SelfLimitationException({
staticMessage: 'can not change parent categories in a way which reduces limits'
})
}
} catch (ex) {
if (ex instanceof GetParentCategoriesException) {
throw new MissingCategoryException()
} else throw ex
}
}
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,12 +17,26 @@
import { SetRelaxPrimaryDeviceAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingUserException } from '../exception/missing-item'
export async function dispatchSetRelaxPrimaryDevice ({ action, cache }: {
action: SetRelaxPrimaryDeviceAction
cache: Cache
}) {
const [affectedRows] = await cache.database.user.update({
const oldUser = cache.database.user.findOne({
transaction: cache.transaction,
where: {
familyId: cache.familyId,
userId: action.userId,
type: 'child'
}
})
if (!oldUser) {
throw new MissingUserException()
}
await cache.database.user.update({
relaxPrimaryDeviceRule: action.relax
}, {
transaction: cache.transaction,
@@ -33,10 +47,6 @@ export async function dispatchSetRelaxPrimaryDevice ({ action, cache }: {
}
})
if (affectedRows === 0) {
throw new Error('did not find user to update relax primary device')
}
cache.invalidiateUserList = true
cache.areChangesImportant = true
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,6 +17,7 @@
import { SetSendDeviceConnected } from '../../../../action'
import { Cache } from '../cache'
import { ApplyActionException } from '../exception/index'
export async function dispatchSetSendDeviceConnected ({ action, cache, sourceDeviceId }: {
action: SetSendDeviceConnected
@@ -24,10 +25,12 @@ export async function dispatchSetSendDeviceConnected ({ action, cache, sourceDev
sourceDeviceId: string | null
}) {
if (sourceDeviceId === null || action.deviceId !== sourceDeviceId) {
throw new Error('only can do that from the device itself')
throw new ApplyActionException({
staticMessage: 'only can do that from the device itself if the connection status should be sent'
})
}
const [affectedRows] = await cache.database.device.update({
await cache.database.device.update({
showDeviceConnected: action.enable
}, {
transaction: cache.transaction,
@@ -37,10 +40,6 @@ export async function dispatchSetSendDeviceConnected ({ action, cache, sourceDev
}
})
if (affectedRows === 0) {
throw new Error('did not find device to update send if connected')
}
cache.devicesWithModifiedShowDeviceConnected.set(action.deviceId, action.enable)
cache.invalidiateDeviceList = true
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,6 +17,8 @@
import { SetUserDisableLimitsUntilAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingUserException } from '../exception/missing-item'
import { PremiumVersionMissingException } from '../exception/premium'
export async function dispatchUserSetDisableLimitsUntil ({ action, cache }: {
action: SetUserDisableLimitsUntilAction
@@ -24,11 +26,24 @@ export async function dispatchUserSetDisableLimitsUntil ({ action, cache }: {
}) {
if (action.timestamp !== 0) {
if (!cache.hasFullVersion) {
throw new Error('action requires full version')
throw new PremiumVersionMissingException()
}
}
const [affectedRows] = await cache.database.user.update({
const oldUser = await cache.database.user.findOne({
where: {
familyId: cache.familyId,
userId: action.childId,
type: 'child'
},
transaction: cache.transaction
})
if (!oldUser) {
throw new MissingUserException()
}
await cache.database.user.update({
disableTimelimitsUntil: action.timestamp.toString(10)
}, {
where: {
@@ -39,10 +54,6 @@ export async function dispatchUserSetDisableLimitsUntil ({ action, cache }: {
transaction: cache.transaction
})
if (affectedRows === 0) {
throw new Error('invalid user id provided')
}
cache.invalidiateUserList = true
cache.areChangesImportant = true
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,12 +17,25 @@
import { SetUserTimezoneAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingUserException } from '../exception/missing-item'
export async function dispatchSetUserTimezone ({ action, cache }: {
action: SetUserTimezoneAction
cache: Cache
}) {
const [affectedRows] = await cache.database.user.update({
const oldUser = await cache.database.user.findOne({
where: {
familyId: cache.familyId,
userId: action.userId
},
transaction: cache.transaction
})
if (!oldUser) {
throw new MissingUserException()
}
await cache.database.user.update({
timeZone: action.timezone
}, {
transaction: cache.transaction,
@@ -32,10 +45,6 @@ export async function dispatchSetUserTimezone ({ action, cache }: {
}
})
if (affectedRows === 0) {
throw new Error('did not find user to update timezone')
}
cache.invalidiateUserList = true
cache.areChangesImportant = true
}
@@ -17,6 +17,7 @@
import { UpdateCategoryBatteryLimitAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingCategoryException } from '../exception/missing-item'
export async function dispatchUpdateCategoryBatteryLimit ({ action, cache }: {
action: UpdateCategoryBatteryLimitAction
@@ -31,7 +32,7 @@ export async function dispatchUpdateCategoryBatteryLimit ({ action, cache }: {
})
if (!categoryEntry) {
throw new Error('invalid category id')
throw new MissingCategoryException()
}
if (action.chargeLimit !== undefined) {
@@ -17,6 +17,8 @@
import { UpdateCategoryBlockAllNotificationsAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingCategoryException } from '../exception/missing-item'
import { CanNotModifyOtherUsersBySelfLimitationException, SelfLimitationException } from '../exception/self-limit'
export async function dispatchUpdateCategoryBlockAllNotifications ({ action, cache, fromChildSelfLimitAddChildUserId }: {
action: UpdateCategoryBlockAllNotificationsAction
@@ -33,16 +35,16 @@ export async function dispatchUpdateCategoryBlockAllNotifications ({ action, cac
})
if (!categoryEntryUnsafe) {
throw new Error('invalid category id for updating notification blocking')
throw new MissingCategoryException()
}
if (fromChildSelfLimitAddChildUserId !== null) {
if (fromChildSelfLimitAddChildUserId !== categoryEntryUnsafe.childId) {
throw new Error('can not add rules for other users')
throw new CanNotModifyOtherUsersBySelfLimitationException()
}
if (!action.blocked) {
throw new Error('can not disable filter as child')
throw new SelfLimitationException({ staticMessage: 'can not disable notification filter as child' })
}
}
@@ -18,6 +18,8 @@
import { blockedTimesBitmaskLength, UpdateCategoryBlockedTimesAction } from '../../../../action/updatecategoryblockedtimes'
import { validateAndParseBitmask } from '../../../../util/bitmask'
import { Cache } from '../cache'
import { MissingCategoryException } from '../exception/missing-item'
import { CanNotModifyOtherUsersBySelfLimitationException, SelfLimitationException } from '../exception/self-limit'
export async function dispatchUpdateCategoryBlockedTimes ({ action, cache, fromChildSelfLimitAddChildUserId }: {
action: UpdateCategoryBlockedTimesAction
@@ -34,7 +36,7 @@ export async function dispatchUpdateCategoryBlockedTimes ({ action, cache, fromC
})
if (!categoryEntryUnsafe) {
throw new Error('can not update blocked time areas for a category which does not exist')
throw new MissingCategoryException()
}
const categoryEntry = {
@@ -44,7 +46,7 @@ export async function dispatchUpdateCategoryBlockedTimes ({ action, cache, fromC
if (fromChildSelfLimitAddChildUserId !== null) {
if (categoryEntry.childId !== fromChildSelfLimitAddChildUserId) {
throw new Error('can not update blocked time areas for other child users')
throw new CanNotModifyOtherUsersBySelfLimitationException()
}
const oldBlocked = validateAndParseBitmask(categoryEntry.blockedMinutesInWeek, blockedTimesBitmaskLength)
@@ -52,7 +54,7 @@ export async function dispatchUpdateCategoryBlockedTimes ({ action, cache, fromC
oldBlocked.forEach((value, index) => {
if (value && !newBlocked[index]) {
throw new Error('new blocked time areas are smaller')
throw new SelfLimitationException({ staticMessage: 'new blocked time areas are smaller' })
}
})
}
@@ -17,6 +17,9 @@
import { UpdateCategoryTemporarilyBlockedAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingCategoryException } from '../exception/missing-item'
import { PremiumVersionMissingException } from '../exception/premium'
import { CanNotModifyOtherUsersBySelfLimitationException, SelfLimitationException } from '../exception/self-limit'
export async function dispatchUpdateCategoryTemporarilyBlocked ({ action, cache, fromChildSelfLimitAddChildUserId }: {
action: UpdateCategoryTemporarilyBlockedAction
@@ -25,7 +28,7 @@ export async function dispatchUpdateCategoryTemporarilyBlocked ({ action, cache,
}) {
if (action.blocked === true) {
if (!cache.hasFullVersion) {
throw new Error('action requires full version')
throw new PremiumVersionMissingException()
}
}
@@ -39,7 +42,7 @@ export async function dispatchUpdateCategoryTemporarilyBlocked ({ action, cache,
})
if (!categoryEntryUnsafe) {
throw new Error('invalid category id for updating temporarily blocking')
throw new MissingCategoryException()
}
const categoryEntry = {
@@ -50,16 +53,16 @@ export async function dispatchUpdateCategoryTemporarilyBlocked ({ action, cache,
if (fromChildSelfLimitAddChildUserId !== null) {
if (fromChildSelfLimitAddChildUserId !== categoryEntry.childId) {
throw new Error('can not update temporarily blocking as child for other users')
throw new CanNotModifyOtherUsersBySelfLimitationException()
}
if (action.endTime === undefined || !action.blocked) {
throw new Error('the child may only enable a temporarily blocking')
throw new SelfLimitationException({ staticMessage: 'the child may only enable a temporarily blocking' })
}
if (categoryEntry.temporarilyBlocked) {
if (action.endTime < categoryEntry.temporarilyBlockedEndTime || categoryEntry.temporarilyBlockedEndTime === 0) {
throw new Error('the child may not reduce the temporarily blocking')
throw new SelfLimitationException({ staticMessage: 'the child may not reduce the temporarily blocking' })
}
}
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,6 +17,7 @@
import { UpdateCategoryTimeWarningsAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingCategoryException } from '../exception/missing-item'
export async function dispatchUpdateCategoryTimeWarnings ({ action, cache }: {
action: UpdateCategoryTimeWarningsAction
@@ -31,7 +32,7 @@ export async function dispatchUpdateCategoryTimeWarnings ({ action, cache }: {
})
if (!categoryEntry) {
throw new Error('invalid category id')
throw new MissingCategoryException()
}
if (action.enable) {
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,11 +17,24 @@
import { UpdateCategoryTitleAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingCategoryException } from '../exception/missing-item'
export async function dispatchUpdateCategoryTitle ({ action, cache }: {
action: UpdateCategoryTitleAction
cache: Cache
}) {
const oldCategory = await cache.database.category.findOne({
where: {
familyId: cache.familyId,
categoryId: action.categoryId
},
transaction: cache.transaction
})
if (!oldCategory) {
throw new MissingCategoryException()
}
const [affectedRows] = await cache.database.category.update({
title: action.newTitle
}, {
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,11 +17,24 @@
import { UpdateDeviceNameAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingDeviceException } from '../exception/missing-item'
export async function dispatchUpdateDeviceName ({ action, cache }: {
action: UpdateDeviceNameAction
cache: Cache
}) {
const oldDevice = await cache.database.device.findOne({
where: {
familyId: cache.familyId,
deviceId: action.deviceId
},
transaction: cache.transaction
})
if (!oldDevice) {
throw new MissingDeviceException()
}
const [affectedRows] = await cache.database.device.update({
name: action.name
}, {
@@ -32,9 +45,7 @@ export async function dispatchUpdateDeviceName ({ action, cache }: {
transaction: cache.transaction
})
if (affectedRows === 0) {
throw new Error('invalid device id')
} else {
if (affectedRows !== 0) {
cache.invalidiateDeviceList = true
cache.areChangesImportant = true
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,12 +17,25 @@
import { UpdateEnableActivityLevelBlockingAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingDeviceException } from '../exception/missing-item'
export async function dispatchUpdateEnableActivityLevelBlocking ({ action, cache }: {
action: UpdateEnableActivityLevelBlockingAction
cache: Cache
}) {
const [affectedRows] = await cache.database.device.update({
const oldDevice = await cache.database.device.findOne({
transaction: cache.transaction,
where: {
familyId: cache.familyId,
deviceId: action.deviceId
}
})
if (!oldDevice) {
throw new MissingDeviceException()
}
await cache.database.device.update({
activityLevelBlocking: action.enable
}, {
transaction: cache.transaction,
@@ -32,10 +45,6 @@ export async function dispatchUpdateEnableActivityLevelBlocking ({ action, cache
}
})
if (affectedRows === 0) {
throw new Error('did not find device to update activity level blocking')
}
cache.invalidiateDeviceList = true
cache.areChangesImportant = true
}
@@ -17,11 +17,24 @@
import { UpdateNetworkTimeVerificationAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingDeviceException } from '../exception/missing-item'
export async function dispatchUpdateNetworkTimeVerification ({ action, cache }: {
action: UpdateNetworkTimeVerificationAction
cache: Cache
}) {
const oldDevice = await cache.database.device.findOne({
transaction: cache.transaction,
where: {
familyId: cache.familyId,
deviceId: action.deviceId
}
})
if (!oldDevice) {
throw new MissingDeviceException()
}
await cache.database.device.update({
networkTime: action.mode
}, {
@@ -17,6 +17,8 @@
import { UpdateParentBlockedTimesAction } from '../../../../action'
import { Cache } from '../cache'
import { ApplyActionException } from '../exception/index'
import { MissingUserException } from '../exception/missing-item'
export async function dispatchUpdateParentBlockedTimes ({ action, cache, parentUserId }: {
action: UpdateParentBlockedTimesAction
@@ -24,10 +26,23 @@ export async function dispatchUpdateParentBlockedTimes ({ action, cache, parentU
parentUserId: string
}) {
if (parentUserId !== action.parentId && action.blockedTimes !== '') {
throw new Error('only a parent itself can add limits')
throw new ApplyActionException({ staticMessage: 'only a parent itself can add limits' })
}
const [affectedRows] = await cache.database.user.update({
const oldUser = await cache.database.user.findOne({
where: {
familyId: cache.familyId,
userId: action.parentId,
type: 'parent'
},
transaction: cache.transaction
})
if (!oldUser) {
throw new MissingUserException()
}
await cache.database.user.update({
blockedTimes: action.blockedTimes
}, {
where: {
@@ -38,10 +53,6 @@ export async function dispatchUpdateParentBlockedTimes ({ action, cache, parentU
transaction: cache.transaction
})
if (affectedRows === 0) {
throw new Error('invalid parent user id provided')
}
cache.invalidiateUserList = true
cache.areChangesImportant = true
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,6 +17,7 @@
import { UpdateParentNotificationFlagsAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingUserException } from '../exception/missing-item'
export async function dispatchUpdateParentNotificationFlags ({ action, cache }: {
action: UpdateParentNotificationFlagsAction
@@ -32,7 +33,7 @@ export async function dispatchUpdateParentNotificationFlags ({ action, cache }:
})
if (!parentEntry) {
throw new Error('parent not found')
throw new MissingUserException()
}
if (action.set) {
@@ -17,6 +17,7 @@
import { UpdateTimelimitRuleAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingRuleException } from '../exception/missing-item'
export async function dispatchUpdateTimelimitRule ({ action, cache }: {
action: UpdateTimelimitRuleAction
@@ -31,7 +32,7 @@ export async function dispatchUpdateTimelimitRule ({ action, cache }: {
})
if (!ruleEntry) {
throw new Error('invalid rule id provided')
throw new MissingRuleException()
}
ruleEntry.applyToExtraTimeUsage = action.applyToExtraTimeUsage
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
* Copyright (C) 2019 - 2020 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
@@ -17,6 +17,8 @@
import { UpdateUserFlagsAction } from '../../../../action'
import { Cache } from '../cache'
import { IllegalStateException } from '../exception/illegal-state'
import { MissingUserException } from '../exception/missing-item'
export async function dispatchUpdateUserFlagsAction ({ action, cache }: {
action: UpdateUserFlagsAction
@@ -31,13 +33,13 @@ export async function dispatchUpdateUserFlagsAction ({ action, cache }: {
})
if (!userEntry) {
throw new Error('user not found')
throw new MissingUserException()
}
const oldFlags = parseInt(userEntry.flags, 10)
if (!Number.isSafeInteger(oldFlags)) {
throw new Error()
throw new IllegalStateException({ staticMessage: 'oldFlags is not a safe integer' })
}
const newFlags = (oldFlags & ~action.modifiedBits) | action.newValues
@@ -17,6 +17,8 @@
import { UpdateUserLimitLoginCategory } from '../../../../action'
import { Cache } from '../cache'
import { ApplyActionException } from '../exception/index'
import { MissingCategoryException, MissingUserException } from '../exception/missing-item'
export async function dispatchUpdateUserLimitLoginCategoryAction ({ action, cache, parentUserId }: {
action: UpdateUserLimitLoginCategory
@@ -26,21 +28,20 @@ export async function dispatchUpdateUserLimitLoginCategoryAction ({ action, cach
const userEntry = await cache.database.user.findOne({
where: {
familyId: cache.familyId,
userId: action.userId
userId: action.userId,
type: 'parent'
},
transaction: cache.transaction
})
if (!userEntry) {
throw new Error('user not found')
}
if (userEntry.type !== 'parent') {
throw new Error('user must be a parent')
throw new MissingUserException()
}
if (action.categoryId !== undefined && parentUserId !== action.userId) {
throw new Error('only the user itself can add a limit')
throw new ApplyActionException({
staticMessage: 'only the parent user itself can add a limit login category'
})
}
await cache.database.userLimitLoginCategory.destroy({
@@ -61,7 +62,7 @@ export async function dispatchUpdateUserLimitLoginCategoryAction ({ action, cach
})
if (!categoryEntry) {
throw new Error('category must exist')
throw new MissingCategoryException()
}
await cache.database.userLimitLoginCategory.create({