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

leif at geodynamics.org leif at geodynamics.org
Thu May 22 18:28:08 PDT 2008


Author: leif
Date: 2008-05-22 18:28:08 -0700 (Thu, 22 May 2008)
New Revision: 12009

Modified:
   cs/portal/trunk/northridge/SeismoWebPortal/forms.py
   cs/portal/trunk/northridge/SeismoWebPortal/mezzanine.py
   cs/portal/trunk/northridge/SeismoWebPortal/models.py
   cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/pluggable.html
   cs/portal/trunk/northridge/SeismoWebPortal/views.py
Log:
Implemented object ownership (per-user objects).  Improved code
sharing by removing the two _manipulate() methods.


Modified: cs/portal/trunk/northridge/SeismoWebPortal/forms.py
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/forms.py	2008-05-23 01:17:14 UTC (rev 12008)
+++ cs/portal/trunk/northridge/SeismoWebPortal/forms.py	2008-05-23 01:28:08 UTC (rev 12009)
@@ -381,17 +381,30 @@
         region, created = models.Region.objects.get_or_create(name = new_data['region'])
         
         # Add the Source.
-        args = {}
-        for k,v in new_data.items():
-            args[k] = v
-        args['event'] = event
-        args['dataSource'] = dataSource
-        args['region'] = region
-        args['when'] = datetime.combine(args['when_date'], args['when_time'])
-        del args['name']
-        del args['when_date']
-        del args['when_time']
-        source = models.Source.objects.create(**args)
+        source = models.Source.objects.create(
+            event = event,
+            dataSource = dataSource,
+            when = datetime.combine(new_data['when_date'], new_data['when_time']),
+            microsecond = new_data['microsecond'],
+            sourceLatitude = new_data['sourceLatitude'],
+            sourceLongitude = new_data['sourceLongitude'],
+            sourceDepth = new_data['sourceDepth'],
+            sourceMB = new_data['sourceMB'],
+            sourceMs = new_data['sourceMs'],
+            region = region,
+            eventName = new_data['eventName'],
+            timeShift = new_data['timeShift'],
+            halfDuration =  new_data['halfDuration'],
+            latitude = new_data['latitude'],
+            longitude = new_data['longitude'],
+            depth = new_data['depth'],
+            Mrr = new_data['Mrr'],
+            Mtt = new_data['Mtt'],
+            Mpp = new_data['Mpp'],
+            Mrt = new_data['Mrt'],
+            Mrp = new_data['Mrp'],
+            Mtp = new_data['Mtp'],
+            )
 
         return event
 

Modified: cs/portal/trunk/northridge/SeismoWebPortal/mezzanine.py
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/mezzanine.py	2008-05-23 01:17:14 UTC (rev 12008)
+++ cs/portal/trunk/northridge/SeismoWebPortal/mezzanine.py	2008-05-23 01:28:08 UTC (rev 12009)
@@ -3,6 +3,7 @@
 from django import oldforms
 from django.db.models import FileField
 from django.contrib.auth.views import redirect_to_login
+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
@@ -28,7 +29,7 @@
     @classmethod
     def create(cls, request, template_name=None,
                template_loader=loader, extra_context=None, post_save_redirect=None,
-               login_required=False):
+               login_required=False, manipulator=None):
         """
         Generic object-creation function.
 
@@ -42,7 +43,8 @@
         if login_required and not request.user.is_authenticated():
             return redirect_to_login(request.path)
 
-        manipulator = cls.addManipulator()
+        if manipulator is None:
+            manipulator = cls.addManipulator()
         if request.POST:
             # If data was POSTed, we're trying to create a new object
             new_data = request.POST.copy()
@@ -57,6 +59,8 @@
             if not errors:
                 # No errors -- this means we can save the data!
                 new_object = manipulator.save(new_data)
+                
+                models.Ownership.objects.create(owner = request.user, obj = new_object)
 
                 if request.user.is_authenticated():
                     request.user.message_set.create(message = 'Created "%s".' % new_object)
@@ -205,7 +209,7 @@
             return t.render(c)
 
     @classmethod
-    def list(cls, request, paginate_by=None, page=None,
+    def list(cls, request, l, paginate_by=None, page=None,
              allow_empty=True, template_name=None, template_loader=loader,
              extra_context=None, template_object_name='object',
              ):
@@ -243,10 +247,8 @@
         """
         
         if extra_context is None: extra_context = {}
-        queryset = cls.Model.objects.all()
-        queryset = queryset._clone()
         if paginate_by:
-            paginator = ObjectPaginator(queryset, paginate_by)
+            paginator = ObjectPaginator(l, paginate_by)
             if not page:
                 page = request.GET.get('page', 1)
             try:
@@ -274,11 +276,11 @@
             })
         else:
             c = Context({
-                '%s_list' % template_object_name: queryset,
+                '%s_list' % template_object_name: l,
                 'is_paginated': False,
                 'root': request.root,
             })
-            if not allow_empty and len(queryset) == 0:
+            if not allow_empty and len(l) == 0:
                 raise Http404
         for key, value in extra_context.items():
             if callable(value):
@@ -286,7 +288,7 @@
             else:
                 c[key] = value
         if not template_name:
-            model = queryset.model
+            model = cls.Model
             template_name = "%s/%s_list.html" % (model._meta.app_label, model._meta.object_name.lower())
         t = template_loader.get_template(template_name)
         return t.render(c)
@@ -327,6 +329,7 @@
 
     def duplicate(self, request):
         dup = self._duplicate()
+        models.Ownership.objects.create(owner = self.owner, 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'))
@@ -341,9 +344,10 @@
         dup.save()
         return dup
 
-    def __init__(self, objId):
+    def __init__(self, objId, owner):
         self.objId = objId
         self.obj = self._lookupObject()
+        self.owner = owner
         return
 
     def _lookupObject(self):
@@ -378,6 +382,7 @@
             if not errors:
                 manipulator.do_html2python(new_data)
                 new_object = manipulator.save(new_data)
+                models.Ownership.objects.create(owner = request.user, obj = new_object)
                 if request.user.is_authenticated():
                     request.user.message_set.create(message = 'Uploaded "%s".' % new_object)
                 if post_save_redirect:
@@ -400,33 +405,28 @@
         return t.render(c)
 
     id = property(lambda self: self.obj.id)
-    prevObject = property(lambda self: self._getPrevObject())
-    nextObject = property(lambda self: self._getNextObject())
 
-    def _getPrevObject(self):
-        if not hasattr(self, '_prevObject'):
-            self._prevObject = None
-            prevObjQ = self._prevObjectQuery()
-            for o in prevObjQ:
-                self._prevObject = o
-                break
-        return self._prevObject
+    @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 _prevObjectQuery(self):
-        return self.Model.objects.filter(id__lt = self.obj.id).order_by('-id')
-    
-    def _getNextObject(self):
-        if not hasattr(self, '_nextObject'):
-            self._nextObject = None
-            nextObjQ = self._nextObjectQuery()
-            for o in nextObjQ:
-                self._nextObject = o
-                break
-        return self._nextObject
+    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,
+                    )
 
-    def _nextObjectQuery(self):
-        return self.Model.objects.filter(id__gt = self.obj.id).order_by('id')
-
     @classmethod
     def urlForObject(cls, obj, root, action=None):
         if action:
@@ -463,44 +463,35 @@
 
     @classmethod
     def create(cls, request):
+        return super(Event, cls).create(
+            request,
+            template_name = cls.singleSourceFormTemplateName(),
+            )
+
+    def update(self, request):
+        if self.obj.singleSource:
+            return super(Event, self).update(
+                request,
+                template_name = self.singleSourceFormTemplateName(),
+                )
+        return super(Event, self).update(request)
+
+    @classmethod
+    def addManipulator(cls):
         from forms import SingleSourceEventAddManipulator
-        return cls._manipulate(request, SingleSourceEventAddManipulator(), 'Created "%s".')
+        return SingleSourceEventAddManipulator()
 
-    def update(self, request):
+    def changeManipulator(self):
         from forms import SingleSourceEventChangeManipulator
         event = self.obj
-        if not event.singleSource:
-            return super(Event, self).update(request)
-        return self._manipulate(request, SingleSourceEventChangeManipulator(event), 'Saved "%s".', event)
+        if event.singleSource:
+            return SingleSourceEventChangeManipulator(event)
+        return super(Event, self).changeManipulator()
 
     @classmethod
-    def _manipulate(cls, request, manipulator, messageFormat, event=None):
-        if request.method == 'POST':
-            new_data = request.POST.copy()
-            errors = manipulator.get_validation_errors(new_data)
-            if not errors:
-                manipulator.do_html2python(new_data)
-                new_data['class'] = None; del new_data['class']
-                new_data['object'] = None; del new_data['object']
-                new_data['action'] = None; del new_data['action']
-                obj = manipulator.save(new_data)
-                if request.user.is_authenticated():
-                    request.user.message_set.create(message = messageFormat % obj)
-                return HttpResponseRedirect(cls.urlForObject(obj, request.root))
-        else:
-            new_data = manipulator.flatten_data()
-            errors = {}
+    def singleSourceFormTemplateName(cls):
+        return 'SeismoWebPortal/single_source_event_form.html'
 
