Send ClientDataStatus after registering new device

This commit is contained in:
Jonas Lochmann 2022-11-28 01:00:00 +01:00
parent 41758c32f2
commit ae044c19d6
No known key found for this signature in database
GPG key ID: 8B8C9AEE10FA5B36
20 changed files with 242 additions and 33 deletions

View file

@ -16,8 +16,7 @@ On a invalid request body: HTTP status code 400 Bad request
On a invalid add device token: HTTP status code 401 Unauthorized On a invalid add device token: HTTP status code 401 Unauthorized
On success: a JSON object with the properties ``deviceAuthToken`` and ``ownDeviceId``, On success: object with ``deviceAuthToken`` (string), ``ownDeviceId`` (string) and ``data`` (like a ``/sync/pull-status`` response)
both of the type string
## POST /child/update-primary-device ## POST /child/update-primary-device

View file

@ -44,7 +44,7 @@ If the mail auth token is invalid/ expired: HTTP status code 401 Unauthorized
If there is already a user with the mail address of the mail auth token: HTTP status code 409 Conflict If there is already a user with the mail address of the mail auth token: HTTP status code 409 Conflict
On success: object with ``deviceAuthToken`` (string) and ``ownDeviceId`` (string) On success: object with ``deviceAuthToken`` (string), ``ownDeviceId`` (string) and ``data`` (like a ``/sync/pull-status`` response)
## POST /parent/sign-in-into-family ## POST /parent/sign-in-into-family
@ -60,7 +60,7 @@ On a invalid request body: HTTP status code 400 Bad Request
If there is no user with the mail address of the mail auth token: HTTP status code 409 Conflict If there is no user with the mail address of the mail auth token: HTTP status code 409 Conflict
On success: object with ``deviceAuthToken`` (string) and ``ownDeviceId`` (string) On success: object with ``deviceAuthToken`` (string), ``ownDeviceId`` (string) and ``data`` (like a ``/sync/pull-status`` response)
## POST /parent/can-recover-password ## POST /parent/can-recover-password

View file

