Converted the Luminotes blog to work like a forum, so now you can post comments on Luminotes blog posts.
This commit is contained in:
parent
9dec0ae991
commit
af42aae7cc
3
NEWS
3
NEWS
|
@ -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
|
||||||
|
|
|
@ -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 )
|
||||||
|
|
|
@ -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 )
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 ),
|
||||||
)
|
)
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Reference in New Issue