Skip to content

Commit 4cfbdb1

Browse files
committed
Update DQ email PDF rendering and API integration
1 parent 3ece128 commit 4cfbdb1

File tree

6 files changed

+42
-20
lines changed

6 files changed

+42
-20
lines changed

api/data_ingestion/internal/email.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import base64
12
from typing import Any
23

34
import requests
@@ -182,7 +183,7 @@ def send_dq_report_email_with_pdf(body: EmailRenderRequest[DqReportRenderRequest
182183
html_content = email_data.get("html")
183184
text_content = email_data.get("text")
184185

185-
# Generate PDF
186+
# Generate PDF (renderer returns binary to avoid large JSON truncation)
186187
pdf_res = requests.post(
187188
f"{settings.EMAIL_RENDERER_SERVICE_URL}/email/dq-report-pdf",
188189
headers={
@@ -198,11 +199,14 @@ def send_dq_report_email_with_pdf(body: EmailRenderRequest[DqReportRenderRequest
198199
except JSONDecodeError:
199200
raise HTTPError(pdf_res.text) from None
200201

201-
pdf_data = pdf_res.json()
202-
pdf_base64 = pdf_data.get("pdf")
203-
pdf_filename = pdf_data.get(
204-
"filename", f"data-quality-report-{body.props.country}.pdf"
205-
)
202+
pdf_bytes = pdf_res.content
203+
pdf_base64 = base64.b64encode(pdf_bytes).decode("ascii")
204+
disp = pdf_res.headers.get("Content-Disposition") or ""
205+
pdf_filename = f"data-quality-report-{body.props.country}.pdf"
206+
if "filename=" in disp:
207+
part = disp.split("filename=", 1)[1].strip().strip('"')
208+
if part:
209+
pdf_filename = part
206210

207211
# Use base64 string directly as required by Mailjet v3 send API
208212
attachment = {
@@ -263,7 +267,15 @@ async def generate_dq_report_pdf(body: EmailRenderRequest[DqReportRenderRequest]
263267
except JSONDecodeError:
264268
raise HTTPError(res.text) from None
265269
logger.info(f"PDF generation response: {res.status_code}")
266-
return res.json()
270+
pdf_bytes = res.content
271+
pdf_b64 = base64.b64encode(pdf_bytes).decode("ascii")
272+
disp = res.headers.get("Content-Disposition") or ""
273+
filename = f"data-quality-report-{body.props.country}-{body.props.uploadId}.pdf"
274+
if "filename=" in disp:
275+
part = disp.split("filename=", 1)[1].strip().strip('"')
276+
if part:
277+
filename = part
278+
return {"pdf": pdf_b64, "filename": filename}
267279

268280

269281
async def generate_dq_report_pdf_from_payload(payload: dict) -> dict:
@@ -283,7 +295,15 @@ async def generate_dq_report_pdf_from_payload(payload: dict) -> dict:
283295
except JSONDecodeError:
284296
raise HTTPError(res.text) from None
285297
logger.info(f"PDF generation response: {res.status_code}")
286-
return res.json()
298+
pdf_bytes = res.content
299+
pdf_b64 = base64.b64encode(pdf_bytes).decode("ascii")
300+
disp = res.headers.get("Content-Disposition") or ""
301+
filename = "data-quality-report.pdf"
302+
if "filename=" in disp:
303+
part = disp.split("filename=", 1)[1].strip().strip('"')
304+
if part:
305+
filename = part
306+
return {"pdf": pdf_b64, "filename": filename}
287307

288308

289309
def send_master_data_release_notification(

email/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

email/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"@hono/zod-validator": "^0.2.2",
1616
"@react-email/components": "^0.0.24",
1717
"@react-email/render": "^1.0.1",
18-
"@react-pdf/renderer": "^3.4.4",
18+
"@react-pdf/renderer": "^3.4.5",
1919
"@sentry/node": "^5.5.0",
2020
"@sentry/profiling-node": "^8.37.1",
2121
"hono": "^4.5.9",

email/src/emails/dq-report-pdf.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ const DataQualityReportPDF: React.FC<PDFReportProps> = ({
251251
<Text style={styles.sectionTitle}>School ID Checks</Text>
252252
<MetricRow label="Duplicate School IDs" value={duplicateSchoolIds} />
253253
<MetricRow label="Missing School IDs" value={missingSchoolIds} />
254-
<MetricRow label="Missing School Names D" value={missingSchoolNames} />
254+
<MetricRow label="Missing School Names" value={missingSchoolNames} />
255255
<CommentBox>{''}</CommentBox>
256256
</View>
257257
</View>

email/src/index.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,15 @@ app.post(
112112
};
113113

114114
const pdfBuffer = await generateDataQualityReportPDF(pdfData);
115-
116-
// Return PDF as base64 for easy attachment
117-
const pdfBase64 = pdfBuffer.toString('base64');
118-
119-
return ctx.json({
120-
pdf: pdfBase64,
121-
filename: `data-quality-report-${json.country}-${json.uploadId}.pdf`
115+
const filename = `data-quality-report-${json.country}-${json.uploadId}.pdf`;
116+
117+
// Return PDF as binary to avoid huge JSON/base64 response truncation
118+
return new Response(pdfBuffer, {
119+
status: 200,
120+
headers: {
121+
"Content-Type": "application/pdf",
122+
"Content-Disposition": `attachment; filename="${filename}"`,
123+
},
122124
});
123125
},
124126
);

email/src/types/data-quality-checks.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ const Check = z.object({
77
count_overall: z.number(),
88
count_passed: z.number(),
99
description: z.string(),
10-
percent_failed: z.number(),
11-
percent_passed: z.number(),
10+
percent_failed: z.number().nullable(),
11+
percent_passed: z.number().nullable(),
1212
dq_remarks: z.string().optional(),
1313
});
1414

0 commit comments

Comments
 (0)