Skip to content

Commit

Permalink
Merge pull request #286 from credebl/certificate-share
Browse files Browse the repository at this point in the history
refactor: developed new certificate html templates
  • Loading branch information
nishad-ayanworks authored Nov 21, 2023
2 parents f141c55 + ccb553e commit c47e915
Show file tree
Hide file tree
Showing 9 changed files with 280 additions and 108 deletions.
8 changes: 6 additions & 2 deletions apps/api-gateway/src/user/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,12 +310,16 @@ export class UserController {
async shareUserCertificate(
@Body() shareUserCredentials: CreateUserCertificateDto,
@Res() res: Response
): Promise<object> {
const imageBuffer = await this.userService.shareUserCertificate(shareUserCredentials);
): Promise<object> {
const schemaIdParts = shareUserCredentials.schemaId.split(':');
// eslint-disable-next-line prefer-destructuring
const title = schemaIdParts[2];

const imageBuffer = await this.userService.shareUserCertificate(shareUserCredentials);
const finalResponse: IResponseType = {
statusCode: HttpStatus.CREATED,
message: 'Certificate url generated successfully',
label: title,
data: imageBuffer.response
};
return res.status(HttpStatus.CREATED).json(finalResponse);
Expand Down
11 changes: 9 additions & 2 deletions apps/user/src/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import validator from 'validator';
import { DISALLOWED_EMAIL_DOMAIN } from '@credebl/common/common.constant';
import { AwsService } from '@credebl/aws';
import puppeteer from 'puppeteer';
import { WorldRecordTemplate } from '../templates/world-record-template';

@Injectable()
export class UserService {
Expand Down Expand Up @@ -578,6 +579,11 @@ export class UserService {
const userArbiterTemplate = new ArbiterTemplate();
template = await userArbiterTemplate.getArbiterTemplate(attributeArray);
break;
case UserCertificateId.WORLD_RECORD:
// eslint-disable-next-line no-case-declarations
const userWorldRecordTemplate = new WorldRecordTemplate();
template = await userWorldRecordTemplate.getWorldRecordTemplate(attributeArray);
break;
default:
throw new NotFoundException('error in get attributes');
}
Expand All @@ -588,7 +594,7 @@ export class UserService {

const imageUrl = await this.awsService.uploadUserCertificate(
imageBuffer,
'jpeg',
'png',
verifyCode,
'certificates',
'base64'
Expand All @@ -606,6 +612,7 @@ export class UserService {
}

return `${process.env.FRONT_END_URL}/certificates/${shareUserCertificate.credentialId}`;

}

async saveCertificateUrl(imageUrl: string, credentialId: string): Promise<unknown> {
Expand All @@ -619,7 +626,7 @@ export class UserService {
headless: true
});
const page = await browser.newPage();
await page.setViewport({ width: 1920, height: 1080 });
await page.setViewport({ width: 800, height: 1020, deviceScaleFactor: 6});
await page.setContent(template);
const screenshot = await page.screenshot();
await browser.close();
Expand Down
105 changes: 83 additions & 22 deletions apps/user/templates/arbiter-template.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,88 @@
import { Attribute } from "../interfaces/user.interface";
import { Attribute } from '../interfaces/user.interface';

export class ArbiterTemplate {
public getArbiterTemplate(attributes: Attribute[]): string {
const name = 0 < attributes.length ? attributes[0].name : '';
findAttributeByName(attributes: Attribute[], name: string): Attribute {
return attributes.find((attr) => name in attr);
}

try {
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Arbiter Template</title>
</head>
<body style="font-family: Arial, sans-serif; margin: 0; padding: 0; background-color: #f5f5f5;">
<div style="text-align: center; padding: 20px; background-color: #ffffff; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); margin: 50px auto;">
<div style="font-size: 48px; margin-bottom: 20px;"> 👩‍⚖️ </div>
<h1 style="color: #007bff;">Thank You, ${name}!</h1>
<p style="color: #333;">Your role as ${attributes} is essential in our contest.</p>
</div>
</body>
</html>`;
} catch (error) {
async getArbiterTemplate(attributes: Attribute[]): Promise<string> {
try {
const [name, country, issuedBy] = await Promise.all(attributes).then((attributes) => {
const name = this.findAttributeByName(attributes, 'full_name')?.full_name ?? '';
const country = this.findAttributeByName(attributes, 'country')?.country ?? '';
const issuedBy = this.findAttributeByName(attributes, 'issued_by')?.issued_by ?? '';
return [name, country, issuedBy];
});
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter&display=swap" rel="stylesheet">
<style>
body {
margin: 0;
background-color: #f0f0f0;
}
#container {
padding: 0 20px;
}
#backgroundImage {
width: 100%;
height: auto;
display: block;
margin: 0 auto;
}
#textOverlay {
position: absolute;
top: 280px;
left: 50%;
transform: translateX(-50%);
text-align: center;
color: #2B2B2A;
font-size: 24px;
}
</style>
</head>
<body>
<div id="container" style="">
<img id="backgroundImage" src="https://credebl-dev-user-certificate.s3.ap-south-1.amazonaws.com/certificates/background_image.png" alt="background"
style="height: 1000px; width: 770px;"
/>
<div id="textOverlay" style="width: 760px; height: 450px;">
<div>
<p style="font-size: 50px; font-family: Inter; margin: 0;">CERTIFICATE</p>
<p style="font-size: 22px; font-family: Inter; margin: 0;"> OF RECOGNITION</p>
</div>
}
}
<p style="font-size: 15px; font-family: Inter;margin: 15; margin-top: 15px;">IS PROUDLY PRESENTED TO</p>
<p style="font-size: 35px; font-style: italic; ">${name}</p>
<span >
<p style="font-size: 16px; " >has served as an Arbiter at the
<span style="font-size: 16px; font-weight: bold;">${issuedBy} World Memory Championship 2023.</span>
</p>
</p>
<p>
<p style="font-size: 14px; margin: 0;">Your dedication, professionalism, and impartiality as an Arbiter</p>
<p style="font-size: 14px; margin: 0;">have significantly contributed to the fair and smooth conduct</p>
<p style="font-size: 14px; margin: 0;">of the championship. Your commitment to upholding the</p>
<p style="font-size: 14px; margin: 0;">highest standards of integrity and sportsmanship has</p>
<p style="font-size: 14px; margin: 0;">played a crucial role in maintaining the credibility of the competition.</p>
</p>
<div style="font-family: Inter; font-weight: bold; font-size: 12px;">Date: 24, 25, 26 November 2023 | Place: Cidco Exhibition Centre, Navi Mumbai, ${country}</div>
</div>
</div>
</body>
</html>`;
} catch {}
}
}
120 changes: 75 additions & 45 deletions apps/user/templates/participant-template.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,84 @@
import { Attribute } from "../interfaces/user.interface";

export class ParticipantTemplate {
public getParticipantTemplate(attributes: Attribute[]): string {
try {
const nameAttribute = attributes.find(attr => 'full_name' in attr);
const countryAttribute = attributes.find(attr => 'country' in attr);
const positionAttribute = attributes.find(attr => 'position' in attr);
const issuedByAttribute = attributes.find(attr => 'issued_by' in attr);
const categoryAttribute = attributes.find(attr => 'category' in attr);
const dateAttribute = attributes.find(attr => 'issued_date' in attr);

const name = nameAttribute ? nameAttribute['full_name'] : '';
const country = countryAttribute ? countryAttribute['country'] : '';
const position = positionAttribute ? positionAttribute['position'] : '';
const issuedBy = issuedByAttribute ? issuedByAttribute['issued_by'] : '';
const category = categoryAttribute ? categoryAttribute['category'] : '';
const date = dateAttribute ? dateAttribute['issued_date'] : '';

return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Certificate of Achievement</title>
</head>
<body style="font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 0; background-color: #000000;">
<div style="text-align: center; padding: 30px; background-color: #000000; border-radius: 12px; box-shadow: 0 0 20px rgba(255, 215, 0, 0.5); margin: 50px auto; color: #ffffff;">
<div style="font-size: 64px; margin-bottom: 20px; color: #ffd700;">🏆</div>
<h1 style="color: #ffffff; margin-bottom: 15px; font-size: 32px;">Certificate of Achievement</h1>
<h2 style="color: #ffffff; margin-bottom: 15px; font-size: 24px;">${name}</h2>
<p style="color: #ffffff; margin-bottom: 30px; font-size: 18px;">has demonstrated outstanding performance and successfully completed the requirements for</p>
<h3 style="color: #ffffff; margin-bottom: 15px; font-size: 28px;">Participant</h3>
<p style="color: #ffffff; margin-bottom: 15px; font-size: 18px;">Position: ${position}</p>
<p style="color: #ffffff; margin-bottom: 30px; font-size: 18px;">Issued by: ${issuedBy}</p>
<div style="border-top: 2px solid #ffffff; margin: 30px 0;"></div>
<p style="color: #ffffff; margin-top: 30px; font-size: 20px;">Country: ${country}</p>
<p style="color: #ffffff; font-size: 20px;">Category: ${category}</p>
findAttributeByName(attributes: Attribute[], name: string): Attribute {
return attributes.find((attr) => name in attr);
}

<p style="color: #ffffff; margin-top: 30px; font-size: 20px;">Issued Date: ${date}</p>
async getParticipantTemplate(attributes: Attribute[]): Promise<string> {

<p style="color: #ffffff; margin-top: 30px; font-size: 24px;">Congratulations!</p>
</div>
try {
const [name, country, issuedBy] = await Promise.all(attributes).then((attributes) => {
const name = this.findAttributeByName(attributes, 'full_name')?.full_name ?? '';
const country = this.findAttributeByName(attributes, 'country')?.country ?? '';
const issuedBy = this.findAttributeByName(attributes, 'issued_by')?.issued_by ?? '';
return [name, country, issuedBy];
});

</body>
</html>`;
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter&display=swap" rel="stylesheet">
<style>
body {
margin: 0;
background-color: #f0f0f0;
}
#container {
padding: 0 20px;
}
#backgroundImage {
width: 100%;
height: auto;
display: block;
margin: 0 auto;
}
#textOverlay {
position: absolute;
top: 280px;
left: 50%;
transform: translateX(-50%);
text-align: center;
color: #2B2B2A;
font-size: 24px;
}
</style>
</head>
<body>
<div id="container" style="">
<img id="backgroundImage" src="https://credebl-dev-user-certificate.s3.ap-south-1.amazonaws.com/certificates/background_image.png" alt="background"
style="height: 1000px; width: 770px;"
/>
<div id="textOverlay" style="width: 760px; height: 450px;">
<div>
<p style="font-size: 50px; font-family: Inter; margin: 0;">CERTIFICATE</p>
<p style="font-size: 22px; font-family: Inter; margin: 0;"> OF ACHIEVEMENT</p>
</div>
<p style="font-size: 15px; font-family: Inter;margin: 15; margin-top: 15px;">IS PROUDLY PRESENTED TO</p>
<p style="font-size: 35px; font-style: italic;">${name}</p>
<span style="font-size: 16px;">for successfully participating in the
<span style="font-size: 16px; font-weight: bold; ">${issuedBy} World Memory Championship 2023.</span>
</p>
<p>
<p style="font-size: 14px; margin: 0;">We acknowledge your dedication, hard work, and</p>
<p style="font-size: 14px; margin: 0;">exceptional memory skills demonstrated during the competition.</p>
</p>
<div style="font-family: Inter; font-weight: bold; font-size: 12px;">Date: 24, 25, 26 November 2023 | Place: Cidco Exhibition Centre, Navi Mumbai, ${country}</div>
</div>
</div>
</body>
</html>`;
} catch (error) {}
}
}
30 changes: 17 additions & 13 deletions apps/user/templates/winner-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ export class WinnerTemplate {

async getWinnerTemplate(attributes: Attribute[]): Promise<string> {
try {
const [name, issuedBy, date] = await Promise.all(attributes).then((attributes) => {
const [name, country, position, discipline, issuedBy, category] = await Promise.all(attributes).then((attributes) => {
const name = this.findAttributeByName(attributes, 'full_name')?.full_name ?? '';
const country = this.findAttributeByName(attributes, 'country')?.country ?? '';
const position = this.findAttributeByName(attributes, 'position')?.position ?? '';
const discipline = this.findAttributeByName(attributes, 'discipline')?.discipline ?? '';
const issuedBy = this.findAttributeByName(attributes, 'issued_by')?.issued_by ?? '';
const category = this.findAttributeByName(attributes, 'category')?.category ?? '';
const date = this.findAttributeByName(attributes, 'issued_date')?.issued_date ?? '';
return [name, country, position, issuedBy, category, date];
return [name, country, position, discipline, issuedBy, category, date];
});
return `<!DOCTYPE html>
<html lang="en">
Expand All @@ -41,7 +42,7 @@ export class WinnerTemplate {
}
#textOverlay {
position: absolute;
position: absolute;
top: 280px;
left: 50%;
transform: translateX(-50%);
Expand All @@ -55,31 +56,34 @@ export class WinnerTemplate {
<body>
<div id="container" style="">
<img id="backgroundImage" src="https://credebl-dev-user-certificate.s3.ap-south-1.amazonaws.com/certificates/background_image.png" alt="background"
style="height: 1000px; width: 770px;"
/>
<div id="textOverlay" style="width: 760px; height: 450px;">
<img id="backgroundImage" src="https://credebl-dev-user-certificate.s3.ap-south-1.amazonaws.com/certificates/background_image.png" alt="background"
style="height: 1000px; width: 770px;"/>
<div id="textOverlay" style="width: 780px; height: 450px;">
<div>
<p style="font-size: 50px; font-family: Inter; margin: 0;">CERTIFICATE</p>
<p style="font-size: 22px; font-family: Inter; margin: 0;"> OF ACHIEVEMENT</p>
<p style="font-size: 22px; font-family: Inter; margin: 0;"> OF EXCELLENCE</p>
</div>
<p style="font-size: 15px; font-family: Inter;margin: 15; margin-top: 15px;">IS PROUDLY PRESENTED TO</p>
<p style="font-size: 35px; font-style: italic;">${name}</p>
<p style="font-size: 30px; font-style: italic; ">${name}</p>
<span style="font-size: 16px;">You are the winner of our contest
<span style="font-size: 16px; font-weight: bold; ">${issuedBy} World Memory Championship 2023.</span>
<p style="font-size: 16px; margin: 0;">has secured ${position} position for ${discipline} </p>
<p style="font-size: 16px; margin: 6px;">in ${category} category at the</p>
<p style="font-size: 16px;" >
<span style="font-size: 16px; font-weight: bold;"> ${issuedBy} World Memory Championship 2023.</span>
</p>
</p>
<p>
<p style="font-size: 14px; margin: 0;">We acknowledge your dedication, hard work, and</p>
<p style="font-size: 14px; margin: 0;">exceptional memory skills demonstrated during the competition.</p>
</p>
<div style="font-family: Inter; font-weight: bold; font-size: 12px;">${date} | Place: Cidco Exhibition Centre, Navi Mumbai, India</div>
<div style="font-family: Inter; font-weight: bold; font-size: 12px;">Date: 24, 25, 26 November 2023 | Place: Cidco Exhibition Centre, Navi Mumbai, ${country}</div>
</div>
</div>
</body>
</html>`;
</html>
`;
} catch {}
}
}
Loading

0 comments on commit c47e915

Please sign in to comment.