@ -18,6 +18,9 @@
}, },
"parentName": { "parentName": {
"type": "string" "type": "string"
},
"clientLevel": {
"type": "number"
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View file

@ -9,6 +9,9 @@
}, },
"deviceName": { "deviceName": {
"type": "string" "type": "string"
},
"clientLevel": {
"type": "number"
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View file

@ -9,6 +9,9 @@
}, },
"deviceName": { "deviceName": {
"type": "string" "type": "string"
},
"clientLevel": {
"type": "number"
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View file

@ -0,0 +1,15 @@
# Untitled number in CreateFamilyByMailTokenRequest Schema
```txt
https://timelimit.io/CreateFamilyByMailTokenRequest#/properties/clientLevel
```
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :---------------------------------------------------------------------------------------------------------------- |
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [CreateFamilyByMailTokenRequest.schema.json\*](CreateFamilyByMailTokenRequest.schema.json "open original schema") |
## clientLevel Type
`number`

View file

@ -24,6 +24,7 @@ https://timelimit.io/CreateFamilyByMailTokenRequest
| [deviceName](#devicename) | `string` | Required | cannot be null | [CreateFamilyByMailTokenRequest](createfamilybymailtokenrequest-properties-devicename.md "https://timelimit.io/CreateFamilyByMailTokenRequest#/properties/deviceName") | | [deviceName](#devicename) | `string` | Required | cannot be null | [CreateFamilyByMailTokenRequest](createfamilybymailtokenrequest-properties-devicename.md "https://timelimit.io/CreateFamilyByMailTokenRequest#/properties/deviceName") |
| [timeZone](#timezone) | `string` | Required | cannot be null | [CreateFamilyByMailTokenRequest](createfamilybymailtokenrequest-properties-timezone.md "https://timelimit.io/CreateFamilyByMailTokenRequest#/properties/timeZone") | | [timeZone](#timezone) | `string` | Required | cannot be null | [CreateFamilyByMailTokenRequest](createfamilybymailtokenrequest-properties-timezone.md "https://timelimit.io/CreateFamilyByMailTokenRequest#/properties/timeZone") |
| [parentName](#parentname) | `string` | Required | cannot be null | [CreateFamilyByMailTokenRequest](createfamilybymailtokenrequest-properties-parentname.md "https://timelimit.io/CreateFamilyByMailTokenRequest#/properties/parentName") | | [parentName](#parentname) | `string` | Required | cannot be null | [CreateFamilyByMailTokenRequest](createfamilybymailtokenrequest-properties-parentname.md "https://timelimit.io/CreateFamilyByMailTokenRequest#/properties/parentName") |
| [clientLevel](#clientlevel) | `number` | Optional | cannot be null | [CreateFamilyByMailTokenRequest](createfamilybymailtokenrequest-properties-clientlevel.md "https://timelimit.io/CreateFamilyByMailTokenRequest#/properties/clientLevel") |
## mailAuthToken ## mailAuthToken
@ -133,6 +134,24 @@ https://timelimit.io/CreateFamilyByMailTokenRequest
`string` `string`
## clientLevel
`clientLevel`
* is optional
* Type: `number`
* cannot be null
* defined in: [CreateFamilyByMailTokenRequest](createfamilybymailtokenrequest-properties-clientlevel.md "https://timelimit.io/CreateFamilyByMailTokenRequest#/properties/clientLevel")
### clientLevel Type
`number`
# CreateFamilyByMailTokenRequest Definitions # CreateFamilyByMailTokenRequest Definitions
## Definitions group PlaintextParentPassword ## Definitions group PlaintextParentPassword

View file

@ -0,0 +1,15 @@
# Untitled number in RegisterChildDeviceRequest Schema
```txt
https://timelimit.io/RegisterChildDeviceRequest#/properties/clientLevel
```
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :-------------------------------------------------------------------------------------------------------- |
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [RegisterChildDeviceRequest.schema.json\*](RegisterChildDeviceRequest.schema.json "open original schema") |
## clientLevel Type
`number`

View file

@ -21,6 +21,7 @@ https://timelimit.io/RegisterChildDeviceRequest
| [registerToken](#registertoken) | `string` | Required | cannot be null | [RegisterChildDeviceRequest](registerchilddevicerequest-properties-registertoken.md "https://timelimit.io/RegisterChildDeviceRequest#/properties/registerToken") | | [registerToken](#registertoken) | `string` | Required | cannot be null | [RegisterChildDeviceRequest](registerchilddevicerequest-properties-registertoken.md "https://timelimit.io/RegisterChildDeviceRequest#/properties/registerToken") |
| [childDevice](#childdevice) | `object` | Required | cannot be null | [RegisterChildDeviceRequest](registerchilddevicerequest-definitions-newdeviceinfo.md "https://timelimit.io/RegisterChildDeviceRequest#/properties/childDevice") | | [childDevice](#childdevice) | `object` | Required | cannot be null | [RegisterChildDeviceRequest](registerchilddevicerequest-definitions-newdeviceinfo.md "https://timelimit.io/RegisterChildDeviceRequest#/properties/childDevice") |
| [deviceName](#devicename) | `string` | Required | cannot be null | [RegisterChildDeviceRequest](registerchilddevicerequest-properties-devicename.md "https://timelimit.io/RegisterChildDeviceRequest#/properties/deviceName") | | [deviceName](#devicename) | `string` | Required | cannot be null | [RegisterChildDeviceRequest](registerchilddevicerequest-properties-devicename.md "https://timelimit.io/RegisterChildDeviceRequest#/properties/deviceName") |
| [clientLevel](#clientlevel) | `number` | Optional | cannot be null | [RegisterChildDeviceRequest](registerchilddevicerequest-properties-clientlevel.md "https://timelimit.io/RegisterChildDeviceRequest#/properties/clientLevel") |
## registerToken ## registerToken
@ -76,6 +77,24 @@ https://timelimit.io/RegisterChildDeviceRequest
`string` `string`
## clientLevel
`clientLevel`
* is optional
* Type: `number`
* cannot be null
* defined in: [RegisterChildDeviceRequest](registerchilddevicerequest-properties-clientlevel.md "https://timelimit.io/RegisterChildDeviceRequest#/properties/clientLevel")
### clientLevel Type
`number`
# RegisterChildDeviceRequest Definitions # RegisterChildDeviceRequest Definitions
## Definitions group NewDeviceInfo ## Definitions group NewDeviceInfo

View file

@ -0,0 +1,15 @@
# Untitled number in SignIntoFamilyRequest Schema
```txt
https://timelimit.io/SignIntoFamilyRequest#/properties/clientLevel
```
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :---------------------------------------------------------------------------------------------- |
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SignIntoFamilyRequest.schema.json\*](SignIntoFamilyRequest.schema.json "open original schema") |
## clientLevel Type
`number`

View file

@ -21,6 +21,7 @@ https://timelimit.io/SignIntoFamilyRequest
| [mailAuthToken](#mailauthtoken) | `string` | Required | cannot be null | [SignIntoFamilyRequest](signintofamilyrequest-properties-mailauthtoken.md "https://timelimit.io/SignIntoFamilyRequest#/properties/mailAuthToken") | | [mailAuthToken](#mailauthtoken) | `string` | Required | cannot be null | [SignIntoFamilyRequest](signintofamilyrequest-properties-mailauthtoken.md "https://timelimit.io/SignIntoFamilyRequest#/properties/mailAuthToken") |
| [parentDevice](#parentdevice) | `object` | Required | cannot be null | [SignIntoFamilyRequest](signintofamilyrequest-definitions-newdeviceinfo.md "https://timelimit.io/SignIntoFamilyRequest#/properties/parentDevice") | | [parentDevice](#parentdevice) | `object` | Required | cannot be null | [SignIntoFamilyRequest](signintofamilyrequest-definitions-newdeviceinfo.md "https://timelimit.io/SignIntoFamilyRequest#/properties/parentDevice") |
| [deviceName](#devicename) | `string` | Required | cannot be null | [SignIntoFamilyRequest](signintofamilyrequest-properties-devicename.md "https://timelimit.io/SignIntoFamilyRequest#/properties/deviceName") | | [deviceName](#devicename) | `string` | Required | cannot be null | [SignIntoFamilyRequest](signintofamilyrequest-properties-devicename.md "https://timelimit.io/SignIntoFamilyRequest#/properties/deviceName") |
| [clientLevel](#clientlevel) | `number` | Optional | cannot be null | [SignIntoFamilyRequest](signintofamilyrequest-properties-clientlevel.md "https://timelimit.io/SignIntoFamilyRequest#/properties/clientLevel") |
## mailAuthToken ## mailAuthToken
@ -76,6 +77,24 @@ https://timelimit.io/SignIntoFamilyRequest
`string` `string`
## clientLevel
`clientLevel`
* is optional
* Type: `number`
* cannot be null
* defined in: [SignIntoFamilyRequest](signintofamilyrequest-properties-clientlevel.md "https://timelimit.io/SignIntoFamilyRequest#/properties/clientLevel")
### clientLevel Type
`number`
# SignIntoFamilyRequest Definitions # SignIntoFamilyRequest Definitions
## Definitions group NewDeviceInfo ## Definitions group NewDeviceInfo

View file

@ -1,6 +1,6 @@
/* /*
* server component for the TimeLimit App * server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann * Copyright (C) 2019 - 2022 Jonas Lochmann
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as * it under the terms of the GNU Affero General Public License as
@ -24,10 +24,12 @@ import { logoutAtPrimaryDevice } from '../function/child/logout-at-primary-devic
import { setPrimaryDevice } from '../function/child/set-primary-device' import { setPrimaryDevice } from '../function/child/set-primary-device'
import { WebsocketApi } from '../websocket' import { WebsocketApi } from '../websocket'
import { isRegisterChildDeviceRequest, isRequestWithAuthToken, isUpdatePrimaryDeviceRequest } from './validator' import { isRegisterChildDeviceRequest, isRequestWithAuthToken, isUpdatePrimaryDeviceRequest } from './validator'
import { EventHandler } from '../monitoring/eventhandler'
export const createChildRouter = ({ database, websocket }: { export const createChildRouter = ({ database, websocket, eventHandler }: {
database: Database, database: Database
websocket: WebsocketApi websocket: WebsocketApi
eventHandler: EventHandler
}) => { }) => {
const router = Router() const router = Router()
@ -37,15 +39,17 @@ export const createChildRouter = ({ database, websocket }: {
throw new BadRequest() throw new BadRequest()
} }
const { deviceAuthToken, deviceId } = await addChildDevice({ const { deviceAuthToken, deviceId, data } = await addChildDevice({
request: req.body, request: req.body,
database, database,
eventHandler,
websocket websocket
}) })
res.json({ res.json({
deviceAuthToken, deviceAuthToken,
ownDeviceId: deviceId ownDeviceId: deviceId,
data
}) })
} catch (ex) { } catch (ex) {
next(ex) next(ex)

View file

@ -1,6 +1,6 @@
/* /*
* server component for the TimeLimit App * server component for the TimeLimit App
* Copyright (C) 2019 - 2020 Jonas Lochmann * Copyright (C) 2019 - 2022 Jonas Lochmann
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as * it under the terms of the GNU Affero General Public License as
@ -47,8 +47,8 @@ export const createApi = ({ database, websocket, connectedDevicesManager, eventH
}) })
app.use('/auth', createAuthRouter(database)) app.use('/auth', createAuthRouter(database))
app.use('/child', createChildRouter({ database, websocket })) app.use('/child', createChildRouter({ database, websocket, eventHandler }))
app.use('/parent', createParentRouter({ database, websocket })) app.use('/parent', createParentRouter({ database, websocket, eventHandler }))
app.use('/purchase', createPurchaseRouter({ database, websocket })) app.use('/purchase', createPurchaseRouter({ database, websocket }))
app.use('/sync', createSyncRouter({ database, websocket, connectedDevicesManager, eventHandler })) app.use('/sync', createSyncRouter({ database, websocket, connectedDevicesManager, eventHandler }))

View file

@ -31,6 +31,7 @@ import { signInIntoFamily } from '../function/parent/sign-in-into-family'
import { validateU2fIntegrity, U2fValidationError } from '../function/u2f' import { validateU2fIntegrity, U2fValidationError } from '../function/u2f'
import { createIdentityToken, MissingSignSecretException } from '../util/identity-token' import { createIdentityToken, MissingSignSecretException } from '../util/identity-token'
import { WebsocketApi } from '../websocket' import { WebsocketApi } from '../websocket'
import { EventHandler } from '../monitoring/eventhandler'
import { import {
isCreateFamilyByMailTokenRequest, isCreateFamilyByMailTokenRequest,
isCreateRegisterDeviceTokenRequest, isLinkParentMailAddressRequest, isCreateRegisterDeviceTokenRequest, isLinkParentMailAddressRequest,
@ -38,7 +39,13 @@ import {
isRemoveDeviceRequest, isSignIntoFamilyRequest, isRequestIdentityTokenRequest isRemoveDeviceRequest, isSignIntoFamilyRequest, isRequestIdentityTokenRequest
} from './validator' } from './validator'
export const createParentRouter = ({ database, websocket }: {database: Database, websocket: WebsocketApi}) => { export const createParentRouter = ({
database, websocket, eventHandler
}: {
database: Database
websocket: WebsocketApi
eventHandler: EventHandler
}) => {
const router = Router() const router = Router()
router.post('/get-status-by-mail-address', json(), async (req, res, next) => { router.post('/get-status-by-mail-address', json(), async (req, res, next) => {
@ -75,17 +82,20 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
const result = await createFamily({ const result = await createFamily({
database, database,
eventHandler,
firstParentDevice: req.body.parentDevice, firstParentDevice: req.body.parentDevice,
mailAuthToken: req.body.mailAuthToken, mailAuthToken: req.body.mailAuthToken,
password: req.body.parentPassword, password: req.body.parentPassword,
deviceName: req.body.deviceName, deviceName: req.body.deviceName,
parentName: req.body.parentName, parentName: req.body.parentName,
timeZone: req.body.timeZone timeZone: req.body.timeZone,
clientLevel: req.body.clientLevel || null
}) })
res.json({ res.json({
deviceAuthToken: result.deviceAuthToken, deviceAuthToken: result.deviceAuthToken,
ownDeviceId: result.deviceId ownDeviceId: result.deviceId,
data: result.data
}) })
} catch (ex) { } catch (ex) {
next(ex) next(ex)
@ -100,15 +110,18 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
const result = await signInIntoFamily({ const result = await signInIntoFamily({
database, database,
eventHandler,
newDeviceInfo: req.body.parentDevice, newDeviceInfo: req.body.parentDevice,
mailAuthToken: req.body.mailAuthToken, mailAuthToken: req.body.mailAuthToken,
deviceName: req.body.deviceName, deviceName: req.body.deviceName,
clientLevel: req.body.clientLevel || null,
websocket websocket
}) })
res.json({ res.json({
deviceAuthToken: result.deviceAuthToken, deviceAuthToken: result.deviceAuthToken,
ownDeviceId: result.deviceId ownDeviceId: result.deviceId,
data: result.data
}) })
} catch (ex) { } catch (ex) {
next(ex) next(ex)

View file

@ -84,12 +84,14 @@ export interface CreateFamilyByMailTokenRequest {
deviceName: string deviceName: string
timeZone: string timeZone: string
parentName: string parentName: string
clientLevel?: number
} }
export interface SignIntoFamilyRequest { export interface SignIntoFamilyRequest {
mailAuthToken: string mailAuthToken: string
parentDevice: NewDeviceInfo parentDevice: NewDeviceInfo
deviceName: string deviceName: string
clientLevel?: number
} }
export interface RecoverParentPasswordRequest { export interface RecoverParentPasswordRequest {
@ -101,6 +103,7 @@ export interface RegisterChildDeviceRequest {
registerToken: string registerToken: string
childDevice: NewDeviceInfo childDevice: NewDeviceInfo
deviceName: string deviceName: string
clientLevel?: number
} }
export interface CreateRegisterDeviceTokenRequest { export interface CreateRegisterDeviceTokenRequest {

View file

@ -2930,6 +2930,9 @@ export const isCreateFamilyByMailTokenRequest: (value: unknown) => value is Crea
}, },
"parentName": { "parentName": {
"type": "string" "type": "string"
},
"clientLevel": {
"type": "number"
} }
}, },
"additionalProperties": false, "additionalProperties": false,
@ -2955,6 +2958,9 @@ export const isSignIntoFamilyRequest: (value: unknown) => value is SignIntoFamil
}, },
"deviceName": { "deviceName": {
"type": "string" "type": "string"
},
"clientLevel": {
"type": "number"
} }
}, },
"additionalProperties": false, "additionalProperties": false,
@ -2995,6 +3001,9 @@ export const isRegisterChildDeviceRequest: (value: unknown) => value is Register
}, },
"deviceName": { "deviceName": {
"type": "string" "type": "string"
},
"clientLevel": {
"type": "number"
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View file

@ -22,13 +22,22 @@ import { generateAuthToken, generateVersionId } from '../../util/token'
import { WebsocketApi } from '../../websocket' import { WebsocketApi } from '../../websocket'
import { prepareDeviceEntry } from '../device/prepare-device-entry' import { prepareDeviceEntry } from '../device/prepare-device-entry'
import { notifyClientsAboutChangesDelayed } from '../websocket' import { notifyClientsAboutChangesDelayed } from '../websocket'
import { generateServerDataStatus } from '../sync/get-server-data-status'
import { EventHandler } from '../../monitoring/eventhandler'
import { ServerDataStatus } from '../../object/serverdatastatus'
import { createEmptyClientDataStatus } from '../../object/clientdatastatus'
export const addChildDevice = async ({ database, websocket, request }: { export const addChildDevice = async ({ database, eventHandler, websocket, request }: {
database: Database database: Database
eventHandler: EventHandler
websocket: WebsocketApi websocket: WebsocketApi
request: RegisterChildDeviceRequest request: RegisterChildDeviceRequest
// no transaction here because this is directly called from an API endpoint // no transaction here because this is directly called from an API endpoint
}) => { }): Promise<{
deviceId: string
deviceAuthToken: string
data: ServerDataStatus
}> => {
return database.transaction(async (transaction) => { return database.transaction(async (transaction) => {
const entry = await database.addDeviceToken.findOne({ const entry = await database.addDeviceToken.findOne({
where: { where: {
@ -75,9 +84,19 @@ export const addChildDevice = async ({ database, websocket, request }: {
transaction transaction
}) })
const data = await generateServerDataStatus({
database,
clientStatus: createEmptyClientDataStatus({ clientLevel: request.clientLevel || null }),
familyId: entry.familyId,
deviceId,
transaction,
eventHandler
})
return { return {
deviceId, deviceId,
deviceAuthToken deviceAuthToken,
data
} }
}) })
} }

View file

@ -16,25 +16,38 @@
*/ */
import { Conflict } from 'http-errors' import { Conflict } from 'http-errors'
import { generateServerDataStatus } from '../sync/get-server-data-status'
import { NewDeviceInfo, PlaintextParentPassword, assertPlaintextParentPasswordValid } from '../../api/schema' import { NewDeviceInfo, PlaintextParentPassword, assertPlaintextParentPasswordValid } from '../../api/schema'
import { Database } from '../../database' import { Database } from '../../database'
import { maxMailNotificationFlags } from '../../database/user' import { maxMailNotificationFlags } from '../../database/user'
import { EventHandler } from '../../monitoring/eventhandler'
import { ServerDataStatus } from '../../object/serverdatastatus'
import { createEmptyClientDataStatus } from '../../object/clientdatastatus'
import { import {
generateAuthToken, generateFamilyId, generateIdWithinFamily, generateVersionId generateAuthToken, generateFamilyId, generateIdWithinFamily, generateVersionId
} from '../../util/token' } from '../../util/token'
import { requireMailAndLocaleByAuthToken } from '../authentication' import { requireMailAndLocaleByAuthToken } from '../authentication'
import { prepareDeviceEntry } from '../device/prepare-device-entry' import { prepareDeviceEntry } from '../device/prepare-device-entry'
export const createFamily = async ({ database, mailAuthToken, firstParentDevice, password, timeZone, parentName, deviceName }: { export async function createFamily ({
database: Database, database, eventHandler, mailAuthToken, firstParentDevice,
mailAuthToken: string, password, timeZone, parentName, deviceName, clientLevel
firstParentDevice: NewDeviceInfo, }: {
password: PlaintextParentPassword, database: Database
timeZone: string, eventHandler: EventHandler
parentName: string, mailAuthToken: string
firstParentDevice: NewDeviceInfo
password: PlaintextParentPassword
timeZone: string
parentName: string
deviceName: string deviceName: string
clientLevel: number | null
// no transaction here because this is directly called from an API endpoint // no transaction here because this is directly called from an API endpoint
}) => { }): Promise<{
deviceAuthToken: string
deviceId: string
data: ServerDataStatus
}> {
assertPlaintextParentPasswordValid(password) assertPlaintextParentPasswordValid(password)
return database.transaction(async (transaction) => { return database.transaction(async (transaction) => {
@ -42,14 +55,14 @@ export const createFamily = async ({ database, mailAuthToken, firstParentDevice,
const mailInfo = await requireMailAndLocaleByAuthToken({ database, mailAuthToken, transaction, invalidate: true }) const mailInfo = await requireMailAndLocaleByAuthToken({ database, mailAuthToken, transaction, invalidate: true })
// ensure that no family was created for this mail yet // ensure that no family was created for this mail yet
const exisitngUserEntry = await database.user.findOne({ const existingUserEntry = await database.user.findOne({
where: { where: {
mail: mailInfo.mail mail: mailInfo.mail
}, },
transaction transaction
}) })
if (exisitngUserEntry) { if (existingUserEntry) {
throw new Conflict() throw new Conflict()
} }
@ -103,9 +116,19 @@ export const createFamily = async ({ database, mailAuthToken, firstParentDevice,
isUserKeptSignedIn: true isUserKeptSignedIn: true
}), { transaction }) }), { transaction })
const data = await generateServerDataStatus({
database,
clientStatus: createEmptyClientDataStatus({ clientLevel }),
familyId,
deviceId,
transaction,
eventHandler
})
return { return {
deviceAuthToken, deviceAuthToken,
deviceId deviceId,
data
} }
}) })
} }

View file

@ -24,15 +24,21 @@ import { WebsocketApi } from '../../websocket'
import { requireMailAndLocaleByAuthToken } from '../authentication' import { requireMailAndLocaleByAuthToken } from '../authentication'
import { prepareDeviceEntry } from '../device/prepare-device-entry' import { prepareDeviceEntry } from '../device/prepare-device-entry'
import { notifyClientsAboutChangesDelayed } from '../websocket' import { notifyClientsAboutChangesDelayed } from '../websocket'
import { generateServerDataStatus } from '../sync/get-server-data-status'
import { EventHandler } from '../../monitoring/eventhandler'
import { ServerDataStatus } from '../../object/serverdatastatus'
import { createEmptyClientDataStatus } from '../../object/clientdatastatus'
export const signInIntoFamily = async ({ database, mailAuthToken, newDeviceInfo, deviceName, websocket }: { export const signInIntoFamily = async ({ database, eventHandler, mailAuthToken, newDeviceInfo, deviceName, websocket, clientLevel }: {
database: Database database: Database
eventHandler: EventHandler
mailAuthToken: string mailAuthToken: string
newDeviceInfo: NewDeviceInfo newDeviceInfo: NewDeviceInfo
deviceName: string deviceName: string
websocket: WebsocketApi websocket: WebsocketApi
clientLevel: number | null
// no transaction here because this is directly called from an API endpoint // no transaction here because this is directly called from an API endpoint
}): Promise<{ deviceId: string; deviceAuthToken: string }> => { }): Promise<{ deviceId: string; deviceAuthToken: string; data: ServerDataStatus }> => {
return database.transaction(async (transaction) => { return database.transaction(async (transaction) => {
const mailInfo = await requireMailAndLocaleByAuthToken({ database, mailAuthToken, transaction, invalidate: true }) const mailInfo = await requireMailAndLocaleByAuthToken({ database, mailAuthToken, transaction, invalidate: true })
@ -94,9 +100,19 @@ export const signInIntoFamily = async ({ database, mailAuthToken, newDeviceInfo,
}) })
}) })
const data = await generateServerDataStatus({
database,
clientStatus: createEmptyClientDataStatus({ clientLevel }),
familyId: userEntry.familyId,
deviceId,
transaction,
eventHandler
})
return { return {
deviceId, deviceId,
deviceAuthToken deviceAuthToken,
data
} }
}) })
} }

View file

@ -28,6 +28,18 @@ export interface ClientDataStatus {
u2f?: string // last u2f list version u2f?: string // last u2f list version
} }
export function createEmptyClientDataStatus({ clientLevel }: {
clientLevel: number | null
}): ClientDataStatus {
return {
devices: '',
apps: {},
categories: {},
users: '',
clientLevel: clientLevel || undefined
}
}
export type ClientDataStatusApps = {[key: string]: string} // installedAppsVersionsByDeviceId export type ClientDataStatusApps = {[key: string]: string} // installedAppsVersionsByDeviceId
export type ClientDataStatusCategories = {[key: string]: CategoryDataStatus} export type ClientDataStatusCategories = {[key: string]: CategoryDataStatus}
export type ClientDataStatusDevicesExtended = {[key: string]: DeviceDataStatus} export type ClientDataStatusDevicesExtended = {[key: string]: DeviceDataStatus}