advancing on a reporting system compatible with python2 & python3

This commit is contained in:
Adolfo Gómez García 2018-02-07 21:38:17 +01:00
parent a9844fc8b4
commit 225bf75770
8 changed files with 131 additions and 111 deletions

View File

@ -49,19 +49,6 @@ logger = logging.getLogger(__name__)
__updated__ = '2018-02-07'
# url fetcher for weasyprint
def report_fetcher(url):
logger.debug('Getting url for weasyprint {}'.format(url))
if url.startswith('stock://'):
imagePath = stock.getStockImagePath(url[8:])
with open(imagePath, 'rb') as f:
image = f.read()
return dict(string=image,
mime_type='image/png')
else:
return default_url_fetcher(url)
class Report(UserInterface):
mime_type = 'application/pdf' # Report returns pdfs by default, but could be anything else
name = _('Base Report') # Report name
@ -99,11 +86,30 @@ class Report(UserInterface):
return cls.uuid
@staticmethod
def asPDF(html, header=None, water=None):
def asPDF(html, header=None, water=None, images=None):
"""
Renders an html as PDF.
Uses the "report.css" as stylesheet
"""
# url fetcher for weasyprint
def report_fetcher(url):
logger.debug('Getting url for weasyprint {}'.format(url))
if url.startswith('stock://'):
imagePath = stock.getStockImagePath(url[8:])
with open(imagePath, 'rb') as f:
image = f.read()
return dict(string=image,
mime_type='image/png')
elif url.startswith('image://'):
if isinstance(images, dict):
logger.debug('Getting image {} --> {}'.format(url[8:], images.get(url[8:])))
img = images.get(url[8:])
return dict(string=img,
mime_type='image/png')
else:
return default_url_fetcher(url)
with open(stock.getStockCssPath('report.css'), 'r') as f:
css = f.read()
@ -121,13 +127,13 @@ class Report(UserInterface):
return h.write_pdf(stylesheets=[c])
@staticmethod
def templateAsPDF(templateName, dct, header=None, water=None):
def templateAsPDF(templateName, dct, header=None, water=None, images=None):
"""
Renders a template as PDF
"""
t = loader.get_template(templateName)
return Report.asPDF(t.render(dct), header, water)
return Report.asPDF(t.render(dct), header=header, water=water, images=images)
def __init__(self, values=None):
"""

View File

@ -3,7 +3,9 @@
@top-center {
content: "{header}";
vertical-align: bottom;
border-bottom: 0.5pt solid
border-bottom: 0.5pt solid;
font-weight: bolder;
}
@top-right {
content: "{page} " counter(page)
@ -17,7 +19,7 @@
}
@left-top {
content: "{water}"; font: .5cm/1.5 Fontin Sans;
background: #005a9c; color: #fff; text-align: right;
background: #557891; color: #fff; text-align: right;
padding-right: 2em; height: 1.5em; width: 10cm;
transform-origin: 100% 0;
transform: rotate(-90deg);
@ -38,6 +40,13 @@ body {
h1 { bookmark-level: none; }
tbody tr:nth-child(odd) {
background-color: #4C8BF5;
color: #fff;
background-color: rgb(199, 222, 241);
/*color: #fff; */
}
img.center {
display: block;
margin-left: auto;
margin-right: auto;
/* width: 50%; */
}

View File

@ -81,7 +81,10 @@ class ListReportUsers(ListReport):
return self.templateAsPDF(
'uds/reports/lists/users.html',
dct={'users': users},
dct={
'users': users,
'auth': auth.name,
},
header=ugettext('Users List for {}').format(auth.name),
water=ugettext('UDS Report of users in {}'.format(auth.name))
)

View File

@ -32,7 +32,7 @@
"""
# from .usage import StatsReportUsage
# from .login import StatsReportLogin, StatsReportLoginCSV
from .login import StatsReportLogin, StatsReportLoginCSV
# from .pool_performance import PoolPerformanceReport
# from .usage_by_pool import UsageByPool
# from .pools_usage import CountersPoolAssigned

View File

@ -35,12 +35,11 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext_noop as _
from uds.core import reports
__updated__ = '2015-06-21'
__updated__ = '2018-02-07'
class StatsReport(reports.Report):
"""
Base report por stats reports
Base report for statistics reports
"""
group = _('Statistics') # So we can make submenus with reports

View File

