diff --git a/wger/gym/forms.py b/wger/gym/forms.py
index ce5a90c6..66c1c611 100644
--- a/wger/gym/forms.py
+++ b/wger/gym/forms.py
@@ -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):
@@ -91,3 +93,47 @@ 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._default_manager.get(username=username)
+ except User.DoesNotExist:
+ raise forms.ValidationError(
+ _("Username does not exists."))
+
+ try:
+ user = User._default_manager.get(username=username)
+
+ if user.userprofile.gym_id is not None:
+ raise forms.ValidationError(
+ _(str(username) + " already belongs to a gym."))
+ except (TypeError, IntegrityError):
+ raise forms.ValidationError(
+ _(str(username) + " already belongs to a gym."))
+
+ return username
diff --git a/wger/gym/templates/gym/member_list.html b/wger/gym/templates/gym/member_list.html
index 4eac16a4..9ea571bf 100644
--- a/wger/gym/templates/gym/member_list.html
+++ b/wger/gym/templates/gym/member_list.html
@@ -428,8 +428,18 @@
{% trans "Emails" %}
{# #}
{% block options %}
{% if perms.gym.manage_gym or perms.gym.manage_gyms %}
-
- {% trans "Add member" %}
-
+
+
+
+
{% endif %}
{% endblock %}
diff --git a/wger/gym/tests/test_user.py b/wger/gym/tests/test_user.py
index 251b5e08..05fa9ddd 100644
--- a/wger/gym/tests/test_user.py
+++ b/wger/gym/tests/test_user.py
@@ -142,6 +142,66 @@ def test_new_user_data_export(self):
self.new_user_data_export(fail=True)
+class GymAddExistingUserTestCase(WorkoutManagerTestCase):
+ '''
+ Tests admin adding users to gyms
+ '''
+ def add_existing_user(self, fail=False, logged_in=True):
+ '''
+ Helper function to add users
+ '''
+ GymAdminConfig.objects.all().delete()
+ count_after = User.objects.all().count()
+
+ 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': 'admin'})
+
+ user = GymAdminConfig.objects.first()
+
+ user_pk = user.pk 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': 'admin'})
+
+ count_before = User.objects.all().count()
+ # self.assertEqual(GymAdminConfig.objects.all().count(), 1)
+
+ if fail:
+ self.assertEqual(response.status_code, 403)
+ self.assertEqual(count_before, count_after)
+ self.assertFalse(self.client.session.get('gym.user'))
+ else:
+ self.assertEqual(response.status_code, 200)
+ self.assertTrue(self.client.session['gym.user']['user_pk'], 3)
+ self.assertTrue(self.client.session['gym.user']['password'])
+
+ 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)
+
+
class TrainerLoginTestCase(WorkoutManagerTestCase):
'''
Tests the trainer login view (switching to user ID)
diff --git a/wger/gym/urls.py b/wger/gym/urls.py
index 2eb31c6e..59584d69 100644
--- a/wger/gym/urls.py
+++ b/wger/gym/urls.py
@@ -51,6 +51,9 @@
url(r'^(?P\d+)/add-member$',
gym.GymAddUserView.as_view(),
name='add-user'),
+ url(r'^(?P\d+)/add-member-existing$',
+ gym.GymAddExistingUserView.as_view(),
+ name='add-user-existing'),
url(r'^add$',
gym.GymAddView.as_view(),
name='add'),
diff --git a/wger/gym/views/gym.py b/wger/gym/views/gym.py
index 7807bf25..febd839e 100644
--- a/wger/gym/views/gym.py
+++ b/wger/gym/views/gym.py
@@ -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,
@@ -179,10 +183,13 @@ 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}))
@@ -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
@@ -450,6 +457,64 @@ 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
+ '''
+ 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()
+
+ # 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(GymAddUserView, 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):
'''