From c52f824355de977cd061a9527d11802f51fb7b89 Mon Sep 17 00:00:00 2001
From: Tanner Prestegard <tanner.prestegard@ligo.org>
Date: Thu, 31 May 2018 11:10:26 -0500
Subject: [PATCH] Adding functionality to confirm superevent as GW

Created a web form and API resource for confirming a superevent as
a GW.  Also added and utilized permissions for allowing this action.
---
 gracedb/superevents/api/view_templates.py     |  1 +
 gracedb/superevents/api/views.py              | 22 ++++++++++-
 .../0007_add_gw_permission_to_superevent.py   | 19 +++++++++
 gracedb/superevents/models.py                 |  5 ++-
 gracedb/superevents/urls.py                   |  2 +
 gracedb/superevents/utils.py                  | 16 ++++++++
 gracedb/superevents/views.py                  | 39 ++++++++++++++++++-
 gracedb/templates/superevents/view.html       | 11 ++++++
 8 files changed, 111 insertions(+), 4 deletions(-)
 create mode 100644 gracedb/superevents/migrations/0007_add_gw_permission_to_superevent.py

diff --git a/gracedb/superevents/api/view_templates.py b/gracedb/superevents/api/view_templates.py
index f80784f32..402058732 100644
--- a/gracedb/superevents/api/view_templates.py
+++ b/gracedb/superevents/api/view_templates.py
@@ -43,6 +43,7 @@ def construct_api_url_templates(request=None):
         'superevent-emobservation-list': [],
         'superevent-emobservation-detail': [
             PH[SupereventEMObservationViewSet.lookup_field]],
+        'superevent-confirm-as-gw': []
     }
 
     # Dict of URL templates:
diff --git a/gracedb/superevents/api/views.py b/gracedb/superevents/api/views.py
index afd5cf7ad..77854a941 100644
--- a/gracedb/superevents/api/views.py
+++ b/gracedb/superevents/api/views.py
@@ -1,4 +1,5 @@
 from rest_framework import parsers
+from rest_framework.decorators import action
 from rest_framework.renderers import BaseRenderer, JSONRenderer, \
     BrowsableAPIRenderer
 from rest_framework.permissions import IsAuthenticated
@@ -14,7 +15,8 @@ from django.shortcuts import get_object_or_404
 
 from ..models import Superevent
 from ..utils import remove_tag_from_log, remove_event_from_superevent, \
-    remove_label_from_superevent, get_superevent_by_date_id_or_404
+    remove_label_from_superevent, confirm_superevent_as_gw, \
+    get_superevent_by_date_id_or_404
 
 from core.vfile import VersionedFile
 from core.http import check_and_serve_file
@@ -78,6 +80,24 @@ class SupereventViewSet(viewsets.ModelViewSet):
 
         return obj
 
+    @action(methods=['post'], detail=True)
+    def confirm_as_gw(self, request, superevent_id):
+        # TODO: permissions checking!!
+
+        # Get superevent
+        superevent = self.get_object()
+
+        # If already a GW, return an error
+        if not superevent.is_gw:
+            confirm_superevent_as_gw(superevent, self.request.user)
+        else:
+            return Response('Superevent is already confirmed as a GW',
+                status=status.HTTP_400_BAD_REQUEST)
+
+        # Return data
+        serializer = self.get_serializer(superevent)
+        return Response(serializer.data)
+
 
 class SupereventEventViewSet(mixins.ListModelMixin,
                              mixins.CreateModelMixin,
diff --git a/gracedb/superevents/migrations/0007_add_gw_permission_to_superevent.py b/gracedb/superevents/migrations/0007_add_gw_permission_to_superevent.py
new file mode 100644
index 000000000..6bc79fd35
--- /dev/null
+++ b/gracedb/superevents/migrations/0007_add_gw_permission_to_superevent.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.5 on 2018-05-29 18:42
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('superevents', '0006_remove_superevent_alert_sent'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='superevent',
+            options={'ordering': ['-id'], 'permissions': (('view_superevent', 'Can view superevent'), ('confirm_gw_superevent', 'Can confirm as a superevent as a GW'))},
+        ),
+    ]
diff --git a/gracedb/superevents/models.py b/gracedb/superevents/models.py
index 50ed0b9cf..1ee8e281a 100644
--- a/gracedb/superevents/models.py
+++ b/gracedb/superevents/models.py
@@ -88,7 +88,10 @@ class Superevent(CleanSaveModel, ModelToDictMixin, AutoIncrementModel):
             ('t_0_date', 'gw_letter_suffix'),)
 
         # Extra permissions beyond the standard add, change, delete perms
-        permissions = (('view_superevent', 'Can view superevent'),)
+        permissions = (
+            ('view_superevent', 'Can view superevent'),
+            ('confirm_gw_superevent', 'Can confirm as a superevent as a GW'),
+        )
 
     # Class method overrides --------------------------------------------------
     def clean(self, *args, **kwargs):
