From 6708675fecd5e11ea463e4bdaf228e01566264fd Mon Sep 17 00:00:00 2001 From: Dan Helfman Date: Fri, 31 Oct 2008 15:17:59 -0700 Subject: [PATCH] Factored out page navigation (pagination) code and made use of it on forum thread list page. --- controller/Forums.py | 29 +++++++++++----- model/User.py | 81 +++++++++++++++++++++++++++++++++++++++++--- view/Forum_page.py | 7 +++- view/Main_page.py | 52 +++++----------------------- 4 files changed, 112 insertions(+), 57 deletions(-) diff --git a/controller/Forums.py b/controller/Forums.py index 1188905..73806ba 100644 --- a/controller/Forums.py +++ b/controller/Forums.py @@ -91,9 +91,11 @@ class Forum( object ): @end_transaction @grab_user_id @validate( + start = Valid_int( min = 0 ), + count = Valid_int( min = 1, max = 50 ), user_id = Valid_id( none_okay = True ), ) - def index( self, user_id ): + def index( self, start = 0, count = 50, user_id = None ): """ Provide the information necessary to display the current threads within a forum. @@ -111,23 +113,34 @@ class Forum( object ): if anonymous is None: raise Access_error() - # load a list of the threads in this forum, excluding those with a default name - threads = [ thread for thread in self.__database.select_many( + # load a slice of the list of the threads in this forum, excluding those with a default name + threads = self.__database.select_many( Notebook, anonymous.sql_load_notebooks( - parents_only = False, undeleted_only = True, tag_name = u"forum", tag_value = self.__name + parents_only = False, undeleted_only = True, tag_name = u"forum", tag_value = self.__name, + exclude_notebook_name = self.DEFAULT_THREAD_NAME, reverse = True, + start = start, count = count, ) - ) if thread.name != self.DEFAULT_THREAD_NAME ] - - # put threads in reverse chronological order by creation date - threads.reverse() + ) # if there are no matching threads, then this forum doesn't exist if len( threads ) == 0: raise cherrypy.NotFound + # count the total number of threads in this forum, excluding those with a default name + total_thread_count = self.__database.select_one( + int, + anonymous.sql_count_notebooks( + parents_only = False, undeleted_only = True, tag_name = u"forum", tag_value = self.__name, + exclude_notebook_name = self.DEFAULT_THREAD_NAME, + ) + ) + result[ "forum_name" ] = self.__name result[ "threads" ] = threads + result[ "start" ] = start + result[ "count" ] = count + result[ "total_thread_count" ] = total_thread_count return result @expose( view = Main_page ) diff --git a/model/User.py b/model/User.py index 8ec52f4..af4185e 100644 --- a/model/User.py +++ b/model/User.py @@ -134,7 +134,8 @@ class User( Persistent ): return "select * from luminotes_user_current where email_address = %s;" % quote( email_address ) def sql_load_notebooks( self, parents_only = False, undeleted_only = False, read_write = False, - tag_name = None, tag_value = None, notebook_id = None ): + tag_name = None, tag_value = None, notebook_id = None, + exclude_notebook_name = None, start = 0, count = None, reverse = False ): """ Return a SQL string to load a list of the notebooks to which this user has access. """ @@ -173,6 +174,26 @@ class User( Persistent ): else: notebook_id_clause = "" + if exclude_notebook_name: + notebook_name_clause = " and not notebook_current.name = %s" % quote( exclude_notebook_name ) + else: + notebook_name_clause = "" + + if reverse: + ordering = u"desc" + else: + ordering = u"asc" + + if count is not None: + limit_clause = " limit %s" % count + else: + limit_clause = "" + + if start: + offset_clause = " offset %s" % start + else: + offset_clause = "" + return \ """ select @@ -180,11 +201,63 @@ class User( Persistent ): from user_notebook, notebook_current%s where - user_notebook.user_id = %s%s%s%s%s%s and + user_notebook.user_id = %s%s%s%s%s%s%s and user_notebook.notebook_id = notebook_current.id - order by user_notebook.rank, notebook_current.revision; + order by user_notebook.rank, notebook_current.revision %s%s%s; """ % ( tag_tables, quote( self.object_id ), parents_only_clause, undeleted_only_clause, - read_write_clause, tag_clause, notebook_id_clause ) + read_write_clause, tag_clause, notebook_id_clause, notebook_name_clause, ordering, + limit_clause, offset_clause ) + + def sql_count_notebooks( self, parents_only = False, undeleted_only = False, read_write = False, + tag_name = None, tag_value = None, exclude_notebook_name = None ): + """ + Return a SQL string to count the number notebooks to which this user has access. + """ + if parents_only: + parents_only_clause = " and trash_id is not null" + else: + parents_only_clause = "" + + if undeleted_only: + undeleted_only_clause = " and deleted = 'f'" + else: + undeleted_only_clause = "" + + if read_write: + read_write_clause = " and user_notebook.read_write = 't'" + else: + read_write_clause = "" + + if tag_name: + tag_tables = ", tag_notebook, tag" + tag_clause = \ + """ + and tag_notebook.tag_id = tag.id and tag_notebook.user_id = %s and + tag_notebook.notebook_id = notebook_current.id and tag.name = %s + """ % ( quote( self.object_id ), quote( tag_name ) ) + + if tag_value: + tag_clause += " and tag_notebook.value = %s" % quote( tag_value ) + else: + tag_tables = "" + tag_clause = "" + + if exclude_notebook_name: + notebook_name_clause = " and not notebook_current.name = %s" % quote( exclude_notebook_name ) + else: + notebook_name_clause = "" + + return \ + """ + select + count( notebook_current.id ) + from + user_notebook, notebook_current%s + where + user_notebook.user_id = %s%s%s%s%s%s and + user_notebook.notebook_id = notebook_current.id; + """ % ( tag_tables, quote( self.object_id ), parents_only_clause, undeleted_only_clause, + read_write_clause, tag_clause, notebook_name_clause ) def sql_save_notebook( self, notebook_id, read_write = True, owner = True, rank = None, own_notes_only = False ): """ diff --git a/view/Forum_page.py b/view/Forum_page.py index 88d033c..5bfaf15 100644 --- a/view/Forum_page.py +++ b/view/Forum_page.py @@ -1,9 +1,13 @@ from Product_page import Product_page +from Page_navigation import Page_navigation from Tags import Div, H1, A, P class Forum_page( Product_page ): - def __init__( self, user, notebooks, first_notebook, login_url, logout_url, rate_plan, groups, forum_name, threads ): + def __init__( + self, user, notebooks, first_notebook, login_url, logout_url, rate_plan, groups, forum_name, + threads, total_thread_count, start = 0, count = None, + ): full_forum_name = "%s forum" % forum_name Product_page.__init__( @@ -32,4 +36,5 @@ class Forum_page( Product_page ): ) for thread in threads ], class_ = u"forum_threads", ), + Page_navigation( u"/forums/%s" % forum_name, len( threads ), total_thread_count, start, count ), ) diff --git a/view/Main_page.py b/view/Main_page.py index 97c0b18..c8bd2ca 100644 --- a/view/Main_page.py +++ b/view/Main_page.py @@ -10,6 +10,7 @@ from Json import Json from Rounded_div import Rounded_div from config.Version import VERSION from model.Notebook import Notebook +from Page_navigation import Page_navigation class Main_page( Page ): @@ -211,7 +212,9 @@ class Main_page( Page ): Div( id = u"deleted_notebooks", ), - self.page_navigation( notebook_path, len( notes ), total_notes_count, start, count ), + Page_navigation( + notebook_path, len( notes ), total_notes_count, start, count, + ), ( notebook.read_write == Notebook.READ_WRITE_FOR_OWN_NOTES and user.username and user.username != u"anonymous" ) and \ P( u"If you write a comment, click the save button to publish it.", class_ = u"small_text" ) or None, Div( @@ -231,7 +234,10 @@ class Main_page( Page ): u"document.getElementById( 'static_notes' ).style.display = 'none';", type = u"text/javascript", ), - self.page_navigation( notebook_path, len( notes ), total_notes_count, start, count, top = False ), + Page_navigation( + notebook_path, len( notes ), total_notes_count, start, count, + return_text = u"return to the discussion", + ), id = u"notebook_background", corners = ( u"tl", ), ), @@ -247,45 +253,3 @@ class Main_page( Page ): id = u"everything_area", ), ) - - def page_navigation( self, notebook_path, displayed_notes_count, total_notes_count, start, notes_per_page, top = True ): - if start is None or notes_per_page is None: - return None - - if displayed_notes_count == 1 and displayed_notes_count < total_notes_count: - if top is True: - return None - return Div( - Span( - A( - u"return to the discussion", - href = "%s" % notebook_path, - ), - ), - ) - - if start == 0 and notes_per_page >= total_notes_count: - return None - - return Div( - ( start > 0 ) and Span( - A( - u"previous", - href = "%s?start=%d&count=%d" % ( notebook_path, max( start - notes_per_page, 0 ), notes_per_page ), - ), - u" | ", - ) or None, - [ Span( - ( start == page_start ) and Strong( unicode( page_number + 1 ) ) or A( - Strong( unicode( page_number + 1 ) ), - href = "%s?start=%d&count=%d" % ( notebook_path, page_start, notes_per_page ), - ), - ) for ( page_number, page_start ) in enumerate( range( 0, total_notes_count, notes_per_page ) ) ], - ( start + notes_per_page < total_notes_count ) and Span( - u" | ", - A( - u"next", - href = "%s?start=%d&count=%d" % ( notebook_path, min( start + notes_per_page, total_notes_count - 1 ), notes_per_page ), - ), - ) or None, - )