From 0d1ca64061ac4ecb30048384f3eec17803e9f47c Mon Sep 17 00:00:00 2001 From: tipusinghaw <126460794+tipusinghaw@users.noreply.github.com> Date: Mon, 15 Apr 2024 18:31:50 +0530 Subject: [PATCH] feat: event certificate (#665) Signed-off-by: tipusinghaw Signed-off-by: KulkarniShashank --- .../src/user/dto/share-certificate.dto.ts | 11 +-- apps/user/src/user.service.ts | 40 +++++++-- apps/user/templates/event-certificates.ts | 82 +++++++++++++++++++ apps/user/templates/event-pinnacle.ts | 80 ++++++++++++++++++ libs/aws/src/aws.service.ts | 6 +- libs/enum/src/enum.ts | 10 ++- 6 files changed, 208 insertions(+), 21 deletions(-) create mode 100644 apps/user/templates/event-certificates.ts create mode 100644 apps/user/templates/event-pinnacle.ts diff --git a/apps/api-gateway/src/user/dto/share-certificate.dto.ts b/apps/api-gateway/src/user/dto/share-certificate.dto.ts index 802b849d9..ca82fd844 100644 --- a/apps/api-gateway/src/user/dto/share-certificate.dto.ts +++ b/apps/api-gateway/src/user/dto/share-certificate.dto.ts @@ -8,24 +8,19 @@ interface Attribute { value: string; } export class CreateCertificateDto { + @ApiProperty() - @IsNotEmpty({ message: 'Please provide valid schemaId' }) + @IsNotEmpty({ message: 'Please provide valid credentialId' }) @Transform(({ value }) => trim(value)) @IsString({ message: 'credentialId should be string' }) credentialId: string; - @ApiProperty({ example: 'SchemaId' }) + @ApiProperty({ example: 'schemaId' }) @IsNotEmpty({ message: 'Please provide valid schemaId' }) @Transform(({ value }) => trim(value)) @IsString({ message: 'schemaId should be string' }) schemaId: string; - @ApiProperty({ example: 'CredDefId' }) - @IsNotEmpty({ message: 'Please provide valid schemaId' }) - @Transform(({ value }) => trim(value)) - @IsString({ message: 'credDefId should be string' }) - credDefId?: string; - @ApiProperty({ example: [ { diff --git a/apps/user/src/user.service.ts b/apps/user/src/user.service.ts index cf47485db..f0c7c8280 100644 --- a/apps/user/src/user.service.ts +++ b/apps/user/src/user.service.ts @@ -945,6 +945,7 @@ export class UserService { async shareUserCertificate(shareUserCertificate: IShareUserCertificate): Promise { + let template; const attributeArray = []; let attributeJson = {}; const attributePromises = shareUserCertificate.attributes.map(async (iterator: Attribute) => { @@ -954,8 +955,6 @@ export class UserService { attributeArray.push(attributeJson); }); await Promise.all(attributePromises); - let template; - switch (shareUserCertificate.schemaId.split(':')[2]) { case UserCertificateId.WINNER: // eslint-disable-next-line no-case-declarations @@ -977,22 +976,35 @@ export class UserService { const userWorldRecordTemplate = new WorldRecordTemplate(); template = await userWorldRecordTemplate.getWorldRecordTemplate(attributeArray); break; + case UserCertificateId.AYANWORKS_EVENT: + // eslint-disable-next-line no-case-declarations + const QRDetails = await this.getShorteningURL(shareUserCertificate, attributeArray); + + if (shareUserCertificate.attributes.some(item => item.value.toLocaleLowerCase().includes("pinnacle"))) { + const userPinnacleTemplate = new EventPinnacle(); + template = await userPinnacleTemplate.getPinnacleWinner(attributeArray, QRDetails); + } else { + const userCertificateTemplate = new EventCertificate(); + template = await userCertificateTemplate.getCertificateWinner(attributeArray, QRDetails); + } + break; default: throw new NotFoundException('error in get attributes'); } - const option: IPuppeteerOption = {height: 0, width: 1000}; + //Need to handle the option for all type of certificate + const option: IPuppeteerOption = {height: 974, width: 1606}; const imageBuffer = await this.convertHtmlToImage(template, shareUserCertificate.credentialId, option); - const verifyCode = uuidv4(); const imageUrl = await this.awsService.uploadUserCertificate( imageBuffer, 'svg', 'certificates', process.env.AWS_PUBLIC_BUCKET_NAME, - 'base64' + 'base64', + 'certificates' ); const existCredentialId = await this.userRepository.getUserCredentialsById(shareUserCertificate.credentialId); @@ -1018,7 +1030,7 @@ export class UserService { const browser = await puppeteer.launch({ executablePath: '/usr/bin/google-chrome', args: ['--no-sandbox', '--disable-setuid-sandbox'], - protocolTimeout: 200000, + protocolTimeout: 800000, //initial - 200000 headless: true }); @@ -1032,6 +1044,22 @@ export class UserService { return screenshot; } + //Need to add interface + async getShorteningURL(shareUserCertificate, attributeArray): Promise { + const urlObject = { + schemaId: shareUserCertificate.schemaId, + credDefId: shareUserCertificate.credDefId, + attribute: attributeArray, + credentialId:shareUserCertificate.credentialId, + email:attributeArray.find((attr) => "email" in attr).email + }; + + const qrCodeOptions = { type: 'image/png' }; + const encodedData = Buffer.from(JSON.stringify(shareUserCertificate)).toString('base64'); + const qrCode = await QRCode.toDataURL(`https://credebl.id/c_v?${encodedData}`, qrCodeOptions); + + return qrCode; + } /** * * @param acceptRejectInvitation diff --git a/apps/user/templates/event-certificates.ts b/apps/user/templates/event-certificates.ts new file mode 100644 index 000000000..bed44507c --- /dev/null +++ b/apps/user/templates/event-certificates.ts @@ -0,0 +1,82 @@ +import { Attribute } from '../interfaces/user.interface'; + +export class EventCertificate { + findAttributeByName(attributes: Attribute[], name: string): Attribute { + return attributes.find((attr) => name in attr); + } + + async getCertificateWinner(attributes: Attribute[], QRDetails): Promise { + try { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [name, description, category] = await Promise.all(attributes).then((attributes) => { + const name = this.findAttributeByName(attributes, 'name').name ?? ''; + const description = this.findAttributeByName(attributes, 'description').description ?? ''; + const category = this.findAttributeByName(attributes, 'category').category ?? ''; + return [name, description, category]; + }); + return ` + + + + + + + + Document + + + +
+
+ +
+
+
+ +
+
+
+ +
+

Certificate of Appreciation

+

- ${category} -

+
+

this certificate is proudly presented to

+

${name}

+

${description}

+

~ 23rd March 2024 ~

+
+
+ QR Code +
+
+
+ +
+

Kirankalyan Kulkarni

+

CEO & Co-Founder

+
+
+
+ +
+

Ajay Jadhav

+

CTO & Co-Founder

+
+
+
+
+
+
+ + + `; + } catch { } + } +} \ No newline at end of file diff --git a/apps/user/templates/event-pinnacle.ts b/apps/user/templates/event-pinnacle.ts new file mode 100644 index 000000000..236478765 --- /dev/null +++ b/apps/user/templates/event-pinnacle.ts @@ -0,0 +1,80 @@ +import { Attribute } from '../interfaces/user.interface'; + +export class EventPinnacle { + findAttributeByName(attributes: Attribute[], name: string): Attribute { + return attributes.find((attr) => name in attr); + } + + async getPinnacleWinner(attributes: Attribute[], qrCode): Promise { + try { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [name, description] = await Promise.all(attributes).then((attributes) => { + const name = this.findAttributeByName(attributes, 'name').name ?? ''; + const description = this.findAttributeByName(attributes, 'description').description ?? ''; + return [name, description]; + }); + return ` + + + + + + + + Document + + + +
+
+ +
+
+
+ +
+ +
+ +
+
+
+ +
+

Certificate of Appreciation

+

- Pinnacle Performer -

+
+

this certificate is proudly presented to

+

${name}

+

${description}

+

~ 23rd March 2024 ~

+
+
+
+ +
+

Kirankalyan Kulkarni

+

CEO & Co-Founder

+
+
+
+ +
+

Ajay Jadhav

+

CTO & Co-Founder

+
+
+
+
+
+
+ + + `; + } catch { } + } +} \ No newline at end of file diff --git a/libs/aws/src/aws.service.ts b/libs/aws/src/aws.service.ts index f9c7cb7e4..01e8b985a 100644 --- a/libs/aws/src/aws.service.ts +++ b/libs/aws/src/aws.service.ts @@ -42,14 +42,14 @@ export class AwsService { try { await putObjectAsync({ - Bucket: `${process.env.AWS_ORG_LOGO_BUCKET_NAME}`, - Key: `${pathAWS}/${encodeURIComponent(filename)}-${timestamp}.png`, + Bucket: `${bucketName}`, + Key: `${pathAWS}/${encodeURIComponent(filename)}-${timestamp}.${ext}`, Body: fileBuffer, ContentEncoding: encoding, ContentType: `image/png` }); - const imageUrl = `https://${process.env.AWS_ORG_LOGO_BUCKET_NAME}.s3.${process.env.AWS_PUBLIC_REGION}.amazonaws.com/${pathAWS}/${encodeURIComponent(filename)}-${timestamp}.${ext}`; + const imageUrl = `https://${bucketName}.s3.${process.env.AWS_PUBLIC_REGION}.amazonaws.com/${pathAWS}/${encodeURIComponent(filename)}-${timestamp}.${ext}`; return imageUrl; } catch (error) { throw new HttpException(error, HttpStatus.SERVICE_UNAVAILABLE); diff --git a/libs/enum/src/enum.ts b/libs/enum/src/enum.ts index 28bbfc393..ca8569ea2 100644 --- a/libs/enum/src/enum.ts +++ b/libs/enum/src/enum.ts @@ -100,11 +100,13 @@ export enum AgentSpinUpStatus { COMPLETED = 2 } + export enum UserCertificateId { - WINNER = 'Winner', - PARTICIPANT = 'Participant', - ARBITER = 'Arbiter', - WORLD_RECORD = 'WorldRecord' + WINNER = 'Winner', + PARTICIPANT = 'Participant', + ARBITER = 'Arbiter', + WORLD_RECORD = 'WorldRecord', + AYANWORKS_EVENT ='Appreciation Certificate' } export enum NodeEnvironment {