diff --git a/controller/Expose.py b/controller/Expose.py index e353390..067cebf 100644 --- a/controller/Expose.py +++ b/controller/Expose.py @@ -68,7 +68,7 @@ def expose( view = None, rss = None ): if rss and use_rss: cherrypy.response.headers[ u"Content-Type" ] = u"application/xml" return unicode( rss( **result ) ) - else: + elif view: return unicode( view( **result ) ) else: return unicode( view_override( **result ) ) diff --git a/controller/Users.py b/controller/Users.py index 2510f62..4654575 100644 --- a/controller/Users.py +++ b/controller/Users.py @@ -105,10 +105,12 @@ def update_auth( function ): # peek in the function's return value to see if we should tweak authentication status user = result.get( "authenticated" ) if user: + result.pop( "authenticated", None ) cherrypy.session[ u"user_id" ] = user.object_id cherrypy.session[ u"username" ] = user.username if result.get( "deauthenticated" ): + result.pop( "deauthenticated", None ) cherrypy.session.pop( u"user_id", None ) cherrypy.session.pop( u"username", None ) @@ -225,6 +227,72 @@ class Users( object ): authenticated = user, ) + @expose() + @grab_user_id + @update_auth + @wait_for_update + @async + @update_client + def demo( self, user_id = None ): + """ + Create a new guest User for purposes of the demo. Start that user with their own Notebook and + "welcome to your wiki" and "this is a demo" notes. For convenience, login the newly created + user as well. + + If the user is already logged in as a guest user when calling this function, then skip + creating a new user and notebook, and just redirect to the guest user's existing notebook. + + @type user_id: unicode + @param user_id: id of current logged-in user (if any), determined by @grab_user_id + @rtype: json dict + @return: { 'redirect': url, 'authenticated': userdict } + """ + # if the user is already logged in as a guest, then just redirect to their existing demo + # notebook + if user_id: + self.__database.load( user_id, self.__scheduler.thread ) + user = ( yield Scheduler.SLEEP ) + if user.username is None and len( user.notebooks ) > 0: + redirect = u"/notebooks/%s" % user.notebooks[ 0 ].object_id + yield dict( redirect = redirect ) + return + + # create a demo notebook for this user, along with a trash for that notebook + self.__database.next_id( self.__scheduler.thread ) + trash_id = ( yield Scheduler.SLEEP ) + trash = Notebook( trash_id, u"trash" ) + + self.__database.next_id( self.__scheduler.thread ) + notebook_id = ( yield Scheduler.SLEEP ) + notebook = Notebook( notebook_id, u"my notebook", trash ) + + # create startup notes for this user's notebook + self.__database.next_id( self.__scheduler.thread ) + note_id = ( yield Scheduler.SLEEP ) + note = Note( note_id, file( u"static/html/this is a demo.html" ).read() ) + notebook.add_note( note ) + notebook.add_startup_note( note ) + + self.__database.next_id( self.__scheduler.thread ) + note_id = ( yield Scheduler.SLEEP ) + note = Note( note_id, file( u"static/html/welcome to your wiki.html" ).read() ) + notebook.add_note( note ) + notebook.add_startup_note( note ) + + # actually create the new user. because this is just a demo user, we're not adding it to the User_list + self.__database.next_id( self.__scheduler.thread ) + user_id = ( yield Scheduler.SLEEP ) + + user = User( user_id, username = None, password = None, email_address = None, notebooks = [ notebook ] ) + self.__database.save( user ) + + redirect = u"/notebooks/%s" % notebook.object_id + + yield dict( + redirect = redirect, + authenticated = user, + ) + @expose( view = Json ) @update_auth @wait_for_update diff --git a/controller/test/Test_users.py b/controller/test/Test_users.py index 3a9e7ee..1167228 100644 --- a/controller/test/Test_users.py +++ b/controller/test/Test_users.py @@ -83,7 +83,6 @@ class Test_users( Test_controller ): ) ) assert result[ u"redirect" ].startswith( u"/notebooks/" ) - assert result[ u"authenticated" ] def test_current_after_signup( self, include_startup_notes = False ): result = self.http_post( "/users/signup", dict( @@ -139,6 +138,83 @@ class Test_users( Test_controller ): assert result[ u"error" ] + def test_demo( self ): + result = self.http_post( "/users/demo", dict() ) + + assert result[ u"redirect" ].startswith( u"/notebooks/" ) + + def test_current_after_demo( self, include_startup_notes = False ): + result = self.http_post( "/users/demo", dict() ) + session_id = result[ u"session_id" ] + + new_notebook_id = result[ u"redirect" ].split( u"/notebooks/" )[ -1 ] + + result = self.http_get( + "/users/current?include_startup_notes=%s" % include_startup_notes, + session_id = session_id, + ) + + assert result[ u"user" ].username == None + notebooks = result[ u"notebooks" ] + assert len( notebooks ) == 2 + assert notebooks[ 0 ] == self.anon_notebook + assert notebooks[ 0 ].trash == None + + notebook = notebooks[ 1 ] + assert notebook.object_id == new_notebook_id + assert notebook.trash + assert len( notebook.notes ) == 2 + assert len( notebook.startup_notes ) == 2 + + startup_notes = result[ "startup_notes" ] + if include_startup_notes: + assert len( startup_notes ) == 1 + assert startup_notes[ 0 ] == self.startup_note + else: + assert startup_notes == [] + + rate_plan = result[ u"rate_plan" ] + assert rate_plan[ u"name" ] == u"super" + assert rate_plan[ u"storage_quota_bytes" ] == 1337 + + def test_current_with_startup_notes_after_demo( self ): + self.test_current_after_demo( include_startup_notes = True ) + + def test_current_after_demo_twice( self, include_startup_notes = False ): + result = self.http_post( "/users/demo", dict() ) + session_id = result[ u"session_id" ] + + new_notebook_id = result[ u"redirect" ].split( u"/notebooks/" )[ -1 ] + + result = self.http_get( + "/users/current?include_startup_notes=%s" % include_startup_notes, + session_id = session_id, + ) + + user_id = result[ u"user" ].object_id + + # request a demo for a second time + result = self.http_post( "/users/demo", dict(), session_id = session_id ) + + assert result[ u"redirect" ].startswith( u"/notebooks/" ) + notebook_id_again = result[ u"redirect" ].split( u"/notebooks/" )[ -1 ] + + assert notebook_id_again == new_notebook_id + + result = self.http_get( + "/users/current?include_startup_notes=%s" % include_startup_notes, + session_id = session_id, + ) + + user_id_again = result[ u"user" ].object_id + + # since we're already logged in as a guest user with a demo notebook, requesting a demo again + # should just use the same guest user with the same notebook + assert user_id_again == user_id + + def test_current_with_startup_notes_after_demo_twice( self ): + self.test_current_after_demo_twice( include_startup_notes = True ) + def test_login( self ): result = self.http_post( "/users/login", dict( username = self.username, @@ -147,7 +223,6 @@ class Test_users( Test_controller ): ) ) assert result[ u"redirect" ] == u"/notebooks/%s" % self.notebooks[ 0 ].object_id - assert result[ u"authenticated" ] def test_login_with_unknown_user( self ): result = self.http_post( "/users/login", dict( @@ -157,7 +232,6 @@ class Test_users( Test_controller ): ) ) assert result[ u"error" ] - assert not result.get( u"authenticated" ) def test_login_with_invalid_password( self ): result = self.http_post( "/users/login", dict( @@ -167,13 +241,11 @@ class Test_users( Test_controller ): ) ) assert result[ u"error" ] - assert not result.get( u"authenticated" ) def test_logout( self ): result = self.http_post( "/users/logout", dict() ) assert result[ u"redirect" ] == self.settings[ u"global" ].get( u"luminotes.http_url" ) + u"/" - assert result[ u"deauthenticated" ] def test_current_after_login( self, include_startup_notes = False ): result = self.http_post( "/users/login", dict( diff --git a/static/html/features.html b/static/html/features.html index 9db8643..01777d9 100644 --- a/static/html/features.html +++ b/static/html/features.html @@ -35,6 +35,7 @@ your wiki.

