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
+}