Skip to content

Commit fe58c71

Browse files
committed
Merge branch 'main' of github.com:dump-hr/internship-app
Merge main
2 parents d44bdde + 9280e97 commit fe58c71

File tree

27 files changed

+418
-55
lines changed

27 files changed

+418
-55
lines changed

apps/api/nest-cli.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
"compilerOptions": {
66
"deleteOutDir": true,
77
"builder": "swc",
8-
"typeCheck": true
8+
"typeCheck": true,
9+
"assets": [
10+
{
11+
"include": "logo/**/*",
12+
"outDir": "dist"
13+
}
14+
]
915
}
1016
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-- CreateTable
2+
CREATE TABLE "OldInternResult" (
3+
"id" TEXT NOT NULL,
4+
"first_name" TEXT NOT NULL,
5+
"last_name" TEXT NOT NULL,
6+
"email" TEXT NOT NULL,
7+
"discipline" TEXT,
8+
"test_score" INTEGER,
9+
"interview_score" INTEGER,
10+
11+
CONSTRAINT "OldInternResult_pkey" PRIMARY KEY ("id")
12+
);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/*
2+
Warnings:
3+
4+
- Added the required column `applicationYear` to the `OldInternResult` table without a default value. This is not possible if the table is not empty.
5+
6+
*/
7+
-- AlterTable
8+
ALTER TABLE "OldInternResult" ADD COLUMN "applicationYear" TIMESTAMP(3) NOT NULL;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
Warnings:
3+
4+
- You are about to drop the column `applicationYear` on the `OldInternResult` table. All the data in the column will be lost.
5+
- You are about to drop the column `first_name` on the `OldInternResult` table. All the data in the column will be lost.
6+
- You are about to drop the column `last_name` on the `OldInternResult` table. All the data in the column will be lost.
7+
- Added the required column `applicationDate` to the `OldInternResult` table without a default value. This is not possible if the table is not empty.
8+
- Added the required column `firstName` to the `OldInternResult` table without a default value. This is not possible if the table is not empty.
9+
- Added the required column `lastName` to the `OldInternResult` table without a default value. This is not possible if the table is not empty.
10+
11+
*/
12+
-- AlterTable
13+
ALTER TABLE "OldInternResult" DROP COLUMN "applicationYear",
14+
DROP COLUMN "first_name",
15+
DROP COLUMN "last_name",
16+
ADD COLUMN "applicationDate" TIMESTAMP(3) NOT NULL,
17+
ADD COLUMN "firstName" TEXT NOT NULL,
18+
ADD COLUMN "lastName" TEXT NOT NULL;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/*
2+
Warnings:
3+
4+
- You are about to drop the column `lastUpdatedAt` on the `Email` table. All the data in the column will be lost.
5+
- Added the required column `updatedAt` to the `Email` table without a default value. This is not possible if the table is not empty.
6+
7+
*/
8+
-- AlterTable
9+
ALTER TABLE "Email" DROP COLUMN "lastUpdatedAt",
10+
ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL;

apps/api/prisma/schema.prisma

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,25 @@ model Email {
155155
internId String
156156
emailRecipient Intern @relation(fields: [internId], references: [id])
157157
createdAt DateTime @default(now())
158-
lastUpdatedAt DateTime @updatedAt
158+
updatedAt DateTime @updatedAt
159159
}
160160

161161
model InternshipApplicationStatus {
162162
id Int @id @default(autoincrement())
163163
isOpened Boolean @default(false)
164164
}
165165

