Projet

Général

Profil

0001-views-extend-log-search-to-responses-39779.patch

Valentin Deniaud, 12 février 2020 16:41

Télécharger (6,55 ko)

Voir les différences:

Subject: [PATCH] views: extend log search to responses (#39779)

 passerelle/views.py   | 54 ++++++++++++++++++++++++++++---------------
 tests/test_manager.py | 14 ++++++++++-
 2 files changed, 48 insertions(+), 20 deletions(-)
passerelle/views.py
26 26
from django.contrib.auth import logout as auth_logout
27 27
from django.contrib.auth import views as auth_views
28 28
from django.db import transaction
29
from django.db.models import TextField
30
from django.db.models.functions import Cast
29 31
from django.http import HttpResponse, HttpResponseRedirect, Http404
30 32
from django.views.decorators.csrf import csrf_exempt
31 33
from django.views.generic import (
......
47 49

  
48 50
from passerelle.base.models import BaseResource, ResourceLog
49 51
from passerelle.compat import json_loads
50
from passerelle.utils.jsonresponse import APIError
52
from passerelle.utils.jsonresponse import APIError, JSONEncoder
51 53
from passerelle.utils.json import unflatten
52 54

  
53 55
from .utils import to_json, is_authorized
......
241 243
            try:
242 244
                date = date_parser.parse(query, dayfirst=True)
243 245
            except Exception:
244
                qs = qs.filter(message__icontains=query)
246
                qs = qs.annotate(
247
                    text_extra=Cast('extra', TextField())
248
                ).filter(text_extra__icontains=query)
245 249
            else:
246 250
                date = make_aware(date)
247 251
                if date.hour == 0 and date.minute == 0 and date.second == 0:
......
428 432
                    extra.append(key)
429 433
            raise WrongParameter(missing, extra)
430 434

  
431
        # auto log request's inputs
435
        payload = request.body  # for logging, but we cannot access it after firing request
436
        result = None
437
        try:
438
            params = self.get_params(request, *args, **kwargs)
439
            if request.method == 'GET' and self.endpoint.endpoint_info.cache_duration:
440
                cache_key = hashlib.md5(
441
                    force_bytes(repr(self.get_object().slug) + repr(self.endpoint) + repr(params))
442
                ).hexdigest()
443
                result = cache.get(cache_key)
444
                if result is not None:
445
                    return result
446

  
447
            result = self.endpoint(request, **params)
448
            if request.method == 'GET' and self.endpoint.endpoint_info.cache_duration:
449
                cache.set(cache_key, result, self.endpoint.endpoint_info.cache_duration)
450
            return result
451
        finally:
452
            # auto log endpoint call
453
            self.log_request(request, payload, result, kwargs)
454

  
455
    def log_request(self, request, payload, result, kwargs):
432 456
        connector_name, endpoint_name = kwargs['connector'], kwargs['endpoint']
433 457
        connector = self.get_object()
458
        payload = payload[:connector.logging_parameters.requests_max_size]
434 459
        url = request.get_full_path()
435
        payload = request.body[:connector.logging_parameters.requests_max_size]
436 460
        try:
437 461
            payload = payload.decode('utf-8')
438 462
        except UnicodeDecodeError:
439 463
            payload = '<BINARY PAYLOAD>'
464
        try:
465
            result = json.dumps(result, cls=JSONEncoder)
466
            result = result[:connector.logging_parameters.responses_max_size]
467
        except TypeError as e:
468
            result = None
440 469
        connector.logger.info('endpoint %s %s (%r) ' %
441 470
                              (request.method, url, payload),
442 471
                              extra={
......
445 474
                                  'connector_endpoint': endpoint_name,
446 475
                                  'connector_endpoint_method': request.method,
447 476
                                  'connector_endpoint_url': url,
448
                                  'connector_payload': payload
477
                                  'connector_payload': payload,
478
                                  'connector_response': result,
449 479
                              })
450 480

  
451
        params = self.get_params(request, *args, **kwargs)
452
        if request.method == 'GET' and self.endpoint.endpoint_info.cache_duration:
453
            cache_key = hashlib.md5(
454
                force_bytes(repr(self.get_object().slug) + repr(self.endpoint) + repr(params))
455
            ).hexdigest()
456
            result = cache.get(cache_key)
457
            if result is not None:
458
                return result
459

  
460
        result = self.endpoint(request, **params)
461
        if request.method == 'GET' and self.endpoint.endpoint_info.cache_duration:
462
            cache.set(cache_key, result, self.endpoint.endpoint_info.cache_duration)
463
        return result
464

  
465 481
    def get(self, request, *args, **kwargs):
466 482
        if self.endpoint.endpoint_info.pattern:
467 483
            pattern = url(self.endpoint.endpoint_info.pattern, self.endpoint)
tests/test_manager.py
138 138
    assert resp.content.startswith(b'FooBar([{"')
139 139

  
140 140
def test_logs(app, admin_user):
141
    data = StringIO('1;Foo\n2;Bar\n3;Baz')
141
    data = StringIO('1;Foo\n2;Bar\n3;Baz\n4;Bat')
142 142
    csv = CsvDataSource.objects.create(csv_file=File(data, 't.csv'),
143 143
           columns_keynames='id, text', slug='test', title='a title', description='a description')
144 144

  
......
193 193
    resp = app.get(base_url + log_pk + '/')
194 194
    resp = app.get(base_url + '12345' + '/', status=404)
195 195

  
196
    app.get('/csvdatasource/test/query/fooba/?q=az')
197
    resp = app.get(csv.get_absolute_url())
198
    assert 'endpoint GET /csvdatasource/test/query/fooba/?q=az' in resp.text
199
    resp = resp.click('full page')
200
    resp.form['q'] = 'Baz'
201
    resp = resp.form.submit()
202
    assert resp.text.count('<td class="timestamp">') == 1
203
    resp.form['q'] = 'Bat'
204
    resp = resp.form.submit()
205
    assert resp.text.count('<td class="timestamp">') == 0
206

  
207

  
196 208
def test_logging_parameters(app, admin_user):
197 209
    data = StringIO('1;Foo\n2;Bar\n3;Baz')
198 210
    csv = CsvDataSource.objects.create(csv_file=File(data, 't.csv'),
199
-