130 lines
5.1 KiB
Python
130 lines
5.1 KiB
Python
# combo - content management system
|
|
# Copyright (C) 2015-2019 Entr'ouvert
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify it
|
|
# under the terms of the GNU Affero General Public License as published
|
|
# by the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from django.core import signing
|
|
from django.core.cache import cache
|
|
from django.core.exceptions import PermissionDenied
|
|
from django.http import Http404, HttpResponse, HttpResponseBadRequest
|
|
from django.shortcuts import render
|
|
from django.template import TemplateSyntaxError, VariableDoesNotExist
|
|
from django.utils.translation import ugettext_lazy as _
|
|
from django.views.decorators.clickjacking import xframe_options_sameorigin
|
|
from django.views.generic import DetailView
|
|
from requests.exceptions import HTTPError
|
|
|
|
from combo.utils import NothingInCacheException, get_templated_url, requests
|
|
|
|
from .forms import ChartNgPartialForm
|
|
from .models import ChartNgCell, Gauge, MissingVariable, UnsupportedDataSet
|
|
|
|
|
|
def ajax_gauge_count(request, *args, **kwargs):
|
|
gauge = Gauge.objects.get(id=kwargs['cell'])
|
|
response = requests.get(get_templated_url(gauge.data_source))
|
|
return HttpResponse(response.content, content_type='text/json')
|
|
|
|
|
|
class DatavizGraphView(DetailView):
|
|
model = ChartNgCell
|
|
pk_url_kwarg = 'cell'
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
self.cell = self.get_object()
|
|
self.filters_cell_id = request.GET.get('filters_cell_id')
|
|
|
|
if not self.cell.page.is_visible(request.user):
|
|
raise PermissionDenied()
|
|
if not self.cell.is_visible(request):
|
|
raise PermissionDenied()
|
|
if not self.cell.statistic or not self.cell.statistic.url:
|
|
raise Http404('misconfigured cell')
|
|
|
|
if self.filters_cell_id:
|
|
self.cell.subfilters = cache.get(
|
|
self.cell.get_cache_key(self.filters_cell_id), self.cell.subfilters
|
|
)
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
form = ChartNgPartialForm(request.GET, instance=self.cell)
|
|
if not form.is_valid():
|
|
return self.error(_('Wrong parameters.'))
|
|
|
|
if request.GET.get('ctx'):
|
|
try:
|
|
request.extra_context = signing.loads(request.GET['ctx'])
|
|
except signing.BadSignature:
|
|
return HttpResponseBadRequest('bad signature')
|
|
|
|
form.instance._request = request
|
|
try:
|
|
chart = form.instance.get_chart(
|
|
width=int(request.GET['width']) if request.GET.get('width') else None,
|
|
height=int(request.GET['height']) if request.GET.get('height') else int(self.cell.height),
|
|
)
|
|
except UnsupportedDataSet:
|
|
return self.error(_('Unsupported dataset.'))
|
|
except MissingVariable:
|
|
return self.error(_('Page variable not found.'))
|
|
except TemplateSyntaxError:
|
|
return self.error(_('Syntax error in page variable.'))
|
|
except VariableDoesNotExist:
|
|
return self.error(_('Cannot evaluate page variable.'))
|
|
except HTTPError as e:
|
|
if e.response.status_code == 404:
|
|
return self.error(_('Visualization not found.'))
|
|
else:
|
|
return self.error(_('Unknown HTTP error: %s' % e))
|
|
|
|
if self.filters_cell_id:
|
|
self.update_subfilters_cache(form.instance)
|
|
|
|
if self.cell.chart_type == 'table':
|
|
if not chart.raw_series:
|
|
return self.error(_('No data'))
|
|
|
|
rendered = chart.render_table(
|
|
transpose=bool(chart.axis_count == 2),
|
|
total=getattr(chart, 'compute_sum', True),
|
|
)
|
|
rendered = rendered.replace('<table>', '<table class="main">')
|
|
return HttpResponse(rendered)
|
|
|
|
return HttpResponse(chart.render(), content_type='image/svg+xml')
|
|
|
|
def error(self, error_text):
|
|
if self.cell.chart_type == 'table':
|
|
return HttpResponse('<p>%s</p>' % error_text)
|
|
|
|
context = {
|
|
'width': self.request.GET.get('width', 200),
|
|
'text': error_text,
|
|
}
|
|
return render(self.request, 'combo/dataviz-error.svg', context=context, content_type='image/svg+xml')
|
|
|
|
def update_subfilters_cache(self, cell):
|
|
try:
|
|
data = cell.get_statistic_data(raise_if_not_cached=True)
|
|
except NothingInCacheException:
|
|
pass # should not happen
|
|
else:
|
|
cache.set(
|
|
cell.get_cache_key(self.filters_cell_id), data.json()['data'].get('subfilters', []), 300
|
|
)
|
|
|
|
|
|
dataviz_graph = xframe_options_sameorigin(DatavizGraphView.as_view())
|