[open-ils-commits] r908 - in servres/trunk/conifer: integration static syrup/views templates templates/components templates/feeds (gfawcett)

svn at svn.open-ils.org svn at svn.open-ils.org
Wed Jul 14 20:53:58 EDT 2010


Author: gfawcett
Date: 2010-07-14 20:53:57 -0400 (Wed, 14 Jul 2010)
New Revision: 908

Added:
   servres/trunk/conifer/static/edit_site.js
   servres/trunk/conifer/static/edit_site_permissions.js
   servres/trunk/conifer/syrup/views/sites.py
   servres/trunk/conifer/templates/components/site.xhtml
   servres/trunk/conifer/templates/edit_site.xhtml
   servres/trunk/conifer/templates/edit_site_permissions.xhtml
   servres/trunk/conifer/templates/feeds/site_atom.xml
   servres/trunk/conifer/templates/feeds/site_feed_index.xhtml
   servres/trunk/conifer/templates/my_sites.xhtml
   servres/trunk/conifer/templates/open_sites.xhtml
   servres/trunk/conifer/templates/site_detail.xhtml
   servres/trunk/conifer/templates/site_invitation.xhtml
   servres/trunk/conifer/templates/site_join.xhtml
   servres/trunk/conifer/templates/sites.xhtml
Removed:
   servres/trunk/conifer/static/edit_course.js
   servres/trunk/conifer/static/edit_course_permissions.js
   servres/trunk/conifer/syrup/views/courses.py
   servres/trunk/conifer/templates/components/course.xhtml
   servres/trunk/conifer/templates/course_detail.xhtml
   servres/trunk/conifer/templates/course_invitation.xhtml
   servres/trunk/conifer/templates/course_join.xhtml
   servres/trunk/conifer/templates/courses.xhtml
   servres/trunk/conifer/templates/edit_course.xhtml
   servres/trunk/conifer/templates/edit_course_permissions.xhtml
   servres/trunk/conifer/templates/feeds/course_atom.xml
   servres/trunk/conifer/templates/feeds/course_feed_index.xhtml
   servres/trunk/conifer/templates/my_courses.xhtml
   servres/trunk/conifer/templates/open_courses.xhtml
Modified:
   servres/trunk/conifer/integration/hooks.py
Log:
rename 'course' files to 'site'

Modified: servres/trunk/conifer/integration/hooks.py
===================================================================
--- servres/trunk/conifer/integration/hooks.py	2010-07-15 00:53:47 UTC (rev 907)
+++ servres/trunk/conifer/integration/hooks.py	2010-07-15 00:53:57 UTC (rev 908)
@@ -4,5 +4,5 @@
 # Your hooks go here.
 
 # @hook
-# def can_create_reading_lists(user):
+# def can_create_sites(user):
 #     ...

Deleted: servres/trunk/conifer/static/edit_course.js
===================================================================
--- servres/trunk/conifer/static/edit_course.js	2010-07-15 00:53:47 UTC (rev 907)
+++ servres/trunk/conifer/static/edit_course.js	2010-07-15 00:53:57 UTC (rev 908)
@@ -1,16 +0,0 @@
-function do_init() {
-    if ($('#id_code').attr('tagName') == 'SELECT') {
-	// code is a SELECT, so we add a callback to lookup titles.
-	$('#id_code').change(function() {
-	    $('#id_title')[0].disabled=true;
-	    $.getJSON(ROOT + '/course/new/ajax_title', {course_code: $(this).val()},
-		      function(resp) {
-			  $('#id_title').val(resp.title)
-			  $('#id_title')[0].disabled=false;
-
-		      });
-	});
-    }
-}
-
-$(do_init);

Deleted: servres/trunk/conifer/static/edit_course_permissions.js
===================================================================
--- servres/trunk/conifer/static/edit_course_permissions.js	2010-07-15 00:53:47 UTC (rev 907)
+++ servres/trunk/conifer/static/edit_course_permissions.js	2010-07-15 00:53:57 UTC (rev 908)
@@ -1,12 +0,0 @@
-function do_init() {
-    show_specific_only();
-    $('#id_access').change(show_specific_only);
-}
-
-function show_specific_only() {
-    $('.specific').hide();
-    var cur = $('#id_access').val();
-    $('#' + cur + '_panel').fadeIn();
-}
-
-$(do_init);
\ No newline at end of file

Copied: servres/trunk/conifer/static/edit_site.js (from rev 907, servres/trunk/conifer/static/edit_course.js)
===================================================================
--- servres/trunk/conifer/static/edit_site.js	                        (rev 0)
+++ servres/trunk/conifer/static/edit_site.js	2010-07-15 00:53:57 UTC (rev 908)
@@ -0,0 +1,16 @@
+function do_init() {
+    if ($('#id_code').attr('tagName') == 'SELECT') {
+	// code is a SELECT, so we add a callback to lookup titles.
+	$('#id_code').change(function() {
+	    $('#id_title')[0].disabled=true;
+	    $.getJSON(ROOT + '/course/new/ajax_title', {course_code: $(this).val()},
+		      function(resp) {
+			  $('#id_title').val(resp.title)
+			  $('#id_title')[0].disabled=false;
+
+		      });
+	});
+    }
+}
+
+$(do_init);

Copied: servres/trunk/conifer/static/edit_site_permissions.js (from rev 907, servres/trunk/conifer/static/edit_course_permissions.js)
===================================================================
--- servres/trunk/conifer/static/edit_site_permissions.js	                        (rev 0)
+++ servres/trunk/conifer/static/edit_site_permissions.js	2010-07-15 00:53:57 UTC (rev 908)
@@ -0,0 +1,12 @@
+function do_init() {
+    show_specific_only();
+    $('#id_access').change(show_specific_only);
+}
+
+function show_specific_only() {
+    $('.specific').hide();
+    var cur = $('#id_access').val();
+    $('#' + cur + '_panel').fadeIn();
+}
+
+$(do_init);
\ No newline at end of file