diff --git a/gracedb/superevents/urls.py b/gracedb/superevents/urls.py
index f64f62911..a504340b6 100644
--- a/gracedb/superevents/urls.py
+++ b/gracedb/superevents/urls.py
@@ -11,6 +11,8 @@ urlpatterns = [
         regex=Superevent.ID_REGEX), views.webview, name="view"),
     url(r'^create_log/(?P<superevent_id>{regex})/$'.format(
         regex=Superevent.ID_REGEX), views.web_create_log, name="create-log"),
+    url(r'^confirm_as_gw/(?P<superevent_id>{regex})/$'.format(
+        regex=Superevent.ID_REGEX), views.confirm_as_gw, name="confirm-gw"),
 
     # Files
     url(r'^(?P<superevent_id>{regex})/files/$'.format(
diff --git a/gracedb/superevents/utils.py b/gracedb/superevents/utils.py
index 2e02dd16e..0bff8ca16 100644
--- a/gracedb/superevents/utils.py
+++ b/gracedb/superevents/utils.py
@@ -388,3 +388,19 @@ def get_superevent_by_date_id_or_404(request, superevent_id):
     queryset = Superevent.objects.all()
 
     return get_object_or_404(queryset, **filter_kwargs)
+
+
+def confirm_superevent_as_gw(superevent, user):
+
+    # Update superevent (mark as a GW, construct new ID, etc.)
+    superevent.confirm_as_gw()
+
+    # Create log message
+    message = "Confirmed as a gravitational wave."
+    gw_log = create_log(user, message, superevent, issue_alert=True,
+        autogenerated=False)
+
+    # TODO: add label?
+
+    # TODO:
+    # issue alert
diff --git a/gracedb/superevents/views.py b/gracedb/superevents/views.py
index 1e5d5016b..c41e6231f 100644
--- a/gracedb/superevents/views.py
+++ b/gracedb/superevents/views.py
@@ -1,4 +1,5 @@
-from django.http import HttpResponse, HttpResponseRedirect, Http404
+from django.http import HttpResponse, HttpResponseRedirect, \
+    HttpResponseForbidden
 from django.shortcuts import render
 from django.urls import reverse
 from django.utils.html import escape
@@ -6,7 +7,7 @@ from django.views.decorators.http import require_POST, require_GET
 
 from .models import Superevent, Log
 from .forms import LogCreateForm
-from .utils import get_superevent_by_date_id_or_404
+from .utils import get_superevent_by_date_id_or_404, confirm_superevent_as_gw
 
 from core.http import check_and_serve_file
 from core.vfile import VersionedFile
@@ -49,6 +50,14 @@ def webview(request, superevent_id):
             display_far_yr = "{0:0.5g} per year".format(far_yr)
     context['display_far_yr'] = display_far_yr
 
+    # Form to change GW status (only for authorized users)
+    # Only show if superevent is NOT a GW.  Require manual intervention to
+    # revert since it will surely mess with automated numbering of date IDs
+    if not superevent.is_gw and request.user.has_perm('confirm_gw_superevent'):
+        context['show_gw_status_form'] = True
+    else:
+        context['show_gw_status_form'] = False
+
     # Is the user an external user? (I.e., not part of the LVC?) The template 
     # needs to know that in order to decide what pieces of information to show.
     context['user_is_external'] = is_external(request.user)
@@ -138,6 +147,32 @@ def web_create_log(request, superevent_id):
         args=[superevent_id]))
 
 
+@require_POST
+def confirm_as_gw(request, superevent_id):
+
+    # Check user permissions
+    if not request.user.has_perm('confirm_gw_superevent'):
+        return HttpResponseForbidden('You do not have permission to perform '
+            'this action.')
+
+    # TODO: make sure user has permission to see the superevent
+    # need to do some kind of filtering on queryset initially, like in
+    # rest_framework. maybe add an optional queryset argument to
+    # get_superevent_by_date_id_or_404, and a check that the queryset's model
+    # is Superevent
+
+    # Get superevent id from superevent_id
+    # Get superevent object
+    superevent = get_superevent_by_date_id_or_404(request, superevent_id)
+
+    # Set superevent as gw
+    confirm_superevent_as_gw(superevent, request.user)
+
+    # Return to superevent page
+    return HttpResponseRedirect(reverse('superevents:view',
+        args=[superevent_id]))
+
+
 # TODO:
 # filter files for external users (see how this is done for events)
 def file_list(request, superevent_id):
diff --git a/gracedb/templates/superevents/view.html b/gracedb/templates/superevents/view.html
index 1a01ccf88..5be75aac5 100644
--- a/gracedb/templates/superevents/view.html
+++ b/gracedb/templates/superevents/view.html
@@ -20,6 +20,17 @@ TBD:
 
 <div id='event_detail_content'>
 
+{% block gw_status %}
+{% if show_gw_status_form %}
+<div class="content-area">
+<form action="{% url "superevents:confirm-gw" superevent.superevent_id %}" method="POST">
+    <input type="submit" value="Confirm this superevent as a GW" class="permButtonClass">
+</form>
+<div><b>Note:</b> this action is irreversible without manual intervention by an admin!</div>
+</div>
+{% endif %}
+{% endblock %}
+
 {% block superevent_info %}
 <h2>Superevent Info</h2>
 <table class="superevent">
-- 
GitLab