Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
views.py 31.66 KiB

from django.http import HttpResponse
from django.http import HttpResponseRedirect, HttpResponseNotFound, Http404
from django.template import RequestContext
from django.core.urlresolvers import reverse, get_script_prefix
from django.shortcuts import render_to_response
from django.contrib.sites.models import Site
from django.utils.html import strip_tags, escape, urlize
from django.utils.safestring import mark_safe

from django.views.generic.list_detail import object_detail, object_list

from models import Event, Group, EventLog, Labelling, Label, User
from forms import CreateEventForm, EventSearchForm, SimpleSearchForm
from alert import issueAlert, issueAlertForLabel, issueAlertForUpdate
from translator import handle_uploaded_data

import urllib

import os
import re
from django.core.mail import mail_admins
from django.conf import settings

from buildVOEvent import buildVOEvent, submitToSkyalert

# XXX This should be configurable / moddable or something
MAX_QUERY_RESULTS = 1000

GRACEDB_DATA_DIR = settings.GRACEDB_DATA_DIR

import simplejson

def index(request):
#   assert request.ligouser
    return render_to_response(
            'gracedb/index.html',
            {},
            context_instance=RequestContext(request))

def skyalert_authorized(request):
    try:
        return request.ligouser.name in settings.SKYALERT_SUBMITTERS
    except:
        return False

def voevent(request, graceid):
    event = Event.getByGraceid(graceid)
    return HttpResponse(buildVOEvent(event), content_type="application/xml")


def skyalert(request, graceid):
    event = Event.getByGraceid(graceid)
    createLogEntry = True

    if not event.gpstime:
        request.session['flash_msg'] = "No GPS time.  Event not suitable for submission to SkyAlert"
        return HttpResponseRedirect(reverse(view, args=[graceid]))

    if not skyalert_authorized(request):
        request.session['flash_msg'] = "You are not authorized for SkyAlert submission"
        return HttpResponseRedirect(reverse(view, args=[graceid]))

    try:
        skyalert_response = submitToSkyalert(event)
    except Exception, e:
        message = "SkyAlert Submission Error"
        skyalert_response = ""
        mail_admins("SkyAlert Submission Error",
                    "Event: %s\nExcption: %s\n" % (graceid, e),
                    fail_silently=True)

    if skyalert_response.find("Success") >= 0:
        urlpat = re.compile('https://[^ ]*')
        match = urlpat.search(skyalert_response)
        if match:
            message = "Submitted to Skyalert: %s" % match.group()
        else:
            message = "SkyAlert submission problem.  Cannot parse SkyAlert response."
            mail_admins("SkyAlert response parsing problem",
                        "Event: %s\nSkyAlert Response: %s\n" % (graceid, skyalert_response),
                        fail_silently=True)
    elif skyalert_response.find('already') >= 0:
            message = "Event already submitted to SkyAlert"
            createLogEntry = False
    elif skyalert_response:
        message = "Skyalert Submission Failed."
        mail_admins("SkyAlert submission failed",
                    "Event: %s\nSkyAlert Response: %s\n" % (graceid, skyalert_response),
                    fail_silently=True)

    request.session['flash_msg'] = message

    if createLogEntry:
        logentry = EventLog(event=event, issuer=request.ligouser, comment=message)
        logentry.save()

    return HttpResponseRedirect(reverse(view, args=[graceid]))