Deleted: servres/trunk/conifer/syrup/views/courses.py
===================================================================
--- servres/trunk/conifer/syrup/views/courses.py	2010-07-15 00:53:47 UTC (rev 907)
+++ servres/trunk/conifer/syrup/views/courses.py	2010-07-15 00:53:57 UTC (rev 908)
@@ -1,259 +0,0 @@
-from _common import *
-from django.utils.translation import ugettext as _
-from search import *
-
-#-----------------------------------------------------------------------------
-# Creating a new course
-
-class NewCourseForm(ModelForm):
-    class Meta:
-        model = models.Course
-        exclude = ('passkey','access')
-
-    def clean_code(self):
-        v = (self.cleaned_data.get('code') or '').strip()
-        is_valid_func = models.campus.course_code_is_valid
-        if (not is_valid_func) or is_valid_func(v):
-            return v
-        else:
-            raise ValidationError, _('invalid course code')
-
-# if we have course-code lookup, hack lookup support into the new-course form.
-
-COURSE_CODE_LIST = bool(models.campus.course_code_list)
-COURSE_CODE_LOOKUP_TITLE = bool(models.campus.course_code_lookup_title)
-
-if COURSE_CODE_LIST:
-    from django.forms import Select
-    course_list = models.campus.course_code_list()
-    choices = [(a,a) for a in course_list]
-    choices.sort()
-    empty_label = u'---------'
-    choices.insert(0, ('', empty_label))
-    NewCourseForm.base_fields['code'].widget = Select(
-        choices = choices)
-    NewCourseForm.base_fields['code'].empty_label = empty_label
-
-#--------------------
-    
- at login_required
-def add_new_course(request):
-    if not request.user.can_create_reading_lists():
-        return _access_denied(_('You are not allowed to create course sites.'))
-    return _add_or_edit_course(request)
-
- at instructors_only
-def edit_course(request, course_id):
-    instance = get_object_or_404(models.Course, pk=course_id)
-    return _add_or_edit_course(request, instance=instance)
-    
-def _add_or_edit_course(request, instance=None):
-    is_add = (instance is None)
-    if is_add:
-        instance = models.Course()
-    current_access_level = not is_add and instance.access or None
-    example = models.campus.course_code_example
-    if request.method != 'POST':
-        form = NewCourseForm(instance=instance)
-        return g.render('edit_course.xhtml', **locals())
-    else:
-        form = NewCourseForm(request.POST, instance=instance)
-        if not form.is_valid():
-            return g.render('edit_course.xhtml', **locals())
-        else:
-            form.save()
-            course = form.instance
-            if course.access == u'INVIT' and not course.passkey:
-                course.generate_new_passkey()
-                course.save()
-            assert course.id
-            user_in_course = models.Member.objects.filter(user=request.user,course=course)
-            if not user_in_course: # for edits, might already be!
-                mbr = course.member_set.create(user=request.user, role='INSTR')
-                mbr.save()
-            
-            if is_add or (current_access_level != course.access):
-                # we need to configure permissions.
-                return HttpResponseRedirect(course.course_url('edit/permission/'))
-            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.campus.course_code_lookup_title(course_code)
-    return HttpResponse(simplejson.dumps({'title':title}))
-
- at instructors_only
-def edit_course_permissions(request, course_id):
-    course = get_object_or_404(models.Course, pk=course_id)
-    # choices: make the access-choice labels more personalized than
-    # the ones in 'models'.
-    choices = [
-        # note: I'm leaving ANON out for now, until we discuss it further.
-        (u'ANON', _(u'Anyone on the planet may access this site.')),
-        (u'CLOSE', _(u'No students: this site is closed.')),
-        (u'STUDT', _(u'Students in my course -- I will provide section numbers')),
-        (u'INVIT', _(u'Students in my course -- I will share an Invitation Code with them')),
-        (u'LOGIN', _(u'All Reserves patrons'))]
-    if models.campus.sections_tuple_delimiter is None:
-        # no course-sections support? Then STUDT cannot be an option.
-        del choices[1]
-    choose_access = django.forms.Select(choices=choices)
-        
-    if request.method != 'POST':
-        return g.render('edit_course_permissions.xhtml', **locals())
-    else:
-        POST = request.POST
-
-        if 'action_change_code' in POST:
-            # update invitation code -------------------------------------
-            course.generate_new_passkey()
-            course.access = u'INVIT'
-            course.save()
-            return HttpResponseRedirect('.#student_access')
-
-        elif 'action_save_instructor' in POST:
-            # update instructor details ----------------------------------
-            iname = POST.get('new_instructor_name','').strip()
-            irole = POST.get('new_instructor_role')
-
-            def get_record_for(username):
-                instr = models.maybe_initialize_user(iname)
-                if instr:
-                    try:
-                        return models.Member.objects.get(user=instr, course=course)
-                    except models.Member.DoesNotExist:
-                        return models.Member.objects.create(user=instr, course=course)
-
-            # add a new instructor
-            if iname:
-                instr = get_record_for(iname)
-                if instr:       # else? should have an error.
-                    instr.role = irole
-                    instr.save()
-                else:
-                    instructor_error = 'No such user: %s' % iname
-                    return g.render('edit_course_permissions.xhtml', **locals())
-
-
-            # removing and changing roles of instructors
-            to_change_role = [(int(name.rsplit('_', 1)[-1]), POST[name]) \
-                                  for name in POST if name.startswith('instructor_role_')]
-            to_remove = [int(name.rsplit('_', 1)[-1]) \
-                             for name in POST if name.startswith('instructor_remove_')]
-            for instr_id, newrole in to_change_role:
-                if not instr_id in to_remove:
-                    instr = models.Member.objects.get(pk=instr_id, course=course)
-                    instr.role = newrole
-                    instr.save()
-            for instr_id in to_remove:
-                # todo, should warn if deleting yourself!
-                instr = models.Member.objects.get(pk=instr_id, course=course)
-                instr.delete()
-            # todo, should have some error-reporting.
-            return HttpResponseRedirect('.')
-
-        elif 'action_save_student' in POST:
-            # update student details ------------------------------------
-            access = POST.get('access')
-            course.access = access
-            # drop all provided users. fixme, this could be optimized to do add/drops.
-            models.Member.objects.filter(course=course, provided=True).delete()
-            if course.access == u'STUDT':
-                initial_sections = course.sections()
-                # add the 'new section' if any
-                new_sec = request.POST.get('add_section')
-                new_sec = models.section_decode_safe(new_sec)
-                if new_sec:
-                    course.add_sections(new_sec)
-                # remove the sections to be dropped
-                to_remove = [models.section_decode_safe(name.rsplit('_',1)[1]) \
-                                 for name in POST \
-                                 if name.startswith('remove_section_')]
-                course.drop_sections(*to_remove)
-                student_names = models.campus.students_in(*course.sections())
-                for name in student_names:
-                    user = models.maybe_initialize_user(name)
-                    if user:
-                        if not models.Member.objects.filter(course=course, user=user):
-                            mbr = models.Member.objects.create(
-                                course=course, user=user, 
-                                role='STUDT', provided=True)
-                            mbr.save()
-            else:
-                pass
-            course.save()
-            return HttpResponseRedirect('.#student_access')
-
- at instructors_only
-def delete_course(request, course_id):
-    course = get_object_or_404(models.Course, pk=course_id)
-    if request.POST.get('confirm_delete'):
-        course.delete()
-        return HttpResponseRedirect(reverse('my_courses'))
-    else:
-        return HttpResponseRedirect('../')
-
-#-----------------------------------------------------------------------------
-# Course Invitation Code handler
-
- at login_required                 # must be, to avoid/audit brute force attacks.
-def course_invitation(request):
-    if request.method != 'POST':
-        return g.render('course_invitation.xhtml', code='', error='',
-                        **locals())
-    else:
-        code = request.POST.get('code', '').strip()
-        # todo, a pluggable passkey implementation would normalize the code here.
-        if not code:
-            return HttpResponseRedirect('.')
-        try:
-            # note, we only allow the passkey if access='INVIT'.
-            crs = models.ReadingList.objects.filter(access='INVIT').get(passkey=code)
-        except models.ReadingList.DoesNotExist:
-            # todo, do we need a formal logging system? Or a table for
-            # invitation failures? They should be captured somehow, I
-            # think. Should we temporarily disable accounts after
-            # multiple failures?
-            log('WARN', 'Invitation failure, user %r gave code %r' % \
-                (request.user.username, code))
-            error = _('The code you provided is not valid.')
-            return g.render('course_invitation.xhtml', **locals())
-
-        # the passkey is good; add the user if not already a member.
-        if not models.Member.objects.filter(user=request.user, course=crs):
-            mbr = models.Member.objects.create(user=request.user, course=crs, 
-                                               role='STUDT')
-            mbr.save()
-        return HttpResponseRedirect(crs.course_url())
-
-#-----------------------------------------------------------------------------
-# ReadingList-instance handlers
-
- at members_only
-def course_detail(request, course_id):
-    course = get_object_or_404(models.ReadingList, pk=course_id)
-    return g.render('course_detail.xhtml', course=course)
-
- at members_only
-def course_search(request, course_id):
-    course = get_object_or_404(models.ReadingList, pk=course_id)
-    return search(request, in_course=course)
-
- at login_required
-def course_join(request, course_id):
-    """Self-register into an open-registration course."""
-    course = get_object_or_404(models.ReadingList, pk=course_id)
-    if not course.is_joinable_by(request.user):
-        # user should never see this.
-        return simple_message(_('You cannot join this course.'), 
-                              _('Sorry, but you cannot join this course at this time.'))
-    elif request.method != 'POST':
-        return g.render('course_join.xhtml', course=course)
-    else:
-        mbr = models.Member.objects.create(user=request.user, course=course, role='STUDT')
-        mbr.save()
-        return HttpResponseRedirect(course.course_url())
-
-       

