1
+ import base64
1
2
import json
2
3
import os
3
4
import re
@@ -18,14 +19,23 @@ def strip_dangerous_s3_chars(filename: str) -> str:
18
19
return re .sub (r"[^0-9a-zA-Z_\.\-\s]" , "" , filename )
19
20
20
21
21
- def pdf_with_splat (
22
+ def pdf_from_html (
22
23
body_html : str ,
23
24
* ,
24
25
bucket_name : Optional [str ] = None ,
25
26
s3_filepath : Optional [str ] = None ,
27
+ javascript : bool = False ,
26
28
fields : Optional [Dict ] = None ,
27
29
conditions : Optional [List [List ]] = None ,
28
30
) -> Optional [bytes ]:
31
+ """Generates a pdf from html using the splat lambda function.
32
+
33
+ :param body_html: the html to convert to pdf
34
+ :param bucket_name: the bucket to upload the html to. defaults to config.default_bucket_name
35
+ :param s3_filepath: the path to upload the pdf to. defaults to a random path in the bucket
36
+ :param fields: additional fields to add to the presigned url
37
+ :param conditions: additional conditions to add to the presigned url
38
+ """
29
39
bucket_name = bucket_name or config .default_bucket_name
30
40
if not bucket_name :
31
41
raise SplatPDFGenerationFailure (
@@ -74,7 +84,11 @@ def pdf_with_splat(
74
84
)
75
85
76
86
splat_body = json .dumps (
77
- {"document_url" : document_url , "presigned_url" : presigned_url }
87
+ {
88
+ "document_url" : document_url ,
89
+ "presigned_url" : presigned_url ,
90
+ "javascript" : javascript ,
91
+ }
78
92
)
79
93
80
94
response = lambda_client .invoke (
@@ -127,3 +141,59 @@ def pdf_with_splat(
127
141
except (KeyError , JSONDecodeError ):
128
142
splat_error = splat_response
129
143
raise SplatPDFGenerationFailure (f"Error returned from splat: { splat_error } " )
144
+
145
+
146
+ def pdf_from_html_without_s3 (
147
+ body_html : str ,
148
+ javascript : bool = False ,
149
+ ) -> Optional [bytes ]:
150
+ """Generates a pdf from html without using s3. This is useful for small pdfs and html documents.
151
+
152
+ The maximum size of the html document is 6MB. The maximum size of the pdf is 6MB.
153
+ """
154
+ session = config .get_session_fn ()
155
+ lambda_client = session .client (
156
+ "lambda" ,
157
+ region_name = config .function_region ,
158
+ config = Config (read_timeout = 60 * 15 , retries = {"max_attempts" : 0 }),
159
+ )
160
+
161
+ splat_body = json .dumps ({"document_content" : body_html , "javascript" : javascript })
162
+
163
+ response = lambda_client .invoke (
164
+ FunctionName = config .function_name ,
165
+ Payload = json .dumps ({"body" : splat_body }),
166
+ )
167
+
168
+ # Check response of the invocation. Note that a successful invocation doesn't mean the PDF was generated.
169
+ if response .get ("StatusCode" ) != 200 :
170
+ raise SplatPDFGenerationFailure (
171
+ "Invalid response while invoking splat lambda -"
172
+ f" { response .get ('StatusCode' )} "
173
+ )
174
+
175
+ # Parse lambda response
176
+ try :
177
+ splat_response = json .loads (response ["Payload" ].read ().decode ("utf-8" ))
178
+ except (KeyError , AttributeError ):
179
+ raise SplatPDFGenerationFailure ("Invalid lambda response format" )
180
+ except JSONDecodeError :
181
+ raise SplatPDFGenerationFailure ("Error decoding splat response body as json" )
182
+
183
+ # ==== Success ====
184
+ if splat_response .get ("statusCode" ) == 200 :
185
+ return base64 .b64decode (splat_response .get ("body" ))
186
+ # ==== Failure ====
187
+ # Lambda timeout et al.
188
+ elif error_message := splat_response .get ("errorMessage" ):
189
+ raise SplatPDFGenerationFailure (
190
+ f"Error returned from lambda invocation: { error_message } "
191
+ )
192
+ # All other errors
193
+ else :
194
+ # Try to extract an error message from splat response
195
+ try :
196
+ splat_error = json .loads (splat_response ["body" ])["errors" ][0 ]
197
+ except (KeyError , JSONDecodeError ):
198
+ splat_error = splat_response
199
+ raise SplatPDFGenerationFailure (f"Error returned from splat: { splat_error } " )
0 commit comments