Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions db/migrations/20250818000000_add_teams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ import { Knex } from "knex";

export async function up(knex: Knex): Promise<void> {
await knex.schema.createTable("teams", (table) => {
table
.uuid("hackathon_id")
.notNullable()
.references("id")
.inTable("hackathons")
.onDelete("CASCADE")
.onUpdate("CASCADE");
table.uuid("id").primary().notNullable();
table.string("name").notNullable();
table
Expand Down
5 changes: 5 additions & 0 deletions src/entities/team.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import { IsBoolean, IsOptional, IsString } from "class-validator";
name: "teams",
})
export class Team extends Entity {
@ApiProperty()
@IsString()
@Column({ type: "string" })
hackathonId: string;
@ApiProperty()
@IsString()
@ID({ type: "string" })
Expand Down Expand Up @@ -55,6 +59,7 @@ export class Team extends Entity {

export class TeamEntity extends PickType(Team, [
"id",
"hackathonId",
"name",
"member1",
"member2",
Expand Down
57 changes: 46 additions & 11 deletions src/modules/team/team.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
Param,
Patch,
Post,
Query,
UseFilters,
ValidationPipe,
} from "@nestjs/common";
Expand All @@ -20,10 +21,12 @@ import { Role, Roles } from "common/gcp";
import { ApiDoc } from "common/docs";
import { DBExceptionFilter } from "common/filters";
import { IsEmail, IsOptional, IsString } from "class-validator";
import { Transform } from "class-transformer";
import { nanoid } from "nanoid";

class TeamCreateEntity extends OmitType(TeamEntity, [
"id",
"hackathonId",
"isActive",
] as const) {}

Expand Down Expand Up @@ -60,6 +63,25 @@ class AddUserByEmailEntity {
email: string;
}

class ActiveTeamsParams {
@ApiProperty({
required: false,
description: "active can either be a boolean or undefined",
})
@IsOptional()
@Transform(({ value }) => {
switch (value) {
case "true":
return true;
case "false":
return false;
default:
return undefined;
}
})
active?: boolean;
}

@ApiTags("Teams")
@Controller("teams")
@UseFilters(DBExceptionFilter)
Expand All @@ -75,13 +97,26 @@ export class TeamController {
@Roles(Role.NONE)
@ApiDoc({
summary: "Get All Teams",
query: [
{
name: "active",
type: ActiveTeamsParams,
},
],
response: {
ok: { type: [TeamEntity] },
},
auth: Role.TEAM,
})
async getAll() {
return this.teamRepo.findAll().exec();
async getAll(
@Query(new ValidationPipe({ transform: true }))
{ active }: ActiveTeamsParams,
) {
if (active === undefined || active === true) {
return this.teamRepo.findAll().byHackathon();
} else if (active === false) {
return this.teamRepo.findAll().exec();
}
}

@Post("/")
Expand Down Expand Up @@ -136,11 +171,11 @@ export class TeamController {
throw new BadRequestException("Duplicate members are not allowed");
}

// Check if any user is already in another team
// Check if any user is already in another team in the current hackathon
if (memberIds.length > 0) {
const existingTeams = await this.teamRepo
.findAll()
.raw()
.byHackathon()
.where((builder) => {
memberIds.forEach((memberId) => {
builder
Expand All @@ -154,7 +189,7 @@ export class TeamController {

if (existingTeams.length > 0) {
const conflictingUser = memberIds.find((memberId) =>
existingTeams.some((team) =>
existingTeams.some((team: any) =>
[
team.member1,
team.member2,
Expand All @@ -176,7 +211,7 @@ export class TeamController {
isActive: true,
...data,
})
.exec();
.byHackathon();

return team;
}
Expand Down Expand Up @@ -273,15 +308,15 @@ export class TeamController {
throw new BadRequestException("Team cannot have more than 5 members");
}

// Check if any new user is already in another team
// Check if any new user is already in another team in the current hackathon
const newMemberIds = memberFields
.filter((field) => data[field] && data[field] !== existingTeam[field])
.map((field) => data[field]);

if (newMemberIds.length > 0) {
const existingTeams = await this.teamRepo
.findAll()
.raw()
.byHackathon()
.where((builder) => {
newMemberIds.forEach((memberId) => {
builder
Expand All @@ -296,7 +331,7 @@ export class TeamController {

if (existingTeams.length > 0) {
const conflictingUser = newMemberIds.find((memberId) =>
existingTeams.some((team) =>
existingTeams.some((team: any) =>
[
team.member1,
team.member2,
Expand Down Expand Up @@ -380,10 +415,10 @@ export class TeamController {
throw new BadRequestException("User is already a member of this team");
}

// Check if user is already in any other team
// Check if user is already in any other team in the current hackathon
const existingTeams = await this.teamRepo
.findAll()
.raw()
.byHackathon()
.where((builder) => {
builder
.where("member1", user.id)
Expand Down