Copied: servres/trunk/conifer/syrup/views/sites.py (from rev 907, servres/trunk/conifer/syrup/views/courses.py)
===================================================================
--- servres/trunk/conifer/syrup/views/sites.py	                        (rev 0)
+++ servres/trunk/conifer/syrup/views/sites.py	2010-07-15 00:53:57 UTC (rev 908)
@@ -0,0 +1,259 @@
+from _common import *
+from django.utils.translation import ugettext as _
+from search import *
+
+#-----------------------------------------------------------------------------
+# Creating a new course
+
+class NewCourseForm(ModelForm):
+    class Meta:
+        model = models.Course
+        exclude = ('passkey','access')
+
+    def clean_code(self):
+        v = (self.cleaned_data.get('code') or '').strip()
+        is_valid_func = models.campus.course_code_is_valid
+        if (not is_valid_func) or is_valid_func(v):
+            return v
+        else:
+            raise ValidationError, _('invalid course code')
+
+# if we have course-code lookup, hack lookup support into the new-course form.
+
+COURSE_CODE_LIST = bool(models.campus.course_code_list)
+COURSE_CODE_LOOKUP_TITLE = bool(models.campus.course_code_lookup_title)
+
+if COURSE_CODE_LIST:
+    from django.forms import Select
+    course_list = models.campus.course_code_list()
+    choices = [(a,a) for a in course_list]
+    choices.sort()
+    empty_label = u'---------'
+    choices.insert(0, ('', empty_label))
+    NewCourseForm.base_fields['code'].widget = Select(
+        choices = choices)
+    NewCourseForm.base_fields['code'].empty_label = empty_label
+
+#--------------------
+    
+ at login_required
+def add_new_course(request):
+    if not request.user.can_create_reading_lists():
+        return _access_denied(_('You are not allowed to create course sites.'))
+    return _add_or_edit_course(request)
+
+ at instructors_only
+def edit_course(request, course_id):
+    instance = get_object_or_404(models.Course, pk=course_id)
+    return _add_or_edit_course(request, instance=instance)
+    
+def _add_or_edit_course(request, instance=None):
+    is_add = (instance is None)
+    if is_add:
+        instance = models.Course()
+    current_access_level = not is_add and instance.access or None
+    example = models.campus.course_code_example
+    if request.method != 'POST':
+        form = NewCourseForm(instance=instance)
+        return g.render('edit_course.xhtml', **locals())
+    else:
+        form = NewCourseForm(request.POST, instance=instance)
+        if not form.is_valid():
+            return g.render('edit_course.xhtml', **locals())
+        else:
+            form.save()
+            course = form.instance
+            if course.access == u'INVIT' and not course.passkey:
+                course.generate_new_passkey()
+                course.save()
+            assert course.id
+            user_in_course = models.Member.objects.filter(user=request.user,course=course)
+            if not user_in_course: # for edits, might already be!
+                mbr = course.member_set.create(user=request.user, role='INSTR')
+                mbr.save()
+            
+            if is_add or (current_access_level != course.access):
+                # we need to configure permissions.
+                return HttpResponseRedirect(course.course_url('edit/permission/'))
+            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.campus.course_code_lookup_title(course_code)
+    return HttpResponse(simplejson.dumps({'title':title}))
+
+ at instructors_only
+def edit_course_permissions(request, course_id):
+    course = get_object_or_404(models.Course, pk=course_id)
+    # choices: make the access-choice labels more personalized than
+    # the ones in 'models'.
+    choices = [
+        # note: I'm leaving ANON out for now, until we discuss it further.
+        (u'ANON', _(u'Anyone on the planet may access this site.')),
+        (u'CLOSE', _(u'No students: this site is closed.')),
+        (u'STUDT', _(u'Students in my course -- I will provide section numbers')),
+        (u'INVIT', _(u'Students in my course -- I will share an Invitation Code with them')),
+        (u'LOGIN', _(u'All Reserves patrons'))]
+    if models.campus.sections_tuple_delimiter is None:
+        # no course-sections support? Then STUDT cannot be an option.
+        del choices[1]
+    choose_access = django.forms.Select(choices=choices)
+        
+    if request.method != 'POST':
+        return g.render('edit_course_permissions.xhtml', **locals())
+    else:
+        POST = request.POST
+
+        if 'action_change_code' in POST:
+            # update invitation code -------------------------------------
+            course.generate_new_passkey()
+            course.access = u'INVIT'
+            course.save()
+            return HttpResponseRedirect('.#student_access')
+
+        elif 'action_save_instructor' in POST:
+            # update instructor details ----------------------------------
+            iname = POST.get('new_instructor_name','').strip()
+            irole = POST.get('new_instructor_role')
+
+            def get_record_for(username):
+                instr = models.maybe_initialize_user(iname)
+                if instr:
+                    try:
+                        return models.Member.objects.get(user=instr, course=course)
+                    except models.Member.DoesNotExist:
+                        return models.Member.objects.create(user=instr, course=course)
+
+            # add a new instructor
+            if iname:
+                instr = get_record_for(iname)
+                if instr:       # else? should have an error.
+                    instr.role = irole
+                    instr.save()
+                else:
+                    instructor_error = 'No such user: %s' % iname
+                    return g.render('edit_course_permissions.xhtml', **locals())
+
+
+            # removing and changing roles of instructors
+            to_change_role = [(int(name.rsplit('_', 1)[-1]), POST[name]) \
+                                  for name in POST if name.startswith('instructor_role_')]
+            to_remove = [int(name.rsplit('_', 1)[-1]) \
+                             for name in POST if name.startswith('instructor_remove_')]
+            for instr_id, newrole in to_change_role:
+                if not instr_id in to_remove:
+                    instr = models.Member.objects.get(pk=instr_id, course=course)
+                    instr.role = newrole
+                    instr.save()
+            for instr_id in to_remove:
+                # todo, should warn if deleting yourself!
+                instr = models.Member.objects.get(pk=instr_id, course=course)
+                instr.delete()
+            # todo, should have some error-reporting.
+            return HttpResponseRedirect('.')
+
+        elif 'action_save_student' in POST:
+            # update student details ------------------------------------
+            access = POST.get('access')
+            course.access = access
+            # drop all provided users. fixme, this could be optimized to do add/drops.
+            models.Member.objects.filter(course=course, provided=True).delete()
+            if course.access == u'STUDT':
+                initial_sections = course.sections()
+                # add the 'new section' if any
+                new_sec = request.POST.get('add_section')
+                new_sec = models.section_decode_safe(new_sec)
+                if new_sec:
+                    course.add_sections(new_sec)
+                # remove the sections to be dropped
+                to_remove = [models.section_decode_safe(name.rsplit('_',1)[1]) \
+                                 for name in POST \
+                                 if name.startswith('remove_section_')]
+                course.drop_sections(*to_remove)
+                student_names = models.campus.students_in(*course.sections())
+                for name in student_names:
+                    user = models.maybe_initialize_user(name)
+                    if user:
+                        if not models.Member.objects.filter(course=course, user=user):
+                            mbr = models.Member.objects.create(
+                                course=course, user=user, 
+                                role='STUDT', provided=True)
+                            mbr.save()
+            else:
+                pass
+            course.save()
+            return HttpResponseRedirect('.#student_access')
+
+ at instructors_only
+def delete_course(request, course_id):
+    course = get_object_or_404(models.Course, pk=course_id)
+    if request.POST.get('confirm_delete'):
+        course.delete()
+        return HttpResponseRedirect(reverse('my_courses'))
+    else:
+        return HttpResponseRedirect('../')
+
+#-----------------------------------------------------------------------------
+# Course Invitation Code handler
+
+ at login_required                 # must be, to avoid/audit brute force attacks.
+def course_invitation(request):
+    if request.method != 'POST':
+        return g.render('course_invitation.xhtml', code='', error='',
+                        **locals())
+    else:
+        code = request.POST.get('code', '').strip()
+        # todo, a pluggable passkey implementation would normalize the code here.
+        if not code:
+            return HttpResponseRedirect('.')
+        try:
+            # note, we only allow the passkey if access='INVIT'.
+            crs = models.ReadingList.objects.filter(access='INVIT').get(passkey=code)
+        except models.ReadingList.DoesNotExist:
+            # todo, do we need a formal logging system? Or a table for
+            # invitation failures? They should be captured somehow, I
+            # think. Should we temporarily disable accounts after
+            # multiple failures?
+            log('WARN', 'Invitation failure, user %r gave code %r' % \
+                (request.user.username, code))
+            error = _('The code you provided is not valid.')
+            return g.render('course_invitation.xhtml', **locals())
+
+        # the passkey is good; add the user if not already a member.
+        if not models.Member.objects.filter(user=request.user, course=crs):
+            mbr = models.Member.objects.create(user=request.user, course=crs, 
+                                               role='STUDT')
+            mbr.save()
+        return HttpResponseRedirect(crs.course_url())
+
+#-----------------------------------------------------------------------------
+# ReadingList-instance handlers
+
+ at members_only
+def course_detail(request, course_id):
+    course = get_object_or_404(models.ReadingList, pk=course_id)
+    return g.render('course_detail.xhtml', course=course)
+
+ at members_only
+def course_search(request, course_id):
+    course = get_object_or_404(models.ReadingList, pk=course_id)
+    return search(request, in_course=course)
+
+ at login_required
+def course_join(request, course_id):
+    """Self-register into an open-registration course."""
+    course = get_object_or_404(models.ReadingList, pk=course_id)
+    if not course.is_joinable_by(request.user):
+        # user should never see this.
+        return simple_message(_('You cannot join this course.'), 
+                              _('Sorry, but you cannot join this course at this time.'))
+    elif request.method != 'POST':
+        return g.render('course_join.xhtml', course=course)
+    else:
+        mbr = models.Member.objects.create(user=request.user, course=course, role='STUDT')
+        mbr.save()
+        return HttpResponseRedirect(course.course_url())
+
+       

