mirror of
https://codeberg.org/timelimit/timelimit-server.git
synced 2026-08-31 19:03:45 +02:00
Add user flags field
This commit is contained in:
@@ -66,3 +66,4 @@ export { UpdateNetworkTimeVerificationAction } from './updatenetworktimeverifica
|
||||
export { UpdateParentBlockedTimesAction } from './updateparentblockedtimes'
|
||||
export { UpdateParentNotificationFlagsAction } from './updateparentnotificationflags'
|
||||
export { UpdateTimelimitRuleAction } from './updatetimelimitrule'
|
||||
export { UpdateUserFlagsAction } from './updateuserflags'
|
||||
|
||||
@@ -55,6 +55,7 @@ import { SerialiizedUpdateNetworkTimeVerificationAction, UpdateNetworkTimeVerifi
|
||||
import { SerializedUpdateParentBlockedTimesAction, UpdateParentBlockedTimesAction } from '../updateparentblockedtimes'
|
||||
import { SerializedUpdateParentNotificationFlagsAction, UpdateParentNotificationFlagsAction } from '../updateparentnotificationflags'
|
||||
import { SerializedUpdateTimelimitRuleAction, UpdateTimelimitRuleAction } from '../updatetimelimitrule'
|
||||
import { SerializedUpdateUserFlagsAction, UpdateUserFlagsAction } from '../updateuserflags'
|
||||
|
||||
export type SerializedParentAction =
|
||||
SerializedAddCategoryAppsAction |
|
||||
@@ -95,7 +96,8 @@ export type SerializedParentAction =
|
||||
SerialiizedUpdateNetworkTimeVerificationAction |
|
||||
SerializedUpdateParentBlockedTimesAction |
|
||||
SerializedUpdateParentNotificationFlagsAction |
|
||||
SerializedUpdateTimelimitRuleAction
|
||||
SerializedUpdateTimelimitRuleAction |
|
||||
SerializedUpdateUserFlagsAction
|
||||
|
||||
export const parseParentAction = (action: SerializedParentAction): ParentAction => {
|
||||
if (action.type === 'ADD_CATEGORY_APPS') {
|
||||
@@ -176,6 +178,8 @@ export const parseParentAction = (action: SerializedParentAction): ParentAction
|
||||
return UpdateParentNotificationFlagsAction.parse(action)
|
||||
} else if (action.type === 'UPDATE_TIMELIMIT_RULE') {
|
||||
return UpdateTimelimitRuleAction.parse(action)
|
||||
} else if (action.type === 'UPDATE_USER_FLAGS') {
|
||||
return UpdateUserFlagsAction.parse(action)
|
||||
} else {
|
||||
throw new Error('illegal state: invalid type for action at parseParentAction')
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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 { UserFlags } from '../model/userflags'
|
||||
import { assertIdWithinFamily } from '../util/token'
|
||||
import { ParentAction } from './basetypes'
|
||||
|
||||
export class UpdateUserFlagsAction extends ParentAction {
|
||||
readonly userId: string
|
||||
readonly modifiedBits: number
|
||||
readonly newValues: number
|
||||
|
||||
constructor ({ userId, modifiedBits, newValues }: {
|
||||
userId: string
|
||||
modifiedBits: number
|
||||
newValues: number
|
||||
}) {
|
||||
super()
|
||||
|
||||
assertIdWithinFamily(userId)
|
||||
|
||||
if ((!Number.isSafeInteger(modifiedBits)) || (!Number.isSafeInteger(newValues))) {
|
||||
throw new Error('flags must be an integer')
|
||||
}
|
||||
|
||||
if ((modifiedBits | UserFlags.ALL_FLAGS) !== UserFlags.ALL_FLAGS || (modifiedBits | newValues) !== modifiedBits) {
|
||||
throw new Error('flags are out of the valid range')
|
||||
}
|
||||
|
||||
this.userId = userId
|
||||
this.modifiedBits = modifiedBits
|
||||
this.newValues = newValues
|
||||
}
|
||||
|
||||
serialize = (): SerializedUpdateUserFlagsAction => ({
|
||||
type: 'UPDATE_USER_FLAGS',
|
||||
userId: this.userId,
|
||||
modified: this.modifiedBits,
|
||||
values: this.newValues
|
||||
})
|
||||
|
||||
static parse = ({ userId, modified, values }: SerializedUpdateUserFlagsAction) => (
|
||||
new UpdateUserFlagsAction({
|
||||
userId,
|
||||
modifiedBits: modified,
|
||||
newValues: values
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
export interface SerializedUpdateUserFlagsAction {
|
||||
type: 'UPDATE_USER_FLAGS'
|
||||
userId: string
|
||||
modified: number
|
||||
values: number
|
||||
}
|
||||
@@ -1125,6 +1125,33 @@ const definitions = {
|
||||
"type"
|
||||
]
|
||||
},
|
||||
"SerializedUpdateUserFlagsAction": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"UPDATE_USER_FLAGS"
|
||||
]
|
||||
},
|
||||
"userId": {
|
||||
"type": "string"
|
||||
},
|
||||
"modified": {
|
||||
"type": "number"
|
||||
},
|
||||
"values": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"modified",
|
||||
"type",
|
||||
"userId",
|
||||
"values"
|
||||
]
|
||||
},
|
||||
"SerializedAddInstalledAppsAction": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2049,6 +2076,9 @@ const definitions = {
|
||||
},
|
||||
"blockedTimes": {
|
||||
"type": "string"
|
||||
},
|
||||
"flags": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@@ -2057,6 +2087,7 @@ const definitions = {
|
||||
"categoryForNotAssignedApps",
|
||||
"currentDevice",
|
||||
"disableLimitsUntil",
|
||||
"flags",
|
||||
"id",
|
||||
"mail",
|
||||
"mailNotificationFlags",
|
||||
@@ -2384,6 +2415,9 @@ export const isSerializedParentAction: (value: object) => value is SerializedPar
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/SerializedUpdateTimelimitRuleAction"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/SerializedUpdateUserFlagsAction"
|
||||
}
|
||||
],
|
||||
"definitions": definitions,
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 { QueryInterface, Sequelize, Transaction } from 'sequelize'
|
||||
import { attributesVersion6 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', 'flags', {
|
||||
...userAttributes.flags
|
||||
}, {
|
||||
transaction
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
|
||||
await sequelize.transaction({
|
||||
type: Transaction.TYPES.EXCLUSIVE
|
||||
}, async (transaction) => {
|
||||
await queryInterface.removeColumn('Users', 'flags', { transaction })
|
||||
})
|
||||
}
|
||||
+21
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { UserFlags } from '../model/userflags'
|
||||
import { serializedBitmaskRegex } from '../util/bitmask'
|
||||
import { optionalPasswordRegex, optionalSaltRegex } from '../util/password'
|
||||
import { booleanColumn, createEnumColumn, familyIdColumn, idWithinFamilyColumn, labelColumn, optionalIdWithinFamilyColumn, timestampColumn } from './columns'
|
||||
@@ -54,8 +55,12 @@ export interface UserAttributesVersion5 {
|
||||
blockedTimes: string
|
||||
}
|
||||
|
||||
export interface UserAttributesVersion6 {
|
||||
flags: string
|
||||
}
|
||||
|
||||
export type UserAttributes = UserAttributesVersion1 & UserAttributesVersion2 &
|
||||
UserAttributesVersion3 & UserAttributesVersion4 & UserAttributesVersion5
|
||||
UserAttributesVersion3 & UserAttributesVersion4 & UserAttributesVersion5 & UserAttributesVersion6
|
||||
|
||||
export type UserModel = Sequelize.Model & UserAttributes
|
||||
export type UserModelStatic = typeof Sequelize.Model & {
|
||||
@@ -139,12 +144,25 @@ export const attributesVersion5: SequelizeAttributes<UserAttributesVersion5> = {
|
||||
}
|
||||
}
|
||||
|
||||
export const attributesVersion6: SequelizeAttributes<UserAttributesVersion6> = {
|
||||
flags: {
|
||||
type: Sequelize.BIGINT,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
validate: {
|
||||
min: 0,
|
||||
max: UserFlags.ALL_FLAGS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const attributes: SequelizeAttributes<UserAttributes> = {
|
||||
...attributesVersion1,
|
||||
...attributesVersion2,
|
||||
...attributesVersion3,
|
||||
...attributesVersion4,
|
||||
...attributesVersion5
|
||||
...attributesVersion5,
|
||||
...attributesVersion6
|
||||
}
|
||||
|
||||
export const createUserModel = (sequelize: Sequelize.Sequelize): UserModelStatic => sequelize.define('User', attributes) as UserModelStatic
|
||||
|
||||
@@ -82,7 +82,8 @@ export const createFamily = async ({ database, mailAuthToken, firstParentDevice,
|
||||
categoryForNotAssignedApps: '',
|
||||
relaxPrimaryDeviceRule: false,
|
||||
mailNotificationFlags: 1, // enable warning notifications
|
||||
blockedTimes: ''
|
||||
blockedTimes: '',
|
||||
flags: '0'
|
||||
}, { transaction })
|
||||
|
||||
// add parent device
|
||||
|
||||
@@ -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
|
||||
@@ -37,7 +37,8 @@ export async function dispatchAddUser ({ action, cache }: {
|
||||
categoryForNotAssignedApps: '',
|
||||
relaxPrimaryDeviceRule: false,
|
||||
mailNotificationFlags: 0,
|
||||
blockedTimes: ''
|
||||
blockedTimes: '',
|
||||
flags: '0'
|
||||
}, { transaction: cache.transaction })
|
||||
|
||||
cache.invalidiateUserList = true
|
||||
|
||||
@@ -55,7 +55,8 @@ import {
|
||||
UpdateNetworkTimeVerificationAction,
|
||||
UpdateParentBlockedTimesAction,
|
||||
UpdateParentNotificationFlagsAction,
|
||||
UpdateTimelimitRuleAction
|
||||
UpdateTimelimitRuleAction,
|
||||
UpdateUserFlagsAction
|
||||
} from '../../../../action'
|
||||
import { Cache } from '../cache'
|
||||
import { dispatchAddCategoryApps } from './addcategoryapps'
|
||||
@@ -97,6 +98,7 @@ import { dispatchUpdateNetworkTimeVerification } from './updatenetworktimeverifi
|
||||
import { dispatchUpdateParentBlockedTimes } from './updateparentblockedtimes'
|
||||
import { dispatchUpdateParentNotificationFlags } from './updateparentnotificationflags'
|
||||
import { dispatchUpdateTimelimitRule } from './updatetimelimitrule'
|
||||
import { dispatchUpdateUserFlagsAction } from './updateuserflags'
|
||||
|
||||
export const dispatchParentAction = async ({ action, cache, parentUserId, sourceDeviceId }: {
|
||||
action: ParentAction
|
||||
@@ -182,6 +184,8 @@ export const dispatchParentAction = async ({ action, cache, parentUserId, source
|
||||
await dispatchResetParentBlockedTimes({ action, cache })
|
||||
} else if (action instanceof UpdateParentBlockedTimesAction) {
|
||||
await dispatchUpdateParentBlockedTimes({ action, cache })
|
||||
} else if (action instanceof UpdateUserFlagsAction) {
|
||||
await dispatchUpdateUserFlagsAction({ action, cache })
|
||||
} else {
|
||||
throw new Error('unsupported action type')
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { UpdateUserFlagsAction } from '../../../../action'
|
||||
import { Cache } from '../cache'
|
||||
|
||||
export async function dispatchUpdateUserFlagsAction ({ action, cache }: {
|
||||
action: UpdateUserFlagsAction
|
||||
cache: Cache
|
||||
}) {
|
||||
const userEntry = await cache.database.user.findOne({
|
||||
where: {
|
||||
familyId: cache.familyId,
|
||||
userId: action.userId
|
||||
},
|
||||
transaction: cache.transaction
|
||||
})
|
||||
|
||||
if (!userEntry) {
|
||||
throw new Error('user not found')
|
||||
}
|
||||
|
||||
const oldFlags = parseInt(userEntry.flags, 10)
|
||||
|
||||
if (!Number.isSafeInteger(oldFlags)) {
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
const newFlags = (oldFlags & ~action.modifiedBits) | action.newValues
|
||||
|
||||
userEntry.flags = newFlags.toString(10)
|
||||
|
||||
await userEntry.save({ transaction: cache.transaction })
|
||||
|
||||
cache.invalidiateUserList = true
|
||||
}
|
||||
@@ -125,7 +125,8 @@ export const generateServerDataStatus = async ({ database, clientStatus, familyI
|
||||
'categoryForNotAssignedApps',
|
||||
'relaxPrimaryDeviceRule',
|
||||
'mailNotificationFlags',
|
||||
'blockedTimes'
|
||||
'blockedTimes',
|
||||
'flags'
|
||||
],
|
||||
transaction
|
||||
})).map((item) => ({
|
||||
@@ -141,7 +142,8 @@ export const generateServerDataStatus = async ({ database, clientStatus, familyI
|
||||
categoryForNotAssignedApps: item.categoryForNotAssignedApps,
|
||||
relaxPrimaryDeviceRule: item.relaxPrimaryDeviceRule,
|
||||
mailNotificationFlags: item.mailNotificationFlags,
|
||||
blockedTimes: item.blockedTimes
|
||||
blockedTimes: item.blockedTimes,
|
||||
flags: item.flags
|
||||
}))
|
||||
|
||||
result.users = {
|
||||
@@ -159,7 +161,8 @@ export const generateServerDataStatus = async ({ database, clientStatus, familyI
|
||||
categoryForNotAssignedApps: item.categoryForNotAssignedApps,
|
||||
relaxPrimaryDevice: item.relaxPrimaryDeviceRule,
|
||||
mailNotificationFlags: item.mailNotificationFlags,
|
||||
blockedTimes: item.blockedTimes
|
||||
blockedTimes: item.blockedTimes,
|
||||
flags: parseInt(item.flags, 10)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
export const UserFlags = {
|
||||
RESTRICT_VIEWING_TO_PARENTS: 1,
|
||||
ALL_FLAGS: 1
|
||||
}
|
||||
@@ -58,6 +58,7 @@ export interface ServerUserEntry {
|
||||
relaxPrimaryDevice: boolean
|
||||
mailNotificationFlags: number
|
||||
blockedTimes: string
|
||||
flags: number
|
||||
}
|
||||
|
||||
export interface ServerDeviceData {
|
||||
|
||||
Reference in New Issue
Block a user