def badskyalert(request, graceid):
    event = Event.getByGraceid(graceid)

    if not event.gpstime:
        request.session['flash_msg'] = "No GPS time.  Event not suitable for submission to SkyAlert"
        return HttpResponse("Ugh no gpstime")
        return HttpResponseRedirect(reverse(view, args=[graceid]))

    logentry = EventLog(event=event, issuer=request.ligouser, comment="TRYING TO SUMIT TO SKYALERT")
    logentry.save()

    skyalert_response = submitToSkyalert(event, validate_only="False")

    if skyalert_response.find("Success") >= 0:
        urlpat = re.compile('https://[^ ]*')
        match = urlpat.search(skyalert_response)
        if match:
            try:
                skyalert_url = match.group()
            except:
                skyalert_url = "fail match"
            comment = "Submitted to SkyALert: %s" % skyalert_url
            logentry = EventLog(event=event, issuer=request.ligouser, comment=comment)
            logentry.save()
            request.session['flash_msg'] = comment
            return HttpResponse("OK " + skyalert_response + skyalert_url + logentry.comment)
        else:
            request.session['flash_msg'] = "Problem parsing skyalert response"
            return HttpResponse('problem ' + skyalert_response)
    elif skyalert_response.find('already found') >= 0:
        request.session['flash_msg'] = "Event already submitted to SkyAlert " + skyalert_response
        return HttpResponse('already done ' + skyalert_response)
    else:
        return HttpResponse('problem2 ' + skyalert_response)
        request.session['flash_msg'] = "Unknown problem submitting to SkyAlert -- %s" % skyalert_response

    #return HttpResponseRedirect(reverse(view, args=[graceid]))
    return HttpResponse('how did we get here? ' + skyalert_response)
    return view(request, graceid)

def create(request):
    d = _create(request)
    if isinstance(d, HttpResponse):
        return d
    elif 'cli' in request.POST:
        if 'cli_version' in request.POST:
            # XXX Risky.  msg should be json, not str.
            # str(x) is *often* the same as json(x), but not always.
            # It's not, because we don't reliably have json on the client side.
            response = HttpResponse(mimetype='application/json')
            if 'graceid' in d:
                d['output'] = "%s" % d['graceid']
                d['graceid'] = "%s" % d['graceid']
            msg = str(d)
        else: # Old client
            response = HttpResponse(mimetype='text/plain')
            if 'error' in d:
                msg = "ERROR: " + d['error']
            elif 'warning' in d:
                msg = "ERROR: " + d['warning']
            else:
                msg = d['graceid']
        response.write(msg)
        response['Content-length'] = len(msg)
        return response
    else:
        return render_to_response('gracedb/create.html',
                    d,
                    context_instance=RequestContext(request))

def _create(request):
    assert request.ligouser

    rv = {}

    if request.method == "GET":
        rv['form'] = CreateEventForm()
    else:
        form = CreateEventForm(request.POST, request.FILES)
        if form.is_valid():
            event, warnings = _createEventFromForm(request, form)
            if 'cli' not in request.POST:
                if not event:
                    # problem creating event...  XXX need an error page for this.
                    raise Exception("\n".join(warnings))
                return HttpResponseRedirect(reverse(view, args=[event.graceid()]))
            if event:
                rv['graceid'] = str(event.graceid())
                if warnings:
                    rv['warning'] = "\n".join(warnings)
            else:
                rv['error'] = "\n".join(warnings)
        else:
            if 'cli' not in request.POST:
                rv['form'] = form
            else:
                # Error occurred in command line client.
                # Most likely group name is wrong.
                # XXX the form should have info about what is wrong.
                #groupname = request.POST.get('group', None)
                #group = Group.objects.filter(name=groupname)
                #if not group:
                #    validGroups = [group.name for group in Group.objects.all()]
                #    msg = "Group must be one of: %s" % ", ".join(validGroups)
                #else:
                #    msg = "Malformed request"
                #rv['error'] = msg
                rv['error'] = ""
                for key in form.errors:
                    # as_text() not str() otherwise we get HTML.
                    rv['error'] += "%s: %s\n" % (key, form.errors[key].as_text())
    return rv

