Skip to content

Commit 1bb979d

Browse files
author
Jon Garcia
committed
still working on html to pdf
1 parent 459aa05 commit 1bb979d

File tree

6 files changed

+60
-20
lines changed

6 files changed

+60
-20
lines changed

api/templates/print.html

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
{% extends "header.html" %}
22
{% block style %}
3-
{{ extra_css }}
3+
{% for css in extra_css %}
4+
<link rel="stylesheet" href="{{ css }}">
5+
{% endfor %}
46
{{ styles }}
57
{% endblock %}
68

api/tests/test_html_to_pdf.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,24 @@
77

88
def test_api_get_project_report(client: FlaskClient, admin_login: dict):
99
from urllib.parse import quote
10+
11+
resp = client.post(endpoint('/to-pdf'))
12+
assert resp.status_code == 401
13+
assert resp.json['error'] == 'Token is missing!'
14+
15+
resp = client.post(endpoint('/to-pdf'), headers=admin_login)
16+
assert resp.status_code == 400
17+
assert resp.json['error'] == 'Missing necessary arguments'
18+
1019
data = {
11-
'html': b64encode(quote('<div></div>').encode()).decode(),
12-
'style': b64encode(quote('style></style>').encode()).decode(),
13-
'extra_css': b64encode(quote('http://file.com/extrashee.css').encode()).decode(),
20+
'html': b64encode(quote('<div><h1>Hello</h1></div>').encode()).decode(),
21+
'style': b64encode(quote('<style>h1 {color: red;}</style>').encode()).decode(),
22+
'extra_css': [b64encode(
23+
quote('https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css').encode()
24+
).decode()],
1425
'uid': 'filename'
1526
}
1627

1728
resp = client.post(endpoint('/to-pdf'), json=data, headers=admin_login)
1829
assert resp.status_code == 200
19-
assert resp.headers['Content-Disposition'] == "download;filename='filename.pdf'"
30+
#assert resp.headers['Content-Disposition'] == "download;filename='filename.pdf'"

api/views/shared.py

+17-9
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
import re
33
from datetime import datetime
44
from io import BytesIO
5+
from urllib.parse import unquote
56

67
import pdfkit
78
import pytz
89

910
from PIL import Image
10-
from flask import request, current_app, render_template
11+
from flask import request, current_app, render_template, send_file
1112
from flask_mail import Message
1213
from markupsafe import Markup
1314

@@ -89,20 +90,27 @@ def email_html(email: str, body, template, title=''):
8990

9091
class HtmlToPdf(API):
9192

93+
@token_required
9294
def post(self):
93-
extra_css = ''
95+
extra_css = []
9496
styles = ''
9597
data = request.get_json()
96-
html = base64.b64decode(data['html']).decode()
97-
filename = data['uid'] = '.pdf'
98+
if data is None or 'html' not in data or 'uid' not in data:
99+
raise HttpException('Missing necessary arguments')
100+
html = unquote(base64.b64decode(data['html']).decode())
101+
filename = data['uid'] + '.pdf'
98102
if 'extra_css' in data:
99-
extra_css = base64.b64decode(data['extra_css']).decode()
103+
extra_css = [unquote(base64.b64decode(link).decode()) for link in data['extra_css']]
100104

101105
if 'style' in data:
102-
styles = base64.b64decode(data['style']).decode()
106+
styles = unquote(base64.b64decode(data['style']).decode())
107+
108+
template = render_template('print.html', body=Markup(html), styles=Markup(styles), extra_css=extra_css)
103109

104-
template = render_template('print.html', body=html, extra_styles=styles, extra_css=extra_css)
110+
with open('file.html', 'w') as pdf:
111+
pdf.write(template)
105112

106-
pdfkit.from_string(template, filename)
113+
fp = BytesIO()
114+
pdfkit.from_file('file.html', 'out.pdf')
107115

108-
return template
116+
return send_file('out.pdf', attachment_filename=filename)

