diff --git a/NEWS b/NEWS index 05fd04b..2de0dc7 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,6 @@ +1.4.0: ?? + * + 1.3.40: May 27, 2008 * Added some minor product page tweaks like meta description tags. diff --git a/controller/Users.py b/controller/Users.py index 7fca7c1..b0d7432 100644 --- a/controller/Users.py +++ b/controller/Users.py @@ -5,6 +5,7 @@ import cherrypy from pytz import utc from datetime import datetime, timedelta from model.User import User +from model.Group import Group from model.Notebook import Notebook from model.Note import Note from model.Password_reset import Password_reset @@ -494,6 +495,7 @@ class Users( object ): 'login_url': url, 'logout_url': url, 'rate_plan': rateplandict, + 'groups': groups, } @raise Validation_error: one of the arguments is invalid @raise Access_error: user_id or anonymous user unknown @@ -514,9 +516,11 @@ class Users( object ): if user_id and user_id != anonymous.object_id: notebooks = self.__database.select_many( Notebook, user.sql_load_notebooks() ) + groups = self.__database.select_many( Group, user.sql_load_groups() ) # if the user is not logged in, return a login URL else: notebooks = [] + groups = [] if len( anon_notebooks ) > 0 and anon_notebooks[ 0 ]: main_notebook = anon_notebooks[ 0 ] login_note = self.__database.select_one( Note, main_notebook.sql_load_note_by_title( u"login" ) ) @@ -529,6 +533,7 @@ class Users( object ): login_url = login_url, logout_url = self.__https_url + u"/users/logout", rate_plan = ( user.rate_plan < len( self.__rate_plans ) ) and self.__rate_plans[ user.rate_plan ] or {}, + groups = groups, ) def calculate_storage( self, user ): diff --git a/controller/test/Stub_database.py b/controller/test/Stub_database.py index 1f79199..d59cd8e 100644 --- a/controller/test/Stub_database.py +++ b/controller/test/Stub_database.py @@ -7,6 +7,7 @@ class Stub_database( object ): # map of object id to list of saved objects (presumably in increasing order of revisions) self.objects = {} self.user_notebook = {} # map of user_id to ( notebook_id, read_write, owner ) + self.user_group = {} # map of user_id to ( group_id, admin ) self.last_saved_obj = None self.last_saved_user = None self.__next_id = 0 diff --git a/controller/test/Test_controller.py b/controller/test/Test_controller.py index 2b5fdf5..46195c9 100644 --- a/controller/test/Test_controller.py +++ b/controller/test/Test_controller.py @@ -179,6 +179,25 @@ class Test_controller( object ): User.sql_highest_notebook_rank = lambda self: \ lambda database: sql_highest_notebook_rank( self, database ) + def sql_load_groups( self, database ): + groups = [] + group_infos = database.user_group.get( self.object_id ) + + if not group_infos: return [] + + for group_info in group_infos: + ( group_id, admin ) = group_info + group = database.objects.get( group_id )[ -1 ] + group.admin = admin + groups.append( group ) + + groups.sort( lambda a, b: cmp( a.name, b.name ) ) + + return groups + + User.sql_load_groups = lambda self: \ + lambda database: sql_load_groups( self, database ) + def sql_revoke_invite_access( notebook_id, trash_id, email_address, database ): invites = [] diff --git a/controller/test/Test_users.py b/controller/test/Test_users.py index eff627c..d11692e 100644 --- a/controller/test/Test_users.py +++ b/controller/test/Test_users.py @@ -195,6 +195,8 @@ class Test_users( Test_controller ): assert rate_plan[ u"name" ] == u"super" assert rate_plan[ u"storage_quota_bytes" ] == 1337 * 10 + assert result[ u"groups" ] == [] + def test_current_after_signup_with_invite_id( self ): # trick send_invites() into using a fake SMTP server Stub_smtp.reset() @@ -275,6 +277,8 @@ class Test_users( Test_controller ): assert rate_plan[ u"name" ] == u"super" assert rate_plan[ u"storage_quota_bytes" ] == 1337 * 10 + assert result[ u"groups" ] == [] + def test_current_after_signup_with_rate_plan( self ): result = self.http_post( "/users/signup", dict( username = self.new_username, @@ -331,6 +335,8 @@ class Test_users( Test_controller ): assert rate_plan[ u"name" ] == u"super" assert rate_plan[ u"storage_quota_bytes" ] == 1337 * 10 + assert result[ u"groups" ] == [] + def test_signup_with_different_passwords( self ): result = self.http_post( "/users/signup", dict( username = self.new_username, @@ -461,6 +467,8 @@ class Test_users( Test_controller ): assert rate_plan[ u"name" ] == u"super" assert rate_plan[ u"storage_quota_bytes" ] == 1337 * 10 + assert result[ u"groups" ] == [] + def test_current_after_demo_twice( self ): result = self.http_post( "/users/demo", dict() ) session_id = result[ u"session_id" ] @@ -562,6 +570,8 @@ class Test_users( Test_controller ): assert rate_plan[ u"name" ] == u"super" assert rate_plan[ u"storage_quota_bytes" ] == 1337 * 10 + assert result[ u"groups" ] == [] + def test_current_anonymous( self ): result = cherrypy.root.users.current( self.anonymous.object_id ) @@ -586,6 +596,8 @@ class Test_users( Test_controller ): assert rate_plan[ u"name" ] == u"super" assert rate_plan[ u"storage_quota_bytes" ] == 1337 * 10 + assert result[ u"groups" ] == [] + def test_login_with_invite_id( self ): # trick send_invites() into using a fake SMTP server Stub_smtp.reset() diff --git a/model/User.py b/model/User.py index f21d39a..50015ce 100644 --- a/model/User.py +++ b/model/User.py @@ -229,7 +229,7 @@ class User( Persistent ): return \ """ select - luminiotes_group_current.*, user_group.admin + luminotes_group_current.*, user_group.admin from user_group, luminotes_group_current where diff --git a/static/js/Wiki.js b/static/js/Wiki.js index 090be5a..b63a5e8 100644 --- a/static/js/Wiki.js +++ b/static/js/Wiki.js @@ -19,6 +19,7 @@ function Wiki( invoker ) { this.after_login = getElement( "after_login" ).value; this.signup_plan = getElement( "signup_plan" ).value; this.email_address = getElement( "email_address" ).value || ""; + this.groups = evalJSON( getElement( "groups" ).value ); this.font_size = null; this.small_toolbar = false; this.large_toolbar_bottom = 0; @@ -1704,8 +1705,28 @@ Wiki.prototype.display_settings = function () { return; } + var group_list = createDOM( "ul" ); + for ( var i in this.groups ) { + var group = this.groups[ i ]; + var item = createDOM( "li", {} ); + appendChildNodes( item, group.name + " " ); + if ( group.admin ) + appendChildNodes( item, "(admin)" ); + appendChildNodes( group_list, item ); + } + + if ( this.groups.length == 0 ) { + var item = createDOM( "li", {}, "You're not a member of any groups." ); + appendChildNodes( group_list, item ); + } + var div = createDOM( "div", {}, createDOM( "form", { "id": "settings_form" }, + createDOM( "p", {}, + createDOM( "b", {}, "group membership" ), + createDOM( "br", {} ), + group_list + ), createDOM( "p", {}, createDOM( "b", {}, "email address" ), createDOM( "br", {} ), @@ -1719,7 +1740,7 @@ Wiki.prototype.display_settings = function () { { "type": "submit", "name": "settings_button", "id": "settings_button", "class": "button", "value": "save settings" } ) ), - createDOM( "p", {}, + createDOM( "p", { "class": "small_text" }, "Your email address will ", createDOM( "a", { "href": "/privacy", "target": "_new" }, "never be shared" ), ". It will only be used for password resets, contacting you about account problems, and the from address in any invite emails you send." diff --git a/view/Front_page.py b/view/Front_page.py index 995e237..0257587 100644 --- a/view/Front_page.py +++ b/view/Front_page.py @@ -3,7 +3,7 @@ from Tags import Div, Img, A, P, Table, Tr, Td, Li, Span, I, Br, Ul, Li class Front_page( Product_page ): - def __init__( self, user, notebooks, first_notebook, login_url, logout_url, rate_plan ): + def __init__( self, user, notebooks, first_notebook, login_url, logout_url, rate_plan, groups ): Product_page.__init__( self, user, diff --git a/view/Main_page.py b/view/Main_page.py index 15afc78..236c89c 100644 --- a/view/Main_page.py +++ b/view/Main_page.py @@ -36,6 +36,7 @@ class Main_page( Page ): signup_plan = None, signup_yearly = None, recent_notes = None, + groups = None, ): startup_note_ids = [ startup_note.object_id for startup_note in startup_notes ] @@ -144,6 +145,7 @@ class Main_page( Page ): Input( type = u"hidden", name = u"after_login", id = u"after_login", value = after_login ), Input( type = u"hidden", name = u"signup_plan", id = u"signup_plan", value = signup_plan ), Input( type = u"hidden", name = u"email_address", id = u"email_address", value = user.email_address ), + Input( type = u"hidden", name = u"groups", id = u"groups", value = json( groups ) ), Div( id = u"status_area", ), diff --git a/view/Notebook_rss.py b/view/Notebook_rss.py index 4f7811d..a38f03c 100644 --- a/view/Notebook_rss.py +++ b/view/Notebook_rss.py @@ -29,6 +29,7 @@ class Notebook_rss( Rss_channel ): signup_plan = None, signup_yearly = None, recent_notes = None, + groups = None, ): if notebook.name == u"Luminotes": notebook_path = u"/" diff --git a/view/Tour_page.py b/view/Tour_page.py index dbd5f8e..ce09dcc 100644 --- a/view/Tour_page.py +++ b/view/Tour_page.py @@ -3,7 +3,7 @@ from Tags import Div, H1, Img, A, Ol, Li, P, Span, I, Br class Tour_page( Product_page ): - def __init__( self, user, notebooks, first_notebook, login_url, logout_url, rate_plan ): + def __init__( self, user, notebooks, first_notebook, login_url, logout_url, rate_plan, groups ): Product_page.__init__( self, user, diff --git a/view/Upgrade_page.py b/view/Upgrade_page.py index 88776ce..a49afc3 100644 --- a/view/Upgrade_page.py +++ b/view/Upgrade_page.py @@ -3,7 +3,7 @@ from Tags import Div, H1, Img, A, P, Table, Th, Tr, Td, Li, Span, I, Br, Ul, Li, class Upgrade_page( Product_page ): - def __init__( self, user, notebooks, first_notebook, login_url, logout_url, rate_plan, rate_plans, unsubscribe_button ): + def __init__( self, user, notebooks, first_notebook, login_url, logout_url, rate_plan, groups, rate_plans, unsubscribe_button ): MEGABYTE = 1024 * 1024 rate_plans = list( rate_plans ) rate_plans.reverse() # show rate plans highest to lowest