Sound interesting? Then -take a tour or -try it out for yourself! +take a tour, +try the demo, or +sign up for a free account.

diff --git a/static/html/login.html b/static/html/login.html index ab36b50..a58957b 100644 --- a/static/html/login.html +++ b/static/html/login.html @@ -1,6 +1,7 @@

login

-No account yet? Want to make a wiki? You can try it out for free. +No account yet? Want to make a wiki? You can try the demo or sign up for a free account.

diff --git a/static/html/navigation.html b/static/html/navigation.html index b828f5a..c614d32 100644 --- a/static/html/navigation.html +++ b/static/html/navigation.html @@ -1,7 +1,6 @@ -about - -features - take a tour - -try it out - +try the demo - +sign up - faq - meet the team - contact info diff --git a/static/html/try it out.html b/static/html/sign up.html similarity index 98% rename from static/html/try it out.html rename to static/html/sign up.html index 8ab2c72..c0fc3a8 100644 --- a/static/html/try it out.html +++ b/static/html/sign up.html @@ -1,4 +1,4 @@ -

try it out

+

sign up

To get started with your own personal wiki, all you need to do is sign up for diff --git a/static/html/this is a demo.html b/static/html/this is a demo.html new file mode 100644 index 0000000..1634b09 --- /dev/null +++ b/static/html/this is a demo.html @@ -0,0 +1,6 @@ +

