witten
/
luminotes
Archived
1
0
Fork 0
This repository has been archived on 2023-12-16. You can view files and clone it, but cannot push or open issues or pull requests.
luminotes/controller/Forums.py

294 lines
9.9 KiB
Python
Raw Normal View History

import os.path
import cherrypy
from model.User import User
from model.Notebook import Notebook
2008-10-30 22:26:27 +00:00
from model.Note import Note
from model.Tag import Tag
from Expose import expose
from Expire import strongly_expire
from Validate import validate, Valid_string, Valid_int, Valid_friendly_id
from Database import Valid_id, end_transaction
from Users import grab_user_id
from Notebooks import Notebooks
from Users import Access_error
from view.Forums_page import Forums_page
from view.Forum_page import Forum_page
2008-11-18 21:28:51 +00:00
from view.Forum_rss import Forum_rss
from view.Main_page import Main_page
class Forums( object ):
"""
Controller for dealing with discussion forums, corresponding to the "/forums" URL.
"""
def __init__( self, database, notebooks, users ):
"""
Create a new Forums object, representing a collection of forums.
@type database: controller.Database
@param database: database that forums are stored in
@type notebooks: controller.Users
@param notebooks: controller for all notebooks
@type users: controller.Users
@param users: controller for all users
@rtype: Forums
@return: newly constructed Forums
"""
self.__database = database
self.__notebooks = notebooks
self.__users = users
self.__general = Forum( database, notebooks, users, u"general" )
self.__support = Forum( database, notebooks, users, u"support" )
@expose( view = Forums_page )
@strongly_expire
@end_transaction
@grab_user_id
@validate(
user_id = Valid_id( none_okay = True ),
)
def index( self, user_id ):
"""
Provide the information necessary to display the listing of available forums (currently hard-coded).
@type user_id: unicode or NoneType
@param user_id: id of the current user
"""
result = self.__users.current( user_id )
parents = [ notebook for notebook in result[ u"notebooks" ] if notebook.trash_id and not notebook.deleted ]
if len( parents ) > 0:
result[ "first_notebook" ] = parents[ 0 ]
else:
result[ "first_notebook" ] = None
return result
general = property( lambda self: self.__general )
support = property( lambda self: self.__support )
class Forum( object ):
2008-10-30 22:26:27 +00:00
DEFAULT_THREAD_NAME = u"new discussion"
def __init__( self, database, notebooks, users, name ):
"""
Create a new Forum object, representing a single forum.
@type database: controller.Database
@param database: database that forums are stored in
@type notebooks: controller.Users
@param notebooks: controller for all notebooks
@type users: controller.Users
@param users: controller for all users
@type name: unicode
@param name: one-word name of this forum
@rtype: Forums
@return: newly constructed Forums
"""
self.__database = database
self.__notebooks = notebooks
self.__users = users
self.__name = name
2008-11-18 21:28:51 +00:00
@expose( view = Forum_page, rss = Forum_rss )
@strongly_expire
@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 ),
note_id = Valid_id( none_okay = True ),
)
def index( self, start = 0, count = 50, note_id = None, user_id = None ):
"""
2008-11-18 21:28:51 +00:00
Provide the information necessary to display the current threads within a forum.
@type start: integer or NoneType
@param start: index of first forum thread to display (optional, defaults to 0)
@type count: integer or NoneType
@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
@param user_id: id of the current user
@rtype: unicode
@return: rendered HTML page
"""
if note_id:
return dict( redirect = os.path.join( cherrypy.request.path, note_id ) )
result = self.__users.current( user_id )
parents = [ notebook for notebook in result[ u"notebooks" ] if notebook.trash_id and not notebook.deleted ]
if len( parents ) > 0:
result[ "first_notebook" ] = parents[ 0 ]
else:
result[ "first_notebook" ] = None
anonymous = self.__database.select_one( User, User.sql_load_by_username( u"anonymous" ), use_cache = True )
if anonymous is None:
raise Access_error()
# 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,
2008-11-18 21:28:51 +00:00
exclude_notebook_name = self.DEFAULT_THREAD_NAME, reverse = True,
start = start, count = count,
)
)
# 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
2008-10-30 22:26:27 +00:00
@expose( view = Main_page )
@strongly_expire
2008-10-30 22:26:27 +00:00
@end_transaction
@grab_user_id
@validate(
thread_id = unicode,
2008-10-30 22:26:27 +00:00
start = Valid_int( min = 0 ),
count = Valid_int( min = 1, max = 50 ),
note_id = Valid_id( none_okay = True ),
posts = Valid_int(),
2008-10-30 22:26:27 +00:00
user_id = Valid_id( none_okay = True ),
)
def default( self, thread_id, start = 0, count = 10, note_id = None, posts = None, user_id = None ):
2008-10-30 22:26:27 +00:00
"""
Provide the information necessary to display a forum thread.
@type thread_id: unicode
@param thread_id: id or "friendly id" of thread notebook to display
2008-10-30 22:26:27 +00:00
@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)
@type posts: integer or NoneType
@param posts: ignored. used for link-visitedness purposes on the client side
@type user_id: unicode or NoneType
@param user_id: id of the current user
2008-10-30 22:26:27 +00:00
@rtype: unicode
@return: rendered HTML page
@raise Validation_error: one of the arguments is invalid
"""
# first try loading the thread by id, and then if not found, try loading by "friendly id"
try:
Valid_id()( thread_id )
if not self.__database.load( Notebook, thread_id ):
raise ValueError()
except ValueError:
try:
Valid_friendly_id()( thread_id )
except ValueError:
raise cherrypy.NotFound
try:
thread = self.__database.select_one( Notebook, Notebook.sql_load_by_friendly_id( thread_id ) )
except:
raise cherrypy.NotFound
if not thread:
raise cherrypy.NotFound
thread_id = thread.object_id
2008-10-30 22:26:27 +00:00
result = self.__users.current( user_id )
result.update( self.__notebooks.old_notes( thread_id, start, count, user_id ) )
# if a single note was requested, just return that one note
if note_id:
note = self.__database.load( Note, note_id )
if note:
result[ "notes" ] = [ note ]
else:
result[ "notes" ] = []
2008-10-30 22:26:27 +00:00
return result
@expose()
@end_transaction
@grab_user_id
@validate(
user_id = Valid_id( none_okay = True ),
)
def create_thread( self, user_id ):
"""
2008-10-30 22:26:27 +00:00
Create a new forum thread with a blank post, and give the thread a default name. Then redirect
to that new thread.
@type user_id: unicode or NoneType
@param user_id: id of current logged-in user (if any)
@rtype dict
@return { 'redirect': new_notebook_url }
@raise Access_error: the current user doesn't have access to create a post
@raise Validation_error: one of the arguments is invalid
"""
if user_id is None:
raise Access_error()
user = self.__database.load( User, user_id )
if user is None or not user.username or user.username == "anonymous":
raise Access_error()
anonymous = self.__database.select_one( User, User.sql_load_by_username( u"anonymous" ), use_cache = True )
if anonymous is None:
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
thread_id = self.__database.next_id( Notebook, commit = False )
2008-10-30 22:26:27 +00:00
thread = Notebook.create( thread_id, self.DEFAULT_THREAD_NAME, user_id = user.object_id )
self.__database.save( thread, commit = False )
# associate the forum tag with the new notebook thread
tag = self.__database.select_one( Tag, Tag.sql_load_by_name( u"forum", user_id = anonymous.object_id ) )
self.__database.execute(
anonymous.sql_save_notebook_tag( thread_id, tag.object_id, value = self.__name ),
commit = False,
)
# give the anonymous user access to the new notebook thread
self.__database.execute(
anonymous.sql_save_notebook( thread_id, read_write = True, owner = False, own_notes_only = True ),
commit = False,
)
2008-10-30 22:26:27 +00:00
# create a blank post in which the user can start off the thread
note_id = self.__database.next_id( Notebook, commit = False )
note = Note.create( note_id, u"<h3>", notebook_id = thread_id, startup = True, rank = 0, user_id = user_id )
self.__database.save( note, commit = False )
self.__database.commit()
2008-11-18 21:28:51 +00:00
if self.__name == "blog":
return dict(
redirect = u"/blog/%s" % thread_id,
)
return dict(
redirect = u"/forums/%s/%s" % ( self.__name, thread_id ),
)