Add new actions for activity level blocking

This commit is contained in:
Jonas L 2019-04-15 00:00:00 +00:00
parent 7fb3f9fb5b
commit 0af0ff961e
11 changed files with 408 additions and 0 deletions

View file

@ -49,12 +49,14 @@ export { SetUserDisableLimitsUntilAction } from './setuserdisablelimitsuntil'
export { SetUserTimezoneAction } from './setusertimezone'
export { SignOutAtDeviceAction } from './signoutatdevice'
export { TriedDisablingDeviceAdminAction } from './trieddisablingdeviceadmin'
export { UpdateAppActivitiesAction } from './updateappactivities'
export { UpdateCategoryBlockAllNotificationsAction } from './updatecategoryblockallnotifications'
export { UpdateCategoryBlockedTimesAction } from './updatecategoryblockedtimes'
export { UpdateCategoryTemporarilyBlockedAction } from './updatecategorytemporarilyblocked'
export { UpdateCategoryTitleAction } from './updatecategorytitle'
export { UpdateDeviceNameAction } from './updatedevicename'
export { UpdateDeviceStatusAction } from './updatedevicestatus'
export { UpdateEnableActivityLevelBlockingAction } from './updateenableactivitylevelblocking'
export { UpdateNetworkTimeVerificationAction } from './updatenetworktimeverification'
export { UpdateParentNotificationFlagsAction } from './updateparentnotificationflags'
export { UpdateTimelimitRuleAction } from './updatetimelimitrule'

View file

