Skip to content

Commit b616285

Browse files
authored
Project create limit (#148)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a daily limit for project creation, capping the number of new projects a user can create per day. - Added a new query endpoint that lets users check how many projects they can still create today. - Enhanced error notifications to clearly inform users when their daily project creation limit has been reached. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 7136304 commit b616285

File tree

3 files changed

+98
-2
lines changed

3 files changed

+98
-2
lines changed

backend/src/project/project-limits.ts

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { ForbiddenException, HttpStatus } from '@nestjs/common';
2+
import { GraphQLError } from 'graphql';
3+
4+
export const PROJECT_DAILY_LIMIT = 3; // Maximum number of projects a user can create per day
5+
6+
export enum ProjectErrorCode {
7+
DAILY_LIMIT_EXCEEDED = 'DAILY_LIMIT_EXCEEDED',
8+
}
9+
10+
export class ProjectRateLimitException extends ForbiddenException {
11+
constructor(limit: number) {
12+
super(
13+
`Daily project creation limit of ${limit} reached. Please try again tomorrow.`,
14+
);
15+
}
16+
17+
getGraphQLError(): GraphQLError {
18+
return new GraphQLError(this.message, {
19+
extensions: {
20+
code: ProjectErrorCode.DAILY_LIMIT_EXCEEDED,
21+
limit: PROJECT_DAILY_LIMIT,
22+
status: HttpStatus.TOO_MANY_REQUESTS,
23+
},
24+
});
25+
}
26+
}

backend/src/project/project.resolver.ts

+9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
ResolveField,
88
Parent,
99
ID,
10+
Int,
1011
} from '@nestjs/graphql';
1112
import { ProjectService } from './project.service';
1213
import { Project } from './project.model';
@@ -147,4 +148,12 @@ export class ProjectsResolver {
147148
): Promise<Project[]> {
148149
return this.projectService.fetchPublicProjects(input);
149150
}
151+
152+
// In ProjectsResolver:
153+
@Query(() => Int)
154+
async getRemainingProjectLimit(
155+
@GetUserIdFromToken() userId: string,
156+
): Promise<number> {
157+
return this.projectService.getRemainingProjectLimit(userId);
158+
}
150159
}

backend/src/project/project.service.ts

+63-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
ForbiddenException,
88
} from '@nestjs/common';
99
import { InjectRepository } from '@nestjs/typeorm';
10-
import { In, Not, Repository } from 'typeorm';
10+
import { Between, In, Not, Repository } from 'typeorm';
1111
import { Project } from './project.model';
1212
import { ProjectPackages } from './project-packages.model';
1313
import {
@@ -26,6 +26,11 @@ import { BuilderContext } from 'src/build-system/context';
2626
import { ChatService } from 'src/chat/chat.service';
2727
import { Chat } from 'src/chat/chat.model';
2828
import { v4 as uuidv4 } from 'uuid';
29+
import {
30+
PROJECT_DAILY_LIMIT,
31+
ProjectRateLimitException,
32+
} from './project-limits';
33+
2934
@Injectable()
3035
export class ProjectService {
3136
private readonly model: OpenAIModelProvider =
@@ -119,12 +124,41 @@ export class ProjectService {
119124
}
120125
}
121126

127+
/**
128+
* Checks if a user has exceeded their daily project creation limit
129+
* @param userId The user ID to check
130+
* @returns A boolean indicating whether the user can create more projects today
131+
*/
132+
async canCreateProject(userId: string): Promise<boolean> {
133+
const today = new Date();
134+
today.setHours(0, 0, 0, 0); // Start of today
135+
136+
const tomorrow = new Date(today);
137+
tomorrow.setDate(tomorrow.getDate() + 1); // Start of tomorrow
138+
139+
// Count projects created by user today
140+
const todayProjectCount = await this.projectsRepository.count({
141+
where: {
142+
userId: userId,
143+
createdAt: Between(today, tomorrow),
144+
},
145+
});
146+
147+
return todayProjectCount < PROJECT_DAILY_LIMIT;
148+
}
149+
122150
async createProject(
123151
input: CreateProjectInput,
124152
userId: string,
125153
): Promise<Chat> {
126154
try {
127-
// First, handle project name generation if needed (this is the only sync operation we need)
155+
//First check if user have reach the create project limit
156+
const canCreate = await this.canCreateProject(userId);
157+
if (!canCreate) {
158+
throw new ProjectRateLimitException(PROJECT_DAILY_LIMIT);
159+
}
160+
161+
// handle project name generation if needed (this is the only sync operation we need)
128162
let projectName = input.projectName;
129163
if (!projectName || projectName === '') {
130164
this.logger.debug(
@@ -164,6 +198,10 @@ export class ProjectService {
164198
// Return chat immediately so user can start interacting
165199
return defaultChat;
166200
} catch (error) {
201+
if (error instanceof ProjectRateLimitException) {
202+
throw error.getGraphQLError(); // Throw as a GraphQL error for the client
203+
}
204+
167205
this.logger.error(
168206
`Error in createProject: ${error.message}`,
169207
error.stack,
@@ -602,4 +640,27 @@ export class ProjectService {
602640

603641
return [];
604642
}
643+
644+
/**
645+
* Gets the number of projects a user can still create today
646+
* @param userId The user ID to check
647+
* @returns The number of remaining projects the user can create today
648+
*/
649+
async getRemainingProjectLimit(userId: string): Promise<number> {
650+
const today = new Date();
651+
today.setHours(0, 0, 0, 0); // Start of today
652+
653+
const tomorrow = new Date(today);
654+
tomorrow.setDate(tomorrow.getDate() + 1); // Start of tomorrow
655+
656+
// Count projects created by this user today
657+
const todayProjectCount = await this.projectsRepository.count({
658+
where: {
659+
userId: userId,
660+
createdAt: Between(today, tomorrow),
661+
},
662+
});
663+
664+
return Math.max(0, PROJECT_DAILY_LIMIT - todayProjectCount);
665+
}
605666
}

0 commit comments

Comments
 (0)