166+
model OldInternResult {
167+
id String @id @default(uuid())
168+
firstName String
169+
lastName String
170+
email String
171+
applicationDate DateTime
172+
discipline String?
173+
test_score Int?
174+
interview_score Int?
175+
}
176+
166177
enum QuestionCategory {
167178
General
168179
Personal

apps/api/src/app.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { InterviewerModule } from './interviewer/interviewer.module';
1414
import { LoggerModule } from './logger/logger.module';
1515
import { PrismaService } from './prisma.service';
1616
import { TestSlotModule } from './test-slot/test-slot.module';
17+
import { OldInternResultModule } from './old-intern-result/old-intern-result.module';
1718

1819
@Module({
1920
imports: [
@@ -31,6 +32,7 @@ import { TestSlotModule } from './test-slot/test-slot.module';
3132
InterviewerModule,
3233
QuestionModule,
3334
InternshipApplicationStatusModule,
35+
OldInternResultModule,
3436
],
3537
controllers: [AppController /* , AuthController */],
3638
providers: [AppService, PrismaService],

apps/api/src/email/email.controller.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import { LoggerService } from 'src/logger/logger.service';
1616
import { EmailsDto } from './dto/emails.dto';
1717
import { EmailsSendDto } from './dto/emailsSend.dto';
1818
import { EmailService } from './email.service';
19+
import { join } from 'path';
20+
import * as fs from 'fs';
1921

2022
@Controller('email')
2123
@ApiTags('email')
@@ -43,20 +45,30 @@ export class EmailController {
4345
return templates;
4446
}
4547

46-
@Get('image')
47-
async getImage(@Query('emailId') emailId: string, @Res() res: Response) {
48+
@Get('logo')
49+
async getImageLogo(@Query('emailId') emailId: string, @Res() res: Response) {
4850
await this.emailService.updateIsSeen(emailId);
4951

50-
const pixel: Buffer = Buffer.from(
51-
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwADfgH+WBwLfwAAAABJRU5ErkJggg==',
52-
'base64',
52+
const imagePath = join(
53+
process.cwd(),
54+
'apps',
55+
'api',
56+
'dist',
57+
'logo',
58+
'dump-logo-internship.png',
5359
);
5460

55-
res.writeHead(200, {
56-
'Content-Type': 'image/png',
57-
'Content-Length': pixel.length,
58-
});
61+
console.log('ImagePath: ', imagePath);
5962

60-
res.end(pixel);
63+
if (fs.existsSync(imagePath)) {
64+
res.sendFile(imagePath, {
65+
headers: {
66+
'Content-Type': 'image/png',
67+
'Cache-Control': 'public, max-age=86400',
68+
},
69+
});
70+
} else {
71+
res.status(404).send('File not found');
72+
}
6173
}
6274
}

apps/api/src/email/email.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@ export class EmailService {
4747
(email) => email.internId === intern.id,
4848
).id;
4949

50-
const trackImage = `<img src="https://internship.dump.hr/api/email/image?emailId=${emailId}" width="1" height="1" style="display:none" />`;
50+
const trackImage = `<img src="https://internship.dump.hr/api/email/logo?emailId=${emailId}" width="1" height="1" style="display:none" />`;
5151

5252
return this.postmark.sendEmail({
5353
From: 'info@dump.hr',
5454
To: intern.email,
5555
Subject: subject,
56-
HtmlBody: `${template.render({ intern })} ${text} ${trackImage}`,
56+
HtmlBody: `${template.render({ intern })} ${trackImage}`,
5757
MessageStream: 'outbound',
5858
});
5959
}),

apps/api/src/intern/intern.service.ts

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ import {
1818
TestStatus,
1919
} from '@prisma/client';
2020
import * as postmark from 'postmark';
21-
import { EmailService } from 'src/email/email.service';
2221
import { PrismaService } from 'src/prisma.service';
2322

2423
import * as disposableEmailBlocklist from './disposable-email-blocklist.json';
2524
import { CreateInternDto } from './dto/createIntern.dto';
25+
import { EmailService } from 'src/email/email.service';
2626

2727
@Injectable()
2828
export class InternService {
@@ -242,13 +242,6 @@ export class InternService {
242242
243243
Link: https://bit.ly/primjer-inicijalnog`;
244244

245-
const trackImage = `<img src="https://internship.dump.hr/api/email/image?emailId=${emailId}" width="1" height="1" style="display:none" />`;
246-
247-
const generalTextEnding = `Lijep pozdrav,
248-
249-
DUMP Udruga mladih programera
250-
dump.hr ${trackImage}`;
251-
252245
let fullGeneralText = generalTextBody;
253246

254247
if (internToCreate.disciplines.includes(Discipline.Marketing))
@@ -261,7 +254,43 @@ export class InternService {
261254
From: 'info@dump.hr',
262255
To: internToCreate.email,
263256
Subject: 'Prijava na DUMP Internship',
264-
HtmlBody: `${fullGeneralText}\n\n${generalTextEnding}`,
257+
HtmlBody: `
258+
<!DOCTYPE html>
259+
<html lang="hr">
260+
<head>
261+
<meta charset="UTF-8" />
262+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
263+
<title>DUMP Internship 2025</title>
264+
</head>
265+
<body style="margin:0; padding:0; background-color:#f4f4f4; font-family:Arial, sans-serif;">
266+
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
267+
<tr>
268+
<td align="center" style="padding:20px 0;">
269+
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="600" style="background:#ffffff; border-radius:8px; box-shadow:0 2px 6px rgba(0,0,0,0.1); overflow:hidden;">
270+
<tr>
271+
<td align="center" style="padding:20px;">
272+
<img src="https://internship.dump.hr/api/email/logo?emailId=${emailId}" alt="DUMP Logo" width="180" />
273+
</td>
274+
</tr>
275+
<tr>
276+
<td style="padding:30px; color:#333333; font-size:16px; line-height:1.5;">
277+
${fullGeneralText.replace(/\n/g, '<br/>')}
278+
</td>
279+
</tr>
280+
<tr>
281+
<td style="padding:20px; background:#f9f9f9; color:#555555; font-size:14px; line-height:1.4; text-align:center;">
282+
Lijep pozdrav,<br/><br/>
283+
<strong>DUMP Udruga mladih programera</strong><br/>
284+
<a href="https://dump.hr" style="color:#007BFF; text-decoration:none;">dump.hr</a>
285+
</td>
286+
</tr>
287+
</table>
288+
</td>
289+
</tr>
290+
</table>
291+
</body>
292+
</html>
293+
`,
265294
MessageStream: 'outbound',
266295
});
267296

0 commit comments

Comments
 (0)