Skip to content
Merged
16 changes: 16 additions & 0 deletions api/db/migrations/1775336799887-event-whitelist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { MigrationInterface, QueryRunner } from "typeorm";

export class EventWhitelist1775336799887 implements MigrationInterface {
name = 'EventWhitelist1775336799887'

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "event_whitelists" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "platform" text NOT NULL, "username" character varying NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "eventId" uuid NOT NULL, CONSTRAINT "UQ_1e66e3e9750244ea3f6563a6d49" UNIQUE ("eventId", "username", "platform"), CONSTRAINT "PK_64d752c5410ff967a715cca3998" PRIMARY KEY ("id"))`);
await queryRunner.query(`ALTER TABLE "event_whitelists" ADD CONSTRAINT "FK_17ccbcee3723a35d6d691532c22" FOREIGN KEY ("eventId") REFERENCES "events"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "event_whitelists" DROP CONSTRAINT "FK_17ccbcee3723a35d6d691532c22"`);
await queryRunner.query(`DROP TABLE "event_whitelists"`);
}

}
2 changes: 1 addition & 1 deletion api/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,6 @@ export class AuthController {
@UseGuards(JwtAuthGuard)
me(@Req() req: Request) {
const user = req.user as UserEntity;
return this.userService.getUserById(user.id);
return this.userService.getUserWithSocialAccounts(user.id);
}
}
26 changes: 26 additions & 0 deletions api/src/event/dtos/whitelistDto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ArrayNotEmpty, IsArray, IsEnum, IsString, IsUUID, ValidateNested } from "class-validator";
import { Type } from "class-transformer";
import { WhitelistPlatform } from "../entities/event-whitelist.entity";

export class WhitelistEntryDto {
@IsString()
username: string;

@IsEnum(WhitelistPlatform)
platform: WhitelistPlatform;
}

export class AddToWhitelistDto {
@IsArray()
@ArrayNotEmpty()
@ValidateNested({ each: true })
@Type(() => WhitelistEntryDto)
entries: WhitelistEntryDto[];
}

export class BulkDeleteWhitelistDto {
@IsArray()
@ArrayNotEmpty()
@IsUUID("4", { each: true })
ids: string[];
}
36 changes: 36 additions & 0 deletions api/src/event/entities/event-whitelist.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {
Entity,
Column,
PrimaryGeneratedColumn,
CreateDateColumn,
ManyToOne,
Unique,
} from "typeorm";
import { EventEntity } from "./event.entity";

export enum WhitelistPlatform {
GITHUB = "GITHUB",
FORTYTWO = "FORTYTWO",
}

@Entity("event_whitelists")
@Unique(["event", "username", "platform"])
export class EventWhitelistEntity {
@PrimaryGeneratedColumn("uuid")
id: string;

@Column({ type: "text" })
platform: WhitelistPlatform;

@Column()
username: string;

@ManyToOne(() => EventEntity, {
onDelete: "CASCADE",
nullable: false,
})
event: EventEntity;

@CreateDateColumn()
createdAt: Date;
}
6 changes: 6 additions & 0 deletions api/src/event/entities/event.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import { TeamEntity } from "../../team/entities/team.entity";
import { Exclude } from "class-transformer";
import { EventStarterTemplateEntity } from "./event-starter-template.entity";
import { EventWhitelistEntity } from "./event-whitelist.entity";

@Entity("events")
export class EventEntity {
Expand Down Expand Up @@ -121,4 +122,9 @@ export class EventEntity {
cascade: true,
})
starterTemplates: EventStarterTemplateEntity[];

@OneToMany(() => EventWhitelistEntity, (whitelist) => whitelist.event, {
onDelete: "CASCADE",
})
whitelists: EventWhitelistEntity[];
}
99 changes: 99 additions & 0 deletions api/src/event/event.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import { SetLockTeamsDateDto } from "./dtos/setLockTeamsDateDto";
import { UpdateEventSettingsDto } from "./dtos/updateEventSettingsDto";
import { CreateEventStarterTemplateDto } from "./dtos/createEventStarterTemplateDto";
import { UpdateEventStarterTemplateDto } from "./dtos/updateEventStarterTemplateDto";
import { AddToWhitelistDto, BulkDeleteWhitelistDto } from "./dtos/whitelistDto";
import { JwtAuthGuard } from "../auth/jwt-auth.guard";
import { UserId } from "../guards/UserGuard";
import { SocialPlatform } from "src/user/entities/social-account.entity";

@Controller("event")
export class EventController {
Expand Down Expand Up @@ -169,6 +171,28 @@ export class EventController {
);
}

const event = await this.eventService.getEventById(eventId);

if (event.isPrivate) {
const user = await this.userService.getUserWithSocialAccounts(userId);
const socialAccounts = user.socialAccounts || [];
const fortyTwoAccount = socialAccounts.find(
(sa) => sa.platform === SocialPlatform.FORTYTWO,
);

const isWhitelisted = await this.eventService.isUserWhitelisted(
eventId,
user.username,
fortyTwoAccount?.username || null,
);

if (!isWhitelisted) {
throw new UnauthorizedException(
"You are not whitelisted for this private event.",
);
}
}
Comment thread
Peu77 marked this conversation as resolved.

this.logger.log({ action: "attempt_join_event", userId, eventId });

return this.userService.joinEvent(userId, eventId);
Expand Down Expand Up @@ -377,4 +401,79 @@ export class EventController {
});
return this.eventService.deleteStarterTemplate(eventId, templateId);
}

@UseGuards(JwtAuthGuard)
@Get(":id/whitelist")
async getWhitelist(
@Param("id", new ParseUUIDPipe()) eventId: string,
@UserId() userId: string,
) {
if (!(await this.eventService.isEventAdmin(eventId, userId))) {
throw new UnauthorizedException("You are not an admin of this event");
}
return this.eventService.getWhitelist(eventId);
}

@UseGuards(JwtAuthGuard)
@Post(":id/whitelist")
async addToWhitelist(
@Param("id", new ParseUUIDPipe()) eventId: string,
@UserId() userId: string,
@Body() body: AddToWhitelistDto,
) {
if (!(await this.eventService.isEventAdmin(eventId, userId))) {
throw new UnauthorizedException("You are not an admin of this event");
}

this.logger.log({
action: "attempt_add_to_whitelist",
userId,
eventId,
entriesCount: body.entries.length,
});

return this.eventService.addToWhitelist(eventId, body.entries);
}

@UseGuards(JwtAuthGuard)
@Delete(":id/whitelist/:whitelistId")
async removeFromWhitelist(
@Param("id", new ParseUUIDPipe()) eventId: string,
@Param("whitelistId", new ParseUUIDPipe()) whitelistId: string,
@UserId() userId: string,
) {
if (!(await this.eventService.isEventAdmin(eventId, userId))) {
throw new UnauthorizedException("You are not an admin of this event");
}

this.logger.log({
action: "attempt_remove_from_whitelist",
userId,
eventId,
whitelistId,
});

return this.eventService.removeFromWhitelist(eventId, whitelistId);
}

@UseGuards(JwtAuthGuard)
@Post(":id/whitelist/bulk-delete")
async bulkRemoveFromWhitelist(
@Param("id", new ParseUUIDPipe()) eventId: string,
@UserId() userId: string,
@Body() body: BulkDeleteWhitelistDto,
) {
if (!(await this.eventService.isEventAdmin(eventId, userId))) {
throw new UnauthorizedException("You are not an admin of this event");
}

this.logger.log({
action: "attempt_bulk_remove_from_whitelist",
userId,
eventId,
idsCount: body.ids.length,
});

return this.eventService.bulkRemoveFromWhitelist(eventId, body.ids);
}
}
2 changes: 2 additions & 0 deletions api/src/event/event.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import { UserEventPermissionEntity } from "../user/entities/user.entity";
import { CheckController } from "./check.controller";

import { EventStarterTemplateEntity } from "./entities/event-starter-template.entity";
import { EventWhitelistEntity } from "./entities/event-whitelist.entity";

@Module({
imports: [
TypeOrmModule.forFeature([
EventEntity,
UserEventPermissionEntity,
EventStarterTemplateEntity,
EventWhitelistEntity,
]),
UserModule,
forwardRef(() => TeamModule),
Expand Down
Loading
Loading