[cig-commits] r12018 - in cs/portal/trunk/northridge/SeismoWebPortal: . templates/SeismoWebPortal

leif at geodynamics.org leif at geodynamics.org
Fri May 23 18:49:03 PDT 2008


Author: leif
Date: 2008-05-23 18:49:02 -0700 (Fri, 23 May 2008)
New Revision: 12018

Added:
   cs/portal/trunk/northridge/SeismoWebPortal/data/
   cs/portal/trunk/northridge/SeismoWebPortal/management.py
Removed:
   cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_confirm_delete.html
   cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_detail.html
   cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_detail_gearth.kml
   cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_form.html
   cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_map.html
Modified:
   cs/portal/trunk/northridge/SeismoWebPortal/fformats.py
   cs/portal/trunk/northridge/SeismoWebPortal/mezzanine.py
   cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/event_detail.html
   cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/pluggable.html
   cs/portal/trunk/northridge/SeismoWebPortal/views.py
Log:
Implemented built-in (shared) objects.  Added access protections.
Prevent creation of global meshes.  Users can no longer monkey with
individual sources in a kinematic rupture.


Copied: cs/portal/trunk/northridge/SeismoWebPortal/data (from rev 12011, cs/portal/trunk/seismo/SeismoWebPortal/data)

Modified: cs/portal/trunk/northridge/SeismoWebPortal/fformats.py
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/fformats.py	2008-05-23 23:00:09 UTC (rev 12017)
+++ cs/portal/trunk/northridge/SeismoWebPortal/fformats.py	2008-05-24 01:49:02 UTC (rev 12018)
@@ -92,7 +92,7 @@
     def create(self, filename, stream):
         mineosModel = models.MineosModel.objects.create(
             name = filename,
-            data = stream.getvalue(),
+            data = stream.read(),
             )
         return mineosModel
 

