Skip to content
Snippets Groups Projects
Commit febe41d7 authored by Tanner Prestegard's avatar Tanner Prestegard Committed by GraceDB
Browse files

basic web view for superevents

parent 12f83d47
No related branches found
No related tags found
1 merge request!8Superevents
from django import forms
from django.utils.translation import ugettext_lazy as _
class ModelFormUpdateMixin(forms.ModelForm):
"""
ModelForm mixin which provides the capability to update an existing model
object with input data which is incomplete - i.e., doesn't contain all
fields required by the form.
Usage:
# For a model with attributes 'attr1' and 'attr2 and a form that
# normally requires both attributes
data_dict = {'attr1': 'example'}
ExampleForm(data_dict, instance=model_instance)
"""
def __init__(self, *args, **kwargs):
super(ModelFormUpdateMixin, self).__init__(*args, **kwargs)
# If instance is provided, populate missing data
if self.instance.pk is not None:
self.populate_missing_data()
def get_instance_data(self):
# Should be overridden by concrete derived classes
return NotImplemented
def populate_missing_data(self):
"""
Populate missing data fields from model instance.
NOTE: the actual data dictionary is populated, not initial data,
because missing fields in the input data would still be ignored.
"""
if self.instance.pk is None:
self.add_error(None, _('Model instance not found'))
# Insert instance data for missing fields only
instance_data = self.get_instance_data()
for key in self.fields.keys():
if not self.data.has_key(key) and instance_data[key]:
self.data[key] = instance_data[key]
......@@ -32,6 +32,12 @@ table.event {width:100%}
/* Tanner added - centering columns in multi-column tables */
table.eventmulti td {text-align:center;}
/* superevent info table */
.superevent th {padding: 5px 10px 5px 10px;border:none;text-align:center;vertical-align:bottom;}
.superevent td {padding:10px;border:none;vertical-align:bottom;}
.superevent {border-bottom:1px solid gray;}
/* #table.superevent {width:100%} */
table.analysis_specific_lm th {padding:3px;border:none;text-align:center;vertical-align:bottom;}
table.analysis_specific_lm {border-bottom:1px solid gray;}
......
from django import forms
from django.utils.translation import ugettext_lazy as _
from .models import Superevent, Log
from .utils import create_log
from core.forms import ModelFormUpdateMixin
from core.vfile import VersionedFile
from events.models import Event
import os
import logging
logger = logging.getLogger(__name__)
class LogCreateForm(forms.ModelForm):
# This field is used to get file upload, but is not actually
# part of the Log model
data_file = forms.FileField(label="Data file", required=False)
class Meta:
model = Log
fields = ['issuer', 'superevent', 'filename', 'file_version',
'data_file', 'comment']
def __init__(self, *args, **kwargs):
super(LogCreateForm, self).__init__(*args, **kwargs)
# Make certain fields hidden in the web view. We will either specify
# the value in the initial view or when we handle the POST data.
self.fields['filename'].widget = forms.HiddenInput()
self.fields['file_version'].widget = forms.HiddenInput()
self.fields['issuer'].widget = forms.HiddenInput()
self.fields['superevent'].widget = forms.HiddenInput()
def save(self, commit=True):
# Get data file (if present)
create_log_args = self.cleaned_data.copy()
create_log_args['issue_alert'] = True
return create_log(**create_log_args)
#return create_log(**self.cleaned_data, issue_alert=True)
#data_file = self.cleaned_data.pop('data_file', None)
## Inherited save from ModelForm
#obj = super(LogCreateForm, self).save(commit)
## Do other stuff with data file
#if data_file:
# filepath = os.path.join(obj.superevent.datadir,
# self.cleaned_data['filename'])
# fdest = VersionedFile(filepath, 'w')
# for chunk in data_file.chunks():
# fdest.write(chunk)
# fdest.close()
# obj.file_version = fdest.version
# if commit:
# obj.save()
#return obj
<h2>Create log message</h2>
<div style="padding-bottom: 20px">
<form enctype="multipart/form-data" action="{% url "superevents:create-log" superevent.superevent_id %}" method="POST">
<table>
{{ log_create_form.as_table }}
</table>
<input type="submit" value="Submit" />
</form>
</div>
{% extends "base.html" %}
{% load timeutil %}
{% load scientific %}
{% load sanitize_html %}
{% load logtags %}
{% block heading %}{% endblock %}
{% block bodyattrs %}class="tundra eventDetail"{% endblock %}
{% block jscript %}
{% endblock %}
{% block content %}
TBD:
<ul style="padding-bottom: 30px;">
<li>javascript update for labels</li>
<li>link for log message files, make sure to link to correct file version</li>
<li>event log tagging</li>
</ul>
<div id='event_detail_content'>
{% block superevent_info %}
<h2>Superevent Info</h2>
<table class="superevent">
<tr>
<th>Superevent ID</th>
<th>Labels</th>
<th>Preferred Event</th>
<th>GW events</th>
<th>External events</th>
</tr>
<tr>
<td>{{ superevent.superevent_id }}</td>
<td>{% for labelling in superevent.labelling_set.all %}
<div style="color: {{ labelling.label.defaultColor }}"><b>{{ labelling.label.name }}</b></div>
{% endfor %}
</td>
<td><a href="{% url "view" preferred_event.graceid %}">{{ preferred_event.graceid }}</a></td>
<td>
<div>
{% for graceid in internal_events %}
<a href="{% url "view" graceid %}">{{ graceid }}</a>
{% endfor %}
</div>
</td>
<td>
<div>
{% for graceid in external_events %}
<a href="{% url "view" graceid %}">{{ graceid }}</a>
{% endfor %}
</div>
</td>
</tr>
</table>
{% endblock %}
<br />
<br />
{% block basic_info %}
<h2>Preferred Event Info</h2>
<table class="event">
<tr>
<th valign="top">UID</th>
<th>Labels</th>
<th>Group</th>
<th>Pipeline</th>
<th>Search</th>
<th>Instruments</th>
<th>
<div id="basic_info_event_ts"></div>
<div> Event Time </div>
</th>
<th>FAR (Hz)</th>
<th>FAR (yr<sup>-1</sup>)</th>
<th>Links</th>
<th>
<div id="basic_info_created_ts"></div>
<div> Submitted </div>
</th>
</tr>
<tr>
<td><a href="{% url "view" preferred_event.graceid %}">{{ preferred_event.graceid }}</a></td>
<td>
{% for labelling in preferred_event.labelling_set.all %}
<span onmouseover="tooltip.show(tooltiptext('{{labelling.label.name}}', '{{labelling.creator.username}}', '{{labelling.created|utc}}', '{{labelling.label.description}}'));" onmouseout="tooltip.hide();" style="color: {{labelling.label.defaultColor}}">{{ labelling.label.name }}</span>
{% endfor %}
</td>
<td>{{ preferred_event.group.name }} </td>
<td>{{ preferred_event.pipeline.name }} </td>
<td>{{ preferred_event.search.name }} </td>
<td>{{ preferred_event.instruments }}</td>
<td>{% if preferred_event.gpstime %}
<!-- <span title="{{ preferred_event.gpstime|gpsdate }}">{{ preferred_event.gpstime }}</span> -->
{{ preferred_event.gpstime|multiTime:"gps" }}
{% endif %}</td>
{# NOTE: XXX Using event_far so it can be floored for external users. #}
<td>{% if far_is_upper_limit %} &lt; {% endif %}{{ display_far|scientific }}</td>
<td>{% if far_is_upper_limit %} &lt; {% endif %}{{ display_far_yr }}</td>
<td><a href="{{ preferred_event.weburl }}">Data</a></td>
<td>{{ preferred_event.created|multiTime:"created" }}</td>
</tr>
</table>
{% endblock %}
</div>
<div class="content-area">
{% if user_is_external %}
{# Analysis-specific attributes which can be exposed to external partners #}
{% block external_analysis_specific %}
{# Empty by default #}
{% endblock %}
{% else %}
{# Analysis-specific attributes #}
{% block analysis_specific %}
{# This block is empty in the base event_detail template #}
{% endblock %}
{% endif %}
</div>
<!-- Form for creating new log messages -->
{% include "log_create_form.html" %}
<!-- Set of log messages -->
<h2>Full event log</h2>
<div style="padding-bottom: 20px">
<table>
<tr>
<th>No.</th>
<th>Log Entry Created</th>
<th>Submitter</th>
<th>Comment</th>
<th>Tags</th>
</tr>
{% for log in logs %}
<tr>
<td>{{ log.N }}</td>
<td>{{ log.created }}</td>
<td>{{ log.issuer }}</td>
<td>{{ log.comment }}
{% if log.filename %}
{{ log.filename }}
{% endif %}
</td>
<td>
{% for tag in log.tags.all %}
<div style="padding: 2px; display: inline; background-color: #000000; color: #FFFFFF;">{{ tag.displayName }}</div>
{% endfor %}
</td>
</tr>
{% endfor %}
</table>
</div>
</div> <!-- end event_detail_content div -->
{% endblock %}
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from django.utils.html import escape
from django.views.decorators.http import require_POST
from .models import Superevent, Log
from .forms import LogCreateForm
from core.vfile import VersionedFile
from events.permission_utils import internal_user_required, is_external
import os
import logging
logger = logging.getLogger(__name__)
# Need to restrict ability to view
def webview(request, superevent_id):
# Get superevent object
superevent = Superevent.objects.get(id=superevent_id[1:])
# Get context
context = {}
context['superevent'] = superevent
context['preferred_event'] = superevent.preferred_event
# Display far
display_far = superevent.preferred_event.far
far_is_upper_limit = False
if display_far and is_external(request.user):
if display_far < settings.VOEVENT_FAR_FLOOR:
display_far = settings.VOEVENT_FAR_FLOOR
far_is_upper_limit = True
context['display_far'] = display_far
context['far_is_upper_limit'] = far_is_upper_limit
display_far_yr = display_far
if display_far:
far_yr = display_far * (86400*365.25) # yr^-1
if (far_yr < 1):
display_far_yr = "1 per {0:0.5g} years".format(1.0/far_yr)
else:
display_far_yr = "{0:0.5g} per year".format(far_yr)
context['display_far_yr'] = display_far_yr
# 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)
# Pass event graceids
context['internal_events'] = superevent.get_internal_events().order_by('id')
context['external_events'] = superevent.get_external_events().order_by('id')
# Form for log creation
context['log_create_form'] = LogCreateForm(initial={
'superevent': superevent.id})
# Temporary method for getting logs
context['logs'] = superevent.log_set.select_related('issuer').all()
return render(request, 'superevent.html', context=context)
# Need to add an auth check for this too
# If we use javascript for this eventually, we will want to enforce
# request.is_ajax()
@require_POST
def web_create_log(request, superevent_id):
"""Webpage-based superevent log message creation"""
# Set up dict for passing to log creation form ----------------------------
log_dict = request.POST.copy()
log_dict['issuer'] = request.user.id
# Get superevent id from superevent_id
# TODO: TEMPORARY until superevent_id is well defined
superevent = Superevent.objects.get(id=int(superevent_id[1:]))
log_dict['superevent'] = superevent.id
# TODO:
# After getting superevent, make sure user has appropriate permissions
# to operate on it
# File version stuff
data_file = request.FILES.get('data_file', None) if request.FILES else None
filename = getattr(data_file, 'name', None)
log_dict['filename'] = filename
log_dict['file_version'] = None # will be updated later, if applicable
log_dict['data_file'] = data_file
# Validate with form and create new log object ----------------------------
form = LogCreateForm(log_dict, request.FILES)
# If form is valid, create new log object from form data
if form.is_valid():
# Create new log object
obj = form.save()
# Save data_file, if applicable
#if data_file:
# # TODO: fix this!
# filepath = '/home/gracedb/' + filename
# #filepath = os.path.join(event.datadir, filename)
# fdest = VersionedFile(filepath, 'w')
# for chunk in data_file.chunks():
# fdest.write(chunk)
# fdest.close()
# # Ascertain the version assigned to this particular file and update
# # the log object
# obj.file_version = fdest.version
# obj.save()
# TODO:
# Attach "analyst_comments" tag - web view only
# TODO:
# Send alert
# TODO:
# attach external tagname if user is external
# TODO:
# Don't have a good way to handle errors in the form at present - since we
# just redirect, we can't update the form with errors. We can just call
# the webview function with extra context, but then the URL is "wrong"
# Return to superevent page
return HttpResponseRedirect(reverse('superevents:view',
args=[superevent_id]))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment