diff --git a/config/settings/base.py b/config/settings/base.py index 55d2b3e61027b57b95e1d048e609fb50e34091c0..a2b76f94e944d33dc6f02349d09c1bdd54d6c378 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -301,7 +301,7 @@ INSTALLED_APPS = [ 'django.contrib.messages', 'maintenance_mode', 'alerts', - 'api' + 'api', 'events', 'ligoauth', 'search', @@ -332,6 +332,11 @@ SHELL_PLUS_MODEL_ALIASES = { # Details used by REST API REST_FRAMEWORK = { + 'DEFAULT_VERSIONING_CLASS': + 'api.versioning.NestedNamespaceVersioning', + #'rest_framework.versioning.NamespaceVersioning', + 'DEFAULT_VERSION': 'default', + 'ALLOWED_VERSIONS': ['default', 'v1'], 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', 'PAGE_SIZE': 1e7, @@ -340,11 +345,11 @@ REST_FRAMEWORK = { 'annotation' : '10/second', }, 'DEFAULT_AUTHENTICATION_CLASSES': ( - 'events.api.backends.LigoAuthentication', + 'api.v1.backends.LigoAuthentication', ), 'COERCE_DECIMAL_TO_STRING': False, 'EXCEPTION_HANDLER': - 'superevents.api.exceptions.gracedb_exception_handler', + 'api.exceptions.gracedb_exception_handler', 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticatedOrReadOnly', ) @@ -530,6 +535,11 @@ LOGGING = { 'propagate': True, 'level': LOG_LEVEL, }, + 'api': { + 'handlers': ['debug_file','error_file'], + 'propagate': True, + 'level': LOG_LEVEL, + }, 'alerts': { 'handlers': ['debug_file','error_file'], 'propagate': True, diff --git a/config/urls.py b/config/urls.py index 4ea8f2ff0ddb5f990d87ba2fa98d99b90bb365f9..cbcc91d610aedc79fb7361b100b30ddc71016f83 100644 --- a/config/urls.py +++ b/config/urls.py @@ -42,12 +42,10 @@ urlpatterns = [ url(r'^search/$', search.views.search, name="mainsearch"), # API URLs - url(r'^apibasic/', include('events.api.urls', app_name="api", - namespace="basic")), - url(r'^apiweb/', include('events.api.urls', app_name="api", - namespace="shib")), - url(r'^api/', include('events.api.urls', app_name="api", - namespace="x509")), + url(r'^apibasic/', include('api.urls', namespace="basic")), + url(r'^apiweb/', include('api.urls', namespace="shib")), + url(r'^api/', include('api.urls', namespace="x509")), + #url(r'^apinew/', include('api.urls')), # one place for all auth schemes # Uncomment the admin/doc line below and add 'django.contrib.admindocs' # to INSTALLED_APPS to enable admin documentation: diff --git a/gracedb/alerts/superevent_utils.py b/gracedb/alerts/superevent_utils.py index 3050afcdee0b6c7399898e64ea3f35bc1b1a1bdc..9579a420da6f11fe926e0b8512ed7ba52e0b10ea 100644 --- a/gracedb/alerts/superevent_utils.py +++ b/gracedb/alerts/superevent_utils.py @@ -3,7 +3,7 @@ from rest_framework.renderers import JSONRenderer from .main import issue_alerts from core.urls import build_absolute_uri -from superevents.api.serializers import SupereventSerializer, \ +from api.v1.superevents.serializers import SupereventSerializer, \ SupereventLogSerializer, SupereventLabelSerializer, \ SupereventEMObservationSerializer, SupereventVOEventSerializer, \ SupereventSignoffSerializer diff --git a/gracedb/superevents/api/exceptions.py b/gracedb/api/exceptions.py similarity index 100% rename from gracedb/superevents/api/exceptions.py rename to gracedb/api/exceptions.py diff --git a/gracedb/api/urls.py b/gracedb/api/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..6e8f80038d348ef8e546fb287d4288b2768b8aa8 --- /dev/null +++ b/gracedb/api/urls.py @@ -0,0 +1,9 @@ +from django.conf.urls import url, include + +app_name = 'api' + +urlpatterns = [ + url(r'^', include('api.v1.urls', namespace='default')), + url(r'^v1/', include('api.v1.urls', namespace='v1')), + #url(r'^v2/', include('api.v2.urls', namespace='v2')), +] diff --git a/gracedb/api/utils.py b/gracedb/api/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..129bec5252e70acdbb25fe49116a508b8b2c604b --- /dev/null +++ b/gracedb/api/utils.py @@ -0,0 +1,86 @@ +import logging + +from django.urls import resolve +from rest_framework.settings import api_settings +from rest_framework.reverse import reverse as drf_reverse + +from core.urls import build_absolute_uri + +# Set up logger +logger = logging.getLogger(__name__) + +# some default values +AUTH_NAMESPACES = ['api', 'x509', 'shib', 'basic'] +DEFAULT_AUTH_NAMESPACE = 'api' + + +def api_reverse(viewname, args=None, kwargs=None, request=None, format=None, + **extra): + """ + Reverse which handles different API auth schemes and versions. If a + request is provided, we want to send back URLs which use the same + auth type and version as the user was using. If not, we send back + the "default" auth scheme (currently 'x509') and version ('default'). + + Standard usage: + api_reverse('events:event-list', request=request) + api_reverse('events:event-list') + + Not sure if we would ever *want* to specify the auth and version + namespaces manually when a request is not provided, but if so, we + can. The following are OK, too: + api_reverse('default:events:event-list') + api_reverse('v1:events:event-list') + api_reverse('api:default:events:event-list') + api_reverse('api:v1:events:event-list') + api_reverse('x509:default:events:event-list') + api_reverse('x509:v1:events:event-list') + """ + namespaces = [] + if request: + resolver_match = resolve(request.path) + + # We have to be careful here because this function is sometimes used + # for requests whose path is not in the API. I.e., when web views + # try to serialize stuff (like EventLogToDict). The 'else' statement + # handles that case + if resolver_match.namespaces: + # We only add the *first* namespace because it specifies the auth + # namespace. The version namespace will be handled by the + # versioning class in this case. + namespaces.append(resolver_match.namespaces[0]) + else: + namespaces.append(DEFAULT_AUTH_NAMESPACE) + namespaces.append(api_settings.DEFAULT_VERSION) + else: + # Otherwise, we check the viewname and add in the auth and version + # namespaces as needed. Note that we have to add version namespaces (if + # the code doesn't specify them) because there is no request, so + # drf_reverse won't trigger the versioning class. + + # Split provided viewname to determine possible namespaces that are + # already included + possible_namespaces = viewname.split(':')[:-1] + + # Check if any auth namespaces were provided already; if not, + # set to default using app_name + if not any([v in possible_namespaces for v in AUTH_NAMESPACES]): + namespaces.append(DEFAULT_AUTH_NAMESPACE) + + # Check if any version namespaces were provided already; if not, + # set to default + if not any([v in possible_namespaces for v in + api_settings.ALLOWED_VERSIONS]): + namespaces.append(api_settings.DEFAULT_VERSION) + + # Join namespaces to viewname + viewname = ':'.join(namespaces + [viewname]) + + # Use rest_framework reverse to get url + url = drf_reverse(viewname, args, kwargs, request, format, **extra) + + # Use sites to build absolute url if request is not available + if request is None: + url = build_absolute_uri(url) + + return url diff --git a/gracedb/events/api/backends.py b/gracedb/api/v1/backends.py similarity index 100% rename from gracedb/events/api/backends.py rename to gracedb/api/v1/backends.py diff --git a/gracedb/events/api/fields.py b/gracedb/api/v1/events/fields.py similarity index 94% rename from gracedb/events/api/fields.py rename to gracedb/api/v1/events/fields.py index c1a3d0e39ce73f8db27102641dbc322481ffbbe5..9129160fa48c1376da2fb74965c245bd90cab622 100644 --- a/gracedb/events/api/fields.py +++ b/gracedb/api/v1/events/fields.py @@ -1,13 +1,19 @@ -from rest_framework import serializers +from __future__ import absolute_import +import logging + from django.contrib.auth import get_user_model -from ..models import Event +from rest_framework import serializers +from events.models import Event + +# Set up user model UserModel = get_user_model() -import logging +# Set up logger logger = logging.getLogger(__name__) + class GenericField(serializers.Field): # Field, property, or callable of the object which will be used to # generate the representation of the object. diff --git a/gracedb/events/api/__init__.py b/gracedb/api/v1/events/tests/__init__.py similarity index 100% rename from gracedb/events/api/__init__.py rename to gracedb/api/v1/events/tests/__init__.py diff --git a/gracedb/events/api/tests/mixins.py b/gracedb/api/v1/events/tests/mixins.py similarity index 100% rename from gracedb/events/api/tests/mixins.py rename to gracedb/api/v1/events/tests/mixins.py diff --git a/gracedb/events/api/throttles.py b/gracedb/api/v1/events/throttles.py similarity index 100% rename from gracedb/events/api/throttles.py rename to gracedb/api/v1/events/throttles.py diff --git a/gracedb/api/v1/events/urls.py b/gracedb/api/v1/events/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..e942dae6f68a70353dc36a55f8cb26dbc24cbfe5 --- /dev/null +++ b/gracedb/api/v1/events/urls.py @@ -0,0 +1,79 @@ +from django.conf.urls import url, include + +from .views import * + + +urlpatterns = [ + # Event Resources + # events/[{graceid}[/{version}]] + url(r'^$', EventList.as_view(), name='event-list'), + url(r'^(?P<graceid>[GEHMT]\d+)$', EventDetail.as_view(), + name='event-detail'), + + # Event Log Resources + # events/{graceid}/logs/[{logid}] + url(r'^(?P<graceid>[GEHMT]\d+)/log/$', EventLogList.as_view(), + name='eventlog-list'), + url(r'^(?P<graceid>[GEHMT]\d+)/log/(?P<n>\d+)$', + EventLogDetail.as_view(), name='eventlog-detail'), + + # VOEvent Resources + # events/{graceid}/voevent/[{serial_number}] + url(r'^(?P<graceid>[GEHMT]\d+)/voevent/$', VOEventList.as_view(), + name='voevent-list'), + url(r'^(?P<graceid>[GEHMT]\d+)/voevent/(?P<n>\d+)$', + VOEventDetail.as_view(), name='voevent-detail'), + + # EMBB Resources + # events/{graceid}/logs/[{logid}] + url(r'^(?P<graceid>[GEHMT]\d+)/embb/$', EMBBEventLogList.as_view(), + name='embbeventlog-list'), + url(r'^(?P<graceid>[GEHMT]\d+)/embb/(?P<n>\d+)$', + EMBBEventLogDetail.as_view(), name='embbeventlog-detail'), + url(r'^(?P<graceid>[GEHMT]\d+)/emobservation/$', + EMObservationList.as_view(), name='emobservation-list'), + url(r'^(?P<graceid>[GEHMT]\d+)/emobservation/(?P<n>\d+)$', + EMObservationDetail.as_view(), name='emobservation-detail'), +# url(r'(?P<graceid>[GEHMT]\d+)/emobservation/(?P<n>\d+)/emfootprint/$', +# EMFootprintList.as_view(), name='emfootprint-list'), +# url(r'(?P<graceid>[GEHMT]\d+)/emobservation/(?P<n>\d+)/emfootprint/(?P<m>\d+)$', +# EMFootprintDetail.as_view(), name='emfootprint-detail'), + + # Tag Resources + url(r'^(?P<graceid>[GEHMT]\d+)/tag/$', EventTagList.as_view(), + name='eventtag-list'), + url(r'^(?P<graceid>[GEHMT]\d+)/tag/(?P<tagname>.+)$', + EventTagDetail.as_view(), name='eventtag-detail'), + url(r'^(?P<graceid>[GEHMT]\d+)/log/(?P<n>\d+)/tag/$', + EventLogTagList.as_view(), name='eventlogtag-list'), + url(r'^(?P<graceid>[GEHMT]\d+)/log/(?P<n>\d+)/tag/(?P<tagname>.+)$', + EventLogTagDetail.as_view(), name='eventlogtag-detail'), + + # Permission Resources + url(r'^(?P<graceid>[GEHMT]\d+)/perms/$', + EventPermissionList.as_view(), name='eventpermission-list'), + url(r'^(?P<graceid>[GEHMT]\d+)/perms/(?P<group_name>.+)/$', + GroupEventPermissionList.as_view(), name='groupeventpermission-list'), + url(r'^(?P<graceid>[GEHMT]\d+)/perms/(?P<group_name>.+)/(?P<perm_shortname>\w+)$', + GroupEventPermissionDetail.as_view(), name='groupeventpermission-detail'), + + # Event File Resources + # events/{graceid}/files/[{filename}[/{version}]] + url(r'^(?P<graceid>\w[\d]+)/files/(?P<filename>.+)?$', + Files.as_view(), name="files"), + + # Event Labels + # events/{graceid}/labels/[{label}] + url(r'^(?P<graceid>\w[\d]+)/labels/(?P<label>.+)?$', + EventLabel.as_view(), name="labels"), + + # Event Neighbors + # events/{graceid}/neighbors/[?delta=(N|(N,N))] + url(r'^(?P<graceid>\w[\d]+)/neighbors/$', EventNeighbors.as_view(), + name="neighbors"), + + # Operator Signoff Resources + url(r'^(?P<graceid>[GEHMT]\d+)/signoff/$', + OperatorSignoffList.as_view(), name='signoff-list'), + +] diff --git a/gracedb/events/api/views.py b/gracedb/api/v1/events/views.py similarity index 87% rename from gracedb/events/api/views.py rename to gracedb/api/v1/events/views.py index d82b26b5367d50b9e0e8848a500cfa1e27937c64..61850f7680c379b04b26989bd44badb1917a4163 100644 --- a/gracedb/events/api/views.py +++ b/gracedb/api/v1/events/views.py @@ -1,93 +1,68 @@ - -from django.http import HttpResponse, HttpResponseNotFound -from django.http import HttpResponseForbidden, HttpResponseServerError -from django.http.request import QueryDict -from django.urls import reverse as django_reverse +from __future__ import absolute_import +import exceptions +import json +import logging +import os +import shutil +import StringIO +import urllib from django.conf import settings -from django.utils.functional import wraps -from django.db import IntegrityError +from django.contrib.auth.models import User, Permission, Group as AuthGroup +from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError +from django.db import IntegrityError +from django.http import HttpResponse, HttpResponseForbidden, \ + HttpResponseNotFound, HttpResponseServerError +from django.http.request import QueryDict +from django.utils.functional import wraps -from django.contrib.auth.models import User, Permission -from django.contrib.auth.models import Group as AuthGroup -from django.contrib.contenttypes.models import ContentType +# Stuff for the LigoLwRenderer +from glue.ligolw import ligolw +# lsctables MUST be loaded before utils. +from glue.ligolw import utils +from glue.ligolw.utils import ligolw_add +from glue.ligolw.ligolw import LIGOLWContentHandler +from glue.ligolw.lsctables import use_in +from guardian.models import GroupObjectPermission +from rest_framework import authentication, parsers, serializers, status +from rest_framework.permissions import IsAuthenticated, BasePermission, SAFE_METHODS +from rest_framework.renderers import BaseRenderer, JSONRenderer, \ + BrowsableAPIRenderer +from rest_framework.response import Response +from rest_framework.views import APIView from alerts.old_alert import issueAlertForUpdate -from ..buildVOEvent import buildVOEvent, VOEventBuilderException -from ..view_utils import BadFARRange, check_query_far_range -from ..query import parseQuery, ParseException -from ..models import Event, Group, Search, Pipeline, EventLog, Tag, Label, \ - EMGroup, EMBBEventLog, EMSPECTRUM, VOEvent -from ..view_logic import create_label, get_performance_info, delete_label, \ - _createEventFromForm, create_eel, create_emobservation -from ..view_utils import eventToDict, eventLogToDict, labelToDict, reverse, \ - embbEventLogToDict, voeventToDict, emObservationToDict, signoffToDict, \ - skymapViewerEMObservationToDict -from ..forms import SimpleSearchForm -from ..translator import handle_uploaded_data -from ..forms import CreateEventForm -from ..permission_utils import user_has_perm, filter_events_for_user, \ - is_external, check_external_file_access - -from .backends import LigoAuthentication -from .throttles import EventCreationThrottle, AnnotationThrottle - -from core.vfile import VersionedFile from core.http import check_and_serve_file - -from guardian.models import GroupObjectPermission - +from core.vfile import VersionedFile +from events.buildVOEvent import buildVOEvent, VOEventBuilderException +from events.forms import SimpleSearchForm, CreateEventForm +from events.query import parseQuery, ParseException +from events.models import Event, Group, Search, Pipeline, EventLog, Tag, \ + Label, EMGroup, EMBBEventLog, EMSPECTRUM, VOEvent +from events.permission_utils import user_has_perm, filter_events_for_user, \ + is_external, check_external_file_access +from events.translator import handle_uploaded_data +from events.view_logic import create_label, get_performance_info, \ + delete_label, _createEventFromForm, create_eel, create_emobservation +from events.view_utils import eventToDict, eventLogToDict, labelToDict, \ + embbEventLogToDict, voeventToDict, emObservationToDict, signoffToDict, \ + skymapViewerEMObservationToDict, BadFARRange, check_query_far_range from superevents.models import Superevent -from superevents.api.view_templates import construct_api_url_templates - -import os -import urllib -import shutil -import exceptions -import json - +from .throttles import EventCreationThrottle, AnnotationThrottle +from ..backends import LigoAuthentication +from ...utils import api_reverse -import logging; logger = logging.getLogger(__name__) -# -# for checking queries in the evnet that the user is external -# +# Set up logger +logger = logging.getLogger(__name__) -################################################################## +# Set up content handler +use_in(LIGOLWContentHandler) +# For checking queries in the event that the user is external REST_FRAMEWORK_SETTINGS = getattr(settings, 'REST_FRAMEWORK', {}) PAGINATE_BY = REST_FRAMEWORK_SETTINGS.get('PAGINATE_BY', 10) -################################################################## -# rest_framework -from rest_framework import serializers, status -from rest_framework.response import Response -#from rest_framework.renderers import JSONRenderer, JSONPRenderer -#from rest_framework.renderers import YAMLRenderer, XMLRenderer -from rest_framework.renderers import BaseRenderer, JSONRenderer -from rest_framework.renderers import BrowsableAPIRenderer -from rest_framework import parsers # YAMLParser, MultiPartParser -from rest_framework.parsers import DataAndFiles - -from rest_framework.permissions import IsAuthenticated, BasePermission, SAFE_METHODS -from rest_framework import authentication -from rest_framework.views import APIView - -MAX_FAILED_OPEN_ATTEMPTS = 5 - - - -################################################################## -# Stuff for the LigoLwRenderer -from glue.ligolw import ligolw -# lsctables MUST be loaded before utils. -from glue.ligolw import utils -from glue.ligolw.utils import ligolw_add -from glue.ligolw.ligolw import LIGOLWContentHandler -from glue.ligolw.lsctables import use_in -import StringIO - -use_in(LIGOLWContentHandler) # # A custom permission class for the EventDetail view. @@ -426,7 +401,7 @@ class EventList(APIView): rv['links'] = links rv['events'] = [eventToDict(e, request=request) for e in events[start:start+count]] - baseuri = reverse('event-list', request=request) + baseuri = api_reverse('events:event-list', request=request) links['self'] = request.build_absolute_uri() @@ -506,8 +481,8 @@ class EventList(APIView): rv.update(eventToDict(event, request=request)) rv['warnings'] += warnings response = Response(rv, status=status.HTTP_201_CREATED) - response["Location"] = reverse( - 'event-detail', + response["Location"] = api_reverse( + 'events:event-detail', args=[event.graceid()], request=request) return response @@ -531,7 +506,7 @@ class RawdataParser(parsers.BaseParser): self.read = read files = { 'upload' : FakeFile("initial.data", stream.read) } data = {} - return DataAndFiles(data, files) + return parsers.DataAndFiles(data, files) class LigoLwParser(parsers.MultiPartParser): # XXX Revisit this. @@ -678,7 +653,8 @@ class EventNeighbors(APIView): 'numRows' : len(neighbors), 'links' : { 'self': request.build_absolute_uri(), - 'event': reverse("event-detail", args=[event.graceid()], request=request), + 'event': api_reverse("events:event-detail", + args=[event.graceid()], request=request), } }) @@ -707,7 +683,7 @@ class EventLabel(APIView): return Response({ 'links' : [{ 'self': request.build_absolute_uri(), - 'event': reverse("event-detail", + 'event': api_reverse("events:event-detail", args=[event.graceid()], request=request), }], @@ -1066,18 +1042,18 @@ def tagToDict(tag, columns=None, request=None, event=None, n=None): if n: # We want a link to the self only. End of the line. rv['links'] = { - "self" : reverse("eventlogtag-detail", + "self" : api_reverse("events:eventlogtag-detail", args=[event.graceid(),n,tag.name], request=request) } else: # Links to all log messages of the event with this tag. rv['links'] = { - "logs" : [reverse("eventlog-detail", + "logs" : [api_reverse("events:eventlog-detail", args=[event.graceid(),log.N], request=request) for log in event.getLogsForTag(tag.name)], - "self" : reverse("eventtag-detail", + "self" : api_reverse("events:eventtag-detail", args=[event.graceid(),tag.name], request=request) } @@ -1096,30 +1072,6 @@ def tagToDict(tag, columns=None, request=None, event=None, n=None): # } return rv -class TagList(APIView): - """Tag List Resource - """ - authentication_classes = (LigoAuthentication,) - permission_classes = (IsAuthenticated,) - - def get(self, request): - # Return a list of links to all tag objects. - tag_dict = {} - for tag in Tag.objects.all(): - tag_dict[tag.name] = { - 'displayName': tag.displayName, - 'blessed': tag.name in settings.BLESSED_TAGS - } - rv = { -# 'tags' : [ reverse("tag-detail", args=[tag.name], -# request=request) -# for tag in Tag.objects.all() ] -# For now, we just output the tag names, since we don't know what -# tag-detail should look like. -# 'tags' : [ tag.name for tag in Tag.objects.all() ] - 'tags' : tag_dict, - } - return Response(rv) # XXX Unclear what the tag detail resource should be. # class TagDetail(APIView): @@ -1151,8 +1103,8 @@ class EventTagList(APIView): rv = { 'tags' : [ { - 'self': reverse("eventtag-detail", args=[ - event.graceid(), tag.name], request=request), + 'self': api_reverse("events:eventtag-detail", + args=[event.graceid(), tag.name], request=request), 'name': tag.name, 'displayName': tag.displayName } @@ -1189,8 +1141,8 @@ class EventLogTagList(APIView): rv = { 'tags' : [ { - 'self': reverse("eventlogtag-detail", args=[ - event.graceid(), eventlog.N, tag.name], + 'self': api_reverse("events:eventlogtag-detail", + args=[event.graceid(), eventlog.N, tag.name], request=request), 'name': tag.name, 'displayName': tag.displayName @@ -1314,7 +1266,7 @@ def groupeventpermissionToDict(gop, event, request=None): rv['permission'] = perm_shortname # We want a link to the self only. End of the line. rv['links'] = { - "self" : reverse("groupeventpermission-detail", + "self" : api_reverse("events:groupeventpermission-detail", args=[event.graceid(),gop.group.name,perm_shortname], request=request) } @@ -1342,7 +1294,7 @@ class EventPermissionList(APIView): out_dict = {} links['groupeventpermissions'] = out_dict for group in groups: - out_dict[group.name] = reverse("groupeventpermission-list", + out_dict[group.name] = api_reverse("events:groupeventpermission-list", args=[event.graceid(),group.name], request=request) return Response(rv, status=status.HTTP_200_OK) @@ -1501,105 +1453,6 @@ class GroupEventPermissionDetail(APIView): rv = {'message': 'Permission successfully deleted.'} return Response(rv, status=status.HTTP_200_OK) -#================================================================== -# Root Resource - -class GracedbRoot(APIView): - """ - Root of the Gracedb REST API - """ - authentication_classes = (LigoAuthentication,) - permission_classes = (IsAuthenticated,) - parser_classes = () - def get(self, request): - # XXX This seems like a scummy way to get a URI template. - # Is there better? - detail = reverse("event-detail", args=["G1200"], request=request) - detail = detail.replace("G1200", "{graceid}") - log = reverse("eventlog-list", args=["G1200"], request=request) - log = log.replace("G1200", "{graceid}") - log_detail = reverse("eventlog-detail", args=["G1200", "3333"], - request=request) - log_detail = log_detail.replace("G1200", "{graceid}") - log_detail = log_detail.replace("3333", "{N}") - voevent = reverse("voevent-list", args=["G1200"], request=request) - voevent = voevent.replace("G1200", "{graceid}") - voevent_detail = reverse("voevent-detail", args=["G1200", "3333"], - request=request) - voevent_detail = voevent_detail.replace("G1200", "{graceid}") - voevent_detail = voevent_detail.replace("3333", "{N}") - embb = reverse("embbeventlog-list", args=["G1200"], request=request) - embb = embb.replace("G1200", "{graceid}") - emo = reverse("emobservation-list", args=["G1200"], request=request) - emo = emo.replace("G1200", "{graceid}") - emo_detail = reverse("emobservation-detail", args=["G1200", "3333"], - request=request) - emo_detail= emo_detail.replace("G1200", "{graceid}") - emo_detail= emo_detail.replace("3333", "{N}") - - files = reverse("files", args=["G1200", "filename"], request=request) - files = files.replace("G1200", "{graceid}") - files = files.replace("filename", "{filename}") - - labels = reverse('labels', args=["G1200", "thelabel"], request=request) - labels = labels.replace("G1200", "{graceid}") - labels = labels.replace("thelabel", "{label}") - - taglist = reverse("eventlogtag-list", args=["G1200", "0"], request=request) - taglist = taglist.replace("G1200", "{graceid}") - taglist = taglist.replace("0", "{N}") - - tag = reverse("eventlogtag-detail", args=["G1200", "0", "tagname"], request=request) - tag = tag.replace("G1200", "{graceid}") - tag = tag.replace("0", "{N}") - tag = tag.replace("tagname", "{tag_name}") - - signofflist = reverse("signoff-list", args=["G1200"], request=request) - signofflist = signofflist.replace("G1200", "{graceid}") - - # XXX Need a template for the tag list? - - templates = { - "event-detail-template" : detail, - "voevent-list-template" : voevent, - "voevent-detail-template" : voevent_detail, - "event-log-template" : log, - "event-log-detail-template" : log_detail, - "emobservation-list-template": emo, - "emobservation-detail-template": emo_detail, - "embb-event-log-template" : embb, - "event-label-template" : labels, - "files-template" : files, - "tag-template" : tag, - "taglist-template" : taglist, - "signoff-list-template": signofflist, - } - - # Get superevent templates - superevent_templates = construct_api_url_templates(request) - templates.update(superevent_templates) - - return Response({ - "links" : { - "superevents" : reverse("superevents:superevent-list", - request=request), - "events" : reverse("event-list", request=request), - "self" : reverse("api-root", request=request), - "performance" : reverse("performance-info", request=request), - }, - "templates" : templates, - "groups" : [group.name for group in Group.objects.all()], - "pipelines" : [pipeline.name for pipeline in Pipeline.objects.all()], - "searches" : [search.name for search in Search.objects.all()], - "labels" : [label.name for label in Label.objects.all()], - "em-groups" : [g.name for g in EMGroup.objects.all()], - "wavebands" : dict(EMSPECTRUM), - "eel-statuses" : dict(EMBBEventLog.EEL_STATUS_CHOICES), - "obs-statuses" : dict(EMBBEventLog.OBS_STATUS_CHOICES), - "superevent-categories": dict(Superevent.SUPEREVENT_CATEGORY_CHOICES), - "voevent-types" : dict(VOEvent.VOEVENT_TYPE_CHOICES), - }) - class Files(APIView): """Files Resource""" @@ -1659,10 +1512,10 @@ class Files(APIView): files = [] for filename in fnames: - rv[filename] = reverse("files", args=[graceid, filename], request=request) + rv[filename] = api_reverse("events:files", args=[graceid, filename], request=request) files.append({ 'name' : filename, - 'link' : reverse("files", + 'link' : api_reverse("events:files", args=[graceid, filename], request=request), }) @@ -1691,8 +1544,8 @@ class Files(APIView): # XXX this seems wobbly. longname = fdest.name shortname = longname[longname.rfind(filename):] - rv['permalink'] = reverse( - "files", args=[event.graceid(), shortname], request=request) + rv['permalink'] = api_reverse( + "events:files", args=[event.graceid(), shortname], request=request) response = Response(rv, status=status.HTTP_201_CREATED) except Exception, e: # XXX This needs some thought. @@ -1731,35 +1584,6 @@ class Files(APIView): return response -class PerformanceInfo(APIView): - """ - Serialized performance information - """ - authentication_classes = (LigoAuthentication,) - permission_classes = (IsAuthenticated,) - parser_classes = (parsers.MultiPartParser,) - - def get(self, request, *args, **kwargs): - user_groups = set(request.user.groups.all()) - allowed_groups = set([]) - try: - allowed_groups = set([ - AuthGroup.objects.get(name=settings.LVC_GROUP), - AuthGroup.objects.get(name=settings.EXEC_GROUP), - ]) - except: - pass - - if not user_groups & allowed_groups: - return HttpResponseForbidden("Forbidden") - - try: - performance_info = get_performance_info() - except Exception, e: - return Response(str(e), status=status.HTTP_500_INTERNAL_SERVER_ERROR) - - return Response(performance_info,status=status.HTTP_200_OK) - #================================================================== # VOEvent Resources diff --git a/gracedb/superevents/api/fields.py b/gracedb/api/v1/fields.py similarity index 99% rename from gracedb/superevents/api/fields.py rename to gracedb/api/v1/fields.py index 5f77531a7b75c1341401e47e0f8b446c28c15e54..fb378b95878dc2058e2b66e33e73036a351681aa 100644 --- a/gracedb/superevents/api/fields.py +++ b/gracedb/api/v1/fields.py @@ -1,7 +1,9 @@ +import logging +import six + from rest_framework import fields -import six -import logging +# Set up logger logger = logging.getLogger(__name__) diff --git a/gracedb/events/api/tests/__init__.py b/gracedb/api/v1/main/__init__.py similarity index 100% rename from gracedb/events/api/tests/__init__.py rename to gracedb/api/v1/main/__init__.py diff --git a/gracedb/api/v1/main/views.py b/gracedb/api/v1/main/views.py new file mode 100644 index 0000000000000000000000000000000000000000..2a5a54ab6336c9bfc1db242579e7ff716309cf85 --- /dev/null +++ b/gracedb/api/v1/main/views.py @@ -0,0 +1,170 @@ +# Needed because our local events and superevents modules (for the API) +# shadow the names of the events and superevents apps. +from __future__ import absolute_import + +from django.conf import settings +from django.contrib.auth.models import Group as AuthGroup +from django.http import HttpResponse, HttpResponseForbidden + +from rest_framework import parsers, status +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework.reverse import reverse as drf_reverse +from rest_framework.views import APIView + +from api.utils import api_reverse +from events.models import Group, Pipeline, Search, Tag, Label, EMGroup, \ + VOEvent, EMBBEventLog, EMSPECTRUM +from events.view_logic import get_performance_info +from superevents.models import Superevent +from ..backends import LigoAuthentication +from ..superevents.url_templates import construct_url_templates + + +class TagList(APIView): + """Tag List Resource + """ + authentication_classes = (LigoAuthentication,) + permission_classes = (IsAuthenticated,) + + def get(self, request): + # Return a list of links to all tag objects. + tag_dict = {} + for tag in Tag.objects.all(): + tag_dict[tag.name] = { + 'displayName': tag.displayName, + 'blessed': tag.name in settings.BLESSED_TAGS + } + rv = {'tags' : tag_dict} + return Response(rv) + + +class GracedbRoot(APIView): + """ + Root of the Gracedb REST API + """ + authentication_classes = (LigoAuthentication,) + permission_classes = (IsAuthenticated,) + parser_classes = () + + def get(self, request): + # XXX This seems like a scummy way to get a URI template. + # Is there better? + detail = api_reverse("events:event-detail", args=["G1200"], request=request) + detail = detail.replace("G1200", "{graceid}") + log = api_reverse("events:eventlog-list", args=["G1200"], request=request) + log = log.replace("G1200", "{graceid}") + log_detail = api_reverse("events:eventlog-detail", args=["G1200", "3333"], + request=request) + log_detail = log_detail.replace("G1200", "{graceid}") + log_detail = log_detail.replace("3333", "{N}") + voevent = api_reverse("events:voevent-list", args=["G1200"], request=request) + voevent = voevent.replace("G1200", "{graceid}") + voevent_detail = api_reverse("events:voevent-detail", args=["G1200", "3333"], + request=request) + voevent_detail = voevent_detail.replace("G1200", "{graceid}") + voevent_detail = voevent_detail.replace("3333", "{N}") + embb = api_reverse("events:embbeventlog-list", args=["G1200"], request=request) + embb = embb.replace("G1200", "{graceid}") + emo = api_reverse("events:emobservation-list", args=["G1200"], request=request) + emo = emo.replace("G1200", "{graceid}") + emo_detail = api_reverse("events:emobservation-detail", args=["G1200", "3333"], + request=request) + emo_detail= emo_detail.replace("G1200", "{graceid}") + emo_detail= emo_detail.replace("3333", "{N}") + + files = api_reverse("events:files", args=["G1200", "filename"], request=request) + files = files.replace("G1200", "{graceid}") + files = files.replace("filename", "{filename}") + + labels = api_reverse("events:labels", args=["G1200", "thelabel"], request=request) + labels = labels.replace("G1200", "{graceid}") + labels = labels.replace("thelabel", "{label}") + + taglist = api_reverse("events:eventlogtag-list", args=["G1200", "0"], request=request) + taglist = taglist.replace("G1200", "{graceid}") + taglist = taglist.replace("0", "{N}") + + tag = api_reverse("events:eventlogtag-detail", args=["G1200", "0", "tagname"], request=request) + tag = tag.replace("G1200", "{graceid}") + tag = tag.replace("0", "{N}") + tag = tag.replace("tagname", "{tag_name}") + + signofflist = api_reverse("events:signoff-list", args=["G1200"], request=request) + signofflist = signofflist.replace("G1200", "{graceid}") + + # XXX Need a template for the tag list? + + templates = { + "event-detail-template" : detail, + "voevent-list-template" : voevent, + "voevent-detail-template" : voevent_detail, + "event-log-template" : log, + "event-log-detail-template" : log_detail, + "emobservation-list-template": emo, + "emobservation-detail-template": emo_detail, + "embb-event-log-template" : embb, + "event-label-template" : labels, + "files-template" : files, + "tag-template" : tag, + "taglist-template" : taglist, + "signoff-list-template": signofflist, + } + + # Get superevent templates + superevent_templates = construct_url_templates(request) + templates.update(superevent_templates) + + return Response({ + "links" : { + "superevents" : api_reverse("superevents:superevent-list", + request=request), + "events" : api_reverse("events:event-list", request=request), + "self" : api_reverse("root", request=request), + "performance" : api_reverse("performance-info", request=request), + }, + "templates" : templates, + "groups" : [group.name for group in Group.objects.all()], + "pipelines" : [pipeline.name for pipeline in + Pipeline.objects.all()], + "searches" : [search.name for search in Search.objects.all()], + "labels" : [label.name for label in Label.objects.all()], + "em-groups" : [g.name for g in EMGroup.objects.all()], + "wavebands" : dict(EMSPECTRUM), + "eel-statuses" : dict(EMBBEventLog.EEL_STATUS_CHOICES), + "obs-statuses" : dict(EMBBEventLog.OBS_STATUS_CHOICES), + "superevent-categories": + dict(Superevent.SUPEREVENT_CATEGORY_CHOICES), + "voevent-types" : dict(VOEvent.VOEVENT_TYPE_CHOICES), + }) + + +class PerformanceInfo(APIView): + """ + Serialized performance information + """ + authentication_classes = (LigoAuthentication,) + permission_classes = (IsAuthenticated,) + parser_classes = (parsers.MultiPartParser,) + + def get(self, request, *args, **kwargs): + user_groups = set(request.user.groups.all()) + allowed_groups = set([]) + try: + allowed_groups = set([ + AuthGroup.objects.get(name=settings.LVC_GROUP), + AuthGroup.objects.get(name=settings.EXEC_GROUP), + ]) + except: + pass + + if not user_groups & allowed_groups: + return HttpResponseForbidden("Forbidden") + + try: + performance_info = get_performance_info() + except Exception, e: + return Response(str(e), + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + return Response(performance_info, status=status.HTTP_200_OK) diff --git a/gracedb/superevents/api/base_viewsets.py b/gracedb/api/v1/superevents/base_viewsets.py similarity index 98% rename from gracedb/superevents/api/base_viewsets.py rename to gracedb/api/v1/superevents/base_viewsets.py index d144924b0debb48418298ac20852b6288fe228da..59f13047e44fb709a009bf3f5bbefafa8fa3fca3 100644 --- a/gracedb/superevents/api/base_viewsets.py +++ b/gracedb/api/v1/superevents/base_viewsets.py @@ -5,9 +5,9 @@ from django.shortcuts import get_object_or_404 from guardian.shortcuts import get_objects_for_user from rest_framework import viewsets +from superevents.models import Superevent +from superevents.utils import get_superevent_by_date_id_or_404 from .settings import SUPEREVENT_LOOKUP_URL_KWARG -from ..models import Superevent -from ..utils import get_superevent_by_date_id_or_404 # Set up logger logger = logging.getLogger(__name__) diff --git a/gracedb/superevents/api/filters.py b/gracedb/api/v1/superevents/filters.py similarity index 97% rename from gracedb/superevents/api/filters.py rename to gracedb/api/v1/superevents/filters.py index 9f71f8e3dda14f7710b52f46b604e0c0f99663b7..85e974487c4783a57771375ca54ba5b364fc29b5 100644 --- a/gracedb/superevents/api/filters.py +++ b/gracedb/api/v1/superevents/filters.py @@ -1,13 +1,17 @@ -from rest_framework import filters, exceptions +from __future__ import absolute_import +import logging +from pyparsing import ParseException from django.http import HttpResponseBadRequest -from ..query import parseSupereventQuery +from rest_framework import filters, exceptions + +from superevents.query import parseSupereventQuery -from pyparsing import ParseException -import logging +# Set up logger logger = logging.getLogger(__name__) + class SupereventSearchFilter(filters.SearchFilter): search_param = 'query' diff --git a/gracedb/superevents/api/mixins.py b/gracedb/api/v1/superevents/mixins.py similarity index 98% rename from gracedb/superevents/api/mixins.py rename to gracedb/api/v1/superevents/mixins.py index bdf91b919926b4bee969207c6f4e23ea782605cd..0b487859983c99022acb87046f9a3a623a9e6129 100644 --- a/gracedb/superevents/api/mixins.py +++ b/gracedb/api/v1/superevents/mixins.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import logging from django.core.exceptions import ValidationError as DjangoValidationError diff --git a/gracedb/superevents/api/paginators.py b/gracedb/api/v1/superevents/paginators.py similarity index 99% rename from gracedb/superevents/api/paginators.py rename to gracedb/api/v1/superevents/paginators.py index d30750d00b5986e831559664f1e51ddde61357f5..6fa5e67775bc13b30d876740eaa129d8dac0d330 100644 --- a/gracedb/superevents/api/paginators.py +++ b/gracedb/api/v1/superevents/paginators.py @@ -1,10 +1,11 @@ +from collections import OrderedDict +import logging +import urllib + from rest_framework import pagination from rest_framework.response import Response -import urllib -from collections import OrderedDict - -import logging +# Set up logger logger = logging.getLogger(__name__) # TP (30 Apr 2018): diff --git a/gracedb/superevents/api/permissions.py b/gracedb/api/v1/superevents/permissions.py similarity index 100% rename from gracedb/superevents/api/permissions.py rename to gracedb/api/v1/superevents/permissions.py diff --git a/gracedb/superevents/api/serializers.py b/gracedb/api/v1/superevents/serializers.py similarity index 95% rename from gracedb/superevents/api/serializers.py rename to gracedb/api/v1/superevents/serializers.py index 9c8c66398b2052d3e3d62530afb8b0669bde1516..ea0c44081afb6b096a94e7212e6aac5d8994021e 100644 --- a/gracedb/superevents/api/serializers.py +++ b/gracedb/api/v1/superevents/serializers.py @@ -1,24 +1,28 @@ -from rest_framework import serializers, validators -from rest_framework.exceptions import ValidationError +from __future__ import absolute_import +import functools +import logging +import os + +from django.conf import settings from django.contrib.auth import get_user_model from django.utils.translation import ugettext_lazy as _ -from django.conf import settings -from ..models import Superevent, Labelling, Log, VOEvent, EMObservation, \ - EMFootprint, Signoff +from rest_framework import serializers, validators +from rest_framework.exceptions import ValidationError + +from events.models import Event, Label, Tag, EMGroup +from superevents.models import Superevent, Labelling, Log, VOEvent, \ + EMObservation, EMFootprint, Signoff from .fields import ParentObjectDefault, CommaSeparatedOrListField, \ ChoiceDisplayField from .settings import SUPEREVENT_LOOKUP_URL_KWARG +from ..events.fields import EventGraceidField +from ...utils import api_reverse -from events.models import Event, Label, Tag, EMGroup -from events.view_utils import reverse as gracedb_reverse -from events.api.fields import EventGraceidField - +# Set up user model UserModel = get_user_model() -import os -import functools -import logging +# Set up logger logger = logging.getLogger(__name__) @@ -94,7 +98,7 @@ class SupereventSerializer(serializers.ModelSerializer): def create(self, validated_data): # Function-level import to prevent circular import in alerts - from ..utils import create_superevent + from superevents.utils import create_superevent submitter = validated_data.pop('user') # TODO: @@ -110,7 +114,7 @@ class SupereventSerializer(serializers.ModelSerializer): return [ev.graceid() for ev in obj.get_external_events()] def get_links(self, obj): - bound_reverse = functools.partial(gracedb_reverse, + bound_reverse = functools.partial(api_reverse, args=[obj.superevent_id], request=self.context.get('request', None)) link_dict = { @@ -174,7 +178,7 @@ class SupereventUpdateSerializer(SupereventSerializer): def update(self, instance, validated_data): # Function-level import to prevent circular import in alerts - from ..utils import update_superevent + from superevents.utils import update_superevent # CurrentUserDefault doesn't work for PATCH requests since the # serializer has self.partial == True, the default function is never @@ -208,7 +212,7 @@ class SupereventEventSerializer(serializers.ModelSerializer): fields = ('self', 'graceid', 'event', 'superevent', 'user') def get_self(self, obj): - return gracedb_reverse('event-detail', args=[obj.graceid()], + return api_reverse('events:event-detail', args=[obj.graceid()], request=self.context.get('request', None)) def validate(self, data): @@ -231,7 +235,7 @@ class SupereventEventSerializer(serializers.ModelSerializer): def create(self, validated_data): # Function-level import to prevent circular import in alerts - from ..utils import add_event_to_superevent + from superevents.utils import add_event_to_superevent superevent = validated_data.pop('superevent') event = validated_data.pop('event') @@ -264,13 +268,13 @@ class SupereventLabelSerializer(serializers.ModelSerializer): 'superevent') def get_self(self, obj): - return gracedb_reverse('superevents:superevent-label-detail', args=[ + return api_reverse('superevents:superevent-label-detail', args=[ obj.superevent.superevent_id, obj.label.name], request=self.context.get('request', None)) def create(self, validated_data): # Function-level import to prevent circular import in alerts - from ..utils import add_label_to_superevent + from superevents.utils import add_label_to_superevent creator = validated_data.pop('submitter') superevent = validated_data.pop('superevent') @@ -319,14 +323,14 @@ class SupereventLogSerializer(serializers.ModelSerializer): self.fields['file_version'].read_only = True def get_self(self, obj): - return gracedb_reverse('superevents:superevent-log-detail', + return api_reverse('superevents:superevent-log-detail', args=[obj.superevent.superevent_id, obj.N], request=self.context.get('request', None)) def get_file(self, obj): link = None if obj.filename: - link = gracedb_reverse('superevents:superevent-file-detail', + link = api_reverse('superevents:superevent-file-detail', args=[obj.superevent.superevent_id, obj.versioned_filename], request=self.context.get('request', None)) return link @@ -343,7 +347,7 @@ class SupereventLogSerializer(serializers.ModelSerializer): def create(self, validated_data): # Function-level import to prevent circular import in alerts - from ..utils import create_log, get_or_create_tags + from superevents.utils import create_log, get_or_create_tags # TODO: # Check user permissions here, or somewhere else? Maybe just on viewset @@ -391,7 +395,7 @@ class SupereventLogTagSerializer(serializers.ModelSerializer): superevent_id = self.context['view'].kwargs.get( SUPEREVENT_LOOKUP_URL_KWARG) log_N = self.context['view'].kwargs.get('N') - return gracedb_reverse('superevents:superevent-log-tag-detail', + return api_reverse('superevents:superevent-log-tag-detail', args=[superevent_id, log_N, obj.name], request=self.context.get('request', None)) @@ -423,7 +427,7 @@ class SupereventLogTagSerializer(serializers.ModelSerializer): def create(self, validated_data): # Function-level import to prevent circular import in alerts - from ..utils import add_tag_to_log, get_or_create_tag + from superevents.utils import add_tag_to_log, get_or_create_tag # Get parent log message parent_log = validated_data.pop('parent_log') @@ -497,12 +501,12 @@ class SupereventVOEventSerializer(serializers.ModelSerializer): if obj.filename: file_name = "{name},{version}".format(name=obj.filename, version=obj.file_version) - file_link = gracedb_reverse('superevents:superevent-file-detail', + file_link = api_reverse('superevents:superevent-file-detail', args=[obj.superevent.superevent_id, file_name], request=self.context.get('request', None)) link_dict = { - 'self': gracedb_reverse('superevents:superevent-voevent-detail', + 'self': api_reverse('superevents:superevent-voevent-detail', args=[obj.superevent.superevent_id, obj.N], request=self.context.get('request', None)), 'file': file_link, @@ -553,8 +557,8 @@ class SupereventVOEventSerializer(serializers.ModelSerializer): return data def create(self, validated_data): - - from ..utils import create_voevent_for_superevent + # Function-level import to prevent circular import in alerts + from superevents.utils import create_voevent_for_superevent # Pop some data superevent = validated_data.pop('superevent') @@ -658,7 +662,7 @@ class SupereventEMObservationSerializer(serializers.ModelSerializer): def create(self, validated_data): # Function-level import to prevent circular import in alerts - from ..utils import create_emobservation_for_superevent + from superevents.utils import create_emobservation_for_superevent # Create EMObservation and EMFootprint set emo = create_emobservation_for_superevent(validated_data['superevent'], diff --git a/gracedb/api/v1/superevents/settings.py b/gracedb/api/v1/superevents/settings.py new file mode 100644 index 0000000000000000000000000000000000000000..8cf021f7df867d905b46107ad384dfaaa3102a78 --- /dev/null +++ b/gracedb/api/v1/superevents/settings.py @@ -0,0 +1,8 @@ +from __future__ import absolute_import + +from superevents.models import Superevent + +# Define superevent lookup URL kwarg and regex pattern for +# use throughout this module +SUPEREVENT_LOOKUP_URL_KWARG = 'superevent_id' +SUPEREVENT_LOOKUP_REGEX = Superevent.ID_REGEX diff --git a/gracedb/superevents/api/__init__.py b/gracedb/api/v1/superevents/tests/__init__.py similarity index 100% rename from gracedb/superevents/api/__init__.py rename to gracedb/api/v1/superevents/tests/__init__.py diff --git a/gracedb/superevents/api/tests/mixins.py b/gracedb/api/v1/superevents/tests/mixins.py similarity index 94% rename from gracedb/superevents/api/tests/mixins.py rename to gracedb/api/v1/superevents/tests/mixins.py index 409383e945587971a15fc77ea72a7938a74b69dd..28a4aa5597a515d6cb6ea2dabe4e7b18d536a141 100644 --- a/gracedb/superevents/api/tests/mixins.py +++ b/gracedb/api/v1/superevents/tests/mixins.py @@ -3,8 +3,8 @@ import os from django.contrib.auth import get_user_model -from events.api.tests.mixins import EventCreateMixin from superevents.models import Superevent +from ...events.tests.mixins import EventCreateMixin UserModel = get_user_model() diff --git a/gracedb/superevents/api/tests/test_access.py b/gracedb/api/v1/superevents/tests/test_access.py similarity index 90% rename from gracedb/superevents/api/tests/test_access.py rename to gracedb/api/v1/superevents/tests/test_access.py index 06ea476cfa1affea0122886c38227f31ff163187..0650d334d8888a042d468145d5d1ea1f7338f837 100644 --- a/gracedb/superevents/api/tests/test_access.py +++ b/gracedb/api/v1/superevents/tests/test_access.py @@ -49,7 +49,7 @@ class TestSupereventListGet(SupereventSetup, GraceDbApiTestBase): @classmethod def setUpClass(cls): super(TestSupereventListGet, cls).setUpClass() - cls.url = reverse('api:superevents:superevent-list') + cls.url = reverse('api:default:superevents:superevent-list') def test_internal_user(self): """Internal user sees all superevents""" @@ -132,7 +132,7 @@ class TestSupereventListPost(SupereventManagersGroupAndUserSetup, @classmethod def setUpClass(cls): super(TestSupereventListPost, cls).setUpClass() - cls.url = reverse('api:superevents:superevent-list') + cls.url = reverse('api:default:superevents:superevent-list') def test_basic_internal_production(self): """Basic internal user can't create a production superevent""" @@ -257,7 +257,7 @@ class TestSupereventDetail(SupereventSetup, GraceDbApiTestBase): """Internal user can get all superevent details""" for s in Superevent.objects.all(): # Set up URL - url = reverse('api:superevents:superevent-detail', + url = reverse('api:default:superevents:superevent-detail', args=[s.superevent_id]) # Get response and check code response = self.request_as_user(url, "GET", @@ -272,7 +272,7 @@ class TestSupereventDetail(SupereventSetup, GraceDbApiTestBase): have not been added """ # Set up URL - url = reverse('api:superevents:superevent-detail', + url = reverse('api:default:superevents:superevent-detail', args=[self.internal_superevent.superevent_id]) # Get response and check code response = self.request_as_user(url, "GET", self.lvem_user) @@ -285,7 +285,7 @@ class TestSupereventDetail(SupereventSetup, GraceDbApiTestBase): LV-EM user can GET this superevent since permissions have been added """ # Set up URL - url = reverse('api:superevents:superevent-detail', + url = reverse('api:default:superevents:superevent-detail', args=[self.lvem_superevent.superevent_id]) # Get response and check code response = self.request_as_user(url, "GET", self.lvem_user) @@ -311,7 +311,7 @@ class TestSupereventDetail(SupereventSetup, GraceDbApiTestBase): def test_basic_internal_patch_production(self): """Basic internal user can't update production superevents""" # Define url, make request, and check response - url = reverse('api:superevents:superevent-detail', + url = reverse('api:default:superevents:superevent-detail', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "PATCH", self.internal_user, data={'t_0': 1234}) @@ -323,7 +323,7 @@ class TestSupereventDetail(SupereventSetup, GraceDbApiTestBase): s = self.create_superevent(self.internal_user, event_search='MDC', category=Superevent.SUPEREVENT_CATEGORY_MDC) # Define url, make request, and check response - url = reverse('api:superevents:superevent-detail', + url = reverse('api:default:superevents:superevent-detail', args=[s.superevent_id]) response = self.request_as_user(url, "PATCH", self.internal_user, data={'t_0': 1234}) @@ -335,7 +335,7 @@ class TestSupereventDetail(SupereventSetup, GraceDbApiTestBase): s = self.create_superevent(self.internal_user, event_group='Test', category=Superevent.SUPEREVENT_CATEGORY_TEST) # Define url, make request, and check response - url = reverse('api:superevents:superevent-detail', + url = reverse('api:default:superevents:superevent-detail', args=[s.superevent_id]) response = self.request_as_user(url, "PATCH", self.internal_user, data={'t_0': 1234}) @@ -373,21 +373,21 @@ class TestSupereventConfirmAsGw(SupereventManagersGroupAndUserSetup, def test_basic_internal_user_confirm_production(self): """Basic internal user can't confirm production superevent as GW""" - url = reverse('api:superevents:superevent-confirm-as-gw', + url = reverse('api:default:superevents:superevent-confirm-as-gw', args=[self.production_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.internal_user) self.assertEqual(response.status_code, 403) def test_basic_internal_user_confirm_mdc(self): """Basic internal user can't confirm MDC superevent as GW""" - url = reverse('api:superevents:superevent-confirm-as-gw', + url = reverse('api:default:superevents:superevent-confirm-as-gw', args=[self.mdc_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.internal_user) self.assertEqual(response.status_code, 403) def test_basic_internal_user_confirm_test(self): """Basic internal user can confirm test superevent as GW""" - url = reverse('api:superevents:superevent-confirm-as-gw', + url = reverse('api:default:superevents:superevent-confirm-as-gw', args=[self.test_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.internal_user) self.assertEqual(response.status_code, 200) @@ -397,7 +397,7 @@ class TestSupereventConfirmAsGw(SupereventManagersGroupAndUserSetup, def test_privileged_internal_user_confirm_production(self): """Privileged internal user can confirm production superevent as GW""" - url = reverse('api:superevents:superevent-confirm-as-gw', + url = reverse('api:default:superevents:superevent-confirm-as-gw', args=[self.production_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.sm_user) self.assertEqual(response.status_code, 200) @@ -407,7 +407,7 @@ class TestSupereventConfirmAsGw(SupereventManagersGroupAndUserSetup, def test_privileged_internal_user_confirm_mdc(self): """Privileged internal user can confirm MDC superevent as GW""" - url = reverse('api:superevents:superevent-confirm-as-gw', + url = reverse('api:default:superevents:superevent-confirm-as-gw', args=[self.mdc_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.sm_user) self.assertEqual(response.status_code, 200) @@ -417,7 +417,7 @@ class TestSupereventConfirmAsGw(SupereventManagersGroupAndUserSetup, def test_privileged_internal_user_confirm_test(self): """Privileged internal user can confirm test superevent as GW""" - url = reverse('api:superevents:superevent-confirm-as-gw', + url = reverse('api:default:superevents:superevent-confirm-as-gw', args=[self.test_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.sm_user) self.assertEqual(response.status_code, 200) @@ -427,7 +427,7 @@ class TestSupereventConfirmAsGw(SupereventManagersGroupAndUserSetup, def test_lvem_user_confirm_production(self): """LV-EM user can't confirm production superevent as GW""" - url = reverse('api:superevents:superevent-confirm-as-gw', + url = reverse('api:default:superevents:superevent-confirm-as-gw', args=[self.production_superevent.superevent_id]) # Make request and check response @@ -442,7 +442,7 @@ class TestSupereventConfirmAsGw(SupereventManagersGroupAndUserSetup, def test_lvem_user_confirm_mdc(self): """LV-EM user can't confirm mdc superevent as GW""" - url = reverse('api:superevents:superevent-confirm-as-gw', + url = reverse('api:default:superevents:superevent-confirm-as-gw', args=[self.mdc_superevent.superevent_id]) # Make request and check response @@ -457,7 +457,7 @@ class TestSupereventConfirmAsGw(SupereventManagersGroupAndUserSetup, def test_lvem_user_confirm_test(self): """LV-EM user can't confirm test superevent as GW""" - url = reverse('api:superevents:superevent-confirm-as-gw', + url = reverse('api:default:superevents:superevent-confirm-as-gw', args=[self.test_superevent.superevent_id]) # Make request and check response @@ -476,7 +476,7 @@ class TestSupereventConfirmAsGw(SupereventManagersGroupAndUserSetup, superevents = [self.production_superevent, self.test_superevent, self.mdc_superevent] for s in superevents: - url = reverse('api:superevents:superevent-confirm-as-gw', + url = reverse('api:default:superevents:superevent-confirm-as-gw', args=[s.superevent_id]) response = self.request_as_user(url, "POST") self.assertEqual(response.status_code, 403) @@ -508,7 +508,7 @@ class TestSupereventLabelList(SupereventSetup, GraceDbApiTestBase): """Internal user sees all labels for all superevents""" for s in Superevent.objects.all(): # Set up URL - url = reverse('api:superevents:superevent-label-list', + url = reverse('api:default:superevents:superevent-label-list', args=[s.superevent_id]) # Get response and check code response = self.request_as_user(url, "GET", @@ -523,7 +523,7 @@ class TestSupereventLabelList(SupereventSetup, GraceDbApiTestBase): def test_lvem_get_no_view_perms(self): """LV-EM user can't see labels for internal-only superevent""" - url = reverse('api:superevents:superevent-label-list', + url = reverse('api:default:superevents:superevent-label-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "GET", self.lvem_user) # Should get 404 response - because of filtering, this object @@ -532,7 +532,7 @@ class TestSupereventLabelList(SupereventSetup, GraceDbApiTestBase): def test_lvem_get_with_view_perms(self): """LV-EM user can see labels for exposed superevent""" - url = reverse('api:superevents:superevent-label-list', + url = reverse('api:default:superevents:superevent-label-list', args=[self.lvem_superevent.superevent_id]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 200) @@ -547,7 +547,7 @@ class TestSupereventLabelList(SupereventSetup, GraceDbApiTestBase): """Public user can't see labels for non-public superevents""" # TODO: these errors will be 404 in the future # Test internal superevent - url = reverse('api:superevents:superevent-label-list', + url = reverse('api:default:superevents:superevent-label-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "GET") # Should get 404 response - because of filtering, this object @@ -555,7 +555,7 @@ class TestSupereventLabelList(SupereventSetup, GraceDbApiTestBase): self.assertEqual(response.status_code, 403) # Test LV-EM superevent - url = reverse('api:superevents:superevent-label-list', + url = reverse('api:default:superevents:superevent-label-list', args=[self.lvem_superevent.superevent_id]) response = self.request_as_user(url, "GET") # Should get 404 response - because of filtering, this object @@ -571,7 +571,7 @@ class TestSupereventLabelList(SupereventSetup, GraceDbApiTestBase): """Internal user can add labels to all superevents""" label, _ = Label.objects.get_or_create(name='NEW_LABEL') for s in Superevent.objects.all(): - url = reverse('api:superevents:superevent-label-list', + url = reverse('api:default:superevents:superevent-label-list', args=[s.superevent_id]) data = {'name': label.name} response = self.request_as_user(url, "POST", self.internal_user, @@ -586,7 +586,7 @@ class TestSupereventLabelList(SupereventSetup, GraceDbApiTestBase): label, _ = Label.objects.get_or_create(name='NEW_LABEL') # Internal-only superevent - should get 404 - url = reverse('api:superevents:superevent-label-list', + url = reverse('api:default:superevents:superevent-label-list', args=[self.internal_superevent.superevent_id]) data = {'name': label.name} response = self.request_as_user(url, "POST", self.lvem_user, @@ -594,7 +594,7 @@ class TestSupereventLabelList(SupereventSetup, GraceDbApiTestBase): self.assertEqual(response.status_code, 404) # LV-EM superevent - should get 403 - url = reverse('api:superevents:superevent-label-list', + url = reverse('api:default:superevents:superevent-label-list', args=[self.lvem_superevent.superevent_id]) data = {'name': label.name} response = self.request_as_user(url, "POST", self.lvem_user, @@ -607,7 +607,7 @@ class TestSupereventLabelList(SupereventSetup, GraceDbApiTestBase): # Internal-only superevent - should get 404 # TODO: eventually this will be a 404, 403 for now - url = reverse('api:superevents:superevent-label-list', + url = reverse('api:default:superevents:superevent-label-list', args=[self.internal_superevent.superevent_id]) data = {'name': label.name} response = self.request_as_user(url, "POST", data=data) @@ -615,7 +615,7 @@ class TestSupereventLabelList(SupereventSetup, GraceDbApiTestBase): # LV-EM superevent - should get 404 # TODO: eventually this will be a 404, 403 for now - url = reverse('api:superevents:superevent-label-list', + url = reverse('api:default:superevents:superevent-label-list', args=[self.lvem_superevent.superevent_id]) data = {'name': label.name} response = self.request_as_user(url, "POST", data=data) @@ -649,7 +649,7 @@ class TestSupereventLabelDetail(SupereventSetup, GraceDbApiTestBase): for s in Superevent.objects.all(): for l in s.labels.all(): # Set up URL - url = reverse('api:superevents:superevent-label-detail', + url = reverse('api:default:superevents:superevent-label-detail', args=[s.superevent_id, l.name]) # Get response and check code response = self.request_as_user(url, "GET", @@ -661,7 +661,7 @@ class TestSupereventLabelDetail(SupereventSetup, GraceDbApiTestBase): def test_lvem_get_no_view_perms(self): """LV-EM user can't see labels for internal-only superevent""" for l in self.internal_superevent.labels.all(): - url = reverse('api:superevents:superevent-label-detail', + url = reverse('api:default:superevents:superevent-label-detail', args=[self.internal_superevent.superevent_id, l.name]) response = self.request_as_user(url, "GET", self.lvem_user) # Should get 404 response - because of filtering, the superevent @@ -671,7 +671,7 @@ class TestSupereventLabelDetail(SupereventSetup, GraceDbApiTestBase): def test_lvem_get_with_view_perms(self): """LV-EM user can see all labels for exposed superevent""" for l in self.lvem_superevent.labels.all(): - url = reverse('api:superevents:superevent-label-detail', + url = reverse('api:default:superevents:superevent-label-detail', args=[self.lvem_superevent.superevent_id, l.name]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 200) @@ -683,14 +683,14 @@ class TestSupereventLabelDetail(SupereventSetup, GraceDbApiTestBase): # TODO: these errors will be 404 in the future # Test internal superevent for l in self.internal_superevent.labels.all(): - url = reverse('api:superevents:superevent-label-detail', + url = reverse('api:default:superevents:superevent-label-detail', args=[self.internal_superevent.superevent_id, l.name]) response = self.request_as_user(url, "GET") self.assertEqual(response.status_code, 403) # Test LV-EM superevent for l in self.lvem_superevent.labels.all(): - url = reverse('api:superevents:superevent-label-detail', + url = reverse('api:default:superevents:superevent-label-detail', args=[self.lvem_superevent.superevent_id, l.name]) response = self.request_as_user(url, "GET") self.assertEqual(response.status_code, 403) @@ -704,7 +704,7 @@ class TestSupereventLabelDetail(SupereventSetup, GraceDbApiTestBase): """Internal user can remove labels from all superevents""" for s in Superevent.objects.all(): for l in s.labels.all(): - url = reverse('api:superevents:superevent-label-detail', + url = reverse('api:default:superevents:superevent-label-detail', args=[s.superevent_id, l.name]) response = self.request_as_user(url, "DELETE", self.internal_user) @@ -715,20 +715,20 @@ class TestSupereventLabelDetail(SupereventSetup, GraceDbApiTestBase): """LV-EM user cannot remove labels from any superevents""" # Internal superevent - should get 404 for l in self.internal_superevent.labels.all(): - url = reverse('api:superevents:superevent-label-detail', + url = reverse('api:default:superevents:superevent-label-detail', args=[self.internal_superevent.superevent_id, l.name]) response = self.request_as_user(url, "DELETE", self.lvem_user) self.assertEqual(response.status_code, 404) # Try to delete a label that doesn't exist to ensure there is no # information leaked that way. - url = reverse('api:superevents:superevent-label-detail', + url = reverse('api:default:superevents:superevent-label-detail', args=[self.internal_superevent.superevent_id, 'FAKE_LABEL']) response = self.request_as_user(url, "DELETE", self.lvem_user) self.assertEqual(response.status_code, 404) # LV-EM superevent - should get 403 for l in self.lvem_superevent.labels.all(): - url = reverse('api:superevents:superevent-label-detail', + url = reverse('api:default:superevents:superevent-label-detail', args=[self.lvem_superevent.superevent_id, l.name]) response = self.request_as_user(url, "DELETE", self.lvem_user) self.assertEqual(response.status_code, 403) @@ -737,21 +737,21 @@ class TestSupereventLabelDetail(SupereventSetup, GraceDbApiTestBase): """Public user cannot remove labels from any superevents""" # Internal superevent - should get 404 (TODO: 403 for now) for l in self.internal_superevent.labels.all(): - url = reverse('api:superevents:superevent-label-detail', + url = reverse('api:default:superevents:superevent-label-detail', args=[self.internal_superevent.superevent_id, l.name]) response = self.request_as_user(url, "DELETE") self.assertEqual(response.status_code, 403) # Try to delete a label that doesn't exist to ensure there is no # information leaked that way. (TODO: 403 for now, will be 404) - url = reverse('api:superevents:superevent-label-detail', + url = reverse('api:default:superevents:superevent-label-detail', args=[self.internal_superevent.superevent_id, 'FAKE_LABEL']) response = self.request_as_user(url, "DELETE") self.assertEqual(response.status_code, 403) # LV-EM superevent - should get 404 (TODO: 403 for now) for l in self.lvem_superevent.labels.all(): - url = reverse('api:superevents:superevent-label-detail', + url = reverse('api:default:superevents:superevent-label-detail', args=[self.lvem_superevent.superevent_id, l.name]) response = self.request_as_user(url, "DELETE") self.assertEqual(response.status_code, 403) @@ -784,7 +784,7 @@ class TestSupereventEventList(SupereventManagersGroupAndUserSetup, """Internal user sees all events for superevents""" for s in Superevent.objects.all(): # Set up URL - url = reverse('api:superevents:superevent-event-list', + url = reverse('api:default:superevents:superevent-event-list', args=[s.superevent_id]) # Get response and check code response = self.request_as_user(url, "GET", self.internal_user) @@ -797,7 +797,7 @@ class TestSupereventEventList(SupereventManagersGroupAndUserSetup, def test_lvem_get_no_view_perms(self): """LV-EM user can't see events for internal-only superevent""" - url = reverse('api:superevents:superevent-event-list', + url = reverse('api:default:superevents:superevent-event-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "GET", self.lvem_user) # Should get 404 response - because of filtering, this object @@ -808,7 +808,7 @@ class TestSupereventEventList(SupereventManagersGroupAndUserSetup, """LV-EM user can see events for exposed superevent""" # TODO: do we deal with permissions on events too? i.e., # don't show events in the list if they aren't exposed? - url = reverse('api:superevents:superevent-event-list', + url = reverse('api:default:superevents:superevent-event-list', args=[self.lvem_superevent.superevent_id]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 200) @@ -823,7 +823,7 @@ class TestSupereventEventList(SupereventManagersGroupAndUserSetup, def test_public_get_no_view_perms(self): """Public user can't see events for non-public superevents""" # Internal superevent - url = reverse('api:superevents:superevent-event-list', + url = reverse('api:default:superevents:superevent-event-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "GET") # Should get 404 response - because of filtering, this object @@ -831,7 +831,7 @@ class TestSupereventEventList(SupereventManagersGroupAndUserSetup, self.assertEqual(response.status_code, 403) # LV-EM superevent - url = reverse('api:superevents:superevent-event-list', + url = reverse('api:default:superevents:superevent-event-list', args=[self.lvem_superevent.superevent_id]) response = self.request_as_user(url, "GET") # Should get 404 response - because of filtering, this object @@ -851,7 +851,7 @@ class TestSupereventEventList(SupereventManagersGroupAndUserSetup, user=self.internal_user) # Set up URL, make request, check response code - url = reverse('api:superevents:superevent-event-list', + url = reverse('api:default:superevents:superevent-event-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.internal_user, data={'event': ev.graceid()}) @@ -866,7 +866,7 @@ class TestSupereventEventList(SupereventManagersGroupAndUserSetup, search_name='MDC', user=self.internal_user) # Set up URL, make request, check response code - url = reverse('api:superevents:superevent-event-list', + url = reverse('api:default:superevents:superevent-event-list', args=[s.superevent_id]) response = self.request_as_user(url, "POST", self.internal_user, data={'event': ev.graceid()}) @@ -881,7 +881,7 @@ class TestSupereventEventList(SupereventManagersGroupAndUserSetup, user=self.internal_user) # Set up URL, make request, check response code and data - url = reverse('api:superevents:superevent-event-list', + url = reverse('api:default:superevents:superevent-event-list', args=[s.superevent_id]) response = self.request_as_user(url, "POST", self.internal_user, data={'event': ev.graceid()}) @@ -895,7 +895,7 @@ class TestSupereventEventList(SupereventManagersGroupAndUserSetup, user=self.internal_user) # Set up URL, make request, check response code - url = reverse('api:superevents:superevent-event-list', + url = reverse('api:default:superevents:superevent-event-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.sm_user, data={'event': ev.graceid()}) @@ -911,7 +911,7 @@ class TestSupereventEventList(SupereventManagersGroupAndUserSetup, search_name='MDC', user=self.internal_user) # Set up URL, make request, check response code - url = reverse('api:superevents:superevent-event-list', + url = reverse('api:default:superevents:superevent-event-list', args=[s.superevent_id]) response = self.request_as_user(url, "POST", self.sm_user, data={'event': ev.graceid()}) @@ -927,7 +927,7 @@ class TestSupereventEventList(SupereventManagersGroupAndUserSetup, user=self.internal_user) # Set up URL, make request, check response code and data - url = reverse('api:superevents:superevent-event-list', + url = reverse('api:default:superevents:superevent-event-list', args=[s.superevent_id]) response = self.request_as_user(url, "POST", self.sm_user, data={'event': ev.graceid()}) @@ -942,7 +942,7 @@ class TestSupereventEventList(SupereventManagersGroupAndUserSetup, # Set up URL, make request, check response code # Should be 404 since superevent is not exposed - url = reverse('api:superevents:superevent-event-list', + url = reverse('api:default:superevents:superevent-event-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.lvem_user, data={'event': ev.graceid()}) @@ -963,7 +963,7 @@ class TestSupereventEventList(SupereventManagersGroupAndUserSetup, # Set up URL, make request, check response code # Should be 404 since superevent is not exposed - url = reverse('api:superevents:superevent-event-list', + url = reverse('api:default:superevents:superevent-event-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", data={'event': ev.graceid()}) @@ -996,7 +996,7 @@ class TestSupereventEventDetail(SupereventManagersGroupAndUserSetup, for s in Superevent.objects.all(): for ev in s.events.all(): # Set up URL - url = reverse('api:superevents:superevent-event-detail', + url = reverse('api:default:superevents:superevent-event-detail', args=[s.superevent_id, ev.graceid()]) # Get response and check code response = self.request_as_user(url, "GET", self.internal_user) @@ -1007,7 +1007,7 @@ class TestSupereventEventDetail(SupereventManagersGroupAndUserSetup, def test_lvem_get_no_view_perms(self): """LV-EM user can't see events for internal-only superevent""" for ev in self.internal_superevent.events.all(): - url = reverse('api:superevents:superevent-event-detail', + url = reverse('api:default:superevents:superevent-event-detail', args=[self.internal_superevent.superevent_id, ev.graceid()]) response = self.request_as_user(url, "GET", self.lvem_user) # Should get 404 response - because of filtering, this superevent @@ -1019,7 +1019,7 @@ class TestSupereventEventDetail(SupereventManagersGroupAndUserSetup, # TODO: do we deal with permissions on events too? i.e., # don't show events in the list if they aren't exposed? for ev in self.lvem_superevent.events.all(): - url = reverse('api:superevents:superevent-event-detail', + url = reverse('api:default:superevents:superevent-event-detail', args=[self.lvem_superevent.superevent_id, ev.graceid()]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 200) @@ -1030,7 +1030,7 @@ class TestSupereventEventDetail(SupereventManagersGroupAndUserSetup, """Public user can't see events for non-public superevents""" # Internal superevent for ev in self.internal_superevent.events.all(): - url = reverse('api:superevents:superevent-event-detail', + url = reverse('api:default:superevents:superevent-event-detail', args=[self.internal_superevent.superevent_id, ev.graceid()]) response = self.request_as_user(url, "GET") # Should get 404 response - because of filtering, this superevent @@ -1039,7 +1039,7 @@ class TestSupereventEventDetail(SupereventManagersGroupAndUserSetup, # NOTE: will be a 404 error in the future for ev in self.lvem_superevent.events.all(): - url = reverse('api:superevents:superevent-event-detail', + url = reverse('api:default:superevents:superevent-event-detail', args=[self.lvem_superevent.superevent_id, ev.graceid()]) response = self.request_as_user(url, "GET") # Should get 404 response - because of filtering, this superevent @@ -1056,7 +1056,7 @@ class TestSupereventEventDetail(SupereventManagersGroupAndUserSetup, """ Basic internal user can't remove events from production superevents. """ - url = reverse('api:superevents:superevent-event-detail', + url = reverse('api:default:superevents:superevent-event-detail', args=[self.internal_superevent.superevent_id, self.event1.graceid()]) response = self.request_as_user(url, "DELETE", self.internal_user) @@ -1074,7 +1074,7 @@ class TestSupereventEventDetail(SupereventManagersGroupAndUserSetup, s.events.add(ev) # Set up URL, make request, check response code - url = reverse('api:superevents:superevent-event-detail', + url = reverse('api:default:superevents:superevent-event-detail', args=[s.superevent_id, ev.graceid()]) response = self.request_as_user(url, "DELETE", self.internal_user) self.assertEqual(response.status_code, 403) @@ -1091,7 +1091,7 @@ class TestSupereventEventDetail(SupereventManagersGroupAndUserSetup, s.events.add(ev) # Set up URL, make request, check response code - url = reverse('api:superevents:superevent-event-detail', + url = reverse('api:default:superevents:superevent-event-detail', args=[s.superevent_id, ev.graceid()]) response = self.request_as_user(url, "DELETE", self.internal_user) self.assertEqual(response.status_code, 204) @@ -1100,7 +1100,7 @@ class TestSupereventEventDetail(SupereventManagersGroupAndUserSetup, """ Privileged internal user can remove events from production superevents. """ - url = reverse('api:superevents:superevent-event-detail', + url = reverse('api:default:superevents:superevent-event-detail', args=[self.internal_superevent.superevent_id, self.event1.graceid()]) response = self.request_as_user(url, "DELETE", self.sm_user) @@ -1118,7 +1118,7 @@ class TestSupereventEventDetail(SupereventManagersGroupAndUserSetup, s.events.add(ev) # Set up URL, make request, check response code - url = reverse('api:superevents:superevent-event-detail', + url = reverse('api:default:superevents:superevent-event-detail', args=[s.superevent_id, ev.graceid()]) response = self.request_as_user(url, "DELETE", self.sm_user) self.assertEqual(response.status_code, 204) @@ -1135,7 +1135,7 @@ class TestSupereventEventDetail(SupereventManagersGroupAndUserSetup, s.events.add(ev) # Set up URL, make request, check response code - url = reverse('api:superevents:superevent-event-detail', + url = reverse('api:default:superevents:superevent-event-detail', args=[s.superevent_id, ev.graceid()]) response = self.request_as_user(url, "DELETE", self.sm_user) self.assertEqual(response.status_code, 204) @@ -1143,14 +1143,14 @@ class TestSupereventEventDetail(SupereventManagersGroupAndUserSetup, def test_lvem_user_remove_event_from_superevent(self): """LV-EM user can't remove events from hidden or exposed superevents""" # Internal superevent - url = reverse('api:superevents:superevent-event-detail', + url = reverse('api:default:superevents:superevent-event-detail', args=[self.internal_superevent.superevent_id, self.event1.graceid()]) response = self.request_as_user(url, "DELETE", self.lvem_user) self.assertEqual(response.status_code, 404) # Exposed superevent - url = reverse('api:superevents:superevent-event-detail', + url = reverse('api:default:superevents:superevent-event-detail', args=[self.lvem_superevent.superevent_id, self.event2.graceid()]) response = self.request_as_user(url, "DELETE", self.lvem_user) @@ -1161,7 +1161,7 @@ class TestSupereventEventDetail(SupereventManagersGroupAndUserSetup, Public user can't remove events from hidden or exposed superevents """ # Internal superevent - url = reverse('api:superevents:superevent-event-detail', + url = reverse('api:default:superevents:superevent-event-detail', args=[self.internal_superevent.superevent_id, self.event1.graceid()]) response = self.request_as_user(url, "DELETE") @@ -1195,7 +1195,7 @@ class TestSupereventLogList(AccessManagersGroupAndUserSetup, def test_internal_user_get(self): """Internal user can see all logs for a superevent""" - url = reverse('api:superevents:superevent-log-list', + url = reverse('api:default:superevents:superevent-log-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "GET", self.internal_user) self.assertEqual(response.status_code, 200) @@ -1206,14 +1206,14 @@ class TestSupereventLogList(AccessManagersGroupAndUserSetup, """LV-EM user can't see any logs for hidden superevent""" # Internal superevent even has one log exposed to LV-EM, # but still shouldn't be able to see it - url = reverse('api:superevents:superevent-log-list', + url = reverse('api:default:superevents:superevent-log-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 404) def test_lvem_user_get_for_exposed_superevent(self): """LV-EM user can see only exposed logs for exposed superevent""" - url = reverse('api:superevents:superevent-log-list', + url = reverse('api:default:superevents:superevent-log-list', args=[self.lvem_superevent.superevent_id]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 200) @@ -1230,7 +1230,7 @@ class TestSupereventLogList(AccessManagersGroupAndUserSetup, """Internal user can create logs for all superevents""" log_data = {'comment': 'test comment'} for s in Superevent.objects.all(): - url = reverse('api:superevents:superevent-log-list', + url = reverse('api:default:superevents:superevent-log-list', args=[s.superevent_id]) response = self.request_as_user(url, "POST", self.internal_user, data=log_data) @@ -1245,7 +1245,7 @@ class TestSupereventLogList(AccessManagersGroupAndUserSetup, 'tagname': ['tag1', 'tag2'] } for s in Superevent.objects.all(): - url = reverse('api:superevents:superevent-log-list', + url = reverse('api:default:superevents:superevent-log-list', args=[s.superevent_id]) response = self.request_as_user(url, "POST", self.internal_user, data=log_data) @@ -1267,7 +1267,7 @@ class TestSupereventLogList(AccessManagersGroupAndUserSetup, Tag.objects.create(name=settings.EXTERNAL_ACCESS_TAGNAME) # Make request - url = reverse('api:superevents:superevent-log-list', + url = reverse('api:default:superevents:superevent-log-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.internal_user, data=log_data) @@ -1287,7 +1287,7 @@ class TestSupereventLogList(AccessManagersGroupAndUserSetup, Tag.objects.create(name=settings.PUBLIC_ACCESS_TAGNAME) # Make request - url = reverse('api:superevents:superevent-log-list', + url = reverse('api:default:superevents:superevent-log-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.internal_user, data=log_data) @@ -1307,7 +1307,7 @@ class TestSupereventLogList(AccessManagersGroupAndUserSetup, Tag.objects.create(name=settings.EXTERNAL_ACCESS_TAGNAME) # Make request - url = reverse('api:superevents:superevent-log-list', + url = reverse('api:default:superevents:superevent-log-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.am_user, data=log_data) @@ -1330,7 +1330,7 @@ class TestSupereventLogList(AccessManagersGroupAndUserSetup, Tag.objects.create(name=settings.EXTERNAL_ACCESS_TAGNAME) # Make request - url = reverse('api:superevents:superevent-log-list', + url = reverse('api:default:superevents:superevent-log-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.am_user, data=log_data) @@ -1347,7 +1347,7 @@ class TestSupereventLogList(AccessManagersGroupAndUserSetup, log_data = {'comment': 'test comment'} # Internal-only superevent - url = reverse('api:superevents:superevent-log-list', + url = reverse('api:default:superevents:superevent-log-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.lvem_user, data=log_data) @@ -1356,7 +1356,7 @@ class TestSupereventLogList(AccessManagersGroupAndUserSetup, self.assertEqual(response.status_code, 404) # LV-EM exposed superevent - url = reverse('api:superevents:superevent-log-list', + url = reverse('api:default:superevents:superevent-log-list', args=[self.lvem_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.lvem_user, data=log_data) @@ -1369,7 +1369,7 @@ class TestSupereventLogList(AccessManagersGroupAndUserSetup, log_data = {'comment': 'test comment', 'tagname': ['test_tag']} # Post to hidden superevent, should get 404 - url = reverse('api:superevents:superevent-log-list', + url = reverse('api:default:superevents:superevent-log-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.lvem_user, data=log_data) @@ -1377,7 +1377,7 @@ class TestSupereventLogList(AccessManagersGroupAndUserSetup, self.assertEqual(response.status_code, 404) # Post to exposed superevent - url = reverse('api:superevents:superevent-log-list', + url = reverse('api:default:superevents:superevent-log-list', args=[self.lvem_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.lvem_user, data=log_data) @@ -1423,7 +1423,7 @@ class TestSupereventLogDetail(SupereventSetup, GraceDbApiTestBase): """Internal user can see all logs for all superevents""" for s in Superevent.objects.all(): for l in s.log_set.all(): - url = reverse('api:superevents:superevent-log-detail', + url = reverse('api:default:superevents:superevent-log-detail', args=[self.internal_superevent.superevent_id, l.N]) response = self.request_as_user(url, "GET", self.internal_user) @@ -1436,7 +1436,7 @@ class TestSupereventLogDetail(SupereventSetup, GraceDbApiTestBase): # Internal superevent even has one log exposed to LV-EM, # but still shouldn't be able to see it for l in self.internal_superevent.log_set.all(): - url = reverse('api:superevents:superevent-log-detail', + url = reverse('api:default:superevents:superevent-log-detail', args=[self.internal_superevent.superevent_id, l.N]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 404) @@ -1444,7 +1444,7 @@ class TestSupereventLogDetail(SupereventSetup, GraceDbApiTestBase): def test_lvem_user_get_for_exposed_superevent(self): """LV-EM user can see only exposed logs for exposed superevent""" for l in self.lvem_superevent.log_set.all(): - url = reverse('api:superevents:superevent-log-detail', + url = reverse('api:default:superevents:superevent-log-detail', args=[self.lvem_superevent.superevent_id, l.N]) response = self.request_as_user(url, "GET", self.lvem_user) @@ -1461,7 +1461,7 @@ class TestSupereventLogDetail(SupereventSetup, GraceDbApiTestBase): """Public user can't get log detail for hidden superevent""" # TODO: add public log to superevent for l in self.internal_superevent.log_set.all(): - url = reverse('api:superevents:superevent-log-detail', + url = reverse('api:default:superevents:superevent-log-detail', args=[self.internal_superevent.superevent_id, l.N]) response = self.request_as_user(url, "GET") # TODO: will be 404 in the future @@ -1512,7 +1512,7 @@ class TestSupereventLogTagList(AccessManagersGroupAndUserSetup, """Internal user can get all tags for all logs for all superevents""" for s in Superevent.objects.all(): for l in s.log_set.all(): - url = reverse('api:superevents:superevent-log-tag-list', + url = reverse('api:default:superevents:superevent-log-tag-list', args=[s.superevent_id, l.N]) # Make request response = self.request_as_user(url, "GET", self.internal_user) @@ -1531,7 +1531,7 @@ class TestSupereventLogTagList(AccessManagersGroupAndUserSetup, def test_lvem_get_for_hidden_superevent(self): """LV-EM user can't get tags for any logs on hidden superevent""" for l in self.internal_superevent.log_set.all(): - url = reverse('api:superevents:superevent-log-tag-list', + url = reverse('api:default:superevents:superevent-log-tag-list', args=[self.internal_superevent.superevent_id, l.N]) # Make request response = self.request_as_user(url, "GET", self.lvem_user) @@ -1543,7 +1543,7 @@ class TestSupereventLogTagList(AccessManagersGroupAndUserSetup, LV-EM user can only get tags for exposed logs on exposed superevent """ for l in self.lvem_superevent.log_set.all(): - url = reverse('api:superevents:superevent-log-tag-list', + url = reverse('api:default:superevents:superevent-log-tag-list', args=[self.lvem_superevent.superevent_id, l.N]) # Make request response = self.request_as_user(url, "GET", self.lvem_user) @@ -1561,7 +1561,7 @@ class TestSupereventLogTagList(AccessManagersGroupAndUserSetup, def test_public_get_for_hidden_superevent(self): """Public user can't get tags for any logs on hidden superevent""" for l in self.internal_superevent.log_set.all(): - url = reverse('api:superevents:superevent-log-tag-list', + url = reverse('api:default:superevents:superevent-log-tag-list', args=[self.internal_superevent.superevent_id, l.N]) # Make request response = self.request_as_user(url, "GET") @@ -1581,7 +1581,7 @@ class TestSupereventLogTagList(AccessManagersGroupAndUserSetup, tag = Tag.objects.create(name='new_tag') for s in Superevent.objects.all(): for l in s.log_set.all(): - url = reverse('api:superevents:superevent-log-tag-list', + url = reverse('api:default:superevents:superevent-log-tag-list', args=[s.superevent_id, l.N]) response = self.request_as_user(url, "POST", self.internal_user, data={'name': tag.name}) @@ -1599,7 +1599,7 @@ class TestSupereventLogTagList(AccessManagersGroupAndUserSetup, superevent=self.internal_superevent, comment='test') # Make request - url = reverse('api:superevents:superevent-log-tag-list', + url = reverse('api:default:superevents:superevent-log-tag-list', args=[self.internal_superevent.superevent_id, log.N]) response = self.request_as_user(url, "POST", self.internal_user, data={'name': settings.EXTERNAL_ACCESS_TAGNAME}) @@ -1619,7 +1619,7 @@ class TestSupereventLogTagList(AccessManagersGroupAndUserSetup, superevent=self.internal_superevent, comment='test') # Make request - url = reverse('api:superevents:superevent-log-tag-list', + url = reverse('api:default:superevents:superevent-log-tag-list', args=[self.internal_superevent.superevent_id, log.N]) response = self.request_as_user(url, "POST", self.internal_user, data={'name': settings.PUBLIC_ACCESS_TAGNAME}) @@ -1639,7 +1639,7 @@ class TestSupereventLogTagList(AccessManagersGroupAndUserSetup, superevent=self.internal_superevent, comment='test') # Make request - url = reverse('api:superevents:superevent-log-tag-list', + url = reverse('api:default:superevents:superevent-log-tag-list', args=[self.internal_superevent.superevent_id, log.N]) response = self.request_as_user(url, "POST", self.am_user, data={'name': settings.EXTERNAL_ACCESS_TAGNAME}) @@ -1660,7 +1660,7 @@ class TestSupereventLogTagList(AccessManagersGroupAndUserSetup, superevent=self.internal_superevent, comment='test') # Make request - url = reverse('api:superevents:superevent-log-tag-list', + url = reverse('api:default:superevents:superevent-log-tag-list', args=[self.internal_superevent.superevent_id, log.N]) response = self.request_as_user(url, "POST", self.am_user, data={'name': settings.PUBLIC_ACCESS_TAGNAME}) @@ -1675,7 +1675,7 @@ class TestSupereventLogTagList(AccessManagersGroupAndUserSetup, log = Log.objects.create(issuer=self.internal_user, superevent=self.internal_superevent, comment='test') - url = reverse('api:superevents:superevent-log-tag-list', + url = reverse('api:default:superevents:superevent-log-tag-list', args=[self.internal_superevent.superevent_id, log.N]) response = self.request_as_user(url, "POST", self.lvem_user, data={'name': self.tag1.name}) @@ -1686,7 +1686,7 @@ class TestSupereventLogTagList(AccessManagersGroupAndUserSetup, # Internal-only superevent again, with tag already applied, # to make sure error message is what we expect and that nothing # leaks out that way. - url = reverse('api:superevents:superevent-log-tag-list', + url = reverse('api:default:superevents:superevent-log-tag-list', args=[self.internal_superevent.superevent_id, self.internal_superevent_exposed_log.N]) response = self.request_as_user(url, "POST", self.lvem_user, @@ -1695,7 +1695,7 @@ class TestSupereventLogTagList(AccessManagersGroupAndUserSetup, self.assertEqual(response.status_code, 404) # LV-EM exposed superevent - url = reverse('api:superevents:superevent-log-tag-list', + url = reverse('api:default:superevents:superevent-log-tag-list', args=[self.lvem_superevent.superevent_id, self.lvem_superevent_exposed_log.N]) response = self.request_as_user(url, "POST", self.lvem_user, @@ -1710,7 +1710,7 @@ class TestSupereventLogTagList(AccessManagersGroupAndUserSetup, log = Log.objects.create(issuer=self.internal_user, superevent=self.internal_superevent, comment='test') - url = reverse('api:superevents:superevent-log-tag-list', + url = reverse('api:default:superevents:superevent-log-tag-list', args=[self.internal_superevent.superevent_id, log.N]) response = self.request_as_user(url, "POST", data={'name': self.tag1.name}) @@ -1722,7 +1722,7 @@ class TestSupereventLogTagList(AccessManagersGroupAndUserSetup, # Internal-only superevent again, with tag already applied, # to make sure error message is what we expect and that nothing # leaks out that way. - url = reverse('api:superevents:superevent-log-tag-list', + url = reverse('api:default:superevents:superevent-log-tag-list', args=[self.internal_superevent.superevent_id, self.internal_superevent_exposed_log.N]) response = self.request_as_user(url, "POST", @@ -1779,7 +1779,8 @@ class TestSupereventLogTagDetail(AccessManagersGroupAndUserSetup, for s in Superevent.objects.all(): for l in s.log_set.all(): for t in l.tags.all(): - url = reverse('api:superevents:superevent-log-tag-detail', + url = reverse(('api:default:superevents:' + 'superevent-log-tag-detail'), args=[s.superevent_id, l.N, t.name]) response = self.request_as_user(url, "GET", self.internal_user) @@ -1790,7 +1791,8 @@ class TestSupereventLogTagDetail(AccessManagersGroupAndUserSetup, """LV-EM user can't get tags for any logs on hidden superevent""" for l in self.internal_superevent.log_set.all(): for t in l.tags.all(): - url = reverse('api:superevents:superevent-log-tag-detail', + url = reverse(('api:default:superevents:' + 'superevent-log-tag-detail'), args=[self.internal_superevent.superevent_id, l.N, t.name]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 404) @@ -1801,7 +1803,8 @@ class TestSupereventLogTagDetail(AccessManagersGroupAndUserSetup, """ for l in self.lvem_superevent.log_set.all(): for t in l.tags.all(): - url = reverse('api:superevents:superevent-log-tag-detail', + url = reverse(('api:default:superevents:' + 'superevent-log-tag-detail'), args=[self.lvem_superevent.superevent_id, l.N, t.name]) response = self.request_as_user(url, "GET", self.lvem_user) if (l == self.lvem_superevent_exposed_log): @@ -1814,7 +1817,8 @@ class TestSupereventLogTagDetail(AccessManagersGroupAndUserSetup, """Public user can't get tags for any logs for hidden superevent""" for l in self.internal_superevent.log_set.all(): for t in l.tags.all(): - url = reverse('api:superevents:superevent-log-tag-detail', + url = reverse(('api:default:superevents:' + 'superevent-log-tag-detail'), args=[self.internal_superevent.superevent_id, l.N, t.name]) response = self.request_as_user(url, "GET") self.assertEqual(response.status_code, 403) @@ -1829,7 +1833,7 @@ class TestSupereventLogTagDetail(AccessManagersGroupAndUserSetup, def test_internal_user_remove_tag(self): """Internal user can remove tags from superevent logs""" - url = reverse('api:superevents:superevent-log-tag-detail', + url = reverse('api:default:superevents:superevent-log-tag-detail', args=[self.internal_superevent.superevent_id, self.internal_superevent_exposed_log.N, self.tag1.name]) response = self.request_as_user(url, "DELETE", self.internal_user) @@ -1842,7 +1846,7 @@ class TestSupereventLogTagDetail(AccessManagersGroupAndUserSetup, log.tags.add(self.lvem_tag) # Make request and check response data - url = reverse('api:superevents:superevent-log-tag-detail', + url = reverse('api:default:superevents:superevent-log-tag-detail', args=[log.superevent.superevent_id, log.N, self.lvem_tag.name]) response = self.request_as_user(url, "DELETE", self.internal_user) self.assertEqual(response.status_code, 403) @@ -1854,7 +1858,7 @@ class TestSupereventLogTagDetail(AccessManagersGroupAndUserSetup, log.tags.add(self.public_tag) # Make request and check response data - url = reverse('api:superevents:superevent-log-tag-detail', + url = reverse('api:default:superevents:superevent-log-tag-detail', args=[log.superevent.superevent_id, log.N, self.public_tag.name]) response = self.request_as_user(url, "DELETE", self.internal_user) self.assertEqual(response.status_code, 403) @@ -1866,7 +1870,7 @@ class TestSupereventLogTagDetail(AccessManagersGroupAndUserSetup, log.tags.add(self.lvem_tag) # Make request and check response data - url = reverse('api:superevents:superevent-log-tag-detail', + url = reverse('api:default:superevents:superevent-log-tag-detail', args=[log.superevent.superevent_id, log.N, self.lvem_tag.name]) response = self.request_as_user(url, "DELETE", self.am_user) self.assertEqual(response.status_code, 204) @@ -1878,7 +1882,7 @@ class TestSupereventLogTagDetail(AccessManagersGroupAndUserSetup, log.tags.add(self.public_tag) # Make request and check response data - url = reverse('api:superevents:superevent-log-tag-detail', + url = reverse('api:default:superevents:superevent-log-tag-detail', args=[log.superevent.superevent_id, log.N, self.public_tag.name]) response = self.request_as_user(url, "DELETE", self.am_user) self.assertEqual(response.status_code, 204) @@ -1886,7 +1890,7 @@ class TestSupereventLogTagDetail(AccessManagersGroupAndUserSetup, def test_lvem_user_remove_tag_from_log_on_hidden_superevent(self): """LV-EM user can't remove tag from logs on hidden superevent""" # Make request and check response data - url = reverse('api:superevents:superevent-log-tag-detail', + url = reverse('api:default:superevents:superevent-log-tag-detail', args=[self.internal_superevent.superevent_id, self.internal_superevent_exposed_log.N, self.tag1.name]) response = self.request_as_user(url, "DELETE", self.lvem_user) @@ -1897,20 +1901,20 @@ class TestSupereventLogTagDetail(AccessManagersGroupAndUserSetup, # Hidden log on exposed superevent, no tags log = Log.objects.create(issuer=self.internal_user, superevent=self.lvem_superevent, comment='test') - url = reverse('api:superevents:superevent-log-tag-detail', + url = reverse('api:default:superevents:superevent-log-tag-detail', args=[self.lvem_superevent.superevent_id, log.N, self.tag1.name]) response = self.request_as_user(url, "DELETE", self.lvem_user) self.assertEqual(response.status_code, 404) # Add the tag and try again just to make sure log.tags.add(self.tag1) - url = reverse('api:superevents:superevent-log-tag-detail', + url = reverse('api:default:superevents:superevent-log-tag-detail', args=[self.lvem_superevent.superevent_id, log.N, self.tag1.name]) response = self.request_as_user(url, "DELETE", self.lvem_user) self.assertEqual(response.status_code, 404) # Exposed log on exposed superevent - url = reverse('api:superevents:superevent-log-tag-detail', + url = reverse('api:default:superevents:superevent-log-tag-detail', args=[self.lvem_superevent.superevent_id, self.lvem_superevent_exposed_log.N, self.tag1.name]) response = self.request_as_user(url, "DELETE", self.lvem_user) @@ -1919,7 +1923,7 @@ class TestSupereventLogTagDetail(AccessManagersGroupAndUserSetup, def test_public_user_remove_tag_from_log_on_hidden_superevent(self): """Public user can't remove tag from logs on hidden superevent""" # Make request and check response data - url = reverse('api:superevents:superevent-log-tag-detail', + url = reverse('api:default:superevents:superevent-log-tag-detail', args=[self.internal_superevent.superevent_id, self.internal_superevent_exposed_log.N, self.tag1.name]) response = self.request_as_user(url, "DELETE") @@ -1969,7 +1973,7 @@ class TestSupereventVOEventList(SupereventSetup, GraceDbApiTestBase): def test_internal_user_get_list(self): """Internal user can get all VOEvents for all superevents""" for s in Superevent.objects.all(): - url = reverse('api:superevents:superevent-voevent-list', + url = reverse('api:default:superevents:superevent-voevent-list', args=[s.superevent_id]) response = self.request_as_user(url, "GET", self.internal_user) self.assertEqual(response.status_code, 200) @@ -1983,14 +1987,14 @@ class TestSupereventVOEventList(SupereventSetup, GraceDbApiTestBase): def test_lvem_user_get_list_for_hidden_superevent(self): """LV-EM user can't get any VOEvents for hidden superevents""" - url = reverse('api:superevents:superevent-voevent-list', + url = reverse('api:default:superevents:superevent-voevent-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 404) def test_lvem_user_get_list_for_exposed_superevent(self): """LV-EM user can get all VOEvents for exposed superevents""" - url = reverse('api:superevents:superevent-voevent-list', + url = reverse('api:default:superevents:superevent-voevent-list', args=[self.lvem_superevent.superevent_id]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 200) @@ -2003,7 +2007,7 @@ class TestSupereventVOEventList(SupereventSetup, GraceDbApiTestBase): def test_public_user_get_list_for_hidden_superevent(self): """Public user can't get any VOEvents for hidden superevents""" - url = reverse('api:superevents:superevent-voevent-list', + url = reverse('api:default:superevents:superevent-voevent-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "GET") self.assertEqual(response.status_code, 403) @@ -2016,7 +2020,7 @@ class TestSupereventVOEventList(SupereventSetup, GraceDbApiTestBase): def test_internal_user_create_voevent(self): """Internal user can create VOEvents for all superevents""" - url = reverse('api:superevents:superevent-voevent-list', + url = reverse('api:default:superevents:superevent-voevent-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.internal_user, data=self.voevent_data) @@ -2026,7 +2030,7 @@ class TestSupereventVOEventList(SupereventSetup, GraceDbApiTestBase): def test_lvem_user_create_voevent_for_hidden_superevent(self): """LV-EM user can't create VOEvents for hidden superevents""" - url = reverse('api:superevents:superevent-voevent-list', + url = reverse('api:default:superevents:superevent-voevent-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.lvem_user, data=self.voevent_data) @@ -2034,7 +2038,7 @@ class TestSupereventVOEventList(SupereventSetup, GraceDbApiTestBase): def test_lvem_user_create_voevent_for_exposed_superevent(self): """LV-EM user can't create VOEvents for exposed superevents""" - url = reverse('api:superevents:superevent-voevent-list', + url = reverse('api:default:superevents:superevent-voevent-list', args=[self.lvem_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.lvem_user, data=self.voevent_data) @@ -2044,7 +2048,7 @@ class TestSupereventVOEventList(SupereventSetup, GraceDbApiTestBase): def test_public_user_create_voevent_for_hidden_superevent(self): """Public user can't create VOEvents for hidden superevents""" - url = reverse('api:superevents:superevent-voevent-list', + url = reverse('api:default:superevents:superevent-voevent-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", data=self.voevent_data) self.assertEqual(response.status_code, 403) @@ -2076,7 +2080,8 @@ class TestSupereventVOEventDetail(SupereventSetup, GraceDbApiTestBase): """Internal user can get all VOEvent details for all superevents""" for s in Superevent.objects.all(): for v in s.voevent_set.all(): - url = reverse('api:superevents:superevent-voevent-detail', + url = reverse(('api:default:superevents:' + 'superevent-voevent-detail'), args=[s.superevent_id, v.N]) response = self.request_as_user(url, "GET", self.internal_user) self.assertEqual(response.status_code, 200) @@ -2086,7 +2091,7 @@ class TestSupereventVOEventDetail(SupereventSetup, GraceDbApiTestBase): def test_lvem_user_get_detail_for_hidden_superevent(self): """LV-EM user can't get VOEvent detail for hidden superevents""" voevent = self.internal_superevent.voevent_set.first() - url = reverse('api:superevents:superevent-voevent-detail', + url = reverse('api:default:superevents:superevent-voevent-detail', args=[self.internal_superevent.superevent_id, voevent.N]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 404) @@ -2094,7 +2099,7 @@ class TestSupereventVOEventDetail(SupereventSetup, GraceDbApiTestBase): def test_lvem_user_get_detail_for_exposed_superevent(self): """LV-EM user can get all VOEvent details for exposed superevents""" for v in self.lvem_superevent.voevent_set.all(): - url = reverse('api:superevents:superevent-voevent-detail', + url = reverse('api:default:superevents:superevent-voevent-detail', args=[self.lvem_superevent.superevent_id, v.N]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 200) @@ -2104,7 +2109,7 @@ class TestSupereventVOEventDetail(SupereventSetup, GraceDbApiTestBase): def test_public_user_get_list_for_hidden_superevent(self): """Public user can't get any VOEvent details for hidden superevents""" v = self.internal_superevent.voevent_set.first() - url = reverse('api:superevents:superevent-voevent-detail', + url = reverse('api:default:superevents:superevent-voevent-detail', args=[self.internal_superevent.superevent_id, v.N]) response = self.request_as_user(url, "GET") self.assertEqual(response.status_code, 403) @@ -2158,7 +2163,8 @@ class TestSupereventEMObservationList(SupereventSetup, GraceDbApiTestBase): def test_internal_user_get_list(self): """Internal user can get all EMObservations for all superevents""" for s in Superevent.objects.all(): - url = reverse('api:superevents:superevent-emobservation-list', + url = reverse(('api:default:superevents:' + 'superevent-emobservation-list'), args=[s.superevent_id]) response = self.request_as_user(url, "GET", self.internal_user) self.assertEqual(response.status_code, 200) @@ -2172,14 +2178,14 @@ class TestSupereventEMObservationList(SupereventSetup, GraceDbApiTestBase): def test_lvem_user_get_list_for_hidden_superevent(self): """LV-EM user can't get any EMObservations for hidden superevents""" - url = reverse('api:superevents:superevent-emobservation-list', + url = reverse('api:default:superevents:superevent-emobservation-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 404) def test_lvem_user_get_list_for_exposed_superevent(self): """LV-EM user can get all EMObservations for exposed superevents""" - url = reverse('api:superevents:superevent-emobservation-list', + url = reverse('api:default:superevents:superevent-emobservation-list', args=[self.lvem_superevent.superevent_id]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 200) @@ -2192,7 +2198,7 @@ class TestSupereventEMObservationList(SupereventSetup, GraceDbApiTestBase): def test_public_user_get_list_for_hidden_superevent(self): """Public user can't get any EMObservations for hidden superevents""" - url = reverse('api:superevents:superevent-emobservation-list', + url = reverse('api:default:superevents:superevent-emobservation-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "GET") self.assertEqual(response.status_code, 403) @@ -2205,7 +2211,7 @@ class TestSupereventEMObservationList(SupereventSetup, GraceDbApiTestBase): def test_internal_user_create_emobservation(self): """Internal user can create EMObservations for all superevents""" - url = reverse('api:superevents:superevent-emobservation-list', + url = reverse('api:default:superevents:superevent-emobservation-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.internal_user, data=self.emobservation_data) @@ -2217,7 +2223,7 @@ class TestSupereventEMObservationList(SupereventSetup, GraceDbApiTestBase): def test_lvem_user_create_emobservation_for_hidden_superevent(self): """LV-EM user can't create EMObservations for hidden superevents""" - url = reverse('api:superevents:superevent-emobservation-list', + url = reverse('api:default:superevents:superevent-emobservation-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.lvem_user, data=self.emobservation_data) @@ -2225,7 +2231,7 @@ class TestSupereventEMObservationList(SupereventSetup, GraceDbApiTestBase): def test_lvem_user_create_emobservation_for_exposed_superevent(self): """LV-EM user can create EMObservations for exposed superevents""" - url = reverse('api:superevents:superevent-emobservation-list', + url = reverse('api:default:superevents:superevent-emobservation-list', args=[self.lvem_superevent.superevent_id]) response = self.request_as_user(url, "POST", self.lvem_user, data=self.emobservation_data) @@ -2237,7 +2243,7 @@ class TestSupereventEMObservationList(SupereventSetup, GraceDbApiTestBase): def test_public_user_create_emobservation_for_hidden_superevent(self): """Public user can't create EMObservations for hidden superevents""" - url = reverse('api:superevents:superevent-emobservation-list', + url = reverse('api:default:superevents:superevent-emobservation-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "POST", data=self.emobservation_data) @@ -2273,7 +2279,8 @@ class TestSupereventEMObservationDetail(SupereventSetup, GraceDbApiTestBase): """Internal user can get EMObservaion details for all superevents""" for s in Superevent.objects.all(): for emo in s.emobservation_set.all(): - url = reverse('api:superevents:superevent-emobservation-detail', + url = reverse(('api:default:superevents:' + 'superevent-emobservation-detail'), args=[s.superevent_id, emo.N]) response = self.request_as_user(url, "GET", self.internal_user) self.assertEqual(response.status_code, 200) @@ -2282,7 +2289,7 @@ class TestSupereventEMObservationDetail(SupereventSetup, GraceDbApiTestBase): def test_lvem_user_get_detail_for_hidden_superevent(self): """LV-EM user can't get EMObservation detail for hidden superevents""" emo = self.internal_superevent.emobservation_set.first() - url = reverse('api:superevents:superevent-emobservation-detail', + url = reverse('api:default:superevents:superevent-emobservation-detail', args=[self.internal_superevent.superevent_id, emo.N]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 404) @@ -2290,7 +2297,8 @@ class TestSupereventEMObservationDetail(SupereventSetup, GraceDbApiTestBase): def test_lvem_user_get_detail_for_exposed_superevent(self): """LV-EM user can get EMObservation details for exposed superevents""" for emo in self.lvem_superevent.emobservation_set.all(): - url = reverse('api:superevents:superevent-emobservation-detail', + url = reverse(('api:default:superevents:' + 'superevent-emobservation-detail'), args=[self.lvem_superevent.superevent_id, emo.N]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 200) @@ -2302,7 +2310,8 @@ class TestSupereventEMObservationDetail(SupereventSetup, GraceDbApiTestBase): Public user can't get any EMObservation details for hidden superevents """ emo = self.internal_superevent.emobservation_set.first() - url = reverse('api:superevents:superevent-emobservation-detail', + url = reverse(('api:default:superevents:' + 'superevent-emobservation-detail'), args=[self.internal_superevent.superevent_id, emo.N]) response = self.request_as_user(url, "GET") self.assertEqual(response.status_code, 403) @@ -2342,7 +2351,7 @@ class TestSupereventFileList(SupereventSetup, GraceDbApiTestBase): def test_internal_get_file_list_for_superevent(self): """Internal user can see all files for all superevents""" for s in Superevent.objects.all(): - url = reverse('api:superevents:superevent-file-list', + url = reverse('api:default:superevents:superevent-file-list', args=[s.superevent_id]) response = self.request_as_user(url, "GET", self.internal_user) self.assertEqual(response.status_code, 200) @@ -2357,7 +2366,7 @@ class TestSupereventFileList(SupereventSetup, GraceDbApiTestBase): def test_lvem_get_file_list_for_hidden_superevent(self): """LV-EM user can't get file list for hidden superevents""" - url = reverse('api:superevents:superevent-file-list', + url = reverse('api:default:superevents:superevent-file-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 404) @@ -2376,7 +2385,7 @@ class TestSupereventFileList(SupereventSetup, GraceDbApiTestBase): expose_log_to_lvem(log) # Make request and check response - url = reverse('api:superevents:superevent-file-list', + url = reverse('api:default:superevents:superevent-file-list', args=[self.lvem_superevent.superevent_id]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 200) @@ -2395,7 +2404,7 @@ class TestSupereventFileList(SupereventSetup, GraceDbApiTestBase): expose_log_to_lvem(log) # Make request and get response - url = reverse('api:superevents:superevent-file-list', + url = reverse('api:default:superevents:superevent-file-list', args=[self.lvem_superevent.superevent_id]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 200) @@ -2405,7 +2414,7 @@ class TestSupereventFileList(SupereventSetup, GraceDbApiTestBase): def test_public_get_file_list_for_hidden_superevent(self): """Public user can't get file list for hidden superevents""" - url = reverse('api:superevents:superevent-file-list', + url = reverse('api:default:superevents:superevent-file-list', args=[self.internal_superevent.superevent_id]) response = self.request_as_user(url, "GET") self.assertEqual(response.status_code, 403) @@ -2461,7 +2470,7 @@ class TestSupereventFileDetail(SupereventSetup, GraceDbApiTestBase): symlinks = list(set([fl.filename for fl in file_logs])) file_list.extend(symlinks) for f in file_list: - url = reverse('api:superevents:superevent-file-detail', + url = reverse('api:default:superevents:superevent-file-detail', args=[s.superevent_id, f]) response = self.request_as_user(url, "GET", self.internal_user) self.assertEqual(response.status_code, 200) @@ -2473,7 +2482,7 @@ class TestSupereventFileDetail(SupereventSetup, GraceDbApiTestBase): symlinks = list(set([fl.filename for fl in file_logs])) file_list.extend(symlinks) for f in file_list: - url = reverse('api:superevents:superevent-file-detail', + url = reverse('api:default:superevents:superevent-file-detail', args=[self.internal_superevent.superevent_id, f]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 404) @@ -2486,7 +2495,7 @@ class TestSupereventFileDetail(SupereventSetup, GraceDbApiTestBase): expose_log_to_lvem(log) # Make request and check response - url = reverse('api:superevents:superevent-file-detail', + url = reverse('api:default:superevents:superevent-file-detail', args=[self.lvem_superevent.superevent_id, log.versioned_filename]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 200) @@ -2496,7 +2505,7 @@ class TestSupereventFileDetail(SupereventSetup, GraceDbApiTestBase): log2 = self.lvem_superevent.log_set.get(filename= self.file1['filename'], file_version=0) # Make request and check response - url = reverse('api:superevents:superevent-file-detail', + url = reverse('api:default:superevents:superevent-file-detail', args=[self.lvem_superevent.superevent_id, log2.versioned_filename]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 404) @@ -2512,14 +2521,14 @@ class TestSupereventFileDetail(SupereventSetup, GraceDbApiTestBase): expose_log_to_lvem(log) # Make request and check response - url = reverse('api:superevents:superevent-file-detail', + url = reverse('api:default:superevents:superevent-file-detail', args=[self.lvem_superevent.superevent_id, log.versioned_filename]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 200) data1 = response.data # Repeat with non-versioned filename - url = reverse('api:superevents:superevent-file-detail', + url = reverse('api:default:superevents:superevent-file-detail', args=[self.lvem_superevent.superevent_id, log.filename]) response = self.request_as_user(url, "GET", self.lvem_user) self.assertEqual(response.status_code, 200) @@ -2532,7 +2541,7 @@ class TestSupereventFileDetail(SupereventSetup, GraceDbApiTestBase): symlinks = list(set([fl.filename for fl in file_logs])) file_list.extend(symlinks) for f in file_list: - url = reverse('api:superevents:superevent-file-detail', + url = reverse('api:default:superevents:superevent-file-detail', args=[self.internal_superevent.superevent_id, f]) response = self.request_as_user(url, "GET") self.assertEqual(response.status_code, 403) diff --git a/gracedb/superevents/api/tests/test_methods.py b/gracedb/api/v1/superevents/tests/test_methods.py similarity index 100% rename from gracedb/superevents/api/tests/test_methods.py rename to gracedb/api/v1/superevents/tests/test_methods.py diff --git a/gracedb/superevents/api/tests/utils.py b/gracedb/api/v1/superevents/tests/utils.py similarity index 100% rename from gracedb/superevents/api/tests/utils.py rename to gracedb/api/v1/superevents/tests/utils.py diff --git a/gracedb/superevents/api/view_templates.py b/gracedb/api/v1/superevents/url_templates.py similarity index 91% rename from gracedb/superevents/api/view_templates.py rename to gracedb/api/v1/superevents/url_templates.py index a070f926099091a9f453c7a82c01531169160ba8..ba3f0b609ab3cd22dc52e0200605081e59b9737f 100644 --- a/gracedb/superevents/api/view_templates.py +++ b/gracedb/api/v1/superevents/url_templates.py @@ -1,9 +1,10 @@ -from events.view_utils import reverse +from __future__ import absolute_import + from .views import SupereventViewSet, SupereventEventViewSet, \ SupereventLabelViewSet, SupereventLogViewSet, SupereventLogTagViewSet, \ SupereventFileViewSet, SupereventVOEventViewSet, \ SupereventEMObservationViewSet - +from ...utils import api_reverse # Placeholder parameters for getting URLs with reverse PH = { @@ -19,10 +20,10 @@ PH = { } -def construct_api_url_templates(request=None): +def construct_url_templates(request=None): # Bind our custom reverse for ease of use - sr = lambda view_name, args=[]: reverse('superevents:' + view_name, args=[ - PH[SupereventViewSet.lookup_url_kwarg]] + args, request=request) + sr = lambda view_name, args=[]: api_reverse('superevents:' + view_name, + args=[PH[SupereventViewSet.lookup_url_kwarg]] + args, request=request) # Dict of views and temporary arguments which will be passed to reverse views = { diff --git a/gracedb/superevents/api/urls.py b/gracedb/api/v1/superevents/urls.py similarity index 100% rename from gracedb/superevents/api/urls.py rename to gracedb/api/v1/superevents/urls.py diff --git a/gracedb/superevents/api/views.py b/gracedb/api/v1/superevents/views.py similarity index 95% rename from gracedb/superevents/api/views.py rename to gracedb/api/v1/superevents/views.py index c63036fa78f927f80ba8edd995333d48f502dcc6..16602f253080fc8ee874b87da1d521b290540cc4 100644 --- a/gracedb/superevents/api/views.py +++ b/gracedb/api/v1/superevents/views.py @@ -1,35 +1,28 @@ +from __future__ import absolute_import from collections import OrderedDict import logging import os from django.http import HttpResponse -from django.db.models import QuerySet, Max +from django.db.models import QuerySet from django.shortcuts import get_object_or_404 from guardian.shortcuts import get_objects_for_user from rest_framework import mixins, parsers, permissions, serializers, status, \ viewsets from rest_framework.decorators import action -from rest_framework.renderers import BaseRenderer, JSONRenderer, \ - BrowsableAPIRenderer -from rest_framework.permissions import IsAuthenticated -from rest_framework.views import APIView from rest_framework.response import Response +from rest_framework.views import APIView - -from ..models import Superevent, Log -from ..utils import remove_tag_from_log, remove_event_from_superevent, \ - 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 +from core.vfile import VersionedFile from events.models import Event, Label from events.view_utils import reverse as gracedb_reverse -#from events.api.views import IsAuthorizedForPipeline, LigoLwRenderer -from events.api.backends import LigoAuthentication - -from ..buildVOEvent import VOEventBuilderException +from superevents.buildVOEvent import VOEventBuilderException +from superevents.models import Superevent, Log +from superevents.utils import remove_tag_from_log, \ + remove_event_from_superevent, remove_label_from_superevent, \ + confirm_superevent_as_gw, get_superevent_by_date_id_or_404 from .base_viewsets import SupereventNestedViewSet from .filters import SupereventSearchFilter, SupereventOrderingFilter, \ DjangoObjectAndGlobalPermissionsFilter @@ -46,7 +39,9 @@ from .serializers import SupereventSerializer, SupereventUpdateSerializer, \ SupereventLogSerializer, SupereventLogTagSerializer, \ SupereventVOEventSerializer, SupereventEMObservationSerializer from .settings import SUPEREVENT_LOOKUP_URL_KWARG, SUPEREVENT_LOOKUP_REGEX +from ...utils import api_reverse +# Set up logger logger = logging.getLogger(__name__) @@ -279,7 +274,7 @@ class SupereventFileViewSet(SupereventNestedViewSet): # Compile sorted dict of filenames and links file_dict = OrderedDict((f, - gracedb_reverse('superevents:superevent-file-detail', + api_reverse('superevents:superevent-file-detail', args=[parent_superevent.superevent_id, f], request=request)) for f in sorted(file_list)) diff --git a/gracedb/api/v1/urls.py b/gracedb/api/v1/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..b4541713716dbf222a77b5ff54d002b29963f025 --- /dev/null +++ b/gracedb/api/v1/urls.py @@ -0,0 +1,26 @@ +from __future__ import absolute_import + +from django.conf.urls import url, include + +from .main.views import GracedbRoot, PerformanceInfo, TagList + + +urlpatterns = [ + # Root level API resources ------------------------------------------------ + # API root + url(r'^$', GracedbRoot.as_view(), name="root"), + + # Tags + url(r'^tag/', TagList.as_view(), name='tag-list'), + + # Performance stats + url(r'^performance/', PerformanceInfo.as_view(), name='performance-info'), + + # Events section of the API ----------------------------------------------- + url(r'^events/', include('api.v1.events.urls', + namespace='events')), + + # Superevents section of the API ------------------------------------------ + url(r'^superevents/', include('api.v1.superevents.urls', + namespace='superevents')), +] diff --git a/gracedb/api/versioning.py b/gracedb/api/versioning.py new file mode 100644 index 0000000000000000000000000000000000000000..a6299221b1e68cf27438b3334a2a3839eed58674 --- /dev/null +++ b/gracedb/api/versioning.py @@ -0,0 +1,40 @@ +import logging + +from rest_framework import versioning + +# Set up logger +logger = logging.getLogger(__name__) + + +class NestedNamespaceVersioning(versioning.NamespaceVersioning): + version_nest_level = 2 # starts with 1 + + def reverse(self, viewname, args=None, kwargs=None, request=None, + format=None, **extra): + if request.version is not None: + viewname = self.get_versioned_viewname(viewname, request) + return super(NestedNamespaceVersioning, self).reverse( + viewname, args, kwargs, request, format, **extra + ) + + def get_versioned_viewname(self, viewname, request=None): + # Split up viewname parts + viewname_parts = viewname.split(':') + namespaces = viewname_parts[:-1] + viewname_only = viewname_parts[-1] + + # Get version + if request and request.version: + version = request.version + else: + # The 'default_version' attribute is set by the BaseVersioning + # class + version = self.default_version + + # Add version into namespaces + if version not in namespaces: + namespaces.insert(self.version_nest_level - 1, version) + + versioned_viewname = ':'.join(namespaces + [viewname_only]) + return versioned_viewname + diff --git a/gracedb/core/middleware/api.py b/gracedb/core/middleware/api.py index 2d017eb9d7db6c9f483b4afb903799e636bf5338..71411c41dd9b3182522d31a34a279c85afb4e588 100644 --- a/gracedb/core/middleware/api.py +++ b/gracedb/core/middleware/api.py @@ -53,6 +53,8 @@ class ClientVersionMiddleware(object): # 3. If User-Agent header and not client_string, assume browser # and allow to pass request_allowed = True + # TODO: can we check the request's resolver match for the api namespace + # instead? That keeps things more DRY. if request.path.startswith('/api'): if (agent_header is None and not settings.ALLOW_BLANK_USER_AGENT_TO_API): diff --git a/gracedb/events/api/urls.py b/gracedb/events/api/urls.py deleted file mode 100644 index 579a58eb780f7024a5c4c7fa5fb975facfd02565..0000000000000000000000000000000000000000 --- a/gracedb/events/api/urls.py +++ /dev/null @@ -1,94 +0,0 @@ -# Changed for Django 1.11 -from django.conf.urls import url, include - -from .views import * - -urlpatterns = [ - url(r'^$', GracedbRoot.as_view(), name="api-root"), - - # Event Resources - # events/[{graceid}[/{version}]] - url(r'^events/$', EventList.as_view(), name='event-list'), - url(r'^events/(?P<graceid>[GEHMT]\d+)$', EventDetail.as_view(), - name='event-detail'), - - # Event Log Resources - # events/{graceid}/logs/[{logid}] - url(r'^events/(?P<graceid>[GEHMT]\d+)/log/$', EventLogList.as_view(), - name='eventlog-list'), - url(r'^events/(?P<graceid>[GEHMT]\d+)/log/(?P<n>\d+)$', - EventLogDetail.as_view(), name='eventlog-detail'), - - # VOEvent Resources - # events/{graceid}/voevent/[{serial_number}] - url(r'^events/(?P<graceid>[GEHMT]\d+)/voevent/$', VOEventList.as_view(), - name='voevent-list'), - url(r'^events/(?P<graceid>[GEHMT]\d+)/voevent/(?P<n>\d+)$', - VOEventDetail.as_view(), name='voevent-detail'), - - # EMBB Resources - # events/{graceid}/logs/[{logid}] - url(r'^events/(?P<graceid>[GEHMT]\d+)/embb/$', EMBBEventLogList.as_view(), - name='embbeventlog-list'), - url(r'^events/(?P<graceid>[GEHMT]\d+)/embb/(?P<n>\d+)$', - EMBBEventLogDetail.as_view(), name='embbeventlog-detail'), - url(r'^events/(?P<graceid>[GEHMT]\d+)/emobservation/$', - EMObservationList.as_view(), name='emobservation-list'), - url(r'^events/(?P<graceid>[GEHMT]\d+)/emobservation/(?P<n>\d+)$', - EMObservationDetail.as_view(), name='emobservation-detail'), -# url(r'events/(?P<graceid>[GEHMT]\d+)/emobservation/(?P<n>\d+)/emfootprint/$', -# EMFootprintList.as_view(), name='emfootprint-list'), -# url(r'events/(?P<graceid>[GEHMT]\d+)/emobservation/(?P<n>\d+)/emfootprint/(?P<m>\d+)$', -# EMFootprintDetail.as_view(), name='emfootprint-detail'), - - # Tag Resources - url(r'^tag/$', TagList.as_view(), name='tag-list'), - # XXX unclear what the tag detail resource should be. - #url(r'^tag/(?P<tagname>.+)$', TagDetail.as_view(), name='tag-detail'), - url(r'^events/(?P<graceid>[GEHMT]\d+)/tag/$', EventTagList.as_view(), - name='eventtag-list'), - url(r'^events/(?P<graceid>[GEHMT]\d+)/tag/(?P<tagname>.+)$', - EventTagDetail.as_view(), name='eventtag-detail'), - url(r'^events/(?P<graceid>[GEHMT]\d+)/log/(?P<n>\d+)/tag/$', - EventLogTagList.as_view(), name='eventlogtag-list'), - url(r'^events/(?P<graceid>[GEHMT]\d+)/log/(?P<n>\d+)/tag/(?P<tagname>.+)$', - EventLogTagDetail.as_view(), name='eventlogtag-detail'), - - # Permission Resources - url(r'^events/(?P<graceid>[GEHMT]\d+)/perms/$', - EventPermissionList.as_view(), name='eventpermission-list'), - url(r'^events/(?P<graceid>[GEHMT]\d+)/perms/(?P<group_name>.+)/$', - GroupEventPermissionList.as_view(), name='groupeventpermission-list'), - url(r'^events/(?P<graceid>[GEHMT]\d+)/perms/(?P<group_name>.+)/(?P<perm_shortname>\w+)$', - GroupEventPermissionDetail.as_view(), name='groupeventpermission-detail'), - - # Event File Resources - # events/{graceid}/files/[{filename}[/{version}]] - url(r'^events/(?P<graceid>\w[\d]+)/files/(?P<filename>.+)?$', - Files.as_view(), name="files"), - - # Event Labels - # events/{graceid}/labels/[{label}] - url(r'^events/(?P<graceid>\w[\d]+)/labels/(?P<label>.+)?$', - EventLabel.as_view(), name="labels"), - - # Event Neighbors - # events/{graceid}/neighbors/[?delta=(N|(N,N))] - url(r'^events/(?P<graceid>\w[\d]+)/neighbors/$', EventNeighbors.as_view(), - name="neighbors"), - - # Operator Signoff Resources - url(r'^events/(?P<graceid>[GEHMT]\d+)/signoff/$', - OperatorSignoffList.as_view(), name='signoff-list'), - - # Performance stats - url(r'^performance/$', PerformanceInfo.as_view(), name='performance-info'), - - # Legacy - url(r'^event/(?P<graceid>\w[\d]+)/files/(?P<filename>.+)?$', - Files.as_view(), name="file-download"), - - # Superevents - url(r'^superevents/', include('superevents.api.urls', - namespace='superevents')), -] diff --git a/gracedb/events/buildVOEvent.py b/gracedb/events/buildVOEvent.py index baa2119270f14ba965a4f99a30ba1d6078c0d0e4..287f4c54205fe5daf56a63f7d3f559c53a52c14f 100644 --- a/gracedb/events/buildVOEvent.py +++ b/gracedb/events/buildVOEvent.py @@ -296,14 +296,18 @@ def buildVOEvent(event, serial_number, voevent_type, request=None, skymap_filena shib_png_skymap_url = get_url(request, objid, "file-download", img_name) # x509 urls. Hafta specify the api namespace. - x509_fits_skymap_url = get_url(request, objid, "x509:files", fits_name) + x509_fits_skymap_url = get_url(request, objid, + "x509:default:events:files", fits_name) if img_name: - x509_png_skymap_url = get_url(request, objid, "x509:files", img_name) + x509_png_skymap_url = get_url(request, objid, + "x509:default:events:files", img_name) # basic urls. Hafta specify the api namespace. - basic_fits_skymap_url = get_url(request, objid, "basic:files", fits_name) + basic_fits_skymap_url = get_url(request, objid, + "basic:default:events:files", fits_name) if img_name: - basic_png_skymap_url = get_url(request, objid, "basic:files", img_name) + basic_png_skymap_url = get_url(request, objid, + "basic:default:events:files", img_name) # Add parameters to the skymap group diff --git a/gracedb/events/view_utils.py b/gracedb/events/view_utils.py index 4e2b9a5f1978a8f360e2f9c222710a1a63da4e46..e8d344de4e5bc07864120da84c246a6cbf168a7f 100644 --- a/gracedb/events/view_utils.py +++ b/gracedb/events/view_utils.py @@ -1,4 +1,4 @@ - +from __future__ import absolute_import from django.http import HttpResponse, HttpResponseBadRequest from django.urls import reverse as django_reverse from django.utils import dateformat @@ -11,6 +11,7 @@ from .models import SingleInspiral, Event, Search, Group from core.urls import build_absolute_uri from core.vfile import VersionedFile from .permission_utils import is_external +from api.utils import api_reverse from django.db.models import Q import os @@ -351,13 +352,13 @@ def eventToDict(event, columns=None, request=None): # Links rv['links'] = { - "neighbors" : reverse("neighbors", args=[graceid], request=request), - "log" : reverse("eventlog-list", args=[graceid], request=request), - "emobservations" : reverse("emobservation-list", args=[graceid], request=request), - "files" : reverse("files", args=[graceid], request=request), - "labels" : reverse("labels", args=[graceid], request=request), - "self" : reverse("event-detail", args=[graceid], request=request), - "tags" : reverse("eventtag-list", args=[graceid], request=request), + "neighbors" : api_reverse("events:neighbors", args=[graceid], request=request), + "log" : api_reverse("events:eventlog-list", args=[graceid], request=request), + "emobservations" : api_reverse("events:emobservation-list", args=[graceid], request=request), + "files" : api_reverse("events:files", args=[graceid], request=request), + "labels" : api_reverse("events:labels", args=[graceid], request=request), + "self" : api_reverse("events:event-detail", args=[graceid], request=request), + "tags" : api_reverse("events:eventtag-list", args=[graceid], request=request), } return rv @@ -367,10 +368,10 @@ def eventLogToDict(log, request=None): file_uri = None # Get some links - uri = reverse("eventlog-detail", + uri = api_reverse("events:eventlog-detail", args=[log.event.graceid(), log.N], request=request) - taglist_uri = reverse("eventlogtag-list", + taglist_uri = api_reverse("events:eventlogtag-list", args=[log.event.graceid(), log.N], request=request) if log.filename: @@ -382,7 +383,7 @@ def eventLogToDict(log, request=None): # escaping twice results in wrong urls. #filename = urlquote(actual_filename) filename = actual_filename - file_uri = reverse("files", + file_uri = api_reverse("events:files", args=[log.event.graceid(), filename], request=request) @@ -422,7 +423,7 @@ def labelToDict(labelling, request=None): "creator" : labelling.creator.username, "created" : labelling.created.strftime( settings.GRACE_STRFTIME_FORMAT), - "self" : reverse("labels", + "self" : api_reverse("events:labels", args=[labelling.event.graceid(), labelling.label.name], request=request), } @@ -431,7 +432,7 @@ def labelToDict(labelling, request=None): def embbEventLogToDict(eel, request=None): uri = None if request: - uri = reverse("embbeventlog-detail", + uri = api_reverse("events:embbeventlog-detail", args=[eel.event.graceid(), eel.N], request=request) return { @@ -467,7 +468,7 @@ def embbEventLogToDict(eel, request=None): # EMObservation serializer. def emObservationToDict(emo, request=None): - uri = reverse("emobservation-detail", + uri = api_reverse("events:emobservation-detail", args=[emo.event.graceid(), emo.N], request=request) @@ -492,7 +493,7 @@ def emObservationToDict(emo, request=None): def emFootprintToDict(emf, request=None): # uri = None # if request: -# uri = reverse("emfootprint-detail", +# uri = api_reverse("events:emfootprint-detail", # args=[emf.emobservation.event.graceid(), emf.emobservation.N, emf.N], # request=request) @@ -513,7 +514,7 @@ def emFootprintToDict(emf, request=None): # XXX Eventually hope to remove this # EMObservation serializer for the skymap Viewer def skymapViewerEMObservationToDict(emo, request=None): - uri = reverse("emobservation-detail", + uri = api_reverse("events:emobservation-detail", args=[emo.event.graceid(), emo.N], request=request) @@ -574,10 +575,10 @@ def voeventToDict(voevent, request=None): #filename = urlquote('%s,%d' % (voevent.filename, voevent.file_version)) filename = '%s,%d' % (voevent.filename, voevent.file_version) - uri = reverse("voevent-detail", + uri = api_reverse("events:voevent-detail", args=[voevent.event.graceid(), voevent.N], request=request) - file_uri = reverse("files", + file_uri = api_reverse("events:files", args=[voevent.event.graceid(), filename], request=request) diff --git a/gracedb/superevents/api/settings.py b/gracedb/superevents/api/settings.py deleted file mode 100644 index 277c5e7e2cd88348f8b2bf53f3e110782db74c03..0000000000000000000000000000000000000000 --- a/gracedb/superevents/api/settings.py +++ /dev/null @@ -1,5 +0,0 @@ -from ..models import Superevent - -SUPEREVENT_LOOKUP_URL_KWARG = 'superevent_id' -SUPEREVENT_LOOKUP_REGEX = Superevent.ID_REGEX - diff --git a/gracedb/superevents/api/tests/__init__.py b/gracedb/superevents/api/tests/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/gracedb/superevents/buildVOEvent.py b/gracedb/superevents/buildVOEvent.py index 6400e55847359b62dba7211b3d0e6d71bcd830fb..9777b988ade739ecce5e401eace2240abd6f2778 100644 --- a/gracedb/superevents/buildVOEvent.py +++ b/gracedb/superevents/buildVOEvent.py @@ -276,12 +276,17 @@ def construct_voevent_file(superevent, voevent, request=None, # shib, x509, and basic API urls for fits skymap file # Temp function for reversing superevent file detail API resource file_abs_reverse = lambda ns, file_name: build_absolute_uri( - reverse(ns + ":superevents:superevent-file-detail", + reverse(ns + ":default:superevents:superevent-file-detail", args=[superevent.superevent_id, file_name]), request) - shib_fits_skymap_url = file_abs_reverse('shib', fits_name) + shib_fits_skymap_url = build_absolute_uri( + reverse("superevents:file-download", + args=[superevent.superevent_id, fits_name]), request) x509_fits_skymap_url = file_abs_reverse('x509', fits_name) basic_fits_skymap_url = file_abs_reverse('basic', fits_name) if img_name: + shib_fits_skymap_url = build_absolute_uri( + reverse("superevents:file-download", + args=[superevent.superevent_id, img_name]), request) shib_png_skymap_url = file_abs_reverse('shib', img_name) x509_png_skymap_url = file_abs_reverse('x509', img_name) basic_png_skymap_url = file_abs_reverse('basic', img_name) diff --git a/gracedb/templates/gracedb/event_detail_script.js b/gracedb/templates/gracedb/event_detail_script.js index 8e7ecaf37e4c8e01c02e0109dd21f44ba0439710..7f7268bd6e225d3d48d6e7225ce53fbe5369d79b 100644 --- a/gracedb/templates/gracedb/event_detail_script.js +++ b/gracedb/templates/gracedb/event_detail_script.js @@ -156,14 +156,14 @@ var hasImage = function(object) { } // some URLs. Usage of Django template syntax should be limited to here -var tagListUrl = '{% url "shib:tag-list" %}'; +var tagListUrl = '{% url "shib:default:tag-list" %}'; var tagUrlPattern = '{% url "taglogentry" object.graceid "000" "temp" %}'; -var eventLogListUrl = '{% url "shib:eventlog-list" object.graceid %}'; +var eventLogListUrl = '{% url "shib:default:events:eventlog-list" object.graceid %}'; var eventLogSaveUrl = '{% url "logentry" object.graceid "" %}'; -var embbEventLogListUrl = '{% url "shib:embbeventlog-list" object.graceid %}'; -var emObservationListUrl = '{% url "shib:emobservation-list" object.graceid %}'; +var embbEventLogListUrl = '{% url "shib:default:events:embbeventlog-list" object.graceid %}'; +var emObservationListUrl = '{% url "shib:default:events:emobservation-list" object.graceid %}'; var fileDownloadUrl = '{% url "file-download" object.graceid "FAKE_FILE_NAME" %}'; -var skymapJsonUrl = '{% url "shib:files" object.graceid "" %}'; +var skymapJsonUrl = '{% url "shib:default:events:files" object.graceid "" %}'; var skymapViewerUrl = '{{ SKYMAP_VIEWER_SERVICE_URL }}'; // This little list determines the priority ordering of the digest sections. diff --git a/gracedb/templates/gracedb/index.html b/gracedb/templates/gracedb/index.html index fe7a0125feb30cbd5b1dea6f97d07c8d919d29ac..f6f2cfd18528f4ee788dc8d99c8184c1055bc9c0 100644 --- a/gracedb/templates/gracedb/index.html +++ b/gracedb/templates/gracedb/index.html @@ -81,7 +81,7 @@ follow-ups. </p> <!-- <li><a href="https://www.lsc-group.phys.uwm.edu/daswg/wiki/GraceDBER6">Recent changes</a> <font color="red">(IMPORTANT!) </font></li> --> <!-- <li><a href="https://gw-astronomy.org/wiki/LV_EM/ElectroMagneticBulletinBoard">Prototype EMBB description</a></li> --> <li><a href="https://wiki.ligo.org/DASWG/GraceDB">Project page on wiki.ligo.org</a></li> -<li><a href="{% url "shib:api-root" %}">Browseable REST API</a> +<li><a href="{% url "shib:default:root" %}">Browseable REST API</a> <li><a href="https://gw-astronomy.org/wiki/LV_EM/TechInfo">LV-EM Technical Info</a></li> <li><a href="https://dcc.ligo.org/G1501296">Tutorial for operators and detector engineers</a></li> diff --git a/gracedb/templates/profile/manage_password.html b/gracedb/templates/profile/manage_password.html index fb62b6fa21915aa3a9b8a4b6c748010fd50ec95b..4c5698b389947c3943fba0b8cff7b95f617077c6 100644 --- a/gracedb/templates/profile/manage_password.html +++ b/gracedb/templates/profile/manage_password.html @@ -6,7 +6,7 @@ {% block content %} -<p>Passwords generated here are intended only for scripted access to GraceDB by LV-EM users. Your password allows access to the <a href={% url "basic:api-root" %}>REST API</a>.</p> +<p>Passwords generated here are intended only for scripted access to GraceDB by LV-EM users. Your password allows access to the <a href={% url "basic:default:root" %}>REST API</a>.</p> <p> Your username is: <b>{{ username }}</b></p> {% if has_password %} diff --git a/gracedb/templates/superevents/superevent_detail_script.js b/gracedb/templates/superevents/superevent_detail_script.js index 373c2d52c2d30f29884ba11f6e27a04a7252c3ed..89320153f7d10d6f78738484dcb6c4b031aa5467 100644 --- a/gracedb/templates/superevents/superevent_detail_script.js +++ b/gracedb/templates/superevents/superevent_detail_script.js @@ -156,12 +156,12 @@ var hasImage = function(object) { } // some URLs. Usage of Django template syntax should be limited to here -var tagListUrl = '{% url "shib:tag-list" %}'; -var tagCreateUrlPattern = '{% url "shib:superevents:superevent-log-tag-list" superevent.superevent_id "000" %}'; -var tagDeleteUrlPattern = '{% url "shib:superevents:superevent-log-tag-detail" superevent.superevent_id "000" "FAKE_TAG_NAME" %}'; -var logListUrl = '{% url "shib:superevents:superevent-log-list" superevent.superevent_id %}'; -var logSaveUrl = '{% url "shib:superevents:superevent-log-list" superevent.superevent_id %}'; -var emObservationListUrl = '{% url "shib:superevents:superevent-emobservation-list" superevent.superevent_id %}'; +var tagListUrl = '{% url "shib:default:tag-list" %}'; +var tagCreateUrlPattern = '{% url "shib:default:superevents:superevent-log-tag-list" superevent.superevent_id "000" %}'; +var tagDeleteUrlPattern = '{% url "shib:default:superevents:superevent-log-tag-detail" superevent.superevent_id "000" "FAKE_TAG_NAME" %}'; +var logListUrl = '{% url "shib:default:superevents:superevent-log-list" superevent.superevent_id %}'; +var logSaveUrl = '{% url "shib:default:superevents:superevent-log-list" superevent.superevent_id %}'; +var emObservationListUrl = '{% url "shib:default:superevents:superevent-emobservation-list" superevent.superevent_id %}'; var fileDownloadUrl = '{% url "superevents:file-download" superevent.superevent_id "FAKE_FILE_NAME" %}'; var skymapViewerUrl = '{{ SKYMAP_VIEWER_SERVICE_URL }}';