Copied: cs/portal/trunk/northridge/SeismoWebPortal/management.py (from rev 12011, cs/portal/trunk/seismo/SeismoWebPortal/management.py)
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/management.py	                        (rev 0)
+++ cs/portal/trunk/northridge/SeismoWebPortal/management.py	2008-05-24 01:49:02 UTC (rev 12018)
@@ -0,0 +1,213 @@
+
+from django.dispatch import dispatcher
+from django.db.models import signals
+import models
+import os
+
+
+def createSpecfem3DGlobeMeshes():
+    
+    m = {}
+    
+    # Iterate through every mesh that could possibly be created using
+    # the global mesh form.  Partition them according to 'Nex', which
+    # determines the shortest period (which is all anyone really cares
+    # about).
+    for nproc in xrange(1, 10):
+        for nex_c in xrange(1, 10):
+            nex = 8 * nex_c * nproc
+            l = m.setdefault(nex, [])
+            l.append((nex_c, nproc))
+
+    # Generate every possible global mesh...
+    nexs = m.keys()
+    nexs.sort()
+    nexs.reverse()
+    lastSP = 0
+    for nex in nexs:
+        # ...rejecting those below Nex = 160 (27s)...
+        if nex < 160:
+            break
+        # ...rejecting those above Nex = 240 (18s)...
+        if nex > 240:
+            continue
+        # ...selecting those variants that use the greatest # of processors...
+        nex_c, nproc = m[nex][-1]
+        mesh = models.Specfem3DGlobeMesh(
+            nchunks = 6,
+            nproc_xi = nproc,
+            nproc_eta = nproc,
+            nex_xi_c = nex_c,
+            nex_eta_c = nex_c,
+            angular_width_eta = 90.0,
+            angular_width_xi = 90.0,
+            center_latitude = 0.0,
+            center_longitude = 0.0,
+            gamma_rotation_azimuth = 0.0,
+            )
+        sp = "%.0f" % mesh.shortestPeriod()
+        # ...rejecting those that look the same when rounded to the
+        # nearest second.
+        if sp == lastSP:
+            continue
+        mesh.name = "global %ss Nex=%d" % (sp, mesh.nex_xi())
+        mesh.save()
+        lastSP = sp
+        print "Adding Specfem3DGlobeMesh '%s'" % mesh
+        models.BuiltIn.objects.create(obj = mesh)
+
+    return
+
+
+def createStationList():
+    from fformats import StationListFormat
+    from os.path import dirname, join
+
+    format = StationListFormat()
+    filename = "STATIONS_FULL_758"
+    pathname = join(dirname(__file__), "data", filename)
+
+    print "Adding StationList '%s'" % filename
+
+    stream = open(pathname, 'r')
+    stationList = format.create(filename, stream)
+    
+    models.BuiltIn.objects.create(obj = stationList)
+
+    return
+
+
+def createMineosModeCatalogs():
+    catalog = models.MineosModeCatalog.objects.create(name = "Built-in")
+    print "Adding MineosModeCatalog '%s'" % catalog
+    models.BuiltIn.objects.create(obj = catalog)
+    return
+
+
+def createMineosModels():
+    from fformats import MineosModelFormat
+    from os.path import dirname, join
+    
+    format = MineosModelFormat()
+    for modelName, filename in [("PREM", "prem_ocean.txt"), ("PREM w/o ocean", "prem_noocean.txt")]:
+        pathname = join(dirname(__file__), "data", filename)
+        stream = open(pathname, 'r')
+        model = format.create(modelName, stream)
+        print "Adding MineosModel '%s'" % model
+        models.BuiltIn.objects.create(obj = model)
+
+    return
+
+
+def createMineosParameters():
+    for catalog in models.MineosModeCatalog.objects.all():
+        for model in models.MineosModel.objects.all():
+            parameters = models.MineosParameters.objects.create(
+                name = "%s, %s Catalog" % (model, catalog),
+                catalog = catalog,
+                model = model,
+                )
+            print "Adding MineosParameters '%s'" % parameters
+            models.BuiltIn.objects.create(obj = parameters)
+    return
+
+
+def importLegacyDatabase(legacyDB):
+    from pysqlite2 import dbapi2 as sqlite
+
+    print "Importing legacy database '%s'" % legacyDB
+    
+    con = sqlite.connect(legacyDB)
+    cur = con.cursor()
+
+    # Invite
+    invites = {}
+    invites[None] = None
+    cur.execute("select * from SeismoWebPortal_invite")
+    for (id, code, name, description,
+         created, modified, expires) in cur:
+        invites[id] = models.Invite.objects.create(
+            id = id,
+            code = code,
+            name = name,
+            description = description,
+            created = created,
+            modified = modified,
+            expires = expires,
+            )
+
+    # User
+    from django.contrib.auth.models import User
+    users = {}
+    cur.execute("select * from auth_user")
+    for (id, username,
+         first_name, last_name, email,
+         password,
+         is_staff, is_active, is_superuser,
+         last_login, date_joined) in cur:
+        users[id] = User.objects.create(
+            id = id,
+            username     = username,
+            first_name   = first_name,
+            last_name    = last_name,
+            email        = email,
+            password     = password,
+            is_staff     = is_staff,
+            is_active    = is_active,
+            is_superuser = is_superuser,
+            last_login   = last_login,
+            date_joined  = date_joined,
+            )
+
+    # UserInfo
+    cur.execute("select * from SeismoWebPortal_userinfo")
+    for (user_id,
+         institution,
+         address1, address2, address3, phone,
+         invite_id, approved,
+         help_visible) in cur:
+        user = users[user_id]
+        models.UserInfo.objects.create(
+            user         = user,
+            institution  = institution,
+            address1     = address1,
+            address2     = address2,
+            address3     = address3,
+            phone        = phone,
+            invite       = invites[invite_id],
+            approved     = approved,
+            )
+        
+    return
+
+
+def createDefaults(app, created_models):
+    
+    # Specfem 3D Globe
+    if models.Specfem3DGlobeMesh in created_models:
+        createSpecfem3DGlobeMeshes()
+
+    # Mineos
+    flag = models.MineosParameters in created_models
+    if models.MineosModeCatalog in created_models:
+        createMineosModeCatalogs()
+        flag = True
+    if models.MineosModel in created_models:
+        createMineosModels()
+        flag = True
+    if flag:
+        createMineosParameters()
+
+    # general
+    if (models.Station in created_models or
+        models.StationList in created_models):
+        createStationList()
+
+    legacyDB = os.environ.get('WEBPORTAL_LEGACY_DB')
+    if legacyDB:
+        importLegacyDatabase(legacyDB)
+
+    return
+
+
+dispatcher.connect(createDefaults, sender=models, signal=signals.post_syncdb)

