diff --git a/controller/Users.py b/controller/Users.py index 9785fc5..1d6ecf2 100644 --- a/controller/Users.py +++ b/controller/Users.py @@ -617,6 +617,40 @@ class Users( object ): return False + @expose( view = Json ) + @end_transaction + @grab_user_id + @validate( + user_id_to_remove = Valid_id(), + group_id = Valid_id(), + user_id = Valid_id( none_okay = True ), + ) + def remove_group( self, user_id_to_remove, group_id, user_id = None ): + """ + Remove a user's membership from the given group. + + @type user_id_to_remove: unicode + @param user_id_to_remove: id of the user to remove from the group + @type group_id: unicode + @param group_id: id of the group to remove membership from + @type user_id: unicode + @param user_id: id of current logged-in user (if any) + @raise Validation_error: one of the arguments is invalid + @raise Access_error: the current user doesn't have admin membership to the given group + """ + if not self.check_group( user_id, group_id, admin = True ): + raise Access_error() + + user = self.__database.load( User, user_id_to_remove ) + if not user: + raise Access_error() + + self.__database.execute( user.sql_remove_group( group_id ) ) + + return dict( + message = u"Group membership for %s has been revoked." % user.username, + ) + @expose( view = Json ) @end_transaction @validate( diff --git a/controller/test/Test_controller.py b/controller/test/Test_controller.py index d561931..013a0ac 100644 --- a/controller/test/Test_controller.py +++ b/controller/test/Test_controller.py @@ -208,6 +208,17 @@ class Test_controller( object ): User.sql_save_group = lambda self, group_id, admin = False: \ lambda database: sql_save_group( self, group_id, admin, database ) + def sql_remove_group( self, group_id, database ): + for ( user_id, group_infos ) in database.user_group.items(): + for group_info in group_infos: + ( db_group_id, db_admin ) = group_info + + if self.object_id == user_id and group_id == db_group_id: + database.user_group[ user_id ].remove( group_info ) + + User.sql_remove_group = lambda self, group_id: \ + lambda database: sql_remove_group( self, group_id, database ) + def sql_in_group( self, group_id, admin, database ): for ( user_id, group_infos ) in database.user_group.items(): for group_info in group_infos: diff --git a/controller/test/Test_users.py b/controller/test/Test_users.py index 1a7e620..fa0b9eb 100644 --- a/controller/test/Test_users.py +++ b/controller/test/Test_users.py @@ -767,6 +767,61 @@ class Test_users( Test_controller ): assert membership is True + def test_check_remove_group( self ): + self.login2() + + result = self.http_post( "/users/remove_group", dict( + user_id_to_remove = self.user.object_id, + group_id = self.group.object_id, + ), session_id = self.session_id ) + + assert u"revoked" in result[ u"message" ] + assert cherrypy.root.users.check_group( self.user.object_id, self.group.object_id ) == False + + def test_check_remove_group_without_access( self ): + self.login2() + + result = self.http_post( "/users/remove_group", dict( + user_id_to_remove = self.user.object_id, + group_id = self.group2.object_id, + ), session_id = self.session_id ) + + assert u"access" in result[ u"error" ] + assert cherrypy.root.users.check_group( self.user.object_id, self.group.object_id ) == True + + def test_check_remove_group_without_admin_access( self ): + self.login() + + result = self.http_post( "/users/remove_group", dict( + user_id_to_remove = self.user.object_id, + group_id = self.group.object_id, + ), session_id = self.session_id ) + + assert u"access" in result[ u"error" ] + assert cherrypy.root.users.check_group( self.user.object_id, self.group.object_id ) == True + + def test_check_remove_group_with_unknown_group( self ): + self.login2() + + result = self.http_post( "/users/remove_group", dict( + user_id_to_remove = self.user.object_id, + group_id = u"unknowngroupid", + ), session_id = self.session_id ) + + assert u"access" in result[ u"error" ] + assert cherrypy.root.users.check_group( self.user.object_id, self.group.object_id ) == True + + def test_check_remove_group_with_unknown_user( self ): + self.login2() + + result = self.http_post( "/users/remove_group", dict( + user_id_to_remove = u"unknownuserid", + group_id = self.group.object_id, + ), session_id = self.session_id ) + + assert u"access" in result[ u"error" ] + assert cherrypy.root.users.check_group( self.user.object_id, self.group.object_id ) == True + def test_send_reset( self ): # trick send_reset() into using a fake SMTP server Stub_smtp.reset() diff --git a/static/js/Wiki.js b/static/js/Wiki.js index 83be704..c12ec49 100644 --- a/static/js/Wiki.js +++ b/static/js/Wiki.js @@ -1419,6 +1419,9 @@ Wiki.prototype.update_editor_revisions = function ( result, editor ) { } Wiki.prototype.submit_form = function ( form ) { + this.clear_messages(); + this.clear_pulldowns(); + var self = this; var args = {} var url = form.getAttribute( "target" ); @@ -1447,6 +1450,9 @@ Wiki.prototype.submit_form = function ( form ) { } Wiki.prototype.editor_button_clicked = function ( editor, button ) { + this.clear_messages(); + this.clear_pulldowns(); + var self = this; if ( hasElementClass( button, "revoke_button" ) ) { @@ -1468,6 +1474,21 @@ Wiki.prototype.editor_button_clicked = function ( editor, button ) { }, function ( result ) { self.display_group_settings( result ); } ); + } else if ( hasElementClass( button, "remove_user_button" ) ) { + var id_pieces = button.id.split( "_" ); + var group_id = id_pieces.pop(); + var user_id = id_pieces.pop(); + + this.invoker.invoke( "/users/remove_group", "POST", { + "user_id_to_remove": user_id, + "group_id": group_id + }, function ( result ) { + self.invoker.invoke( "/groups/load_users", "GET", { + "group_id": group_id + }, function ( result ) { + self.display_group_settings( result ); + } ); + } ); } } @@ -1798,11 +1819,11 @@ Wiki.prototype.display_settings = function () { } Wiki.prototype.display_group_settings = function ( result ) { + this.clear_pulldowns(); + var group_frame = getElement( "note_group_" + result.group.object_id ); - if ( group_frame ) { - group_frame.editor.highlight(); - return; - } + if ( group_frame ) + group_frame.editor.shutdown(); var admin_list = createDOM( "div" ); var user_list = createDOM( "div" ); @@ -1826,16 +1847,6 @@ Wiki.prototype.display_group_settings = function ( result ) { ) ) ), - createDOM( "p", {}, - createDOM( "b", {}, "admins" ), - createDOM( "br", {} ), - admin_list - ), - createDOM( "p", {}, - createDOM( "b", {}, "members" ), - createDOM( "br", {} ), - user_list - ), createDOM( "h3", {}, "create group member" ), createDOM( "form", { "id": "create_user_form", "target": "/users/signup_group_member" }, createDOM( "input", @@ -1878,6 +1889,17 @@ Wiki.prototype.display_group_settings = function ( result ) { { "type": "submit", "name": "create_user_button", "id": "create_user_button", "class": "button", "value": "create member" } ) ) + ), + createDOM( "h3", {}, "group members" ), + createDOM( "p", {}, + createDOM( "b", {}, "admins" ), + createDOM( "br", {} ), + admin_list + ), + createDOM( "p", {}, + createDOM( "b", {}, "members" ), + createDOM( "br", {} ), + user_list ) ); @@ -1894,7 +1916,7 @@ Wiki.prototype.display_group_settings = function ( result ) { appendChildNodes( user_list, createDOM( "div", { "class": "indented" }, user.username, createDOM( "input", { "type": "button", - "id": "remove_user_" + user.object_id, + "id": "remove_user_" + user.object_id + "_" + result.group.object_id, "class": "remove_user_button button", "value": " x ", "title": "remove this user from the group"