Deleted: servres/trunk/conifer/templates/components/course.xhtml
===================================================================
--- servres/trunk/conifer/templates/components/course.xhtml	2010-07-15 00:53:47 UTC (rev 907)
+++ servres/trunk/conifer/templates/components/course.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -1,125 +0,0 @@
-<?python
-searchtext = _('search this course...')
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
-      xmlns:py="http://genshi.edgewall.org/"
-      xmlns:xi="http://www.w3.org/2001/XInclude"
-      py:strip="">
-  
-  <div py:def="course_search(course)" id="coursesearch" style="float: right;">
-    <form method="get" action="${course.course_url('search')}" 
-	  onsubmit="if(q.value.replace(/^\s*/, '').replace(/\s*$/, '') =='') return false;">
-      <input id="q" name="q" maxlength="100" size="25" type="text" 
-	     value="${searchtext}" onblur="if(this.value=='') this.value='${searchtext}';" 
-	     onfocus="if(this.value=='${searchtext}') this.value='';"/>
-    </form>
-  </div>
-  
-  <div py:def="course_banner(course)" py:strip="True">
-    <div id="coursebanner">
-      ${course_search(course)}
-      <div class="deptident">${course.department}</div>
-      <h1><a href="${course.course_url()}"><span py:if="course.code">${course.code}: </span>${course.title}</a></h1>
-    </div>
-  </div>
-  
-  <!-- !show_tree: display a tree of items in a hierarchical style. -->
-  <ul py:def="show_tree(tree, edit=False)"
-      py:if="tree"
-      class="itemtree">
-    <li py:for="item, subs in tree" class="item_${item.item_type} an_item"
-	id="item_${item.id}">
-      <div class="mainline ${item.item_type=='HEADING' and 'headingmainline' or ''}">
-	<a href="${item.item_url()}" class="mainlink">${item}</a> 
-	<span class="menublock" py:if="not (item.item_type=='HEADING' and not edit)">
-
-	  <!-- !I'm really sorry, this is ugly, but I want
-	       non-breaking spaces here, so that on long-named items,
-	       the links will stay togeter. A better way?  -->
-	  <span py:if="item.needs_meta_link()"><a href="${item.item_url('meta')}">about</a>&#160;</span><span py:if="edit">&bull;&#160;<a href="${item.item_url('edit/')}">edit</a></span><span py:if="edit">&#160;&bull;&#160;<a href="${item.item_url('relocate/')}">relocate</a></span>
-	</span>
-      </div>
-      <!-- !to show a full tree, uncomment the following: -->
-      ${show_tree(subs, edit)}
-    </li>
-  </ul>
-
-  <ul py:def="heading_tree(tree, stop_at=None)" class="heading_tree">
-    <li><input type="radio" name="heading" value="0" id="heading_0"/><label for="heading_0">Top Level</label></li>
-    ${_heading_tree(tree, stop_at)}
-  </ul>
-
-  <ul py:def="_heading_tree(tree, stop_at=None)">
-    <li py:for="item, subs in tree" py:if="item.item_type=='HEADING' and item != stop_at">
-      <input type="radio" name="heading" value="${item.id}" id="heading_${item.id}"/><label for="heading_${item.id}">${item}</label>
-      ${_heading_tree(subs, stop_at)}
-      </li>
-  </ul>
-  
-  <div py:def="nested_title(item)"
-       py:if="item"
-       py:with="hier=item.hierarchy()[:-1]; lastnum=len(hier)"
-       class="nestedtitle">
-    <div id="breadcrumbs">
-      <span><a href="${item.course.course_url()}">Top</a></span> &raquo;
-      <span py:for="n, x in enumerate(hier)"><a href="${x.item_url()}">${x.title}</a> &raquo; </span>
-      <span class="final_item">${item.title}</span>
-    </div>
-  </div>
-  
-  <div py:def="add_subs(parent=None)" class="itemadd">
-    <div>Add a new item:</div>
-    <ul py:with="prefix = (not parent) and 'item/0/' or ''">
-      <li><a href="${prefix}add/?item_type=HEADING">Subheading</a></li>
-      <li><a href="${prefix}add/?item_type=URL">URL</a></li>
-      <li><a href="${prefix}add/?item_type=ELEC">Electronic Document</a></li>
-      <li><a href="${prefix}add/?item_type=PHYS">Physical Item or Catalogued Electronic Item</a></li>
-    </ul>
-  </div>
-
-  <div py:def="item_metadata_formset_header()" py:strip="True">
-    <script type="text/javascript">
-      $(function() {$('#metadatatable').hide(); });
-      function show_metadata() {
-      $('#metadatatable').show();
-      $('#show_metadata').fadeOut();
-      }
-    </script>
-  </div>
-
-  <div py:def="item_metadata_formset(show_more=True)">
-      <p py:if="show_more"><a href="javascript:show_metadata();" id="show_metadata">Show more attributes</a></p>
-      <div  id="metadatatable">
-      ${Markup(metadata_formset.management_form)}
-      <table class="metadata_table">
-	<thead>
-	  <tr><th>Attribute</th><th>Value</th><th/><th>Delete?</th></tr>
-	</thead>
-	<tbody>
-	<tr py:for="form in metadata_formset.forms">
-	  <td py:if="cell" class="meta${n}" py:for="n, cell in enumerate(form)">${Markup(cell)}</td>
-	</tr>
-	</tbody>
-      </table>
-      </div>
-   </div>
-
-   <div py:def="item_resequence_panel()" py:strip="True">
-    <div id="resequence_panel" class="little_action_panel">
-      <a href="javascript:doResequence();">Resequence items</a>
-      <div id="ropanelmessage" style="clear: right; display: none;"
-	   class="little_action_panel">Drag the items around. Then click Save Sequence, above.</div>
-    </div>
-    <div style="display: none;">
-      <span id="i18n-save-order">Save Sequence</span>
-      <span id="i18n-resequence-items">Resequence Items</span>
-      <span id="i18n-new-order-saved">The new sequence has been saved.</span>
-    </div>
-    </div>
-
-    <div py:def="offer_to_delete(item)" class="little_action_panel" py:if="item.id">
-      <a href="../delete/">Delete this item</a>
-    </div>
-
-</html>
-

Copied: servres/trunk/conifer/templates/components/site.xhtml (from rev 907, servres/trunk/conifer/templates/components/course.xhtml)
===================================================================
--- servres/trunk/conifer/templates/components/site.xhtml	                        (rev 0)
+++ servres/trunk/conifer/templates/components/site.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -0,0 +1,125 @@
+<?python
+searchtext = _('search this course...')
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://genshi.edgewall.org/"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      py:strip="">
+  
+  <div py:def="course_search(course)" id="coursesearch" style="float: right;">
+    <form method="get" action="${course.course_url('search')}" 
+	  onsubmit="if(q.value.replace(/^\s*/, '').replace(/\s*$/, '') =='') return false;">
+      <input id="q" name="q" maxlength="100" size="25" type="text" 
+	     value="${searchtext}" onblur="if(this.value=='') this.value='${searchtext}';" 
+	     onfocus="if(this.value=='${searchtext}') this.value='';"/>
+    </form>
+  </div>
+  
+  <div py:def="course_banner(course)" py:strip="True">
+    <div id="coursebanner">
+      ${course_search(course)}
+      <div class="deptident">${course.department}</div>
+      <h1><a href="${course.course_url()}"><span py:if="course.code">${course.code}: </span>${course.title}</a></h1>
+    </div>
+  </div>
+  
+  <!-- !show_tree: display a tree of items in a hierarchical style. -->
+  <ul py:def="show_tree(tree, edit=False)"
+      py:if="tree"
+      class="itemtree">
+    <li py:for="item, subs in tree" class="item_${item.item_type} an_item"
+	id="item_${item.id}">
+      <div class="mainline ${item.item_type=='HEADING' and 'headingmainline' or ''}">
+	<a href="${item.item_url()}" class="mainlink">${item}</a> 
+	<span class="menublock" py:if="not (item.item_type=='HEADING' and not edit)">
+
+	  <!-- !I'm really sorry, this is ugly, but I want
+	       non-breaking spaces here, so that on long-named items,
+	       the links will stay togeter. A better way?  -->
+	  <span py:if="item.needs_meta_link()"><a href="${item.item_url('meta')}">about</a>&#160;</span><span py:if="edit">&bull;&#160;<a href="${item.item_url('edit/')}">edit</a></span><span py:if="edit">&#160;&bull;&#160;<a href="${item.item_url('relocate/')}">relocate</a></span>
+	</span>
+      </div>
+      <!-- !to show a full tree, uncomment the following: -->
+      ${show_tree(subs, edit)}
+    </li>
+  </ul>
+
+  <ul py:def="heading_tree(tree, stop_at=None)" class="heading_tree">
+    <li><input type="radio" name="heading" value="0" id="heading_0"/><label for="heading_0">Top Level</label></li>
+    ${_heading_tree(tree, stop_at)}
+  </ul>
+
+  <ul py:def="_heading_tree(tree, stop_at=None)">
+    <li py:for="item, subs in tree" py:if="item.item_type=='HEADING' and item != stop_at">
+      <input type="radio" name="heading" value="${item.id}" id="heading_${item.id}"/><label for="heading_${item.id}">${item}</label>
+      ${_heading_tree(subs, stop_at)}
+      </li>
+  </ul>
+  
+  <div py:def="nested_title(item)"
+       py:if="item"
+       py:with="hier=item.hierarchy()[:-1]; lastnum=len(hier)"
+       class="nestedtitle">
+    <div id="breadcrumbs">
+      <span><a href="${item.course.course_url()}">Top</a></span> &raquo;
+      <span py:for="n, x in enumerate(hier)"><a href="${x.item_url()}">${x.title}</a> &raquo; </span>
+      <span class="final_item">${item.title}</span>
+    </div>
+  </div>
+  
+  <div py:def="add_subs(parent=None)" class="itemadd">
+    <div>Add a new item:</div>
+    <ul py:with="prefix = (not parent) and 'item/0/' or ''">
+      <li><a href="${prefix}add/?item_type=HEADING">Subheading</a></li>
+      <li><a href="${prefix}add/?item_type=URL">URL</a></li>
+      <li><a href="${prefix}add/?item_type=ELEC">Electronic Document</a></li>
+      <li><a href="${prefix}add/?item_type=PHYS">Physical Item or Catalogued Electronic Item</a></li>
+    </ul>
+  </div>
+
+  <div py:def="item_metadata_formset_header()" py:strip="True">
+    <script type="text/javascript">
+      $(function() {$('#metadatatable').hide(); });
+      function show_metadata() {
+      $('#metadatatable').show();
+      $('#show_metadata').fadeOut();
+      }
+    </script>
+  </div>
+
+  <div py:def="item_metadata_formset(show_more=True)">
+      <p py:if="show_more"><a href="javascript:show_metadata();" id="show_metadata">Show more attributes</a></p>
+      <div  id="metadatatable">
+      ${Markup(metadata_formset.management_form)}
+      <table class="metadata_table">
+	<thead>
+	  <tr><th>Attribute</th><th>Value</th><th/><th>Delete?</th></tr>
+	</thead>
+	<tbody>
+	<tr py:for="form in metadata_formset.forms">
+	  <td py:if="cell" class="meta${n}" py:for="n, cell in enumerate(form)">${Markup(cell)}</td>
+	</tr>
+	</tbody>
+      </table>
+      </div>
+   </div>
+
+   <div py:def="item_resequence_panel()" py:strip="True">
+    <div id="resequence_panel" class="little_action_panel">
+      <a href="javascript:doResequence();">Resequence items</a>
+      <div id="ropanelmessage" style="clear: right; display: none;"
+	   class="little_action_panel">Drag the items around. Then click Save Sequence, above.</div>
+    </div>
+    <div style="display: none;">
+      <span id="i18n-save-order">Save Sequence</span>
+      <span id="i18n-resequence-items">Resequence Items</span>
+      <span id="i18n-new-order-saved">The new sequence has been saved.</span>
+    </div>
+    </div>
+
+    <div py:def="offer_to_delete(item)" class="little_action_panel" py:if="item.id">
+      <a href="../delete/">Delete this item</a>
+    </div>
+
+</html>
+