@ -36,7 +36,6 @@ from django.utils.translation import ugettext, ugettext_lazy as _
import django.template.defaultfilters as filters
from uds.core.ui.UserInterface import gui
from uds.core.reports.tools import UDSImage, UDSGeraldoReport
from uds.core.util.stats import events
import csv
@ -48,11 +47,6 @@ import pycha.bar
from .base import StatsReport
from uds.core.util import tools
from geraldo.generators.pdf import PDFGenerator
from geraldo import ReportBand, ObjectValue, BAND_WIDTH, Label, SubReport
from reportlab.lib.units import cm, mm
from reportlab.lib.enums import TA_RIGHT, TA_CENTER
from PIL import Image as PILImage
import datetime
import six
@ -60,65 +54,10 @@ import logging
logger = logging.getLogger(__name__)
__updated__ = '2017-05-04'
__updated__ = '2018-02-07'
# several constants as Width height, margins, ..
WIDTH, HEIGHT = 1800, 1000
GERALDO_WIDTH = 120 * mm
GERALDO_HEIGHT = GERALDO_WIDTH * HEIGHT / WIDTH
class AccessReport(UDSGeraldoReport):
header_elements = []
class band_detail(ReportBand):
height = 400 * mm # Height bigger than a page, so a new page is launched
# auto_expand_height = True
elements = (
Label(text=_('Users access by date'), top=0.6 * cm, left=0, width=BAND_WIDTH,
style={'fontName': 'Helvetica-Bold', 'fontSize': 10, 'alignment': TA_CENTER}),
UDSImage(left=4 * cm, top=1 * cm,
width=GERALDO_WIDTH, height=GERALDO_HEIGHT,
get_image=lambda x: x.instance['image']),
Label(text=_('Users access by day of week'), top=GERALDO_HEIGHT + 1.2 * cm, left=0, width=BAND_WIDTH,
style={'fontName': 'Helvetica-Bold', 'fontSize': 10, 'alignment': TA_CENTER}),
UDSImage(left=4 * cm, top=GERALDO_HEIGHT + 1.6 * cm,
width=GERALDO_WIDTH, height=GERALDO_HEIGHT,
get_image=lambda x: x.instance['image2']),
Label(text=_('Users access by hour'), top=2 * GERALDO_HEIGHT + 2 * cm, left=0, width=BAND_WIDTH,
style={'fontName': 'Helvetica-Bold', 'fontSize': 10, 'alignment': TA_CENTER}),
UDSImage(left=4 * cm, top=2 * GERALDO_HEIGHT + 2.4 * cm,
width=GERALDO_WIDTH, height=GERALDO_HEIGHT,
get_image=lambda x: x.instance['image3']),
)
subreports = [
SubReport(
queryset_string='%(object)s["data"]',
band_header=ReportBand(
height=1 * cm,
auto_expand_height=True,
elements=(
Label(text=_('Users access by date'), top=0.2 * cm, left=0, width=BAND_WIDTH,
style={'fontName': 'Helvetica-Bold', 'fontSize': 12, 'alignment': TA_CENTER}),
Label(text=_('Date range'), top=1.0 * cm, left=1.2 * cm,
style={'fontName': 'Helvetica-Bold', 'fontSize': 10}),
Label(text=_('Users'), top=1.0 * cm, left=14 * cm,
style={'fontName': 'Helvetica-Bold', 'fontSize': 10}),
),
# borders={'bottom': True}
),
band_detail=ReportBand(
height=0.5 * cm,
elements=(
ObjectValue(attribute_name='date', top=0, left=1.2 * cm, width=12 * cm, style={'fontName': 'Helvetica', 'fontSize': 9}),
ObjectValue(attribute_name='users', top=0, left=14 * cm, style={'fontName': 'Helvetica', 'fontSize': 9}),
)
),
)
]
# several constants as Width height
WIDTH, HEIGHT = 1920, 1080
class StatsReportLogin(StatsReport):
@ -180,7 +119,7 @@ class StatsReportLogin(StatsReport):
samplingIntervals = []
prevVal = None
for val in range(start, end, (end - start) / (samplingPoints + 1)):
for val in range(start, end, int((end - start) / (samplingPoints + 1))):
if prevVal is None:
prevVal = val
continue
@ -232,6 +171,9 @@ class StatsReportLogin(StatsReport):
#
# User access by date graph
#
graph1 = six.BytesIO()
graph2 = six.BytesIO()
graph3 = six.BytesIO()
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT) # @UndefinedVariable
@ -242,7 +184,7 @@ class StatsReportLogin(StatsReport):
'axis': {
'x': {
'ticks': [
dict(v=i, label=filters.date(datetime.datetime.fromtimestamp(i), xLabelFormat)) for i in range(start, end, (end - start) / 11)
dict(v=i, label=filters.date(datetime.datetime.fromtimestamp(i), xLabelFormat)) for i in range(start, end, int((end - start) / 11))
],
'range': (start, end),
'showLines': True,
@ -259,7 +201,7 @@ class StatsReportLogin(StatsReport):
'lineColor': '#187FF2'
},
'colorScheme': {
'name': 'gradient',
'name': 'rainbow',
'args': {
'initialColor': '#B8CA16',
},
@ -285,7 +227,12 @@ class StatsReportLogin(StatsReport):
chart.addDataset(dataset)
chart.render()
img = PILImage.frombuffer("RGBA", (surface.get_width(), surface.get_height()), surface.get_data(), "raw", "BGRA", 0, 1)
surface.write_to_png(graph1)
del chart
del surface # calls finish, flushing to SVG
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT) # @UndefinedVariable
#
# User access by day of week
@ -313,8 +260,12 @@ class StatsReportLogin(StatsReport):
chart.addDataset(dataset)
chart.render()
img2 = PILImage.frombuffer("RGBA", (surface.get_width(), surface.get_height()), surface.get_data(), "raw", "BGRA", 0, 1)
surface.write_to_png(graph2)
del chart
del surface # calls finish, flushing to SVG
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT) # @UndefinedVariable
# Hourly chart
dataset = ((ugettext('Users access to UDS'), [(i, dataHour[i]) for i in range(0, 24)]),)
@ -338,25 +289,26 @@ class StatsReportLogin(StatsReport):
chart.addDataset(dataset)
chart.render()
img3 = PILImage.frombuffer("RGBA", (surface.get_width(), surface.get_height()), surface.get_data(), "raw", "BGRA", 0, 1)
surface.write_to_png(graph3)
output = six.StringIO()
del chart
del surface # calls finish, flushing to SVG
queryset = [
{'image': img, 'image2': img2, 'image3': img3, 'data': reportData}
]
with open('/home/dkmaster/kk/g1.svg', 'wb') as f:
f.write(graph1.getvalue())
logger.debug(queryset)
try:
report = AccessReport(queryset=queryset)
report.title = ugettext('Users access to UDS')
# report = UsersReport(queryset=users)
report.generate_by(PDFGenerator, filename=output)
return output.getvalue()
except Exception:
logger.exception('Errool')
return None
return self.templateAsPDF(
'uds/reports/stats/user-access.html',
dct={
'data': reportData,
'begining': self.startDate.date(),
'ending': self.endDate.date(),
'intervals': self.samplingPoints.num(),
},
header=ugettext('Users access to UDS'),
water=ugettext('UDS Report for users access'),
images={'graph1': graph1.getvalue(), 'graph2': graph2.getvalue(), 'graph3': graph3.getvalue()},
)
class StatsReportLoginCSV(StatsReportLogin):
@ -373,7 +325,7 @@ class StatsReportLoginCSV(StatsReportLogin):
samplingPoints = StatsReportLogin.samplingPoints
def generate(self):
output = StringIO.StringIO()
output = six.StringIO()
writer = csv.writer(output)
reportData = self.getRangeData()[2]

