add invite code support
This commit is contained in:
+2
-4
@@ -3,9 +3,7 @@ import { AppController } from './app.controller';
|
|||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
import { VoteController } from './vote/vote.controller';
|
import { Answer, InviteCode, Vote } from './vote/vote.entity';
|
||||||
import { VoteService } from './vote/vote.service';
|
|
||||||
import { Answer, Vote } from './vote/vote.entity';
|
|
||||||
import { VoteModule } from './vote/vote.module';
|
import { VoteModule } from './vote/vote.module';
|
||||||
|
|
||||||
void ConfigModule.forRoot({
|
void ConfigModule.forRoot({
|
||||||
@@ -24,7 +22,7 @@ const configService = new ConfigService();
|
|||||||
username: configService.get('PG_USER'),
|
username: configService.get('PG_USER'),
|
||||||
database: configService.get('PG_DATABASE'),
|
database: configService.get('PG_DATABASE'),
|
||||||
synchronize: configService.get('DEV_MODE') == 'true',
|
synchronize: configService.get('DEV_MODE') == 'true',
|
||||||
entities: [Vote, Answer],
|
entities: [Vote, Answer, InviteCode],
|
||||||
}),
|
}),
|
||||||
VoteModule,
|
VoteModule,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,4 +1,13 @@
|
|||||||
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
|
import {
|
||||||
|
Body,
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
HttpException,
|
||||||
|
HttpStatus,
|
||||||
|
Param,
|
||||||
|
ParseUUIDPipe,
|
||||||
|
Post,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { VoteCreateDTO } from './vote.dto';
|
import { VoteCreateDTO } from './vote.dto';
|
||||||
import { VoteService } from './vote.service';
|
import { VoteService } from './vote.service';
|
||||||
import { ApiOperation } from '@nestjs/swagger';
|
import { ApiOperation } from '@nestjs/swagger';
|
||||||
@@ -7,18 +16,38 @@ import { ApiOperation } from '@nestjs/swagger';
|
|||||||
export class VoteController {
|
export class VoteController {
|
||||||
constructor(private readonly voteService: VoteService) {}
|
constructor(private readonly voteService: VoteService) {}
|
||||||
|
|
||||||
|
@Get('check/:accessCode')
|
||||||
|
@ApiOperation({ summary: 'Checks if a code has been used' })
|
||||||
|
async check(@Param('accessCode', new ParseUUIDPipe()) accessCode: string) {
|
||||||
|
const value = await this.voteService.check(accessCode);
|
||||||
|
if (value === null) {
|
||||||
|
throw new HttpException('Invalid accessCode', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (value === false) {
|
||||||
|
throw new HttpException('AccessCode expired', HttpStatus.FORBIDDEN);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
@Post('vote/:accessCode')
|
@Post('vote/:accessCode')
|
||||||
@ApiOperation({ summary: 'Vote for a poll' })
|
@ApiOperation({ summary: 'Vote for a poll' })
|
||||||
async vote(
|
async vote(
|
||||||
@Param('accessCode') accessCode: string,
|
@Param('accessCode', new ParseUUIDPipe()) accessCode: string,
|
||||||
@Body() answer: VoteCreateDTO,
|
@Body() answer: VoteCreateDTO,
|
||||||
) {
|
) {
|
||||||
await this.voteService.create(answer);
|
const code = await this.voteService.check(accessCode);
|
||||||
|
if (code === null) {
|
||||||
|
throw new HttpException('Invalid accessCode', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (code === false) {
|
||||||
|
throw new HttpException('AccessCode expired', HttpStatus.FORBIDDEN);
|
||||||
|
}
|
||||||
|
await this.voteService.create(answer, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('results/:accessCode')
|
@Get('results/:accessCode')
|
||||||
@ApiOperation({ summary: 'Get results' })
|
@ApiOperation({ summary: 'Get results' })
|
||||||
async results(@Param('accessCode') accessCode: string) {
|
async results(@Param('accessCode', new ParseUUIDPipe()) accessCode: string) {
|
||||||
return await this.voteService.getResults();
|
return await this.voteService.getResults();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import {
|
|||||||
OneToMany,
|
OneToMany,
|
||||||
ManyToOne,
|
ManyToOne,
|
||||||
Column,
|
Column,
|
||||||
|
OneToOne,
|
||||||
|
Generated,
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
@@ -16,6 +18,13 @@ export class Vote {
|
|||||||
eager: true,
|
eager: true,
|
||||||
})
|
})
|
||||||
answers: Answer[];
|
answers: Answer[];
|
||||||
|
|
||||||
|
@OneToOne(() => InviteCode, (code) => code.vote, {
|
||||||
|
eager: false,
|
||||||
|
onDelete: 'CASCADE',
|
||||||
|
nullable: false,
|
||||||
|
})
|
||||||
|
code: Promise<InviteCode>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
@@ -35,3 +44,22 @@ export class Answer {
|
|||||||
@Column()
|
@Column()
|
||||||
answer: string;
|
answer: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class InviteCode {
|
||||||
|
@PrimaryGeneratedColumn({})
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@OneToOne(() => Vote, (vote) => vote.code, {
|
||||||
|
eager: false,
|
||||||
|
onDelete: 'CASCADE',
|
||||||
|
})
|
||||||
|
vote: Promise<Vote>;
|
||||||
|
|
||||||
|
@Column({ default: 1 })
|
||||||
|
usages_left: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
@Generated('uuid')
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { Answer, Vote } from './vote.entity';
|
import { InviteCode, Vote } from './vote.entity';
|
||||||
import { VoteController } from './vote.controller';
|
import { VoteController } from './vote.controller';
|
||||||
import { VoteService } from './vote.service';
|
import { VoteService } from './vote.service';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [TypeOrmModule.forFeature([Vote, Answer])],
|
imports: [TypeOrmModule.forFeature([Vote, InviteCode])],
|
||||||
controllers: [VoteController],
|
controllers: [VoteController],
|
||||||
providers: [VoteService],
|
providers: [VoteService],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { VoteCreateDTO } from './vote.dto';
|
import { VoteCreateDTO } from './vote.dto';
|
||||||
import { Vote } from './vote.entity';
|
import { InviteCode, Vote } from './vote.entity';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
|
||||||
@@ -17,8 +17,13 @@ interface IVote {
|
|||||||
export class VoteService {
|
export class VoteService {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(Vote) private voteRepository: Repository<Vote>,
|
@InjectRepository(Vote) private voteRepository: Repository<Vote>,
|
||||||
|
@InjectRepository(InviteCode)
|
||||||
|
private inviteCodeRepository: Repository<InviteCode>,
|
||||||
) {}
|
) {}
|
||||||
async create(value: VoteCreateDTO) {
|
async create(value: VoteCreateDTO, accessCode: InviteCode) {
|
||||||
|
accessCode.usages_left--;
|
||||||
|
await this.inviteCodeRepository.save(accessCode);
|
||||||
|
|
||||||
const vote = Object.entries(value).reduce<IVote>(
|
const vote = Object.entries(value).reduce<IVote>(
|
||||||
(acc, [question_id, a]) => {
|
(acc, [question_id, a]) => {
|
||||||
const answer = String(a);
|
const answer = String(a);
|
||||||
@@ -51,4 +56,17 @@ export class VoteService {
|
|||||||
}
|
}
|
||||||
return compiled_results;
|
return compiled_results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async check(inviteCode: string) {
|
||||||
|
const code = await this.inviteCodeRepository.findOneBy({
|
||||||
|
value: inviteCode,
|
||||||
|
});
|
||||||
|
if (!code) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (code.usages_left > 0) {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user