Add timer REST stuff
This commit is contained in:
parent
4dfc3129e3
commit
36412c9f58
@ -21,5 +21,14 @@ module.exports = {
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'warn', // or "error"
|
||||
{
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
caughtErrorsIgnorePattern: '^_',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the `_FriendToTimer` table. If the table is not empty, all the data it contains will be lost.
|
||||
- Added the required column `created_by_id` to the `Timer` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_FriendToTimer" DROP CONSTRAINT "_FriendToTimer_A_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_FriendToTimer" DROP CONSTRAINT "_FriendToTimer_B_fkey";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Timer" ADD COLUMN "created_by_id" INTEGER NOT NULL;
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "_FriendToTimer";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_referenced_friend_fk" (
|
||||
"A" INTEGER NOT NULL,
|
||||
"B" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "_referenced_friend_fk_AB_unique" ON "_referenced_friend_fk"("A", "B");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_referenced_friend_fk_B_index" ON "_referenced_friend_fk"("B");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Timer" ADD CONSTRAINT "Timer_created_by_id_fkey" FOREIGN KEY ("created_by_id") REFERENCES "Friend"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_referenced_friend_fk" ADD CONSTRAINT "_referenced_friend_fk_A_fkey" FOREIGN KEY ("A") REFERENCES "Friend"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_referenced_friend_fk" ADD CONSTRAINT "_referenced_friend_fk_B_fkey" FOREIGN KEY ("B") REFERENCES "Timer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Timer" ALTER COLUMN "start" SET DEFAULT CURRENT_TIMESTAMP;
|
@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Timer" ALTER COLUMN "start" DROP NOT NULL;
|
@ -23,18 +23,22 @@ model Friend {
|
||||
name String @unique @db.Citext
|
||||
public_key String @db.Text
|
||||
|
||||
timers Timer[]
|
||||
referenced_in Timer[] @relation(name: "referenced_friend_fk")
|
||||
created_timers Timer[] @relation(name: "created_by_fk")
|
||||
god_tokens GodToken[]
|
||||
TimerRefreshes TimerRefreshes[]
|
||||
}
|
||||
|
||||
model Timer {
|
||||
id Int @id @default(autoincrement())
|
||||
start DateTime
|
||||
start DateTime? @default(now())
|
||||
name String @unique
|
||||
|
||||
created_by Friend @relation(name: "created_by_fk", fields: [created_by_id], references: [id])
|
||||
created_by_id Int
|
||||
|
||||
timer_refreshes TimerRefreshes[]
|
||||
referenced_friends Friend[]
|
||||
referenced_friends Friend[] @relation(name: "referenced_friend_fk")
|
||||
}
|
||||
|
||||
model TimerRefreshes {
|
||||
|
@ -10,20 +10,12 @@ import {
|
||||
UseGuards,
|
||||
Req,
|
||||
} from '@nestjs/common';
|
||||
import { IsNotEmpty } from 'class-validator';
|
||||
|
||||
import { readKey, readCleartextMessage, verify } from 'openpgp';
|
||||
import { AuthService } from './auth.service';
|
||||
import { AuthGuard } from './auth.guard';
|
||||
|
||||
export class LoginUserDTO {
|
||||
@IsNotEmpty()
|
||||
signature: string;
|
||||
}
|
||||
|
||||
export class RetrieveTokenDTO {
|
||||
@IsNotEmpty()
|
||||
name: string;
|
||||
}
|
||||
import { RetrieveFriendDTO, SignedGodTokenDTO } from '../dto/dtos';
|
||||
|
||||
@Controller('/auth')
|
||||
export class AuthController {
|
||||
@ -40,7 +32,7 @@ export class AuthController {
|
||||
}
|
||||
|
||||
@Get('/')
|
||||
async retrieveGodToken(@Query() query: RetrieveTokenDTO) {
|
||||
async makeGodToken(@Query() query: RetrieveFriendDTO) {
|
||||
const friend = await this.authService.findFriendByName(query.name);
|
||||
if (!friend) throw new NotFoundException('Friend not found with that name');
|
||||
|
||||
@ -50,7 +42,7 @@ export class AuthController {
|
||||
@Post()
|
||||
async verifyFriend(
|
||||
@Res({ passthrough: true }) res,
|
||||
@Body() { signature }: LoginUserDTO,
|
||||
@Body() { signature }: SignedGodTokenDTO,
|
||||
) {
|
||||
let signatureObj;
|
||||
try {
|
||||
|
@ -7,7 +7,7 @@ import { AuthService } from './auth.service';
|
||||
@Module({
|
||||
imports: [PrismaModule],
|
||||
controllers: [AuthController],
|
||||
exports: [AuthGuard],
|
||||
exports: [AuthGuard, AuthService],
|
||||
providers: [AuthService, AuthGuard],
|
||||
})
|
||||
export class AuthModule {}
|
||||
|
16
server/src/dto/dtos.ts
Normal file
16
server/src/dto/dtos.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { IsNotEmpty } from 'class-validator';
|
||||
|
||||
export class SignedGodTokenDTO {
|
||||
@IsNotEmpty()
|
||||
signature: string;
|
||||
}
|
||||
|
||||
export class RetrieveFriendDTO {
|
||||
@IsNotEmpty()
|
||||
name: string;
|
||||
}
|
||||
|
||||
export class CreateTimerDTO {
|
||||
@IsNotEmpty()
|
||||
name: string;
|
||||
}
|
@ -1,4 +1,75 @@
|
||||
import { Controller } from '@nestjs/common';
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Req,
|
||||
Query,
|
||||
NotFoundException,
|
||||
UseGuards,
|
||||
BadRequestException,
|
||||
} from '@nestjs/common';
|
||||
import { TimerService } from './timer.service';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
import { CreateTimerDTO, RetrieveFriendDTO } from '../dto/dtos';
|
||||
import { AuthGuard } from 'src/auth/auth.guard';
|
||||
import { Prisma } from '@prisma/client';
|
||||
|
||||
@Controller('timer')
|
||||
export class TimerController {}
|
||||
@Controller('timers')
|
||||
@UseGuards(AuthGuard)
|
||||
export class TimerController {
|
||||
constructor(
|
||||
private readonly timerService: TimerService,
|
||||
private readonly authService: AuthService,
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
public async getAllTimers() {
|
||||
return this.timerService.getAll();
|
||||
}
|
||||
|
||||
@Get('/friend')
|
||||
public async getFriendTimers(@Query() { name }: RetrieveFriendDTO) {
|
||||
const friend = await this.authService.findFriendByName(name);
|
||||
if (!friend) throw new NotFoundException('Friend not found with that name');
|
||||
return this.timerService.friendTimers(friend);
|
||||
}
|
||||
|
||||
@Post()
|
||||
public async createTimer(@Body() { name }: CreateTimerDTO, @Req() req) {
|
||||
const referencedFriendIds = Array.from(
|
||||
new Set(
|
||||
[...name.matchAll(/\@<(\d+)>/g)].map(([_match, id]) =>
|
||||
parseInt(id, 10),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (referencedFriendIds.length > 10)
|
||||
throw new BadRequestException(
|
||||
'Can link no more than 10 unique friends to timer',
|
||||
);
|
||||
|
||||
try {
|
||||
return await this.timerService.createTimerWithFriends(
|
||||
{
|
||||
name,
|
||||
created_by: {
|
||||
connect: {
|
||||
id: req.friend.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
referencedFriendIds,
|
||||
);
|
||||
} catch (e) {
|
||||
if (
|
||||
e instanceof Prisma.PrismaClientKnownRequestError &&
|
||||
e.code === 'P2002'
|
||||
)
|
||||
throw new BadRequestException('Timer with name already exists');
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,12 @@ import { Module } from '@nestjs/common';
|
||||
import { TimerGateway } from './timer.gateway';
|
||||
import { TimerController } from './timer.controller';
|
||||
import { TimerService } from './timer.service';
|
||||
import { PrismaModule } from '../prisma/prisma.module';
|
||||
import { AuthModule } from '../auth/auth.module';
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule, AuthModule],
|
||||
providers: [TimerGateway, TimerService],
|
||||
controllers: [TimerController]
|
||||
controllers: [TimerController],
|
||||
})
|
||||
export class TimerModule {}
|
||||
|
@ -1,4 +1,72 @@
|
||||
import { Friend, Prisma } from '@prisma/client';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
|
||||
@Injectable()
|
||||
export class TimerService {}
|
||||
export class TimerService {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
public getAll() {
|
||||
return this.prismaService.timer.findMany({
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
start: true,
|
||||
referenced_friends: {
|
||||
select: {
|
||||
name: true,
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
created_by: {
|
||||
select: {
|
||||
name: true,
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public friendTimers(friend: Friend) {
|
||||
return this.prismaService.timer.findMany({
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
start: true,
|
||||
referenced_friends: {
|
||||
where: {
|
||||
id: friend.id,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
created_by: {
|
||||
select: {
|
||||
name: true,
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public createTimerWithFriends(
|
||||
timer: Prisma.TimerCreateInput,
|
||||
friendIds: number[],
|
||||
) {
|
||||
if (friendIds.length > 0)
|
||||
return this.prismaService.timer.create({
|
||||
data: {
|
||||
...timer,
|
||||
referenced_friends: {
|
||||
connect: friendIds.map((id) => ({ id })),
|
||||
},
|
||||
},
|
||||
});
|
||||
return this.prismaService.timer.create({ data: timer });
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user