View File

@ -2,6 +2,10 @@
<html lang="en">
<head>
<title>Users Report</title>
<meta name="author" content="UDS">
<meta name="description" content="List of UDS users of {{ auth }}">
<meta name="keywords" content="uds,report,users,list">
<meta name="generator" content="UDS Reporting">
</head>
<body>
<table style="width: 100%; font-size: 0.8em;">

View File

@ -0,0 +1,47 @@
{% load l10n i18n %}
<html lang="en">
<head>
<title>Users Access Report</title>
<meta name="author" content="UDS">
<meta name="description" content="List of UDS accesses from {{ begining }} to {{ ending }} with {{ interval }} intervals">
<meta name="keywords" content="uds,report,access">
<meta name="generator" content="UDS Reporting">
</head>
<body>
<p style="text-align: center">
{% trans "Users Access by date" %}
</p>
<img src="image://graph1" class="center" style="height: 7.2cm;">
<p style="text-align: center">
{% trans "Users Access by day of week" %}
</p>
<img src="image://graph2" class="center" style="height: 7.2cm;">
<p style="text-align: center">
{% trans "Users Access by hour" %}
</p>
<img src="image://graph3" class="center" style="height: 7.2cm;">
<p style="page-break-before: always; text-align: center;">
{% trans "Users Access by date" %}
</p>
<table style="width: 100%; font-size: 0.8em;">
<thead>
<tr>
<th style="width: 70%">{% trans 'Date range' %}</th>
<th style="width: 30%">{% trans 'Users' %}</th>
</tr>
</thead>
<tbody>
{% for d in data %}
<tr>
<td>{{ d.date }}</td>
<td>{{ d.users }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- <p style="page-break-before: always">
This is a new page
</p> -->
</body>
</html>