forked from shaba/openuds
Removing geraldo reports/reportlabs in favor of weasyprint
This commit is contained in:
parent
c9bea9cf78
commit
766786715d
@ -109,13 +109,16 @@ class Reports(model.BaseModelHandler):
|
||||
logger.debug('Report: {}'.format(report))
|
||||
result = report.generateEncoded()
|
||||
|
||||
return {
|
||||
data = {
|
||||
'mime_type': report.mime_type,
|
||||
'encoded': report.encoded,
|
||||
'filename': report.filename,
|
||||
'data': result
|
||||
}
|
||||
|
||||
logger.debug('Data: {}'.format(data))
|
||||
|
||||
return data
|
||||
except Exception as e:
|
||||
logger.exception('Generating report')
|
||||
return self.invalidRequestException(six.text_type(e))
|
||||
|
@ -33,17 +33,20 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext, ugettext_noop as _
|
||||
from django.template import loader
|
||||
|
||||
from uds.core.ui.UserInterface import UserInterface
|
||||
from uds.core.util import encoders
|
||||
from . import stock
|
||||
|
||||
import datetime
|
||||
import six
|
||||
from weasyprint import HTML, CSS
|
||||
from datetime import datetime
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
__updated__ = '2017-11-15'
|
||||
__updated__ = '2018-02-07'
|
||||
|
||||
|
||||
class Report(UserInterface):
|
||||
@ -82,6 +85,46 @@ class Report(UserInterface):
|
||||
raise Exception('Class does not includes an uuid!!!: {}'.format(cls))
|
||||
return cls.uuid
|
||||
|
||||
@staticmethod
|
||||
def asPDF(html, header=None, water=None):
|
||||
"""
|
||||
Renders an html as PDF.
|
||||
Uses the "report.css" as stylesheet
|
||||
"""
|
||||
with open(stock.getStockCssPath('report.css'), 'r') as f:
|
||||
css = f.read()
|
||||
|
||||
css = (
|
||||
css.replace("{header}", _('Report') if header is None else header)
|
||||
.replace('{page}', _('Page'))
|
||||
.replace('{of}', _('of'))
|
||||
.replace('{water}', 'UDS Enterprise' if water is None else water)
|
||||
.replace('{printed}', _('Printed in {now:%Y, %b %d} at {now:%H:%M}').format(now=datetime.now()))
|
||||
)
|
||||
|
||||
h = HTML(string=html)
|
||||
c = CSS(string=css)
|
||||
|
||||
pdf = h.write_pdf(stylesheets=[c])
|
||||
|
||||
with open('/home/dkmaster/kk/kk.pdf', 'wb') as f:
|
||||
f.write(pdf)
|
||||
|
||||
return pdf
|
||||
|
||||
@staticmethod
|
||||
def templateAsPDF(templateName, dct, header=None, water=None):
|
||||
"""
|
||||
Renders a template as PDF
|
||||
"""
|
||||
t = loader.get_template(templateName)
|
||||
|
||||
renderedHtml = t.render(dct)
|
||||
|
||||
logger.debug('HTML: {}'.format(renderedHtml))
|
||||
|
||||
return Report.asPDF(renderedHtml, header, water)
|
||||
|
||||
def __init__(self, values=None):
|
||||
"""
|
||||
Do not forget to invoke this in your derived class using
|
||||
@ -127,10 +170,14 @@ class Report(UserInterface):
|
||||
Basically calls generate and encodes resuslt as base64
|
||||
"""
|
||||
data = self.generate()
|
||||
with open('/home/dkmaster/kk/kk2.pdf', 'wb') as f:
|
||||
f.write(data)
|
||||
if self.encoded:
|
||||
return encoders.encode(data, 'base64', asText=True).replace('\n', '')
|
||||
else:
|
||||
return data
|
||||
data = encoders.encode(data, 'base64', asText=True).replace('\n', '')
|
||||
with open('/home/dkmaster/kk/kk2.base64', 'w') as f:
|
||||
f.write(data)
|
||||
|
||||
return data
|
||||
|
||||
def __str__(self):
|
||||
return 'Report {} with uuid {}'.format(self.name, self.uuid)
|
||||
|
32
server/src/uds/core/reports/css/report.css
Normal file
32
server/src/uds/core/reports/css/report.css
Normal file
@ -0,0 +1,32 @@
|
||||
@page {
|
||||
margin: 3cm 2cm; padding-left: 1.5cm;
|
||||
@top-center {
|
||||
content: "{header}";
|
||||
vertical-align: bottom;
|
||||
border-bottom: 0.5pt solid
|
||||
}
|
||||
@top-right {
|
||||
content: "{page} " counter(page)
|
||||
" {of} " counter(pages)
|
||||
}
|
||||
@bottom-left {
|
||||
content: "Generated by UDS"
|
||||
}
|
||||
@bottom-right {
|
||||
content: '{printed}'
|
||||
}
|
||||
@left-top {
|
||||
content: "{water}"; font: .5cm/1.5 Fontin Sans;
|
||||
background: #005a9c; color: #fff; text-align: right;
|
||||
padding-right: 2em; height: 1.5em; width: 10cm;
|
||||
transform-origin: 100% 0;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
}
|
||||
body { text-align: justify }
|
||||
h1 { bookmark-level: none }
|
||||
|
||||
tbody tr:nth-child(odd) {
|
||||
background-color: #4C8BF5;
|
||||
color: #fff;
|
||||
}
|
@ -39,10 +39,19 @@ import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
__updated__ = '2015-04-29'
|
||||
__updated__ = '2018-02-07'
|
||||
|
||||
LOGO = 'logo-512.png'
|
||||
CSS = 'report.css'
|
||||
|
||||
|
||||
def getStockImagePath(stockImg):
|
||||
def getStockImagePath(stockImg=None):
|
||||
if stockImg is None:
|
||||
stockImg = LOGO
|
||||
return tools.packageRelativeFile(__name__, 'stock_images/' + stockImg)
|
||||
|
||||
|
||||
def getStockCssPath(css=None):
|
||||
if css is None:
|
||||
css = CSS
|
||||
return tools.packageRelativeFile(__name__, 'css/' + css)
|
||||
|
@ -46,8 +46,7 @@ import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
__updated__ = '2017-05-10'
|
||||
|
||||
__updated__ = '2018-02-07'
|
||||
|
||||
availableReports = []
|
||||
|
||||
@ -78,10 +77,10 @@ def __init__():
|
||||
# Dinamycally import children of this package. The __init__.py files must import classes
|
||||
pkgpath = os.path.dirname(sys.modules[__name__].__file__)
|
||||
# TODO: Make this work with python3 also!!! (look for alternative, we have time...)
|
||||
if six.PY2:
|
||||
for _, name, _ in pkgutil.iter_modules([pkgpath]):
|
||||
__import__(name, globals(), locals(), [], 1)
|
||||
for _, name, _ in pkgutil.iter_modules([pkgpath]):
|
||||
__import__(name, globals(), locals(), [], 1)
|
||||
|
||||
recursiveAdd(reports.Report)
|
||||
|
||||
|
||||
__init__()
|
||||
|
@ -34,7 +34,6 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
from uds.core.ui.UserInterface import gui
|
||||
from uds.core.reports import stock
|
||||
from uds.models import Authenticator
|
||||
|
||||
import six
|
||||
@ -42,62 +41,11 @@ import csv
|
||||
|
||||
from .base import ListReport
|
||||
|
||||
from geraldo.generators.pdf import PDFGenerator
|
||||
from geraldo import Report, landscape, ReportBand, ObjectValue, SystemField, BAND_WIDTH, Label, Image
|
||||
from reportlab.lib.pagesizes import A4
|
||||
from reportlab.lib.units import cm
|
||||
from reportlab.lib.enums import TA_RIGHT, TA_CENTER
|
||||
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
__updated__ = '2015-06-21'
|
||||
|
||||
|
||||
class UsersReport(Report):
|
||||
title = ''
|
||||
author = 'UDS'
|
||||
|
||||
print_if_empty = True
|
||||
page_size = A4
|
||||
margin_left = 2 * cm
|
||||
margin_top = 0.5 * cm
|
||||
margin_right = 0.5 * cm
|
||||
margin_bottom = 0.5 * cm
|
||||
|
||||
class band_detail(ReportBand):
|
||||
height = 0.5 * cm
|
||||
elements = (
|
||||
ObjectValue(attribute_name='name', left=0.5 * cm, style={'fontName': 'Helvetica', 'fontSize': 8}),
|
||||
ObjectValue(attribute_name='real_name', left=6 * cm, style={'fontName': 'Helvetica', 'fontSize': 8}),
|
||||
ObjectValue(attribute_name='last_access', left=15 * cm, style={'fontName': 'Helvetica', 'fontSize': 8}),
|
||||
)
|
||||
|
||||
class band_page_header(ReportBand):
|
||||
height = 2.0 * cm
|
||||
elements = [
|
||||
SystemField(expression='%(report_title)s', top=0.5 * cm, left=0, width=BAND_WIDTH,
|
||||
style={'fontName': 'Helvetica-Bold', 'fontSize': 14, 'alignment': TA_CENTER}),
|
||||
|
||||
Label(text=_('User ID'), top=1.5 * cm, left=0.5 * cm),
|
||||
Label(text=_('Real Name'), top=1.5 * cm, left=6 * cm),
|
||||
Label(text=_('Last access'), top=1.5 * cm, left=15 * cm),
|
||||
SystemField(expression=_('Page %(page_number)d of %(page_count)d'), top=0.1 * cm,
|
||||
width=BAND_WIDTH, style={'alignment': TA_RIGHT}),
|
||||
Image(filename=stock.getStockImagePath(stock.LOGO), left=0.1 * cm, top=0.0 * cm, width=2 * cm, height=2 * cm),
|
||||
]
|
||||
borders = {'bottom': True}
|
||||
|
||||
class band_page_footer(ReportBand):
|
||||
height = 0.5 * cm
|
||||
elements = [
|
||||
Label(text='Generated by UDS', top=0.1 * cm),
|
||||
SystemField(expression=_('Printed in %(now:%Y, %b %d)s at %(now:%H:%M)s'), top=0.1 * cm,
|
||||
width=BAND_WIDTH, style={'alignment': TA_RIGHT}),
|
||||
]
|
||||
borders = {'top': True}
|
||||
__updated__ = '2018-02-07'
|
||||
|
||||
|
||||
class ListReportUsers(ListReport):
|
||||
@ -131,12 +79,12 @@ class ListReportUsers(ListReport):
|
||||
auth = Authenticator.objects.get(uuid=self.authenticator.value)
|
||||
users = auth.users.order_by('name')
|
||||
|
||||
output = six.StringIO()
|
||||
|
||||
report = UsersReport(queryset=users)
|
||||
report.title = _('Users List for {}').format(auth.name)
|
||||
report.generate_by(PDFGenerator, filename=output)
|
||||
return output.getvalue()
|
||||
return self.templateAsPDF(
|
||||
'uds/reports/lists/users.html',
|
||||
dct={'users': users},
|
||||
header=ugettext('Users List for {}').format(auth.name),
|
||||
water=auth.name
|
||||
)
|
||||
|
||||
|
||||
class ListReportsUsersCSV(ListReportUsers):
|
||||
@ -154,7 +102,7 @@ class ListReportsUsersCSV(ListReportUsers):
|
||||
self.filename = auth.name + '.csv'
|
||||
|
||||
def generate(self):
|
||||
output = StringIO.StringIO()
|
||||
output = six.StringIO()
|
||||
writer = csv.writer(output)
|
||||
auth = Authenticator.objects.get(uuid=self.authenticator.value)
|
||||
users = auth.users.order_by('name')
|
||||
|
@ -31,10 +31,10 @@
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
|
||||
from .usage import StatsReportUsage
|
||||
from .login import StatsReportLogin, StatsReportLoginCSV
|
||||
from .pool_performance import PoolPerformanceReport
|
||||
from .usage_by_pool import UsageByPool
|
||||
from .pools_usage import CountersPoolAssigned
|
||||
from .usage_summary_pool import UsageSummaryByPool
|
||||
# from .usage import StatsReportUsage
|
||||
# from .login import StatsReportLogin, StatsReportLoginCSV
|
||||
# from .pool_performance import PoolPerformanceReport
|
||||
# from .usage_by_pool import UsageByPool
|
||||
# from .pools_usage import CountersPoolAssigned
|
||||
# from .usage_summary_pool import UsageSummaryByPool
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# jshint strict: true
|
||||
# jshint strict: true
|
||||
gui.reports = new GuiElement(api.reports, "reports")
|
||||
gui.reports.link = (event) ->
|
||||
"use strict"
|
||||
@ -9,7 +9,7 @@ gui.reports.link = (event) ->
|
||||
reports: "reports-placeholder"
|
||||
)
|
||||
gui.setLinksEvents()
|
||||
|
||||
|
||||
tableId = gui.reports.table(
|
||||
icon: 'reports'
|
||||
container: "reports-placeholder"
|
||||
@ -43,14 +43,18 @@ gui.reports.link = (event) ->
|
||||
closeFnc()
|
||||
gui.doLog data
|
||||
if data.encoded
|
||||
gui.doLog('Data is encoded')
|
||||
content = base64.decode(data.data)
|
||||
gui.doLog('Length: ' + content.length)
|
||||
else
|
||||
content = data.data
|
||||
setTimeout( (()->
|
||||
byteContent = new Uint8Array(content.length)
|
||||
byteContent[i] = content.charCodeAt(i) for i in [0..content.length-1]
|
||||
|
||||
blob = new Blob([byteContent], type: data.content_type)
|
||||
saveAs(
|
||||
new Blob([content],
|
||||
type: data.content_type
|
||||
),
|
||||
blob,
|
||||
data.filename
|
||||
)
|
||||
), 100)
|
||||
@ -83,4 +87,4 @@ gui.reports.link = (event) ->
|
||||
)
|
||||
return
|
||||
|
||||
false
|
||||
false
|
||||
|
49
server/src/uds/templates/uds/reports/lists/users.html
Normal file
49
server/src/uds/templates/uds/reports/lists/users.html
Normal file
@ -0,0 +1,49 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Report test</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="content">
|
||||
<table style="width: 100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Age</th>
|
||||
<th>Parent</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>name of person</td>
|
||||
<td>123</td>
|
||||
<td>his</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>name of person 2</td>
|
||||
<td>123 2</td>
|
||||
<td>his 2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>name of person 3</td>
|
||||
<td>123 3</td>
|
||||
<td>his </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>name of person 4</td>
|
||||
<td>123 4</td>
|
||||
<td>his 4</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>name of person 5</td>
|
||||
<td>123 5</td>
|
||||
<td>his 5</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<p style="page-break-before: always">
|
||||
This is a new page
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user