witten
/
luminotes
Archived
1
0
Fork 0

Converted the Luminotes blog to work like a forum, so now you can post comments on Luminotes blog posts.

This commit is contained in:
Dan Helfman 2008-11-17 15:23:22 -08:00
parent 9dec0ae991
commit af42aae7cc
7 changed files with 42 additions and 49 deletions

3
NEWS
View File

@ -3,6 +3,9 @@
so that the note title links have a little more horizontal breathing room. so that the note title links have a little more horizontal breathing room.
* You can now add an existing note directly to the note tree, instead of * You can now add an existing note directly to the note tree, instead of
having to click "options" -> "show on startup". having to click "options" -> "show on startup".
* Improved site navigation by adding more useful links to the page footer.
* Converted the Luminotes blog to work like a forum, so now you can post
comments on Luminotes blog posts.
* Fixed a bug in which search result note summaries were not showing the * Fixed a bug in which search result note summaries were not showing the
portion of the note that matched the search term. (Luminotes Server) portion of the note that matched the search term. (Luminotes Server)
* Fixed a visual bug in which undoing the deletion of a note didn't always * Fixed a visual bug in which undoing the deletion of a note didn't always

View File

@ -1,3 +1,4 @@
import os.path
import cherrypy import cherrypy
from model.User import User from model.User import User
from model.Notebook import Notebook from model.Notebook import Notebook
@ -97,8 +98,9 @@ class Forum( object ):
start = Valid_int( min = 0 ), start = Valid_int( min = 0 ),
count = Valid_int( min = 1, max = 50 ), count = Valid_int( min = 1, max = 50 ),
user_id = Valid_id( none_okay = True ), user_id = Valid_id( none_okay = True ),
note_id = Valid_id( none_okay = True ),
) )
def index( self, start = 0, count = 50, user_id = None ): def index( self, start = 0, count = 50, note_id = None, user_id = None ):
""" """
Provide the information necessary to display the current threads within a forum (in reverse Provide the information necessary to display the current threads within a forum (in reverse
chronological order). chronological order).
@ -107,11 +109,16 @@ class Forum( object ):
@param start: index of first forum thread to display (optional, defaults to 0) @param start: index of first forum thread to display (optional, defaults to 0)
@type count: integer or NoneType @type count: integer or NoneType
@param count: how many forum threads to display (optional, defaults to quite a few) @param count: how many forum threads to display (optional, defaults to quite a few)
@type note_id: unicode or NoneType
@param note_id: id of thread to redirect to (optional, legacy support for old URLs)
@type user_id: unicode or NoneType @type user_id: unicode or NoneType
@param user_id: id of the current user @param user_id: id of the current user
@rtype: unicode @rtype: unicode
@return: rendered HTML page @return: rendered HTML page
""" """
if note_id:
return dict( redirect = os.path.join( cherrypy.request.path, note_id ) )
result = self.__users.current( user_id ) result = self.__users.current( user_id )
parents = [ notebook for notebook in result[ u"notebooks" ] if notebook.trash_id and not notebook.deleted ] parents = [ notebook for notebook in result[ u"notebooks" ] if notebook.trash_id and not notebook.deleted ]
if len( parents ) > 0: if len( parents ) > 0:
@ -123,12 +130,19 @@ class Forum( object ):
if anonymous is None: if anonymous is None:
raise Access_error() raise Access_error()
# whether this is a blog determines whether the posts are diplayed in forward or reverse
# chronological order
if self.__name == u"blog":
reverse = False
else:
reverse = True
# load a slice of the list of the threads in this forum, excluding those with a default name # load a slice of the list of the threads in this forum, excluding those with a default name
threads = self.__database.select_many( threads = self.__database.select_many(
Notebook, Notebook,
anonymous.sql_load_notebooks( 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, exclude_notebook_name = self.DEFAULT_THREAD_NAME, reverse = reverse,
start = start, count = count, start = start, count = count,
) )
) )
@ -220,6 +234,10 @@ class Forum( object ):
if anonymous is None: if anonymous is None:
raise Access_error() raise Access_error()
# for now, crappy hard-coding to prevent just anyone from creating a blog thread
if self.__name == u"blog" and user.username != u"witten":
raise Access_error()
# create the new notebook thread # create the new notebook thread
thread_id = self.__database.next_id( Notebook, commit = False ) thread_id = self.__database.next_id( Notebook, commit = False )
thread = Notebook.create( thread_id, self.DEFAULT_THREAD_NAME, user_id = user.object_id ) thread = Notebook.create( thread_id, self.DEFAULT_THREAD_NAME, user_id = user.object_id )