def _createEventFromForm(request, form):
    saved = False
    warnings = []
    try:
        group = Group.objects.filter(name=form.cleaned_data['group'])
        type = form.cleaned_data['type']
        # Create Event
        event = Event()
        event.submitter = request.ligouser
        event.group = group[0]
        event.analysisType = type
        #  ARGH.  We don't get a graceid until we save,
        #  but we don't know in advance if we can actually
        #  create all the things we need for success!
        #  What to do?!
        event.save()
        saved = True  # in case we have to undo this.
        # Create data directory/directories
        #    Save uploaded file.
        dirPrefix = GRACEDB_DATA_DIR
        eventDir = os.path.join(dirPrefix, event.graceid())
        os.mkdir( eventDir )
        os.mkdir( os.path.join(eventDir,"private") )
        os.mkdir( os.path.join(eventDir,"general") )
        #os.chmod( os.path.join(eventDir,"general"), int("041777",8) )
        os.chmod( os.path.join(eventDir,"general"), 041777 )
        f = request.FILES['eventFile']
        uploadDestination = os.path.join(eventDir, "private", f.name)
        fdest = open(uploadDestination, 'w')
        # Save uploaded file into user private area.
        for chunk in f.chunks():
            fdest.write(chunk)
        fdest.close()
        # Create WIKI page
        createWikiPage(event.graceid())

        # Extract Info from uploaded data
        # Temp (ha!) hack to deal with
        # out of band data from Omega to LUMIN.
        try:
            temp_data_loc = handle_uploaded_data(event, uploadDestination)
            try:
                # Send an alert.
                issueAlert(event,
                           os.path.join(event.clusterurl(), "private", f.name),
                           temp_data_loc)
            except Exception, e:
                warnings += ["Problem issuing an alert (%s)" % e]
        except Exception, e:
            warnings += ["Problem scanning data. No alert issued (%s)" % e]
        #return HttpResponseRedirect(reverse(view, args=[event.graceid()]))
    except Exception, e:
        # something went wrong.
        # XXX We need to make sure we clean up EVERYTHING.
        # We don't.  Wiki page and data directories remain.
        # According to Django docs, EventLog entries cascade on delete.
        # Also, we probably want to keep track of what's failing
        # and send out an email (or something)
        if saved:
            # undo save.
            event.delete()
        warnings += ["Problem creating event (%s)" % e]
        event = None
    return event, warnings

def _saveUploadedFile(event, uploadedFile):
    # XXX Hardcoding.
    fname = os.path.join(GRACEDB_DATA_DIR, event.graceid(), "private", uploadedFile.name)
    f = open(fname, "w")
    for chunk in uploadedFile.chunks():
        f.write(chunk)
    f.close()

def _createLog(request, graceid, comment, uploadedFile=None):
    response = HttpResponse(mimetype='application/json')
    rdict = {}

    try:
        event = graceid and Event.getByGraceid(graceid)
    except Event.DoesNotExist:
        event = None

    if not event:
        rdict['error'] = "No such event id: %s" % graceid
    elif (not comment) and (not uploadedFile):
        rdict['error'] = "Missing argument(s)"
    else:
        logEntry = EventLog(event=event,
                            issuer=request.ligouser,
                            comment=comment)
        if uploadedFile:
            try:
                _saveUploadedFile(event, uploadedFile)
                logEntry.filename = uploadedFile.name
            except Exception, e:
                rdict['error'] = "Problem saving file: %s" % str(e)
        logEntry.save()

        if request.POST.get('alert') == "True":
            description = "LOG: "
            if uploadedFile:
                description = "UPLOAD: '%s' " % uploadedFile.name
            issueAlertForUpdate(event, description+comment, doxmpp=True)

    # XXX should be json
    rval = str(rdict)
    response['Content-length'] = len(rval)
    response.write(rval)
    return response

def upload(request):
    graceid = request.POST.get('graceid', None)
    comment = request.POST.get('comment', None)
    uploadedfile = request.FILES['upload']

    if 'cli_version' in request.POST:
        return _createLog(request, graceid, comment, uploadedfile)

    # else: old, old client
    response = HttpResponse(mimetype='text/plain')
    try:
        event = graceid and Event.getByGraceid(graceid)
    except Event.DoesNotExist:
        event = None
    # uploadedFile.{name/chunks()}
    if not (comment and uploadedfile and graceid):
        msg = "ERROR: missing arg(s)"
    elif not event:
        msg = "ERROR: Event '%s' does not exist" % graceid
    else:
        #event issuer comment
        log = EventLog(event=event,
                       issuer=request.ligouser,
                       filename=uploadedfile.name,
                       comment=comment)
        try:
            log.save()
            msg = "OK"
        except:
            msg = "ERROR: problem creating log entry"
        try:
            # XXX
            # Badnesses:
            #   Same hardcoded path in multiple places.
            #   What if we're clobbering an existing file?
            fname = os.path.join(GRACEDB_DATA_DIR, event.graceid(), "private", uploadedfile.name)
            f = open(fname, "w")
            for chunk in uploadedfile.chunks():
                f.write(chunk)
            f.close()
        except Exception, e:
            msg = "ERROR: could not save file " + fname + " " + str(e)
            log.delete()
    response = HttpResponse(mimetype='text/plain')
    response.write(msg)
    response['Content-length'] = len(msg)
    return response

