[open-ils-commits] r164 - in servres/trunk: . conifer/syrup (gfawcett)

svn at svn.open-ils.org svn at svn.open-ils.org
Mon Mar 9 22:44:49 EDT 2009


Author: gfawcett
Date: 2009-03-09 22:44:47 -0400 (Mon, 09 Mar 2009)
New Revision: 164

Modified:
   servres/trunk/.gitignore
   servres/trunk/conifer/syrup/generics.py
   servres/trunk/conifer/syrup/views.py
Log:
Added access-controls to admin-option editing; general cleanup of views.py.

Admin-option editing was public; that's changed, you must now be an
'admin' which for now means you are Django's 'user.is_staff'.

I reorganized views.py into more-logical sections, and think we are
going to split it up into multiple views/* files.

Modified: servres/trunk/.gitignore
===================================================================
--- servres/trunk/.gitignore	2009-03-10 00:38:42 UTC (rev 163)
+++ servres/trunk/.gitignore	2009-03-10 02:44:47 UTC (rev 164)
@@ -3,4 +3,4 @@
 sip/doc/sip2_developers_guide.pdf
 sip/java/*
 *.pyc
-
+PyZ3950_parsetab.py
\ No newline at end of file

Modified: servres/trunk/conifer/syrup/generics.py
===================================================================
--- servres/trunk/conifer/syrup/generics.py	2009-03-10 00:38:42 UTC (rev 163)
+++ servres/trunk/conifer/syrup/generics.py	2009-03-10 02:44:47 UTC (rev 164)
@@ -4,6 +4,18 @@
 from django.shortcuts import get_object_or_404
 from django.forms import ModelForm, ValidationError
 
+
+def generic_handler(form, decorator=lambda x: x):
+    def handler(request, obj_id=None, action=None):
+        if obj_id is None and action is None:
+            return generic_index(form)
+        elif action is None:
+            return generic_edit(form, request, obj_id)
+        elif action == 'delete':
+            return generic_delete(form, request, obj_id)
+    return decorator(handler)
+
+
 def generic_index(form):
     assert hasattr(form, 'Index')
     return g.render('generic/index.xhtml', form=form)
@@ -33,17 +45,7 @@
         instance.delete()
         return HttpResponseRedirect('../')
 
-def generic_handler(form):
-    def handler(request, obj_id=None, action=None):
-        if obj_id is None and action is None:
-            return generic_index(form)
-        elif action is None:
-            return generic_edit(form, request, obj_id)
-        elif action == 'delete':
-            return generic_delete(form, request, obj_id)
-    return handler
 
-
 def strip_and_nonblank(fieldname):
     def clean(self):
         v = self.cleaned_data.get(fieldname) or ''

Modified: servres/trunk/conifer/syrup/views.py
===================================================================
--- servres/trunk/conifer/syrup/views.py	2009-03-10 00:38:42 UTC (rev 163)
+++ servres/trunk/conifer/syrup/views.py	2009-03-10 02:44:47 UTC (rev 164)
@@ -1,33 +1,50 @@
+#-----------------------------------------------------------------------------
+# todo: break this up. It's getting long. I think we should have
+# something like:
+#
+#   views/__init__.py                     # which imports:
+#   views/course_site_handlers.py
+#   views/search_stuff.py
+#   views/add_edit_course.py
+#   ...
+#   views/common_imports.py              # imported by all.
+#
+# though these are just examples. Everything in views/* would include
+# 'from common_imports import *' just to keep the imports
+# tidy. Views/__init__ would import all the other bits: that ought to
+# satisfy Django.
+
+from conifer.syrup import models
+from datetime import datetime
+from django.contrib.auth import authenticate, login, logout
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth.models import User
+from django.core.paginator import Paginator
+from django.db.models import Q
 from django.http import HttpResponse, HttpResponseRedirect
 from django.http import HttpResponseForbidden
-from django.core.paginator import Paginator
 from django.shortcuts import get_object_or_404
-from django.contrib.auth.decorators import login_required
-from django.contrib.auth import authenticate, login, logout
+from django.utils import simplejson
+from generics import *
+from gettext import gettext as _ # fixme, is this the right function to import?
 import conifer.genshi_support as g
+import django.forms
 import re
-from conifer.syrup import models
-from django.contrib.auth.models import User
-from django.db.models import Q
-import django.forms
-from datetime import datetime
-from generics import *
-from gettext import gettext as _ # fixme, is this the right function to import?
-from django.utils import simplejson
 import sys
 
 # Graham needs this import hackery to get PyZ3950 working. Presumably
-# Art can 'import profile', so this code won't run for him.
+# Art can 'import profile; import lex', so this hack won't run for
+# him.
 
 try:
     import profile
     import lex
     import yacc
 except ImportError:
-    sys.modules['profile'] = sys # just get something called profile;
+    sys.modules['profile'] = sys # just get something called 'profile';
                                  # it's not actually used.
     import ply.lex              
-    import ply.yacc             # pyz3950 thinks these are toplevel modules
+    import ply.yacc             # pyz3950 thinks these are toplevel modules.
     sys.modules['lex'] = ply.lex
     sys.modules['yacc'] = ply.yacc
 
@@ -36,6 +53,8 @@
 from PyZ3950 import zoom
 
 #-----------------------------------------------------------------------------
+# poor-man's logging. Not sure we need more yet.
+
 def log(level, msg):
     print >> sys.stderr, '[%s] %s: %s' % (datetime.now(), level.upper(), msg)
 
@@ -96,7 +115,7 @@
                     content=message,
                     _django_type=HttpResponseForbidden)
 
-
+# decorator
 def instructors_only(handler):
     def hdlr(request, course_id, *args, **kwargs):
         allowed = request.user.is_superuser
@@ -110,6 +129,7 @@
     return hdlr
 
 
+# decorator
 def members_only(handler):
     def hdlr(request, course_id, *args, **kwargs):
         allowed = request.user.is_superuser
@@ -121,6 +141,18 @@
             return _access_denied(_('Only course members are allowed here.'))
     return hdlr
 
+# decorator
+def admin_only(handler):
+    # fixme, 'admin' is vaguely defined for now as anyone who is
+    # 'staff', i.e. who has access to the Django admin interface.
+    def hdlr(request, *args, **kwargs):
+        allowed = request.user.is_staff
+        if allowed:
+            return handler(request, *args, **kwargs)
+        else:
+            return _access_denied(_('Only administrators are allowed here.'))
+    return hdlr
+
 #-----------------------------------------------------------------------------
 
 def welcome(request):
@@ -134,8 +166,6 @@
                     page_num=page_num,
                     count=count)
 
-#
-#
 def instructors(request):
     page_num = int(request.GET.get('page', 1))
     count = int(request.GET.get('count', 5))
@@ -206,21 +236,28 @@
 def my_courses(request):
     return g.render('my_courses.xhtml')
 
- at members_only
-def course_detail(request, course_id):
-    course = get_object_or_404(models.Course, pk=course_id)
-    if course.access != 'ANON' and request.user.is_anonymous():
-        #fixme, don't stop access just if anonymous, but rather if not
-        #allowed to access. We need to set up a permissions model.
-        return login_required(lambda *args: None)(request)
-    return g.render('course_detail.xhtml', course=course)
+def instructor_detail(request, instructor_id):
+    page_num = int(request.GET.get('page', 1))
+    count = int(request.GET.get('count', 5))
+    paginator = Paginator(models.Course.objects.
+        filter(member__id=instructor_id).
+        filter(active=True).order_by('title'), count)
 
- at members_only
-def course_search(request, course_id):
-    course = get_object_or_404(models.Course, pk=course_id)
-    return search(request, in_course=course)
+    return g.render('courses.xhtml', paginator=paginator,
+            page_num=page_num,
+            count=count)
 
+def department_detail(request, department_id):
+    page_num = int(request.GET.get('page', 1))
+    count = int(request.GET.get('count', 5))
+    paginator = Paginator(models.Course.objects.
+        filter(department__id=department_id).
+        filter(active=True).order_by('title'), count)
 
+    return g.render('courses.xhtml', paginator=paginator,
+            page_num=page_num,
+            count=count)
+
 #-----------------------------------------------------------------------------
 # Creating a new course
 
@@ -237,8 +274,8 @@
         else:
             raise ValidationError, _('invalid course code')
 
+# if we have course-code lookup, hack lookup support into the new-course form.
 
-# hack the new-course form if we have course-code lookup
 COURSE_CODE_LIST = bool(models.course_codes.course_code_list)
 COURSE_CODE_LOOKUP_TITLE = bool(models.course_codes.course_code_lookup_title)
 
@@ -252,6 +289,8 @@
     NewCourseForm.base_fields['code'].widget = Select(
         choices = choices)
     NewCourseForm.base_fields['code'].empty_label = empty_label
+
+#--------------------
     
 @login_required
 def add_new_course(request):
@@ -295,6 +334,7 @@
             else:
                 return HttpResponseRedirect('../') # back to main view.
 
+# no access-control needed to protect title lookup.
 def add_new_course_ajax_title(request):
     course_code = request.GET['course_code']
     title = models.course_codes.course_code_lookup_title(course_code)
@@ -407,6 +447,7 @@
         return HttpResponseRedirect('../')
 
 #-----------------------------------------------------------------------------
+# Course Invitation Code handler
 
 @login_required                 # must be, to avoid/audit brute force attacks.
 def course_invitation(request):
@@ -437,31 +478,20 @@
                                                role='STUDT')
             mbr.save()
         return HttpResponseRedirect(crs.course_url())
-        
+
 #-----------------------------------------------------------------------------
+# Course-instance handlers
 
-def instructor_detail(request, instructor_id):
-    page_num = int(request.GET.get('page', 1))
-    count = int(request.GET.get('count', 5))
-    paginator = Paginator(models.Course.objects.
-        filter(member__id=instructor_id).
-        filter(active=True).order_by('title'), count)
+ at members_only
+def course_detail(request, course_id):
+    course = get_object_or_404(models.Course, pk=course_id)
+    return g.render('course_detail.xhtml', course=course)
 
-    return g.render('courses.xhtml', paginator=paginator,
-            page_num=page_num,
-            count=count)
+ at members_only
+def course_search(request, course_id):
+    course = get_object_or_404(models.Course, pk=course_id)
+    return search(request, in_course=course)
 
-def department_detail(request, department_id):
-    page_num = int(request.GET.get('page', 1))
-    count = int(request.GET.get('count', 5))
-    paginator = Paginator(models.Course.objects.
-        filter(department__id=department_id).
-        filter(active=True).order_by('title'), count)
-
-    return g.render('courses.xhtml', paginator=paginator,
-            page_num=page_num,
-            count=count)
-
 @members_only
 def item_detail(request, course_id, item_id):
     """Display an item (however that makes sense).""" 
@@ -506,7 +536,7 @@
         course = get_object_or_404(models.Course, pk=course_id)
     else:
         parent_item = get_object_or_404(models.Item, pk=parent_item_id, course__id=course_id)
-        assert parent_item.item_type == 'HEADING', 'Can only add items to headings!'
+        assert parent_item.item_type == 'HEADING', _('You can only add items to headings!')
         course = parent_item.course
 
     if not course.can_edit(request.user):
@@ -515,7 +545,7 @@
     item_type = request.GET.get('item_type')
     assert item_type, _('No item_type parameter was provided.')
 
-    # for the moment, only HEADINGs, URLs and ELECs can be added.
+    # for the moment, only HEADINGs, URLs and ELECs can be added. fixme.
     assert item_type in ('HEADING', 'URL', 'ELEC'), \
         _('Sorry, only HEADINGs, URLs and ELECs can be added right now.')
 
@@ -651,7 +681,9 @@
             query = query & or_query
     return query
 
+
 #-----------------------------------------------------------------------------
+# Search and search support
 
 def search(request, in_course=None):
     ''' Need to work on this, the basic idea is
@@ -736,12 +768,12 @@
 
 
 #-----------------------------------------------------------------------------
-# administrative options
+# Administrative options
 
+ at admin_only
 def admin_index(request):
     return g.render('admin/index.xhtml')
 
-# fixme, no auth or permissions stuff yet.
 
 class TermForm(ModelForm):
     class Meta:
@@ -763,8 +795,9 @@
             raise ValidationError, _('start must precede finish')
         return cd
 
-admin_terms = generic_handler(TermForm)
+admin_terms = generic_handler(TermForm, decorator=admin_only)
 
+
 class DeptForm(ModelForm):
     class Meta:
         model = models.Department
@@ -778,7 +811,7 @@
     clean_abbreviation = strip_and_nonblank('abbreviation')
     clean_name = strip_and_nonblank('name')
 
-admin_depts = generic_handler(DeptForm)
+admin_depts = generic_handler(DeptForm, decorator=admin_only)
 
 
 class NewsForm(ModelForm):
@@ -794,4 +827,4 @@
     clean_subject = strip_and_nonblank('subject')
     clean_body = strip_and_nonblank('body')
 
-admin_news = generic_handler(NewsForm)
+admin_news = generic_handler(NewsForm, decorator=admin_only)



More information about the open-ils-commits mailing list