diff --git a/controller/Forums.py b/controller/Forums.py new file mode 100644 index 0000000..5eb668e --- /dev/null +++ b/controller/Forums.py @@ -0,0 +1,43 @@ +from Expose import expose +from Validate import validate +from Database import Valid_id, end_transaction +from Users import grab_user_id +from view.Forums_page import Forums_page + + +class Forums( object ): + """ + Controller for dealing with discussion forums, corresponding to the "/forums" URL. + """ + def __init__( self, database, users ): + """ + Create a new Forums object. + + @type database: controller.Database + @param database: database that forums are stored in + @type users: controller.Users + @param users: controller for all users + @rtype: Forums + @return: newly constructed Forums + """ + self.__database = database + self.__users = users + + @expose( view = Forums_page ) + @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). + """ + 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 diff --git a/controller/Root.py b/controller/Root.py index 6867af7..06e656b 100644 --- a/controller/Root.py +++ b/controller/Root.py @@ -6,6 +6,7 @@ from Validate import validate, Valid_int, Valid_string from Notebooks import Notebooks from Users import Users, grab_user_id from Files import Files +from Forums import Forums from Database import Valid_id, end_transaction from model.Note import Note from model.Notebook import Notebook @@ -14,6 +15,7 @@ from view.Main_page import Main_page from view.Front_page import Front_page from view.Tour_page import Tour_page from view.Upgrade_page import Upgrade_page +from view.Forums_page import Forums_page from view.Notebook_rss import Notebook_rss from view.Json import Json from view.Error_page import Error_page @@ -47,6 +49,7 @@ class Root( object ): ) self.__files = Files( database, self.__users ) self.__notebooks = Notebooks( database, self.__users, self.__files, settings[ u"global" ].get( u"luminotes.https_url", u"" ) ) + self.__forums = Forums( database, self.__users ) self.__suppress_exceptions = suppress_exceptions # used for unit tests @expose( Main_page ) @@ -385,3 +388,4 @@ class Root( object ): notebooks = property( lambda self: self.__notebooks ) users = property( lambda self: self.__users ) files = property( lambda self: self.__files ) + forums = property( lambda self: self.__forums ) diff --git a/controller/test/Test_forums.py b/controller/test/Test_forums.py new file mode 100644 index 0000000..ec9a4a0 --- /dev/null +++ b/controller/test/Test_forums.py @@ -0,0 +1,55 @@ +import cherrypy +from model.Note import Note +from model.Notebook import Notebook +from model.User import User +from Test_controller import Test_controller + + +class Test_forums( Test_controller ): + def setUp( self ): + Test_controller.setUp( self ) + + self.notebook = Notebook.create( self.database.next_id( Notebook ), u"my notebook", trash_id = u"foo" ) + self.database.save( self.notebook ) + + self.anon_notebook = Notebook.create( self.database.next_id( Notebook ), u"Luminotes" ) + self.database.save( self.anon_notebook ) + self.anon_note = Note.create( + self.database.next_id( Note ), u"

my note

", + notebook_id = self.anon_notebook.object_id, + ) + self.database.save( self.anon_note ) + + self.login_note = Note.create( + self.database.next_id( Note ), u"

login

", + notebook_id = self.anon_notebook.object_id, + ) + self.database.save( self.login_note ) + + self.username = u"mulder" + self.password = u"trustno1" + self.email_address = u"outthere@example.com" + self.user = None + self.session_id = None + + self.user = User.create( self.database.next_id( User ), self.username, self.password, self.email_address ) + self.database.save( self.user ) + self.database.execute( self.user.sql_save_notebook( self.notebook.object_id ) ) + + self.anonymous = User.create( self.database.next_id( User ), u"anonymous" ) + self.database.save( self.anonymous ) + self.database.execute( self.anonymous.sql_save_notebook( self.anon_notebook.object_id ) ) + + def test_index( self ): + result = self.http_get( "/forums/" ) + + assert result + assert result.get( u"redirect" ) is None + assert result[ u"user" ].username == u"anonymous" + assert len( result[ u"notebooks" ] ) == 1 + assert result[ u"first_notebook" ] == None + assert result[ u"login_url" ] == u"https://luminotes.com/notebooks/%s?note_id=%s" % ( + self.anon_notebook.object_id, self.login_note.object_id, + ) + assert result[ u"logout_url" ] == u"https://luminotes.com/users/logout" + assert result[ u"rate_plan" ] diff --git a/static/css/product.css b/static/css/product.css index d84d594..94a10ab 100644 --- a/static/css/product.css +++ b/static/css/product.css @@ -198,6 +198,27 @@ margin: 0 auto; } +.forums_area { + text-align: center; + padding-top: 1em; + padding-bottom: 1em; + background-color: #ffffff; + border-bottom: 1px solid #cccccc; + margin: 0 auto; +} + +.forums_text { + text-align: left; + width: 500px; + margin: 0 auto; + margin-top: 1em; +} + +.forum_title { + font-weight: bold; + font-size: 105%; +} + .tour_screenshot { margin: 1.5em 1em 0.25em 1em; border: 1px solid #999999; diff --git a/static/html/support.html b/static/html/support.html index f0cb0f9..3d0cbf8 100644 --- a/static/html/support.html +++ b/static/html/support.html @@ -1,22 +1,35 @@

support

-

frequently asked questions

+

frequently asked questions

-The Luminotes faq covers some of the -most common questions about the software, so it's a good place to start. +The Luminotes faq covers some of the most common questions about the software, +so it's a good place to start.

-

Luminotes User Guide

+

user guide

-The User Guide explains every feature of -Luminotes in full detail, and it even includes tips for organizing your wiki. +The Luminotes user guide explains every feature of Luminotes in full detail, +and it even includes tips for organizing your wiki.

-

contact info

+

discussion forums

-Have a question? I'll be happy to answer it. Check out my contact info for details. +In the Luminotes discussion forums, you can ask about Luminotes features and +chat with your fellow Luminoters. +

+ +

blog

+ +

+With the Luminotes blog, you can stay up to date on all the latest features +and announcements. +

+ +

contact support

+ +

+Have a question? I'll be happy to answer it.

diff --git a/static/images/forums.png b/static/images/forums.png new file mode 100644 index 0000000..d1ed619 Binary files /dev/null and b/static/images/forums.png differ diff --git a/view/Forums_page.py b/view/Forums_page.py new file mode 100644 index 0000000..117ed3b --- /dev/null +++ b/view/Forums_page.py @@ -0,0 +1,46 @@ +from Product_page import Product_page +from Tags import Div, Img, A, P, Span, I, Br + + +class Forums_page( Product_page ): + def __init__( self, user, notebooks, first_notebook, login_url, logout_url, rate_plan ): + Product_page.__init__( + self, + user, + first_notebook, + login_url, + logout_url, + u"forums", # note title + + Div( + Div( + Img( + src = u"/static/images/forums.png", + width = u"335", height = u"47", + alt = u"Discussion Forums", + ), + ), + Div( + Span( A( u"technical support", href = u"/forums/support" ), class_ = u"forum_title" ), + P( u"Having a problem with your wiki? Something not working as expected? Ask about it here." ), + + Span( A( u"feature requests", href = u"/forums/features" ), class_ = u"forum_title" ), + P( u"Discuss your ideas for new Luminotes features and enhancements." ), + + Span( A( u"general discussion", href = u"/forums/general" ), class_ = u"forum_title" ), + P( u"Swap tips about making the most out of your personal wiki." ), + class_ = u"forums_text", + ), + class_ = u"forums_area", + ), + + Div( + P( + Span( u"Need more help?", class_ = u"hook_action_question" ), Br(), + A( u"Contact support directly", href = u"/contact_info", class_ = u"hook_action" ), + class_ = u"hook_action_area", + separator = u"", + ), + class_ = u"center_area", + ), + )