def cli_tag(request):
    raise Exception("tag is not implemented.  Maybe you're thinking of 'label'?")
    graceid = request.POST.get('graceid')
    tagname = request.POST.get('tag')

    event = graceid and Event.getByGraceid(graceid)
    event.add_tag(tagname)

    msg = str({})
    response = HttpResponse(mimetype='application/json')
    response.write(msg)
    response['Content-length'] = len(msg)

    return response

def cli_label(request):
    graceid = request.POST.get('graceid')
    labelName = request.POST.get('label')

    d = {}
    event = graceid and Event.getByGraceid(graceid)
    
    try:
        label = Label.objects.filter(name=labelName)[0]
    except IndexError:
        raise ValueError("No such Label '%s'" % labelName)

    # Don't add a label more than once.
    if label in event.labels.all():
            d['warning'] = "Event %s already labeled with '%s'" % (event.graceid(), labelName)
    else:
        labelling = Labelling(
                event = event,
                label = label,
                creator = request.ligouser
            )
        labelling.save()
        message = "Label: %s" % label.name
        log = EventLog(event=event, issuer=request.ligouser, comment=message)
        log.save()

        try:
            doxmpp = request.POST.get('alert') == "True"
            issueAlertForLabel(event, label, doxmpp)
        except Exception, e:
            d['warning'] = "Problem issuing alert (%s)" % str(e)

    msg = str(d)
    response = HttpResponse(mimetype='application/json')
    response.write(msg)
    response['Content-length'] = len(msg)

    return response

def log(request):
    message = request.POST.get('message')
    graceid = request.POST.get('graceid')

    if 'cli_version' in request.POST:
        return _createLog(request, graceid, message)

    # old, old client only
    response = HttpResponse(mimetype='text/plain')
    try:
        event = graceid and Event.getByGraceid(graceid)
    except Event.DoesNotExist:
        event = None

    if not (message and graceid):
        msg = "ERROR: missing arg(s)"
    elif not event:
        msg = "ERROR: Event '%s' does not exist" % graceid
    else:
        #event issuer comment
        log = EventLog(event=event, issuer=request.ligouser, comment=message)
        try:
            log.save()
            msg = "OK"
        except:
            msg = "ERROR: problem creating log entry"

    response = HttpResponse(mimetype='text/plain')
    response.write(msg)
    response['Content-length'] = len(msg)
    return response

def ping(request):
    #ack = "(%s) " % Site.objects.get_current()
    ack = "(%s) " % request.META['SERVER_NAME']
    ack += request.POST.get('ack', None) or request.GET.get('ack','ACK')

    from templatetags.timeutil import utc
    if 'cli_version' in request.POST:
        response = HttpResponse(mimetype='application/json')
        d = {'output': ack}
        if 'extended' in request.POST:
            latest = Event.objects.order_by("-id")[0]
            d['latest'] = {}
            d['latest']['id'] = latest.graceid()
            d['latest']['created'] = str(utc(latest.created))
        d =  simplejson.dumps(d)
        response.write(d)
        response['Content-length'] = len(d)
    else:
        # Old client
        response = HttpResponse(mimetype='text/plain')
        response.write(ack)
        response['Content-length'] = len(ack)
    return response

def view(request, graceid):
    context = {}
    try:
        a = Event.getByGraceid(graceid)
    except Event.DoesNotExist:
        raise Http404
    context['object'] = a
    context['eventdesc'] = get_file(graceid, "event.log")
    context['userdesc'] = get_file(graceid, "user.log")
    context['nearby'] = [(event.gpstime - a.gpstime, event)
                            for event in a.neighbors()]
    context['skyalert_authorized'] = skyalert_authorized(request)
    return render_to_response(
        'gracedb/event_detail.html',
        context,
        context_instance=RequestContext(request))

