Skip to content

Commit

Permalink
feat: event certificate (#665)
Browse files Browse the repository at this point in the history
Signed-off-by: tipusinghaw <[email protected]>
Signed-off-by: KulkarniShashank <[email protected]>
  • Loading branch information
tipusinghaw authored and KulkarniShashank committed Sep 12, 2024
1 parent 20cbc1f commit 48afb97
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 211 deletions.
11 changes: 3 additions & 8 deletions apps/api-gateway/src/user/dto/share-certificate.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
{
Expand Down
134 changes: 65 additions & 69 deletions apps/user/interfaces/user.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,75 +49,71 @@ export interface OrgInvitations {
}

export interface ISendVerificationEmail {
email: string;
username?: string;
clientId?: string;
clientSecret?: string;
}

export interface IUserInformation {
email: string;
password: string;
firstName: string;
lastName: string;
isPasskey: boolean;
isHolder?: boolean;
}

export interface AddPasskeyDetails {
password: string;
}

export interface UpdateUserProfile {
id: string;
profileImg?: string;
firstName: string;
lastName: string;
isPublic: boolean;
}
export interface PlatformSettings {
externalIp: string;
inboundEndpoint: string;
sgApiKey: string;
emailFrom: string;
apiEndPoint: string;
enableEcosystem: boolean;
multiEcosystemSupport: boolean;
}

export interface IShareUserCertificate {
schemaId: string;
credDefId: string;
credentialId: string;
attributes: Attribute[];
invitationUrl?: string;
}

export interface IShareDegreeCertificateRes {
cretificate: string;
invitationUrl?: string;
}

export interface Attribute {
[key: string]: string;
label: string;
}

export interface ICheckUserDetails {
isEmailVerified?: boolean;
isFidoVerified?: boolean;
isRegistrationCompleted?: boolean;
}
export interface IUserCredentials {
id: string;
imageUrl?: string;
credentialId?: string;
createDateTime: Date;
lastChangedDateTime: Date;
deletedAt: Date;
}

export interface IOrgUsers {
email: string;
username?: string;
}

export interface IUserInformation {
email: string;
password: string;
firstName: string;
lastName: string;
isPasskey: boolean;
}

export interface AddPasskeyDetails {
password: string;
}

export interface UpdateUserProfile {
id: string;
profileImg?: string;
firstName: string;
lastName: string;
isPublic: boolean;
}
export interface PlatformSettings {
externalIp: string;
inboundEndpoint: string;
sgApiKey: string;
emailFrom: string;
apiEndPoint: string;
enableEcosystem: boolean;
multiEcosystemSupport: boolean;
}

export interface IShareUserCertificate {
schemaId: string;
credentialId: string;
attributes: Attribute[];
invitationUrl?: string;
}

export interface IShareDegreeCertificateRes {
cretificate: string;
invitationUrl?: string;
}

export interface Attribute {
[key: string]: string;
label: string;
}

export interface ICheckUserDetails {
isEmailVerified?: boolean;
isFidoVerified?: boolean;
isRegistrationCompleted?: boolean;
}
export interface IUserCredentials {
id: string;
imageUrl?: string;
credentialId?: string;
createDateTime: Date;
lastChangedDateTime: Date;
deletedAt: Date;
}

export interface IOrgUsers {
totalPages: number,
users: OrgUser[]
}
Expand Down
47 changes: 38 additions & 9 deletions apps/user/src/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import { UserActivityService } from '@credebl/user-activity';
import { SupabaseService } from '@credebl/supabase';
import { UserDevicesRepository } from '../repositories/user-device.repository';
import { v4 as uuidv4 } from 'uuid';
import { EcosystemConfigSettings, Invitation, UserCertificateId, UserRole } from '@credebl/enum/enum';
import { EcosystemConfigSettings, UserCertificateId, CertificateDetails} from '@credebl/enum/enum';
import { WinnerTemplate } from '../templates/winner-template';
import { ParticipantTemplate } from '../templates/participant-template';
import { ArbiterTemplate } from '../templates/arbiter-template';
Expand All @@ -65,8 +65,9 @@ import { IUsersActivity } from 'libs/user-activity/interface';
import { ISendVerificationEmail, ISignInUser, IVerifyUserEmail, IUserInvitations, IResetPasswordResponse, ISignUpUserResponse } from '@credebl/common/interfaces/user.interface';
import { AddPasskeyDetailsDto } from 'apps/api-gateway/src/user/dto/add-user.dto';
import { URLUserResetPasswordTemplate } from '../templates/reset-password-template';
import { toNumber } from '@credebl/common/cast.helper';
import * as jwt from 'jsonwebtoken';
import { EventPinnacle } from '../templates/event-pinnacle';
import { EventCertificate } from '../templates/event-certificates';
import * as QRCode from 'qrcode';

@Injectable()
export class UserService {
Expand Down Expand Up @@ -944,6 +945,7 @@ export class UserService {

async shareUserCertificate(shareUserCertificate: IShareUserCertificate): Promise<string> {

let template;
const attributeArray = [];
let attributeJson = {};
const attributePromises = shareUserCertificate.attributes.map(async (iterator: Attribute) => {
Expand All @@ -953,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
Expand All @@ -976,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);

Expand All @@ -1017,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
});

Expand All @@ -1031,6 +1044,22 @@ export class UserService {
return screenshot;
}

//Need to add interface
async getShorteningURL(shareUserCertificate, attributeArray): Promise<unknown> {
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
Expand Down
82 changes: 82 additions & 0 deletions apps/user/templates/event-certificates.ts
Original file line number Diff line number Diff line change
@@ -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<string> {
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 `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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=Federo&family=Gentium+Book+Plus:ital,wght@0,400;0,700;1,400;1,700&family=MonteCarlo&display=swap" rel="stylesheet">
<title>Document</title>
<style>
p, h1, h2, h3 {
margin: 0;
}
</style>
</head>
<body style="font-family: 'Gentium Book Plus', serif; font-weight: 400; font-style: normal;">
<div style="position: relative; margin: auto; width: fit-content;">
<div style="width: 1591px;min-width: 1591px;">
<img style="width: 1591px;min-width: 1591px;" src="https://credebl-dev-user-certificate.s3.ap-south-1.amazonaws.com/certificates/cert-background.png" />
</div>
<div style="box-shadow: 0px 0px 25px -10px black;padding: 2rem 6rem;position: absolute;width: 1372px;min-width: 1398px;height: calc(100% - 4.45rem + 1.5px);top: 0px;">
<div style="position: absolute; right: 4rem; top: 3rem">
<img style="height: 65px;" src="https://credebl-dev-user-certificate.s3.ap-south-1.amazonaws.com/certificates/anniversary.svg" />
</div>
<div style="display: flex; flex-direction: column; justify-content: center; align-items: center; margin: 0 auto;">
<div>
<img style="height: 68px;" src="https://credebl-dev-user-certificate.s3.ap-south-1.amazonaws.com/certificates/ayanworks-logo.svg" />
</div>
<h2 style="color: #10005F; font-size: 60px; font-weight: 400;">Certificate of Appreciation</h2>
<h1 style="color: #10005F; font-size: 86px; font-family: 'Federo', sans-serif; font-weight: 600;">- ${category} -</h1>
<div style="font-size: 32px; text-align: center; max-width: 1082px;">
<p style="color: #342094;">this certificate is proudly presented to</p>
<h1 style="color: #02205F; font-size: 120px; font-family: 'MonteCarlo', cursive; font-weight: 400;">${name}</h1>
<p style="color: #342094;">${description}</p>
<p style="font-weight: bolder; color: #342094;">~ 23rd March 2024 ~</p>
</div>
<div style="position: absolute;
left: 9.5rem;
bottom: 2.5rem;">
<img src="${QRDetails}" style="width: 220px; height: 220px;" alt="QR Code" flex; margin-right: 10px;/>
</div>
<div style="display: flex; justify-content: center; gap: 3rem; font-size: 32px; text-align: center; margin-top: 1rem; position: absolute; bottom: 3rem; color: #342094;">
<div style="display: flex; flex-direction: column; align-items: center;">
<img style="height: 99px" src="https://credebl-dev-user-certificate.s3.ap-south-1.amazonaws.com/certificates/kk-sign.svg" />
<div style="border-top: 1px solid #000000; margin-top: -1rem; padding: 1rem 2rem 0 2rem;">
<p>Kirankalyan Kulkarni</p>
<p>CEO & Co-Founder</p>
</div>
</div>
<div style="display: flex; flex-direction: column; align-items: center;">
<img style="height: 99px" src="https://credebl-dev-user-certificate.s3.ap-south-1.amazonaws.com/certificates/ak-sign.svg" />
<div style="border-top: 1px solid #000000; margin-top: -1rem; padding: 1rem 2rem 0 2rem;">
<p>Ajay Jadhav</p>
<p>CTO & Co-Founder</p>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
`;
} catch { }
}
}
Loading

0 comments on commit 48afb97

Please sign in to comment.