Deleted: servres/trunk/conifer/templates/course_detail.xhtml
===================================================================
--- servres/trunk/conifer/templates/course_detail.xhtml	2010-07-15 00:53:47 UTC (rev 907)
+++ servres/trunk/conifer/templates/course_detail.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -1,40 +0,0 @@
-<?python
-title = '%s: %s (%s)' % (course.code, course.title, course.term)
-item_tree = course.item_tree()
-is_editor = course.can_edit(request.user)
-is_joinable = course.is_joinable_by(request.user)
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
-      xmlns:xi="http://www.w3.org/2001/XInclude"
-      xmlns:py="http://genshi.edgewall.org/">
-  <xi:include href="master.xhtml"/>
-  <xi:include href="components/course.xhtml"/>
-  <head>
-    <title>${title}</title>
-    <script type="text/javascript" src="${ROOT}/static/menublocks.js"/>
-  </head>
-  <body>
-    ${course_banner(course)}
-    <p py:if="not item_tree">
-      There are no items associated with this course yet.
-    </p>
-    <div id="sidepanel">
-      <div py:if="is_editor" id="edit_course" class="little_action_panel">
-	<a href="${course.course_url()}edit/">Edit course details</a>
-      </div>
-      <div py:if="is_joinable">
-	<a href="${course.course_url()}join/">Join this course</a>
-      </div>
-      <div id="showtree_panel" class="little_action_panel">
-	<a href="javascript:doToggleItemTree();">Show/hide tree</a>
-      </div>
-      <div py:if="is_editor">${item_resequence_panel()}</div>
-    </div>
-    <div id="treepanel">
-      ${show_tree(item_tree, edit=is_editor)}
-    </div>
-    <div py:if="is_editor">${add_subs()}</div>
-
-
-  </body>
-</html>

Deleted: servres/trunk/conifer/templates/course_invitation.xhtml
===================================================================
--- servres/trunk/conifer/templates/course_invitation.xhtml	2010-07-15 00:53:47 UTC (rev 907)
+++ servres/trunk/conifer/templates/course_invitation.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -1,32 +0,0 @@
-<?python
-title = _('Join a course using an Invitation Code')
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
-      xmlns:xi="http://www.w3.org/2001/XInclude"
-      xmlns:py="http://genshi.edgewall.org/">
-<xi:include href="master.xhtml"/>
-<head>
-  <title>${title}</title>
-  <script>
-    $(function() {
-    $('#code').focus();
-    });
-  </script>
-</head>
-<body>
-  <h1>${title}</h1>
-  <p>Your instructor may have provided you with an Invitation Code,
-  which will give you access to your course's reserves. Enter the
-  invitation code below to continue. Note that not all courses require
-  an invitation code; contact your instructor or the library staff for
-  more information.</p>
-  <div class="errors" py:if="error">${error}</div>
-  <form action="." method="POST">
-  <table class="metadata_table">
-    <tr><th>Invitation Code:</th><td><input type="text" id="code" name="code" size="30" value="${code}"/></td></tr>
-  </table>
-<p><input type="submit" value="Continue"/> ${go_back_link()}</p>
-  </form>
-  <div class="gap"/>
-</body>
-</html>

Deleted: servres/trunk/conifer/templates/course_join.xhtml
===================================================================
--- servres/trunk/conifer/templates/course_join.xhtml	2010-07-15 00:53:47 UTC (rev 907)
+++ servres/trunk/conifer/templates/course_join.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -1,24 +0,0 @@
-<?python
-title = _('Join this course?')
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
-      xmlns:xi="http://www.w3.org/2001/XInclude"
-      xmlns:py="http://genshi.edgewall.org/">
-  <xi:include href="master.xhtml"/>
-  <xi:include href="components/course.xhtml"/>
-  <head>
-    <title>${title}</title>
-    <script type="text/javascript" src="${ROOT}/static/menublocks.js"/>
-  </head>
-  <body>
-    ${course_banner(course)}
-    <h2>${title}</h2>
-
-    <p>If you choose to join this course, it will be added to your "My
-    Courses" list.</p>
-    <form action="." method="POST">
-      <p><input type="submit" value="Yes, join this course"/> ${go_back_link()}</p>
-    </form>    
-
-  </body>
-</html>

Deleted: servres/trunk/conifer/templates/courses.xhtml
===================================================================
--- servres/trunk/conifer/templates/courses.xhtml	2010-07-15 00:53:47 UTC (rev 907)
+++ servres/trunk/conifer/templates/courses.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -1,26 +0,0 @@
-<?python
-title = defined('custom_title') and custom_title or _('Courses')
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
-      xmlns:xi="http://www.w3.org/2001/XInclude"
-      xmlns:py="http://genshi.edgewall.org/">
-<xi:include href="master.xhtml"/>
-<xi:include href="paginate.xhtml"/>
-<head>
-  <title>${title}</title>
-  <script type="text/javascript">
-    <!-- !This ought to be in paginate.xhtml, not here. how to do? -->
-    $(function() { $('.pagetable').tablesorter(); });
-  </script>
-</head>
-<body>
-  <h1>${title}</h1>
-  <tr py:def="pageheader()">
-    <th>Name</th>
-  </tr>
-  <span py:def="pagerow(item)">
-    <td><a href="${item.course_url()}">${item.title}, ${item.term}</a></td>
-  </span>
-  ${pagetable(paginator, count, pagerow, pageheader)}
-</body>
-</html>

Deleted: servres/trunk/conifer/templates/edit_course.xhtml
===================================================================
--- servres/trunk/conifer/templates/edit_course.xhtml	2010-07-15 00:53:47 UTC (rev 907)
+++ servres/trunk/conifer/templates/edit_course.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -1,52 +0,0 @@
-<?python
-if instance.id:
-    title = _('Edit course details')
-else:
-    title = _('Create a new course site')
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
-      xmlns:xi="http://www.w3.org/2001/XInclude"
-      xmlns:py="http://genshi.edgewall.org/">
-<xi:include href="master.xhtml"/>
-<xi:include href="components/course.xhtml"/>
-<head>
-  <title>${title}</title>
-  <script type="text/javascript" src="${ROOT}/static/edit_course.js"/>
-</head>
-<body>
-  <div py:if="instance.id">${course_banner(instance)}</div>
-  <h1>${title}</h1>
-  <p py:if="instance.id"><a href="permission/">Edit course permissions</a> &bull; <a href="${instance.course_url()}">Return to course page</a></p>
-  <form action="." method="POST">
-    <tr py:def="field_row(field, example=None)">
-      <th>${field.label}</th>
-      <td>
-	<ul py:if="field.errors" class="errorlist">
-	  <li py:for="err in field.errors">${err}</li>
-	</ul>
-	${Markup(field)}
-      </td>
-      <td class="example" py:if="example">e.g., ${example}</td>
-    </tr>
-    <h2>General description</h2>
-    <table class="metadata_table">
-    ${field_row(form.code, example)}
-    ${field_row(form.title)}
-    ${field_row(form.term)}
-    ${field_row(form.department)}
-    <!-- <tr><th>Department</th><td>${Markup(form.department)} ${errorlist(form.department)}</td></tr> -->
-  </table>
-  <p><input type="submit" value="Continue"/> ${go_back_link()}</p>
-  </form>
-  <div class="gap"/>
-  <div py:if="instance.id">
-    <h2>Delete this course</h2>
-    <form action="delete/" method="POST">
-      <p><input type="checkbox" name="confirm_delete" id="confirm_delete"/>
-      <label for="confirm_delete">Yes, I want to delete this course site and all of its contents.</label>
-      </p>
-      <p><input type="submit" value="Delete this course"/> ${go_back_link()}</p>
-    </form>
-  </div>
-</body>
-</html>

Deleted: servres/trunk/conifer/templates/edit_course_permissions.xhtml
===================================================================
--- servres/trunk/conifer/templates/edit_course_permissions.xhtml	2010-07-15 00:53:47 UTC (rev 907)
+++ servres/trunk/conifer/templates/edit_course_permissions.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -1,113 +0,0 @@
-<?python
-title = _('Edit course permissions')
-instructors = [m for m in models.Member.objects.filter(course=course) if m.role in ('PROXY', 'INSTR')]
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
-      xmlns:xi="http://www.w3.org/2001/XInclude"
-      xmlns:py="http://genshi.edgewall.org/">
-<xi:include href="master.xhtml"/>
-  <xi:include href="components/course.xhtml"/>
-<head>
-  <title>${title}</title>
-  <script type="text/javascript" src="${ROOT}/static/edit_course_permissions.js"/>
-</head>
-<body>
-  ${course_banner(course)}
-  <h1>${title}</h1>
-  <p><a href="../">Edit course details</a> &bull; <a href="${course.course_url()}">Return to course page</a></p>
-  <form action="." method="POST">
-    <h2>Instructor Access</h2>
-    <div py:if="defined('instructor_error')" class="errors">${instructor_error}</div>
-    <table class="pagetable">
-      <thead>
-	<tr><th>Person</th><th>Role</th><th>Remove?</th></tr>
-      </thead>
-      <tbody>
-	<select py:def="select_role(mbr)" 
-		py:replace="Markup(django.forms.Select(choices=
-			    [(u'INSTR',_('Instructor')), (u'PROXY', _('Proxy instructor'))])
-			    .render('instructor_role_%d' % mbr.id, mbr.role))"/>
-      <tr py:for="mbr in instructors">
-	<td>${mbr.user.get_full_name() or ''} <code>(${mbr.user.username})</code></td>
-	<td>${select_role(mbr)}</td>
-	<td><input type="checkbox" name="instructor_remove_${mbr.id}"/></td>
-      </tr>
-      <tr style="vertical-align: bottom;">
-	<td><p>Username of the new instructor.</p><input type="text" name="new_instructor_name"/></td>
-	<td><select name="new_instructor_role">
-	  <option value="INSTR">Instructor</option>
-	  <option value="PROXY">Proxy instructor</option>
-	  </select>
-	</td>
-	<td/>
-      </tr>
-      </tbody>
-    </table>
-    <p>	  <input type="submit" name="action_save_instructor" value="Save changes to instructors"/></p>
-    <div class="gap"/>
-    <h2 id="student_access">Student Access</h2>
-    <p>Who will have student-level access to this site?
-    <span style="margin-left: 12;"/>${Markup(choose_access.render('access', course.access, {'id':'id_access'}, []))}</p>
-    <div id="INVIT_panel" class="specific">
-      <h3>Course Invitation Code</h3>
-      <p style="font-size: larger;">Your Course Invitation Code is: <strong>${course.passkey}</strong>
-      <span style="margin-left: 16;">
-	  <input type="submit" name="action_change_code" value="Select a new code"/>
-      </span>
-      </p>
-      <p>This invitation code will enable your students to join this
-      course site. Share it only with your students: anyone who has
-      the code can join your site.</p>
-      <p>You may change the code at any time. This will not block
-      students who have already joined, but will prevent new students
-      from joining with the old code.</p>
-    </div>
-    <div id="STUDT_panel" class="specific">
-      <h3>Course section numbers</h3>
-	<?python
-	  current_sections = course.sections()
-	  my_sections = [s for s in models.campus.sections_taught_by(user.username) if not s in current_sections]
-	  ct_sections = [s for s in models.campus.sections_for_code_and_term(course.code, course.term.code) \
-                         if not s in current_sections]
-          encode = lambda t,c,s: models.section_encode_safe((t,c,s))
-	?>
-      <table class="pagetable">
-	<thead>
-	  <tr>
-	    <th>Associated section</th><th>Remove?</th>
-	  </tr>
-	</thead>
-	<tbody>	    
-	<tr py:for="(term, code, sec) in current_sections">
-	  <td>${code}, section ${sec}, in term ${term}</td>
-	  <td><input type="checkbox" name="remove_section_${encode(term,code,sec)}"/></td>
-	</tr>
-	</tbody>
-      </table>
-      <p>Add section: 
-      <select name="add_section">
-	<option value="">--------</option>
-	<optgroup py:for="label, sections in ((_('My Courses'), my_sections), (_('%s in term %s') % (course.code, course.term), ct_sections))"
-		  label="${label}" py:if="sections">
-	  <option py:for="(term, code, sec) in sections"
-		  value="${encode(term,code,sec)}">
-	    ${code}, section ${sec}, in term ${term}
-	  </option>
-	</optgroup>
-	</select>
-      </p>
-    </div>
-    <p><input type="submit" name="action_save_student" value="Save changes to student access"/></p>
-
-    <div class="gap"/>
-    <h2>Class List</h2>
-    <p>The following users have student-level access in this course site.</p>
-    <ol>
-      <li py:for="student in course.get_students()">
-	${student.get_full_name()} (${student.email})
-      </li>
-    </ol>
-  </form>
-  <div class="gap"/>
-</body>
-</html>

Copied: servres/trunk/conifer/templates/edit_site.xhtml (from rev 907, servres/trunk/conifer/templates/edit_course.xhtml)
===================================================================
--- servres/trunk/conifer/templates/edit_site.xhtml	                        (rev 0)
+++ servres/trunk/conifer/templates/edit_site.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -0,0 +1,52 @@
+<?python
+if instance.id:
+    title = _('Edit course details')
+else:
+    title = _('Create a new course site')
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:py="http://genshi.edgewall.org/">
+<xi:include href="master.xhtml"/>
+<xi:include href="components/course.xhtml"/>
+<head>
+  <title>${title}</title>
+  <script type="text/javascript" src="${ROOT}/static/edit_course.js"/>
+</head>
+<body>
+  <div py:if="instance.id">${course_banner(instance)}</div>
+  <h1>${title}</h1>
+  <p py:if="instance.id"><a href="permission/">Edit course permissions</a> &bull; <a href="${instance.course_url()}">Return to course page</a></p>
+  <form action="." method="POST">
+    <tr py:def="field_row(field, example=None)">
+      <th>${field.label}</th>
+      <td>
+	<ul py:if="field.errors" class="errorlist">
+	  <li py:for="err in field.errors">${err}</li>
+	</ul>
+	${Markup(field)}
+      </td>
+      <td class="example" py:if="example">e.g., ${example}</td>
+    </tr>
+    <h2>General description</h2>
+    <table class="metadata_table">
+    ${field_row(form.code, example)}
+    ${field_row(form.title)}
+    ${field_row(form.term)}
+    ${field_row(form.department)}
+    <!-- <tr><th>Department</th><td>${Markup(form.department)} ${errorlist(form.department)}</td></tr> -->
+  </table>
+  <p><input type="submit" value="Continue"/> ${go_back_link()}</p>
+  </form>
+  <div class="gap"/>
+  <div py:if="instance.id">
+    <h2>Delete this course</h2>
+    <form action="delete/" method="POST">
+      <p><input type="checkbox" name="confirm_delete" id="confirm_delete"/>
+      <label for="confirm_delete">Yes, I want to delete this course site and all of its contents.</label>
+      </p>
+      <p><input type="submit" value="Delete this course"/> ${go_back_link()}</p>
+    </form>
+  </div>
+</body>
+</html>