Modified: cs/portal/trunk/northridge/SeismoWebPortal/mezzanine.py
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/mezzanine.py	2008-05-23 23:00:09 UTC (rev 12017)
+++ cs/portal/trunk/northridge/SeismoWebPortal/mezzanine.py	2008-05-24 01:49:02 UTC (rev 12018)
@@ -6,7 +6,7 @@
 from django.contrib.contenttypes.models import ContentType
 from django.template import loader, Context
 from django.http import HttpResponse, HttpResponseRedirect, Http404
-from django.core.exceptions import ObjectDoesNotExist
+from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
 from django.core.paginator import ObjectPaginator, InvalidPage
 from HTMLParser import HTMLParser
 
@@ -185,6 +185,9 @@
 
         if request.method == 'POST':
             message = 'Deleted "%s".' % object
+            ctype = ContentType.objects.get_for_model(model)
+            ownership = models.Ownership.objects.get(objType = ctype, objId = object.id)
+            ownership.delete()
             object.delete()
             if request.user.is_authenticated():
                 request.user.message_set.create(message = message)
@@ -329,7 +332,7 @@
 
     def duplicate(self, request):
         dup = self._duplicate()
-        models.Ownership.objects.create(owner = self.owner, obj = dup)
+        models.Ownership.objects.create(owner = request.user, obj = dup)
         if request.user.is_authenticated():
             request.user.message_set.create(message = 'Editing a new copy of "%s".' % self.obj)
         return HttpResponseRedirect(self.urlForObject(dup, request.root, action = 'edit'))
@@ -344,25 +347,10 @@
         dup.save()
         return dup
 
-    def __init__(self, objId, owner):
-        self.objId = objId
-        self.obj = self._lookupObject()
-        self.owner = owner
+    def __init__(self, obj):
+        self.obj = obj
         return
 
-    def _lookupObject(self):
-        # Look up the object to be edited
-        object_id = self.objId
-        model = self.Model
-        lookup_kwargs = {}
-        lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id
-        try:
-            object = model.objects.get(**lookup_kwargs)
-        except ObjectDoesNotExist:
-            raise Http404, "No %s found for %s" % (model._meta.verbose_name, lookup_kwargs)
-            #raise Http404, "No %s found for %s" % (model._meta.app_label, lookup_kwargs)
-        return object
-
     @classmethod
     def title(cls):
         return cls.Model._meta.verbose_name
@@ -407,26 +395,9 @@
     id = property(lambda self: self.obj.id)
 
     @classmethod
-    def objectList(cls, owner):
-        ctype = ContentType.objects.get_for_model(cls.Model)
-        return [o.obj for o in models.Ownership.objects.filter(owner = owner, objType = ctype)]
+    def contentType(cls):
+        return ContentType.objects.get_for_model(cls.Model)
 
-    def navigation(self):
-        prevObject = None
-        nextObject = None
-        l = self.objectList(self.owner)
-        i = l.index(self.obj)
-        if i > 0:
-            prevObject = l[i - 1]
-        i += 1
-        if i < len(l):
-            nextObject = l[i]
-        return dict(index = i,
-                    count = len(l),
-                    prevObject = prevObject,
-                    nextObject =  nextObject,
-                    )
-
     @classmethod
     def urlForObject(cls, obj, root, action=None):
         if action:
@@ -502,6 +473,37 @@
             sourceCopy.save()
         return dup
 
+    def detail(self, request, view):
+        event = self.obj
+        if event.singleSource or view != 'detail':
+            return super(Event, self).detail(request, view)
+        sourceId = request.REQUEST.get('source')
+        if sourceId is None:
+            return super(Event, self).detail(request, view)
+        try:
+            sourceId = int(sourceId)
+        except ValueError:
+            raise Http404
+        sourceList = [s for s in event.sources()]
+        source = None
+        for i, o in enumerate(sourceList):
+            if o.id == sourceId:
+                source = o
+                sourceIndex = i
+        if source is None:
+            raise Http404
+        c = dict(
+            source = source,
+            sourceIndex = sourceIndex + 1,
+            #sourceList = sourceList,
+            sourceCount = len(sourceList),
+            )
+        return super(Event, self).detail(
+            request,
+            view,
+            extra_context = c,
+            )
+
     @classmethod
     def search(cls, request):
         import urllib2
@@ -565,63 +567,6 @@
                                   )
 
 
