mirror of
https://github.com/dkmstr/openuds.git
synced 2024-12-22 13:34:04 +03:00
Fixed report & created "basic" report class
This commit is contained in:
parent
b77fa7dfd6
commit
abf6d3751b
@ -116,6 +116,7 @@ class Reports(model.BaseModelHandler):
|
|||||||
}
|
}
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
logger.exception('Generating report')
|
||||||
return self.invalidRequestException(six.text_type(e))
|
return self.invalidRequestException(six.text_type(e))
|
||||||
|
|
||||||
report.__dict__.update()
|
report.__dict__.update()
|
||||||
|
38
server/src/uds/core/reports/tools/__init__.py
Normal file
38
server/src/uds/core/reports/tools/__init__.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015 Virtual Cable S.L.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
# are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||||
|
# may be used to endorse or promote products derived from this software
|
||||||
|
# without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
'''
|
||||||
|
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
|
'''
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from .geraldo_graphics import UDSImage
|
||||||
|
from .report import UDSGeraldoReport
|
||||||
|
|
||||||
|
__updated__ = '2015-06-21'
|
31
server/src/uds/core/reports/tools/geraldo_graphics.py
Normal file
31
server/src/uds/core/reports/tools/geraldo_graphics.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
from geraldo.base import BAND_WIDTH, BAND_HEIGHT, Element
|
||||||
|
from geraldo.utils import cm, black
|
||||||
|
from geraldo import Image
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class UDSImage(Image):
|
||||||
|
def _get_height(self):
|
||||||
|
logger.debug('get height called')
|
||||||
|
ret = self._height or (self.image and self.image.size[1] or 0)
|
||||||
|
return ret * cm / 118
|
||||||
|
|
||||||
|
def _set_height(self, value):
|
||||||
|
logger.debug('set height called')
|
||||||
|
self._height = value / cm * 118
|
||||||
|
|
||||||
|
height = property(_get_height, _set_height)
|
||||||
|
|
||||||
|
def _get_width(self):
|
||||||
|
logger.debug('get width called')
|
||||||
|
ret = self._width or (self.image and self.image.size[0] or 0)
|
||||||
|
return ret * cm / 118
|
||||||
|
|
||||||
|
def _set_width(self, value):
|
||||||
|
logger.debug('set width called')
|
||||||
|
self._width = value / cm * 118
|
||||||
|
|
||||||
|
width = property(_get_width, _set_width)
|
88
server/src/uds/core/reports/tools/report.py
Normal file
88
server/src/uds/core/reports/tools/report.py
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015 Virtual Cable S.L.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
# are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||||
|
# may be used to endorse or promote products derived from this software
|
||||||
|
# without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
'''
|
||||||
|
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
|
'''
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||||
|
from uds.core.reports import stock
|
||||||
|
|
||||||
|
from geraldo import Report, landscape, ReportBand, ObjectValue, SystemField, BAND_WIDTH, Label, SubReport, Rect
|
||||||
|
from uds.core.reports.tools.geraldo_graphics import UDSImage
|
||||||
|
from reportlab.lib.pagesizes import A4
|
||||||
|
from reportlab.lib.units import cm, mm
|
||||||
|
from reportlab.lib.enums import TA_RIGHT, TA_CENTER
|
||||||
|
from reportlab.lib import colors
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
__updated__ = '2015-06-21'
|
||||||
|
|
||||||
|
|
||||||
|
class UDSGeraldoReport(Report):
|
||||||
|
author = 'UDS Enterprise'
|
||||||
|
title = 'UDS Report'
|
||||||
|
|
||||||
|
print_if_empty = True
|
||||||
|
page_size = A4
|
||||||
|
margin_left = 0.5 * cm
|
||||||
|
margin_top = 0.5 * cm
|
||||||
|
margin_right = 0.5 * cm
|
||||||
|
margin_bottom = 0.5 * cm
|
||||||
|
|
||||||
|
class band_page_header(ReportBand):
|
||||||
|
height = 1.8 * 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}),
|
||||||
|
|
||||||
|
SystemField(expression=_('Page %(page_number)d of %(page_count)d'), top=0.1 * cm,
|
||||||
|
width=BAND_WIDTH, style={'alignment': TA_RIGHT}),
|
||||||
|
UDSImage(filename=stock.getStockImagePath(stock.LOGO), left=0.0 * cm, top=0.0 * cm, width=2.0 * cm, height=2.0 * 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}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def viewSize():
|
||||||
|
return (
|
||||||
|
UDSGeraldoReport.page_size - UDSGeraldoReport.mar
|
||||||
|
)
|
@ -38,6 +38,7 @@ import django.template.defaultfilters as filters
|
|||||||
|
|
||||||
from uds.core.ui.UserInterface import gui
|
from uds.core.ui.UserInterface import gui
|
||||||
from uds.core.reports import stock
|
from uds.core.reports import stock
|
||||||
|
from uds.core.reports.tools import UDSImage, UDSGeraldoReport
|
||||||
from uds.models import StatsEvents
|
from uds.models import StatsEvents
|
||||||
from uds.core.util.stats import events
|
from uds.core.util.stats import events
|
||||||
|
|
||||||
@ -45,15 +46,17 @@ import StringIO
|
|||||||
|
|
||||||
import cairo
|
import cairo
|
||||||
import pycha.line
|
import pycha.line
|
||||||
|
import pycha.bar
|
||||||
|
|
||||||
from .base import StatsReport
|
from .base import StatsReport
|
||||||
|
|
||||||
from uds.core.util import tools
|
from uds.core.util import tools
|
||||||
from geraldo.generators.pdf import PDFGenerator
|
from geraldo.generators.pdf import PDFGenerator
|
||||||
from geraldo import Report, landscape, ReportBand, ObjectValue, SystemField, BAND_WIDTH, Label, Image, SubReport
|
from geraldo import Report, landscape, ReportBand, ObjectValue, SystemField, BAND_WIDTH, Label, SubReport, Rect
|
||||||
from reportlab.lib.pagesizes import A4
|
from reportlab.lib.pagesizes import A4
|
||||||
from reportlab.lib.units import cm
|
from reportlab.lib.units import cm, mm
|
||||||
from reportlab.lib.enums import TA_RIGHT, TA_CENTER
|
from reportlab.lib.enums import TA_RIGHT, TA_CENTER
|
||||||
|
from reportlab.lib import colors
|
||||||
from PIL import Image as PILImage
|
from PIL import Image as PILImage
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
@ -61,53 +64,39 @@ import logging
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
__updated__ = '2015-05-04'
|
__updated__ = '2015-06-21'
|
||||||
|
|
||||||
# Width & height
|
# several constants as Width height, margins, ..
|
||||||
WIDTH, HEIGHT = 1800, 1000
|
WIDTH, HEIGHT = 1800, 1000
|
||||||
GERARLDO_WIDTH = 800
|
GERALDO_WIDTH = 120 * mm
|
||||||
GERALDO_HEIGHT = GERARLDO_WIDTH * HEIGHT / WIDTH
|
GERALDO_HEIGHT = GERALDO_WIDTH * HEIGHT / WIDTH
|
||||||
|
|
||||||
|
|
||||||
class AccessReport(Report):
|
class AccessReport(UDSGeraldoReport):
|
||||||
author = 'UDS Enterprise'
|
|
||||||
|
|
||||||
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):
|
class band_detail(ReportBand):
|
||||||
height = 10 * cm
|
height = 10 * cm
|
||||||
auto_expand_height = True
|
auto_expand_height = True
|
||||||
elements = (
|
elements = (
|
||||||
Label(text='Users', top=0.6 * cm, left=10 * cm, style={'fontName': 'Helvetica-Bold'}),
|
Label(text=_('Users access by date'), top=0.6 * cm, left=0, width=BAND_WIDTH,
|
||||||
Image(get_image=lambda x: x.instance['image'], left=1.0 * cm, top=1.0 * cm, width=GERARLDO_WIDTH, height=GERALDO_HEIGHT, stretch=True),
|
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']),
|
||||||
)
|
)
|
||||||
|
|
||||||
class band_page_header(ReportBand):
|
|
||||||
height = 1.8 * 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}),
|
|
||||||
|
|
||||||
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.0 * cm, height=2.0 * 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}
|
|
||||||
|
|
||||||
subreports = [
|
subreports = [
|
||||||
SubReport(
|
SubReport(
|
||||||
queryset_string='%(object)s["data"]',
|
queryset_string='%(object)s["data"]',
|
||||||
@ -188,6 +177,9 @@ class StatsReportLogin(StatsReport):
|
|||||||
else:
|
else:
|
||||||
xLabelFormat = 'SHORT_DATETIME_FORMAT'
|
xLabelFormat = 'SHORT_DATETIME_FORMAT'
|
||||||
|
|
||||||
|
#
|
||||||
|
# User access by date graph
|
||||||
|
#
|
||||||
samplingIntervals = []
|
samplingIntervals = []
|
||||||
prevVal = None
|
prevVal = None
|
||||||
for val in range(start, end, (end - start) / (samplingPoints + 1)):
|
for val in range(start, end, (end - start) / (samplingPoints + 1)):
|
||||||
@ -212,7 +204,7 @@ class StatsReportLogin(StatsReport):
|
|||||||
|
|
||||||
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
|
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
|
||||||
|
|
||||||
dataset = (('Users access to UDS', data),)
|
dataset = ((ugettext('Users access to UDS'), data),)
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
'encoding': 'utf-8',
|
'encoding': 'utf-8',
|
||||||
@ -255,7 +247,7 @@ class StatsReportLogin(StatsReport):
|
|||||||
'right': 48,
|
'right': 48,
|
||||||
'bottom': 48,
|
'bottom': 48,
|
||||||
},
|
},
|
||||||
'title': _('Users usage of UDS')
|
'title': _('Users access to UDS')
|
||||||
}
|
}
|
||||||
|
|
||||||
chart = pycha.line.LineChart(surface, options)
|
chart = pycha.line.LineChart(surface, options)
|
||||||
@ -264,18 +256,78 @@ class StatsReportLogin(StatsReport):
|
|||||||
|
|
||||||
img = PILImage.frombuffer("RGBA", (surface.get_width(), surface.get_height()), surface.get_data(), "raw", "BGRA", 0, 1)
|
img = PILImage.frombuffer("RGBA", (surface.get_width(), surface.get_height()), surface.get_data(), "raw", "BGRA", 0, 1)
|
||||||
|
|
||||||
|
#
|
||||||
|
# User access by day of week
|
||||||
|
#
|
||||||
|
dataWeek = [0] * 7
|
||||||
|
dataHour = [0] * 24
|
||||||
|
for val in events.statsManager().getEvents(events.OT_AUTHENTICATOR, events.ET_LOGIN, since=start, to=end):
|
||||||
|
s = datetime.datetime.fromtimestamp(val.stamp)
|
||||||
|
dataWeek[s.weekday()] += 1
|
||||||
|
dataHour[s.hour] += 1
|
||||||
|
|
||||||
|
dataset = ((ugettext('Users access to UDS'), [(i, dataWeek[i]) for i in range(0, 7)]),)
|
||||||
|
|
||||||
|
options['axis'] = {
|
||||||
|
'x': {
|
||||||
|
'ticks': [
|
||||||
|
dict(v=i, label='Day {}'.format(i)) for i in range(0, 7)
|
||||||
|
],
|
||||||
|
'range': (0, 6),
|
||||||
|
'showLines': True,
|
||||||
|
},
|
||||||
|
'y': {
|
||||||
|
'tickCount': 10,
|
||||||
|
'showLines': True,
|
||||||
|
},
|
||||||
|
'tickFontSize': 16,
|
||||||
|
}
|
||||||
|
|
||||||
|
chart = pycha.bar.VerticalBarChart(surface, options)
|
||||||
|
chart.addDataset(dataset)
|
||||||
|
chart.render()
|
||||||
|
|
||||||
|
img2 = PILImage.frombuffer("RGBA", (surface.get_width(), surface.get_height()), surface.get_data(), "raw", "BGRA", 0, 1)
|
||||||
|
|
||||||
|
|
||||||
|
# Hourly chart
|
||||||
|
dataset = ((ugettext('Users access to UDS'), [(i, dataHour[i]) for i in range(0, 24)]),)
|
||||||
|
|
||||||
|
options['axis'] = {
|
||||||
|
'x': {
|
||||||
|
'ticks': [
|
||||||
|
dict(v=i, label='{}:00'.format(i)) for i in range(0, 24)
|
||||||
|
],
|
||||||
|
'range': (0, 24),
|
||||||
|
'showLines': True,
|
||||||
|
},
|
||||||
|
'y': {
|
||||||
|
'tickCount': 10,
|
||||||
|
'showLines': True,
|
||||||
|
},
|
||||||
|
'tickFontSize': 16,
|
||||||
|
}
|
||||||
|
|
||||||
|
chart = pycha.bar.VerticalBarChart(surface, options)
|
||||||
|
chart.addDataset(dataset)
|
||||||
|
chart.render()
|
||||||
|
|
||||||
|
img3 = PILImage.frombuffer("RGBA", (surface.get_width(), surface.get_height()), surface.get_data(), "raw", "BGRA", 0, 1)
|
||||||
|
|
||||||
output = StringIO.StringIO()
|
output = StringIO.StringIO()
|
||||||
|
|
||||||
queryset = [
|
queryset = [
|
||||||
{'image': img, 'data': reportData}
|
{'image': img, 'image2': img2, 'image3': img3, 'data': reportData}
|
||||||
]
|
]
|
||||||
|
|
||||||
logger.debug(queryset)
|
logger.debug(queryset)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
report = AccessReport(queryset=queryset)
|
report = AccessReport(queryset=queryset)
|
||||||
|
report.title = ugettext('User access to UDS')
|
||||||
# report = UsersReport(queryset=users)
|
# report = UsersReport(queryset=users)
|
||||||
report.generate_by(PDFGenerator, filename=output)
|
report.generate_by(PDFGenerator, filename=output)
|
||||||
return output.getvalue()
|
return output.getvalue()
|
||||||
except:
|
except Exception:
|
||||||
logger.exception('Errool')
|
logger.exception('Errool')
|
||||||
|
return None
|
||||||
|
Loading…
Reference in New Issue
Block a user