diff --git a/controller/Forums.py b/controller/Forums.py index 221cc55..e2813b6 100644 --- a/controller/Forums.py +++ b/controller/Forums.py @@ -1,11 +1,13 @@ import cherrypy from model.User import User from model.Notebook import Notebook +from model.Tag import Tag from Expose import expose from Validate import validate, Valid_string 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 from view.Main_page import Main_page @@ -17,7 +19,7 @@ class Forums( object ): """ def __init__( self, database, notebooks, users ): """ - Create a new Forums object. + Create a new Forums object, representing a collection of forums. @type database: controller.Database @param database: database that forums are stored in @@ -32,6 +34,9 @@ class Forums( object ): 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 ) @end_transaction @grab_user_id @@ -54,19 +59,41 @@ class Forums( object ): return result + general = property( lambda self: self.__general ) + support = property( lambda self: self.__support ) + + +class Forum( object ): + 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 + @expose( view = Forum_page ) @end_transaction @grab_user_id @validate( - forum_name = Valid_string( max = 100 ), user_id = Valid_id( none_okay = True ), ) - def default( self, forum_name, user_id ): + def index( self, user_id ): """ Provide the information necessary to display the current threads within a forum. - @type forum_name: unicode - @param forum_name: name of the forum to display @type user_id: unicode or NoneType @param user_id: id of the current user """ @@ -85,7 +112,7 @@ class Forums( object ): threads = self.__database.select_many( Notebook, anonymous.sql_load_notebooks( - parents_only = False, undeleted_only = True, tag_name = u"forum", tag_value = forum_name + parents_only = False, undeleted_only = True, tag_name = u"forum", tag_value = self.__name ) ) @@ -93,11 +120,64 @@ class Forums( object ): if len( threads ) == 0: raise cherrypy.NotFound - result[ "forum_name" ] = forum_name + result[ "forum_name" ] = self.__name result[ "threads" ] = threads return result - # threads() is just an alias for Notebooks.default() - def threads( self, *args, **kwargs ): + # default() is just an alias for Notebooks.default() + def default( self, *args, **kwargs ): return self.__notebooks.default( *args, **kwargs ) - threads.exposed = True + + default.exposed = True + + @expose() + @end_transaction + @grab_user_id + @validate( + user_id = Valid_id( none_okay = True ), + ) + def create_thread( self, user_id ): + """ + Create a new forum post and give it a default name. Then redirect to that new post 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() + + # create the new notebook thread + thread_id = self.__database.next_id( Notebook, commit = False ) + thread = Notebook.create( thread_id, u"new forum post", 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, + ) + + self.__database.commit() + + return dict( + redirect = u"/forums/%s/%s" % ( self.__name, thread_id ), + ) diff --git a/static/css/product.css b/static/css/product.css index 094a159..c28299c 100644 --- a/static/css/product.css +++ b/static/css/product.css @@ -232,6 +232,14 @@ margin-top: 1em; } +.forum_threads { + text-align: left; + width: 500px; + margin: 0 auto; + margin-top: 1em; + line-height: 200%; +} + .forum_title { font-weight: bold; font-size: 105%; diff --git a/static/js/Wiki.js b/static/js/Wiki.js index dcdb818..2675f39 100644 --- a/static/js/Wiki.js +++ b/static/js/Wiki.js @@ -317,7 +317,15 @@ Wiki.prototype.populate = function ( startup_notes, current_notes, note_read_wri if ( this.notebook.read_write != NOTEBOOK_READ_ONLY ) { connect( window, "onunload", function ( event ) { self.editor_focused( null, true ); } ); - connect( "newNote", "onclick", this, "create_blank_editor" ); + + if ( this.notebook.read_write == NOTEBOOK_READ_WRITE || + ( this.notebook.read_write == NOTEBOOK_READ_WRITE_FOR_OWN_NOTES && + this.user.username && this.user.username != "anonymous" ) + ) + connect( "newNote", "onclick", this, "create_blank_editor" ); + else + connect( "newNote", "onclick", function( event ) { self.display_message( 'Please login first. No account? Click "sign up".' ) } ); + connect( "createLink", "onclick", this, "toggle_link_button" ); if ( this.notebook.read_write == NOTEBOOK_READ_WRITE ) connect( "attachFile", "onclick", this, "toggle_attach_button" ); @@ -748,7 +756,7 @@ Wiki.prototype.create_editor = function ( id, note_text, deleted_from_id, revisi read_write = true; else if ( read_write == NOTEBOOK_READ_WRITE_FOR_OWN_NOTES ) { own_notes_only = true; - if ( user_id == this.user.object_id ) + if ( user_id == this.user.object_id && this.user.username && this.user.username != "anonymous" ) read_write = true; else read_write = false; diff --git a/view/Forum_page.py b/view/Forum_page.py index 80bf4ea..9f11de8 100644 --- a/view/Forum_page.py +++ b/view/Forum_page.py @@ -18,12 +18,16 @@ class Forum_page( Product_page ): H1( full_forum_name ), ), Div( + P( + A( u"start a new discussion", href = u"/forums/%s/create_thread" % forum_name ), + class_ = u"small_text", + ), [ Div( A( thread.name, - href = u"/forums/threads/%s" % thread.object_id, + href = u"/forums/%s/%s" % ( forum_name, thread.object_id ), ), ) for thread in threads ], - class_ = u"forums_text", + class_ = u"forum_threads", ), )