-
Notifications
You must be signed in to change notification settings - Fork 47
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
Implement Application Completion Workflow with Certificate Generation and Email Notification #130
Changes from 1 commit
a9d954c
afac5d8
28012ed
89fb972
08caab7
0e4a52f
37e1ab0
6943990
6236907
769cd41
a933df7
008fa39
b0bce78
7010463
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { PDFDocument, rgb } from 'pdf-lib' | ||
import fs from 'fs' | ||
|
||
export async function generateCertificate( | ||
menteeName: string, | ||
sourcePdfPath: string, | ||
outputPath: string | ||
): Promise<string> { | ||
try { | ||
const existingPdfBytes = fs.readFileSync(sourcePdfPath) | ||
const pdfDoc = await PDFDocument.load(existingPdfBytes) | ||
const page = pdfDoc.getPage(0) | ||
const fontSize = 24 | ||
const datezFontSize = 18 | ||
|
||
page.drawText(menteeName, { | ||
x: 66, | ||
y: page.getHeight() - 220, | ||
size: fontSize, | ||
color: rgb(0, 0, 0) | ||
}) | ||
|
||
const issueDate = new Date().toLocaleDateString() | ||
|
||
page.drawText(issueDate, { | ||
x: 160, | ||
y: page.getHeight() - 476, | ||
size: datezFontSize, | ||
color: rgb(0, 0, 0) | ||
}) | ||
|
||
const pdfBytes = await pdfDoc.save() | ||
|
||
fs.writeFileSync(outputPath, pdfBytes) | ||
return outputPath | ||
} catch (error) { | ||
console.error('Failed to modify the PDF:', error) | ||
throw error | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -6,6 +6,7 @@ | |||||
import multer from 'multer' | ||||||
import ejs from 'ejs' | ||||||
import { ApplicationStatus } from './enums' | ||||||
import { generateCertificate } from './services/admin/generateCertificate' | ||||||
|
||||||
export const signAndSetCookie = (res: Response, uuid: string): void => { | ||||||
const token = jwt.sign({ userId: uuid }, JWT_SECRET ?? '') | ||||||
|
@@ -65,7 +66,7 @@ | |||||
subject: string | ||||||
message: string | ||||||
} | ||||||
): any => { | ||||||
const templatePath = path.join(__dirname, 'templates', `${templateName}.ejs`) | ||||||
|
||||||
return new Promise<string>((resolve, reject) => { | ||||||
|
@@ -79,11 +80,18 @@ | |||||
}) | ||||||
} | ||||||
|
||||||
export const getEmailContent = ( | ||||||
export const getEmailContent = async ( | ||||||
type: 'mentor' | 'mentee', | ||||||
status: ApplicationStatus, | ||||||
name: string | ||||||
): { subject: string; message: string } | undefined => { | ||||||
): Promise< | ||||||
| { | ||||||
subject: string | ||||||
message: string | ||||||
attachment?: Array<{ filename: string; path: string }> | ||||||
} | ||||||
| undefined | ||||||
> => { | ||||||
if (type === 'mentor') { | ||||||
switch (status) { | ||||||
case ApplicationStatus.PENDING: | ||||||
|
@@ -145,6 +153,28 @@ | |||||
We do offer the possibility for you to apply again next time if you meet the eligibility criteria. We invite you to stay engaged with us by attending our events, reaching out to our admissions team, and taking advantage of any opportunities to connect with our current students and alumni.<br /><br /> | ||||||
Thank you again for considering our program and for the time you invested in your application. We wish you all the best in your future endeavours.` | ||||||
} | ||||||
case ApplicationStatus.COMPLETED: { | ||||||
const pdfFileName = await generateCertificate( | ||||||
name, | ||||||
'./src/certificates/certificate_template.pdf', | ||||||
`./src/certificates/${name}_certificate.pdf` | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shall we use a unique id here? There might be a chance of having the same name. Also you need to update the certificate_id field of the mentee with file path as well.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. okay sure There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||
) | ||||||
return { | ||||||
subject: 'Congratulations! You have completed ScholarX', | ||||||
message: `Dear ${name},<br /><br /> | ||||||
We are delighted to inform you that you have successfully completed the ScholarX program. We extend our heartfelt congratulations to you!<br /><br /> | ||||||
We are proud of your dedication, hard work, and commitment to the program. You have demonstrated exceptional talent, and we are confident that you will go on to achieve great success in your academic and professional pursuits.<br /><br /> | ||||||
To commemorate your achievement, we have attached your certificate of completion. Please download and save the certificate for your records.<br /><br /> | ||||||
We look forward to seeing the unique perspective and insights you will bring to the program. We believe that you will flourish in this year's edition of ScholarX, and we are thrilled to be a part of your academic or professional journey.<br /><br /> | ||||||
Once again, congratulations on your completion! We cannot wait to see the great things you will achieve in the future.`, | ||||||
attachment: [ | ||||||
{ | ||||||
filename: `${name}_certificate.pdf`, | ||||||
path: pdfFileName | ||||||
} | ||||||
] | ||||||
} | ||||||
} | ||||||
default: | ||||||
return undefined | ||||||
} | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we rename this to
MenteeStatus
and create separate one form Mentors? Cuz mentors don't need a completed state.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now, could we avoid changing this? There is a lot of refactoring involved.