-class Source(Object):
-    Model = models.Source
-    FileFormat = fformats.CMTSolutionFormat
-
-    downloadableAsText = True
-    downloadableAsKML = True
-
-    views = [('detail', "Mechanism"), ('map', "Map")]
-
-    def postDeleteRedirect(self, root):
-        return "%s/?class=Event&object=%d" % (root, self.obj.event.id)
-
-    def downloadAsText(self, request):
-        source = self.obj
-        response = HttpResponse(mimetype='text/plain')
-        response['Content-Disposition'] = 'attachment; filename=%s' % source.eventName
-        response.write(str(source.cmtSolution()))
-        return response
-
-    def downloadAsKML(self, request):
-        source = self.obj
-        response = HttpResponse(mimetype='application/vnd.google-earth')
-        response['Content-Disposition'] = 'attachment; filename=%s.kml' % source.eventName
-        response.write(self.detail(request, 
-                                   template_name = 'SeismoWebPortal/source_detail_gearth.kml',
-                                   )
-                       )
-        return response
-
-    def navigation(self):
-        neighbors = []
-        queries = [
-            self.obj.event.source_set.filter(timeShift__lte = self.obj.timeShift).order_by('-timeShift', '-id'),
-            self.obj.event.source_set.filter(timeShift__gte = self.obj.timeShift).order_by('timeShift', 'id'),
-            ]
-        i = None
-        for q in queries:
-            neighbor = None
-            sawSelf = False
-            tally = 0
-            for o in q:
-                if o.id == self.obj.id:
-                    sawSelf = True
-                    if i is None:
-                        i = q.count() - tally
-                elif sawSelf:
-                    neighbor = o
-                    break
-                tally += 1
-            neighbors.append(neighbor)
-        return dict(index = i,
-                    count = self.obj.event.sources().count(),
-                    prevObject = neighbors[0],
-                    nextObject = neighbors[1],
-                    )
-
-
 # support code
 
 class HarvardCMTSearchResultsParser(HTMLParser):
@@ -716,6 +661,8 @@
 class Specfem3DGlobeMesh(Object):
     Model = models.Specfem3DGlobeMesh
 
+    duplicatable = property(lambda self: self.obj.nchunks != 6) # see the comment in create()
+
     @classmethod
     def create(cls, request):
         nchunks = request.REQUEST.get('nchunks')
@@ -725,6 +672,10 @@
             nchunks = int(nchunks)
         except ValueError:
             raise Http404
+        if nchunks == 6:
+            # Allowed global meshes are built-in; the user should have
+            # no reason to create them.
+            raise PermissionDenied
         return super(Specfem3DGlobeMesh, cls).create(
             request,
             template_name = cls.formTemplateName(nchunks),
@@ -732,6 +683,12 @@
             manipulator = cls.addManipulator(nchunks),
             )
 
