From 40eded4707b16203a26c56748977b195deb549ae Mon Sep 17 00:00:00 2001
From: Tanner Prestegard <tanner.prestegard@ligo.org>
Date: Tue, 4 Jun 2019 15:02:24 -0500
Subject: [PATCH] A few updates to public candidate view

---
 gracedb/superevents/urls.py                   |   6 +-
 gracedb/superevents/views.py                  |  78 ++++++-------
 gracedb/templates/base.html                   |   4 +-
 gracedb/templates/navbar_min.html             |  26 -----
 gracedb/templates/superevents/public.html     | 103 -----------------
 .../templates/superevents/public_alerts.html  | 104 ++++++++++++++++++
 6 files changed, 144 insertions(+), 177 deletions(-)
 delete mode 100644 gracedb/templates/navbar_min.html
 delete mode 100644 gracedb/templates/superevents/public.html
 create mode 100644 gracedb/templates/superevents/public_alerts.html

diff --git a/gracedb/superevents/urls.py b/gracedb/superevents/urls.py
index 026b27cd8..0dea4db31 100644
--- a/gracedb/superevents/urls.py
+++ b/gracedb/superevents/urls.py
@@ -34,10 +34,6 @@ urlpatterns = legacy_urlpatterns + [
     url(r'^(?P<superevent_id>{regex})/'.format(regex=Superevent.ID_REGEX),
         include(suburlpatterns)),
 
-    # table of all public events
+    # View of all candidates
     url(r'^public/$', views.SupereventPublic.as_view(), name="public-alerts"),
-
-    # Tanner customizations (now, both links go to same view)
-    url(r'^public2/$', views.SupereventPublic.as_view(), name="public-alerts2"),
-    
 ]
diff --git a/gracedb/superevents/views.py b/gracedb/superevents/views.py
index 19bbe38a3..b033c75b2 100644
--- a/gracedb/superevents/views.py
+++ b/gracedb/superevents/views.py
@@ -120,20 +120,20 @@ class SupereventFileList(SupereventDetailView):
 # handled through the API. Links on the file list page point to the
 # API file download page.
 
+
 class SupereventPublic(DisplayFarMixin, ListView):
     model = Superevent
-    template_name = 'superevents/public.html'
+    template_name = 'superevents/public_alerts.html'
     filter_permissions = ['superevents.view_superevent']
     log_view_permission = 'superevents.view_log'
     noticeurl_template = 'https://gcn.gsfc.nasa.gov/notices_l/{s_id}.lvc'
     gcnurl_template = 'https://gcn.gsfc.nasa.gov/other/GW{sd_id}.gcn3'
     skymap_filename = 'bayestar.png'
+    pe_results_tagname = 'pe_results'
 
-    
     def get_queryset(self, **kwargs):
-        # -- Query only for public events
-        # Comment from Tanner: Use the category directly from the superevent
-        # model rather than hard-coding
+        # Query only for public events
+        # NOTE: may want to fix this to only O3 events at some point
         qs = Superevent.objects.filter(is_exposed=True,
             category=Superevent.SUPEREVENT_CATEGORY_PRODUCTION) \
             .prefetch_related('voevent_set', 'log_set')
@@ -141,73 +141,70 @@ class SupereventPublic(DisplayFarMixin, ListView):
 
     def get_context_data(self, **kwargs):
         # Get base context
-        # Comment from Tanner: use super() here; it's equivalent in this case
-        # to directly calling ListView.get_context_data, but super() is
-        # typically better practice
         context = super(SupereventPublic, self).get_context_data(**kwargs)
 
         #-- For each superevent, get list of log messages and construct pastro string
         candidates = 0
         for se in self.object_list:
 
-            # Comment from Tanner: use reverse() for internal URLs
-            se.maplocal = reverse('legacy_apiweb:default:superevents:superevent-file-detail',
-                args=[se.default_superevent_id, self.skymap_filename])
+            # Get skymap image (if a public one exists)
+            se.skymap_image = None
+            if se.log_set.filter(tags__name='public',
+                filename=self.skymap_filename).exists():
+                se.skymap_image = reverse(
+                    'legacy_apiweb:default:superevents:superevent-file-detail',
+                    args=[se.default_superevent_id, self.skymap_filename])
 
