mirror of
https://github.com/wger-project/wger.git
synced 2026-02-18 00:17:51 +01:00
Add system wide gym configuration options
At the moment this only allows the administrator to set a default gym for the installation.
This commit is contained in:
@@ -60,7 +60,12 @@ filter_dump(data, ('exercises.equipment', 'exercises.equipment',), 'equipment.js
|
||||
filter_dump(data, ('core.gym',), 'gyms.json')
|
||||
filter_dump(data, ('core.language',), 'languages.json')
|
||||
filter_dump(data, ('core.license',), 'licenses.json')
|
||||
|
||||
#
|
||||
# Configurations
|
||||
#
|
||||
filter_dump(data, ('config.languageconfig',), 'language_config.json')
|
||||
filter_dump(data, ('config.gymconfig',), 'gym-config.json')
|
||||
|
||||
#
|
||||
# Other
|
||||
|
||||
9
wger/config/fixtures/gym-config.json
Normal file
9
wger/config/fixtures/gym-config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
[
|
||||
{
|
||||
"pk": 1,
|
||||
"model": "config.gymconfig",
|
||||
"fields": {
|
||||
"default_gym": null
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,69 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from south.utils import datetime_utils as datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding model 'GymConfig'
|
||||
db.create_table(u'config_gymconfig', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('default_gym', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.Gym'], null=True, blank=True)),
|
||||
))
|
||||
db.send_create_signal(u'config', ['GymConfig'])
|
||||
|
||||
|
||||
# Changing field 'LanguageConfig.language_target'
|
||||
db.alter_column(u'config_languageconfig', 'language_target_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.Language']))
|
||||
|
||||
# Changing field 'LanguageConfig.language'
|
||||
db.alter_column(u'config_languageconfig', 'language_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.Language']))
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting model 'GymConfig'
|
||||
db.delete_table(u'config_gymconfig')
|
||||
|
||||
|
||||
# Changing field 'LanguageConfig.language_target'
|
||||
db.alter_column(u'config_languageconfig', 'language_target_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['exercises.Language']))
|
||||
|
||||
# Changing field 'LanguageConfig.language'
|
||||
db.alter_column(u'config_languageconfig', 'language_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['exercises.Language']))
|
||||
|
||||
models = {
|
||||
u'config.gymconfig': {
|
||||
'Meta': {'object_name': 'GymConfig'},
|
||||
'default_gym': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Gym']", 'null': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
u'config.languageconfig': {
|
||||
'Meta': {'ordering': "['item', 'language_target']", 'object_name': 'LanguageConfig'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'item': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
|
||||
'language': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'language_source'", 'to': u"orm['core.Language']"}),
|
||||
'language_target': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'language_target'", 'to': u"orm['core.Language']"}),
|
||||
'show': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
u'core.gym': {
|
||||
'Meta': {'object_name': 'Gym'},
|
||||
'city': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '60'}),
|
||||
'owner': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
|
||||
'phone': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
|
||||
'street': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
|
||||
'zip_code': ('django.db.models.fields.IntegerField', [], {'max_length': '5', 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
u'core.language': {
|
||||
'Meta': {'ordering': "['full_name']", 'object_name': 'Language'},
|
||||
'full_name': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'short_name': ('django.db.models.fields.CharField', [], {'max_length': '2'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['config']
|
||||
@@ -22,6 +22,8 @@ from django.db.models.signals import post_save
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.cache import cache
|
||||
from wger.core.models import Language
|
||||
from wger.core.models import Gym
|
||||
from wger.core.models import UserProfile
|
||||
|
||||
from wger.utils.cache import delete_template_fragment_cache
|
||||
from wger.utils.cache import cache_mapper
|
||||
@@ -119,3 +121,38 @@ def init_language_config(sender, instance, created, **kwargs):
|
||||
config.show = False
|
||||
config.save()
|
||||
post_save.connect(init_language_config, sender=Language)
|
||||
|
||||
|
||||
class GymConfig(models.Model):
|
||||
'''
|
||||
System wide configuration for gyms
|
||||
|
||||
At the moment this only allows to set one gym as the default
|
||||
'''
|
||||
|
||||
default_gym = models.ForeignKey(Gym,
|
||||
verbose_name=_('Default gym'),
|
||||
help_text=_('Select the default gym for this installation. '
|
||||
'This will assign all new registered users to this '
|
||||
'gym and update all existing users without a '
|
||||
'gym.'),
|
||||
null=True,
|
||||
blank=True)
|
||||
'''
|
||||
Default gym for the wger installation
|
||||
'''
|
||||
|
||||
def __unicode__(self):
|
||||
'''
|
||||
Return a more human-readable representation
|
||||
'''
|
||||
return u"Default gym {0}".format(self.gym)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
'''
|
||||
All users that have no gym set in the profile are edited
|
||||
'''
|
||||
if self.default_gym:
|
||||
UserProfile.objects.filter(gym=None).update(gym=self.default_gym)
|
||||
|
||||
return super(GymConfig, self).save(*args, **kwargs)
|
||||
|
||||
86
wger/config/tests/test_gym_config.py
Normal file
86
wger/config/tests/test_gym_config.py
Normal file
@@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This file is part of wger Workout Manager.
|
||||
#
|
||||
# wger Workout Manager is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# wger Workout Manager is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from wger.config.models import GymConfig
|
||||
from wger.core.models import Gym, UserProfile
|
||||
from wger.manager.tests.testcase import WorkoutManagerTestCase
|
||||
|
||||
|
||||
class GymConfigTestCase(WorkoutManagerTestCase):
|
||||
'''
|
||||
Test the system wide gym configuration
|
||||
'''
|
||||
|
||||
def test_default_gym(self):
|
||||
'''
|
||||
Test that newly registered users get a gym
|
||||
'''
|
||||
|
||||
gym = Gym.objects.get(pk=2)
|
||||
gym_config = GymConfig.objects.get(pk=1)
|
||||
gym_config.default_gym = gym
|
||||
gym_config.save()
|
||||
|
||||
# Register
|
||||
registration_data = {'username': 'myusername',
|
||||
'password1': 'secret',
|
||||
'password2': 'secret',
|
||||
'email': 'my.email@example.com',
|
||||
'recaptcha_response_field': 'PASSED', }
|
||||
self.client.post(reverse('core:registration'), registration_data)
|
||||
new_user = User.objects.get(pk=4)
|
||||
|
||||
self.assertEqual(new_user.userprofile.gym, gym)
|
||||
|
||||
def test_no_default_gym(self):
|
||||
'''
|
||||
Test the user registration without a default gym
|
||||
'''
|
||||
|
||||
gym = Gym.objects.get(pk=2)
|
||||
gym_config = GymConfig.objects.get(pk=1)
|
||||
gym_config.default_gym = None
|
||||
gym_config.save()
|
||||
|
||||
# Register
|
||||
registration_data = {'username': 'myusername',
|
||||
'password1': 'secret',
|
||||
'password2': 'secret',
|
||||
'email': 'my.email@example.com',
|
||||
'recaptcha_response_field': 'PASSED', }
|
||||
self.client.post(reverse('core:registration'), registration_data)
|
||||
|
||||
new_user = User.objects.get(pk=4)
|
||||
self.assertEqual(new_user.userprofile.gym_id, None)
|
||||
|
||||
def test_update_userprofile(self):
|
||||
'''
|
||||
Test setting the gym for users when setting a default gym
|
||||
'''
|
||||
|
||||
UserProfile.objects.update(gym=None)
|
||||
self.assertEqual(UserProfile.objects.exclude(gym=None).count(), 0)
|
||||
|
||||
gym = Gym.objects.get(pk=2)
|
||||
gym_config = GymConfig.objects.get(pk=1)
|
||||
gym_config.default_gym = gym
|
||||
gym_config.save()
|
||||
|
||||
self.assertEqual(UserProfile.objects.filter(gym=gym).count(), 3)
|
||||
@@ -19,6 +19,7 @@ from django.conf.urls import patterns, url
|
||||
|
||||
from wger.config.views import languages
|
||||
from wger.config.views import language_config
|
||||
from wger.config.views import gym_config
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
@@ -40,8 +41,13 @@ urlpatterns = patterns('',
|
||||
languages.LanguageCreateView.as_view(),
|
||||
name='language-add'),
|
||||
|
||||
# Language configs
|
||||
url(r'^language/config/(?P<pk>\d+)/edit',
|
||||
language_config.LanguageConfigUpdateView.as_view(),
|
||||
name='languageconfig-edit'),
|
||||
# Language configs
|
||||
url(r'^language-config/(?P<pk>\d+)/edit',
|
||||
language_config.LanguageConfigUpdateView.as_view(),
|
||||
name='languageconfig-edit'),
|
||||
|
||||
# Gym config
|
||||
url(r'^default-gym',
|
||||
gym_config.GymConfigUpdateView.as_view(),
|
||||
name='gymconfig-edit'),
|
||||
)
|
||||
|
||||
49
wger/config/views/gym_config.py
Normal file
49
wger/config/views/gym_config.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This file is part of wger Workout Manager.
|
||||
#
|
||||
# wger Workout Manager is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# wger Workout Manager is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
|
||||
import logging
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.views.generic import UpdateView
|
||||
|
||||
from wger.config.models import GymConfig
|
||||
from wger.utils.generic_views import WgerFormMixin
|
||||
|
||||
|
||||
logger = logging.getLogger('wger.custom')
|
||||
|
||||
|
||||
class GymConfigUpdateView(WgerFormMixin, UpdateView):
|
||||
'''
|
||||
Generic view to edit the gym config table
|
||||
'''
|
||||
model = GymConfig
|
||||
permission_required = 'config.change_gymconfig'
|
||||
success_url = reverse_lazy('config:gymconfig-edit')
|
||||
|
||||
def get_object(self):
|
||||
'''
|
||||
Return the only gym config object
|
||||
'''
|
||||
return GymConfig.objects.get(pk=1)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(GymConfigUpdateView, self).get_context_data(**kwargs)
|
||||
context['form_action'] = reverse('config:gymconfig-edit')
|
||||
context['title'] = _('Edit')
|
||||
return context
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
{% block sidebar %}
|
||||
{% if perms.core.add_gym %}
|
||||
<h3>{% trans "Options" %}</h3>
|
||||
<h4>{% trans "Options" %}</h4>
|
||||
<p>
|
||||
<a href="{% url 'core:gym-add' %}"
|
||||
{% auto_link_css flavour "wger-modal-dialog" %}>
|
||||
@@ -49,4 +49,19 @@
|
||||
</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if perms.core.change_gymconfig %}
|
||||
<h4>{% trans "Default gym" %}</h4>
|
||||
<p>
|
||||
<a href="{% url 'config:gymconfig-edit' %}"
|
||||
{% auto_link_css flavour %}>
|
||||
<img src="{% static 'images/icons/list.svg' %}"
|
||||
width="32"
|
||||
height="32"
|
||||
alt="{% trans 'Default gym configuration' %}"
|
||||
title="{% trans 'Default gym configuration' %}">
|
||||
{% trans "Default gym configuration" %}
|
||||
</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -42,6 +42,7 @@ from wger.core.forms import UserPreferencesForm, UserPersonalInformationForm
|
||||
from wger.core.forms import PasswordConfirmationForm
|
||||
from wger.core.forms import RegistrationForm
|
||||
from wger.core.forms import RegistrationFormNoCaptcha
|
||||
from wger.config.models import GymConfig
|
||||
|
||||
logger = logging.getLogger('wger.custom')
|
||||
|
||||
@@ -168,9 +169,14 @@ def registration(request):
|
||||
password)
|
||||
user.save()
|
||||
|
||||
# Save the notification language
|
||||
# Pre-set some values of the user's profile
|
||||
language = Language.objects.get(short_name=translation.get_language())
|
||||
user.userprofile.notification_language = language
|
||||
|
||||
gym_config = GymConfig.objects.get(pk=1)
|
||||
if gym_config:
|
||||
user.userprofile.gym = gym_config.default_gym
|
||||
|
||||
user.userprofile.save()
|
||||
|
||||
user = authenticate(username=username, password=password)
|
||||
|
||||
@@ -51,6 +51,7 @@ class BaseTestCase(object):
|
||||
'''
|
||||
|
||||
fixtures = ('days_of_week',
|
||||
'gym-config',
|
||||
'test-languages',
|
||||
'test-licenses',
|
||||
'test-gyms',
|
||||
|
||||
@@ -348,3 +348,9 @@ REST_FRAMEWORK = {
|
||||
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',
|
||||
'rest_framework.filters.OrderingFilter',)
|
||||
}
|
||||
|
||||
|
||||
# Configure south database migrations
|
||||
SOUTH_MIGRATION_MODULES = {
|
||||
'easy_thumbnails': 'easy_thumbnails.south_migrations',
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user