+    def duplicate(self, request):
+        if self.obj.nchunks == 6:
+            # see the comment in create()
+            raise PermissionDenied
+        return super(Specfem3DGlobeMesh, self).duplicate(request)
+
     def update(self, request):
         nchunks = self.obj.nchunks
         return super(Specfem3DGlobeMesh, self).update(
@@ -761,7 +718,7 @@
         elif nchunks == 6:
             template = 'SeismoWebPortal/mesh_form_global.html'
         else:
-            assert False
+            raise Http404
         return template
 
 

Modified: cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/event_detail.html
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/event_detail.html	2008-05-23 23:00:09 UTC (rev 12017)
+++ cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/event_detail.html	2008-05-24 01:49:02 UTC (rev 12018)
@@ -1,10 +1,10 @@
 
+{% if object.singleSource %}
+
 <h2>{{ object }}</h2>
 
-{% if object.singleSource %}
+<p id=sourceBeachballMw><img src="{{root}}/beachballs/{{object.singleSource.id}}/detail.gif" width=114 height=114> M<sub>w</sub> &cong; {{ object.singleSource.momentMagnitude|stringformat:".2f" }}</p>
 
-<p id=sourceBeachballMw><img src="{{root}}/beachballs/{{object.singleSource.id}}/detail.gif"> M<sub>w</sub> &cong; {{ object.singleSource.momentMagnitude|stringformat:".2f" }}</p>
-
 <div class=cmtsolution>
     <h3><code>CMTSOLUTION</code></h3>
     <pre>{{ object.singleSource.cmtSolution }}</pre>
@@ -14,8 +14,25 @@
 
 <!-- kinematic rupture -->
 
-<p class=infobar>{{ object.source_set.count }} source{{ object.source_set.count|pluralize }}
+{% if source %}
 
+<h2>{{ object }} &rarr; {{ source }}</h2>
+
+<p class=infobar><a href="{{root}}/?class=Event&object={{object.id}}#s{{source.id}}"><img src="{{root}}/images/highlight-item.gif" alt="Highlight Item" width=24 height=16></a> source {{ sourceIndex }} of {{ sourceCount }}</p>
+
+<p id=sourceBeachballMw><img src="{{root}}/beachballs/{{source.id}}/detail.gif" width=114 height=114> M<sub>w</sub> &cong; {{ source.momentMagnitude|stringformat:".2f" }}</p>
+
+<div class=cmtsolution>
+    <h3><code>CMTSOLUTION</code></h3>
+    <pre>{{ source.cmtSolution }}</pre>
+</div>
+
+{% else %}
+
+<h2>{{ object }}</h2>
+
+<p class=infobar>{{ object.source_set.count }} source{{ object.source_set.count|pluralize }}</p>
+
 {% if object.source_set.count %}
     <table rules=cols class="clickable">
         <colgroup><col class=odd><col class=even><col class=odd><col class=even><col class=odd><col class=even><col class=odd></colgroup>
@@ -34,8 +51,8 @@
 
         <tbody>
         {% for source in object.sources %}
-        <tr class="{% cycle odd,even %}" id="s{{source.id}}" onclick="location.href='{{root}}/?class=Source&object={{source.id}}'">
-            <td><a href="{{root}}/?class=Source&object={{source.id}}">{{ source.eventName }}</a></td>
+        <tr class="{% cycle odd,even %}" id="s{{source.id}}" onclick="location.href='{{root}}/?class=Event&object={{object.id}}&source={{source.id}}'">
+            <td><a href="{{root}}/?class=Event&object={{object.id}}&source={{source.id}}">{{ source.eventName }}</a></td>
             <td class=float>{{ source.timeShift|stringformat:".4f" }}</td>
             <td class=float>{{ source.halfDuration|stringformat:".4f" }}</td>
             <td class=float>{{ source.latitude|stringformat:".4f" }}&deg;</td>
@@ -50,3 +67,5 @@
 {% endif %}
 
 {% endif %}
+
+{% endif %}

Modified: cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/pluggable.html
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/pluggable.html	2008-05-23 23:00:09 UTC (rev 12017)
+++ cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/pluggable.html	2008-05-24 01:49:02 UTC (rev 12018)
@@ -88,7 +88,7 @@
                                     <li><a href="{{root}}/?class={{klass}}&action=new&nchunks=1">1-chunk regional mesh</a></li>
                                     <li><a href="{{root}}/?class={{klass}}&action=new&nchunks=2">2-chunk regional mesh</a></li>
                                     <li><a href="{{root}}/?class={{klass}}&action=new&nchunks=3">3-chunk regional mesh</a></li>
-                                    <li><a href="{{root}}/?class={{klass}}&action=new&nchunks=6">global mesh</a></li>
+                                    <!--<li><a href="{{root}}/?class={{klass}}&action=new&nchunks=6">global mesh</a></li>-->
                                 </ul>
                             </dd>
                         </dl>
@@ -114,7 +114,7 @@
                         {% endif %}
                     </td>
                     <td>
-                        {% if object %}
+                        {% if editable %}
                         <a href="{{root}}/?class={{klass}}&object={{object.id}}&action=edit">Edit</a>
                         {% else %}
                         <span class="disabled">Edit</span>
@@ -128,7 +128,7 @@
                         {% endif %}
                     </td>
                     <td>
-                        {% if object %}
+                        {% if deletable %}
                         <a href="{{root}}/?class={{klass}}&object={{object.id}}&action=delete"><img src="{{root}}/images/delete_icon.gif"> Delete</a>
                         {% else %}
                         <span class="disabled"><img src="{{root}}/images/delete_icon.gif"> Delete</span>
@@ -176,31 +176,27 @@
                         &nbsp;{{ index }} of {{ count }}&nbsp;
                         {% else %}
                         {% ifnotequal count None %}
-                        &nbsp;{{ count }} items&nbsp;
+                        &nbsp;{{ count }} item{{count|pluralize}}&nbsp;
                         {% endifnotequal %}
                         {% endif %}
                     </td>
                     <td class="iconButton">
                         {% if object %}
-                        {% ifequal klass 'Source' %}
-                        <a href="{{root}}/?class=Event&object={{object.obj.event.id}}#s{{object.id}}"><img src="{{root}}/images/highlight-item.gif" alt="Highlight Item" width=24 height=16></a>
-                        {% else %}
                         <a href="{{root}}/?class={{klass}}#o{{object.id}}"><img src="{{root}}/images/highlight-item.gif" alt="Highlight Item" width=24 height=16></a>
-                        {% endifequal %}
                         {% else %}
                         <img src="{{root}}/images/highlight-item-disabled.gif" alt="Highlight Item" width=24 height=16>
                         {% endif %}
                     </td>
                     <td>
                         {% if prevObject %}
-                            <a href="{{root}}/?class={{klass}}&object={{prevObject.id}}">&larr;</a>
+                            <a href="{{root}}/?class={{klass}}&object={{prevObject.id}}&action={{prevAction}}{%if activeView%}&view={{activeView}}{%endif%}">&larr;</a>
                         {% else %}
                             <span class="disabled">&larr;</span>
                         {% endif %}
                     </td>
                     <td>
                         {% if nextObject %}
-                            <a href="{{root}}/?class={{klass}}&object={{nextObject.id}}">&rarr;</a>
+                            <a href="{{root}}/?class={{klass}}&object={{nextObject.id}}&action={{nextAction}}{%if activeView%}&view={{activeView}}{%endif%}">&rarr;</a>
                         {% else %}
                             <span class="disabled">&rarr;</span>
                         {% endif %}

Deleted: cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_confirm_delete.html
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_confirm_delete.html	2008-05-23 23:00:09 UTC (rev 12017)
+++ cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_confirm_delete.html	2008-05-24 01:49:02 UTC (rev 12018)
@@ -1,10 +0,0 @@
-
-<h2>delete source</h2>
-
-<form method="post" action="{{action}}">
-    <input type="hidden" name="class" value="Source">
-    <input type="hidden" name="object" value="{{object.id}}">
-    <input type="hidden" name="action" value="delete">
-    <p>Are you sure you want to delete the source "{{ object }}"?
-    <p><input type="submit" value="Delete" />
-</form>

Deleted: cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_detail.html
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_detail.html	2008-05-23 23:00:09 UTC (rev 12017)
+++ cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_detail.html	2008-05-24 01:49:02 UTC (rev 12018)
@@ -1,9 +0,0 @@
-
-<h2>{{ object }}</h2>
-
-<p id=sourceBeachballMw><img src="{{root}}/beachballs/{{object.id}}/detail.gif"> M<sub>w</sub> &cong; {{ object.momentMagnitude|stringformat:".2f" }}</p>
-
-<div class=cmtsolution>
-    <h3><code>CMTSOLUTION</code></h3>
-    <pre>{{ object.cmtSolution }}</pre>
-</div>

Deleted: cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_detail_gearth.kml
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_detail_gearth.kml	2008-05-23 23:00:09 UTC (rev 12017)
+++ cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_detail_gearth.kml	2008-05-24 01:49:02 UTC (rev 12018)
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<kml xmlns="http://earth.google.com/kml/2.0">
-    <Placemark>
-        <name><![CDATA[{{object.eventName}}]]></name>
-        <description><![CDATA[M<sub>w</sub> = {{ object.momentMagnitude|stringformat:".2f" }}]]></description>
-        <styleUrl>root://styleMaps#default+nicon=0x304+hicon=0x314</styleUrl>
-        <Point>
-            <coordinates>{{object.longitude}},{{object.latitude}},0</coordinates>
-        </Point>
-    </Placemark>
-</kml>

Deleted: cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_form.html
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_form.html	2008-05-23 23:00:09 UTC (rev 12017)
+++ cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_form.html	2008-05-24 01:49:02 UTC (rev 12018)
@@ -1,107 +0,0 @@
-
-<h2>edit source</h2>
-
-{% if form.has_errors %}
-<p><span class=error>Please correct the following error{{ form.error_dict|pluralize }}.</span>
-{% endif %}
-
-<form method="post" action="{{action}}">
-    <input type="hidden" name="class" value="Source">
-    <input type="hidden" name="object" value="{{object.id}}">
-    <input type="hidden" name="action" value="edit">
-
-    <div class=tab30ex>
-
-    <input type="hidden" name="event" value="{{ object.event.id }}">
-
-    <!-- PDE info is not used by the code -->
-    <input type="hidden" name="dataSource" value="{{ object.dataSource }}">
-    <input type="hidden" name="when_date" value="{{ object.when.date }}">
-    <input type="hidden" name="when_time" value="{{ object.when.time }}">
-    <input type="hidden" name="microsecond" value="{{ object.microsecond }}">
-    <input type="hidden" name="sourceLatitude" value="{{ object.sourceLatitude }}">
-    <input type="hidden" name="sourceLongitude" value="{{ object.sourceLongitude }}">
-    <input type="hidden" name="sourceDepth" value="{{ object.sourceDepth }}">
-    <input type="hidden" name="sourceMB" value="{{ object.sourceMB }}">
-    <input type="hidden" name="sourceMs" value="{{ object.sourceMs }}">
-    <input type="hidden" name="region" value="{{ object.region }}">
-
-    <div>
-        <label for="id_eventName" class=before>event name</label>
-        {{ form.eventName }}
-        {% if form.eventName.errors %}<span class=error>{{ form.eventName.errors|join:", " }}</span>{% endif %}
-    </div>
-
-    <div>
-        <label for="id_timeShift" class=before>time shift</label>
-        {{ form.timeShift }} s
-        {% if form.timeShift.errors %}<span class=error>{{ form.timeShift.errors|join:", " }}</span>{% endif %}
-    </div>
-
-    <div>
-        <label for="id_halfDuration" class=before>half duration</label>
-        {{ form.halfDuration }} s
-        {% if form.halfDuration.errors %}<span class=error>{{ form.halfDuration.errors|join:", " }}</span>{% endif %}
-    </div>
-
-    <div>
-        <label for="id_latitude" class=before>latitude</label>
-        {{ form.latitude }} deg
-        {% if form.latitude.errors %}<span class=error>{{ form.latitude.errors|join:", " }}</span>{% endif %}
-    </div>
-
-    <div>
-        <label for="id_longitude" class=before>longitude</label>
-        {{ form.longitude }} deg
-        {% if form.longitude.errors %}<span class=error>{{ form.longitude.errors|join:", " }}</span>{% endif %}
-    </div>
-
-    <div>
-        <label for="id_depth" class=before>depth</label>
-        {{ form.depth }} km
-        {% if form.depth.errors %}<span class=error>{{ form.depth.errors|join:", " }}</span>{% endif %}
-    </div>
-
-    <div>
-        <label for="id_Mrr" class=before>Mrr</label>
-        {{ form.Mrr }} dyne cm
-        {% if form.Mrr.errors %}<span class=error>{{ form.Mrr.errors|join:", " }}</span>{% endif %}
-    </div>
-
-    <div>
-        <label for="id_Mtt" class=before>Mtt</label>
-        {{ form.Mtt }} dyne cm
-        {% if form.Mtt.errors %}<span class=error>{{ form.Mtt.errors|join:", " }}</span>{% endif %}
-    </div>
-
-    <div>
-        <label for="id_Mpp" class=before>Mpp</label>
-        {{ form.Mpp }} dyne cm
-        {% if form.Mpp.errors %}<span class=error>{{ form.Mpp.errors|join:", " }}</span>{% endif %}
-    </div>
-
-    <div>
-        <label for="id_Mrt" class=before>Mrt</label>
-        {{ form.Mrt }} dyne cm
-        {% if form.Mrt.errors %}<span class=error>{{ form.Mrt.errors|join:", " }}</span>{% endif %}
-    </div>
-
-    <div>
-        <label for="id_Mrp" class=before>Mrp</label>
-        {{ form.Mrp }} dyne cm
-        {% if form.Mrp.errors %}<span class=error>{{ form.Mrp.errors|join:", " }}</span>{% endif %}
-    </div>
-
-    <div>
-        <label for="id_Mtp" class=before>Mtp</label>
-        {{ form.Mtp }} dyne cm
-        {% if form.Mtp.errors %}<span class=error>{{ form.Mtp.errors|join:", " }}</span>{% endif %}
-    </div>
-
-    <div>
-        <input class=submit type="submit" value="Save" />
-    </div>
-
-    </div> <!-- tab30ex -->
-
-</form>

Deleted: cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_map.html
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_map.html	2008-05-23 23:00:09 UTC (rev 12017)
+++ cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/source_map.html	2008-05-24 01:49:02 UTC (rev 12018)
@@ -1,5 +0,0 @@
-
-<h2>{{ object }}</h2>
-
-<center><p><img src="{{root}}/maps/events/{{object.id}}/global/event.jpg">
-           <img src="{{root}}/maps/events/{{object.id}}/global/antipode.jpg"></p></center>

Modified: cs/portal/trunk/northridge/SeismoWebPortal/views.py
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/views.py	2008-05-23 23:00:09 UTC (rev 12017)
+++ cs/portal/trunk/northridge/SeismoWebPortal/views.py	2008-05-24 01:49:02 UTC (rev 12018)
@@ -3,6 +3,7 @@
 from django.conf import settings
 from django.contrib.auth import login, logout
 from django.core import validators
+from django.core.exceptions import PermissionDenied
 from django.http import HttpResponse, HttpResponseRedirect, Http404
 from django.shortcuts import render_to_response, get_object_or_404
 from django.template import loader, Context
@@ -47,14 +48,22 @@
         except AttributeError:
             raise Http404
 
+        ctype = Class.contentType()
+        objList = []
+        objList.extend([o.obj for o in models.BuiltIn.objects.filter(objType = ctype)])
+        builtInCount = len(objList)
+        objList.extend([o.obj for o in models.Ownership.objects.filter(owner = request.user, objType = ctype)])
+        count = len(objList)
+        c['count'] = count
+
         objId = request.REQUEST.get('object')
-        action = request.REQUEST.get('action')
+        action = request.REQUEST.get('action', 'view')
+        c['prevAction'] = action
+        c['nextAction'] = action
 
         if objId is None:
-            if action is None:
-                l = Class.objectList(request.user)
-                ret = Class.list(request, l)
-                c['count'] = len(l)
+            if action == 'view':
+                ret = Class.list(request, objList)
             elif action == 'new':
                 ret = Class.create(request)
             elif action == 'upload':
@@ -68,28 +77,63 @@
             except ValueError:
                 raise Http404
 
-            obj = Class(objId, request.user)
+            obj = None
+            for i, o in enumerate(objList):
+                if o.id == objId:
+                    obj = o
+                    objIndex = i
+
+            if obj is None:
+                # The user is attepting to examine another user's object.
+                raise PermissionDenied
+
+            builtIn = objIndex < builtInCount
+
+            # navigation
+            prevObject = None
+            nextObject = None
+            if objIndex > 0:
+                prevObject = objList[objIndex - 1]
+            i = objIndex + 1
+            if i < count:
+                nextObject = objList[i]
             c.update(dict(
+                index = i,
+                prevObject = prevObject,
+                nextObject =  nextObject,
+                ))
+
+            obj = Class(obj)
+            c.update(dict(
                 object = obj,
                 # menus/buttons
+                editable = not builtIn,
+                duplicatable = obj.duplicatable,
+                deletable = not builtIn,
                 downloadableAsText = obj.downloadableAsText,
                 downloadableAsKML = obj.downloadableAsKML,
                 downloadable = obj.downloadableAsText or obj.downloadableAsKML,
-                duplicatable = obj.duplicatable,
                 views = obj.views,
                 ))
-            c.update(obj.navigation())
 
-            if action is None:
+            if action == 'view':
                 activeView = request.REQUEST.get('view', obj.defaultView)
                 ret = obj.detail(request, activeView)
                 c['activeView'] = activeView
             elif action == 'edit':
+                if builtIn:
+                    raise PermissionDenied
+                if objIndex == builtInCount:
+                    c['prevAction'] = 'view'
                 ret = obj.update(request)
             elif action == 'duplicate':
                 ret = obj.duplicate(request)
             elif action == 'delete':
+                if builtIn:
+                    raise PermissionDenied
                 ret = obj.delete(request)
+                c['prevAction'] = 'view'
+                c['nextAction'] = 'view'
             elif action == 'downloadAsText':
                 ret = obj.downloadAsText(request)
             elif action == 'downloadAsKML':



More information about the cig-commits mailing list