Skip to content

Commit

Permalink
[Feature #159687667] Enable manager to delete from a gym and add alre…
Browse files Browse the repository at this point in the history
…ady existing users to the gym.

  The following changes have been made:
   * Modified the UI to enable addition of already existing users to the gym.
   * Enabled deletion of users from the gym only but not the entire app.
   * Created form to verify if the user already exists.
   * added tests.

 [Delivers #159687667]
  • Loading branch information
ja-odur committed Aug 20, 2018
1 parent 0113d88 commit fddbba9
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 9 deletions.
40 changes: 40 additions & 0 deletions wger/gym/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

from wger.core.forms import UserPersonalInformationForm
from wger.utils.widgets import BootstrapSelectMultiple
from wger.gym.models import GymAdminConfig
from django.db.utils import IntegrityError


class GymUserPermisssionForm(forms.ModelForm):
Expand Down Expand Up @@ -91,3 +93,41 @@ def clean_username(self):
return username
raise forms.ValidationError(
_("A user with that username already exists."))


class GymAddExistingUserForm(GymUserPermisssionForm):
'''
Form used when adding a user to a gym
'''

class Meta:
model = GymAdminConfig
widgets = {'role': BootstrapSelectMultiple()}
fields = ('username', 'role',)

username = forms.RegexField(label=_("Username"),
max_length=30,
regex=r'^[\w.@+-]+$',
help_text=_("Required. 30 characters or fewer. Letters, digits and "
"@/./+/-/_ only."),
error_messages={
'invalid': _("This value may contain only letters, numbers and "
"@/.//-/_ characters.")})

def clean_username(self):
'''
Since User.username is unique, this check is redundant,
but it sets a nicer error message than the ORM. See #13147.
'''
username = self.cleaned_data["username"]
try:
user = User._default_manager.get(username=username)
except User.DoesNotExist:
raise forms.ValidationError(
_("Username does not exists."))

if user.userprofile.gym_id is not None:
raise forms.ValidationError(
_(str(username) + " already belongs to a gym."))

return username
16 changes: 13 additions & 3 deletions wger/gym/templates/gym/member_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,18 @@ <h4>{% trans "Emails" %}</h4>
{# #}
{% block options %}
{% if perms.gym.manage_gym or perms.gym.manage_gyms %}
<a href="{% url 'gym:gym:add-user' gym.pk %}" class="btn btn-success btn-sm wger-modal-dialog">
{% trans "Add member" %}
</a>
<div class="btn-group pull-right">
<button type="button" class="btn btn-success btn-sm dropdown-toggle" data-toggle="dropdown">
{% trans "Add Member" %} <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li>
<a href="{% url 'gym:gym:add-user' gym.pk %}" class="wger-modal-dialog">{% trans "New User"%}</a>
</li>
<li>
<a href="{% url 'gym:gym:add-user-existing' gym.pk %}" class="wger-modal-dialog">{% trans "Existing User"%}</a>
</li>
</ul>
</div>
{% endif %}
{% endblock %}
56 changes: 56 additions & 0 deletions wger/gym/tests/test_add_existing_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from django.core.urlresolvers import reverse
from wger.core.tests.base_testcase import WorkoutManagerTestCase
from wger.gym.models import GymAdminConfig
from django.contrib.auth.models import User


class GymAddExistingUserTestCase(WorkoutManagerTestCase):
'''
Tests admin adding users to gyms
'''
def add_existing_user(self, fail=False, logged_in=True, role='admin'):
'''
Helper function to add users
'''
GymAdminConfig.objects.all().delete()

self.client.post(reverse('gym:gym:add-user', kwargs={'gym_pk': 1}),
{'first_name': 'Cletus',
'last_name': 'Spuckle',
'username': 'cletus',
'email': 'cletus@spuckle-megacorp.com',
'role': str(role)})

user = GymAdminConfig.objects.first()
if not fail:
user_pk = user.user_id if user else 4
self.client.post(
reverse('gym:gym:delete-user', kwargs={'user_pk': user_pk}))

response = self.client.post(reverse('gym:gym:add-user-existing', kwargs={'gym_pk': 1}),
{'username': 'cletus', 'role': str(role)})

if fail:
self.assertEqual(response.status_code, 403)
else:
self.assertEqual(response.status_code, 302)

def test_delete_user_authorized(self):
"""
Tests deleting a user an authorized user
"""
self.user_login('admin')
self.add_existing_user()

def test_delete_user_unauthorized(self):
"""
Tests deleting a user an unauthorized user
"""
self.user_login('test')
self.add_existing_user(fail=True)

def test_delete_user_not_logged_in(self):
"""
Tests deleting a user an unauthorized user
"""
self.add_existing_user(fail=True, logged_in=False)
5 changes: 4 additions & 1 deletion wger/gym/tests/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
from wger.core.models import UserProfile
from wger.core.tests.base_testcase import WorkoutManagerTestCase
from wger.gym.models import Gym
from wger.gym.models import GymAdminConfig
from wger.gym.models import (
GymAdminConfig,
GymUserConfig
)


class GymAddUserTestCase(WorkoutManagerTestCase):
Expand Down
3 changes: 3 additions & 0 deletions wger/gym/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
url(r'^(?P<gym_pk>\d+)/add-member$',
gym.GymAddUserView.as_view(),
name='add-user'),
url(r'^(?P<gym_pk>\d+)/add-member-existing$',
gym.GymAddExistingUserView.as_view(),
name='add-user-existing'),
url(r'^add$',
gym.GymAddView.as_view(),
name='add'),
Expand Down
80 changes: 75 additions & 5 deletions wger/gym/views/gym.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@
UpdateView
)

from wger.gym.forms import GymUserAddForm, GymUserPermisssionForm
from wger.gym.forms import (
GymUserAddForm,
GymAddExistingUserForm,
GymUserPermisssionForm
)
from wger.gym.helpers import (
get_user_last_activity,
is_any_gym_admin,
Expand Down Expand Up @@ -179,12 +183,15 @@ def delete_user(request, user_pk):

user_matched = GymUserConfig.objects.filter(user_id=member.id).first() or \
GymAdminConfig.objects.filter(user_id=member.id).first()
gym_id = user_matched.gym_id

if user_matched:
member = User.objects.filter(pk=user_pk).first()
member.delete()
member.userprofile.gym_id = None
member.userprofile.save()
user_matched.delete()

return HttpResponseRedirect(reverse("gym:gym:user-list", kwargs={'pk': user_matched.gym_id}))
return HttpResponseRedirect(reverse("gym:gym:user-list", kwargs={'pk': gym_id}))


@login_required()
Expand Down Expand Up @@ -359,8 +366,8 @@ class GymAddUserView(WgerFormMixin,
View to add a user to a new gym
'''

model = User
title = ugettext_lazy('Add user to gym')
model = GymAdminConfig
title = ugettext_lazy('Add new user to gym')
success_url = reverse_lazy('gym:gym:new-user-data')
permission_required = ('gym.manage_gym', 'gym.manage_gyms')
form_class = GymUserAddForm
Expand Down Expand Up @@ -450,6 +457,69 @@ def get_context_data(self, **kwargs):
return context


class GymAddExistingUserView(GymAddUserView):
'''
View to add a user to a new gym
'''

model = GymAdminConfig
title = ugettext_lazy('Add existing user to gym')
success_url = reverse_lazy('gym:gym:new-user-data')
permission_required = ('gym.manage_gym', 'gym.manage_gyms')
form_class = GymAddExistingUserForm

def form_valid(self, form):
'''
Create the user, set the user permissions and gym
'''
permissions = ['gym_member', 'gym_trainer', 'gym_manager', 'general_gym_manager']
gym = Gym.objects.get(pk=self.kwargs['gym_pk'])
user = User.objects.filter(username=form.cleaned_data['username']).first()
form.instance = user

# Update profile
user.userprofile.gym = gym
user.userprofile.save()

# Remove all previously set permissions
for perm in permissions:
user.groups.remove(Group.objects.get(name=str(perm)))

# Set appropriate permission groups
if 'user' in form.cleaned_data['role']:
user.groups.add(Group.objects.get(name='gym_member'))
if 'trainer' in form.cleaned_data['role']:
user.groups.add(Group.objects.get(name='gym_trainer'))
if 'admin' in form.cleaned_data['role']:
user.groups.add(Group.objects.get(name='gym_manager'))
if 'manager' in form.cleaned_data['role']:
user.groups.add(Group.objects.get(name='general_gym_manager'))

self.request.session['gym.user'] = {'user_pk': user.pk,
'password': '-/-'}

# Create config
if is_any_gym_admin(user):
config = GymAdminConfig()
else:
config = GymUserConfig()

config.user = user
config.gym = gym
config.save()

return super(GymAddUserView, self).form_valid(form)

def get_context_data(self, **kwargs):
'''
Send some additional data to the template
'''
context = super(GymAddExistingUserView, self).get_context_data(**kwargs)
context['form_action'] = reverse('gym:gym:add-user-existing',
kwargs={'gym_pk': self.kwargs['gym_pk']})
return context


class GymUpdateView(WgerFormMixin, LoginRequiredMixin,
PermissionRequiredMixin, UpdateView):
'''
Expand Down

0 comments on commit fddbba9

Please sign in to comment.