Skip to content
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

Merged
merged 1 commit into from
Mar 4, 2025
Merged

Project create limit #148

merged 1 commit into from
Mar 4, 2025

Conversation

ZHallen122
Copy link
Collaborator

@ZHallen122 ZHallen122 commented Mar 4, 2025

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.

@ZHallen122 ZHallen122 requested a review from Sma1lboy March 4, 2025 01:47
Copy link
Contributor

coderabbitai bot commented Mar 4, 2025

Walkthrough

This 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

File(s) Change Summary
backend/src/project/project-limits.ts, backend/src/project/project.service.ts Added daily project creation rate limiting. Defined PROJECT_DAILY_LIMIT, an enumeration ProjectErrorCode, and the ProjectRateLimitException (with getGraphQLError() method) in project-limits.ts. In project.service.ts, implemented canCreateProject and getRemainingProjectLimit methods and updated createProject to enforce the limit.
backend/src/project/project.resolver.ts Introduced a new GraphQL query method getRemainingProjectLimit in the ProjectsResolver class, which calls the service layer to determine the remaining number of projects a user can create.

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
Loading
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
Loading

Poem

I hopped through lines of code so neat,
Where project limits keep the flow complete.
Constants and checks, exceptions in sight,
Ensure our projects stay within their light.
With each query and creation, a gentle, timely beat,
This rabbit celebrates changes oh-so-sweet! 🐇

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

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

backend/src/project/project.service.ts

Oops! 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:

npm install eslint-plugin-prettier@latest --save-dev

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.ts

Oops! 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:

npm install eslint-plugin-prettier@latest --save-dev

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.ts

Oops! 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:

npm install eslint-plugin-prettier@latest --save-dev

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
  • 📝 Generate Docstrings

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?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@ZHallen122 ZHallen122 marked this pull request as ready for review March 4, 2025 01:50
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 configurable

The 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 day
backend/src/project/project.service.ts (2)

644-665: Well-implemented method to get remaining project limit

The getRemainingProjectLimit method:

  1. Sets the date range correctly for "today"
  2. Counts projects created today
  3. Calculates the remaining limit
  4. Ensures the result is non-negative with Math.max
  5. 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 limits

The 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:

  1. Using UTC consistently for all date calculations
  2. 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 tomorrow

Then make the same change in getRemainingProjectLimit method.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7136304 and 9642291.

📒 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 type

This import is correctly added to support the new query method returning an integer value.


151-158: GraphQL query implementation looks good

The implementation properly:

  1. Uses the @Query(() => Int) decorator to specify the return type
  2. Uses the existing @GetUserIdFromToken() decorator to authenticate the user
  3. Delegates to the service layer implementation
  4. 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 GraphQL

The imports correctly include the necessary NestJS exception types and GraphQL error handling.


6-8: Error code enum looks good

Well-defined error code that clearly indicates the nature of the error.


10-26: Well-implemented custom exception class

The ProjectRateLimitException class:

  1. Properly extends ForbiddenException
  2. Has a clear error message that includes the limit
  3. Provides a GraphQL-specific error format via getGraphQLError()
  4. 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 operator

The Between operator is correctly imported for date range queries.


29-32: Properly imported project limits constants

The new imports from the project-limits.ts file are correctly added.


127-148: Well-implemented daily limit check method

The canCreateProject method:

  1. Sets the date range correctly for "today" (midnight to midnight)
  2. Uses the TypeORM Between operator appropriately
  3. Compares against the defined daily limit
  4. 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 createProject

The 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 exceptions

The error handling correctly:

  1. Checks if the error is a ProjectRateLimitException
  2. 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.

Copy link
Owner

@Sma1lboy Sma1lboy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Sma1lboy Sma1lboy merged commit b616285 into main Mar 4, 2025
3 of 4 checks passed
PengyuChen01 pushed a commit that referenced this pull request Mar 5, 2025
<!-- 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 -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants