From 49a30b6d6b258bdc9bed193391ec316510c5c480 Mon Sep 17 00:00:00 2001 From: gfawcett Date: Mon, 27 Apr 2009 00:07:11 +0000 Subject: [PATCH] Enabled ANON courses. Search and browse results are now limited by user-permissions level. ANON courses are courses which are open to non-authenticated users. I'm not sure that this is a good idea yet, but it is useful for testing. Browsing will no longer show, for example, courses which the current user cannot enter. Search will not return items that the current user cannot view. This is extended to browse-instructors: if the instructor has no accessible courses, don't bother showing the course. git-svn-id: svn://svn.open-ils.org/ILS-Contrib/servres/trunk@396 6d9bc8c9-1ec2-4278-b937-99fde70a366f --- conifer/TODO | 10 +++++----- conifer/syrup/models.py | 2 +- conifer/syrup/views/_common.py | 27 +++++++++++++++++++++++++-- conifer/syrup/views/courses.py | 1 + conifer/syrup/views/general.py | 9 +++++++-- conifer/syrup/views/search.py | 40 ++++++++++++++++++++++++---------------- 6 files changed, 63 insertions(+), 26 deletions(-) diff --git a/conifer/TODO b/conifer/TODO index 6faf533..3bd75dd 100644 --- a/conifer/TODO +++ b/conifer/TODO @@ -2,14 +2,16 @@ CRITICAL: IMPORTANT: -* set up a proper issue-tracker? +* "create course site" (not "add course") -* CSS fixes for Internet Explorer. It looks crappy in IE. +* save-sequence fails on IE6. -* if someone has item checked out, show due date/time on item-about page. +* set up a proper issue-tracker? * need more than 10 results on physical-item search results. +* if someone has item checked out, show due date/time on item-about page. + * People should be able to register themselves into open courses. That is, actually become a member of them. @@ -21,8 +23,6 @@ IMPORTANT: * Send me email when my sites change? -* "create course site" (not "add course") - MAYBE: * Generating barcodes in emails, printable screens? (3 of 9 enough?) diff --git a/conifer/syrup/models.py b/conifer/syrup/models.py index c038980..df55421 100644 --- a/conifer/syrup/models.py +++ b/conifer/syrup/models.py @@ -56,7 +56,7 @@ class UserExtensionHack(object): """Return a queryset of all active instructors.""" # We are using the Django is_active flag to model activeness. return cls.objects.filter(member__role='INSTR', is_active=True) \ - .order_by('-last_name','-first_name') + .order_by('-last_name','-first_name').distinct() for k,v in [(k,v) for k,v in UserExtensionHack.__dict__.items() \ if not k.startswith('_')]: diff --git a/conifer/syrup/views/_common.py b/conifer/syrup/views/_common.py index 070ff05..60587a0 100644 --- a/conifer/syrup/views/_common.py +++ b/conifer/syrup/views/_common.py @@ -164,8 +164,8 @@ def members_only(handler): allowed = user.is_superuser if not allowed: course = models.Course.objects.get(pk=course_id) - allowed = ((user.is_anonymous() and course.access=='ANON') or \ - (user.is_authenticated() and course.access=='LOGIN')) + allowed = course.access=='ANON' or \ + (user.is_authenticated() and course.access=='LOGIN') if not allowed: allowed = _fast_user_membership_query(user.id, course_id) if allowed: @@ -216,3 +216,26 @@ def custom_400_handler(request): msg = simple_message(_('Not found'), _('The page you requested could not be found')) return HttpResponse(msg._container, status=404) + +#----------------------------------------------------------- + +def user_filters(user): + """Returns a dict of filters for Item, Course, etc. querysets, + based on the given user's permissions.""" + # TODO, figure out a way of EXPLAIN'ing these queries! I have no + # idea of their complexity. + if user.is_anonymous(): + # then only anonymous-access courses are available. + filters = {'items': Q(course__access='ANON'), + 'courses': Q(access='ANON'), + 'instructors': Q(member__course__access='ANON'), + } + else: + # logged-in users have access to courses which are of the + # LOGIN class ('all logged-in users') or in which they + # have explicit Member-ship. + filters = {'items': (Q(course__access__in=('LOGIN','ANON')) | Q(course__member__user=user)), + 'courses': (Q(access__in=('LOGIN','ANON')) | Q(member__user=user)), + 'instructors': (Q(member__course__access__in=('LOGIN','ANON')) | Q(member__course__member__user=user)), + } + return filters diff --git a/conifer/syrup/views/courses.py b/conifer/syrup/views/courses.py index 812dc46..062ca2a 100644 --- a/conifer/syrup/views/courses.py +++ b/conifer/syrup/views/courses.py @@ -91,6 +91,7 @@ def edit_course_permissions(request, course_id): # 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')), diff --git a/conifer/syrup/views/general.py b/conifer/syrup/views/general.py index edd17b9..0c3a0c4 100644 --- a/conifer/syrup/views/general.py +++ b/conifer/syrup/views/general.py @@ -85,16 +85,19 @@ def browse(request, browse_option=''): template = 'browse_index.xhtml' elif browse_option == 'instructors': queryset = models.User.active_instructors() + queryset = queryset.filter(user_filters(request.user)['instructors']) template = 'instructors.xhtml' elif browse_option == 'departments': queryset = models.Department.objects.filter(active=True) template = 'departments.xhtml' elif browse_option == 'courses': # fixme, course filter should not be (active=True) but based on user identity. - queryset = models.Course.objects.all() + for_courses = user_filters(request.user)['courses'] + queryset = models.Course.objects.filter(for_courses) template = 'courses.xhtml' - paginator = queryset and Paginator(queryset, count) or None # index has no queryset. + queryset = queryset and queryset.distinct() + paginator = Paginator(queryset, count) return g.render(template, paginator=paginator, page_num=page_num, count=count) @@ -112,6 +115,8 @@ def instructor_detail(request, instructor_id): ''' courses = models.Course.objects.filter(member__user=instructor_id, member__role='INSTR') + filters = user_filters(request.user) + courses = courses.filter(filters['courses']) paginator = Paginator(courses.order_by('title'), count) ''' diff --git a/conifer/syrup/views/search.py b/conifer/syrup/views/search.py index f83ad63..4525f4a 100644 --- a/conifer/syrup/views/search.py +++ b/conifer/syrup/views/search.py @@ -63,11 +63,14 @@ def search(request, in_course=None): # we start with an empty results_list, as a default results_list = models.Item.objects.filter(pk=-1) + # Next, we filter based on user permissions. + flt = user_filters(request.user) + user_filter_for_items, user_filter_for_courses = flt['items'], flt['courses'] + # Note, we haven't user-filtered anything yet; we've just set + # up the filters. + # numeric search: If the query-string is a single number, then - # we do an item-ID search, or a barcode search. fixme: - # item-ID is not a good short-id, since the physical item may - # be represented in multiple Item records. We need a - # short-number for barcodes. + # we do a short-number search, or a barcode search. if re.match(r'\d+', query_string): # Search by short ID. @@ -85,7 +88,13 @@ def search(request, in_course=None): results_list = models.Item.objects.filter(item_query) if in_course: + # For an in-course search, we know the user has + # permissions to view the course; no need for + # user_filter_for_items. results_list = results_list.filter(course=in_course) + else: + results_list = results_list.filter(user_filter_for_items) + results_list = results_list.order_by('title') results_len = len(results_list) paginator = Paginator(results_list, count) @@ -96,22 +105,21 @@ def search(request, in_course=None): course_list = []; course_len = 0 else: course_query = get_query(query_string, ['title', 'department__name']) - print 'course_query' - print course_query - course_results = models.Course.objects.filter(course_query).all() - # course_list = models.Course.objects.filter(course_query).filter(active=True).order_by('title')[0:5] - course_list = course_results.order_by('title')[0:5] - #there might be a better way of doing this, though instr and course tables should not be expensive to query - #len directly on course_list will reflect limit + # apply the search-filter and the user-filter + course_results = models.Course.objects.filter(course_query).filter(user_filter_for_courses) + course_list = course_results.order_by('title') course_len = len(course_results) #instructor search - instr_query = get_query(query_string, ['user__last_name']) - instructor_results = models.Member.objects.filter(instr_query).filter(role='INSTR') if in_course: - instructor_results = instructor_results.filter(course=in_course) - instructor_list = instructor_results.order_by('user__last_name')[0:5] - instr_len = len(instructor_results) + instructor_list = []; instr_len = 0 + else: + instr_query = get_query(query_string, ['user__last_name']) + instructor_results = models.Member.objects.filter(instr_query).filter(role='INSTR') + if in_course: + instructor_results = instructor_results.filter(course=in_course) + instructor_list = instructor_results.order_by('user__last_name')[0:5] + instr_len = len(instructor_results) elif in_course: # we are in a course, but have no query? Return to the course-home page. return HttpResponseRedirect('../') -- 2.11.0