-            #-- GCN links
-            # Comment from Tanner: define link templates outside of function
-            # so they are loaded at "compile-time" rather than each time the
-            # function is called
+            # External links to GCN notice and circular
             se.noticeurl = self.noticeurl_template.format(s_id=
                 se.default_superevent_id)
             se.gcnurl = self.gcnurl_template.format(sd_id=
                 se.default_superevent_id[1:])
-            
+
             se.t0_iso = gpstime.gps_to_utc(se.t_0).isoformat(' ').split('.')[0]
             se.t0_utc = se.t0_iso.split()[1]
 
             # Get display FARs for preferred_event
-            se.far_hz, se.far_hr, se.far_limit = self.get_display_far(obj=se.preferred_event)
-            
-            
-
-            #-- Get list of voevents
-            # Comment from Tanner: do as much work as you can in the database.
-            # Also, use VOEvent types from the model rather than hard-coding
-            # -- Filter out retractions
-            # Comment from Tanner: looks like we only ever use the
-            # non-retraction VOEvent with the highest N, so let's just get
-            # it in one query.
+            se.far_hz, se.far_hr, se.far_limit = self.get_display_far(
+                obj=se.preferred_event)
+
+            # Get list of voevents, filtering out retractions
             voe = se.voevent_set.exclude(voevent_type=
                 VOEvent.VOEVENT_TYPE_RETRACTION).order_by('-N').first()
-            # -- Was this candidate retracted?
+
+            # Was the candidate retracted?
             se.retract = se.voevent_set.filter(voevent_type=
                 VOEvent.VOEVENT_TYPE_RETRACTION).exists()
             candidates += int(not se.retract)
 
             # Get list of viewable logs for user which are tagged with
             # 'analyst_comments'
-            viewable_logs = get_objects_for_user(self.request.user,
-                self.log_view_permission,
-                klass=se.log_set.filter(tags__name='analyst_comments'))
+            #viewable_logs = get_objects_for_user(self.request.user,
+            #    self.log_view_permission,
+            #    klass=se.log_set.filter(tags__name='analyst_comments'))
+            viewable_logs = se.log_set.filter(tags__name='public').filter(tags__name='analyst_comments')
             # Compile comments from these logs
             se.comments = ' ** '.join(list(viewable_logs.values_list(
                 'comment', flat=True)))
-            if se.retract: se.comments += "RETRACTED"
+            if se.retract:
+                if se.comments:
+                    se.comments += " "
+                se.comments += "RETRACTED"
 
-            # -- Get list of PE results
+            # Get list of PE results
             pe_results = get_objects_for_user(self.request.user,
                 self.log_view_permission,
-                klass=se.log_set.filter(tags__name='pe_result'))
+                klass=se.log_set.filter(tags__name=self.pe_results_tagname))
             # Compile comments from these logs
             se.pe = ' ** '.join(list(pe_results.values_list(
                 'comment', flat=True)))
-            
-            # -- Read out probabilities
-            pastro_values = [ ("BNS",voe.prob_bns), ("NSBH",voe.prob_nsbh),
-                              ("BBH", voe.prob_bbh), ("Terrestrial", voe.prob_terrestrial),
-                              ("MassGap", voe.prob_mass_gap) ]
 
+            # Get p_astro probabilities
+            pastro_values = [("BNS", voe.prob_bns),
+                ("NSBH", voe.prob_nsbh),
+                ("BBH", voe.prob_bbh),
+                ("Terrestrial", voe.prob_terrestrial),
+                ("MassGap", voe.prob_mass_gap)]
             pastro_values.sort(reverse=True, key=lambda (a,b):b)
             sourcelist = []
             for key, value in pastro_values:
@@ -222,7 +219,4 @@ class SupereventPublic(DisplayFarMixin, ListView):
         # Number of non-retracted candidate events
         context['candidates'] = candidates
 
-        #-- Is this user outside the LVC?
-        context['user_is_external'] = is_external(self.request.user)
-
         return context