@ -21,6 +21,7 @@ import { AppLogicAction } from '../basetypes'
import { RemoveInstalledAppsAction, SerializedRemoveInstalledAppsAction } from '../removeinstalledapps'
import { SerializedSignOutAtDeviceAction, SignOutAtDeviceAction } from '../signoutatdevice'
import { SerialiezdTriedDisablingDeviceAdminAction, TriedDisablingDeviceAdminAction } from '../trieddisablingdeviceadmin'
import { SerializedUpdateAppActivitiesAction, UpdateAppActivitiesAction } from '../updateappactivities'
import { SerializedUpdateDeviceStatusAction, UpdateDeviceStatusAction } from '../updatedevicestatus'
export type SerializedAppLogicAction =
@ -29,6 +30,7 @@ export type SerializedAppLogicAction =
SerializedRemoveInstalledAppsAction |
SerializedSignOutAtDeviceAction |
SerialiezdTriedDisablingDeviceAdminAction |
SerializedUpdateAppActivitiesAction |
SerializedUpdateDeviceStatusAction
export const parseAppLogicAction = (serialized: SerializedAppLogicAction): AppLogicAction => {
@ -42,6 +44,8 @@ export const parseAppLogicAction = (serialized: SerializedAppLogicAction): AppLo
return SignOutAtDeviceAction.parse(serialized)
} else if (serialized.type === 'TRIED_DISABLING_DEVICE_ADMIN') {
return new TriedDisablingDeviceAdminAction()
} else if (serialized.type === 'UPDATE_APP_ACTIVITIES') {
return UpdateAppActivitiesAction.parse(serialized)
} else if (serialized.type === 'UPDATE_DEVICE_STATUS') {
return UpdateDeviceStatusAction.parse(serialized)
} else {

View file

@ -46,6 +46,7 @@ import { SerializedUpdateCategoryBlockedTimesAction, UpdateCategoryBlockedTimesA
import { SerializedUpdateCategoryTemporarilyBlockedAction, UpdateCategoryTemporarilyBlockedAction } from '../updatecategorytemporarilyblocked'
import { SerializedUpdateCategoryTitleAction, UpdateCategoryTitleAction } from '../updatecategorytitle'
import { SerializedUpdateDeviceNameAction, UpdateDeviceNameAction } from '../updatedevicename'
import { SerializedUpdateEnableActivityLevelBlockingAction, UpdateEnableActivityLevelBlockingAction } from '../updateenableactivitylevelblocking'
import { SerialiizedUpdateNetworkTimeVerificationAction, UpdateNetworkTimeVerificationAction } from '../updatenetworktimeverification'
import { SerializedUpdateParentNotificationFlagsAction, UpdateParentNotificationFlagsAction } from '../updateparentnotificationflags'
import { SerializedUpdateTimelimitRuleAction, UpdateTimelimitRuleAction } from '../updatetimelimitrule'
@ -81,6 +82,7 @@ export type SerializedParentAction =
SerializedUpdateCategoryTemporarilyBlockedAction |
SerializedUpdateCategoryTitleAction |
SerializedUpdateDeviceNameAction |
SerializedUpdateEnableActivityLevelBlockingAction |
SerialiizedUpdateNetworkTimeVerificationAction |
SerializedUpdateParentNotificationFlagsAction |
SerializedUpdateTimelimitRuleAction
@ -146,6 +148,8 @@ export const parseParentAction = (action: SerializedParentAction): ParentAction
return UpdateCategoryTemporarilyBlockedAction.parse(action)
} else if (action.type === 'UPDATE_DEVICE_NAME') {
return UpdateDeviceNameAction.parse(action)
} else if (action.type === 'UPDATE_ENABLE_ACTIVITY_LEVEL_BLOCKING') {
return UpdateEnableActivityLevelBlockingAction.parse(action)
} else if (action.type === 'UPDATE_NETWORK_TIME_VERIFICATION') {
return UpdateNetworkTimeVerificationAction.parse(action)
} else if (action.type === 'UPDATE_PARENT_NOTIFICATION_FLAGS') {

View file

@ -0,0 +1,61 @@
/*
* 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 { AppActivityItem, RemovedAppActivityItem, SerializedAppActivityItem, SerializedRemovedAppActivityItem } from '../model/appactivity'
import { assertNonEmptyListWithoutDuplicates } from '../util/list'
import { AppLogicAction } from './basetypes'
export class UpdateAppActivitiesAction extends AppLogicAction {
readonly removed: Array<RemovedAppActivityItem>
readonly updatedOrAdded: Array<AppActivityItem>
constructor ({ removed, updatedOrAdded }: {
removed: Array<RemovedAppActivityItem>
updatedOrAdded: Array<AppActivityItem>
}) {
super()
assertNonEmptyListWithoutDuplicates(removed.map((item) => item.packageName + ':' + item.activityName))
assertNonEmptyListWithoutDuplicates(updatedOrAdded.map((item) => item.packageName + ':' + item.activityName))
if (removed.length === 0 && updatedOrAdded.length === 0) {
throw new Error('UpdateAppActivitiesAction is empty')
}
this.removed = removed
this.updatedOrAdded = updatedOrAdded
}
serialize = (): SerializedUpdateAppActivitiesAction => ({
type: 'UPDATE_APP_ACTIVITIES',
removed: this.removed.map((item) => item.serialize()),
updatedOrAdded: this.updatedOrAdded.map((item) => item.serialize())
})
static parse = ({ removed, updatedOrAdded }: SerializedUpdateAppActivitiesAction) => (
new UpdateAppActivitiesAction({
removed: removed.map((item) => RemovedAppActivityItem.parse(item)),
updatedOrAdded: updatedOrAdded.map((item) => AppActivityItem.parse(item))
})
)
}
export interface SerializedUpdateAppActivitiesAction {
type: 'UPDATE_APP_ACTIVITIES'
removed: Array<SerializedRemovedAppActivityItem>
updatedOrAdded: Array<SerializedAppActivityItem>
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
import { assertIdWithinFamily } from '../util/token'
import { ParentAction } from './basetypes'
export class UpdateEnableActivityLevelBlockingAction extends ParentAction {
readonly deviceId: string
readonly enable: boolean
constructor ({ deviceId, enable }: {deviceId: string, enable: boolean}) {
super()
assertIdWithinFamily(deviceId)
this.deviceId = deviceId
this.enable = enable
}
serialize = (): SerializedUpdateEnableActivityLevelBlockingAction => ({
type: 'UPDATE_ENABLE_ACTIVITY_LEVEL_BLOCKING',
deviceId: this.deviceId,
enable: this.enable
})
static parse = ({ deviceId, enable }: SerializedUpdateEnableActivityLevelBlockingAction) => (
new UpdateEnableActivityLevelBlockingAction({ deviceId, enable })
)
}
export interface SerializedUpdateEnableActivityLevelBlockingAction {
type: 'UPDATE_ENABLE_ACTIVITY_LEVEL_BLOCKING'
deviceId: string
enable: boolean
}

View file

@ -861,6 +861,29 @@ const definitions = {
"type"
]
},
"SerializedUpdateEnableActivityLevelBlockingAction": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"UPDATE_ENABLE_ACTIVITY_LEVEL_BLOCKING"
]
},
"deviceId": {
"type": "string"
},
"enable": {
"type": "boolean"
}
},
"additionalProperties": false,
"required": [
"deviceId",
"enable",
"type"
]
},
"SerialiizedUpdateNetworkTimeVerificationAction": {
"type": "object",
"properties": {
@ -1084,6 +1107,74 @@ const definitions = {
"type"
]
},
"SerializedUpdateAppActivitiesAction": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"UPDATE_APP_ACTIVITIES"
]
},
"removed": {
"type": "array",
"items": {
"type": "array",
"items": [
{
"type": "string"
},
{
"type": "string"
}
],
"minItems": 2,
"additionalItems": {
"anyOf": [
{
"type": "string"
},
{
"type": "string"
}
]
}
}
},
"updatedOrAdded": {
"type": "array",
"items": {
"$ref": "#/definitions/SerializedAppActivityItem"
}
}
},
"additionalProperties": false,
"required": [
"removed",
"type",
"updatedOrAdded"
]
},
"SerializedAppActivityItem": {
"type": "object",
"properties": {
"p": {
"type": "string"
},
"c": {
"type": "string"
},
"t": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"c",
"p",
"t"
]
},
"SerializedUpdateDeviceStatusAction": {
"type": "object",
"properties": {
@ -1479,6 +1570,9 @@ export const isSerializedParentAction: (value: object) => value is SerializedPar
{
"$ref": "#/definitions/SerializedUpdateDeviceNameAction"
},
{
"$ref": "#/definitions/SerializedUpdateEnableActivityLevelBlockingAction"
},
{
"$ref": "#/definitions/SerialiizedUpdateNetworkTimeVerificationAction"
},
@ -1509,6 +1603,9 @@ export const isSerializedAppLogicAction: (value: object) => value is SerializedA
{
"$ref": "#/definitions/SerialiezdTriedDisablingDeviceAdminAction"
},
{
"$ref": "#/definitions/SerializedUpdateAppActivitiesAction"
},
{
"$ref": "#/definitions/SerializedUpdateDeviceStatusAction"
}

View file

@ -22,6 +22,7 @@ import {
RemoveInstalledAppsAction,
SignOutAtDeviceAction,
TriedDisablingDeviceAdminAction,
UpdateAppActivitiesAction,
UpdateDeviceStatusAction
} from '../../../../action'
import { Cache } from '../cache'
@ -30,6 +31,7 @@ import { dispatchAddUsedTime } from './addusedtime'
import { dispatchRemoveInstalledApps } from './removeinstalledapps'
import { dispatchSignOutAtDevice } from './signoutatdevice'
import { dispatchTriedDisablingDeviceAdmin } from './trieddisablingdeviceadmin'
import { dispatchUpdateAppActivities } from './updateappactivities'
import { dispatchUpdateDeviceStatus } from './updatedevicestatus'
export const dispatchAppLogicAction = async ({ action, deviceId, cache }: {
@ -47,6 +49,8 @@ export const dispatchAppLogicAction = async ({ action, deviceId, cache }: {
await dispatchSignOutAtDevice({ deviceId, action, cache })
} else if (action instanceof UpdateDeviceStatusAction) {
await dispatchUpdateDeviceStatus({ deviceId, action, cache })
} else if (action instanceof UpdateAppActivitiesAction) {
await dispatchUpdateAppActivities({ deviceId, action, cache })
} else if (action instanceof TriedDisablingDeviceAdminAction) {
await dispatchTriedDisablingDeviceAdmin({ deviceId, action, cache })
} else {

View file

@ -0,0 +1,72 @@
/*
* 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 * as Sequelize from 'sequelize'
import { UpdateAppActivitiesAction } from '../../../../action'
import { AppActivityAttributes } from '../../../../database/appactivity'
import { Cache } from '../cache'
export async function dispatchUpdateAppActivities ({ deviceId, action, cache }: {
deviceId: string
action: UpdateAppActivitiesAction
cache: Cache
}) {
if (action.updatedOrAdded.length > 0) {
await cache.database.appActivity.destroy({
where: {
familyId: cache.familyId,
deviceId,
[Sequelize.Op.or]: (
action.updatedOrAdded.map((item) => ({
packageName: item.packageName,
activityName: item.activityName
}))
)
},
transaction: cache.transaction
})
await cache.database.appActivity.bulkCreate(
action.updatedOrAdded.map((item): AppActivityAttributes => ({
familyId: cache.familyId,
deviceId,
packageName: item.packageName,
activityName: item.activityName,
title: item.title
})),
{ transaction: cache.transaction }
)
}
if (action.removed.length > 0) {
await cache.database.appActivity.destroy({
where: {
familyId: cache.familyId,
deviceId,
[Sequelize.Op.or]: (
action.removed.map((item) => ({
packageName: item.packageName,
activityName: item.activityName
}))
)
},
transaction: cache.transaction
})
}
cache.devicesWithModifiedInstalledApps.push(deviceId)
}

View file

@ -47,6 +47,7 @@ import {
UpdateCategoryTemporarilyBlockedAction,
UpdateCategoryTitleAction,
UpdateDeviceNameAction,
UpdateEnableActivityLevelBlockingAction,
UpdateNetworkTimeVerificationAction,
UpdateParentNotificationFlagsAction,
UpdateTimelimitRuleAction
@ -82,6 +83,7 @@ import { dispatchUpdateCategoryBlockedTimes } from './updatecategoryblockedtimes
import { dispatchUpdateCategoryTemporarilyBlocked } from './updatecategorytemporarilyblocked'
import { dispatchUpdateCategoryTitle } from './updatecategorytitle'
import { dispatchUpdateDeviceName } from './updatedevicename'
import { dispatchUpdateEnableActivityLevelBlocking } from './updateenableactivitylevelblocking'
import { dispatchUpdateNetworkTimeVerification } from './updatenetworktimeverification'
import { dispatchUpdateParentNotificationFlags } from './updateparentnotificationflags'
import { dispatchUpdateTimelimitRule } from './updatetimelimitrule'
@ -144,6 +146,8 @@ export const dispatchParentAction = async ({ action, cache, parentUserId, source
await dispatchDeleteTimeLimitRule({ action, cache })
} else if (action instanceof UpdateDeviceNameAction) {
await dispatchUpdateDeviceName({ action, cache })
} else if (action instanceof UpdateEnableActivityLevelBlockingAction) {
await dispatchUpdateEnableActivityLevelBlocking({ action, cache })
} else if (action instanceof UpdateNetworkTimeVerificationAction) {
await dispatchUpdateNetworkTimeVerification({ action, cache })
} else if (action instanceof UpdateParentNotificationFlagsAction) {

View file

@ -0,0 +1,41 @@
/*
* 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 { UpdateEnableActivityLevelBlockingAction } from '../../../../action'
import { Cache } from '../cache'
export async function dispatchUpdateEnableActivityLevelBlocking ({ action, cache }: {
action: UpdateEnableActivityLevelBlockingAction
cache: Cache
}) {
const [affectedRows] = await cache.database.device.update({
activityLevelBlocking: action.enable
}, {
transaction: cache.transaction,
where: {
familyId: cache.familyId,
deviceId: action.deviceId
}
})
if (affectedRows === 0) {
throw new Error('did not find device to update activity level blocking')
}
cache.invalidiateDeviceList = true
cache.areChangesImportant = true
}

70
src/model/appactivity.ts Normal file
View file

@ -0,0 +1,70 @@
export interface SerializedAppActivityItem {
p: string
c: string
t: string
}
export class AppActivityItem {
readonly packageName: string
readonly activityName: string
readonly title: string
constructor ({ packageName, activityName, title }: {
packageName: string
activityName: string
title: string
}) {
if ((!packageName) || (!activityName)) {
throw new Error('incomplete app activity')
}
this.packageName = packageName
this.activityName = activityName
this.title = title
}
static parse = ({ p, c, t }: SerializedAppActivityItem) => (
new AppActivityItem({
packageName: p,
activityName: c,
title: t
})
)
serialize = (): SerializedAppActivityItem => ({
p: this.packageName,
c: this.activityName,
t: this.title
})
}
export type SerializedRemovedAppActivityItem = [string, string]
export class RemovedAppActivityItem {
readonly packageName: string
readonly activityName: string
constructor ({ packageName, activityName }: {
packageName: string
activityName: string
}) {
if ((!packageName) || (!activityName)) {
throw new Error('incomplete app activity')
}
this.packageName = packageName
this.activityName = activityName
}
static parse = (data: SerializedRemovedAppActivityItem) => (
new RemovedAppActivityItem({
packageName: data[0],
activityName: data[1]
})
)
serialize = (): SerializedRemovedAppActivityItem => ([
this.packageName,
this.activityName
])
}