-        form = oldforms.FormWrapper(manipulator, new_data, errors)
-        t = loader.get_template('SeismoWebPortal/single_source_event_form.html')
-        c = Context(dict(
-            form = form,
-            action = request.path,
-            object = event,
-            root = request.root,
-            ))
-        return t.render(c)
-
     def _duplicate(self):
         from copy import copy
         dup = super(Event, self)._duplicate()
@@ -603,11 +594,32 @@
                        )
         return response
 
-    def _prevObjectQuery(self):
-        return self.obj.event.source_set.filter(timeShift__lte = self.obj.timeShift, id__lt = self.obj.id).order_by('-timeShift', '-id')
-    
-    def _nextObjectQuery(self):
-        return self.obj.event.source_set.filter(timeShift__gte = self.obj.timeShift, id__gt = self.obj.id).order_by('timeShift', 'id')
+    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
@@ -706,7 +718,6 @@
 
     @classmethod
     def create(cls, request):
-        from forms import MeshAddManipulator
         nchunks = request.REQUEST.get('nchunks')
         if nchunks is None:
             raise Http404
@@ -714,17 +725,33 @@
             nchunks = int(nchunks)
         except ValueError:
             raise Http404
-        return cls._manipulate(request, nchunks, MeshAddManipulator(nchunks), 'Created "%s".')
+        return super(Specfem3DGlobeMesh, cls).create(
+            request,
+            template_name = cls.formTemplateName(nchunks),
+            extra_context = { 'nchunks': nchunks },
+            manipulator = cls.addManipulator(nchunks),
+            )
 
     def update(self, request):
+        nchunks = self.obj.nchunks
+        return super(Specfem3DGlobeMesh, self).update(
+            request,
+            template_name = self.formTemplateName(nchunks),
+            extra_context = { 'nchunks': nchunks },
+            )
+
+    @classmethod
+    def addManipulator(cls, nchunks):
+        from forms import MeshAddManipulator
+        return MeshAddManipulator(nchunks)
+
+    def changeManipulator(self):
         from forms import MeshChangeManipulator
         mesh = self.obj
-        nchunks = mesh.nchunks
-        return self._manipulate(request, nchunks, MeshChangeManipulator(nchunks, mesh.id), 'Saved "%s".', mesh)
+        return MeshChangeManipulator(mesh.nchunks, mesh.id)
 
     @classmethod
-    def _manipulate(cls, request, nchunks, manipulator, messageFormat, mesh=None):
-
+    def formTemplateName(cls, nchunks):
         if nchunks == 1:
             template = 'SeismoWebPortal/mesh_form_1chunk.html'
         elif nchunks == 2:
@@ -735,34 +762,9 @@
             template = 'SeismoWebPortal/mesh_form_global.html'
         else:
             assert False
+        return template
 
-        if request.method == 'POST':
-            new_data = request.POST.copy()
-            errors = manipulator.get_validation_errors(new_data)
-            if not errors:
-                manipulator.do_html2python(new_data)
-                new_object = manipulator.save(new_data)
-                if request.user.is_authenticated():
-                    request.user.message_set.create(message = messageFormat % new_object)
-                return HttpResponseRedirect(cls.urlForObject(new_object, request.root))
-        else:
-            # Populate new_data with a 'flattened' version of the current data.
-            new_data = manipulator.flatten_data()
-            errors = {}
 
-        # Populate the FormWrapper.
-        form = oldforms.FormWrapper(manipulator, new_data, errors)
-        t = loader.get_template(template)
-        c = Context(dict(
-            form = form,
-            nchunks = nchunks,
-            object = mesh,
-            action = request.path,
-            root = request.root,
-            ))
-        return t.render(c)
-
-
 class Specfem3DGlobeParameters(Object):
     Model = models.Specfem3DGlobeParameters
 

Modified: cs/portal/trunk/northridge/SeismoWebPortal/models.py
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/models.py	2008-05-23 01:17:14 UTC (rev 12008)
+++ cs/portal/trunk/northridge/SeismoWebPortal/models.py	2008-05-23 01:28:08 UTC (rev 12009)
@@ -493,4 +493,24 @@
         list_filter = ('approved',)
 
 
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Object Grouping
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+class Ownership(models.Model):
+
+    owner = models.ForeignKey(User, db_index=True)
+    
+    objType = models.ForeignKey(ContentType, db_index=True)
+    objId = models.PositiveIntegerField(db_index=True)
+    obj = models.GenericForeignKey(ct_field='objType', fk_field='objId')
+
+
+class BuiltIn(models.Model):
+    objType = models.ForeignKey(ContentType, db_index=True)
+    objId = models.PositiveIntegerField(db_index=True)
+    obj = models.GenericForeignKey(ct_field='objType', fk_field='objId')
+
+
 # end of file

