Projet

Général

Profil

0004-add-a-new-page-for-resource-paginated-logs-14671.patch

extra commit for djdt - Anonyme, 13 avril 2018 19:31

Télécharger (12 ko)

Voir les différences:

Subject: [PATCH 4/4] add a new page for resource paginated logs (#14671)

 passerelle/base/models.py                     | 21 +++++-
 passerelle/base/templatetags/passerelle.py    | 12 ---
 .../includes/resource-logs-table.html         | 30 --------
 .../passerelle/manage/service_log.html        | 47 ++++++++++++
 .../passerelle/manage/service_view.html       |  7 +-
 passerelle/urls.py                            |  2 +-
 passerelle/views.py                           | 74 +++++++------------
 7 files changed, 93 insertions(+), 100 deletions(-)
 delete mode 100644 passerelle/templates/passerelle/includes/resource-logs-table.html
 create mode 100644 passerelle/templates/passerelle/manage/service_log.html
passerelle/base/models.py
190 190
        return reverse('delete-connector',
191 191
                kwargs={'connector': self.get_connector_slug(), 'slug': self.slug})
192 192

  
193
    def get_log_url(self):
194
        return reverse('view-connector-log',
195
                kwargs={'connector': self.get_connector_slug(), 'slug': self.slug})
196

  
197

  
193 198
    def get_description_fields(self):
194 199
        fields = []
195 200
        for field in self._meta.fields:
......
430 435

  
431 436

  
432 437
class ResourceLogManager(models.Manager):
433
    def get_paginated_logs(self, appname, slug, page, order_by=None, page_size=None):
438
    def get_paginated_logs(self, appname, slug, page, lookup_dict=None, lookup_or=None, order_by=None, page_size=None):
434 439
        if order_by is None:
435 440
            order_by = '-timestamp'
436 441
        if page_size is None:
437 442
            page_size = 10
438 443

  
439
        qs = self.filter(appname=appname, slug=slug).order_by(order_by)
444
        if lookup_dict:
445
            q_list = [Q(key=value) for key, value in lookup_dict.items()]
446
            lookups = q_list.pop()
447
            for q_item in q_list:
448
                if lookup_or is None:
449
                    lookups &= q_item
450
                else:
451
                    lookups |= q_item
452
            qs = self.filter(lookups, appname=appname, slug=slug)
453
        else:
454
            qs = self.filter(appname=appname, slug=slug)
455
        qs.order_by(order_by)
440 456
        paginator = Paginator(qs, page_size)
441 457
        try:
442 458
            logrecords = paginator.page(page)
......
471 487
    def __unicode__(self):
472 488
        return '%s %s %s %s' % (self.timestamp, self.levelno, self.appname, self.slug)
473 489

  
490

  
474 491
STATUS_CHOICES = (
475 492
    ('unknown', _('Unknown')),
476 493
    ('up', _('Up')),
passerelle/base/templatetags/passerelle.py
22 22
    return context
23 23

  
24 24

  
25
@register.inclusion_tag('passerelle/includes/resource-logs-table.html', takes_context=True)
26
def resource_logs_table(context, resource):
27
    request = context.get('request')
28
    page = request.GET.get('page', 1)
29

  
30
    connector = resource.get_connector_slug()
31
    context['connector'] = connector
32
    context['slug'] = resource.slug
33
    context['logrecords'] = ResourceLog.objects.get_paginated_logs(connector, resource.slug, page)
34
    return context
35

  
36

  
37 25
@register.filter
38 26
def can_edit(obj, user):
39 27
    return user.has_perm(get_permission_codename('change', obj._meta), obj=obj)
passerelle/templates/passerelle/includes/resource-logs-table.html
1
{% load i18n passerelle %}
2
{% load tz %}
3

  
4
{% block content %}
5
{% if logrecords %}
6
<table class="main">
7
    <thead>
8
        <th>{% trans 'Timestamp' %}</th>
9
        <th>{% trans 'Source IP' %}</th>
10
        <th>{% trans 'Message' %}</th>
11
    </thead>
12
    <tbody>
13
    {% for record in logrecords %}
14
    <tr class="level-{{record.level}}">
15
        <td class="timestamp">{{ record.timestamp|localtime }}</td>
16
        <td>{{ record.sourceip|default:"-" }}</td>
17
        <td class="message">{{ record.message}}</td>
18
    </tr>
19
    {% endfor %}
20
    </tbody>
21
</table>
22

  
23
{% with page_obj=logrecords %}
24
  {% include "gadjo/pagination.html" with anchor="#logs" %}
25
{% endwith %}
26

  
27
{% else %}
28
<p>{% trans 'No records found' %}</p>
29
{% endif %}
30
{% endblock %}
passerelle/templates/passerelle/manage/service_log.html
1
{% extends "passerelle/manage/service_view.html" %}
2
{% load i18n passerelle %}
3
{% load tz %}
4

  
5
{% block breadcrumb %}
6
{{ block.super }}
7
<a href="{{object.get_absolute_url}}">{{ object.get_verbose_name }}</a>
8
{% endblock %}
9

  
10
{% block content %}
11
{% if perms.base.view_resourcelog %}
12
<div id="logs" class="section">
13
  <h3>{% trans "Logs" %}</h3>
14
  <div>
15
  {% block logs %}
16

  
17
  {% if logrecords %}
18
  <table class="main">
19
      <thead>
20
          <th>{% trans 'Timestamp' %}</th>
21
          <th>{% trans 'Source IP' %}</th>
22
          <th>{% trans 'Message' %}</th>
23
      </thead>
24
      <tbody>
25
      {% for record in logrecords %}
26
      <tr class="level-{{record.level}}">
27
          <td class="timestamp">{{ record.timestamp|localtime }}</td>
28
          <td>{{ record.sourceip|default:"-" }}</td>
29
          <td class="message">{{ record.message}}</td>
30
      </tr>
31
      {% endfor %}
32
      </tbody>
33
  </table>
34

  
35
  {% with page_obj=logrecords %}
36
    {% include "gadjo/pagination.html" with anchor="#logs" %}
37
  {% endwith %}
38

  
39
  {% else %}
40
  <p>{% trans 'No records found' %}</p>
41
  {% endif %}
42

  
43
  {% endblock %}
44
  </div>
45
</div>
46
{% endif %}
47
{% endblock %}
passerelle/templates/passerelle/manage/service_view.html
87 87

  
88 88
{% if perms.base.view_resourcelog %}
89 89
<div id="logs" class="section">
90
  <h3>{% trans "Logs" %}</h3>
91
  <div>
92
  {% block logs %}
93
    {% resource_logs_table resource=object %}
94
  {% endblock %}
95
  </div>
90
  <h3><a href={{ object.get_log_url }}>{% trans "Logs" %}</a></h3>
96 91
</div>
97 92
{% endif %}
98 93

  
passerelle/urls.py
79 79
urlpatterns += [
80 80
    url(r'^(?P<connector>[\w,-]+)/(?P<slug>[\w,-]+)/$',
81 81
        GenericConnectorView.as_view(), name='view-connector'),
82
    url(r'^(?P<connector>[\w,-]+)/(?P<slug>[\w,-]+)/logs.json$',
82
    url(r'^(?P<connector>[\w,-]+)/(?P<slug>[\w,-]+)/logs$',
83 83
        GenericConnectorLogView.as_view(), name='view-connector-log'),
84 84
    url(r'^(?P<connector>[\w,-]+)/(?P<slug>[\w,-]+)/(?P<endpoint>[\w,-]+)(?:/(?P<rest>.*))?$',
85 85
        GenericEndpointView.as_view(), name='generic-endpoint')
passerelle/views.py
8 8
from django.core.exceptions import PermissionDenied
9 9
from django.contrib.auth import logout as auth_logout
10 10
from django.contrib.auth import views as auth_views
11
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseRedirect, Http404
11
from django.http import HttpResponse, HttpResponseRedirect, Http404
12 12
from django.views.decorators.csrf import csrf_exempt
13 13
from django.views.generic import (RedirectView, View, TemplateView, CreateView,
14 14
        DeleteView, UpdateView, DetailView)
......
16 16
from django.conf import settings
17 17
from django.shortcuts import resolve_url
18 18
from django.core.urlresolvers import reverse
19
from django.core.paginator import EmptyPage, PageNotAnInteger
20 19
from django.utils.translation import ugettext_lazy as _
21 20
from django.utils.encoding import force_text
22
from django.utils.timezone import make_aware
23 21
from django.forms.models import modelform_factory
24 22
from django.forms.widgets import ClearableFileInput
23
from .base.models import BaseResource, ResourceLog
24
from .utils import to_json, is_authorized
25
from .forms import GenericConnectorForm
25 26

  
26 27
if 'mellon' in settings.INSTALLED_APPS:
27 28
    from mellon.utils import get_idps
28 29
else:
29 30
    get_idps = lambda: []
30 31

  
31
from passerelle.base.models import BaseResource, ResourceLog
32

  
33
from .utils import to_json, response_for_json, is_authorized
34
from .forms import GenericConnectorForm
35

  
36 32

  
37 33
def get_all_apps():
38 34
    return [x for x in apps.get_models() if issubclass(x, BaseResource) and \
......
141 137
        template_names.append('passerelle/manage/service_view.html')
142 138
        return template_names
143 139

  
144
class GenericConnectorLogView(GenericConnectorMixin, View):
145

  
146
    content_type = 'application/json'
147
    epoch = make_aware(datetime(1970,1,1))
148

  
149
    def totimestamp(self, datetime_obj):
150
        td = datetime_obj - self.epoch
151
        # return td.total_seconds()
152
        return int((td.microseconds + (td.seconds + td.days * 86400) * 10**6) / 10**3)
153

  
154
    def resource_logs_table(self, request, *args, **kwargs):
155
        if 'slug' not in kwargs:
156
            raise HttpResponseBadRequest('URL must specify a slug value')
157
        if 'connector' not in kwargs:
158
            raise HttpResponseBadRequest('URL must specify a connector value')
159
        page = request.GET.get('page', 1)
160
        return ResourceLog.objects.get_paginated_logs(kwargs['connector'], kwargs['slug'], page)
161

  
162
    def get(self, request, *args, **kwargs):
163
        page_obj = self.resource_logs_table(request, *args, **kwargs)
164
        # no previous or next is representezd a None value
165
        try:
166
            previous_page_number = page_obj.previous_page_number()
167
        except (EmptyPage,):
168
            previous_page_number = None
169
        try:
170
            next_page_number = page_obj.next_page_number()
171
        except (EmptyPage,):
172
            next_page_number = None
173
        return response_for_json(request, dict([
174
            ('count', page_obj.paginator.count),
175
            ('page_range', list(page_obj.paginator.page_range)),
176
            ('number', page_obj.number),
177
            ('next_page_number', next_page_number),
178
            ('previous_page_number', previous_page_number),
179
            ('logs', [dict([('message', log.message),
180
                ('timestamp', self.totimestamp(log.timestamp)),
181
                ('level', log.level),
182
                ('extra', log.extra),
183
                ('sourceip', log.sourceip)]) for log in page_obj])
184
        ]))
140
class GenericConnectorLogView(GenericConnectorMixin, DetailView):
141

  
142
    template_name = 'passerelle/manage/service_log.html'
143

  
144
    def query_resource_log_paginator(self, connector, slug, **kwargs):
145
        page = kwargs.get('page', 1)
146
        return ResourceLog.objects.get_paginated_logs(connector, slug, page,
147
            lookup_dict=kwargs.get('lookups'), lookup_or=kwargs.get('lookup_or'),
148
            order_by=kwargs.get('order_by'), page_size=kwargs.get('page_size'))
149

  
150
    def get_context_data(self, object, **kwargs):
151
        # request = context.get('request')
152
        connector = object.get_connector_slug()
153
        page_obj = self.query_resource_log_paginator(connector, object.slug, **kwargs)
154
        return {
155
            'view': self,
156
            'object': object,
157
            'connector': connector,
158
            'slug': object.slug,
159
            'logrecords': page_obj
160
        }
185 161

  
186 162

  
187 163
class GenericCreateConnectorView(GenericConnectorMixin, CreateView):
188
-