this is a demo

+ +

+Once you've finished trying out the demo, feel free to logout and sign up for +an actual account. Then you can get started creating your own wiki! +

diff --git a/static/js/Wiki.js b/static/js/Wiki.js index 4f1451b..7c115e5 100644 --- a/static/js/Wiki.js +++ b/static/js/Wiki.js @@ -91,7 +91,7 @@ Wiki.prototype.display_user = function ( result ) { this.display_storage_usage( result.user.storage_bytes ); // display the name of the logged in user and a logout link - appendChildNodes( user_span, "logged in as " + result.user.username ); + appendChildNodes( user_span, "logged in as " + ( result.user.username || "a guest" ) ); appendChildNodes( user_span, " | " ); appendChildNodes( user_span, createDOM( "a", { "href": result.http_url + "/", "id": "logout_link" }, "logout" ) ); diff --git a/tools/deletenote.py b/tools/deletenote.py index b7993a1..6ac272c 100755 --- a/tools/deletenote.py +++ b/tools/deletenote.py @@ -32,7 +32,7 @@ class Deleter( object ): startup_notes = [] for note in main_notebook.notes: - if note and note.title == "take a tour": # FIXME: make the note title to delete not hard-coded + if note and note.title == "try it out": # FIXME: make the note title to delete not hard-coded print "deleting note %s: %s" % ( note.object_id, note.title ) main_notebook.remove_note( note ) diff --git a/tools/initdb.py b/tools/initdb.py index fd7ef01..b9ca356 100644 --- a/tools/initdb.py +++ b/tools/initdb.py @@ -17,7 +17,7 @@ class Initializer( object ): ( u"navigation.html", True ), ( u"about.html", True ), ( u"features.html", True ), - ( u"try it out.html", False ), + ( u"sign up.html", False ), ( u"faq.html", False ), ( u"meet the team.html", False ), ( u"contact info.html", False ), @@ -122,7 +122,7 @@ def fix_note_contents( contents, notebook_id, note_ids ): https_url = u"" - if title in ( u"try it out", u"login" ): + if title in ( u"sign up", u"login" ): https_url = settings[ u"global" ].get( u"luminotes.https_url", u"" ) return u"".join( [ diff --git a/tools/updatedb.py b/tools/updatedb.py index 5b6817f..9ec3234 100755 --- a/tools/updatedb.py +++ b/tools/updatedb.py @@ -15,7 +15,7 @@ class Initializer( object ): NOTE_FILES = [ # the second element of the tuple is whether to show the note on startup ( u"about.html", True ), ( u"features.html", True ), - ( u"try it out.html", False ), + ( u"sign up.html", False ), ( u"faq.html", False ), ( u"meet the team.html", False ), ( u"contact info.html", False ),