From 7a66c2d3d0a1a20ce69ec5290ca76d05780339c2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Fri, 20 Mar 2020 14:28:22 +0100
Subject: [PATCH] logs: direct access to a log (#23298)

---
 passerelle/static/js/passerelle.js            | 28 +++++++++++++++----
 .../includes/resource-logs-table.html         |  5 +++-
 .../passerelle/manage/service_logs.html       |  8 ++++++
 passerelle/views.py                           |  9 ++++++
 tests/test_manager.py                         | 12 ++++++++
 5 files changed, 56 insertions(+), 6 deletions(-)

diff --git a/passerelle/static/js/passerelle.js b/passerelle/static/js/passerelle.js
index f4612ef8..b46c5f86 100644
--- a/passerelle/static/js/passerelle.js
+++ b/passerelle/static/js/passerelle.js
@@ -1,12 +1,30 @@
-$(function() {
-  $('#logs tbody tr').on('click', function() {
-    var base_url = $(this).parents('table.main').data('log-base-url');
-    var log_pk = $(this).data('pk');
+open_log_window = function(base_url, log_pk) {
     var url = base_url + log_pk + '/';
+    var current_url = window.location;
+    if (window.location.href == window.location.origin + base_url + '?log_id=' + log_pk) {
+      // remove log_id from url on modal close if direct access to a log
+      window.history.pushState({}, 'no log', base_url);
+    }
     $.get(url,
         function(response) {
-          var $dialog = $(response).dialog({modal: true, width: 'auto'});
+          var $dialog = $(response).dialog({
+            modal: true,
+            width: 'auto',
+            open: function(event, ui) {
+              window.history.pushState({'log_id': log_pk}, 'log id', base_url + '?log_id=' + log_pk);
+            },
+            close: function (event, ui) {
+              window.history.back();
+            }
+          });
         });
+};
+
+$(function() {
+  $('#logs tbody tr').on('click', function() {
+    var base_url = $(this).parents('table.main').data('log-base-url');
+    var log_pk = $(this).data('pk');
+    open_log_window(base_url, log_pk);
   });
   $('#jobs tbody tr').on('click', function() {
     var base_url = $(this).parents('table.main').data('job-base-url');
diff --git a/passerelle/templates/passerelle/includes/resource-logs-table.html b/passerelle/templates/passerelle/includes/resource-logs-table.html
index 0372952f..85b7c7be 100644
--- a/passerelle/templates/passerelle/includes/resource-logs-table.html
+++ b/passerelle/templates/passerelle/includes/resource-logs-table.html
@@ -11,7 +11,10 @@
     <tbody>
     {% for record in logrecords %}
     <tr class="level-{{record.level}}" data-pk="{{ record.pk }}">
-        <td class="timestamp">{{ record.timestamp|localtime }}</td>
+        <td class="timestamp">
+          {{ record.timestamp|localtime|date:'DATE_FORMAT' }}
+          {{ record.timestamp|localtime|time:"H:i:s" }}
+        </td>
         <td>{{ record.sourceip|default:"-" }}</td>
         <td class="message">{{ record.message|censor }}</td>
     </tr>
diff --git a/passerelle/templates/passerelle/manage/service_logs.html b/passerelle/templates/passerelle/manage/service_logs.html
index 60ccf221..07f0d254 100644
--- a/passerelle/templates/passerelle/manage/service_logs.html
+++ b/passerelle/templates/passerelle/manage/service_logs.html
@@ -24,4 +24,12 @@
 {% include "passerelle/includes/resource-logs-table.html" with logrecords=page_obj %}
 </div>
 
+{% if log_target %}
+<script>
+$(function () {
+    open_log_window($('table.main').data('log-base-url'), {{ log_target.id }});
+});
+</script>
+{% endif %}
+
 {% endblock %}
diff --git a/passerelle/views.py b/passerelle/views.py
index 207fc923..1a2a37be 100644
--- a/passerelle/views.py
+++ b/passerelle/views.py
@@ -229,6 +229,15 @@ class GenericViewLogsConnectorView(GenericConnectorMixin, ListView):
         context = super(GenericViewLogsConnectorView, self).get_context_data(**kwargs)
         context['object'] = self.get_object()
         context['query'] = self.request.GET.get('q') or ''
+        if self.request.GET.get('log_id'):
+            try:
+                context['log_target'] = ResourceLog.objects.get(
+                    appname=self.kwargs['connector'],
+                    slug=self.kwargs['slug'],
+                    pk=self.request.GET['log_id']
+                )
+            except (ValueError, ResourceLog.DoesNotExist):
+                pass
         return context
 
     def get_object(self):
diff --git a/tests/test_manager.py b/tests/test_manager.py
index b1a6e18d..dd0abea4 100644
--- a/tests/test_manager.py
+++ b/tests/test_manager.py
@@ -137,6 +137,7 @@ def test_menu_json(app, admin_user):
     assert resp.headers['content-type'] == 'application/javascript'
     assert resp.content.startswith(b'FooBar([{"')
 
+
 def test_logs(app, admin_user):
     data = StringIO('1;Foo\n2;Bar\n3;Baz')
     csv = CsvDataSource.objects.create(csv_file=File(data, 't.csv'),
@@ -197,6 +198,17 @@ def test_logs(app, admin_user):
 
     resp = app.get(base_url + '12345' + '/', status=404)
 
+    resp = app.get('/manage/csvdatasource/test/logs/?log_id=%s' % log_pk)
+    assert 'log_target' in resp.context
+
+    # unknown id
+    resp = app.get('/manage/csvdatasource/test/logs/?log_id=0')
+    assert 'log_target' not in resp.context
+    # bad id
+    resp = app.get('/manage/csvdatasource/test/logs/?log_id=foo')
+    assert 'log_target' not in resp.context
+
+
 def test_logging_parameters(app, admin_user):
     data = StringIO('1;Foo\n2;Bar\n3;Baz')
     csv = CsvDataSource.objects.create(csv_file=File(data, 't.csv'),
-- 
2.20.1

