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