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

Added certificate and user certificate module #23

Merged
merged 1 commit into from
Feb 21, 2025

Conversation

arati-tekdi
Copy link
Collaborator

No description provided.

Copy link

coderabbitai bot commented Feb 20, 2025

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Introduced certificate management capabilities including digital identity generation, credential schema and template creation, certificate issuance, and certificate rendering.
    • Added user certificate functionalities that enable course enrollment, certificate status updates, and course search.

Walkthrough

The changes add two modules to the application: one for certificate management and another for user certificate enrollment and management. The new CertificateModule includes a controller, service, DTO, and an entity to handle operations such as generating DIDs, creating credential schemas, templates, issuing, and rendering certificates. The UserCertificateModule provides endpoints and a service to enroll users in courses, update and fetch certificate statuses, and search courses. Both modules integrate with TypeORM using a shared certificate entity while being incorporated into the main AppModule.

Changes

File(s) Change Summary
src/app.module.ts Updated to import the new CertificateModule and UserCertificateModule.
src/.../certificate/*.ts Added new certificate components: CertificateController with endpoints (generateDid, createCredentialSchema, createTemplate, issueCertificate, renderCertificate), CertificateModule, CertificateService, IssueCredentialDto, and UserCourseCertificate entity.
src/.../user_certificate/*.ts Added new user certificate components: UserCertificateController with endpoints (enrollUserForCourse, updateUserStatusForCourse, fetchUserStatusForCourse, searchUsersCourses), UserCertificateModule, UserCertificateService, and CreateCertificateDto.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant CertController as CertificateController
    participant CertService as CertificateService
    participant ExternalAPI as External API

    Client->>CertController: POST /certificate/generateDid
    CertController->>CertService: generateDid(userId)
    CertService->>ExternalAPI: POST request to generate DID
    ExternalAPI-->>CertService: DID response
    CertService-->>CertController: returns generated DID
    CertController-->>Client: Response with DID
Loading
sequenceDiagram
    participant Client
    participant UserCertController as UserCertificateController
    participant UserCertService as UserCertificateService
    participant Database as TypeORM Repository

    Client->>UserCertController: POST /user_certificate/enrollUserForCourse
    UserCertController->>UserCertService: enrollUserForCourse(dto)
    UserCertService->>Database: Check for existing certificate
    Database-->>UserCertService: Existing record or empty
    UserCertService->>Database: Insert new certificate record
    Database-->>UserCertService: Confirmation
    UserCertService-->>UserCertController: Operation result
    UserCertController-->>Client: Success/Error response
Loading
✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

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. (Beta)
  • @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.

Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
7.9% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Copy link

@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: 13

🧹 Nitpick comments (14)
src/modules/user_certificate/user_certificate.service..ts (2)

27-27: Use 'const' instead of 'let' for variables not reassigned

Variables like apiId and data are never reassigned. Declaring them with const clarifies immutability:

- let apiId = 'api.create.userEnrollment';
+ const apiId = 'api.create.userEnrollment';

- let data = new UserCourseCertificate();
+ const data = new UserCourseCertificate();

Also applies to: 40-40, 88-88, 112-112, 154-154, 208-208

🧰 Tools
🪛 ESLint

[error] 27-27: 'apiId' is never reassigned. Use 'const' instead.

(prefer-const)


206-206: Remove unused 'request' parameter

In searchUsersCourses, request is never read. Remove it to streamline function parameters:

- async searchUsersCourses(searchObj, response, request) {
+ async searchUsersCourses(searchObj, response) {
🧰 Tools
🪛 ESLint

[error] 206-206: 'request' is defined but never used.

(@typescript-eslint/no-unused-vars)

src/modules/certificate/certificate.service.ts (4)

20-20: Use 'const' instead of 'let' for 'apiId'

apiId variables are never reassigned, so they should be declared with const:

- let apiId = 'api.generate.did';
+ const apiId = 'api.generate.did';

Also applies to: 188-188

🧰 Tools
🪛 ESLint

[error] 20-20: 'apiId' is never reassigned. Use 'const' instead.

(prefer-const)


191-191: Use 'const' for 'learnerDid'

learnerDid is never reassigned, reflecting immutability more accurately with const:

- let learnerDid = await this.generateDidByUserId(issueCredential.userId);
+ const learnerDid = await this.generateDidByUserId(issueCredential.userId);
🧰 Tools
🪛 ESLint

[error] 191-191: 'learnerDid' is never reassigned. Use 'const' instead.

(prefer-const)


232-232: Remove or utilize 'updateResponse'

updateResponse is declared but not referenced. Remove it if unnecessary:

- const updateResponse = await this.updateUserCertificate({ ... });
🧰 Tools
🪛 ESLint

[error] 232-232: 'updateResponse' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)


283-283: Use 'const' instead of 'let' for 'url'

url is never reassigned, so const is more consistent and clearer:

- let url = ...
+ const url = ...
🧰 Tools
🪛 ESLint

[error] 283-283: 'url' is never reassigned. Use 'const' instead.

(prefer-const)

src/modules/user_certificate/dto/create-user-certificate-dto.ts (1)

25-27: Add a transformer for the 'issuedOn' date field

When using @IsDate(), apply @Type(() => Date) from class-transformer to handle JSON string-to-date conversion:

+ import { Type } from 'class-transformer';

  @IsOptional()
+ @Type(() => Date)
  @IsDate()
  issuedOn?: Date;
src/modules/certificate/dto/issue-certificate-dto.ts (3)

20-22: Remove redundant validation on userId.

The @IsString() decorator is redundant here since @IsUUID() already ensures the value is a valid UUID string.

  @IsUUID()
- @IsString()
  userId: string;

24-25: Add UUID validation for courseId.

Consider adding @IsUUID() validation to ensure courseId is a valid UUID.

+ @IsUUID()
  @IsString()
  courseId: string;

3-29: Add validation messages for better error handling.

Consider adding custom validation messages to improve error feedback.

Example:

  @IsDateString({}, {
+   message: 'Issuance date must be a valid ISO date string'
  })
  issuanceDate: string;
src/modules/user_certificate/user_certificate.module.ts (1)

7-7: Use relative paths for imports within the same module.

Consider using relative paths for consistency when importing from the same module.

- import { LoggerService } from 'src/common/logger/logger.service';
+ import { LoggerService } from '../../../common/logger/logger.service';
src/modules/certificate/certificate.module.ts (1)

6-7: Use relative paths for imports within the same module.

Consider using relative paths for consistency when importing from the same module.

- import { LoggerService } from 'src/common/logger/logger.service';
- import { AxiosRequest } from 'src/common/middleware/axios.middleware';
+ import { LoggerService } from '../../common/logger/logger.service';
+ import { AxiosRequest } from '../../common/middleware/axios.middleware';
src/modules/certificate/entities/user_course_certificate.ts (1)

9-45: Add indexes for better query performance.

Consider adding indexes for frequently queried columns like userId, courseId, and status.

+ import { Index } from 'typeorm';

  @Entity({ name: 'user_course_certificate' })
+ @Index(['userId'])
+ @Index(['courseId'])
+ @Index(['status'])
  export class UserCourseCertificate {
    // ... existing code ...
  }
src/modules/certificate/certificate.contoller.ts (1)

70-70: Use consistent async/await pattern.

Some methods use await while others don't. Since these are asynchronous operations, consistently use await:

-return this.certificateService.generateDid(
+return await this.certificateService.generateDid(

-return this.certificateService.createCredentialSchema(
+return await this.certificateService.createCredentialSchema(

-return this.certificateService.createTemplate(
+return await this.certificateService.createTemplate(

Also applies to: 85-85

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6d95808 and 862a1eb.

📒 Files selected for processing (10)
  • src/app.module.ts (2 hunks)
  • src/modules/certificate/certificate.contoller.ts (1 hunks)
  • src/modules/certificate/certificate.module.ts (1 hunks)
  • src/modules/certificate/certificate.service.ts (1 hunks)
  • src/modules/certificate/dto/issue-certificate-dto.ts (1 hunks)
  • src/modules/certificate/entities/user_course_certificate.ts (1 hunks)
  • src/modules/user_certificate/dto/create-user-certificate-dto.ts (1 hunks)
  • src/modules/user_certificate/user_certificate.contoller.ts (1 hunks)
  • src/modules/user_certificate/user_certificate.module.ts (1 hunks)
  • src/modules/user_certificate/user_certificate.service..ts (1 hunks)
🧰 Additional context used
🪛 ESLint
src/modules/certificate/certificate.contoller.ts

[error] 1-1: 'UseGuards' is defined but never used.

(@typescript-eslint/no-unused-vars)

src/modules/certificate/certificate.service.ts

[error] 20-20: 'apiId' is never reassigned. Use 'const' instead.

(prefer-const)


[error] 188-188: 'apiId' is never reassigned. Use 'const' instead.

(prefer-const)


[error] 191-191: 'learnerDid' is never reassigned. Use 'const' instead.

(prefer-const)


[error] 232-232: 'updateResponse' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)


[error] 283-283: 'url' is never reassigned. Use 'const' instead.

(prefer-const)

src/modules/user_certificate/user_certificate.service..ts

[error] 11-11: 'axios' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)


[error] 11-11: Require statement not part of import statement.

(@typescript-eslint/no-var-requires)


[error] 27-27: 'apiId' is never reassigned. Use 'const' instead.

(prefer-const)


[error] 40-40: 'data' is never reassigned. Use 'const' instead.

(prefer-const)


[error] 88-88: 'apiId' is never reassigned. Use 'const' instead.

(prefer-const)


[error] 112-112: 'updateResult' is never reassigned. Use 'const' instead.

(prefer-const)


[error] 154-154: 'apiId' is never reassigned. Use 'const' instead.

(prefer-const)


[error] 206-206: 'request' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 208-208: 'apiId' is never reassigned. Use 'const' instead.

(prefer-const)

🔇 Additional comments (2)
src/modules/user_certificate/user_certificate.service..ts (1)

215-235: Verify dynamic filters to prevent potential SQL injection

Although TypeORM uses parameterized queries, confirm filters does not allow injection of raw SQL. I can generate a verification script if needed.

src/app.module.ts (1)

10-11: LGTM!

The new certificate modules are properly imported and integrated into the AppModule following the established pattern.

Also applies to: 20-21

Comment on lines +60 to +61
'User already enrolled for course',
HttpStatus.OK,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Return a correct status code for error responses

These blocks return HttpStatus.OK while delivering an error message, which can confuse API clients. Consider HttpStatus.CONFLICT or HttpStatus.BAD_REQUEST instead:

- HttpStatus.OK,
+ HttpStatus.CONFLICT,

Also applies to: 134-137, 189-190

import APIResponse from 'src/common/utils/response';
import { LoggerService } from 'src/common/logger/logger.service';
import { ConfigService } from '@nestjs/config';
const axios = require('axios');
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove unused 'axios' import to comply with best practices

ESLint complains that axios is declared but never used. If you don’t need it, remove it:

- const axios = require('axios');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const axios = require('axios');
🧰 Tools
🪛 ESLint

[error] 11-11: 'axios' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)


[error] 11-11: Require statement not part of import statement.

(@typescript-eslint/no-var-requires)

Comment on lines +2 to +3
import { UserCertificateController } from './user_certificate.contoller';
import { UserCertificateService } from './user_certificate.service.';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix typos in import paths.

There are typos in the import paths:

  • .contoller should be .controller
  • .service. has an extra dot
- import { UserCertificateController } from './user_certificate.contoller';
- import { UserCertificateService } from './user_certificate.service.';
+ import { UserCertificateController } from './user_certificate.controller';
+ import { UserCertificateService } from './user_certificate.service';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { UserCertificateController } from './user_certificate.contoller';
import { UserCertificateService } from './user_certificate.service.';
import { UserCertificateController } from './user_certificate.controller';
import { UserCertificateService } from './user_certificate.service';

@@ -0,0 +1,14 @@
import { Module } from '@nestjs/common';
import { CertificateService } from './certificate.service';
import { CertificateController } from './certificate.contoller';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix typo in controller import path.

There's a typo in the import path: .contoller should be .controller

- import { CertificateController } from './certificate.contoller';
+ import { CertificateController } from './certificate.controller';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { CertificateController } from './certificate.contoller';
import { CertificateController } from './certificate.controller';

Comment on lines +17 to +18
@Column()
courseId: string;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use consistent UUID type for ID columns.

The courseId and certificateId columns should use the UUID type for consistency with other ID columns.

  @Column()
- courseId: string;
+ @Column({ type: 'uuid' })
+ courseId: string;

  @Column()
- certificateId: string;
+ @Column({ type: 'uuid' })
+ certificateId: string;

Also applies to: 23-24

@ApiBadRequestResponse({ description: 'Bad Request.' })
@Post('status/search')
async searchUsersCourses(
@Body() searchObj: Record<string, any>,
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Define a DTO for search parameters.

Using Record<string, any> loses type safety and validation capabilities. Create a proper DTO to define and validate the search parameters.

Example:

// search-courses.dto.ts
export class SearchCoursesDto {
  @IsOptional()
  @IsString()
  courseId?: string;

  @IsOptional()
  @IsString()
  userId?: string;

  // Add other search parameters
}

ApiOkResponse,
} from '@nestjs/swagger';
import { Response } from 'express';
import { UserCertificateService } from './user_certificate.service..js';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix the import path typo.

The service import has a typo in the file extension and an extra dot:

-import { UserCertificateService } from './user_certificate.service..js';
+import { UserCertificateService } from './user_certificate.service';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { UserCertificateService } from './user_certificate.service..js';
import { UserCertificateService } from './user_certificate.service';

@ApiBadRequestResponse({ description: 'Bad Request.' })
@Post('generateDid')
async generateDid(
@Body() createCertificateDto: any,
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Define proper DTOs for request validation.

Using any type loses type safety and validation capabilities. Create proper DTOs for each operation:

// generate-did.dto.ts
export class GenerateDidDto {
  @IsString()
  @IsNotEmpty()
  userId: string;
}

// create-schema.dto.ts
export class CreateSchemaDto {
  @IsObject()
  @IsNotEmpty()
  schema: Record<string, unknown>;
}

// create-template.dto.ts
export class CreateTemplateDto {
  @IsString()
  @IsNotEmpty()
  schemaId: string;

  @IsObject()
  @IsNotEmpty()
  template: Record<string, unknown>;
}

// render-certificate.dto.ts
export class RenderCertificateDto {
  @IsString()
  @IsNotEmpty()
  credentialId: string;

  @IsString()
  @IsNotEmpty()
  templateId: string;
}

Also applies to: 35-35, 50-50, 82-82

Comment on lines +20 to +28
async generateDid(
@Body() createCertificateDto: any,
@Res() response: Response,
) {
return this.certificateService.generateDid(
createCertificateDto.userId,
response,
);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Follow NestJS best practices for response handling.

Similar to the user certificate controller, avoid using Express's Response object directly and let NestJS handle the response transformation:

Example refactor:

 async generateDid(
-  @Body() createCertificateDto: any,
+  @Body() createCertificateDto: GenerateDidDto,
-  @Res() response: Response,
 ) {
-  return this.certificateService.generateDid(
+  return await this.certificateService.generateDid(
     createCertificateDto.userId,
-    response,
   );
 }

Apply similar changes to other methods.

Also applies to: 34-42, 49-58, 65-75, 81-90

@@ -0,0 +1,91 @@
import { Controller, Post, Body, Res, UseGuards, Req } from '@nestjs/common';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove unused import.

The UseGuards import is not used in this file.

-import { Controller, Post, Body, Res, UseGuards, Req } from '@nestjs/common';
+import { Controller, Post, Body, Res, Req } from '@nestjs/common';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { Controller, Post, Body, Res, UseGuards, Req } from '@nestjs/common';
import { Controller, Post, Body, Res, Req } from '@nestjs/common';
🧰 Tools
🪛 ESLint

[error] 1-1: 'UseGuards' is defined but never used.

(@typescript-eslint/no-unused-vars)

@rushi-tekdi rushi-tekdi merged commit b8fe723 into tekdi:main Feb 21, 2025
2 of 3 checks passed
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