From 1969fe4042b398fc333bddbf39f0ae5ce1dd1d4d Mon Sep 17 00:00:00 2001 From: Jonas Lochmann Date: Mon, 19 Aug 2019 00:00:00 +0000 Subject: [PATCH] Add support for parent blocked times --- src/action/index.ts | 2 + src/action/resetparentblockedtimes.ts | 49 ++++++++++++ src/action/serialization/parentaction.ts | 8 ++ src/action/updateparentblockedtimes.ts | 74 +++++++++++++++++++ src/api/validator.ts | 48 ++++++++++++ .../20190819-add-parent-blocked-times.ts | 39 ++++++++++ src/database/user.ts | 21 +++++- src/function/parent/create-family.ts | 3 +- .../dispatch-parent-action/adduser.ts | 3 +- .../dispatch-parent-action/index.ts | 8 ++ .../resetparentblockedtimes.ts | 42 +++++++++++ .../updateparentblockedtimes.ts | 42 +++++++++++ src/function/sync/get-server-data-status.ts | 9 ++- src/object/serverdatastatus.ts | 1 + src/util/bitmask.ts | 22 +++++- 15 files changed, 363 insertions(+), 8 deletions(-) create mode 100644 src/action/resetparentblockedtimes.ts create mode 100644 src/action/updateparentblockedtimes.ts create mode 100644 src/database/migration/migrations/20190819-add-parent-blocked-times.ts create mode 100644 src/function/sync/apply-actions/dispatch-parent-action/resetparentblockedtimes.ts create mode 100644 src/function/sync/apply-actions/dispatch-parent-action/updateparentblockedtimes.ts diff --git a/src/action/index.ts b/src/action/index.ts index d4142e7..3c9b18a 100644 --- a/src/action/index.ts +++ b/src/action/index.ts @@ -34,6 +34,7 @@ export { RemoveCategoryAppsAction } from './removecategoryapps' export { RemoveInstalledAppsAction } from './removeinstalledapps' export { RemoveUserAction } from './removeuser' export { RenameChildAction } from './renamechild' +export { ResetParentBlockedTimesAction } from './resetparentblockedtimes' export { SetCategoryExtraTimeAction } from './setcategoryextratime' export { SetCategoryForUnassignedAppsAction } from './setcategoryforunassignedapps' export { SetChildPasswordAction } from './setchildpassword' @@ -59,5 +60,6 @@ export { UpdateDeviceNameAction } from './updatedevicename' export { UpdateDeviceStatusAction } from './updatedevicestatus' export { UpdateEnableActivityLevelBlockingAction } from './updateenableactivitylevelblocking' export { UpdateNetworkTimeVerificationAction } from './updatenetworktimeverification' +export { UpdateParentBlockedTimesAction } from './updateparentblockedtimes' export { UpdateParentNotificationFlagsAction } from './updateparentnotificationflags' export { UpdateTimelimitRuleAction } from './updatetimelimitrule' diff --git a/src/action/resetparentblockedtimes.ts b/src/action/resetparentblockedtimes.ts new file mode 100644 index 0000000..97de7e5 --- /dev/null +++ b/src/action/resetparentblockedtimes.ts @@ -0,0 +1,49 @@ +/* + * server component for the TimeLimit App + * Copyright (C) 2019 Jonas Lochmann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { assertIdWithinFamily } from '../util/token' +import { ParentAction } from './basetypes' + +export class ResetParentBlockedTimesAction extends ParentAction { + readonly parentId: string + + constructor ({ parentId }: { + parentId: string + }) { + super() + + assertIdWithinFamily(parentId) + + this.parentId = parentId + } + + serialize = (): SerializedResetParentBlockedTimesAction => ({ + type: 'RESET_PARENT_BLOCKED_TIMES', + parentId: this.parentId + }) + + static parse = ({ parentId }: SerializedResetParentBlockedTimesAction) => ( + new ResetParentBlockedTimesAction({ + parentId + }) + ) +} + +export interface SerializedResetParentBlockedTimesAction { + type: 'RESET_PARENT_BLOCKED_TIMES' + parentId: string +} diff --git a/src/action/serialization/parentaction.ts b/src/action/serialization/parentaction.ts index ac97862..7556b80 100644 --- a/src/action/serialization/parentaction.ts +++ b/src/action/serialization/parentaction.ts @@ -28,6 +28,7 @@ import { IncrementCategoryExtraTimeAction, SerializedIncrementCategoryExtraTimeA import { RemoveCategoryAppsAction, SerializedRemoveCategoryAppsAction } from '../removecategoryapps' import { RemoveUserAction, SerializedRemoveUserAction } from '../removeuser' import { RenameChildAction, SerializedRenameChildAction } from '../renamechild' +import { ResetParentBlockedTimesAction, SerializedResetParentBlockedTimesAction } from '../resetparentblockedtimes' import { SerializedSetCategoryExtraTimeAction, SetCategoryExtraTimeAction } from '../setcategoryextratime' import { SerializedSetCategoryForUnassignedAppsAction, SetCategoryForUnassignedAppsAction } from '../setcategoryforunassignedapps' import { SerializedSetChildPasswordAction, SetChildPasswordAction } from '../setchildpassword' @@ -49,6 +50,7 @@ import { SerializedUpdateCategoryTitleAction, UpdateCategoryTitleAction } from ' import { SerializedUpdateDeviceNameAction, UpdateDeviceNameAction } from '../updatedevicename' import { SerializedUpdateEnableActivityLevelBlockingAction, UpdateEnableActivityLevelBlockingAction } from '../updateenableactivitylevelblocking' import { SerialiizedUpdateNetworkTimeVerificationAction, UpdateNetworkTimeVerificationAction } from '../updatenetworktimeverification' +import { SerializedUpdateParentBlockedTimesAction, UpdateParentBlockedTimesAction } from '../updateparentblockedtimes' import { SerializedUpdateParentNotificationFlagsAction, UpdateParentNotificationFlagsAction } from '../updateparentnotificationflags' import { SerializedUpdateTimelimitRuleAction, UpdateTimelimitRuleAction } from '../updatetimelimitrule' @@ -65,6 +67,7 @@ export type SerializedParentAction = SerializedRemoveCategoryAppsAction | SerializedRemoveUserAction | SerializedRenameChildAction | + SerializedResetParentBlockedTimesAction | SerializedSetCategoryForUnassignedAppsAction | SerializedSetChildPasswordAction | SerializedSetConsiderRebootManipulationAction | @@ -86,6 +89,7 @@ export type SerializedParentAction = SerializedUpdateDeviceNameAction | SerializedUpdateEnableActivityLevelBlockingAction | SerialiizedUpdateNetworkTimeVerificationAction | + SerializedUpdateParentBlockedTimesAction | SerializedUpdateParentNotificationFlagsAction | SerializedUpdateTimelimitRuleAction @@ -114,6 +118,8 @@ export const parseParentAction = (action: SerializedParentAction): ParentAction return RemoveUserAction.parse(action) } else if (action.type === 'RENAME_CHILD') { return RenameChildAction.parse(action) + } else if (action.type === 'RESET_PARENT_BLOCKED_TIMES') { + return ResetParentBlockedTimesAction.parse(action) } else if (action.type === 'SET_CATEGORY_EXTRA_TIME') { return SetCategoryExtraTimeAction.parse(action) } else if (action.type === 'SET_CATEGORY_FOR_UNASSIGNED_APPS') { @@ -156,6 +162,8 @@ export const parseParentAction = (action: SerializedParentAction): ParentAction return UpdateEnableActivityLevelBlockingAction.parse(action) } else if (action.type === 'UPDATE_NETWORK_TIME_VERIFICATION') { return UpdateNetworkTimeVerificationAction.parse(action) + } else if (action.type === 'UPDATE_PARENT_BLOCKED_TIMES') { + return UpdateParentBlockedTimesAction.parse(action) } else if (action.type === 'UPDATE_PARENT_NOTIFICATION_FLAGS') { return UpdateParentNotificationFlagsAction.parse(action) } else if (action.type === 'UPDATE_TIMELIMIT_RULE') { diff --git a/src/action/updateparentblockedtimes.ts b/src/action/updateparentblockedtimes.ts new file mode 100644 index 0000000..e251724 --- /dev/null +++ b/src/action/updateparentblockedtimes.ts @@ -0,0 +1,74 @@ +/* + * server component for the TimeLimit App + * Copyright (C) 2019 Jonas Lochmann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { validateAndParseBitmask } from '../util/bitmask' +import { assertIdWithinFamily } from '../util/token' +import { ParentAction } from './basetypes' + +export class UpdateParentBlockedTimesAction extends ParentAction { + readonly parentId: string + readonly blockedTimes: string + + constructor ({ parentId, blockedTimes }: { + parentId: string + blockedTimes: string + }) { + super() + + assertIdWithinFamily(parentId) + + { + const parsedBlockedTimes = validateAndParseBitmask(blockedTimes, 60 * 24 * 7 /* number of minutes per week */) + + for (let day = 0; day < 7; day++) { + let blockedMinutes = 0 + + for (let minute = 0; minute < 60 * 24 /* 1 day */; minute++) { + if (parsedBlockedTimes[day * 60 * 24 + minute]) { + blockedMinutes++ + } + } + + if (blockedMinutes > 60 * 18 /* 18 hours */) { + throw new Error('too much blocked minutes per day') + } + } + } + + this.parentId = parentId + this.blockedTimes = blockedTimes + } + + serialize = (): SerializedUpdateParentBlockedTimesAction => ({ + type: 'UPDATE_PARENT_BLOCKED_TIMES', + parentId: this.parentId, + times: this.blockedTimes + }) + + static parse = ({ parentId, times }: SerializedUpdateParentBlockedTimesAction) => ( + new UpdateParentBlockedTimesAction({ + parentId, + blockedTimes: times + }) + ) +} + +export interface SerializedUpdateParentBlockedTimesAction { + type: 'UPDATE_PARENT_BLOCKED_TIMES' + parentId: string + times: string +} diff --git a/src/api/validator.ts b/src/api/validator.ts index 21cec82..ce1ad26 100644 --- a/src/api/validator.ts +++ b/src/api/validator.ts @@ -450,6 +450,25 @@ const definitions = { "type" ] }, + "SerializedResetParentBlockedTimesAction": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "RESET_PARENT_BLOCKED_TIMES" + ] + }, + "parentId": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "parentId", + "type" + ] + }, "SerializedSetCategoryExtraTimeAction": { "type": "object", "properties": { @@ -942,6 +961,29 @@ const definitions = { "type" ] }, + "SerializedUpdateParentBlockedTimesAction": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "UPDATE_PARENT_BLOCKED_TIMES" + ] + }, + "parentId": { + "type": "string" + }, + "times": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "parentId", + "times", + "type" + ] + }, "SerializedUpdateParentNotificationFlagsAction": { "type": "object", "properties": { @@ -1535,6 +1577,9 @@ export const isSerializedParentAction: (value: object) => value is SerializedPar { "$ref": "#/definitions/SerializedRenameChildAction" }, + { + "$ref": "#/definitions/SerializedResetParentBlockedTimesAction" + }, { "$ref": "#/definitions/SerializedSetCategoryExtraTimeAction" }, @@ -1598,6 +1643,9 @@ export const isSerializedParentAction: (value: object) => value is SerializedPar { "$ref": "#/definitions/SerialiizedUpdateNetworkTimeVerificationAction" }, + { + "$ref": "#/definitions/SerializedUpdateParentBlockedTimesAction" + }, { "$ref": "#/definitions/SerializedUpdateParentNotificationFlagsAction" }, diff --git a/src/database/migration/migrations/20190819-add-parent-blocked-times.ts b/src/database/migration/migrations/20190819-add-parent-blocked-times.ts new file mode 100644 index 0000000..5689abc --- /dev/null +++ b/src/database/migration/migrations/20190819-add-parent-blocked-times.ts @@ -0,0 +1,39 @@ +/* + * server component for the TimeLimit App + * Copyright (C) 2019 Jonas Lochmann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { QueryInterface, Sequelize, Transaction } from 'sequelize' +import { attributesVersion5 as userAttributes } from '../../user' + +export async function up (queryInterface: QueryInterface, sequelize: Sequelize) { + await sequelize.transaction({ + type: Transaction.TYPES.EXCLUSIVE + }, async (transaction) => { + await queryInterface.addColumn('Users', 'blockedTimes', { + ...userAttributes.blockedTimes + }, { + transaction + }) + }) +} + +export async function down (queryInterface: QueryInterface, sequelize: Sequelize) { + await sequelize.transaction({ + type: Transaction.TYPES.EXCLUSIVE + }, async (transaction) => { + await queryInterface.removeColumn('Users', 'blockedTimes', { transaction }) + }) +} diff --git a/src/database/user.ts b/src/database/user.ts index b646e32..fb4da51 100644 --- a/src/database/user.ts +++ b/src/database/user.ts @@ -16,6 +16,7 @@ */ import * as Sequelize from 'sequelize' +import { serializedBitmaskRegex } from '../util/bitmask' import { optionalPasswordRegex, optionalSaltRegex } from '../util/password' import { booleanColumn, createEnumColumn, familyIdColumn, idWithinFamilyColumn, labelColumn, optionalIdWithinFamilyColumn, timestampColumn } from './columns' import { SequelizeAttributes } from './types' @@ -49,8 +50,12 @@ export interface UserAttributesVersion4 { mailNotificationFlags: number } +export interface UserAttributesVersion5 { + blockedTimes: string +} + export type UserAttributes = UserAttributesVersion1 & UserAttributesVersion2 & - UserAttributesVersion3 & UserAttributesVersion4 + UserAttributesVersion3 & UserAttributesVersion4 & UserAttributesVersion5 export type UserModel = Sequelize.Model & UserAttributes export type UserModelStatic = typeof Sequelize.Model & { @@ -123,11 +128,23 @@ export const attributesVersion4: SequelizeAttributes = { } } +export const attributesVersion5: SequelizeAttributes = { + blockedTimes: { + type: Sequelize.TEXT, + allowNull: false, + defaultValue: '', + validate: { + is: serializedBitmaskRegex + } + } +} + export const attributes: SequelizeAttributes = { ...attributesVersion1, ...attributesVersion2, ...attributesVersion3, - ...attributesVersion4 + ...attributesVersion4, + ...attributesVersion5 } export const createUserModel = (sequelize: Sequelize.Sequelize): UserModelStatic => sequelize.define('User', attributes) as UserModelStatic diff --git a/src/function/parent/create-family.ts b/src/function/parent/create-family.ts index 8bc664a..3524bd0 100644 --- a/src/function/parent/create-family.ts +++ b/src/function/parent/create-family.ts @@ -81,7 +81,8 @@ export const createFamily = async ({ database, mailAuthToken, firstParentDevice, currentDevice: '', categoryForNotAssignedApps: '', relaxPrimaryDeviceRule: false, - mailNotificationFlags: 1 // enable warning notifications + mailNotificationFlags: 1, // enable warning notifications + blockedTimes: '' }, { transaction }) // add parent device diff --git a/src/function/sync/apply-actions/dispatch-parent-action/adduser.ts b/src/function/sync/apply-actions/dispatch-parent-action/adduser.ts index b92c777..d857202 100644 --- a/src/function/sync/apply-actions/dispatch-parent-action/adduser.ts +++ b/src/function/sync/apply-actions/dispatch-parent-action/adduser.ts @@ -36,7 +36,8 @@ export async function dispatchAddUser ({ action, cache }: { currentDevice: '', categoryForNotAssignedApps: '', relaxPrimaryDeviceRule: false, - mailNotificationFlags: 0 + mailNotificationFlags: 0, + blockedTimes: '' }, { transaction: cache.transaction }) cache.invalidiateUserList = true diff --git a/src/function/sync/apply-actions/dispatch-parent-action/index.ts b/src/function/sync/apply-actions/dispatch-parent-action/index.ts index d976bb4..78f445a 100644 --- a/src/function/sync/apply-actions/dispatch-parent-action/index.ts +++ b/src/function/sync/apply-actions/dispatch-parent-action/index.ts @@ -29,6 +29,7 @@ import { RemoveCategoryAppsAction, RemoveUserAction, RenameChildAction, + ResetParentBlockedTimesAction, SetCategoryExtraTimeAction, SetCategoryForUnassignedAppsAction, SetChildPasswordAction, @@ -50,6 +51,7 @@ import { UpdateDeviceNameAction, UpdateEnableActivityLevelBlockingAction, UpdateNetworkTimeVerificationAction, + UpdateParentBlockedTimesAction, UpdateParentNotificationFlagsAction, UpdateTimelimitRuleAction } from '../../../../action' @@ -66,6 +68,7 @@ import { dispatchIncrementCategoryExtraTime } from './incrementcategoryextratime import { dispatchRemoveCategoryApps } from './removecategoryapps' import { dispatchRemoveUser } from './removeuser' import { dispatchRenameChild } from './renamechild' +import { dispatchResetParentBlockedTimes } from './resetparentblockedtimes' import { dispatchSetCategoryExtraTime } from './setcategoryextratime' import { dispatchSetCategoryForUnassignedApps } from './setcategoryforunassignedapps' import { dispatchSetChildPassword } from './setchildpassword' @@ -87,6 +90,7 @@ import { dispatchUpdateCategoryTitle } from './updatecategorytitle' import { dispatchUpdateDeviceName } from './updatedevicename' import { dispatchUpdateEnableActivityLevelBlocking } from './updateenableactivitylevelblocking' import { dispatchUpdateNetworkTimeVerification } from './updatenetworktimeverification' +import { dispatchUpdateParentBlockedTimes } from './updateparentblockedtimes' import { dispatchUpdateParentNotificationFlags } from './updateparentnotificationflags' import { dispatchUpdateTimelimitRule } from './updatetimelimitrule' @@ -166,6 +170,10 @@ export const dispatchParentAction = async ({ action, cache, parentUserId, source await dispatchIgnoreManipulation({ action, cache }) } else if (action instanceof UpdateCategoryTimeWarningsAction) { await dispatchUpdateCategoryTimeWarnings({ action, cache }) + } else if (action instanceof ResetParentBlockedTimesAction) { + await dispatchResetParentBlockedTimes({ action, cache }) + } else if (action instanceof UpdateParentBlockedTimesAction) { + await dispatchUpdateParentBlockedTimes({ action, cache }) } else { throw new Error('unsupported action type') } diff --git a/src/function/sync/apply-actions/dispatch-parent-action/resetparentblockedtimes.ts b/src/function/sync/apply-actions/dispatch-parent-action/resetparentblockedtimes.ts new file mode 100644 index 0000000..6957f7f --- /dev/null +++ b/src/function/sync/apply-actions/dispatch-parent-action/resetparentblockedtimes.ts @@ -0,0 +1,42 @@ +/* + * server component for the TimeLimit App + * Copyright (C) 2019 Jonas Lochmann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { ResetParentBlockedTimesAction } from '../../../../action' +import { Cache } from '../cache' + +export async function dispatchResetParentBlockedTimes ({ action, cache }: { + action: ResetParentBlockedTimesAction + cache: Cache +}) { + const [affectedRows] = await cache.database.user.update({ + blockedTimes: '' + }, { + where: { + familyId: cache.familyId, + userId: action.parentId, + type: 'parent' + }, + transaction: cache.transaction + }) + + if (affectedRows === 0) { + throw new Error('invalid parent user id provided') + } + + cache.invalidiateUserList = true + cache.areChangesImportant = true +} diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updateparentblockedtimes.ts b/src/function/sync/apply-actions/dispatch-parent-action/updateparentblockedtimes.ts new file mode 100644 index 0000000..910d52b --- /dev/null +++ b/src/function/sync/apply-actions/dispatch-parent-action/updateparentblockedtimes.ts @@ -0,0 +1,42 @@ +/* + * server component for the TimeLimit App + * Copyright (C) 2019 Jonas Lochmann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { UpdateParentBlockedTimesAction } from '../../../../action' +import { Cache } from '../cache' + +export async function dispatchUpdateParentBlockedTimes ({ action, cache }: { + action: UpdateParentBlockedTimesAction + cache: Cache +}) { + const [affectedRows] = await cache.database.user.update({ + blockedTimes: action.blockedTimes + }, { + where: { + familyId: cache.familyId, + userId: action.parentId, + type: 'parent' + }, + transaction: cache.transaction + }) + + if (affectedRows === 0) { + throw new Error('invalid parent user id provided') + } + + cache.invalidiateUserList = true + cache.areChangesImportant = true +} diff --git a/src/function/sync/get-server-data-status.ts b/src/function/sync/get-server-data-status.ts index 414e55b..bba8e39 100644 --- a/src/function/sync/get-server-data-status.ts +++ b/src/function/sync/get-server-data-status.ts @@ -123,7 +123,8 @@ export const generateServerDataStatus = async ({ database, clientStatus, familyI 'currentDevice', 'categoryForNotAssignedApps', 'relaxPrimaryDeviceRule', - 'mailNotificationFlags' + 'mailNotificationFlags', + 'blockedTimes' ], transaction })).map((item) => ({ @@ -138,7 +139,8 @@ export const generateServerDataStatus = async ({ database, clientStatus, familyI currentDevice: item.currentDevice, categoryForNotAssignedApps: item.categoryForNotAssignedApps, relaxPrimaryDeviceRule: item.relaxPrimaryDeviceRule, - mailNotificationFlags: item.mailNotificationFlags + mailNotificationFlags: item.mailNotificationFlags, + blockedTimes: item.blockedTimes })) result.users = { @@ -155,7 +157,8 @@ export const generateServerDataStatus = async ({ database, clientStatus, familyI currentDevice: item.currentDevice, categoryForNotAssignedApps: item.categoryForNotAssignedApps, relaxPrimaryDevice: item.relaxPrimaryDeviceRule, - mailNotificationFlags: item.mailNotificationFlags + mailNotificationFlags: item.mailNotificationFlags, + blockedTimes: item.blockedTimes })) } } diff --git a/src/object/serverdatastatus.ts b/src/object/serverdatastatus.ts index 7c8ab5f..ca1e553 100644 --- a/src/object/serverdatastatus.ts +++ b/src/object/serverdatastatus.ts @@ -57,6 +57,7 @@ export interface ServerUserEntry { categoryForNotAssignedApps: string relaxPrimaryDevice: boolean mailNotificationFlags: number + blockedTimes: string } export interface ServerDeviceData { diff --git a/src/util/bitmask.ts b/src/util/bitmask.ts index 29affef..a774848 100644 --- a/src/util/bitmask.ts +++ b/src/util/bitmask.ts @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -import { split } from 'lodash' +import { range, split } from 'lodash' export const serializedBitmaskRegex = /^(\d*,\d*(,\d*,\d*)*)?$/ @@ -52,3 +52,23 @@ export const validateBitmask = (bitmask: string, maxLength: number) => { previousValue = item }) } + +export const validateAndParseBitmask = (bitmask: string, maxLength: number) => { + validateBitmask(bitmask, maxLength) + + const result = range(0, maxLength).map((_) => false) + + const splitpoints = split(bitmask, ',').map((item) => parseInt(item, 10)) + + let i = 0 + while (i < splitpoints.length) { + const start = splitpoints[i++] + const end = splitpoints[i++] + + for (let j = start; j < end; j++) { + result[j] = true + } + } + + return result +}