Copied: servres/trunk/conifer/templates/edit_site_permissions.xhtml (from rev 907, servres/trunk/conifer/templates/edit_course_permissions.xhtml)
===================================================================
--- servres/trunk/conifer/templates/edit_site_permissions.xhtml	                        (rev 0)
+++ servres/trunk/conifer/templates/edit_site_permissions.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -0,0 +1,113 @@
+<?python
+title = _('Edit course permissions')
+instructors = [m for m in models.Member.objects.filter(course=course) if m.role in ('PROXY', 'INSTR')]
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:py="http://genshi.edgewall.org/">
+<xi:include href="master.xhtml"/>
+  <xi:include href="components/course.xhtml"/>
+<head>
+  <title>${title}</title>
+  <script type="text/javascript" src="${ROOT}/static/edit_course_permissions.js"/>
+</head>
+<body>
+  ${course_banner(course)}
+  <h1>${title}</h1>
+  <p><a href="../">Edit course details</a> &bull; <a href="${course.course_url()}">Return to course page</a></p>
+  <form action="." method="POST">
+    <h2>Instructor Access</h2>
+    <div py:if="defined('instructor_error')" class="errors">${instructor_error}</div>
+    <table class="pagetable">
+      <thead>
+	<tr><th>Person</th><th>Role</th><th>Remove?</th></tr>
+      </thead>
+      <tbody>
+	<select py:def="select_role(mbr)" 
+		py:replace="Markup(django.forms.Select(choices=
+			    [(u'INSTR',_('Instructor')), (u'PROXY', _('Proxy instructor'))])
+			    .render('instructor_role_%d' % mbr.id, mbr.role))"/>
+      <tr py:for="mbr in instructors">
+	<td>${mbr.user.get_full_name() or ''} <code>(${mbr.user.username})</code></td>
+	<td>${select_role(mbr)}</td>
+	<td><input type="checkbox" name="instructor_remove_${mbr.id}"/></td>
+      </tr>
+      <tr style="vertical-align: bottom;">
+	<td><p>Username of the new instructor.</p><input type="text" name="new_instructor_name"/></td>
+	<td><select name="new_instructor_role">
+	  <option value="INSTR">Instructor</option>
+	  <option value="PROXY">Proxy instructor</option>
+	  </select>
+	</td>
+	<td/>
+      </tr>
+      </tbody>
+    </table>
+    <p>	  <input type="submit" name="action_save_instructor" value="Save changes to instructors"/></p>
+    <div class="gap"/>
+    <h2 id="student_access">Student Access</h2>
+    <p>Who will have student-level access to this site?
+    <span style="margin-left: 12;"/>${Markup(choose_access.render('access', course.access, {'id':'id_access'}, []))}</p>
+    <div id="INVIT_panel" class="specific">
+      <h3>Course Invitation Code</h3>
+      <p style="font-size: larger;">Your Course Invitation Code is: <strong>${course.passkey}</strong>
+      <span style="margin-left: 16;">
+	  <input type="submit" name="action_change_code" value="Select a new code"/>
+      </span>
+      </p>
+      <p>This invitation code will enable your students to join this
+      course site. Share it only with your students: anyone who has
+      the code can join your site.</p>
+      <p>You may change the code at any time. This will not block
+      students who have already joined, but will prevent new students
+      from joining with the old code.</p>
+    </div>
+    <div id="STUDT_panel" class="specific">
+      <h3>Course section numbers</h3>
+	<?python
+	  current_sections = course.sections()
+	  my_sections = [s for s in models.campus.sections_taught_by(user.username) if not s in current_sections]
+	  ct_sections = [s for s in models.campus.sections_for_code_and_term(course.code, course.term.code) \
+                         if not s in current_sections]
+          encode = lambda t,c,s: models.section_encode_safe((t,c,s))
+	?>
+      <table class="pagetable">
+	<thead>
+	  <tr>
+	    <th>Associated section</th><th>Remove?</th>
+	  </tr>
+	</thead>
+	<tbody>	    
+	<tr py:for="(term, code, sec) in current_sections">
+	  <td>${code}, section ${sec}, in term ${term}</td>
+	  <td><input type="checkbox" name="remove_section_${encode(term,code,sec)}"/></td>
+	</tr>
+	</tbody>
+      </table>
+      <p>Add section: 
+      <select name="add_section">
+	<option value="">--------</option>
+	<optgroup py:for="label, sections in ((_('My Courses'), my_sections), (_('%s in term %s') % (course.code, course.term), ct_sections))"
+		  label="${label}" py:if="sections">
+	  <option py:for="(term, code, sec) in sections"
+		  value="${encode(term,code,sec)}">
+	    ${code}, section ${sec}, in term ${term}
+	  </option>
+	</optgroup>
+	</select>
+      </p>
+    </div>
+    <p><input type="submit" name="action_save_student" value="Save changes to student access"/></p>
+
+    <div class="gap"/>
+    <h2>Class List</h2>
+    <p>The following users have student-level access in this course site.</p>
+    <ol>
+      <li py:for="student in course.get_students()">
+	${student.get_full_name()} (${student.email})
+      </li>
+    </ol>
+  </form>
+  <div class="gap"/>
+</body>
+</html>

Deleted: servres/trunk/conifer/templates/feeds/course_atom.xml
===================================================================
--- servres/trunk/conifer/templates/feeds/course_atom.xml	2010-07-15 00:53:47 UTC (rev 907)
+++ servres/trunk/conifer/templates/feeds/course_atom.xml	2010-07-15 00:53:57 UTC (rev 908)
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<feed xmlns="http://www.w3.org/2005/Atom"
-      xmlns:xi="http://www.w3.org/2001/XInclude"
-      xmlns:py="http://genshi.edgewall.org/">
-  <title>Reserves (${feed_type}) for ${course.list_display()}</title>
-  <link href="${root}${course.course_url()}"
-  rel="alternate"/>
-  <link href="${root}${course.course_url('feeds/' + feed_type)}"
-  rel="self"/>
-  <id>${root}${course.course_url('feeds/') + feed_type}</id>
-  <updated>${lastmod.strftime("%Y-%m-%dT%H:%M:%SZ")}</updated>
-  <entry py:for="item in items">
-    <title>${render_title(item)}</title>
-    <link href="${root}${item.item_url(force_local_url=True)}"
-    rel="alternate"></link>
-    <updated>${item.last_modified.strftime("%Y-%m-%dT%H:%M:%SZ")}</updated>
-    <id>${root}${item.item_url('')}</id>
-    <summary type="html">${item.get_item_type_display()}.
-    <div py:if="item.item_type=='HEADING'" py:strip="True">
-      Contains ${len(models.Item.objects.filter(parent_heading=item))} items.
-    </div>
-  </summary>
-  </entry>
-</feed>

Deleted: servres/trunk/conifer/templates/feeds/course_feed_index.xhtml
===================================================================
--- servres/trunk/conifer/templates/feeds/course_feed_index.xhtml	2010-07-15 00:53:47 UTC (rev 907)
+++ servres/trunk/conifer/templates/feeds/course_feed_index.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -1,22 +0,0 @@
-<?python
-title = _('Available Feeds')
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
-      xmlns:xi="http://www.w3.org/2001/XInclude"
-      xmlns:py="http://genshi.edgewall.org/">
-  <xi:include href="../master.xhtml"/>
-  <xi:include href="../components/course.xhtml"/>
-  <head>
-    <title>${title}</title>
-    <script type="text/javascript" src="${ROOT}/static/menublocks.js"/>
-  </head>
-  <body>
-    ${course_banner(course)}
-    <h2>Available Feeds</h2>
-    <ul>
-      <li><a href="recent-changes">Recent changes</a></li>
-      <li><a href="top-level">Top level items in this site</a></li>
-      <li><a href="tree">Tree-walk of all items in this site</a></li>
-    </ul>
-  </body>
-</html>

Copied: servres/trunk/conifer/templates/feeds/site_atom.xml (from rev 907, servres/trunk/conifer/templates/feeds/course_atom.xml)
===================================================================
--- servres/trunk/conifer/templates/feeds/site_atom.xml	                        (rev 0)
+++ servres/trunk/conifer/templates/feeds/site_atom.xml	2010-07-15 00:53:57 UTC (rev 908)
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:py="http://genshi.edgewall.org/">
+  <title>Reserves (${feed_type}) for ${course.list_display()}</title>
+  <link href="${root}${course.course_url()}"
+  rel="alternate"/>
+  <link href="${root}${course.course_url('feeds/' + feed_type)}"
+  rel="self"/>
+  <id>${root}${course.course_url('feeds/') + feed_type}</id>
+  <updated>${lastmod.strftime("%Y-%m-%dT%H:%M:%SZ")}</updated>
+  <entry py:for="item in items">
+    <title>${render_title(item)}</title>
+    <link href="${root}${item.item_url(force_local_url=True)}"
+    rel="alternate"></link>
+    <updated>${item.last_modified.strftime("%Y-%m-%dT%H:%M:%SZ")}</updated>
+    <id>${root}${item.item_url('')}</id>
+    <summary type="html">${item.get_item_type_display()}.
+    <div py:if="item.item_type=='HEADING'" py:strip="True">
+      Contains ${len(models.Item.objects.filter(parent_heading=item))} items.
+    </div>
+  </summary>
+  </entry>
+</feed>

Copied: servres/trunk/conifer/templates/feeds/site_feed_index.xhtml (from rev 907, servres/trunk/conifer/templates/feeds/course_feed_index.xhtml)
===================================================================
--- servres/trunk/conifer/templates/feeds/site_feed_index.xhtml	                        (rev 0)
+++ servres/trunk/conifer/templates/feeds/site_feed_index.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -0,0 +1,22 @@
+<?python
+title = _('Available Feeds')
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:py="http://genshi.edgewall.org/">
+  <xi:include href="../master.xhtml"/>
+  <xi:include href="../components/course.xhtml"/>
+  <head>
+    <title>${title}</title>
+    <script type="text/javascript" src="${ROOT}/static/menublocks.js"/>
+  </head>
+  <body>
+    ${course_banner(course)}
+    <h2>Available Feeds</h2>
+    <ul>
+      <li><a href="recent-changes">Recent changes</a></li>
+      <li><a href="top-level">Top level items in this site</a></li>
+      <li><a href="tree">Tree-walk of all items in this site</a></li>
+    </ul>
+  </body>
+</html>

Deleted: servres/trunk/conifer/templates/my_courses.xhtml
===================================================================
--- servres/trunk/conifer/templates/my_courses.xhtml	2010-07-15 00:53:47 UTC (rev 907)
+++ servres/trunk/conifer/templates/my_courses.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -1,29 +0,0 @@
-<?python
-title = _('My Reserves')
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
-      xmlns:xi="http://www.w3.org/2001/XInclude"
-      xmlns:py="http://genshi.edgewall.org/">
-<xi:include href="master.xhtml"/>
-<head>
-  <title>${title}</title>
-</head>
-<body>
-  <h1>${title}</h1>
-  <?python
-    if user.is_authenticated():
-        my_courses = user.reading_lists()
-    else:
-        my_courses = []
-  ?>
-  <p py:if="not my_courses">You are not part of any course reserves at this time.</p>
-  <p py:for="course in my_courses" style="font-size: large;">
-    <a href="${course.id}/">${course.list_display()}</a>
-  </p>
-  <div class="gap"/>
-  <div class="itemadd">
-  <p py:if="user.can_create_reading_lists()"><a href="new/">Create a new course reserves list</a></p>
-  <p><a href="invitation/">Join a reserves list using an Invitation Code</a></p>
-  </div>
-</body>
-</html>

