Skip to content
Snippets Groups Projects
token-code.resolver.ts 4.87 KiB
Newer Older
Adrian Paschkowski's avatar
V2  
Adrian Paschkowski committed
	Args,
	Context,
	Mutation,
	Parent,
	Query,
	ResolveField,
	Resolver,
	Subscription,
} from '@nestjs/graphql';
Adrian Paschkowski's avatar
V2  
Adrian Paschkowski committed
import { TokenCodeModel } from './models/token-code.model';
import { PrismaService } from '../prisma/prisma.service';
Adrian Paschkowski's avatar
V2  
Adrian Paschkowski committed
import { Request } from 'express';
import { NotFoundException, UseGuards } from '@nestjs/common';
import { AuthGuard } from '../auth/auth.guard';
import { AgentGuard } from '../auth/agent.guard';
import { GroupGuard } from '../auth/group.guard';
import { TokenCode } from '@prisma/client';
import { AgentFlags, AgentModel } from './models/agent.model';
import { PubSub } from 'graphql-subscriptions';
import { TokenCodeInputModel } from './models/token-code-input.model';

@Resolver(() => TokenCodeModel)
export class TokenCodeResolver {
Adrian Paschkowski's avatar
V2  
Adrian Paschkowski committed
	constructor(
		private readonly pubSub: PubSub,
		private readonly prisma: PrismaService,
	) {}

	@Subscription(() => TokenCodeModel, {
		filter: (payload: TokenCode, variables, { req }: { req: Request }) => {
			return req.agent && req.agent.id === payload.agentId;
		},
	})
	onTokenCodeUpdate(@Context('pubsub') pubSub: PubSub) {
		return pubSub.asyncIterator('onTokenCodeUpdate');
	}

	@Mutation(() => TokenCodeModel)
	@UseGuards(AuthGuard, AgentGuard)
	async invalidateTokenCode(
		@Args('tokenCode') tokenCode: string,
		@Context() { req }: { req: Request },
	) {
		return await this.prisma.$transaction(async (prisma) => {
			const token = await prisma.tokenCode.findFirst({
				where: { id: tokenCode },
			});

			if (!token) throw new NotFoundException();

			const newToken = await prisma.tokenCode.create({
				data: {
					agent: {
						connect: { id: req.agent.id },
					},
				},
				include: { agent: true },
			});

			const oldToken = await prisma.tokenCode.delete({
				where: { id: tokenCode },
				include: { agent: true },
			});

			await this.pubSub.publish('onTokenCodeUpdate', newToken);
			await this.pubSub.publish('onTokenCodeUpdate', {
				id: oldToken.id,
				deleted: true,
			});

			return newToken;
		});
	}

	@Query(() => [TokenCodeModel])
	@UseGuards(AuthGuard)
	async getTokenCodes(
		@Context() { req }: { req: Request },
	): Promise<TokenCodeModel[]> {
		if (!req.agent) return [];

		if ((req.agent.flags & AgentFlags.ADMIN) === AgentFlags.ADMIN)
			return await this.prisma.tokenCode.findMany({
				include: {
					agent: true,
				},
			});
		else
			return await this.prisma.tokenCode.findMany({
				where: { agentId: req.agent.id },
				include: {
					agent: {
						select: {
							id: true,
							bio: true,
							name: true,
							slug: false,
							flags: true,
							avatar: true,
						},
					},
				},
			});
	}

	@Mutation(() => TokenCodeModel)
	@UseGuards(AuthGuard, GroupGuard)
	async redeemTokenCode(
		@Args('tokenCode') tokenCode: string,
		@Context() { req }: { req: Request },
	): Promise<TokenCodeModel> {
		return this.prisma.$transaction(async (prisma) => {
			const token = await prisma.tokenCode.findFirst({
				where: { id: tokenCode },
				include: {
					agent: {
						select: {
							id: true,
							bio: true,
							name: true,
							slug: false,
							flags: true,
							avatar: true,
						},
					},
				},
			});

			if (!token) throw new NotFoundException();

			const deleted = await prisma.tokenCode.delete({
				where: { id: tokenCode },
			});

			const { tokenCodes } = await prisma.agent.update({
				where: { id: token.agentId },
				data: {
					tokenCodes: {
						create: { value: 1 },
					},
				},
				include: { tokenCodes: true },
			});

			const group = await prisma.group.update({
				where: { id: req.group.id },
				data: {
					tokens: { increment: token.value },
				},
			});

			await this.pubSub.publish('onTokenCodeUpdate', {
				id: deleted.id,
				deleted: true,
			});

			await this.pubSub.publish('onGroupUpdate', group);
			await this.pubSub.publish('onTokenCodeUpdate', tokenCodes[0]);

			return token;
		});
	}

	@Mutation(() => TokenCodeModel)
	@UseGuards(AuthGuard, AgentGuard)
	async updateTokenCode(
		@Args('id') id: string,
		@Args('data') data: TokenCodeInputModel,
		@Context() { req }: { req: Request },
	): Promise<TokenCode> {
		const count = await this.prisma.tokenCode.count({
			where: { id, agentId: req.agent.id },
		});

		if (count === 0) throw new NotFoundException();

		const tokenCode = await this.prisma.tokenCode.update({
			where: {
				id,
			},
			data,
			include: {
				agent: {
					select: {
						id: true,
						bio: true,
						name: true,
						slug: false,
						flags: true,
						avatar: true,
					},
				},
			},
		});

		await this.pubSub.publish('onTokenCodeUpdate', tokenCode);

		return tokenCode;
	}

	/*@ResolveField('agent')
	async agent(@Parent() parent: TokenCodeModel): Promise<AgentModel> {
		return this.prisma.agent.findFirst({
			where: {
				tokenCodes: {
					some: { id: parent.id },
				},
			},
			select: {
				id: true,
				bio: true,
				name: true,
				slug: false,
				flags: true,
				avatar: true,
			},
		});
	}*/