View File

@ -7,7 +7,7 @@ from Notebooks import Notebooks
from Users import Users, grab_user_id from Users import Users, grab_user_id
from Groups import Groups from Groups import Groups
from Files import Files from Files import Files
from Forums import Forums from Forums import Forums, Forum
from Database import Valid_id, end_transaction from Database import Valid_id, end_transaction
from Users import update_auth from Users import update_auth
from model.Note import Note from model.Note import Note
@ -59,6 +59,7 @@ class Root( object ):
) )
self.__notebooks = Notebooks( database, self.__users, self.__files, settings[ u"global" ].get( u"luminotes.https_url", u"" ) ) self.__notebooks = Notebooks( database, self.__users, self.__files, settings[ u"global" ].get( u"luminotes.https_url", u"" ) )
self.__forums = Forums( database, self.__notebooks, self.__users ) self.__forums = Forums( database, self.__notebooks, self.__users )
self.__blog = Forum( database, self.__notebooks, self.__users, u"blog" )
self.__suppress_exceptions = suppress_exceptions # used for unit tests self.__suppress_exceptions = suppress_exceptions # used for unit tests
@expose( Main_page ) @expose( Main_page )
@ -253,43 +254,6 @@ class Root( object ):
def take_a_tour( self ): def take_a_tour( self ):
return dict( redirect = u"/tour" ) return dict( redirect = u"/tour" )
@expose( view = Main_page, rss = Notebook_rss )
@end_transaction
@grab_user_id
@validate(
start = Valid_int( min = 0 ),
count = Valid_int( min = 1, max = 50 ),
note_id = Valid_id( none_okay = True ),
user_id = Valid_id( none_okay = True ),
)
def blog( self, start = 0, count = 5, note_id = None, user_id = None ):
"""
Provide the information necessary to display the blog notebook with notes in reverse
chronological order.
@type start: unicode or NoneType
@param start: index of recent note to start with (defaults to 0, the most recent note)
@type count: int or NoneType
@param count: number of recent notes to display (defaults to 10 notes)
@type note_id: unicode or NoneType
@param note_id: id of single note to load (optional)
@rtype: unicode
@return: rendered HTML page
@raise Validation_error: one of the arguments is invalid
"""
result = self.__users.current( user_id )
blog_notebooks = [ nb for nb in result[ "notebooks" ] if nb.name == u"Luminotes blog" ]
result.update( self.__notebooks.recent_notes( blog_notebooks[ 0 ].object_id, start, count, user_id ) )
# if a single note was requested, just return that one note
if note_id:
result[ "notes" ] = [ note for note in result[ "notes" ] if note.object_id == note_id ]
result[ "http_url" ] = self.__settings[ u"global" ].get( u"luminotes.http_url", u"" )
return result
@expose( view = Main_page ) @expose( view = Main_page )
@end_transaction @end_transaction
@grab_user_id @grab_user_id
@ -493,3 +457,4 @@ class Root( object ):
groups = property( lambda self: self.__groups ) groups = property( lambda self: self.__groups )
files = property( lambda self: self.__files ) files = property( lambda self: self.__files )
forums = property( lambda self: self.__forums ) forums = property( lambda self: self.__forums )
blog = property( lambda self: self.__blog )

View File