Copied: servres/trunk/conifer/templates/my_sites.xhtml (from rev 907, servres/trunk/conifer/templates/my_courses.xhtml)
===================================================================
--- servres/trunk/conifer/templates/my_sites.xhtml	                        (rev 0)
+++ servres/trunk/conifer/templates/my_sites.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -0,0 +1,29 @@
+<?python
+title = _('My Reserves')
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:py="http://genshi.edgewall.org/">
+<xi:include href="master.xhtml"/>
+<head>
+  <title>${title}</title>
+</head>
+<body>
+  <h1>${title}</h1>
+  <?python
+    if user.is_authenticated():
+        my_courses = user.reading_lists()
+    else:
+        my_courses = []
+  ?>
+  <p py:if="not my_courses">You are not part of any course reserves at this time.</p>
+  <p py:for="course in my_courses" style="font-size: large;">
+    <a href="${course.id}/">${course.list_display()}</a>
+  </p>
+  <div class="gap"/>
+  <div class="itemadd">
+  <p py:if="user.can_create_reading_lists()"><a href="new/">Create a new course reserves list</a></p>
+  <p><a href="invitation/">Join a reserves list using an Invitation Code</a></p>
+  </div>
+</body>
+</html>

Deleted: servres/trunk/conifer/templates/open_courses.xhtml
===================================================================
--- servres/trunk/conifer/templates/open_courses.xhtml	2010-07-15 00:53:47 UTC (rev 907)
+++ servres/trunk/conifer/templates/open_courses.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -1,31 +0,0 @@
-<?python
-title = _('Open Courses')
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
-      xmlns:xi="http://www.w3.org/2001/XInclude"
-      xmlns:py="http://genshi.edgewall.org/">
-<xi:include href="master.xhtml"/>
-<xi:include href="paginate.xhtml"/>
-<head>
-  <title>${title}</title>
-  <script type="text/javascript">
-    <!-- !This ought to be in paginate.xhtml, not here. how to do? -->
-    $(function() { $('.pagetable').tablesorter(); });
-  </script>
-</head>
-<body>
-  <h1>${title}</h1>
-  <tr py:def="pageheader()">
-    <th>Term</th><th>Code</th><th>Title</th>
-  </tr>
-  <span py:def="pagerow(item)">
-    <td>${item.term}</td>
-    <td><a href="../course/${item.id}/">${item.code}</a></td>
-    <td><a href="../course/${item.id}/">${item.title}</a></td>
-  </span>
-    <!--
-  ${pagetable(paginator, start, count, pagerow, pageheader)}
-    -->
-  ${pagetable(paginator, count, pagerow, pageheader)}
-</body>
-</html>

Copied: servres/trunk/conifer/templates/open_sites.xhtml (from rev 907, servres/trunk/conifer/templates/open_courses.xhtml)
===================================================================
--- servres/trunk/conifer/templates/open_sites.xhtml	                        (rev 0)
+++ servres/trunk/conifer/templates/open_sites.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -0,0 +1,31 @@
+<?python
+title = _('Open Courses')
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:py="http://genshi.edgewall.org/">
+<xi:include href="master.xhtml"/>
+<xi:include href="paginate.xhtml"/>
+<head>
+  <title>${title}</title>
+  <script type="text/javascript">
+    <!-- !This ought to be in paginate.xhtml, not here. how to do? -->
+    $(function() { $('.pagetable').tablesorter(); });
+  </script>
+</head>
+<body>
+  <h1>${title}</h1>
+  <tr py:def="pageheader()">
+    <th>Term</th><th>Code</th><th>Title</th>
+  </tr>
+  <span py:def="pagerow(item)">
+    <td>${item.term}</td>
+    <td><a href="../course/${item.id}/">${item.code}</a></td>
+    <td><a href="../course/${item.id}/">${item.title}</a></td>
+  </span>
+    <!--
+  ${pagetable(paginator, start, count, pagerow, pageheader)}
+    -->
+  ${pagetable(paginator, count, pagerow, pageheader)}
+</body>
+</html>

Copied: servres/trunk/conifer/templates/site_detail.xhtml (from rev 907, servres/trunk/conifer/templates/course_detail.xhtml)
===================================================================
--- servres/trunk/conifer/templates/site_detail.xhtml	                        (rev 0)
+++ servres/trunk/conifer/templates/site_detail.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -0,0 +1,40 @@
+<?python
+title = '%s: %s (%s)' % (course.code, course.title, course.term)
+item_tree = course.item_tree()
+is_editor = course.can_edit(request.user)
+is_joinable = course.is_joinable_by(request.user)
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:py="http://genshi.edgewall.org/">
+  <xi:include href="master.xhtml"/>
+  <xi:include href="components/course.xhtml"/>
+  <head>
+    <title>${title}</title>
+    <script type="text/javascript" src="${ROOT}/static/menublocks.js"/>
+  </head>
+  <body>
+    ${course_banner(course)}
+    <p py:if="not item_tree">
+      There are no items associated with this course yet.
+    </p>
+    <div id="sidepanel">
+      <div py:if="is_editor" id="edit_course" class="little_action_panel">
+	<a href="${course.course_url()}edit/">Edit course details</a>
+      </div>
+      <div py:if="is_joinable">
+	<a href="${course.course_url()}join/">Join this course</a>
+      </div>
+      <div id="showtree_panel" class="little_action_panel">
+	<a href="javascript:doToggleItemTree();">Show/hide tree</a>
+      </div>
+      <div py:if="is_editor">${item_resequence_panel()}</div>
+    </div>
+    <div id="treepanel">
+      ${show_tree(item_tree, edit=is_editor)}
+    </div>
+    <div py:if="is_editor">${add_subs()}</div>
+
+
+  </body>
+</html>

Copied: servres/trunk/conifer/templates/site_invitation.xhtml (from rev 907, servres/trunk/conifer/templates/course_invitation.xhtml)
===================================================================
--- servres/trunk/conifer/templates/site_invitation.xhtml	                        (rev 0)
+++ servres/trunk/conifer/templates/site_invitation.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -0,0 +1,32 @@
+<?python
+title = _('Join a course using an Invitation Code')
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:py="http://genshi.edgewall.org/">
+<xi:include href="master.xhtml"/>
+<head>
+  <title>${title}</title>
+  <script>
+    $(function() {
+    $('#code').focus();
+    });
+  </script>
+</head>
+<body>
+  <h1>${title}</h1>
+  <p>Your instructor may have provided you with an Invitation Code,
+  which will give you access to your course's reserves. Enter the
+  invitation code below to continue. Note that not all courses require
+  an invitation code; contact your instructor or the library staff for
+  more information.</p>
+  <div class="errors" py:if="error">${error}</div>
+  <form action="." method="POST">
+  <table class="metadata_table">
+    <tr><th>Invitation Code:</th><td><input type="text" id="code" name="code" size="30" value="${code}"/></td></tr>
+  </table>
+<p><input type="submit" value="Continue"/> ${go_back_link()}</p>
+  </form>
+  <div class="gap"/>
+</body>
+</html>

Copied: servres/trunk/conifer/templates/site_join.xhtml (from rev 907, servres/trunk/conifer/templates/course_join.xhtml)
===================================================================
--- servres/trunk/conifer/templates/site_join.xhtml	                        (rev 0)
+++ servres/trunk/conifer/templates/site_join.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -0,0 +1,24 @@
+<?python
+title = _('Join this course?')
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:py="http://genshi.edgewall.org/">
+  <xi:include href="master.xhtml"/>
+  <xi:include href="components/course.xhtml"/>
+  <head>
+    <title>${title}</title>
+    <script type="text/javascript" src="${ROOT}/static/menublocks.js"/>
+  </head>
+  <body>
+    ${course_banner(course)}
+    <h2>${title}</h2>
+
+    <p>If you choose to join this course, it will be added to your "My
+    Courses" list.</p>
+    <form action="." method="POST">
+      <p><input type="submit" value="Yes, join this course"/> ${go_back_link()}</p>
+    </form>    
+
+  </body>
+</html>

Copied: servres/trunk/conifer/templates/sites.xhtml (from rev 907, servres/trunk/conifer/templates/courses.xhtml)
===================================================================
--- servres/trunk/conifer/templates/sites.xhtml	                        (rev 0)
+++ servres/trunk/conifer/templates/sites.xhtml	2010-07-15 00:53:57 UTC (rev 908)
@@ -0,0 +1,26 @@
+<?python
+title = defined('custom_title') and custom_title or _('Courses')
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:py="http://genshi.edgewall.org/">
+<xi:include href="master.xhtml"/>
+<xi:include href="paginate.xhtml"/>
+<head>
+  <title>${title}</title>
+  <script type="text/javascript">
+    <!-- !This ought to be in paginate.xhtml, not here. how to do? -->
+    $(function() { $('.pagetable').tablesorter(); });
+  </script>
+</head>
+<body>
+  <h1>${title}</h1>
+  <tr py:def="pageheader()">
+    <th>Name</th>
+  </tr>
+  <span py:def="pagerow(item)">
+    <td><a href="${item.course_url()}">${item.title}, ${item.term}</a></td>
+  </span>
+  ${pagetable(paginator, count, pagerow, pageheader)}
+</body>
+</html>



More information about the open-ils-commits mailing list