import { Args, Context, Mutation, Resolver } from '@nestjs/graphql'; import { Person } from '../models/Person'; import { Client } from '../../client'; import { PersonService } from '../person.service'; import { HttpException } from '@nestjs/common'; import {UUID} from '../../global/scalars/UUID' import {OrganizerService} from '../../organizer/organizer.service' import {EmailAddress} from '../../global/scalars/EmailAddress' import {checkPassword, secureHash} from '../../generate' import {pubsub} from '../../main' import {sendmail} from '../../mail' import {SERVERDATA, SYSDATA} from '../../config' import { v4 as uuid } from 'uuid' @Resolver(() => Person) export class PersonResolverM { constructor( private readonly service: PersonService, ) {} @Mutation(() => Person, { nullable: false }) async login( @Context('client') client: Client, @Args('email', { nullable: true }) email?: string, @Args('passwort', { nullable: true }) passwort?: string, @Args('token', { nullable: true }) token?: string ): Promise { await client.login({email, passwort, token}); const newtoken: string = client.getToken(); if (!newtoken) { throw new HttpException('Logindaten falsch', 403); } const tmp = await this.service.findOneById(client.getUser()?._id); if (!!(tmp as unknown as any).confirmCode) { throw new HttpException('E-Mail-Adresse noch nicht bestätigt!', 403); } return tmp; } @Mutation(() => Person, { nullable: false }) async PersonRegister( @Context('client') client: Client, @Args('organizer', { type: () => UUID, nullable: false }) organizer: UUID, @Args('givenName', { nullable: false }) givenName: string, @Args('familyName', { nullable: false }) familyName: string, @Args('email', { type: () => EmailAddress, nullable: false }) email: EmailAddress, @Args('passwort', { nullable: false }) passwort: string, ): Promise { const organizerService = new OrganizerService(); const o = await organizerService.findOneById(organizer); if (!o) { throw new HttpException('Organizer-ID not found!', 404); } const tmp = await this.service.create(client, givenName, familyName, email, passwort); let isAdmin = false; if (!o._admins) { await organizerService.update(client, o._id, {$set: {_admins: [ tmp._id ] }}, {}); isAdmin = true; } else if (o._admins.length === 0) { await organizerService.update(client, o._id, {$push: {_admins: tmp._id }}, {}); isAdmin = true; } else if (!o._pending) { await organizerService.update(client, o._id, {$set: {_pending: [ tmp._id ] }}, {}); } else { await organizerService.update(client, o._id, {$push: {_pending: tmp._id }}, {}); } const link = `${SERVERDATA.host}/confirm/${(tmp as unknown as any).confirmCode}` const text = `Vielen Dank für Ihre Registrierung bei ${SYSDATA.name} Bitte bestätigen Sie unter folgendem Link Ihre Registrierung: ${link}` + (isAdmin?'':` Sie müssen außerdem zunächst von einem Administrator Ihrer Schule/Ihres Vereins freigeschaltet werden. Dieser erhält ebenfalls eine E-Mail über Ihre Registrierung.`); sendmail(email,`[${SYSDATA.name}] Neu-Registrierung`, text); if (!isAdmin) { const admintext = `${givenName} ${familyName} hat sich neu bei ${SYSDATA.name} für Ihre Schule/Ihren Verein ${o.name} registriert. Bitte melden Sie sich unter ${SERVERDATA.host} an und bearbeiten die Registrierung.` for (let i = 0; i < o._admins?.length; i++) { const p = await this.service.findOneById(o._admins[i]); sendmail(p.email, `[${SYSDATA.name}] Neu-Registrierung für ${o.name}`, admintext); } } pubsub.publish('PersonUpdated', { PersonUpdated: tmp }); return tmp; } @Mutation(() => Person, { nullable: true }) async PersonConfirmMail( @Context('client') client: Client, @Args('email') email: string, @Args('confirmCode') confirmCode: string, ): Promise { const tmp = await this.service.find({email, confirmCode}); if (tmp.length !== 1) { throw new HttpException('E-Mail-Adresse oder Bestätigungscode ungültig', 403); } this.service.update(client, tmp[0]._id, { $unset: { confirmCode } }) return tmp[0]; } @Mutation(() => Boolean, { nullable: true }) async PersonPasswordReset( @Context('client') client: Client, @Args('email') email: EmailAddress, @Args('resetCode', { type: () => String, nullable: true }) resetCode?: string, @Args('newPassword', { type: () => String, nullable: true }) newPassword?: string, ): Promise { const tmp = await this.service.find({email}); console.log((tmp[0] as unknown as any).resetCode) console.log(resetCode) if (tmp.length === 1) { if (!resetCode && !newPassword) { const code = uuid(); this.service.update(client, tmp[0]._id, {$set: {resetCode: code}}) const link = `${SERVERDATA.host}/reset/${code}` const text = `Unter folgendem Link können Sie Ihr Passwort zurücksetzen: ${link} Alternativ können Sie auch den folgenden Code in das Eingabefeld kopieren: ${code}` console.log(text); sendmail(email,`[${SYSDATA.name}] Passwort zurücksetzen`, text); } else if ((tmp[0] as unknown as any).resetCode === resetCode) { this.service.update(client, tmp[0]._id, {$set: { passwort: await secureHash(newPassword) }, $unset: { resetCode: '' } }); return true; } } return null; } @Mutation(() => Boolean, { nullable: false }) async ChangePassword( @Context('client') client: Client, @Args('oldPassword', { nullable: false }) oldPassword: string, @Args('newPassword', { nullable: false }) newPassword: string, ): Promise { if (!client.getUser()) { throw new HttpException('you need to be logged in to change your password!', 403); } const tmp = await this.service.findOneById(client.getUser()._id); if (!(await checkPassword(oldPassword, (tmp as unknown as any).passwort))) { throw new HttpException('old password wrong!', 403); } this.service.update(client, tmp._id, {$set: { passwort: await secureHash(newPassword) }}); return true; } @Mutation(() => Person, { nullable: false }) async PersonUpdate( @Context('client') client: Client, @Args('id', { type: () => UUID, nullable: false }) id: UUID, @Args('givenName', { nullable: true }) givenName?: string, @Args('familyName', { nullable: true }) familyName?: string, @Args('email', { type: () => EmailAddress, nullable: true }) email?: EmailAddress, @Args('master', { nullable: true }) master?: boolean ): Promise { if (!client.isMaster() && !client.isSelf(id)) throw new HttpException('Access denied', 403); const tmp = await this.service.findOneById(id); const set: { givenName?: string familyName?: string email?: EmailAddress master?: boolean } = {}; if (givenName !== undefined && givenName !== tmp.givenName) set.givenName = givenName if (familyName !== undefined && familyName !== tmp.familyName) set.familyName = familyName if (email !== undefined && email !== tmp.email) set.email = email if (client.isMaster() && master !== undefined && master !== tmp.master) set.master = master if (Object.values(set).length === 0) return tmp; const neu = await this.service.update(client, tmp._id, {$set: set}); pubsub.publish('PersonUpdated', { PersonUpdated: neu }); return neu; } @Mutation(() => Person, { nullable: false }) async PersonCreate( @Context('client') client: Client, @Args('givenName', { nullable: false }) givenName: string, @Args('familyName', { nullable: false }) familyName: string, @Args('email', { type: () => EmailAddress, nullable: false }) email: EmailAddress, @Args('master', { nullable: true }) master?: boolean ): Promise { if (!client.isMaster()) throw new HttpException('Access denied', 403); const neu = await this.service.insert(client, { givenName, familyName, email, master }); pubsub.publish('PersonUpdated', { PersonUpdated: neu }); return neu; } @Mutation(() => UUID, { nullable: false }) async PersonDelete( @Context('client') client: Client, @Args('id', { type: () => UUID, nullable: false }) id: UUID ): Promise { if (!client.isMaster()) throw new HttpException('Access denied', 403); this.service.delete(client, id); pubsub.publish('PersonDeleted', { PersonDeleted: id }); return id; } }