mirror of
https://codeberg.org/timelimit/timelimit-server.git
synced 2026-08-31 19:03:45 +02:00
Compare commits
2
Commits
2020-09-02
...
2020-09-09
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8cc9fd5e6 | ||
|
|
6518159069 |
@@ -56,6 +56,7 @@ export interface Database {
|
||||
user: UserModelStatic
|
||||
userLimitLoginCategory: UserLimitLoginCategoryModelStatic
|
||||
transaction: <T> (autoCallback: (t: Sequelize.Transaction) => Promise<T>) => Promise<T>
|
||||
dialect: string
|
||||
}
|
||||
|
||||
const createDatabase = (sequelize: Sequelize.Sequelize): Database => ({
|
||||
@@ -79,7 +80,8 @@ const createDatabase = (sequelize: Sequelize.Sequelize): Database => ({
|
||||
userLimitLoginCategory: createUserLimitLoginCategoryModel(sequelize),
|
||||
transaction: <T> (autoCallback: (transaction: Sequelize.Transaction) => Promise<T>) => (sequelize.transaction({
|
||||
isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED
|
||||
}, autoCallback) as any) as Promise<T>
|
||||
}, autoCallback) as any) as Promise<T>,
|
||||
dialect: sequelize.getDialect()
|
||||
})
|
||||
|
||||
export const sequelize = new Sequelize.Sequelize(process.env.DATABASE_URL || 'sqlite://test.db', {
|
||||
|
||||
@@ -64,9 +64,12 @@ export async function dispatchAddUsedTime ({ deviceId, action, cache }: {
|
||||
currentExtraTime: number
|
||||
}) => {
|
||||
if (action.timeToAdd !== 0) {
|
||||
const maxOperator = cache.database.dialect === 'sqlite' ? 'MAX' : 'GREATEST'
|
||||
const minOperator = cache.database.dialect === 'sqlite' ? 'MIN' : 'LEAST'
|
||||
|
||||
// try to update first
|
||||
const [updatedRows] = await cache.database.usedTime.update({
|
||||
usedTime: Sequelize.literal(`MAX(0, MIN(usedTime + ${action.timeToAdd}, ${dayLengthInMs}))`) as any,
|
||||
usedTime: Sequelize.literal(`${maxOperator}(0, ${minOperator}(usedTime + ${action.timeToAdd}, ${dayLengthInMs}))`) as any,
|
||||
lastUpdate: roundedTimestamp
|
||||
}, {
|
||||
where: {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { AddUsedTimeActionVersion2 } from '../../../../action'
|
||||
import { EventHandler } from '../../../../monitoring/eventhandler'
|
||||
import { MinuteOfDay } from '../../../../util/minuteofday'
|
||||
import { Cache } from '../cache'
|
||||
import { getRoundedTimestamp as getRoundedTimestampForUsedTime } from './addusedtime'
|
||||
@@ -27,14 +28,34 @@ export const getRoundedTimestampForSessionDuration = () => {
|
||||
return now - (now % (1000 * 60 * 60 * 12 /* 12 hours */))
|
||||
}
|
||||
|
||||
export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache }: {
|
||||
export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, eventHandler }: {
|
||||
deviceId: string
|
||||
action: AddUsedTimeActionVersion2
|
||||
cache: Cache
|
||||
eventHandler: EventHandler
|
||||
}) {
|
||||
const deviceEntryUnsafe = await cache.database.device.findOne({
|
||||
where: {
|
||||
familyId: cache.familyId,
|
||||
deviceId: deviceId
|
||||
},
|
||||
attributes: ['currentUserId'],
|
||||
transaction: cache.transaction
|
||||
})
|
||||
|
||||
if (!deviceEntryUnsafe) {
|
||||
throw new Error('source device not found')
|
||||
}
|
||||
|
||||
const deviceEntry = {
|
||||
currentUserId: deviceEntryUnsafe.currentUserId
|
||||
}
|
||||
|
||||
const roundedTimestampForUsedTime = getRoundedTimestampForUsedTime().toString(10)
|
||||
const roundedTimestampForSessionDuration = getRoundedTimestampForSessionDuration().toString(10)
|
||||
|
||||
let addUsedTimeForADifferentUserThanTheCurrentUserOfTheDevice = false
|
||||
|
||||
for (let i = 0; i < action.items.length; i++) {
|
||||
const item = action.items[i]
|
||||
|
||||
@@ -62,14 +83,21 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache }:
|
||||
extraTimeInMillis: categoryEntryUnsafe.extraTimeInMillis
|
||||
}
|
||||
|
||||
if (categoryEntry.childId !== deviceEntry.currentUserId) {
|
||||
addUsedTimeForADifferentUserThanTheCurrentUserOfTheDevice = true
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:no-inner-declarations
|
||||
async function handle (start: number, end: number) {
|
||||
const lengthInMinutes = (end - start) + 1
|
||||
const lengthInMs = lengthInMinutes * 1000 * 60
|
||||
|
||||
const maxOperator = cache.database.dialect === 'sqlite' ? 'MAX' : 'GREATEST'
|
||||
const minOperator = cache.database.dialect === 'sqlite' ? 'MIN' : 'LEAST'
|
||||
|
||||
// try to update first
|
||||
const [updatedRows] = await cache.database.usedTime.update({
|
||||
usedTime: Sequelize.literal(`MAX(0, MIN(usedTime + ${item.timeToAdd}, ${lengthInMs}))`) as any,
|
||||
usedTime: Sequelize.literal(`${maxOperator}(0, ${minOperator}(usedTime + ${item.timeToAdd}, ${lengthInMs}))`) as any,
|
||||
lastUpdate: roundedTimestampForUsedTime
|
||||
}, {
|
||||
where: {
|
||||
@@ -171,5 +199,20 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache }:
|
||||
|
||||
cache.categoriesWithModifiedBaseData.push(item.categoryId)
|
||||
}
|
||||
|
||||
if (addUsedTimeForADifferentUserThanTheCurrentUserOfTheDevice) {
|
||||
// there are two possible causes for this:
|
||||
// - a device user was changed remotely while it was used by this user for
|
||||
// limited Apps (rarely)
|
||||
// - a parent added time manually (rarely)
|
||||
//
|
||||
// For the second case, it's important to sync this change.
|
||||
// As it should occur not too often, a full sync should be no problem.
|
||||
// To keep an eye on it, it is counted.
|
||||
|
||||
cache.areChangesImportant = true
|
||||
|
||||
eventHandler.countEvent('add used time for a different user than the current user of the device')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
UpdateAppActivitiesAction,
|
||||
UpdateDeviceStatusAction
|
||||
} from '../../../../action'
|
||||
import { EventHandler } from '../../../../monitoring/eventhandler'
|
||||
import { Cache } from '../cache'
|
||||
import { dispatchAddInstalledApps } from './addinstalledapps'
|
||||
import { dispatchAddUsedTime } from './addusedtime'
|
||||
@@ -36,17 +37,18 @@ import { dispatchTriedDisablingDeviceAdmin } from './trieddisablingdeviceadmin'
|
||||
import { dispatchUpdateAppActivities } from './updateappactivities'
|
||||
import { dispatchUpdateDeviceStatus } from './updatedevicestatus'
|
||||
|
||||
export const dispatchAppLogicAction = async ({ action, deviceId, cache }: {
|
||||
export const dispatchAppLogicAction = async ({ action, deviceId, cache, eventHandler }: {
|
||||
action: AppLogicAction
|
||||
deviceId: string
|
||||
cache: Cache
|
||||
eventHandler: EventHandler
|
||||
}) => {
|
||||
if (action instanceof AddInstalledAppsAction) {
|
||||
await dispatchAddInstalledApps({ deviceId, action, cache })
|
||||
} else if (action instanceof AddUsedTimeAction) {
|
||||
await dispatchAddUsedTime({ deviceId, action, cache })
|
||||
} else if (action instanceof AddUsedTimeActionVersion2) {
|
||||
await dispatchAddUsedTimeVersion2({ deviceId, action, cache })
|
||||
await dispatchAddUsedTimeVersion2({ deviceId, action, cache, eventHandler })
|
||||
} else if (action instanceof RemoveInstalledAppsAction) {
|
||||
await dispatchRemoveInstalledApps({ deviceId, action, cache })
|
||||
} else if (action instanceof SignOutAtDeviceAction) {
|
||||
|
||||
@@ -183,7 +183,8 @@ export const applyActionsFromDevice = async ({ database, request, websocket, con
|
||||
await dispatchAppLogicAction({
|
||||
action: parsedAction,
|
||||
cache,
|
||||
deviceId: deviceEntry.deviceId
|
||||
deviceId: deviceEntry.deviceId,
|
||||
eventHandler
|
||||
})
|
||||
} catch (ex) {
|
||||
eventHandler.countEvent('applyActionsFromDevice actionWithError:' + parsedSerializedAction.type)
|
||||
|
||||
Reference in New Issue
Block a user