Modified: cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/pluggable.html
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/pluggable.html	2008-05-23 01:17:14 UTC (rev 12008)
+++ cs/portal/trunk/northridge/SeismoWebPortal/templates/SeismoWebPortal/pluggable.html	2008-05-23 01:28:08 UTC (rev 12009)
@@ -173,6 +173,15 @@
                 <tr>
                     <td>
                         {% if object %}
+                        &nbsp;{{ index }} of {{ count }}&nbsp;
+                        {% else %}
+                        {% ifnotequal count None %}
+                        &nbsp;{{ count }} items&nbsp;
+                        {% endifnotequal %}
+                        {% endif %}
+                    </td>
+                    <td>
+                        {% 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 %}

Modified: cs/portal/trunk/northridge/SeismoWebPortal/views.py
===================================================================
--- cs/portal/trunk/northridge/SeismoWebPortal/views.py	2008-05-23 01:17:14 UTC (rev 12008)
+++ cs/portal/trunk/northridge/SeismoWebPortal/views.py	2008-05-23 01:28:08 UTC (rev 12009)
@@ -32,22 +32,10 @@
         return render_to_response('SeismoWebPortal/splash.html', {'root': root},
                                   RequestContext(request, {}))
 
-    className = request.REQUEST.get('class')
-    Class = None
-    obj = None
     ret = None
-    creatable = False
-    uploadable = False
-    downloadable = False
-    downloadableAsText = False
-    downloadableAsKML = False
-    duplicatable = False
-    views = []
-    activeView = None
-    prevObject = None
-    nextObject = None
-    klass = None
+    c = {}
     
+    className = request.REQUEST.get('class')
     if className is None:
         t = loader.get_template('SeismoWebPortal/home.html')
         ret = t.render({})
@@ -64,7 +52,9 @@
 
         if objId is None:
             if action is None:
-                ret = Class.list(request)
+                l = Class.objectList(request.user)
+                ret = Class.list(request, l)
+                c['count'] = len(l)
             elif action == 'new':
                 ret = Class.create(request)
             elif action == 'upload':
@@ -78,18 +68,22 @@
             except ValueError:
                 raise Http404
 
-            obj = Class(objId)
-            downloadableAsText = obj.downloadableAsText
-            downloadableAsKML = obj.downloadableAsKML
-            downloadable = downloadableAsText or downloadableAsKML
-            duplicatable = obj.duplicatable
-            views = obj.views
-            prevObject = obj.prevObject
-            nextObject = obj.nextObject
+            obj = Class(objId, request.user)
+            c.update(dict(
+                object = obj,
+                # menus/buttons
+                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:
                 activeView = request.REQUEST.get('view', obj.defaultView)
                 ret = obj.detail(request, activeView)
+                c['activeView'] = activeView
             elif action == 'edit':
                 ret = obj.update(request)
             elif action == 'duplicate':
@@ -107,28 +101,19 @@
         if isinstance(ret, HttpResponse):
             return ret
 
-        creatable = Class.creatable
-        uploadable = Class.uploadable
-        klass = Class.__name__
-
+        c.update(dict(
+            creatable = Class.creatable,
+            uploadable = Class.uploadable,
+            klass = Class.__name__,
+            ))
+    
     response = HttpResponse(mimetype='text/html')
     t = loader.get_template('SeismoWebPortal/pluggable.html')
-    c = RequestContext(request, dict(
+    c.update(dict(
         content = ret,
-        klass = klass,
-        object = obj,
-        creatable = creatable,
-        uploadable = uploadable,
-        downloadable = downloadable,
-        downloadableAsText = downloadableAsText,
-        downloadableAsKML = downloadableAsKML,
-        duplicatable = duplicatable,
-        views = views,
-        activeView = activeView,
-        prevObject = prevObject,
-        nextObject = nextObject,
         root = root,
         ))
+    c = RequestContext(request, c)
     response.write(t.render(c))
     return response
 
@@ -554,7 +539,7 @@
                 if isNewUser:
                     request.session.delete_test_cookie()
                     notify_managers_of_new_user(request, user)
-                    user.message_set.create(message="Welcome to the SPECFEM 3D GLOBE web portal!")
+                    user.message_set.create(message="Welcome to the CIG Seismology Web Portal!")
                 else:
                     user.message_set.create(message="Your contact information has been saved.")
                 return HttpResponseRedirect("%s/" % root)



More information about the cig-commits mailing list