def cli_search(request):
    assert request.ligouser
    form = SimpleSearchForm(request.POST)
    if form.is_valid():
        query = form.cleaned_data['query']
        objects = Event.objects.filter(query).distinct()
        # Assemble the output... should be able to choose format.
        outTable = ["#graceid\tlabels\tgroup\ttype\tgpstime\tcreatetime\turl"]
        outTable += [
            "%s\t%s\t%s\t%s\t%s\t%s\t%s" % (
                e.graceid(),
                ",".join([labelling.label.name for labelling in e.labelling_set.all()]),
                e.group,
                e.get_analysisType_display(),
                e.gpstime or "",
                e.created,
                e.weburl(),
            )
            for e in objects
        ]
        d = {'output': "\n".join(outTable)}
    else:
        d = {'error': ""}
        for key in form.errors:
            d['error'] += "%s: %s\n" % (key, strip_tags(form.errors[key]))
    response = HttpResponse(mimetype='application/javascript')
    msg = simplejson.dumps(d)
    response['Content-length'] = len(msg)
    response.write(msg)
    return response

def search(request, format=""):
    assert request.ligouser
    # XXX DO NOT HARDCODE THIS
    # Also, user should be notified if their result hits this limit.
    limit = MAX_QUERY_RESULTS
    form2 = None

    # This block is crap and for debugging.  Remove it!
    if False and format == "flex":
        response = HttpResponse(mimetype='application/json')
        rows = [
                { 'id': 1, 'cell': 
                    [ "G0966", "", "CBC", "MBTAOnline", 9382382, "Data Wiki", "today!"]
                    },
                { 'id': 2, 'cell':
                    [ "G0967", "", "CBC", "MBTAOnline", 9382382, "Data Wiki", "today!"]
                    },
                { 'id': 3, 'cell':
                    [ "G0968", "", "CBC", "MBTAOnline", 9382382, "Data Wiki", "today!"]
                    },
            ]
        d = {
                'page': 1, #self.page,
                'total': 1,
                'records' : 3,
                'rows': rows
            }
        msg = simplejson.dumps(d)
        response['Content-length'] = len(msg)
        response.write(msg)

        #query = request.POST['query']
        # ???!!!
        query = "blah"

        return response

    if request.method == "GET" and "query" not in request.GET:
        form = SimpleSearchForm()
        form2 = EventSearchForm()
    else:
        if request.method == "POST" and 'query' not in request.POST:
            return oldsearch(request)
        if request.method == "GET":
            form = SimpleSearchForm(request.GET)
            rawquery = request.GET['query']
        else:
            form = SimpleSearchForm(request.POST)
            rawquery = request.POST['query']
        if form.is_valid():
            query = form.cleaned_data['query']

            objects = Event.objects.filter(query).distinct()

            if format == "json":
                return HttpResponse("Not Implemented")
            elif format == "flex":
                # Flexigrid request.
                return flexigridResponse(request, objects)
            elif format == "jqgrid":
                return jqgridResponse(request, objects)
            else:
                #objects = objects[:limit]
                #if objects.count() >= limit:
                #    request.session['flash_msg'] = \
                #        "Number of events in results exceeds maximum (%s) allowed." % limit
                if objects.count() == 1:
                    title = "Query Results. %s event" % objects.count()
                else:
                    title = "Query Results. %s events" % objects.count()
                context = {
                    'title': title,
                    'form': form,
                    'formAction': reverse(search),
                    'maxCount': limit,
                    'rawquery' : rawquery,
                }
                return object_list(request, objects, extra_context=context)
    return render_to_response('gracedb/query.html',
            { 'form' : form,
              'form2' : form2,
            },
            context_instance=RequestContext(request))

