-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Project create limit #148
Project create limit #148
Conversation
WalkthroughThis update introduces daily rate limiting for project creation. A new module defines the project creation limit, associated error codes, and a custom exception. The service layer now includes methods to check if a user can create a project and to calculate the remaining limit. Additionally, a new GraphQL query returns the user's remaining project creation allowance. Changes
Sequence Diagram(s)sequenceDiagram
participant U as User
participant R as ProjectsResolver
participant S as ProjectService
participant DB as Database
U->>R: Query getRemainingProjectLimit(userId)
R->>S: Call getRemainingProjectLimit(userId)
S->>DB: Count projects created between start and end of day
DB-->>S: Return project count
S-->>R: Calculate and return remaining limit
R-->>U: Return integer response
sequenceDiagram
participant U as User
participant R as ProjectsResolver
participant S as ProjectService
participant DB as Database
U->>R: Request createProject
R->>S: Call createProject(userId, projectData)
S->>S: Invoke canCreateProject(userId)
S->>DB: Query today's project count
DB-->>S: Return count
alt Under daily limit
S-->>R: Proceed with project creation
R-->>U: Project created successfully
else Limit exceeded
S-->>R: Throw ProjectRateLimitException
R-->>U: Return GraphQL error (DAILY_LIMIT_EXCEEDED)
end
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure. 🔧 ESLint
backend/src/project/project.service.tsOops! Something went wrong! :( ESLint: 8.57.1 ESLint couldn't find the plugin "eslint-plugin-prettier". (The package "eslint-plugin-prettier" was not found when loaded as a Node module from the directory "/backend".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
The plugin "eslint-plugin-prettier" was referenced from the config file in "backend/.eslintrc.js". If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team. backend/src/project/project.resolver.tsOops! Something went wrong! :( ESLint: 8.57.1 ESLint couldn't find the plugin "eslint-plugin-prettier". (The package "eslint-plugin-prettier" was not found when loaded as a Node module from the directory "/backend".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
The plugin "eslint-plugin-prettier" was referenced from the config file in "backend/.eslintrc.js". If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team. backend/src/project/project-limits.tsOops! Something went wrong! :( ESLint: 8.57.1 ESLint couldn't find the plugin "eslint-plugin-prettier". (The package "eslint-plugin-prettier" was not found when loaded as a Node module from the directory "/backend".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
The plugin "eslint-plugin-prettier" was referenced from the config file in "backend/.eslintrc.js". If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team. ✨ Finishing Touches
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
backend/src/project/project-limits.ts (1)
4-4
: Consider making the limit configurableThe hardcoded daily limit of 3 is reasonable for many use cases, but consider making this configurable via environment variables for greater flexibility.
-export const PROJECT_DAILY_LIMIT = 3; // Maximum number of projects a user can create per day +export const PROJECT_DAILY_LIMIT = parseInt(process.env.PROJECT_DAILY_LIMIT || '3', 10); // Maximum number of projects a user can create per daybackend/src/project/project.service.ts (2)
644-665
: Well-implemented method to get remaining project limitThe
getRemainingProjectLimit
method:
- Sets the date range correctly for "today"
- Counts projects created today
- Calculates the remaining limit
- Ensures the result is non-negative with Math.max
- Is well-documented with proper JSDoc comments
However, there's duplicated logic between this method and
canCreateProject
. Consider extracting the common date range and counting logic to a private helper method.+ /** + * Helper method to count projects created by a user today + * @param userId The user ID to check + * @returns The count of projects created today by the user + */ + private async countProjectsCreatedToday(userId: string): Promise<number> { + const today = new Date(); + today.setHours(0, 0, 0, 0); // Start of today + + const tomorrow = new Date(today); + tomorrow.setDate(tomorrow.getDate() + 1); // Start of tomorrow + + return this.projectsRepository.count({ + where: { + userId: userId, + createdAt: Between(today, tomorrow), + }, + }); + } + /** * Checks if a user has exceeded their daily project creation limit * @param userId The user ID to check * @returns A boolean indicating whether the user can create more projects today */ async canCreateProject(userId: string): Promise<boolean> { - const today = new Date(); - today.setHours(0, 0, 0, 0); // Start of today - - const tomorrow = new Date(today); - tomorrow.setDate(tomorrow.getDate() + 1); // Start of tomorrow - - // Count projects created by user today - const todayProjectCount = await this.projectsRepository.count({ - where: { - userId: userId, - createdAt: Between(today, tomorrow), - }, - }); + const todayProjectCount = await this.countProjectsCreatedToday(userId); return todayProjectCount < PROJECT_DAILY_LIMIT; } // ... other methods ... /** * Gets the number of projects a user can still create today * @param userId The user ID to check * @returns The number of remaining projects the user can create today */ async getRemainingProjectLimit(userId: string): Promise<number> { - const today = new Date(); - today.setHours(0, 0, 0, 0); // Start of today - - const tomorrow = new Date(today); - tomorrow.setDate(tomorrow.getDate() + 1); // Start of tomorrow - - // Count projects created by this user today - const todayProjectCount = await this.projectsRepository.count({ - where: { - userId: userId, - createdAt: Between(today, tomorrow), - }, - }); + const todayProjectCount = await this.countProjectsCreatedToday(userId); return Math.max(0, PROJECT_DAILY_LIMIT - todayProjectCount); }
132-138
: Consider time zone handling for daily limitsThe current implementation uses the server's local time zone to determine "today". This could lead to inconsistent behavior if the server and users are in different time zones.
Consider either:
- Using UTC consistently for all date calculations
- Using the user's time zone (if stored in their profile)
For a consistent experience across all users:
async canCreateProject(userId: string): Promise<boolean> { - const today = new Date(); + const today = new Date(Date.now()); today.setHours(0, 0, 0, 0); // Start of today const tomorrow = new Date(today); tomorrow.setDate(tomorrow.getDate() + 1); // Start of tomorrowThen make the same change in
getRemainingProjectLimit
method.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
backend/src/project/project-limits.ts
(1 hunks)backend/src/project/project.resolver.ts
(2 hunks)backend/src/project/project.service.ts
(5 hunks)
🔇 Additional comments (10)
backend/src/project/project.resolver.ts (2)
10-10
: New import added for Int GraphQL typeThis import is correctly added to support the new query method returning an integer value.
151-158
: GraphQL query implementation looks goodThe implementation properly:
- Uses the
@Query(() => Int)
decorator to specify the return type- Uses the existing
@GetUserIdFromToken()
decorator to authenticate the user- Delegates to the service layer implementation
- Returns the result as a Promise
This follows the established patterns in the codebase.
backend/src/project/project-limits.ts (3)
1-3
: Proper imports for exception handling and GraphQLThe imports correctly include the necessary NestJS exception types and GraphQL error handling.
6-8
: Error code enum looks goodWell-defined error code that clearly indicates the nature of the error.
10-26
: Well-implemented custom exception classThe
ProjectRateLimitException
class:
- Properly extends ForbiddenException
- Has a clear error message that includes the limit
- Provides a GraphQL-specific error format via getGraphQLError()
- Returns the appropriate HTTP status code (TOO_MANY_REQUESTS)
This implementation follows best practices for error handling in GraphQL APIs.
backend/src/project/project.service.ts (5)
10-10
: Updated TypeORM import to include Between operatorThe Between operator is correctly imported for date range queries.
29-32
: Properly imported project limits constantsThe new imports from the project-limits.ts file are correctly added.
127-148
: Well-implemented daily limit check methodThe
canCreateProject
method:
- Sets the date range correctly for "today" (midnight to midnight)
- Uses the TypeORM Between operator appropriately
- Compares against the defined daily limit
- Is well-documented with proper JSDoc comments
This implementation for checking the daily limit is clear and correct.
155-159
: Properly integrated limit check into createProjectThe limit check is correctly placed at the beginning of the method before any resource-intensive operations, ensuring users can't bypass the limit.
201-203
: Good error handling for rate limit exceptionsThe error handling correctly:
- Checks if the error is a ProjectRateLimitException
- Uses the custom getGraphQLError() method to format the error appropriately for GraphQL clients
This ensures the client receives a proper GraphQL error with the right code and message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
<!-- 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 -->
Summary by CodeRabbit