Skip to content
Snippets Groups Projects
Commit 6c07e9b1 authored by Branson Craig Stephens's avatar Branson Craig Stephens
Browse files

Filtered out pipeline-specific attributes in views for external

users (i.e., LV-EM MOU partners). Group names in the settings file,
as well as an external access tagname are used to control access.
parent 7b56fee0
No related branches found
Tags 0.2.3
No related merge requests found
...@@ -29,7 +29,8 @@ from view_utils import reverse ...@@ -29,7 +29,8 @@ from view_utils import reverse
from translator import handle_uploaded_data from translator import handle_uploaded_data
from forms import CreateEventForm from forms import CreateEventForm
from permission_utils import user_has_perm, filter_events_for_user from permission_utils import user_has_perm, filter_events_for_user, is_external
from permission_utils import check_external_file_access
from guardian.models import GroupObjectPermission from guardian.models import GroupObjectPermission
from throttles import EventCreationThrottle, AnnotationThrottle from throttles import EventCreationThrottle, AnnotationThrottle
...@@ -738,6 +739,11 @@ class EventLogList(APIView): ...@@ -738,6 +739,11 @@ class EventLogList(APIView):
@event_and_auth_required @event_and_auth_required
def get(self, request, event): def get(self, request, event):
logset = event.eventlog_set.order_by("created","N") logset = event.eventlog_set.order_by("created","N")
# Filter log messages for external users.
if is_external(request.user):
logset = logset.filter(tag__name=settings.EXTERNAL_ACCESS_TAGNAME)
count = logset.count() count = logset.count()
log = [ eventLogToDict(log, request) log = [ eventLogToDict(log, request)
...@@ -802,6 +808,12 @@ class EventLogList(APIView): ...@@ -802,6 +808,12 @@ class EventLogList(APIView):
return Response("Failed to save log entry: %s" % str(e), return Response("Failed to save log entry: %s" % str(e),
status=status.HTTP_503_SERVICE_UNAVAILABLE) status=status.HTTP_503_SERVICE_UNAVAILABLE)
# XXX For external users, make sure that the new log entry is tagged so
# they'll be able to see it later.
if is_external(request.user):
if settings.EXTERNAL_ACCESS_TAGNAME not in tagnames:
tagnames.append(settings.EXTERNAL_ACCESS_TAGNAME)
tw_dict = {} tw_dict = {}
if tagnames and len(tagnames): if tagnames and len(tagnames):
for tagname in tagnames: for tagname in tagnames:
...@@ -839,6 +851,12 @@ class EventLogDetail(APIView): ...@@ -839,6 +851,12 @@ class EventLogDetail(APIView):
@event_and_auth_required @event_and_auth_required
@eventlog_required @eventlog_required
def get(self, request, event, eventlog): def get(self, request, event, eventlog):
# XXX Access control to log messages for external users.
if is_external(request.user):
tagnames = [t.name for t in eventlog.tag_set.all()]
if settings.EXTERNAL_ACCESS_TAGNAME not in tagnames:
msg = 'You do not have permission to view this log message.'
return HttpResponseForbidden(msg)
return Response(eventLogToDict(eventlog, request=request)) return Response(eventLogToDict(eventlog, request=request))
...@@ -1000,7 +1018,7 @@ class EMObservationDetail(APIView): ...@@ -1000,7 +1018,7 @@ class EMObservationDetail(APIView):
#================================================================== #==================================================================
# Tags # Tags
# XXX This serializer should be moved to view_utils along with the others.
def tagToDict(tag, columns=None, request=None, event=None, n=None): def tagToDict(tag, columns=None, request=None, event=None, n=None):
"""Convert a tag to a dictionary. """Convert a tag to a dictionary.
Output depends on the level of specificity. Output depends on the level of specificity.
...@@ -1010,6 +1028,9 @@ def tagToDict(tag, columns=None, request=None, event=None, n=None): ...@@ -1010,6 +1028,9 @@ def tagToDict(tag, columns=None, request=None, event=None, n=None):
rv['name'] = tag.name rv['name'] = tag.name
rv['displayName'] = tag.displayName rv['displayName'] = tag.displayName
if event: if event:
# XXX Technically, this list should be filtered based on whether the
# user is external and has access to the logs. I don't think this is
# a big deal, though.
if n: if n:
# We want a link to the self only. End of the line. # We want a link to the self only. End of the line.
rv['links'] = { rv['links'] = {
...@@ -1092,6 +1113,9 @@ class EventTagList(APIView): ...@@ -1092,6 +1113,9 @@ class EventTagList(APIView):
@event_and_auth_required @event_and_auth_required
def get(self, request, event): def get(self, request, event):
# Return a list of links to all tags for this event. # Return a list of links to all tags for this event.
# XXX Technically, this list should be filtered based on whether the
# user is external and has access to the logs. I don't think this is
# a big deal, though.
rv = { rv = {
'tags' : [ reverse("eventtag-detail",args=[event.graceid(), 'tags' : [ reverse("eventtag-detail",args=[event.graceid(),
tag.name], tag.name],
...@@ -1166,6 +1190,11 @@ class EventLogTagDetail(APIView): ...@@ -1166,6 +1190,11 @@ class EventLogTagDetail(APIView):
msg = "Log already has tag %s" % unicode(tag) msg = "Log already has tag %s" % unicode(tag)
return Response(msg,status=status.HTTP_409_CONFLICT) return Response(msg,status=status.HTTP_409_CONFLICT)
except: except:
# Check authorization
if is_external(request.user) and tagname == settings.EXTERNAL_ACCESS_TAGNAME:
msg = "You do not have permission to add or remove this tag."
return HttpResponseForbidden(msg)
# Look for the tag. If it doesn't already exist, create it. # Look for the tag. If it doesn't already exist, create it.
try: try:
tag = Tag.objects.filter(name=tagname)[0] tag = Tag.objects.filter(name=tagname)[0]
...@@ -1531,6 +1560,12 @@ def download(request, graceid, filename=""): ...@@ -1531,6 +1560,12 @@ def download(request, graceid, filename=""):
except Event.DoesNotExist: except Event.DoesNotExist:
return HttpResponseNotFound("Event not found") return HttpResponseNotFound("Event not found")
# If the user is external, check for authorization
if is_external(request.user):
if not check_external_file_access(event, filename):
msg = "You do not have permission to view this file."
return HttpResponseForbidden(msg)
filepath = os.path.join(event.datadir(), filename) filepath = os.path.join(event.datadir(), filename)
if not os.path.exists(filepath): if not os.path.exists(filepath):
...@@ -1601,6 +1636,12 @@ class Files(APIView): ...@@ -1601,6 +1636,12 @@ class Files(APIView):
response = HttpResponseNotFound("File not readable") response = HttpResponseNotFound("File not readable")
elif os.path.isfile(filepath): elif os.path.isfile(filepath):
# get an actual file. # get an actual file.
# If the user is external, check for authorization
if is_external(request.user):
if not check_external_file_access(event, filename):
msg = "You do not have permission to view this file."
return HttpResponseForbidden(msg)
content_type, encoding = VersionedFile.guess_mimetype(filepath) content_type, encoding = VersionedFile.guess_mimetype(filepath)
content_type = content_type or "application/octet-stream" content_type = content_type or "application/octet-stream"
# XXX encoding should probably not be ignored. # XXX encoding should probably not be ignored.
...@@ -1613,19 +1654,40 @@ class Files(APIView): ...@@ -1613,19 +1654,40 @@ class Files(APIView):
# Get list of files w/urls. # Get list of files w/urls.
rv = {} rv = {}
filepath = event.datadir() filepath = event.datadir()
fnames = []
# Filter files for external users.
if is_external(request.user):
# XXX Note that the following snippet is repeated in views.py.
# Construct the file list, filtering as necessary:
for l in event.eventlog_set.all():
filename = l.filename
if len(filename):
version = l.file_version
tagnames = [t.name for t in l.tag_set.all()]
if settings.EXTERNAL_ACCESS_TAGNAME not in tagnames:
continue
if version>=0:
fnames.append(filename + ',' + str(version))
# We only want the unadorned filename once.
if filename not in fnames:
fnames.append(filename)
else:
for dirname, dirnames, filenames in os.walk(filepath):
dirname = dirname[len(filepath):] # cut off base event dir path
for filename in filenames:
# relative path from root of event data dir
filename = os.path.join(dirname, filename)
fnames.append(filename)
files = [] files = []
for dirname, dirnames, filenames in os.walk(filepath): for filename in fnames:
dirname = dirname[len(filepath):] # cut off base event dir path rv[filename] = reverse("files", args=[graceid, filename], request=request)
for filename in filenames: files.append({
# relative path from root of event data dir 'name' : filename,
filename = os.path.join(dirname, filename) 'link' : reverse("files",
rv[filename] = reverse("files", args=[graceid, filename], request=request) args=[graceid, filename],
files.append({ request=request),
'name' : filename, })
'link' : reverse("files",
args=[graceid, filename],
request=request),
})
response = Response(rv) response = Response(rv)
elif os.path.isdir(filepath): elif os.path.isdir(filepath):
# XXX Really? # XXX Really?
...@@ -1675,6 +1737,15 @@ class Files(APIView): ...@@ -1675,6 +1737,15 @@ class Files(APIView):
# XXX something should be done here. # XXX something should be done here.
pass pass
# If the user is external, we need to try to tag the log entry appropriately
if is_external(request.user):
try:
tag = Tag.objects.get(name=settings.EXTERNAL_ACCESS_TAGNAME)
tag.eventlogs.add(logentry)
except:
# XXX probably should at least log a warning here.
pass
try: try:
description = "UPLOAD: {0}".format(filename) description = "UPLOAD: {0}".format(filename)
issueAlertForUpdate(event, description, doxmpp=True, issueAlertForUpdate(event, description, doxmpp=True,
...@@ -1704,8 +1775,8 @@ class PerformanceInfo(APIView): ...@@ -1704,8 +1775,8 @@ class PerformanceInfo(APIView):
allowed_groups = set([]) allowed_groups = set([])
try: try:
allowed_groups = set([ allowed_groups = set([
AuthGroup.objects.get(name='Communities:LSCVirgoLIGOGroupMembers'), AuthGroup.objects.get(name=settings.LVC_GROUP),
AuthGroup.objects.get(name='executives'), AuthGroup.objects.get(name=settings.EXEC_GROUP),
]) ])
except: except:
pass pass
......
from django.conf import settings
from django.db.models import Q from django.db.models import Q
from guardian.shortcuts import assign_perm from guardian.shortcuts import assign_perm
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.utils.functional import wraps from django.utils.functional import wraps
from django.http import HttpResponseForbidden from django.http import HttpResponseForbidden
from gracedb.models import Event from gracedb.models import Event
import os
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# A convenient wrapper for permission checks. # A convenient wrapper for permission checks.
...@@ -37,8 +39,8 @@ def filter_events_for_user(events, user, shortname): ...@@ -37,8 +39,8 @@ def filter_events_for_user(events, user, shortname):
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
def assign_default_event_perms(event): def assign_default_event_perms(event):
# Retrieve the group objects # Retrieve the group objects
executives = Group.objects.get(name='executives') executives = Group.objects.get(name=settings.EXEC_GROUP)
internal = Group.objects.get(name='Communities:LSCVirgoLIGOGroupMembers') internal = Group.objects.get(name=settings.LVC_GROUP)
# Need to find the *type* of event. Could be a subclass. # Need to find the *type* of event. Could be a subclass.
model = event.__class__ model = event.__class__
...@@ -53,7 +55,7 @@ def assign_default_event_perms(event): ...@@ -53,7 +55,7 @@ def assign_default_event_perms(event):
# If the event is an MDC event, then we expose it to LV-EM also # If the event is an MDC event, then we expose it to LV-EM also
if event.search and event.search.name == 'MDC': if event.search and event.search.name == 'MDC':
lvem = Group.objects.get(name='gw-astronomy:LV-EM') lvem = Group.objects.get(name=settings.LVEM_GROUP)
assign_perm(view_codename, lvem, event) assign_perm(view_codename, lvem, event)
assign_perm(change_codename, lvem, event) assign_perm(change_codename, lvem, event)
...@@ -66,7 +68,7 @@ def internal_user_required(view): ...@@ -66,7 +68,7 @@ def internal_user_required(view):
def inner(request, *args, **kwargs): def inner(request, *args, **kwargs):
# XXX Should probably move this list of internal groups into settings. # XXX Should probably move this list of internal groups into settings.
internal_groups = Group.objects.filter( internal_groups = Group.objects.filter(
name__in=['Communities:LSCVirgoLIGOGroupMembers', 'executives']) name__in=[settings.LVC_GROUP, settings.EXEC_GROUP])
if not set(list(internal_groups)) & set(list(request.user.groups.all())): if not set(list(internal_groups)) & set(list(request.user.groups.all())):
return HttpResponseForbidden("Forbidden") return HttpResponseForbidden("Forbidden")
return view(request, *args, **kwargs) return view(request, *args, **kwargs)
...@@ -80,8 +82,77 @@ def lvem_user_required(view): ...@@ -80,8 +82,77 @@ def lvem_user_required(view):
@wraps(view) @wraps(view)
def inner(request, *args, **kwargs): def inner(request, *args, **kwargs):
# XXX Should probably move this list of internal groups into settings. # XXX Should probably move this list of internal groups into settings.
lvem_groups = [Group.objects.get(name='gw-astronomy:LV-EM')] lvem_groups = [Group.objects.get(name=settings.LVEM_GROUP)]
if not set(list(lvem_groups)) & set(list(request.user.groups.all())): if not set(list(lvem_groups)) & set(list(request.user.groups.all())):
return HttpResponseForbidden("Forbidden") return HttpResponseForbidden("Forbidden")
return view(request, *args, **kwargs) return view(request, *args, **kwargs)
return inner return inner
#-------------------------------------------------------------------------------
# A utility for determining whether a user is 'external' (i.e., not part of the
# LVC). This is useful for controlling which pieces of information to display
# in a view.
#-------------------------------------------------------------------------------
def is_external(user):
if user:
user_groups = [g.name for g in user.groups.all()]
if settings.LVC_GROUP not in user_groups:
return True
return False
else:
return True
# return True
#-------------------------------------------------------------------------------
# A utility for determining whether an external user should have access to a
# particular file, given the event and filename. This is done by finding the
# log message associated with that file and checking that the log message is
# tagged for external access. Returns True if the user should have access, and
# False if not. Note that this presumes that the user is external and does not
# check this.
#-------------------------------------------------------------------------------
def get_file_version(filename):
version = None
base_filename = filename
if len(filename.split(',')) > 1:
try:
toks = filename.split(',')
base_filename = toks[0]
version = int(toks[1])
except:
pass
return base_filename, version
def check_external_file_access(event, filename):
filename, version = get_file_version(filename)
if version is None:
# Figure out the version by following the link
filepath = os.path.join(event.datadir(), filename)
if os.path.islink(filepath):
target_file = os.path.realpath(filepath)
target_basename = os.path.basename(target_file)
filename, version = get_file_version(target_basename)
else:
return False
# find the associated log message
logs = event.eventlog_set.filter(filename=filename, file_version=version)
count = logs.count()
log = None
if count == 0:
# Could not find logfile
# XXX Write log
return False
elif count > 1:
# There should only be one file. Ugh. What's going on?
# XXX Write log
return False
else:
log = logs[0]
# check access
tagnames = [t.name for t in log.tag_set.all()]
if settings.EXTERNAL_ACCESS_TAGNAME not in tagnames:
return False
return True
...@@ -9,6 +9,7 @@ from django.utils.safestring import mark_safe ...@@ -9,6 +9,7 @@ from django.utils.safestring import mark_safe
from gracedb.models import SingleInspiral from gracedb.models import SingleInspiral
from utils.vfile import VersionedFile from utils.vfile import VersionedFile
from permission_utils import is_external
import os import os
from django.conf import settings from django.conf import settings
...@@ -138,140 +139,142 @@ def eventToDict(event, columns=None, request=None): ...@@ -138,140 +139,142 @@ def eventToDict(event, columns=None, request=None):
request=request)) request=request))
for labelling in event.labelling_set.all()]) for labelling in event.labelling_set.all()])
# XXX Try to produce a dictionary of analysis specific attributes. Duck typing. # XXX Try to produce a dictionary of analysis specific attributes. Duck typing.
rv['extra_attributes'] = {} # XXX These extra attributes should only be seen by internal users.
try: if request and request.user and not is_external(request.user):
# GrbEvent rv['extra_attributes'] = {}
rv['extra_attributes']['GRB'] = { try:
"ivorn" : event.ivorn, # GrbEvent
"author_ivorn" : event.author_ivorn, rv['extra_attributes']['GRB'] = {
"author_shortname" : event.author_shortname, "ivorn" : event.ivorn,
"observatory_location_id" : event.observatory_location_id, "author_ivorn" : event.author_ivorn,
"coord_system" : event.coord_system, "author_shortname" : event.author_shortname,
"ra" : event.ra, "observatory_location_id" : event.observatory_location_id,
"dec" : event.dec, "coord_system" : event.coord_system,
"error_radius" : event.error_radius, "ra" : event.ra,
"how_description" : event.how_description, "dec" : event.dec,
"how_reference_url" : event.how_reference_url, "error_radius" : event.error_radius,
"T90" : event.t90, "how_description" : event.how_description,
"trigger_duration": event.trigger_duration, "how_reference_url" : event.how_reference_url,
"designation": event.designation, "T90" : event.t90,
"redshift": event.redshift, "trigger_duration": event.trigger_duration,
"trigger_id": event.trigger_id, "designation": event.designation,
} "redshift": event.redshift,
except: "trigger_id": event.trigger_id,
pass }
try: except:
# CoincInspiralEvent pass
rv['extra_attributes']['CoincInspiral'] = { try:
"ifos" : event.ifos, # CoincInspiralEvent
"end_time" : event.end_time, rv['extra_attributes']['CoincInspiral'] = {
"end_time_ns" : event.end_time_ns, "ifos" : event.ifos,
"mass" : event.mass, "end_time" : event.end_time,
"mchirp" : event.mchirp, "end_time_ns" : event.end_time_ns,
"minimum_duration" : event.minimum_duration, "mass" : event.mass,
"snr" : event.snr, "mchirp" : event.mchirp,
"false_alarm_rate" : event.false_alarm_rate, "minimum_duration" : event.minimum_duration,
"combined_far" : event.combined_far, "snr" : event.snr,
} "false_alarm_rate" : event.false_alarm_rate,
except: "combined_far" : event.combined_far,
pass }
try: except:
# SimInspiralEvent pass
rv['extra_attributes']['SimInspiral'] = { try:
"source_channel": event.source_channel, # SimInspiralEvent
"destination_channel": event.destination_channel, rv['extra_attributes']['SimInspiral'] = {
"mass1": event.mass1, "source_channel": event.source_channel,
"mass2": event.mass2, "destination_channel": event.destination_channel,
"eta": event.eta, "mass1": event.mass1,
"mchirp": event.mchirp, "mass2": event.mass2,
"amp_order": event.amp_order, "eta": event.eta,
"coa_phase": event.coa_phase, "mchirp": event.mchirp,
"spin1y": event.spin1y, "amp_order": event.amp_order,
"spin1x": event.spin1x, "coa_phase": event.coa_phase,
"spin1z": event.spin1z, "spin1y": event.spin1y,
"spin2x": event.spin2x, "spin1x": event.spin1x,
"spin2y": event.spin2y, "spin1z": event.spin1z,
"spin2z": event.spin2z, "spin2x": event.spin2x,
"geocent_end_time": event.geocent_end_time, "spin2y": event.spin2y,
"geocent_end_time_ns": event.geocent_end_time_ns, "spin2z": event.spin2z,
"end_time_gmst": event.end_time_gmst, "geocent_end_time": event.geocent_end_time,
"f_lower": event.f_lower, "geocent_end_time_ns": event.geocent_end_time_ns,
"f_final": event.f_final, "end_time_gmst": event.end_time_gmst,
"distance": event.distance, "f_lower": event.f_lower,
"latitude": event.latitude, "f_final": event.f_final,
"longitude": event.longitude, "distance": event.distance,
"polarization": event.polarization, "latitude": event.latitude,
"inclination": event.inclination, "longitude": event.longitude,
"theta0": event.theta0, "polarization": event.polarization,
"phi0": event.phi0, "inclination": event.inclination,
"waveform": event.waveform, "theta0": event.theta0,
"numrel_mode_min": event.numrel_mode_min, "phi0": event.phi0,
"numrel_mode_max": event.numrel_mode_max, "waveform": event.waveform,
"numrel_data": event.numrel_data, "numrel_mode_min": event.numrel_mode_min,
"source": event.source, "numrel_mode_max": event.numrel_mode_max,
"taper": event.taper, "numrel_data": event.numrel_data,
"bandpass": event.bandpass, "source": event.source,
"alpha": event.alpha, "taper": event.taper,
"beta": event.beta, "bandpass": event.bandpass,
"psi0": event.psi0, "alpha": event.alpha,
"psi3": event.psi3, "beta": event.beta,
"alpha1": event.alpha1, "psi0": event.psi0,
"alpha2": event.alpha2, "psi3": event.psi3,
"alpha3": event.alpha3, "alpha1": event.alpha1,
"alpha4": event.alpha4, "alpha2": event.alpha2,
"alpha5": event.alpha5, "alpha3": event.alpha3,
"alpha6": event.alpha6, "alpha4": event.alpha4,
"g_end_time": event.g_end_time, "alpha5": event.alpha5,
"g_end_time_ns": event.g_end_time_ns, "alpha6": event.alpha6,
"h_end_time": event.h_end_time, "g_end_time": event.g_end_time,
"h_end_time_ns": event.h_end_time_ns, "g_end_time_ns": event.g_end_time_ns,
"l_end_time": event.l_end_time, "h_end_time": event.h_end_time,
"l_end_time_ns": event.l_end_time_ns, "h_end_time_ns": event.h_end_time_ns,
"t_end_time": event.t_end_time, "l_end_time": event.l_end_time,
"t_end_time_ns": event.t_end_time_ns, "l_end_time_ns": event.l_end_time_ns,
"v_end_time": event.v_end_time, "t_end_time": event.t_end_time,
"v_end_time_ns": event.v_end_time_ns, "t_end_time_ns": event.t_end_time_ns,
"eff_dist_g": event.eff_dist_g, "v_end_time": event.v_end_time,
"eff_dist_h": event.eff_dist_h, "v_end_time_ns": event.v_end_time_ns,
"eff_dist_l": event.eff_dist_l, "eff_dist_g": event.eff_dist_g,
"eff_dist_t": event.eff_dist_t, "eff_dist_h": event.eff_dist_h,
"eff_dist_v": event.eff_dist_v, "eff_dist_l": event.eff_dist_l,
} "eff_dist_t": event.eff_dist_t,
except: "eff_dist_v": event.eff_dist_v,
pass }
try: except:
# MultiBurstEvent pass
rv['extra_attributes']['MultiBurst'] = { try:
"ifos" : event.ifos, # MultiBurstEvent
"start_time" : event.start_time, rv['extra_attributes']['MultiBurst'] = {
"start_time_ns" : event.start_time_ns, "ifos" : event.ifos,
"duration" : event.duration, "start_time" : event.start_time,
"peak_time" : event.peak_time, "start_time_ns" : event.start_time_ns,
"peak_time_ns" : event.peak_time_ns, "duration" : event.duration,
"central_freq" : event.central_freq, "peak_time" : event.peak_time,
"bandwidth" : event.bandwidth, "peak_time_ns" : event.peak_time_ns,
"amplitude" : event.amplitude, "central_freq" : event.central_freq,
"snr" : event.snr, "bandwidth" : event.bandwidth,
"confidence" : event.confidence, "amplitude" : event.amplitude,
"false_alarm_rate" : event.false_alarm_rate, "snr" : event.snr,
"ligo_axis_ra" : event.ligo_axis_ra, "confidence" : event.confidence,
"ligo_axis_dec" : event.ligo_axis_dec, "false_alarm_rate" : event.false_alarm_rate,
"ligo_angle" : event.ligo_angle, "ligo_axis_ra" : event.ligo_axis_ra,
"ligo_angle_sig" : event.ligo_angle_sig, "ligo_axis_dec" : event.ligo_axis_dec,
} "ligo_angle" : event.ligo_angle,
except: "ligo_angle_sig" : event.ligo_angle_sig,
pass }
except:
# Finally add extra attributes for any SingleInspiral objects associated with this event pass
# This will be a list of dictionaries.
si_set = event.singleinspiral_set.all() # Finally add extra attributes for any SingleInspiral objects associated with this event
if si_set.count(): # This will be a list of dictionaries.
rv['extra_attributes']['SingleInspiral'] = [ singleInspiralToDict(si) for si in si_set ] si_set = event.singleinspiral_set.all()
if si_set.count():
rv['extra_attributes']['SingleInspiral'] = [ singleInspiralToDict(si) for si in si_set ]
rv['links'] = { rv['links'] = {
"neighbors" : reverse("neighbors", args=[graceid], request=request), "neighbors" : reverse("neighbors", args=[graceid], request=request),
"log" : reverse("eventlog-list", args=[graceid], request=request), "log" : reverse("eventlog-list", args=[graceid], request=request),
"embb" : reverse("embbeventlog-list", args=[graceid], request=request), "emobservations" : reverse("emobservation-list", args=[graceid], request=request),
"files" : reverse("files", args=[graceid], request=request), "files" : reverse("files", args=[graceid], request=request),
"filemeta" : reverse("filemeta", args=[graceid], request=request), "filemeta" : reverse("filemeta", args=[graceid], request=request),
"labels" : reverse("labels", args=[graceid], request=request), "labels" : reverse("labels", args=[graceid], request=request),
......
...@@ -14,7 +14,7 @@ from django.contrib.auth.models import User, Permission ...@@ -14,7 +14,7 @@ from django.contrib.auth.models import User, Permission
from django.contrib.auth.models import Group as AuthGroup from django.contrib.auth.models import Group as AuthGroup
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from permission_utils import filter_events_for_user, user_has_perm from permission_utils import filter_events_for_user, user_has_perm
from permission_utils import internal_user_required from permission_utils import internal_user_required, is_external
from guardian.models import GroupObjectPermission from guardian.models import GroupObjectPermission
from view_logic import _createEventFromForm from view_logic import _createEventFromForm
...@@ -241,6 +241,22 @@ def logentry(request, event, num=None): ...@@ -241,6 +241,22 @@ def logentry(request, event, num=None):
msg = msg + "\n However, the log message itself was saved." msg = msg + "\n However, the log message itself was saved."
return HttpResponse(msg) return HttpResponse(msg)
# XXX If the user is external, tag the message appropriately.
if is_external(request.user):
try:
tag = Tag.objects.get(name=settings.EXTERNAL_ACCESS_TAGNAME)
except:
displayName = request.POST.get('displayName')
tag = Tag(name=tagname, displayName=displayName)
tag.save()
# I'm putting this in a try/except in case the user has already
# added the external access tagname somehow, and the following
# would result in an IntegrityError
try:
tag.eventlogs.add(elog)
except:
pass
elif request.method == "GET": elif request.method == "GET":
if not user_has_perm(request.user, 'view', event): if not user_has_perm(request.user, 'view', event):
return HttpResponseForbidden("Forbidden") return HttpResponseForbidden("Forbidden")
...@@ -248,6 +264,13 @@ def logentry(request, event, num=None): ...@@ -248,6 +264,13 @@ def logentry(request, event, num=None):
elog = event.eventlog_set.filter(N=num)[0] elog = event.eventlog_set.filter(N=num)[0]
except Exception, e: except Exception, e:
raise Http404 raise Http404
# Check authorization for this log message
if is_external(request.user):
tagnames = [t.name for t in elog.tag_set.all()]
if settings.EXTERNAL_ACCESS_TAGNAME not in tagnames:
msg = "You do not have permission to view this log message."
return HttpResponseForbidden(msg)
else: else:
return HttpResponseBadRequest return HttpResponseBadRequest
...@@ -313,16 +336,15 @@ def view(request, event): ...@@ -313,16 +336,15 @@ def view(request, event):
can_expose_to_lvem, can_protect_from_lvem = get_lvem_perm_status(request,event) can_expose_to_lvem, can_protect_from_lvem = get_lvem_perm_status(request,event)
context['can_expose_to_lvem'] = can_expose_to_lvem context['can_expose_to_lvem'] = can_expose_to_lvem
context['can_protect_from_lvem'] = can_protect_from_lvem context['can_protect_from_lvem'] = can_protect_from_lvem
lvem_group_name = '' context['lvem_group_name'] = settings.LVEM_GROUP
try:
lvem_group_name = AuthGroup.objects.get(name__contains='LV-EM').name
except:
pass
context['lvem_group_name'] = lvem_group_name
if event.pipeline.name in settings.GRB_PIPELINES: if event.pipeline.name in settings.GRB_PIPELINES:
context['can_modify_t90'] = request.user.has_perm('gracedb.t90_grbevent') context['can_modify_t90'] = request.user.has_perm('gracedb.t90_grbevent')
# 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)
# Does the user have permission to sign off on the event? # Does the user have permission to sign off on the event?
signoff_authorized = False signoff_authorized = False
# XXX Note that this may not be the best way to perform the authorization check. # XXX Note that this may not be the best way to perform the authorization check.
...@@ -609,6 +631,11 @@ def taglogentry(request, event, num, tagname): ...@@ -609,6 +631,11 @@ def taglogentry(request, event, num, tagname):
msg = "Log already has tag %s" % tagname msg = "Log already has tag %s" % tagname
return HttpResponse(msg, content_type="text") return HttpResponse(msg, content_type="text")
except: except:
# Check authorization
if is_external(request.user) and tagname == settings.EXTERNAL_ACCESS_TAGNAME:
msg = "You do not have permission to add or remove this tag."
return HttpResponseForbidden(msg)
# Look for the tag. If it doesn't already exist, create it. # Look for the tag. If it doesn't already exist, create it.
try: try:
tag = Tag.objects.filter(name=tagname)[0] tag = Tag.objects.filter(name=tagname)[0]
...@@ -686,9 +713,24 @@ def performance(request): ...@@ -686,9 +713,24 @@ def performance(request):
@event_and_auth_required @event_and_auth_required
def file_list(request, event): def file_list(request, event):
f = [] f = []
for dirname, dirnames, filenames in os.walk(event.datadir()): if is_external(request.user):
f.extend(filenames) # Construct the file list, filtering as necessary:
break for l in event.eventlog_set.all():
filename = l.filename
if len(filename):
version = l.file_version
tagnames = [t.name for t in l.tag_set.all()]
if settings.EXTERNAL_ACCESS_TAGNAME not in tagnames:
continue
if version>=0:
f.append(filename + ',' + str(version))
# We only want the unadorned filename once.
if filename not in f:
f.append(filename)
else:
for dirname, dirnames, filenames in os.walk(event.datadir()):
f.extend(filenames)
break
context = {} context = {}
context['file_list'] = f context['file_list'] = f
......
...@@ -47,6 +47,12 @@ EMBB_IGNORE_ADDRESSES = ['Mailer-Daemon@gracedb.phys.uwm.edu',] ...@@ -47,6 +47,12 @@ EMBB_IGNORE_ADDRESSES = ['Mailer-Daemon@gracedb.phys.uwm.edu',]
# Added for django 1.7.8 # Added for django 1.7.8
TEST_RUNNER = 'django.test.runner.DiscoverRunner' TEST_RUNNER = 'django.test.runner.DiscoverRunner'
# Some proper names related to authorization
LVC_GROUP = 'Communities:LSCVirgoLIGOGroupMembers'
LVEM_GROUP = 'gw-astronomy:LV-EM'
EXEC_GROUP = 'executives'
EXTERNAL_ACCESS_TAGNAME = 'lvem'
# 11/18/14. No longer checking XMPP_ALERT_CHANNELS. This is not necessary. # 11/18/14. No longer checking XMPP_ALERT_CHANNELS. This is not necessary.
# If someone sends out an event, an alert should go out. Listerers have the # If someone sends out an event, an alert should go out. Listerers have the
# option to unsubscribe from nodes if so desired. # option to unsubscribe from nodes if so desired.
......
...@@ -161,12 +161,14 @@ ...@@ -161,12 +161,14 @@
{% endblock %} {% endblock %}
</div> </div>
{% if not user_is_external %}
<div class="content-area"> <div class="content-area">
{# Analysis-specific attributes #} {# Analysis-specific attributes #}
{% block analysis_specific %} {% block analysis_specific %}
{# This block is empty in the base event_detail template #} {# This block is empty in the base event_detail template #}
{% endblock %} {% endblock %}
</div> </div>
{% endif %}
{# Neighbors #} {# Neighbors #}
<script type="text/javascript"> <script type="text/javascript">
......
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