Files
timelimit-server/src/function/parent/link-mail-address.ts
T

112 lines
2.9 KiB
TypeScript

/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2022 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 { Conflict, Unauthorized } from 'http-errors'
import { Database } from '../../database'
import { generateVersionId } from '../../util/token'
import { WebsocketApi } from '../../websocket'
import { requireMailAndLocaleByAuthToken } from '../authentication'
import { notifyClientsAboutChangesDelayed } from '../websocket'
export const linkMailAddress = async ({ mailAuthToken, deviceAuthToken, parentUserId, parentPasswordSecondHash, database, websocket }: {
mailAuthToken: string
deviceAuthToken: string
parentUserId: string
parentPasswordSecondHash: string
database: Database
websocket: WebsocketApi
// no transaction here because this is directly called from an API endpoint
}) => {
await database.transaction(async (transaction) => {
const deviceEntry = await database.device.findOne({
where: {
deviceAuthToken
},
transaction
})
if (!deviceEntry) {
throw new Unauthorized()
}
const familyId = deviceEntry.familyId
const mailInfo = await requireMailAndLocaleByAuthToken({ mailAuthToken, database, transaction, invalidate: true })
const exisitingUser = await database.user.findOne({
where: {
mail: mailInfo.mail
},
transaction
})
if (exisitingUser) {
throw new Conflict()
}
const parentEntry = await database.user.findOne({
where: {
type: 'parent',
familyId,
userId: parentUserId
},
transaction
})
if (!parentEntry) {
throw new Conflict()
}
if (parentEntry.mail !== '') {
throw new Conflict()
}
if (parentEntry.secondPasswordHash !== parentPasswordSecondHash) {
throw new Conflict()
}
if (!parentEntry.secondPasswordSalt) {
throw new Conflict()
}
parentEntry.mail = mailInfo.mail
await parentEntry.save({ transaction })
// invalidiate client caches
await database.family.update({
userListVersion: generateVersionId()
}, {
where: {
familyId
},
transaction
})
// notify
await notifyClientsAboutChangesDelayed({
familyId,
sourceDeviceId: null,
generalLevel: 1,
targetedLevels: new Map(),
database,
websocket,
transaction
})
})
}