def oldsearch(request):
    assert request.ligouser
    if request.method == 'GET':
        form = EventSearchForm()
    else:
        form = EventSearchForm(request.POST)
        if form.is_valid():
            start = form.cleaned_data['graceidStart']
            end = form.cleaned_data['graceidEnd']
            submitter = form.cleaned_data['submitter']
            groupname = form.cleaned_data['group']
            typename = form.cleaned_data['type']
            labels = form.cleaned_data['labels']
            gpsStart =  form.cleaned_data['gpsStart']
            gpsEnd =  form.cleaned_data['gpsEnd']

            textQuery = []

            if not groupname:
                # don't show test events unless explicitly requested
                # Scales?  Or should we find test group and do group= ?
                objects = Event.objects.exclude(group__name='Test')
            else:
                objects = Event.objects.all()

            if start:
                if start[0] != 'G':
                    # XXX This is the deprecated uid stuff. Take it out when uid is gone.
                    objects = objects.filter(uid__gte=start)
                    objects = objects.filter(uid__startswith="0")
                else:
                    objects = objects.filter(id__gte=int(start[1:]))
                    objects = objects.filter(uid="")
            if end:
                if end[0] != 'G':
                    # XXX This is the deprecated uid stuff. Take it out when uid is gone.
                    objects = objects.filter(uid__lte=end)
                    objects = objects.filter(uid__startswith="0")
                else:
                    objects = objects.filter(id__lte=int(end[1:]))
                    objects = objects.filter(uid="")

            if start and end:
                textQuery.append("gid: %s..%s" % (start, end))
            elif start or end:
                textQuery.append("gid: %s" % (start or end))

            if gpsStart != None or gpsEnd != None :
                if gpsStart == gpsEnd:
                    objects = objects.filter(gpstime=gpsStart)
                    textQuery.append("gpstime: %s" % gpsStart)
                else:
                    if gpsStart != None:
                        objects = objects.filter(gpstime__gte=gpsStart)
                    if gpsEnd != None:
                        objects = objects.filter(gpstime__lte=gpsEnd)
                    if gpsStart and gpsEnd:
                        textQuery.append("gpstime: %s .. %s" % (gpsStart, gpsEnd))
                    elif gpsStart:
                        textQuery.append("gpstime: %s..2000000000" % gpsStart)
                    else:
                        textQuery.append("gpstime: 0..%s" % gpsEnd)

            if submitter:
                try:
                    submitter_name = User.objects.get(id=submitter)
                except User.DoesNotExist:
                    submitter_name = "Error looking up user"
                objects = objects.filter(submitter=submitter)
                textQuery.append('submitter: "%s"' % submitter_name)
            if groupname:
                group = Group.objects.filter(name=groupname)[0]
                objects = objects.filter(group=group)
                textQuery.append("group: %s" % group.name)
            if typename:
                objects = objects.filter(analysisType=typename)
                textQuery.append("type: %s" % Event.getTypeLabel(typename))

            if labels:
                objects = objects.filter(labels__in=labels)
                textQuery.append("label: %s" % " ".join([
                    Label.objects.filter(id=l)[0].name for l in labels]))

            # Need this because events with multiple labels can appear multiple times!
            objects = objects.distinct()

            if objects.count() == 1:
                title = "Query Results. %s event" % objects.count()
            else:
                title = "Query Results. %s events" % objects.count()
            extra_context = {'title': title }

            textQuery = " ".join(textQuery)
            simple_form = SimpleSearchForm({'query': textQuery})
            extra_context['form'] = simple_form
            extra_context['maxCount'] = MAX_QUERY_RESULTS
            extra_context['rawquery' ] = textQuery

            return object_list(request, objects, extra_context=extra_context)


    return render_to_response('gracedb/query.html',
            { 'form' : form },
            context_instance=RequestContext(request))

def timeline(request):
    from gracedb.utils import gpsToUtc
    from django.utils import dateformat

    response = HttpResponse(mimetype='application/javascript')
    events = []
    for event in Event.objects.exclude(group__name="Test").all():
        if event.gpstime:
            t = dateformat.format(gpsToUtc(event.gpstime), "F j, Y h:i:s")+" UTC"

            events.append({
                'start': t,
                'title': event.get_analysisType_display(),
                'description':
                    "%s<br/>%s" %(event.get_analysisType_display(),"GPS time:%s"%event.gpstime),
                'durationEvent':False,
              })
    d = {'events': events}
    msg = simplejson.dumps(d)
    response['Content-length'] = len(msg)
    response.write(msg)
    return response

#-----------------------------------------------------------------
# Things that aren't views and should really be elsewhere.
#-----------------------------------------------------------------

from templatetags.timeutil import timeSelections