diff --git a/gracedb/templates/base.html b/gracedb/templates/base.html
index 754a5ae64..8ac97c1be 100644
--- a/gracedb/templates/base.html
+++ b/gracedb/templates/base.html
@@ -7,7 +7,9 @@
 
     {# remove requests for favicon #}
     <link rel="icon" href="data:,">
-    {% block csslink %}<link rel="stylesheet" href="{% static "css/style.css" %}" /> {% endblock %}
+    {% block csslink %}
+    <link rel="stylesheet" href="{% static "css/style.css" %}" />
+    {% endblock %}
     <title>GraceDb | {% block title %}{% endblock %}</title>
 <!-- START TESTING -->
 <script type="text/javascript">
diff --git a/gracedb/templates/navbar_min.html b/gracedb/templates/navbar_min.html
deleted file mode 100644
index 1e430f461..000000000
--- a/gracedb/templates/navbar_min.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<div style="padding-bottom: 30px;">
-<ul id="nav">
-    <li id="nav-home"><a href="{% url "home" %}">Home</a></li>
-    {% if user.is_authenticated %}
-        <li id="nav-logout"><a href="{% url "logout" %}">Logout</a></li>
-        <li id="nav-user">Authenticated as:
-        {% if user.first_name %}
-            {{ user.get_full_name }}
-        {% else %}
-            {{ user.username }}
-        {% endif %}
-        </li>
-    {% else %}
-        <li id="nav-login"><a href="{% url "login" %}">Login</a></li>
-    {% endif %}
-</ul>
-
-{% if 'lvem_view' in request.path %}
-<div id="lvem_view_message">
-<b>IMPORTANT:</b> You are viewing this page as a member of the LV-EM Observers group.
-At the end of your session, please remove the 'lvem_view/' string from the URL to 
-return to the regular GraceDB site. This will ensure that your group memberships 
-are correct the next time you log in. 
-</div>
-{% endif %}
-</div>
diff --git a/gracedb/templates/superevents/public.html b/gracedb/templates/superevents/public.html
deleted file mode 100644
index b190eccb6..000000000
--- a/gracedb/templates/superevents/public.html
+++ /dev/null
@@ -1,103 +0,0 @@
-{% extends "base.html" %}
-{% load sanitize_html %}
-{% load logtags %}
-{% load static %}
-
-
-{% block csslink %}
-<link rel="stylesheet" href="{% static "css/style.css" %}" />
-<link rel="stylesheet" href="{% static "css/public.css" %}" />
-<meta name="viewport" content="width=device-width, initial-scale=1">
-{% endblock %}
-
-{% block heading %}{% endblock %}
-
-{% block jscript %}
-<link rel="stylesheet" type="text/css" href="{% static "tablesaw/dist/tablesaw.css" %}" />
-<script language="javascript" type="text/javascript" src="{% static "tablesaw/dist/tablesaw.js" %}"></script>
-<script language="javascript" type="text/javascript" src="{% static "tablesaw/dist/tablesaw-init.js" %}"></script>
-{% endblock %}
-
-{% block nav %}
-<!-- This nav bar only has links for HOME and LOGIN to fit on mobile -->
-{% include "navbar_min.html" %}
-{% endblock %}
-
-{% block content %}
-<br/>
-<h1>LIGO/Virgo Public Alerts</h1> 
-
-<h3>Detection candidates: {{ candidates }}</h3>
-<br/><br/>
-
-<div style="overflow-x: auto">
-<table class="tablesaw" data-tablesaw-sortable data-tablesaw-sortable-switch data-tablesaw-mode="columntoggle">
-  <thead><tr>
-      <th  scope="col" data-tablesaw-sortable-col data-tablesaw-priority="persist">Event ID</th>
-      <th  scope="col" data-tablesaw-sortable-col data-tablesaw-priority="1">Possible Source (Probability)</th>
-      <th  scope="col" data-tablesaw-sortable-col data-tablesaw-priority="2">UTC</th>
-      <th  scope="col" data-tablesaw-col data-tablesaw-priority="3">GCN</th>
-      <th  scope="col" data-tablesaw-col data-tablesaw-priority="4">Location</th>
-      <th  scope="col" data-tablesaw-sortable-col data-tablesaw-priority="5">FAR</th>
-      <th  scope="col" data-tablesaw-sortable-col data-tablesaw-priority="6">Comments</th>
-      <th  scope="col" data-tablesaw-sortable-col data-tablesaw-priority="0">GPS</th> 
-
-      {% if not user_is_external %}
-      <th  scope="col" data-tablesaw-col data-tablesaw-priority="6">&Omega; Scan</th>
-      <th  scope="col" data-tablesaw-col data-tablesaw-priority="6">PE</th>
-      {% endif %}      
-
-    </tr>
-  </thead>
-  <tbody>
-
-
-{% for event in object_list %}
-<tr{% if event.retract %} style='background-color:#EDD' {% endif %}>
-
-  <td style='min-width:100px;'><a href=/superevents/{{ event.superevent_id }}>{{ event.default_superevent_id }}</a></td>
-
-  <td style='min-width:100px;'>{{ event.sourcetypes }} </td>
-
-  <td style='min-width:140px'>
-    <span style='font-size:0px;'>{{ event.t0_iso }}</span>{{ event.t_0_date }}<br/>
-    {{ event.t0_utc }} UTC
-  </td>
-
-  <td style='min-width:110px;'>
-    <a href={{ event.gcnurl }}>GCN Circulars</a><br/>
-    <a href={{ event.noticeurl }}>Notices</a> | 
-    <a href='/api/superevents/{{ event.default_superevent_id }}/voevents/'>VOE</a>
-  </td>
-
-  <td> <a href='{{ event.maplocal }}'> <img src='{{ event.maplocal }}' width='120px'/> </a> </td>
-
-
-  <td style='min-width:120px;'><span style='font-size:0px'>{{ event.far_hz|floatformat:10 }}</span>{{ event.far_hr }}</td>
-  <td style='min-width:80px;'>{{ event.comments |safe}} </td>
-  <td>{{ event.t_0|floatformat:2 }} </td>
-
-  {% if not user_is_external %}
-  <td style='min-width:70px'>
-    <a href='https://ldas-jobs.ligo-la.caltech.edu/~detchar/dqr/events/{{ event.superevent_id }}/L1deepomegascan/'>&Omega; L1</a><br/>
-    <a href='https://ldas-jobs.ligo-wa.caltech.edu/~detchar/dqr/events/{{ event.superevent_id }}/H1deepomegascan/'>&Omega; H1</a>
-  </td> 
-  <td>{{ event.pe |safe}}</td>
-  {% endif %}
-
-</tr>
-
-{% endfor %}
-</tbody></table>
-</div>
-
-<hr/>
-<ul style="list-style-type:square">
-  <li> Retractions are marked in red</li>
-  <li> Details in the <a href='https://emfollow.docs.ligo.org/userguide/'>LIGO/Virgo Alerts User Guide</a>
-</ul>
-
-<br/><br/><br/>
-
-{% endblock %}
-
diff --git a/gracedb/templates/superevents/public_alerts.html b/gracedb/templates/superevents/public_alerts.html
new file mode 100644
index 000000000..f97ee8f95
--- /dev/null
+++ b/gracedb/templates/superevents/public_alerts.html
@@ -0,0 +1,104 @@
+{% extends "base.html" %}
+{% load sanitize_html %}
+{% load logtags %}
+{% load static %}
+
+
+{% block csslink %}
+{{ block.super }}
+<link rel="stylesheet" href="{% static "css/public.css" %}" />
+<meta name="viewport" content="width=device-width, initial-scale=1">
+{% endblock %}
+
+{% block heading %}{% endblock %}
+
+{% block jscript %}
+<link rel="stylesheet" type="text/css" href="{% static "tablesaw/dist/tablesaw.css" %}" />
+<script language="javascript" type="text/javascript" src="{% static "tablesaw/dist/tablesaw.js" %}"></script>
+<script language="javascript" type="text/javascript" src="{% static "tablesaw/dist/tablesaw-init.js" %}"></script>
+{% endblock %}
+
+{% block content %}
+<br />
+<h1>LIGO/Virgo Public Alerts</h1>
+
+<h3>Detection candidates: {{ candidates }}</h3>
+<br /><br />
+
+<div style="overflow-x: auto">
+<table class="tablesaw" data-tablesaw-sortable data-tablesaw-sortable-switch data-tablesaw-mode="columntoggle">
+  <thead><tr>
+      <th scope="col" data-tablesaw-sortable-col data-tablesaw-priority="persist">Event ID</th>
+      <th scope="col" data-tablesaw-sortable-col data-tablesaw-priority="1">Possible Source (Probability)</th>
+      <th scope="col" data-tablesaw-sortable-col data-tablesaw-sortable-string data-tablesaw-priority="2">UTC</th>
+      <th scope="col" data-tablesaw-col data-tablesaw-priority="3">GCN</th>
+      <th scope="col" data-tablesaw-col data-tablesaw-priority="4">Location</th>
+      <th scope="col" data-tablesaw-sortable-col data-tablesaw-priority="5">FAR</th>
+      <th scope="col" data-tablesaw-col data-tablesaw-priority="6">Comments</th>
+      <th scope="col" data-tablesaw-sortable-col data-tablesaw-priority="0">GPS</th>
+
+      {% if user_is_internal %}
+      <th scope="col" data-tablesaw-col data-tablesaw-priority="6">&Omega; Scan</th>
+      <th scope="col" data-tablesaw-col data-tablesaw-priority="6">PE</th>
+      {% endif %}
+
+    </tr>
+  </thead>
+  <tbody>
+
+
+{% for event in object_list %}
+<tr{% if event.retract %} style="background-color: #EDD;" {% endif %}>
+
+  <td style="min-width: 100px;">
+    <a href="{% url "superevents:view" event.superevent_id %}">{{ event.default_superevent_id }}</a>
+  </td>
+  <td style="min-width: 100px;">{{ event.sourcetypes }}</td>
+  <td style="min-width: 140px;">
+    <span style="font-size: 0px;">{{ event.t_0|floatformat:2 }}</span>{{ event.t_0_date }}<br/>
+    {{ event.t0_utc }} UTC
+  </td>
+  <td style="min-width: 110px;">
+    <a href={{ event.gcnurl }}>GCN Circulars</a><br/>
+    <a href={{ event.noticeurl }}>Notices</a> | <a href="{% url "legacy_apiweb:default:superevents:superevent-voevent-list" event.default_superevent_id %}">VOE</a>
+  </td>
+  <td>
+    {% if event.skymap_image %}
+    <a href="{{ event.skymap_image }}">
+      <img src="{{ event.skymap_image }}" width="120px" />
+    </a>
+    {% else %}
+    No public skymap image found.
+    {% endif %}
+  </td>
+  <td style="min-width: 120px;">
+    <!-- Hidden float FAR value for table sorting -->
+    <span style="font-size: 0px;">{{ event.far_hz|floatformat:20 }}</span>{{ event.far_hr }}
+  </td>
+  <td style="min-width: 80px;">{{ event.comments|safe }} </td>
+  <td>{{ event.t_0|floatformat:2 }} </td>
+
+  {% if user_is_internal %}
+  <!-- Add Omega scans and PE results for LVC users -->
+  <td style="min-width: 70px;">
+    <a href="https://ldas-jobs.ligo-la.caltech.edu/~detchar/dqr/events/{{ event.superevent_id }}/L1deepomegascan/">&Omega; L1</a><br/>
+    <a href="https://ldas-jobs.ligo-wa.caltech.edu/~detchar/dqr/events/{{ event.superevent_id }}/H1deepomegascan/">&Omega; H1</a>
+  </td>
+  <td>{{ event.pe|safe }}</td>
+  {% endif %}
+
+</tr>
+{% endfor %}
+</tbody></table>
+</div>
+
+<hr />
+<ul style="list-style-type: square;">
+  <li>Retractions are marked in red.</li>
+  <li>More details about public alerts are provided in the <a href="https://emfollow.docs.ligo.org/userguide/">LIGO/Virgo Alerts User Guide</a>.</li>
+</ul>
+
+<br /><br /><br />
+
+{% endblock %}
+
-- 
GitLab