service.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ run_tests() {
3535
FLAGS="$FLAGS $3"
3636
APPEND="${@:4}"
3737
fi
38-
COMMAND="pytest $FLAGS tests/$APPEND"
38+
COMMAND="pytest $FLAGS $APPEND"
3939
printf "%s\n" "$COMMAND"
4040

4141
docker exec -ti "$CONTAINER_ID" bash -c \

static/js/actions/projectActions.js

+21-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ export const REPORT_FETCHED = 'REPORT_FETCHED';
1919
export const REPORTS_FETCHED = 'REPORTS_FETCHED';
2020
export const REPORTS_FETCH_FAILED = 'REPORTS_FETCH_FAILED';
2121
export const REPORT_CLEAR = 'REPORT_CLEAR';
22+
export const REPORT_DOWNLOADED = 'REPORT_CLEAR';
23+
export const REPORT_DOWNLOADING = 'REPORT_DOWNLOADING';
24+
export const REPORT_DOWNLOAD_FAILED = 'REPORT_CLEAR';
2225

2326
export const fetchProjects = (fail) =>
2427
(dispatch) => {
@@ -116,7 +119,7 @@ export const fetchReportByUid = (uid) =>
116119
};
117120

118121
export const fetchReports = (project_id, uid) =>
119-
(dispatch) => {
122+
dispatch => {
120123
dispatch({ type: REPORT_FETCHING });
121124
const q = { project_id };
122125
if (uid) {
@@ -127,7 +130,7 @@ export const fetchReports = (project_id, uid) =>
127130
url: `/reports?${urlEncode.stringify(q)}`,
128131
method: 'GET',
129132
headers: header
130-
}).then((resp) => {
133+
}).then(resp => {
131134
dispatch({ type: REPORTS_FETCHED, payload: resp.data });
132135
}, err => {
133136
dispatch({ type: REPORTS_FETCH_FAILED, payload: err });
@@ -140,3 +143,19 @@ export const setCurrentReport = (report) =>
140143

141144
export const currentReportClear = () =>
142145
dispatch => dispatch({ type: REPORT_CLEAR });
146+
147+
export const download_report = (filename, html, styles, extra_css = []) =>
148+
dispatch => {
149+
dispatch({ type: REPORT_DOWNLOADING });
150+
token.through().then(header =>
151+
api({
152+
url: '/to-pdf',
153+
method: 'POST',
154+
headers: header
155+
}, { filename, html, styles, extra_css }).then(resp => {
156+
dispatch({ type: REPORT_DOWNLOADED, payload: resp.data });
157+
}, err => {
158+
dispatch({ type: REPORT_DOWNLOAD_FAILED, payload: err });
159+
})
160+
);
161+
};

static/js/components/projects/reports/Report.jsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import React from 'react';
66
import PropTypes from 'prop-types';
77
import Breadcrumbs from '../../../utils/Breadcrumbs';
8-
import { currentReportClear, fetchReportByUid } from '../../../actions/projectActions';
8+
import { currentReportClear, download_report, fetchReportByUid } from '../../../actions/projectActions';
99
import Spinner from '../../../utils/Spinner';
1010
import Table from '../../../utils/Table';
1111
import { formatDateEs, numberWithCommas } from '../../../utils/helpers';
@@ -18,6 +18,7 @@ export default class Report extends React.Component {
1818
if (props.projects.currentReport.project_id === '') {
1919
props.dispatch(fetchReportByUid(props.match.params.report_uid));
2020
}
21+
this.download = this.download.bind(this);
2122
}
2223

2324
render() {
@@ -56,8 +57,7 @@ export default class Report extends React.Component {
5657
let html = '<div class="monthly-report"><div class="report-body">';
5758
html += document.querySelector('.report-body').innerHTML;
5859
html += '</div></div>';
59-
console.log(styles);
60-
console.log(html);
60+
this.props.dispatch(download_report(this.props.match.params.report_uid, html, styles));
6161
}
6262

6363
getRender({ projects: { currentReport }}) {

0 commit comments

Comments
 (0)