@ -638,7 +638,7 @@ class Users( object ):
anon_notebooks = self.__database.select_many( Notebook, anonymous.sql_load_notebooks( undeleted_only = True ) ) anon_notebooks = self.__database.select_many( Notebook, anonymous.sql_load_notebooks( undeleted_only = True ) )
if user_id and user_id != anonymous.object_id: if user_id and user_id != anonymous.object_id:
notebooks = self.__database.select_many( Notebook, user.sql_load_notebooks() ) notebooks = self.__database.select_many( Notebook, user.sql_load_notebooks( parents_only = True ) )
groups = self.__database.select_many( Group, user.sql_load_groups() ) groups = self.__database.select_many( Group, user.sql_load_groups() )
# if the user is not logged in, return a login URL # if the user is not logged in, return a login URL
else: else:

View File

@ -13,7 +13,7 @@ In the Luminotes discussion forums, you can ask about Luminotes features and
chat with your fellow Luminoters. chat with your fellow Luminoters.
</p> </p>
<h4><a href="/blog" target="_top">blog</a></h4> <h4><a href="/blog/" target="_top">blog</a></h4>
<p> <p>
With the Luminotes blog, you can stay up to date on all the latest features With the Luminotes blog, you can stay up to date on all the latest features

View File

@ -1,3 +1,5 @@
import os.path
import cherrypy
from Product_page import Product_page from Product_page import Product_page
from Page_navigation import Page_navigation from Page_navigation import Page_navigation
from Tags import Div, H1, A, P from Tags import Div, H1, A, P
@ -8,7 +10,12 @@ class Forum_page( Product_page ):
self, user, notebooks, first_notebook, login_url, logout_url, rate_plan, groups, forum_name, self, user, notebooks, first_notebook, login_url, logout_url, rate_plan, groups, forum_name,
threads, total_thread_count, start = 0, count = None, threads, total_thread_count, start = 0, count = None,
): ):
full_forum_name = "%s forum" % forum_name base_path = cherrypy.request.path
if base_path.startswith( u"/forums/" ):
full_forum_name = u"%s forum" % forum_name
else:
full_forum_name = u"Luminotes %s" % forum_name
Product_page.__init__( Product_page.__init__(
self, self,
@ -22,19 +29,19 @@ class Forum_page( Product_page ):
H1( full_forum_name ), H1( full_forum_name ),
), ),
Div( Div(
P( base_path.startswith( u"/forums/" ) and P(
A( u"start a new discussion", href = u"/forums/%s/create_thread" % forum_name ), A( u"start a new discussion", href = os.path.join( base_path, u"create_thread" ) ),
u" | ", u" | ",
A( u"all forums", href = u"/forums/" ), A( u"all forums", href = u"/forums/" ),
class_ = u"small_text", class_ = u"small_text",
), ) or None,
[ Div( [ Div(
A( A(
thread.name, thread.name,
href = u"/forums/%s/%s" % ( forum_name, thread.object_id ), href = os.path.join( base_path, thread.object_id ),
), ),
) for thread in threads ], ) for thread in threads ],
class_ = u"forum_threads", class_ = u"forum_threads",
), ),
Page_navigation( u"/forums/%s" % forum_name, len( threads ), total_thread_count, start, count ), Page_navigation( base_path, len( threads ), total_thread_count, start, count ),
) )

View File

@ -45,7 +45,7 @@ class Product_page( Page ):
Li( u"Community", class_ = u"footer_category" ), Li( u"Community", class_ = u"footer_category" ),
Li( A( u"contact support", href = u"/contact_info" ) ), Li( A( u"contact support", href = u"/contact_info" ) ),
Li( A( u"discussion forums", href = u"/forums/" ) ), Li( A( u"discussion forums", href = u"/forums/" ) ),
Li( A( u"blog", href = u"/blog" ) ), Li( A( u"blog", href = u"/blog/" ) ),
Li( A( u"Facebook group", href = u"http://www.facebook.com/pages/Luminotes-personal-wiki-notebook/17143857741" ) ), Li( A( u"Facebook group", href = u"http://www.facebook.com/pages/Luminotes-personal-wiki-notebook/17143857741" ) ),
Li( A( u"Twitter stream", href = u"http://twitter.com/Luminotes" ) ), Li( A( u"Twitter stream", href = u"http://twitter.com/Luminotes" ) ),
class_ = u"footer_list", class_ = u"footer_list",