Skip to content
Snippets Groups Projects
entry.resolver.ts 2.67 KiB
Newer Older
  • Learn to ignore specific revisions
  • Pascal Kosak's avatar
    Pascal Kosak committed
    import {
    
    Adrian Paschkowski's avatar
    V2  
    Adrian Paschkowski committed
    	Args,
    	Context,
    	Mutation,
    	Parent,
    	Query,
    	ResolveField,
    	Resolver,
    	Subscription,
    
    Pascal Kosak's avatar
    Pascal Kosak committed
    } from '@nestjs/graphql';
    
    Adrian Paschkowski's avatar
    V2  
    Adrian Paschkowski committed
    import { EntryModel } from './models/entry.model';
    
    Pascal Kosak's avatar
    Pascal Kosak committed
    import { PrismaService } from '../prisma/prisma.service';
    
    Pascal Kosak's avatar
    Pascal Kosak committed
    import {
    
    Adrian Paschkowski's avatar
    V2  
    Adrian Paschkowski committed
    	BadRequestException,
    	InternalServerErrorException,
    	NotFoundException,
    	UseGuards,
    
    Pascal Kosak's avatar
    Pascal Kosak committed
    } from '@nestjs/common';
    
    Adrian Paschkowski's avatar
    V2  
    Adrian Paschkowski committed
    import { AuthGuard } from '../auth/auth.guard';
    
    import { Request } from 'express';
    
    Adrian Paschkowski's avatar
    V2  
    Adrian Paschkowski committed
    import { EntryService } from '../utils/entry.service';
    import { AgentModel } from './models/agent.model';
    import { GroupGuard } from '../auth/group.guard';
    import { PubSub } from 'graphql-subscriptions';
    import { Entry, Group } from '@prisma/client';
    
    Pascal Kosak's avatar
    Pascal Kosak committed
    
    
    Adrian Paschkowski's avatar
    V2  
    Adrian Paschkowski committed
    @Resolver(() => EntryModel)
    
    Pascal Kosak's avatar
    Pascal Kosak committed
    export class EntryResolver {
    
    Adrian Paschkowski's avatar
    V2  
    Adrian Paschkowski committed
    	constructor(
    		private readonly pubSub: PubSub,
    		private readonly prisma: PrismaService,
    		private readonly entryService: EntryService,
    	) {}
    
    	@Subscription(() => EntryModel, {
    		filter: (payload: Entry & { by?: Group }, variables, { req }) => {
    			if (payload.by) return req.group.id === payload.by.id;
    
    			return true;
    		},
    	})
    	onEntryUpdate(@Context('pubsub') pubSub: PubSub) {
    		return pubSub.asyncIterator('onEntryUpdate');
    	}
    
    	@Mutation(() => EntryModel)
    	@UseGuards(AuthGuard, GroupGuard)
    	unlockEntry(
    		@Args('id') id: string,
    		@Context() { req }: { req: Request },
    	): Promise<EntryModel> {
    		return this.prisma.$transaction(async (prisma) => {
    			const entry = await prisma.entry.findFirst({
    				where: {
    					id,
    					unlockedBy: {
    						none: { id: req.group.id },
    					},
    				},
    			});
    
    			if (!entry) throw new NotFoundException();
    
    			if (req.group.tokens < entry.cost)
    				throw new BadRequestException('Not enough tokens');
    
    			const group = await prisma.group.update({
    				where: { id: req.group.id },
    				data: {
    					tokens: { decrement: entry.cost },
    					unlocks: {
    						connect: { id: entry.id },
    					},
    				},
    			});
    
    			if (!group)
    				throw new InternalServerErrorException('Group not found');
    
    			await this.pubSub.publish('onEntryUpdate', {
    				...entry,
    				by: group,
    			});
    
    			return this.entryService.unlockedEntry(entry);
    		});
    	}
    
    	@Query(() => [EntryModel])
    	@UseGuards(AuthGuard)
    	async getEntries(@Context() { req }: { req: Request }) {
    		if (req.agent)
    			return this.prisma.entry
    				.findMany()
    				.then((entries) =>
    					entries.map(this.entryService.unlockedEntry),
    				);
    
    		return await this.entryService.getAccessibleEntries(req.group.id);
    	}
    
    	@ResolveField('agent')
    	async agent(@Parent() parent: EntryModel): Promise<AgentModel> {
    		return this.prisma.agent.findFirst({
    			where: {
    				entries: {
    					some: { id: parent.id },
    				},
    			},
    			select: {
    				id: true,
    				name: true,
    				slug: false,
    				flags: true,
    			},
    		});
    	}
    
    Pascal Kosak's avatar
    Pascal Kosak committed
    }