Skip to content

Commit

Permalink
feat: return certificate metadata if append .json to certificate id (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
apalchys authored Apr 25, 2024
1 parent 61b207d commit 14f10c0
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 9 deletions.
29 changes: 23 additions & 6 deletions nestjs/src/certificates/certificates.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,35 @@ export class CertificatesController {
private studentsService: StudentsService,
) {}

/**
* /certificate/abc - returns certificate in PDF format
* /certificate/abc.json - returns certificate metadata in JSON format
*/
@Get('/:publicId')
@ApiOperation({ operationId: 'getCertificate' })
public async getCertificate(@Param('publicId') publicId: string, @Res() res: Response) {
const certificate = await this.certificatesService.getByPublicId(publicId);
if (!certificate) throw new NotFoundException('not found');
const normalizedPublicId = publicId.endsWith('.json') ? publicId.slice(0, -5) : publicId;
const responseType = publicId.endsWith('.json') ? 'json' : 'pdf';

const certificate = await this.certificatesService.getByPublicId(normalizedPublicId);
if (!certificate) throw new NotFoundException();

try {
const stream = await this.certificatesService.getFileStream(certificate.s3Bucket, certificate.s3Key);
res.set('Content-Type', 'application/pdf');
stream.pipe(res);
switch (responseType) {
case 'json': {
const metadata = await this.certificatesService.getCertificateMetadata(certificate);
res.json(metadata);
break;
}
case 'pdf': {
const stream = await this.certificatesService.getFileStream(certificate.s3Bucket, certificate.s3Key);
res.set('Content-Type', 'application/pdf');
stream.pipe(res);
break;
}
}
} catch {
throw new NotFoundException('not found');
throw new NotFoundException();
}
}

Expand Down
3 changes: 2 additions & 1 deletion nestjs/src/certificates/certificates.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import { ConfigModule } from '../config';
import { CoursesModule } from '../courses/courses.module';
import { CertificatesController } from './certificates.controller';
import { CertificationsService } from './certificates.service';
import { User } from '@entities/user';

@Module({
imports: [
TypeOrmModule.forFeature([Certificate, Student, Course]),
TypeOrmModule.forFeature([Certificate, Student, Course, User]),
ConfigModule,
UsersNotificationsModule,
CoursesModule,
Expand Down
25 changes: 23 additions & 2 deletions nestjs/src/certificates/certificates.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Readable } from 'stream';
import { GetObjectCommand, S3 } from '@aws-sdk/client-s3';
import { Injectable } from '@nestjs/common';
import { Injectable, HttpException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Certificate } from '@entities/certificate';
Expand All @@ -9,6 +9,8 @@ import { SaveCertificateDto } from './dto/save-certificate-dto';
import { ConfigService } from 'src/config';
import { Student } from '@entities/student';
import { Course } from '@entities/course';
import { User } from '@entities/user';
import { CertificateMetadataDto } from './dto/certificate-metadata.dto';

@Injectable()
export class CertificationsService {
Expand All @@ -19,6 +21,8 @@ export class CertificationsService {
private certificateRepository: Repository<Certificate>,
@InjectRepository(Course)
private courseRepository: Repository<Course>,
@InjectRepository(User)
private userRepository: Repository<User>,
private readonly configService: ConfigService,
) {
this.s3 = new S3({
Expand All @@ -31,7 +35,24 @@ export class CertificationsService {
}

public async getByPublicId(publicId: string) {
return await this.certificateRepository.findOne({ where: { publicId } });
return this.certificateRepository.findOne({
where: { publicId },
relations: ['student'],
});
}

public async getCertificateMetadata(certificate: Certificate): Promise<CertificateMetadataDto> {
const user = await this.userRepository.findOneByOrFail({ id: certificate.studentId });
const course = await this.courseRepository.findOne({
where: { id: certificate.student.courseId },
relations: ['discipline'],
});

if (!course) {
throw new HttpException('Course not found', 404);
}

return new CertificateMetadataDto(certificate, course, user);
}

public async getFileStream(bucket: string, key: string) {
Expand Down
45 changes: 45 additions & 0 deletions nestjs/src/certificates/dto/certificate-metadata.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Certificate } from '@entities/certificate';
import { Course } from '@entities/course';
import { User } from '@entities/user';
import { ApiProperty } from '@nestjs/swagger';
import { IsDateString, IsString } from 'class-validator';

export class CertificateMetadataDto {
constructor(certificate: Certificate, course: Course, user: User) {
this.id = certificate.publicId;
this.name = `${user.firstName} ${user.lastName}`;
this.issueDate = certificate.issueDate.toISOString().split('T')[0] as string;
this.issuer = 'RS School';
this.courseTrainers = course.certificateIssuer;
this.courseFullName = course.fullName;
this.courseDiscipline = course.discipline?.name ?? 'N/A';
}

@ApiProperty()
@IsString()
public id: string;

@ApiProperty()
@IsString()
public name: string;

@ApiProperty()
@IsDateString()
public issueDate: string;

@ApiProperty()
@IsString()
public issuer: string;

@ApiProperty()
@IsString()
public courseTrainers: string;

@ApiProperty()
@IsString()
public courseFullName: string;

@ApiProperty()
@IsString()
public courseDiscipline: string;
}

0 comments on commit 14f10c0

Please sign in to comment.