|
1 | | -import json |
2 | | -import pathlib |
3 | | -import tempfile |
4 | | -import time |
5 | 1 | from datetime import datetime |
6 | 2 |
|
7 | 3 | from celery import shared_task |
8 | | -from django.conf import settings |
9 | 4 | from django.contrib.auth.models import User |
10 | | -from django.core.files.base import ContentFile |
11 | 5 | from django.utils import timezone |
12 | | -from playwright.sync_api import sync_playwright |
13 | 6 | from rest_framework.authtoken.models import Token |
14 | 7 |
|
| 8 | +from api.playwright import render_pdf_from_url |
15 | 9 | from main.utils import logger_context |
16 | 10 |
|
17 | 11 | from .logger import logger |
18 | 12 | from .models import Export |
19 | | -from .utils import DebugPlaywright |
20 | 13 |
|
21 | 14 |
|
22 | | -def build_storage_state(tmp_dir, user, token, language="en"): |
23 | | - temp_file = pathlib.Path(tmp_dir, "storage_state.json") |
24 | | - temp_file.touch() |
| 15 | +def build_export_filename(export: Export, title: str) -> str: |
| 16 | + timestamp = datetime.now().strftime("%Y-%m-%d %H-%M-%S") |
25 | 17 |
|
26 | | - state = { |
27 | | - "origins": [ |
28 | | - { |
29 | | - "origin": settings.GO_WEB_INTERNAL_URL + "/", |
30 | | - "localStorage": [ |
31 | | - { |
32 | | - "name": "user", |
33 | | - "value": json.dumps( |
34 | | - { |
35 | | - "id": user.id, |
36 | | - "username": user.username, |
37 | | - "firstName": user.first_name, |
38 | | - "lastName": user.last_name, |
39 | | - "token": token.key, |
40 | | - } |
41 | | - ), |
42 | | - }, |
43 | | - {"name": "language", "value": json.dumps(language)}, |
44 | | - ], |
45 | | - } |
46 | | - ] |
| 18 | + prefix_map = { |
| 19 | + Export.ExportType.PER: "PER", |
| 20 | + Export.ExportType.SIMPLIFIED_EAP: "SIMPLIFIED EAP", |
| 21 | + Export.ExportType.FULL_EAP: "FULL EAP", |
47 | 22 | } |
48 | | - with open(temp_file, "w") as f: |
49 | | - json.dump(state, f) |
50 | | - return temp_file |
| 23 | + |
| 24 | + prefix = prefix_map.get(export.export_type, "DREF") |
| 25 | + return f"{prefix} {title} ({timestamp}).pdf" |
51 | 26 |
|
52 | 27 |
|
53 | 28 | @shared_task |
54 | | -def generate_url(url, export_id, user, title, language): |
| 29 | +def generate_export_pdf(export_id, title, set_user_language="en"): |
55 | 30 | export = Export.objects.get(id=export_id) |
56 | | - user = User.objects.get(id=user) |
| 31 | + user = User.objects.get(id=export.requested_by.id) |
57 | 32 | token = Token.objects.filter(user=user).last() |
58 | 33 | logger.info(f"Starting export: {export.pk}") |
59 | 34 |
|
60 | | - footer_template = """ |
61 | | - <div class="footer" style="width: 100%;font-size: 8px;color: #FEFEFE; bottom: 10px; position: absolute;"> |
62 | | - <div style="float: left; margin-top: 10px; margin-left: 40px;"> |
63 | | - Page <span class="pageNumber"></span> / <span class="totalPages"></span> |
64 | | - </div> |
65 | | - <div style="float: right; margin-right: 40px;"> |
66 | | - <svg |
67 | | - xmlns="http://www.w3.org/2000/svg" |
68 | | - viewBox="0 0 89.652 89.654" |
69 | | - height="48" |
70 | | - width="48" |
71 | | - > |
72 | | - <path |
73 | | - d="M50.284 18.637a5.14 5.14 0 00-5.136-5.135 5.139 5.139 0 00-5.135 5.135 5.141 5.141 0 005.135 5.138 5.146 5.146 0 005.136-5.138M28.416 63.032a5.143 5.143 0 00-5.138 5.138 5.14 5.14 0 005.138 5.133 5.14 5.14 0 005.136-5.133 5.143 5.143 0 00-5.136-5.138M45.151 34.057a7.021 7.021 0 00-7.02 7.025 7.02 7.02 0 0014.04 0 7.021 7.021 0 00-7.02-7.025M61.883 63.032a5.143 5.143 0 00-5.135 5.138 5.138 5.138 0 005.135 5.133 5.14 5.14 0 005.136-5.133 5.143 5.143 0 00-5.136-5.138" |
74 | | - class="st1" |
75 | | - fill="#F5333F" |
76 | | - /> |
77 | | - <path |
78 | | - d="M61.883 75.769c-4.19 0-7.601-3.41-7.601-7.602 0-2.32 1.05-4.4 2.696-5.794L49.726 50.26a10.205 10.205 0 01-4.575 1.085c-1.648 0-3.196-.397-4.577-1.085l-7.252 12.113a7.571 7.571 0 012.693 5.794c0 4.191-3.408 7.602-7.599 7.602-4.19 0-7.601-3.41-7.601-7.602 0-4.19 3.41-7.601 7.601-7.601.984 0 1.926.196 2.791.54l7.303-12.2a10.236 10.236 0 01-3.63-7.827c0-5.254 3.947-9.58 9.038-10.189v-4.762c-3.606-.59-6.368-3.72-6.368-7.49 0-4.192 3.41-7.602 7.601-7.602s7.599 3.41 7.599 7.601c0 3.77-2.762 6.9-6.366 7.49v4.763c5.093.611 9.038 4.935 9.038 10.19a10.23 10.23 0 01-3.633 7.826l7.306 12.2a7.544 7.544 0 012.791-.54c4.191 0 7.599 3.41 7.599 7.601s-3.41 7.602-7.602 7.602m-49.286-34.65c0-5.485 3.44-10.057 9.194-10.057 4.194 0 7.715 2.236 8.226 6.562h-3.281c-.32-2.524-2.524-3.818-4.945-3.818-4.117 0-5.834 3.627-5.834 7.313s1.717 7.313 5.834 7.313c3.44.056 5.32-2.016 5.376-5.268h-5.106v-2.556h8.173v10.11h-2.151l-.51-2.257c-1.803 2.043-3.44 2.715-5.78 2.715-5.754 0-9.196-4.57-9.196-10.057M44.826 0C20.07 0 0 20.069 0 44.828c0 24.755 20.071 44.826 44.826 44.826 24.757 0 44.826-20.071 44.826-44.826C89.652 20.068 69.582 0 44.826 0" |
79 | | - class="st1" |
80 | | - fill="#F5333F" |
81 | | - /> |
82 | | - </svg> |
83 | | - </div> |
84 | | - </div> |
85 | | - """ # noqa: E501 |
86 | | - |
87 | 35 | try: |
88 | | - with tempfile.TemporaryDirectory() as tmp_dir: |
89 | | - with sync_playwright() as p: |
90 | | - browser = p.chromium.connect(settings.PLAYWRIGHT_SERVER_URL) |
91 | | - # NOTE: DREF Export use the language from request |
92 | | - if export.export_type in [ |
93 | | - Export.ExportType.DREF, |
94 | | - Export.ExportType.OPS_UPDATE, |
95 | | - Export.ExportType.FINAL_REPORT, |
96 | | - ]: |
97 | | - storage_state = build_storage_state( |
98 | | - tmp_dir, |
99 | | - user, |
100 | | - token, |
101 | | - language, |
102 | | - ) |
103 | | - else: |
104 | | - # NOTE: Other Export types use default language (en) |
105 | | - storage_state = build_storage_state( |
106 | | - tmp_dir, |
107 | | - user, |
108 | | - token, |
109 | | - ) |
110 | | - context = browser.new_context(storage_state=storage_state) |
111 | | - page = context.new_page() |
112 | | - if settings.DEBUG_PLAYWRIGHT: |
113 | | - DebugPlaywright.debug(page) |
114 | | - # FIXME: Use of Timeout correct? |
115 | | - timeout = 300_000 # 5 min |
116 | | - page.goto(url, timeout=timeout) |
117 | | - time.sleep(5) |
118 | | - page.wait_for_selector("#pdf-preview-ready", state="attached", timeout=timeout) |
119 | | - if export.export_type == Export.ExportType.PER: |
120 | | - file_name = f'PER {title} ({datetime.now().strftime("%Y-%m-%d %H-%M-%S")}).pdf' |
121 | | - elif export.export_type == Export.ExportType.SIMPLIFIED_EAP: |
122 | | - file_name = f'SIMPLIFIED EAP {title} ({datetime.now().strftime("%Y-%m-%d %H-%M-%S")}).pdf' |
123 | | - elif export.export_type == Export.ExportType.FULL_EAP: |
124 | | - file_name = f'FULL EAP {title} ({datetime.now().strftime("%Y-%m-%d %H-%M-%S")}).pdf' |
125 | | - else: |
126 | | - file_name = f'DREF {title} ({datetime.now().strftime("%Y-%m-%d %H-%M-%S")}).pdf' |
127 | | - file = ContentFile( |
128 | | - page.pdf( |
129 | | - display_header_footer=True, |
130 | | - prefer_css_page_size=True, |
131 | | - print_background=True, |
132 | | - footer_template=footer_template, |
133 | | - header_template="<p></p>", |
134 | | - ) |
135 | | - ) |
136 | | - browser.close() |
137 | | - export.pdf_file.save(file_name, file) |
138 | | - export.status = Export.ExportStatus.COMPLETED |
139 | | - export.completed_at = timezone.now() |
140 | | - export.save( |
141 | | - update_fields=[ |
142 | | - "status", |
143 | | - "completed_at", |
144 | | - ] |
145 | | - ) |
| 36 | + file = render_pdf_from_url( |
| 37 | + url=export.url, |
| 38 | + user=user, |
| 39 | + token=token, |
| 40 | + language=set_user_language, |
| 41 | + ) |
| 42 | + |
| 43 | + file_name = build_export_filename(export, title) |
| 44 | + export.pdf_file.save(file_name, file) |
| 45 | + export.status = Export.ExportStatus.COMPLETED |
| 46 | + export.completed_at = timezone.now() |
| 47 | + export.save( |
| 48 | + update_fields=[ |
| 49 | + "status", |
| 50 | + "completed_at", |
| 51 | + ] |
| 52 | + ) |
146 | 53 | except Exception: |
147 | 54 | logger.error( |
148 | 55 | f"Failed to export PDF: {export.export_type}", |
|
0 commit comments