From 362d4c3074983b6dbc5e420b7b4f4ebd8f1d380d Mon Sep 17 00:00:00 2001 From: Evgeny Fadeev Date: Tue, 20 Mar 2012 21:37:05 -0400 Subject: user groups are deletable, commit from the bus en route to Cordoba --- askbot/forms.py | 13 ++- askbot/models/__init__.py | 18 +++- askbot/models/tag.py | 10 +- askbot/skins/common/media/js/user.js | 110 ++++++++++++++++++--- askbot/skins/common/media/js/utils.js | 16 +++ askbot/skins/default/media/style/style.less | 21 ++++ .../skins/default/templates/user_profile/user.html | 2 +- askbot/urls.py | 6 +- askbot/views/commands.py | 22 +++-- 9 files changed, 186 insertions(+), 32 deletions(-) diff --git a/askbot/forms.py b/askbot/forms.py index ebb1b519..45b722cc 100644 --- a/askbot/forms.py +++ b/askbot/forms.py @@ -1136,6 +1136,17 @@ class SimpleEmailSubscribeForm(forms.Form): email_settings_form = EFF(initial=EFF.NO_EMAIL_INITIAL) email_settings_form.save(user, save_unbound=True) -class AddUserToGroupForm(forms.Form): +class EditGroupMembershipForm(forms.Form): + """a form for adding or removing users + to and from user groups""" user_id = forms.IntegerField() group_name = forms.CharField() + action = forms.CharField() + + def clean_action(self): + """allowed actions are 'add' and 'remove'""" + action = self.cleaned_data['action'] + if action not in ('add', 'remove'): + del self.cleaned_data['action'] + raise forms.ValidationError('invalid action') + return action diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py index bbda51bc..7ad46619 100644 --- a/askbot/models/__init__.py +++ b/askbot/models/__init__.py @@ -2174,10 +2174,20 @@ def user_update_wildcard_tag_selections( return new_tags -def user_add_user_to_group(self, user = None, group = None): - """allows one user to add another to a pre-existing group""" - GroupMembership.objects.get_or_create(user = user, group = group) +def user_edit_group_membership(self, user = None, group = None, action = None): + """allows one user to add another to a group + or remove user from group. + If when adding, the group does not exist, it will be created + the delete function is not symmetric, the group will remain + even if it becomes empty + """ + if action == 'add': + GroupMembership.objects.get_or_create(user = user, group = group) + elif action == 'remove': + GroupMembership.objects.get(user = user, group = group).delete() + else: + raise ValueError('invalid action') User.add_to_class( 'add_missing_askbot_subscriptions', @@ -2241,7 +2251,7 @@ User.add_to_class('can_post_comment', user_can_post_comment) User.add_to_class('is_administrator', user_is_administrator) User.add_to_class('is_administrator_or_moderator', user_is_administrator_or_moderator) User.add_to_class('set_admin_status', user_set_admin_status) -User.add_to_class('add_user_to_group', user_add_user_to_group) +User.add_to_class('edit_group_membership', user_edit_group_membership) User.add_to_class('remove_admin_status', user_remove_admin_status) User.add_to_class('is_moderator', user_is_moderator) User.add_to_class('is_approved', user_is_approved) diff --git a/askbot/models/tag.py b/askbot/models/tag.py index 097c2df9..6e92bab9 100644 --- a/askbot/models/tag.py +++ b/askbot/models/tag.py @@ -86,6 +86,11 @@ class TagManager(BaseQuerySetManager): #class GroupTagQuerySet(models.query.QuerySet): # """Custom query set for the group""" # def __init__(self, model): +def clean_group_name(name): + """group names allow spaces, + tag names do not, so we use this method + to replace spaces with dashes""" + return re.sub('\s+', '-', name.strip()) class GroupTagManager(TagManager): """manager for group tags""" @@ -98,7 +103,7 @@ class GroupTagManager(TagManager): #todo: here we might fill out the group profile #replace spaces with dashes - group_name = re.sub('\s+', '-', group_name.strip()) + group_name = clean_group_name(group_name) try: tag = self.get(name = group_name) except self.model.DoesNotExist: @@ -118,6 +123,9 @@ class GroupTagManager(TagManager): member_count__gt = 0 ) + def get_by_name(self, group_name = None): + return self.get(name = clean_group_name(group_name)) + class Tag(models.Model): name = models.CharField(max_length=255, unique=True) created_by = models.ForeignKey(User, related_name='created_tags') diff --git a/askbot/skins/common/media/js/user.js b/askbot/skins/common/media/js/user.js index aed926d1..feab4d27 100644 --- a/askbot/skins/common/media/js/user.js +++ b/askbot/skins/common/media/js/user.js @@ -222,36 +222,114 @@ FollowUser.prototype.toggleState = function(){ /** * @constructor + * @param {string} name */ -GroupsContainer = function(){ +var UserGroup = function(name){ + WrappedElement.call(this); + this._name = name; +}; +inherits(UserGroup, WrappedElement); + +UserGroup.prototype.getDeleteHandler = function(){ + var group_name = this._name; + var me = this; + var groups_container = me._groups_container; + return function(){ + var data = { + user_id: askbot['data']['viewUserId'], + group_name: group_name, + action: 'remove' + }; + $.ajax({ + type: 'POST', + dataType: 'json', + data: data, + cache: false, + url: askbot['urls']['edit_group_membership'], + success: function(){ + groups_container.removeGroup(me); + } + }); + }; +}; + +UserGroup.prototype.getName = function(){ + return this._name; +}; + +UserGroup.prototype.setGroupsContainer = function(container){ + this._groups_container = container; +}; + +UserGroup.prototype.decorate = function(element){ + this._element = element; + this._name = $.trim(element.html()); + var deleter = new DeleteIcon(); + deleter.setHandler(this.getDeleteHandler()); + deleter.setContent('x'); + this._element.append(deleter.getElement()); + this._delete_icon = deleter; +}; + +UserGroup.prototype.createDom = function(){ + var element = this.makeElement('li'); + element.html(this._name + ' '); + this._element = element; + this.decorate(element); +}; + +UserGroup.prototype.dispose = function(){ + this._delete_icon.dispose(); + this._element.remove(); +}; + +/** + * @constructor + */ +var GroupsContainer = function(){ WrappedElement.call(this); }; inherits(GroupsContainer, WrappedElement); GroupsContainer.prototype.decorate = function(element){ this._element = element; - var groups = {}; + var groups = []; + var group_names = []; + var me = this; //collect list of groups $.each(element.find('li'), function(idx, li){ - groups[$(li).html()] = 1; - //var str = $(li).html(); - //var bytes = []; - //for (var i = 0; i -1){ return; } - var group = this.makeElement('li'); - group.html(group_name); - this._element.append(group); + var group = new UserGroup(group_name); + group.setGroupsContainer(this); + this._groups.push(group); + this._group_names.push(group_name); + this._element.append(group.getElement()); }; -GroupAdderWidget = function(){ +GroupsContainer.prototype.removeGroup = function(group){ + var idx = $.inArray(group, this._groups); + if (idx === -1){ + return; + } + this._groups.splice(idx, 1); + this._group_names.splice(idx, 1); + group.dispose(); +}; + +var GroupAdderWidget = function(){ WrappedElement.call(this); this._state = 'display';//display or edit }; @@ -291,14 +369,15 @@ GroupAdderWidget.prototype.getAddGroupHandler = function(){ var group_name = me.getValue(); var data = { group_name: group_name, - user_id: askbot['data']['viewUserId'] + user_id: askbot['data']['viewUserId'], + action: 'add' }; $.ajax({ type: 'POST', dataType: 'json', data: data, cache: false, - url: askbot['urls']['add_user_to_group'], + url: askbot['urls']['edit_group_membership'], success: function(data){ if (data['success'] == true){ me.addGroup(group_name); @@ -358,7 +437,7 @@ GroupAdderWidget.prototype.decorate = function(element){ * @constructor * allows editing user groups */ -UserGroupsEditor = function(){ +var UserGroupsEditor = function(){ WrappedElement.call(this); }; inherits(UserGroupsEditor, WrappedElement); @@ -389,4 +468,3 @@ UserGroupsEditor.prototype.decorate = function(element){ $('#add-group').remove(); } })(); - diff --git a/askbot/skins/common/media/js/utils.js b/askbot/skins/common/media/js/utils.js index 9e02b5d4..3a6fbfe5 100644 --- a/askbot/skins/common/media/js/utils.js +++ b/askbot/skins/common/media/js/utils.js @@ -240,6 +240,9 @@ WrappedElement.prototype.setElement = function(element){ WrappedElement.prototype.createDom = function(){ this._element = $('
'); }; +WrappedElement.prototype.decorate = function(element){ + this._element = element; +}; WrappedElement.prototype.getElement = function(){ if (this._element === null){ this.createDom(); @@ -308,6 +311,7 @@ EditLink.prototype.decorate = function(element){ var DeleteIcon = function(title){ SimpleControl.call(this); this._title = title; + this._content = null; }; inherits(DeleteIcon, SimpleControl); @@ -327,8 +331,20 @@ DeleteIcon.prototype.setHandlerInternal = function(){ DeleteIcon.prototype.createDom = function(){ this._element = this.makeElement('span'); this.decorate(this._element); + if (this._content !== null){ + this.setContent(this._content); + } }; +DeleteIcon.prototype.setContent = function(content){ + if (this._element === null){ + this._content = content; + } else { + this._content = content; + this._element.html(content); + } +} + var Tag = function(){ SimpleControl.call(this); this._deletable = false; diff --git a/askbot/skins/default/media/style/style.less b/askbot/skins/default/media/style/style.less index e63ff373..41e42d68 100644 --- a/askbot/skins/default/media/style/style.less +++ b/askbot/skins/default/media/style/style.less @@ -3383,3 +3383,24 @@ body.anon.lang-es { } } } + +/* user groups */ +#user-groups ul { + margin-bottom: 0px; +} +#user-groups .delete-icon { + float: none; + display: inline; + color: #525252; + padding: 0 3px 0 3px; + background: #ccc; + border-radius: 4px; + line-height:inherit; + -moz-border-radius: 4px; + -khtml-border-radius: 4px; + -webkit-border-radius: 4px; +} +#user-groups .delete-icon:hover { + color: white; + background: #b32f2f; +} diff --git a/askbot/skins/default/templates/user_profile/user.html b/askbot/skins/default/templates/user_profile/user.html index f204d338..15e0622a 100644 --- a/askbot/skins/default/templates/user_profile/user.html +++ b/askbot/skins/default/templates/user_profile/user.html @@ -23,7 +23,7 @@ var viewUserID = {{view_user.id}}; askbot['data']['viewUserName'] = '{{ view_user.username }}'; askbot['data']['viewUserId'] = {{view_user.id}}; - askbot['urls']['add_user_to_group'] = '{% url add_user_to_group %}'; + askbot['urls']['edit_group_membership'] = '{% url edit_group_membership %}'; askbot['urls']['get_groups_list'] = '{% url get_groups_list %}'; {% if request.user|can_moderate_user(view_user) %} diff --git a/askbot/urls.py b/askbot/urls.py index 1cc51be3..a920ee6a 100644 --- a/askbot/urls.py +++ b/askbot/urls.py @@ -258,9 +258,9 @@ urlpatterns = patterns('', name='manage_inbox' ), url(#ajax only - r'^add_user_to_group/$', - views.commands.add_user_to_group, - name='add_user_to_group' + r'^edit-group-membership/$', + views.commands.edit_group_membership, + name='edit_group_membership' ), url( r'^feeds/(?P.*)/$', diff --git a/askbot/views/commands.py b/askbot/views/commands.py index 2a7f9a0a..8d0fdda9 100644 --- a/askbot/views/commands.py +++ b/askbot/views/commands.py @@ -656,16 +656,16 @@ def read_message(request):#marks message a read @csrf.csrf_exempt @decorators.ajax_only @decorators.post_only -def add_user_to_group(request): +def edit_group_membership(request): if request.user.is_anonymous(): raise exceptions.PermissionDenied() if not request.user.is_administrator_or_moderator(): raise exceptions.PermissionDenied( - _('Only moderators and administrators can assign users to groups') + _('Only moderators and administrators can change user groups') ) - form = forms.AddUserToGroupForm(request.POST) + form = forms.EditGroupMembershipForm(request.POST) if form.is_valid(): group_name = form.cleaned_data['group_name'] user_id = form.cleaned_data['user_id'] @@ -676,8 +676,18 @@ def add_user_to_group(request): 'user with id %d not found' % user_id ) - group_params = {'group_name': group_name, 'user': user} - group = models.Tag.group_tags.get_or_create(**group_params) - request.user.add_user_to_group(user, group) + action = form.cleaned_data['action'] + if action == 'add': + group_params = {'group_name': group_name, 'user': user} + group = models.Tag.group_tags.get_or_create(**group_params) + request.user.edit_group_membership(user, group, 'add') + elif action == 'remove': + try: + group = models.Tag.group_tags.get_by_name(group_name = group_name) + request.user.edit_group_membership(user, group, 'remove') + except models.Tag.DoesNotExist: + raise exceptions.PermissionDenied() + else: + raise exceptions.PermissionDenied() else: raise exceptions.PermissionDenied() -- cgit v1.2.3-1-g7c22