def jqgridResponse(request, objects):
    # "GET /data?_search=false&nd=1266350238476&rows=10&page=1&sidx=invid&sord=asc HTTP/1.1"
    pass

def flexigridResponse(request, objects):
    response = HttpResponse(mimetype='application/json')

    #sortname = request.POST.get('sortname', None)
    #sortorder = request.POST.get('sortorder', 'desc')
    #page = int(request.POST.get('page', 1))
    #rp = int(request.POST.get('rp', 10))

    sortname = request.GET.get('sidx', None)    # get index row - i.e. user click to sort
    sortorder = request.GET.get('sord', 'desc') # get the direction
    page = int(request.GET.get('page', 1))      # get the requested page
    rp = int(request.GET.get('rows', 10))       # get how many rows we want to have into the grid

    if sortname:
        if sortorder == "desc":
            sortname = "-" + sortname
        objects = objects.order_by(sortname)

    start = (page-1) * rp
    rows = []
    total = objects.count()

    if total:
        total_pages = (total / rp) + 1
    else:
        total_pages = 0

    if page > total_pages:
        page = total_pages

    for object in objects[start:start+rp]:
        event_times = timeSelections(object.gpstime)
        created_times = timeSelections(object.created)
        rows.append(
            { 'id' : object.id,
              'cell': [ '<a href="%s">%s</a>' %
                            (reverse(view, args=[object.graceid()]), object.graceid()),
                         #Labels
                        " ".join(['<span title="%s %s" style="color: %s">%s</span>' %
                                (label.creator.name, label.created, label.label.defaultColor, label.label.name)
                                for label in object.labelling_set.all()
                            ]),
                        # Links to neighbors
                        ', '.join([
                            '<a href="%s">%s</a>' %
                            (reverse(view, args=[n.graceid()]), n.graceid())
                            for n in object.neighbors()
                        ]),
                        object.group.name,
                        object.get_analysisType_display(),

                        event_times.get('gps',""),
                        #event_times['utc'],

                        '<a href="%s">Data</a> <a href="%s">Wiki</a>' %
                            (object.weburl(), object.wikiurl()),

                        #created_times['gps'],
                        created_times.get('utc',""),

                        object.submitter.name,

                      ]
            }
        )
    d = {
            'page': page,
            'total': total_pages,
            'records': total,
            'rows': rows,
        }
    try:
        msg = simplejson.dumps(d)
    except Exception, e:
        # XXX Not right not right not right.
        msg = "{}"
    response['Content-length'] = len(msg)
    response.write(msg)

    #query = request.POST['query']

    return response

def get_file(graceid, filename="event.log"):
    dirPrefix = GRACEDB_DATA_DIR
    logfilename = os.path.join(dirPrefix, graceid, "private", filename)
    contents = ""
    try:
        lines = open(logfilename, "r").readlines()
        contents = "<br/>".join([ escape(line) for line in lines])
        contents = mark_safe(urlize(contents))
    except Exception, e:
        contents = None
    return contents

def createWikiPage(graceid):
    # Do not create wiki pages these reasons
    # (1) freaks out the wiki/filesystem to have too many files in one directory.
    # (2) do not need them if they are empty. They'll be auto-created if ppl go to them and want them.
    # (3) htdocs (where the wikipage goes) is mounted read-only.
    return
    twikiroot = "/mnt/htdocs/uwmlsc/secure/twiki/data/Sandbox/"
    plainFile = """
Initial Entry for %s

%%TOC{depth="2"}%%
""" % graceid
    rcsFile = """head    1.1;
access; 
symbols;
locks
    apache:1.1; strict;
comment @# @;


1.1
date    2009.06.13.00.09.15;    author apache;    state Exp;
branches;
next    ;


desc
@Initial Revision
@


1.1
log
@Initial revision
@
text
@
Initial Entry for %s

%%TOC{depth="2"}%%
@
""" % graceid
    pname = os.path.join(twikiroot, graceid+".txt")
    rcsname = os.path.join(twikiroot, graceid+".txt,r")
    f = open(pname, "w")
    f.write(plainFile)
    f.close()

    f = open(rcsname, "w")
    f.write(rcsFile)
    f.close()

    os.chmod(pname, 0644)
    os.chmod(rcsname, 0444)