mirror of
https://codeberg.org/timelimit/timelimit-server.git
synced 2026-08-31 19:03:45 +02:00
Refactor exception usage
This commit is contained in:
@@ -15,9 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertNonEmptyListWithoutDuplicates } from '../util/list'
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily, assertNonEmptyListWithoutDuplicates } from './meta/util'
|
||||
|
||||
const actionType = 'AddCategoryApps'
|
||||
|
||||
export class AddCategoryAppsAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
@@ -26,8 +27,8 @@ export class AddCategoryAppsAction extends ParentAction {
|
||||
constructor ({ categoryId, packageNames }: {categoryId: string, packageNames: Array<string>}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertNonEmptyListWithoutDuplicates(packageNames)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
assertNonEmptyListWithoutDuplicates({ actionType, field: 'packageNames', list: packageNames })
|
||||
|
||||
this.categoryId = categoryId
|
||||
this.packageNames = packageNames
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
*/
|
||||
|
||||
import { anonymizedNetworkIdLength } from '../database/categorynetworkid'
|
||||
import { assertIsHexString } from '../util/hexstring'
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertHexString, assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'AddCategoryNetworkIdAction'
|
||||
|
||||
export class AddCategoryNetworkIdAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
@@ -32,10 +34,16 @@ export class AddCategoryNetworkIdAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertIdWithinFamily(itemId)
|
||||
assertIsHexString(hashedNetworkId)
|
||||
if (hashedNetworkId.length !== anonymizedNetworkIdLength) throw new Error('wrong network id length')
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
assertIdWithinFamily({ actionType, field: 'itemId', value: itemId })
|
||||
assertHexString({ actionType, field: 'hashedNetworkId', value: hashedNetworkId })
|
||||
|
||||
if (hashedNetworkId.length !== anonymizedNetworkIdLength) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'wrong network id length'
|
||||
})
|
||||
}
|
||||
|
||||
this.categoryId = categoryId
|
||||
this.itemId = itemId
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
*/
|
||||
|
||||
import { InstalledApp, SerializedInstalledApp } from '../model/installedapp'
|
||||
import { assertNonEmptyListWithoutDuplicates } from '../util/list'
|
||||
import { AppLogicAction } from './basetypes'
|
||||
import { assertNonEmptyListWithoutDuplicates } from './meta/util'
|
||||
|
||||
const actionType = 'AddInstalledAppsAction'
|
||||
|
||||
export class AddInstalledAppsAction extends AppLogicAction {
|
||||
readonly apps: Array<InstalledApp>
|
||||
@@ -25,7 +27,7 @@ export class AddInstalledAppsAction extends AppLogicAction {
|
||||
constructor ({ apps }: {apps: Array<InstalledApp>}) {
|
||||
super()
|
||||
|
||||
assertNonEmptyListWithoutDuplicates(apps.map((app) => app.packageName))
|
||||
assertNonEmptyListWithoutDuplicates({ actionType, field: 'apps', list: apps.map((app) => app.packageName) })
|
||||
|
||||
this.apps = apps
|
||||
}
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { AppLogicAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'AddUsedTimeAction'
|
||||
|
||||
export class AddUsedTimeAction extends AppLogicAction {
|
||||
readonly categoryId: string
|
||||
@@ -32,18 +35,30 @@ export class AddUsedTimeAction extends AppLogicAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
|
||||
if (dayOfEpoch < 0 || (!Number.isSafeInteger(dayOfEpoch))) {
|
||||
throw new Error('illegal dayOfEpoch')
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'invalid dayOfEpoch',
|
||||
dynamicMessage: 'invalid dayOfEpoch: ' + dayOfEpoch
|
||||
})
|
||||
}
|
||||
|
||||
if (timeToAdd < 0 || (!Number.isSafeInteger(timeToAdd))) {
|
||||
throw new Error('illegal timeToAdd')
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'illegal timeToAdd',
|
||||
dynamicMessage: 'illegal timeToAdd: ' + timeToAdd
|
||||
})
|
||||
}
|
||||
|
||||
if (extraTimeToSubtract < 0 || (!Number.isSafeInteger(extraTimeToSubtract))) {
|
||||
throw new Error('illegal extra time to subtract')
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'illegal extra time to subtract',
|
||||
dynamicMessage: 'illegal extra time to subtract: ' + extraTimeToSubtract
|
||||
})
|
||||
}
|
||||
|
||||
this.categoryId = categoryId
|
||||
|
||||
+47
-40
@@ -15,10 +15,12 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { uniq } from 'lodash'
|
||||
import { MinuteOfDay } from '../util/minuteofday'
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { AppLogicAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertIdWithinFamily, assertListWithoutDuplicates, assertSafeInteger, throwOutOfRange } from './meta/util'
|
||||
|
||||
const actionType = 'AddUsedTimeActionVersion2'
|
||||
|
||||
export class AddUsedTimeActionVersion2 extends AppLogicAction {
|
||||
readonly dayOfEpoch: number
|
||||
@@ -44,46 +46,54 @@ export class AddUsedTimeActionVersion2 extends AppLogicAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
if (dayOfEpoch < 0 || (!Number.isSafeInteger(dayOfEpoch))) {
|
||||
throw new Error('illegal dayOfEpoch')
|
||||
assertSafeInteger({ actionType, field: 'dayOfEpoch', value: dayOfEpoch })
|
||||
|
||||
if (dayOfEpoch < 0) {
|
||||
throwOutOfRange({ actionType, field: 'dayOfEpoch', value: dayOfEpoch })
|
||||
}
|
||||
|
||||
if (trustedTimestamp < 0 || (!Number.isSafeInteger(trustedTimestamp))) {
|
||||
throw new Error('illegal trustedTimestamp')
|
||||
assertSafeInteger({ actionType, field: 'trustedTimestamp', value: trustedTimestamp })
|
||||
|
||||
if (trustedTimestamp < 0) {
|
||||
throwOutOfRange({ actionType, field: 'trustedTimestamp', value: trustedTimestamp })
|
||||
}
|
||||
|
||||
if (items.length === 0) {
|
||||
throw new Error('missing items')
|
||||
throw new InvalidActionParameterException({ actionType, staticMessage: 'no items' })
|
||||
}
|
||||
|
||||
if (items.length !== uniq(items.map((item) => item.categoryId)).length) {
|
||||
throw new Error('duplicate category ids')
|
||||
}
|
||||
assertListWithoutDuplicates({
|
||||
actionType,
|
||||
field: 'categoryIds',
|
||||
list: items.map((item) => item.categoryId)
|
||||
})
|
||||
|
||||
items.forEach((item) => {
|
||||
assertIdWithinFamily(item.categoryId)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: item.categoryId })
|
||||
|
||||
if (item.timeToAdd < 0 || (!Number.isSafeInteger(item.timeToAdd))) {
|
||||
throw new Error('illegal timeToAdd')
|
||||
assertSafeInteger({ actionType, field: 'timeToAdd', value: item.timeToAdd })
|
||||
|
||||
if (item.timeToAdd < 0) {
|
||||
throwOutOfRange({ actionType, field: 'timeToAdd', value: item.timeToAdd })
|
||||
}
|
||||
|
||||
if (item.extraTimeToSubtract < 0 || (!Number.isSafeInteger(item.extraTimeToSubtract))) {
|
||||
throw new Error('illegal extra time to subtract')
|
||||
assertSafeInteger({ actionType, field: 'extraTimeToSubtract', value: item.extraTimeToSubtract })
|
||||
|
||||
if (item.extraTimeToSubtract < 0) {
|
||||
throwOutOfRange({ actionType, field: 'extraTimeToSubtract', value: item.extraTimeToSubtract })
|
||||
}
|
||||
|
||||
if (
|
||||
uniq(item.additionalCountingSlots.map((item) => JSON.stringify(item.serialize()))).length !==
|
||||
item.additionalCountingSlots.length
|
||||
) {
|
||||
throw new Error()
|
||||
}
|
||||
assertListWithoutDuplicates({
|
||||
actionType,
|
||||
field: 'additionalCountingSlots',
|
||||
list: item.additionalCountingSlots.map((item) => JSON.stringify(item.serialize()))
|
||||
})
|
||||
|
||||
if (
|
||||
uniq(item.sessionDurationLimits.map((item) => JSON.stringify(item.serialize()))).length !==
|
||||
item.sessionDurationLimits.length
|
||||
) {
|
||||
throw new Error()
|
||||
}
|
||||
assertListWithoutDuplicates({
|
||||
actionType,
|
||||
field: 'sessionDurationLimits',
|
||||
list: item.sessionDurationLimits.map((item) => JSON.stringify(item.serialize()))
|
||||
})
|
||||
})
|
||||
|
||||
this.dayOfEpoch = dayOfEpoch
|
||||
@@ -111,16 +121,15 @@ class AddUsedTimeActionItemAdditionalCountingSlot {
|
||||
readonly end: number
|
||||
|
||||
constructor ({ start, end }: { start: number, end: number }) {
|
||||
if ((!Number.isSafeInteger(start)) || (!Number.isSafeInteger(end))) {
|
||||
throw new Error()
|
||||
}
|
||||
assertSafeInteger({ actionType, field: 'start', value: start })
|
||||
assertSafeInteger({ actionType, field: 'end', value: end })
|
||||
|
||||
if (start < MinuteOfDay.MIN || end > MinuteOfDay.MAX || start > end) {
|
||||
throw new Error()
|
||||
throw new InvalidActionParameterException({ actionType, staticMessage: 'start or end out of range' })
|
||||
}
|
||||
|
||||
if (start === MinuteOfDay.MIN && end === MinuteOfDay.MAX) {
|
||||
throw new Error()
|
||||
throw new InvalidActionParameterException({ actionType, staticMessage: 'couting slot can not fill the whole day' })
|
||||
}
|
||||
|
||||
this.start = start
|
||||
@@ -139,19 +148,17 @@ class AddUsedTimeActionItemSessionDurationLimitSlot {
|
||||
readonly pause: number
|
||||
|
||||
constructor ({ start, end, duration, pause }: { start: number, end: number, duration: number, pause: number }) {
|
||||
if (
|
||||
(!Number.isSafeInteger(start)) || (!Number.isSafeInteger(end)) ||
|
||||
(!Number.isSafeInteger(duration)) || (!Number.isSafeInteger(pause))
|
||||
) {
|
||||
throw new Error()
|
||||
}
|
||||
assertSafeInteger({ actionType, field: 'start', value: start })
|
||||
assertSafeInteger({ actionType, field: 'end', value: end })
|
||||
assertSafeInteger({ actionType, field: 'duration', value: duration })
|
||||
assertSafeInteger({ actionType, field: 'pause', value: pause })
|
||||
|
||||
if (start < MinuteOfDay.MIN || end > MinuteOfDay.MAX || start > end) {
|
||||
throw new Error()
|
||||
throw new InvalidActionParameterException({ actionType, staticMessage: 'start or end out of range' })
|
||||
}
|
||||
|
||||
if (duration <= 0 || pause <= 0) {
|
||||
throw new Error()
|
||||
throw new InvalidActionParameterException({ actionType, staticMessage: 'duration and pause must not be zero or smaller' })
|
||||
}
|
||||
|
||||
this.start = start
|
||||
|
||||
+20
-5
@@ -15,9 +15,12 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertParentPasswordValid, ParentPassword } from '../api/schema'
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { assertParentPasswordValid, ParentPassword, ParentPasswordValidationException } from '../api/schema'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'AddUserAction'
|
||||
|
||||
export class AddUserAction extends ParentAction {
|
||||
readonly userId: string
|
||||
@@ -35,7 +38,7 @@ export class AddUserAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(userId)
|
||||
assertIdWithinFamily({ actionType, field: 'userId', value: userId })
|
||||
|
||||
this.userId = userId
|
||||
this.name = name
|
||||
@@ -45,12 +48,24 @@ export class AddUserAction extends ParentAction {
|
||||
|
||||
if (userType === 'parent') {
|
||||
if (!password) {
|
||||
throw new Error('parent users must have got an password')
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'parent users must have got an password'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (password) {
|
||||
assertParentPasswordValid(password)
|
||||
try {
|
||||
assertParentPasswordValid(password)
|
||||
} catch (ex) {
|
||||
if (ex instanceof ParentPasswordValidationException) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'invalid password data'
|
||||
})
|
||||
} else throw ex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
*/
|
||||
|
||||
import { createDecipheriv, createHash } from 'crypto'
|
||||
import { assertIsHexString } from '../util/hexstring'
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertHexString, assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'ChangeParentPasswordAction'
|
||||
|
||||
export class ChangeParentPasswordAction extends ParentAction {
|
||||
readonly parentUserId: string
|
||||
@@ -36,7 +38,7 @@ export class ChangeParentPasswordAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(parentUserId)
|
||||
assertIdWithinFamily({ actionType, field: 'parentUserId', value: parentUserId })
|
||||
|
||||
if (
|
||||
(!parentUserId) ||
|
||||
@@ -45,15 +47,25 @@ export class ChangeParentPasswordAction extends ParentAction {
|
||||
(!newPasswordSecondHashEncrypted) ||
|
||||
(!integrity)
|
||||
) {
|
||||
throw new Error('missing required parameter for change parent password')
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'missing required parameter for change parent password'
|
||||
})
|
||||
}
|
||||
|
||||
if (integrity.length !== 128) {
|
||||
throw new Error('wrong length of integrity data')
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'wrong length of integrity data'
|
||||
})
|
||||
}
|
||||
|
||||
assertIsHexString(newPasswordSecondHashEncrypted)
|
||||
assertIsHexString(integrity)
|
||||
assertHexString({ actionType, field: 'newPasswordSecondHashEncrypted', value: newPasswordSecondHashEncrypted })
|
||||
assertHexString({ actionType, field: 'integrity', value: integrity })
|
||||
|
||||
if (newPasswordSecondHashEncrypted.length <= 70) {
|
||||
throw new InvalidActionParameterException({ actionType, staticMessage: 'wrong length of the new password' })
|
||||
}
|
||||
|
||||
this.parentUserId = parentUserId
|
||||
this.newPasswordFirstHash = newPasswordFirstHash
|
||||
@@ -82,15 +94,11 @@ export class ChangeParentPasswordAction extends ParentAction {
|
||||
const expected = createHash('sha512').update(integrityData).digest('hex')
|
||||
|
||||
if (expected !== this.integrity) {
|
||||
throw new Error('invalid integrity for change parent password action')
|
||||
throw new InvalidChangeParentPasswordIntegrityException()
|
||||
}
|
||||
}
|
||||
|
||||
decryptSecondHash ({ oldPasswordSecondHash }: {oldPasswordSecondHash: string}) {
|
||||
if (this.newPasswordSecondHashEncrypted.length <= 70) {
|
||||
throw new Error('wrong length of the new password')
|
||||
}
|
||||
|
||||
decryptSecondHash ({ oldPasswordSecondHash }: { oldPasswordSecondHash: string }) {
|
||||
const ivHex = this.newPasswordSecondHashEncrypted.substring(0, 32)
|
||||
const salt = this.newPasswordSecondHashEncrypted.substring(32, 64)
|
||||
const encryptedData = this.newPasswordSecondHashEncrypted.substring(64)
|
||||
@@ -115,3 +123,7 @@ export interface SerializedChangeParentPasswordAction {
|
||||
secondHashEncrypted: string
|
||||
integrity: string
|
||||
}
|
||||
|
||||
export class InvalidChangeParentPasswordIntegrityException extends Error {
|
||||
constructor () { super('invalid integrity for change parent password action') }
|
||||
}
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertParentPasswordValid, ParentPassword } from '../api/schema'
|
||||
import { assertParentPasswordValid, ParentPassword, ParentPasswordValidationException } from '../api/schema'
|
||||
import { ChildAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
|
||||
const actionType = 'ChildChangePasswordAction'
|
||||
|
||||
export class ChildChangePasswordAction extends ChildAction {
|
||||
readonly password: ParentPassword
|
||||
@@ -26,7 +29,16 @@ export class ChildChangePasswordAction extends ChildAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertParentPasswordValid(password)
|
||||
try {
|
||||
assertParentPasswordValid(password)
|
||||
} catch (ex) {
|
||||
if (ex instanceof ParentPasswordValidationException) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'invalid password'
|
||||
})
|
||||
} else throw ex
|
||||
}
|
||||
|
||||
this.password = password
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export class ChildSignInAction extends ChildAction {
|
||||
super()
|
||||
}
|
||||
|
||||
static parse = (action: SerializedChildSignInAction) => (
|
||||
static parse = (_: SerializedChildSignInAction) => (
|
||||
new ChildSignInAction()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'CreateCategoryAction'
|
||||
|
||||
export class CreateCategoryAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
@@ -26,8 +28,8 @@ export class CreateCategoryAction extends ParentAction {
|
||||
constructor ({ categoryId, childId, title }: {categoryId: string, childId: string, title: string}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertIdWithinFamily(childId)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
assertIdWithinFamily({ actionType, field: 'childId', value: childId })
|
||||
|
||||
this.categoryId = categoryId
|
||||
this.childId = childId
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { SerializedTimeLimitRule, TimelimitRule } from '../model/timelimitrule'
|
||||
import { ParseTimeLimitRuleException, SerializedTimeLimitRule, TimelimitRule } from '../model/timelimitrule'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
|
||||
const actionType = 'CreateTimeLimitRuleAction'
|
||||
|
||||
export class CreateTimeLimitRuleAction extends ParentAction {
|
||||
rule: TimelimitRule
|
||||
@@ -27,11 +30,21 @@ export class CreateTimeLimitRuleAction extends ParentAction {
|
||||
this.rule = rule
|
||||
}
|
||||
|
||||
static parse = ({ rule }: SerializedCreateTimelimtRuleAction) => (
|
||||
new CreateTimeLimitRuleAction({
|
||||
rule: TimelimitRule.parse(rule)
|
||||
})
|
||||
)
|
||||
static parse = ({ rule }: SerializedCreateTimelimtRuleAction) => {
|
||||
try {
|
||||
return new CreateTimeLimitRuleAction({
|
||||
rule: TimelimitRule.parse(rule)
|
||||
})
|
||||
} catch (ex) {
|
||||
if (ex instanceof ParseTimeLimitRuleException) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'invalid time limit rule',
|
||||
dynamicMessage: 'invalid time limit rule: ' + ex.toString()
|
||||
})
|
||||
} else throw ex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface SerializedCreateTimelimtRuleAction {
|
||||
|
||||
@@ -15,16 +15,18 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'DeleteCategoryAction'
|
||||
|
||||
export class DeleteCategoryAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
|
||||
constructor ({ categoryId }: {categoryId: string}) {
|
||||
constructor ({ categoryId }: { categoryId: string }) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
|
||||
this.categoryId = categoryId
|
||||
}
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'DeleteTimeLimitRuleAction'
|
||||
|
||||
export class DeleteTimeLimitRuleAction extends ParentAction {
|
||||
readonly ruleId: string
|
||||
@@ -24,7 +26,7 @@ export class DeleteTimeLimitRuleAction extends ParentAction {
|
||||
constructor ({ ruleId }: {ruleId: string}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(ruleId)
|
||||
assertIdWithinFamily({ actionType, field: 'ruleId', value: ruleId })
|
||||
|
||||
this.ruleId = ruleId
|
||||
}
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
*/
|
||||
|
||||
import { DeviceHadManipulationFlags } from '../database/device'
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily, assertSafeInteger, throwOutOfRange } from './meta/util'
|
||||
|
||||
const actionType = 'IgnoreManipulationAction'
|
||||
|
||||
export class IgnoreManipulationAction extends ParentAction {
|
||||
readonly deviceId: string
|
||||
@@ -51,13 +53,14 @@ export class IgnoreManipulationAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(deviceId)
|
||||
assertIdWithinFamily({ actionType, field: 'deviceId', value: deviceId })
|
||||
|
||||
assertSafeInteger({ actionType, field: 'ignoreHadManipulationFlags', value: ignoreHadManipulationFlags })
|
||||
|
||||
if (
|
||||
(!Number.isSafeInteger(ignoreHadManipulationFlags)) ||
|
||||
ignoreHadManipulationFlags < 0 || ignoreHadManipulationFlags > DeviceHadManipulationFlags.ALL
|
||||
) {
|
||||
throw new Error('invalid ignoreHadManipulationFlags')
|
||||
throwOutOfRange({ actionType, field: 'ignoreHadManipulationFlags', value: ignoreHadManipulationFlags })
|
||||
}
|
||||
|
||||
this.deviceId = deviceId
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily, assertSafeInteger, throwOutOfRange } from './meta/util'
|
||||
|
||||
const actionType = 'IncrementCategoryExtraTimeAction'
|
||||
|
||||
export class IncrementCategoryExtraTimeAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
@@ -26,14 +28,18 @@ export class IncrementCategoryExtraTimeAction extends ParentAction {
|
||||
constructor ({ categoryId, addedExtraTime, day }: {categoryId: string, addedExtraTime: number, day: number}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
|
||||
if (addedExtraTime <= 0 || (!Number.isSafeInteger(addedExtraTime))) {
|
||||
throw new Error('must add some extra time with IncrementCategoryExtraTimeAction')
|
||||
assertSafeInteger({ actionType, field: 'addedExtraTime', value: addedExtraTime })
|
||||
|
||||
if (addedExtraTime < 0) {
|
||||
throwOutOfRange({ actionType, field: 'addedExtraTime', value: addedExtraTime })
|
||||
}
|
||||
|
||||
if (day < -1 || (!Number.isSafeInteger(day))) {
|
||||
throw Error('day must be valid')
|
||||
assertSafeInteger({ actionType, field: 'day', value: day })
|
||||
|
||||
if (day < -1) {
|
||||
throwOutOfRange({ actionType, field: 'day', value: day })
|
||||
}
|
||||
|
||||
this.categoryId = categoryId
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* 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
|
||||
* 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 { StaticMessageException } from '../../exception'
|
||||
|
||||
export class InvalidActionParameterException extends StaticMessageException {
|
||||
constructor ({ actionType, staticMessage, dynamicMessage }: {
|
||||
actionType: string
|
||||
staticMessage: string
|
||||
dynamicMessage?: string
|
||||
}) {
|
||||
super({
|
||||
staticMessage: 'invalid action paramters:' + actionType + ':' + staticMessage,
|
||||
dynamicMessage: dynamicMessage ? 'invalid action paramters:' + actionType + ':' + dynamicMessage : undefined
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export class UnknownActionTypeException extends InvalidActionParameterException {
|
||||
constructor ({ group }: { group: string }) {
|
||||
super({
|
||||
actionType: group,
|
||||
staticMessage: 'unknown action type'
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* 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
|
||||
* 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 { checkIfHexString } from '../../util/hexstring'
|
||||
import { hasDuplicates } from '../../util/list'
|
||||
import { isIdWithinFamily } from '../../util/token'
|
||||
import { InvalidActionParameterException } from './exception'
|
||||
|
||||
export const assertIdWithinFamily = ({ value, actionType, field }: {
|
||||
value: string
|
||||
actionType: string
|
||||
field: string
|
||||
}) => {
|
||||
if (!isIdWithinFamily(value)) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'invalid id within family for ' + field,
|
||||
dynamicMessage: 'invalid id within family for ' + field + ': ' + value
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const assertHexString = ({ value, actionType, field }: {
|
||||
value: string
|
||||
actionType: string
|
||||
field: string
|
||||
}) => {
|
||||
if (!checkIfHexString(value)) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'invalid hex string for ' + field,
|
||||
dynamicMessage: 'invalid hex string for ' + field + ': ' + value
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const assertSafeInteger = ({ value, actionType, field }: {
|
||||
value: number
|
||||
actionType: string
|
||||
field: string
|
||||
}) => {
|
||||
if (!Number.isSafeInteger(value)) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'require number for ' + field,
|
||||
dynamicMessage: 'require number for ' + field + ': ' + value
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const throwOutOfRange = ({ value, actionType, field }: {
|
||||
value: number
|
||||
actionType: string
|
||||
field: string
|
||||
}) => {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: field + ' out of range',
|
||||
dynamicMessage: field + ' out of range: ' + value
|
||||
})
|
||||
}
|
||||
|
||||
export function assertNonEmptyListWithoutDuplicates ({ list, actionType, field }: {
|
||||
list: Array<string>
|
||||
actionType: string
|
||||
field: string
|
||||
}) {
|
||||
assertListWithoutDuplicates({ list, actionType, field })
|
||||
|
||||
if (hasDuplicates(list)) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'empty list for ' + field
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function assertListWithoutDuplicates ({ list, actionType, field }: {
|
||||
list: Array<string>
|
||||
actionType: string
|
||||
field: string
|
||||
}) {
|
||||
if (hasDuplicates(list)) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'list has duplicates for ' + field,
|
||||
dynamicMessage: 'list has duplicates for ' + field + ': ' + list.join(';')
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertNonEmptyListWithoutDuplicates } from '../util/list'
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily, assertNonEmptyListWithoutDuplicates } from './meta/util'
|
||||
|
||||
const actionType = 'RemoveCategoryAppsAction'
|
||||
|
||||
export class RemoveCategoryAppsAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
@@ -26,8 +27,8 @@ export class RemoveCategoryAppsAction extends ParentAction {
|
||||
constructor ({ categoryId, packageNames }: {categoryId: string, packageNames: Array<string>}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertNonEmptyListWithoutDuplicates(packageNames)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
assertNonEmptyListWithoutDuplicates({ actionType, field: 'packageNames', list: packageNames })
|
||||
|
||||
this.categoryId = categoryId
|
||||
this.packageNames = packageNames
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertNonEmptyListWithoutDuplicates } from '../util/list'
|
||||
import { AppLogicAction } from './basetypes'
|
||||
import { assertNonEmptyListWithoutDuplicates } from './meta/util'
|
||||
|
||||
const actionType = 'RemoveInstalledAppsAction'
|
||||
|
||||
export class RemoveInstalledAppsAction extends AppLogicAction {
|
||||
readonly packageNames: Array<string>
|
||||
@@ -24,7 +26,7 @@ export class RemoveInstalledAppsAction extends AppLogicAction {
|
||||
constructor ({ packageNames }: {packageNames: Array<string>}) {
|
||||
super()
|
||||
|
||||
assertNonEmptyListWithoutDuplicates(packageNames)
|
||||
assertNonEmptyListWithoutDuplicates({ actionType, field: 'packageNames', list: packageNames })
|
||||
|
||||
this.packageNames = packageNames
|
||||
}
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'RemoveUserAction'
|
||||
|
||||
export class RemoveUserAction extends ParentAction {
|
||||
readonly userId: string
|
||||
@@ -31,7 +33,7 @@ export class RemoveUserAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(userId)
|
||||
assertIdWithinFamily({ actionType, field: 'userId', value: userId })
|
||||
|
||||
this.userId = userId
|
||||
this.authentication = authentication
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'RenameChildAction'
|
||||
|
||||
export class RenameChildAction extends ParentAction {
|
||||
readonly childId: string
|
||||
@@ -28,10 +31,13 @@ export class RenameChildAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(childId)
|
||||
assertIdWithinFamily({ actionType, field: 'childId', value: childId })
|
||||
|
||||
if (newName === '') {
|
||||
throw new Error('new name must not be empty')
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'new name must not be empty'
|
||||
})
|
||||
}
|
||||
|
||||
this.childId = childId
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'ResetCategoryNetworkIdsAction'
|
||||
|
||||
export class ResetCategoryNetworkIdsAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
@@ -26,7 +28,7 @@ export class ResetCategoryNetworkIdsAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
|
||||
this.categoryId = categoryId
|
||||
}
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'ResetParentBlockedTimesAction'
|
||||
|
||||
export class ResetParentBlockedTimesAction extends ParentAction {
|
||||
readonly parentId: string
|
||||
@@ -26,7 +28,7 @@ export class ResetParentBlockedTimesAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(parentId)
|
||||
assertIdWithinFamily({ actionType, field: 'parentId', value: parentId })
|
||||
|
||||
this.parentId = parentId
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import { AddUsedTimeAction, SerializedAddUsedTimeAction } from '../addusedtime'
|
||||
import { AddUsedTimeActionVersion2, SerializedAddUsedTimeActionVersion2 } from '../addusedtime2'
|
||||
import { AppLogicAction } from '../basetypes'
|
||||
import { ForceSyncAction, SerializedForceSyncAction } from '../forcesync'
|
||||
import { UnknownActionTypeException } from '../meta/exception'
|
||||
import { RemoveInstalledAppsAction, SerializedRemoveInstalledAppsAction } from '../removeinstalledapps'
|
||||
import { SerializedSignOutAtDeviceAction, SignOutAtDeviceAction } from '../signoutatdevice'
|
||||
import { SerialiezdTriedDisablingDeviceAdminAction, TriedDisablingDeviceAdminAction } from '../trieddisablingdeviceadmin'
|
||||
@@ -57,6 +58,6 @@ export const parseAppLogicAction = (serialized: SerializedAppLogicAction): AppLo
|
||||
} else if (serialized.type === 'UPDATE_DEVICE_STATUS') {
|
||||
return UpdateDeviceStatusAction.parse(serialized)
|
||||
} else {
|
||||
throw new Error('illegal state: unsupported type at parseAppLogicAction')
|
||||
throw new UnknownActionTypeException({ group: 'app logic' })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 { ChildChangePasswordAction, SerializedChildChangePasswordAction } from '../childchangepassword'
|
||||
import { ChildSignInAction, SerializedChildSignInAction } from '../childsignin'
|
||||
import { UnknownActionTypeException } from '../meta/exception'
|
||||
|
||||
export type SerializedChildAction = SerializedChildChangePasswordAction | SerializedChildSignInAction
|
||||
|
||||
@@ -26,6 +27,6 @@ export const parseChildAction = (serialized: SerializedChildAction) => {
|
||||
} else if (serialized.type === 'CHILD_SIGN_IN') {
|
||||
return ChildSignInAction.parse(serialized)
|
||||
} else {
|
||||
throw new Error('illegal state: unsupported type at parseChildAction')
|
||||
throw new UnknownActionTypeException({ group: 'child' })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import { DeleteCategoryAction, SerializedDeleteCategoryAction } from '../deletec
|
||||
import { DeleteTimeLimitRuleAction, SerializedDeleteTimeLimitRuleAction } from '../deletetimelimitrule'
|
||||
import { IgnoreManipulationAction, SerializedIgnoreManipulationAction } from '../ignoremanipulation'
|
||||
import { IncrementCategoryExtraTimeAction, SerializedIncrementCategoryExtraTimeAction } from '../incrementcategoryextratime'
|
||||
import { UnknownActionTypeException } from '../meta/exception'
|
||||
import { RemoveCategoryAppsAction, SerializedRemoveCategoryAppsAction } from '../removecategoryapps'
|
||||
import { RemoveUserAction, SerializedRemoveUserAction } from '../removeuser'
|
||||
import { RenameChildAction, SerializedRenameChildAction } from '../renamechild'
|
||||
@@ -193,6 +194,6 @@ export const parseParentAction = (action: SerializedParentAction): ParentAction
|
||||
} else if (action.type === 'UPDATE_USER_LIMIT_LOGIN_CATEGORY') {
|
||||
return UpdateUserLimitLoginCategory.parse(action)
|
||||
} else {
|
||||
throw new Error('illegal state: invalid type for action at parseParentAction')
|
||||
throw new UnknownActionTypeException({ group: 'parent' })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily, assertSafeInteger, throwOutOfRange } from './meta/util'
|
||||
|
||||
const actionType = 'SetCategoryExtraTimeAction'
|
||||
|
||||
export class SetCategoryExtraTimeAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
@@ -26,14 +28,18 @@ export class SetCategoryExtraTimeAction extends ParentAction {
|
||||
constructor ({ categoryId, newExtraTime, day }: {categoryId: string, newExtraTime: number, day: number}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
|
||||
if (newExtraTime < 0 || (!Number.isSafeInteger(newExtraTime))) {
|
||||
throw Error('newExtraTime must be >= 0')
|
||||
assertSafeInteger({ actionType, field: 'newExtraTime', value: newExtraTime })
|
||||
|
||||
if (newExtraTime < 0) {
|
||||
throwOutOfRange({ actionType, field: 'newExtraTime', value: newExtraTime })
|
||||
}
|
||||
|
||||
if (day < -1 || (!Number.isSafeInteger(day))) {
|
||||
throw Error('day must be valid')
|
||||
assertSafeInteger({ actionType, field: 'day', value: day })
|
||||
|
||||
if (day < -1) {
|
||||
throwOutOfRange({ actionType, field: 'day', value: day })
|
||||
}
|
||||
|
||||
this.categoryId = categoryId
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'SetCategoryForUnassignedAppsAction'
|
||||
|
||||
export class SetCategoryForUnassignedAppsAction extends ParentAction {
|
||||
readonly childId: string
|
||||
@@ -28,10 +30,10 @@ export class SetCategoryForUnassignedAppsAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(childId)
|
||||
assertIdWithinFamily({ actionType, field: 'childId', value: childId })
|
||||
|
||||
if (categoryId !== '') {
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
}
|
||||
|
||||
this.childId = childId
|
||||
|
||||
@@ -15,9 +15,12 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertParentPasswordValid, ParentPassword } from '../api/schema'
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { assertParentPasswordValid, ParentPassword, ParentPasswordValidationException } from '../api/schema'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'SetChildPasswordAction'
|
||||
|
||||
export class SetChildPasswordAction extends ParentAction {
|
||||
readonly childUserId: string
|
||||
@@ -29,8 +32,18 @@ export class SetChildPasswordAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(childUserId)
|
||||
assertParentPasswordValid(newPassword)
|
||||
assertIdWithinFamily({ actionType, field: 'childUserId', value: childUserId })
|
||||
|
||||
try {
|
||||
assertParentPasswordValid(newPassword)
|
||||
} catch (ex) {
|
||||
if (ex instanceof ParentPasswordValidationException) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'invalid parent password'
|
||||
})
|
||||
} else throw ex
|
||||
}
|
||||
|
||||
this.childUserId = childUserId
|
||||
this.newPassword = newPassword
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'SetConsiderRebootManipulationAction'
|
||||
|
||||
export class SetConsiderRebootManipulationAction extends ParentAction {
|
||||
readonly deviceId: string
|
||||
@@ -25,7 +27,7 @@ export class SetConsiderRebootManipulationAction extends ParentAction {
|
||||
constructor ({ deviceId, enable }: {deviceId: string, enable: boolean}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(deviceId)
|
||||
assertIdWithinFamily({ actionType, field: 'deviceId', value: deviceId })
|
||||
|
||||
this.deviceId = deviceId
|
||||
this.enable = enable
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'SetDeviceDefaultUserAction'
|
||||
|
||||
export class SetDeviceDefaultUserAction extends ParentAction {
|
||||
readonly deviceId: string
|
||||
@@ -28,10 +30,10 @@ export class SetDeviceDefaultUserAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(deviceId)
|
||||
assertIdWithinFamily({ actionType, field: 'deviceId', value: deviceId })
|
||||
|
||||
if (defaultUserId !== '') {
|
||||
assertIdWithinFamily(defaultUserId)
|
||||
assertIdWithinFamily({ actionType, field: 'defaultUserId', value: defaultUserId })
|
||||
}
|
||||
|
||||
this.deviceId = deviceId
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertIdWithinFamily, assertSafeInteger } from './meta/util'
|
||||
|
||||
const actionType = 'SetDeviceDefaultUserTimeoutAction'
|
||||
|
||||
export class SetDeviceDefaultUserTimeoutAction extends ParentAction {
|
||||
readonly deviceId: string
|
||||
@@ -28,10 +31,15 @@ export class SetDeviceDefaultUserTimeoutAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(deviceId)
|
||||
assertIdWithinFamily({ actionType, field: 'deviceId', value: deviceId })
|
||||
assertSafeInteger({ actionType, field: 'timeout', value: timeout })
|
||||
|
||||
if ((!Number.isInteger(timeout)) || (timeout < 0)) {
|
||||
throw new Error('timeout must be a non-negative integer')
|
||||
if (timeout < 0) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'timeout must be a non-negative integer',
|
||||
dynamicMessage: 'timeout must be a non-negative integer, was ' + timeout
|
||||
})
|
||||
}
|
||||
|
||||
this.deviceId = deviceId
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'SetDeviceUserAction'
|
||||
|
||||
export class SetDeviceUserAction extends ParentAction {
|
||||
readonly deviceId: string
|
||||
@@ -28,10 +30,10 @@ export class SetDeviceUserAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(deviceId)
|
||||
assertIdWithinFamily({ actionType, field: 'deviceId', value: deviceId })
|
||||
|
||||
if (userId !== '') {
|
||||
assertIdWithinFamily(userId)
|
||||
assertIdWithinFamily({ actionType, field: 'userId', value: userId })
|
||||
}
|
||||
|
||||
this.deviceId = deviceId
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'SetKeepSignedInAction'
|
||||
|
||||
export class SetKeepSignedInAction extends ParentAction {
|
||||
readonly deviceId: string
|
||||
@@ -28,7 +30,7 @@ export class SetKeepSignedInAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(deviceId)
|
||||
assertIdWithinFamily({ actionType, field: 'deviceId', value: deviceId })
|
||||
|
||||
this.deviceId = deviceId
|
||||
this.keepSignedIn = keepSignedIn
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'SetParentCategoryAction'
|
||||
|
||||
export class SetParentCategoryAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
@@ -28,10 +30,10 @@ export class SetParentCategoryAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
|
||||
if (parentCategory !== '') {
|
||||
assertIdWithinFamily(parentCategory)
|
||||
assertIdWithinFamily({ actionType, field: 'parentCategory', value: parentCategory })
|
||||
}
|
||||
|
||||
this.categoryId = categoryId
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'SetRelaxPrimaryDeviceAction'
|
||||
|
||||
export class SetRelaxPrimaryDeviceAction extends ParentAction {
|
||||
readonly userId: string
|
||||
@@ -28,7 +30,7 @@ export class SetRelaxPrimaryDeviceAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(userId)
|
||||
assertIdWithinFamily({ actionType, field: 'userId', value: userId })
|
||||
|
||||
this.userId = userId
|
||||
this.relax = relax
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'SetSendDeviceConnected'
|
||||
|
||||
export class SetSendDeviceConnected extends ParentAction {
|
||||
readonly deviceId: string
|
||||
@@ -28,7 +30,7 @@ export class SetSendDeviceConnected extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(deviceId)
|
||||
assertIdWithinFamily({ actionType, field: 'deviceId', value: deviceId })
|
||||
|
||||
this.deviceId = deviceId
|
||||
this.enable = enable
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertIdWithinFamily, assertSafeInteger } from './meta/util'
|
||||
|
||||
const actionType = 'SetUserDisableLimitsUntilAction'
|
||||
|
||||
export class SetUserDisableLimitsUntilAction extends ParentAction {
|
||||
readonly childId: string
|
||||
@@ -28,10 +31,15 @@ export class SetUserDisableLimitsUntilAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(childId)
|
||||
assertIdWithinFamily({ actionType, field: 'childId', value: childId })
|
||||
assertSafeInteger({ actionType, field: 'timestamp', value: timestamp })
|
||||
|
||||
if (timestamp < 0 || (!Number.isSafeInteger(timestamp))) {
|
||||
throw new Error('timestamp for set user disabe limits until must be >= 0')
|
||||
if (timestamp < 0) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'timestamp for set user disabe limits until must be >= 0',
|
||||
dynamicMessage: 'timestamp for set user disabe limits until must be >= 0, but was ' + timestamp
|
||||
})
|
||||
}
|
||||
|
||||
this.childId = childId
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'SetUserTimezoneAction'
|
||||
|
||||
export class SetUserTimezoneAction extends ParentAction {
|
||||
readonly userId: string
|
||||
@@ -28,7 +30,7 @@ export class SetUserTimezoneAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(userId)
|
||||
assertIdWithinFamily({ actionType, field: 'userId', value: userId })
|
||||
|
||||
this.userId = userId
|
||||
this.timezone = timezone
|
||||
|
||||
@@ -24,7 +24,7 @@ export class SignOutAtDeviceAction extends AppLogicAction {
|
||||
super()
|
||||
}
|
||||
|
||||
static parse = (action: SerializedSignOutAtDeviceAction) => SignOutAtDeviceAction.instance
|
||||
static parse = (_: SerializedSignOutAtDeviceAction) => SignOutAtDeviceAction.instance
|
||||
}
|
||||
|
||||
export interface SerializedSignOutAtDeviceAction {
|
||||
|
||||
@@ -15,9 +15,14 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { AppActivityItem, RemovedAppActivityItem, SerializedAppActivityItem, SerializedRemovedAppActivityItem } from '../model/appactivity'
|
||||
import { assertListWithoutDuplicates } from '../util/list'
|
||||
import {
|
||||
AppActivityItem, IncompleteAppActivityItemException, RemovedAppActivityItem, SerializedAppActivityItem, SerializedRemovedAppActivityItem
|
||||
} from '../model/appactivity'
|
||||
import { AppLogicAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertListWithoutDuplicates } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateAppActivitiesAction'
|
||||
|
||||
export class UpdateAppActivitiesAction extends AppLogicAction {
|
||||
readonly removed: Array<RemovedAppActivityItem>
|
||||
@@ -29,23 +34,44 @@ export class UpdateAppActivitiesAction extends AppLogicAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertListWithoutDuplicates(removed.map((item) => item.packageName + ':' + item.activityName))
|
||||
assertListWithoutDuplicates(updatedOrAdded.map((item) => item.packageName + ':' + item.activityName))
|
||||
assertListWithoutDuplicates({
|
||||
actionType,
|
||||
field: 'removed',
|
||||
list: removed.map((item) => item.packageName + ':' + item.activityName)
|
||||
})
|
||||
|
||||
assertListWithoutDuplicates({
|
||||
actionType,
|
||||
field: 'updatedOrAdded',
|
||||
list: updatedOrAdded.map((item) => item.packageName + ':' + item.activityName)
|
||||
})
|
||||
|
||||
if (removed.length === 0 && updatedOrAdded.length === 0) {
|
||||
throw new Error('UpdateAppActivitiesAction is empty')
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'UpdateAppActivitiesAction is empty'
|
||||
})
|
||||
}
|
||||
|
||||
this.removed = removed
|
||||
this.updatedOrAdded = updatedOrAdded
|
||||
}
|
||||
|
||||
static parse = ({ removed, updatedOrAdded }: SerializedUpdateAppActivitiesAction) => (
|
||||
new UpdateAppActivitiesAction({
|
||||
removed: removed.map((item) => RemovedAppActivityItem.parse(item)),
|
||||
updatedOrAdded: updatedOrAdded.map((item) => AppActivityItem.parse(item))
|
||||
})
|
||||
)
|
||||
static parse = ({ removed, updatedOrAdded }: SerializedUpdateAppActivitiesAction) => {
|
||||
try {
|
||||
return new UpdateAppActivitiesAction({
|
||||
removed: removed.map((item) => RemovedAppActivityItem.parse(item)),
|
||||
updatedOrAdded: updatedOrAdded.map((item) => AppActivityItem.parse(item))
|
||||
})
|
||||
} catch (ex) {
|
||||
if (ex instanceof IncompleteAppActivityItemException) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'invalid app activity item'
|
||||
})
|
||||
} else throw ex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface SerializedUpdateAppActivitiesAction {
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily, assertSafeInteger, throwOutOfRange } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateCategoryBatteryLimitAction'
|
||||
|
||||
export class UpdateCategoryBatteryLimitAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
@@ -30,17 +32,21 @@ export class UpdateCategoryBatteryLimitAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
|
||||
if (chargeLimit !== undefined) {
|
||||
if ((!Number.isSafeInteger(chargeLimit)) || chargeLimit < 0 || chargeLimit > 100) {
|
||||
throw new Error('charge limit out of range')
|
||||
assertSafeInteger({ actionType, field: 'chargeLimit', value: chargeLimit })
|
||||
|
||||
if (chargeLimit < 0 || chargeLimit > 100) {
|
||||
throwOutOfRange({ actionType, field: 'chargeLimit', value: chargeLimit })
|
||||
}
|
||||
}
|
||||
|
||||
if (mobileLimit !== undefined) {
|
||||
if ((!Number.isSafeInteger(mobileLimit)) || mobileLimit < 0 || mobileLimit > 100) {
|
||||
throw new Error('mobile limit out of range')
|
||||
assertSafeInteger({ actionType, field: 'mobileLimit', value: mobileLimit })
|
||||
|
||||
if (mobileLimit < 0 || mobileLimit > 100) {
|
||||
throwOutOfRange({ actionType, field: 'mobileLimit', value: mobileLimit })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateCategoryBlockAllNotificationsAction'
|
||||
|
||||
export class UpdateCategoryBlockAllNotificationsAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
@@ -25,7 +27,7 @@ export class UpdateCategoryBlockAllNotificationsAction extends ParentAction {
|
||||
constructor ({ categoryId, blocked }: {categoryId: string, blocked: boolean}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
|
||||
this.categoryId = categoryId
|
||||
this.blocked = blocked
|
||||
|
||||
@@ -15,12 +15,15 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { validateBitmask } from '../util/bitmask'
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { BitmapValidationException, validateBitmask } from '../util/bitmask'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
export const blockedTimesBitmaskLength = 60 * 24 * 7 /* number of minutes per week */
|
||||
|
||||
const actionType = 'UpdateCategoryBlockedTimesAction'
|
||||
|
||||
export class UpdateCategoryBlockedTimesAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
readonly blockedTimes: string
|
||||
@@ -31,8 +34,18 @@ export class UpdateCategoryBlockedTimesAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
validateBitmask(blockedTimes, blockedTimesBitmaskLength)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
|
||||
try {
|
||||
validateBitmask(blockedTimes, blockedTimesBitmaskLength)
|
||||
} catch (ex) {
|
||||
if (ex instanceof BitmapValidationException) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'invalid bitmask'
|
||||
})
|
||||
} else throw ex
|
||||
}
|
||||
|
||||
this.categoryId = categoryId
|
||||
this.blockedTimes = blockedTimes
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { uniq } from 'lodash'
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily, assertNonEmptyListWithoutDuplicates } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateCategorySortingAction'
|
||||
|
||||
export class UpdateCategorySortingAction extends ParentAction {
|
||||
readonly categoryIds: Array<string>
|
||||
@@ -27,15 +28,13 @@ export class UpdateCategorySortingAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
if (categoryIds.length === 0) {
|
||||
throw new Error('empty category sorting list')
|
||||
}
|
||||
assertNonEmptyListWithoutDuplicates({ actionType, field: 'categoryIds', list: categoryIds })
|
||||
|
||||
if (uniq(categoryIds).length !== categoryIds.length) {
|
||||
throw new Error('category sorting list has duplicates')
|
||||
}
|
||||
|
||||
categoryIds.forEach((categoryId) => assertIdWithinFamily(categoryId))
|
||||
categoryIds.forEach((categoryId) => assertIdWithinFamily({
|
||||
actionType,
|
||||
field: 'categoryIds',
|
||||
value: categoryId
|
||||
}))
|
||||
|
||||
this.categoryIds = categoryIds
|
||||
}
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertIdWithinFamily, assertSafeInteger } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateCategoryTemporarilyBlockedAction'
|
||||
|
||||
export class UpdateCategoryTemporarilyBlockedAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
@@ -30,15 +33,16 @@ export class UpdateCategoryTemporarilyBlockedAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
|
||||
if (endTime !== undefined) {
|
||||
if (!Number.isSafeInteger(endTime)) {
|
||||
throw new Error()
|
||||
}
|
||||
assertSafeInteger({ actionType, field: 'endTime', value: endTime })
|
||||
|
||||
if (!blocked) {
|
||||
throw new Error()
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'can not set a end time when disabling blocking'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
*/
|
||||
|
||||
import { allowedTimeWarningFlags } from '../database/category'
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily, assertSafeInteger, throwOutOfRange } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateCategoryTimeWarningsAction'
|
||||
|
||||
export class UpdateCategoryTimeWarningsAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
@@ -31,10 +33,11 @@ export class UpdateCategoryTimeWarningsAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
assertSafeInteger({ actionType, field: 'flags', value: flags })
|
||||
|
||||
if ((flags & allowedTimeWarningFlags) !== flags) {
|
||||
throw new Error('illegal flags')
|
||||
throwOutOfRange({ actionType, field: 'flags', value: flags })
|
||||
}
|
||||
|
||||
this.categoryId = categoryId
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateCategoryTitleAction'
|
||||
|
||||
export class UpdateCategoryTitleAction extends ParentAction {
|
||||
readonly categoryId: string
|
||||
@@ -25,7 +27,7 @@ export class UpdateCategoryTitleAction extends ParentAction {
|
||||
constructor ({ categoryId, newTitle }: {categoryId: string, newTitle: string}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
|
||||
this.categoryId = categoryId
|
||||
this.newTitle = newTitle
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateDeviceNameAction'
|
||||
|
||||
export class UpdateDeviceNameAction extends ParentAction {
|
||||
readonly deviceId: string
|
||||
@@ -31,10 +34,13 @@ export class UpdateDeviceNameAction extends ParentAction {
|
||||
this.deviceId = deviceId
|
||||
this.name = name
|
||||
|
||||
assertIdWithinFamily(deviceId)
|
||||
assertIdWithinFamily({ actionType, field: 'deviceId', value: deviceId })
|
||||
|
||||
if (name.trim().length === 0) {
|
||||
throw new Error('new device name must not be blank')
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'new device name must not be blank'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ import { NewPermissionStatus } from '../model/newpermissionstatus'
|
||||
import { ProtectionLevel } from '../model/protectionlevel'
|
||||
import { RuntimePermissionStatus } from '../model/runtimepermissionstatus'
|
||||
import { AppLogicAction } from './basetypes'
|
||||
import { assertSafeInteger, throwOutOfRange } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateDeviceStatusAction'
|
||||
|
||||
export class UpdateDeviceStatusAction extends AppLogicAction {
|
||||
readonly newProtetionLevel?: ProtectionLevel
|
||||
@@ -52,8 +55,10 @@ export class UpdateDeviceStatusAction extends AppLogicAction {
|
||||
super()
|
||||
|
||||
if (newAppVersion !== undefined) {
|
||||
if (!Number.isSafeInteger(newAppVersion) || (newAppVersion < 0)) {
|
||||
throw new Error('invalid new ap version')
|
||||
assertSafeInteger({ actionType, field: 'newAppVersion', value: newAppVersion })
|
||||
|
||||
if (newAppVersion < 0) {
|
||||
throwOutOfRange({ actionType, field: 'newAppVersion', value: newAppVersion })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateEnableActivityLevelBlockingAction'
|
||||
|
||||
export class UpdateEnableActivityLevelBlockingAction extends ParentAction {
|
||||
readonly deviceId: string
|
||||
@@ -25,7 +27,7 @@ export class UpdateEnableActivityLevelBlockingAction extends ParentAction {
|
||||
constructor ({ deviceId, enable }: {deviceId: string, enable: boolean}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(deviceId)
|
||||
assertIdWithinFamily({ actionType, field: 'deviceId', value: deviceId })
|
||||
|
||||
this.deviceId = deviceId
|
||||
this.enable = enable
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateNetworkTimeVerificationAction'
|
||||
|
||||
export class UpdateNetworkTimeVerificationAction extends ParentAction {
|
||||
readonly deviceId: string
|
||||
@@ -28,7 +30,7 @@ export class UpdateNetworkTimeVerificationAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(deviceId)
|
||||
assertIdWithinFamily({ actionType, field: 'deviceId', value: deviceId })
|
||||
|
||||
this.deviceId = deviceId
|
||||
this.mode = mode
|
||||
|
||||
@@ -15,9 +15,12 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { validateAndParseBitmask } from '../util/bitmask'
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { BitmapValidationException, validateAndParseBitmask } from '../util/bitmask'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateParentBlockedTimesAction'
|
||||
|
||||
export class UpdateParentBlockedTimesAction extends ParentAction {
|
||||
readonly parentId: string
|
||||
@@ -29,9 +32,9 @@ export class UpdateParentBlockedTimesAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(parentId)
|
||||
assertIdWithinFamily({ actionType, field: 'parentId', value: parentId })
|
||||
|
||||
{
|
||||
try {
|
||||
const parsedBlockedTimes = validateAndParseBitmask(blockedTimes, 60 * 24 * 7 /* number of minutes per week */)
|
||||
|
||||
for (let day = 0; day < 7; day++) {
|
||||
@@ -44,9 +47,19 @@ export class UpdateParentBlockedTimesAction extends ParentAction {
|
||||
}
|
||||
|
||||
if (blockedMinutes > 60 * 18 /* 18 hours */) {
|
||||
throw new Error('too much blocked minutes per day')
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'too much blocked minutes per day'
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
if (ex instanceof BitmapValidationException) {
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'invalid bitmask'
|
||||
})
|
||||
} else throw ex
|
||||
}
|
||||
|
||||
this.parentId = parentId
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily, assertSafeInteger, throwOutOfRange } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateParentNotificationFlagsAction'
|
||||
|
||||
export class UpdateParentNotificationFlagsAction extends ParentAction {
|
||||
readonly parentId: string
|
||||
@@ -30,14 +32,12 @@ export class UpdateParentNotificationFlagsAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(parentId)
|
||||
assertIdWithinFamily({ actionType, field: 'parentId', value: parentId })
|
||||
|
||||
if (!Number.isSafeInteger(flags)) {
|
||||
throw new Error('flags must be an integer')
|
||||
}
|
||||
assertSafeInteger({ actionType, field: 'flags', value: flags })
|
||||
|
||||
if (flags < 0 || flags > 1) {
|
||||
throw new Error('flags are out of the valid range')
|
||||
throwOutOfRange({ actionType, field: 'flags', value: flags })
|
||||
}
|
||||
|
||||
this.parentId = parentId
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
*/
|
||||
|
||||
import { MinuteOfDay } from '../util/minuteofday'
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertIdWithinFamily, assertSafeInteger, throwOutOfRange } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateTimelimitRuleAction'
|
||||
|
||||
export class UpdateTimelimitRuleAction extends ParentAction {
|
||||
readonly ruleId: string
|
||||
@@ -53,35 +56,37 @@ export class UpdateTimelimitRuleAction extends ParentAction {
|
||||
this.sessionDurationMilliseconds = sessionDurationMilliseconds
|
||||
this.sessionPauseMilliseconds = sessionPauseMilliseconds
|
||||
|
||||
assertIdWithinFamily(ruleId)
|
||||
assertIdWithinFamily({ actionType, field: 'ruleId', value: ruleId })
|
||||
|
||||
if (maximumTimeInMillis < 0 || (!Number.isSafeInteger(maximumTimeInMillis))) {
|
||||
throw new Error('maximumTimeInMillis must be >= 0')
|
||||
assertSafeInteger({ actionType, field: 'maximumTimeInMillis', value: maximumTimeInMillis })
|
||||
|
||||
if (maximumTimeInMillis < 0) {
|
||||
throwOutOfRange({ actionType, field: 'maximumTimeInMillis', value: maximumTimeInMillis })
|
||||
}
|
||||
|
||||
if (!(
|
||||
Number.isSafeInteger(dayMask) ||
|
||||
dayMask < 0 ||
|
||||
dayMask > (1 | 2 | 4 | 8 | 16 | 32 | 64)
|
||||
)) {
|
||||
throw new Error('invalid day mask')
|
||||
assertSafeInteger({ actionType, field: 'dayMask', value: dayMask })
|
||||
|
||||
if (dayMask < 0 || dayMask > (1 | 2 | 4 | 8 | 16 | 32 | 64)) {
|
||||
throwOutOfRange({ actionType, field: 'dayMask', value: dayMask })
|
||||
}
|
||||
|
||||
if (
|
||||
(!Number.isSafeInteger(start)) ||
|
||||
(!Number.isSafeInteger(end)) ||
|
||||
(!Number.isSafeInteger(sessionDurationMilliseconds)) ||
|
||||
(!Number.isSafeInteger(sessionPauseMilliseconds))
|
||||
) {
|
||||
throw new Error()
|
||||
}
|
||||
assertSafeInteger({ actionType, field: 'start', value: start })
|
||||
assertSafeInteger({ actionType, field: 'end', value: end })
|
||||
assertSafeInteger({ actionType, field: 'sessionDurationMilliseconds', value: sessionDurationMilliseconds })
|
||||
assertSafeInteger({ actionType, field: 'sessionPauseMilliseconds', value: sessionPauseMilliseconds })
|
||||
|
||||
if (start < MinuteOfDay.MIN || end > MinuteOfDay.MAX || start > end) {
|
||||
throw new Error()
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'time slot out of range'
|
||||
})
|
||||
}
|
||||
|
||||
if (sessionDurationMilliseconds < 0 || sessionPauseMilliseconds < 0) {
|
||||
throw new Error()
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'session duration lesser than zero'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
*/
|
||||
|
||||
import { UserFlags } from '../model/userflags'
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { InvalidActionParameterException } from './meta/exception'
|
||||
import { assertIdWithinFamily, assertSafeInteger } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateUserFlagsAction'
|
||||
|
||||
export class UpdateUserFlagsAction extends ParentAction {
|
||||
readonly userId: string
|
||||
@@ -31,14 +34,16 @@ export class UpdateUserFlagsAction extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(userId)
|
||||
|
||||
if ((!Number.isSafeInteger(modifiedBits)) || (!Number.isSafeInteger(newValues))) {
|
||||
throw new Error('flags must be an integer')
|
||||
}
|
||||
assertIdWithinFamily({ actionType, field: 'userId', value: userId })
|
||||
assertSafeInteger({ actionType, field: 'modifiedBits', value: modifiedBits })
|
||||
assertSafeInteger({ actionType, field: 'newValues', value: newValues })
|
||||
|
||||
if ((modifiedBits | UserFlags.ALL_FLAGS) !== UserFlags.ALL_FLAGS || (modifiedBits | newValues) !== modifiedBits) {
|
||||
throw new Error('flags are out of the valid range')
|
||||
throw new InvalidActionParameterException({
|
||||
actionType,
|
||||
staticMessage: 'flags are out of the valid range',
|
||||
dynamicMessage: 'flags are out of the valid range: ' + modifiedBits + ', ' + newValues
|
||||
})
|
||||
}
|
||||
|
||||
this.userId = userId
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
import { assertIdWithinFamily } from './meta/util'
|
||||
|
||||
const actionType = 'UpdateUserLimitLoginCategory'
|
||||
|
||||
export class UpdateUserLimitLoginCategory extends ParentAction {
|
||||
readonly userId: string
|
||||
@@ -28,10 +30,10 @@ export class UpdateUserLimitLoginCategory extends ParentAction {
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(userId)
|
||||
assertIdWithinFamily({ actionType, field: 'userId', value: userId })
|
||||
|
||||
if (categoryId !== undefined) {
|
||||
assertIdWithinFamily(categoryId)
|
||||
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
|
||||
}
|
||||
|
||||
this.userId = userId
|
||||
|
||||
Reference in New Issue
Block a user