[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