diff --git a/.DS_Store b/.DS_Store
deleted file mode 100644
index 273f9dd..0000000
Binary files a/.DS_Store and /dev/null differ
diff --git a/.gitignore b/.gitignore
index 080429a..3ffb631 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,10 +43,10 @@ coverage.xml
# Translations
*.mo
*.pot
-
+.DS_Store
# Django stuff:
*.log
-settings*.py
+settings.py
*.sqlite
/CACHE
diff --git a/.travis.yml b/.travis.yml
index ef974a0..e7d2845 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,9 +14,9 @@ sudo: false
# Python versions to test
python:
- - "2.7"
- - "3.4"
- - "3.5"
+ # - "2.7"
+ - "3.6"
+
# Manually define here the combinations environment variables to test
# https://github.com/travis-ci/travis-ci/issues/1519
@@ -37,6 +37,9 @@ install:
- nvm install $TRAVIS_NODE_VERSION
- nvm use $TRAVIS_NODE_VERSION
+ # upgrade setuptools separately to avoid race condition
+ - pip install -U setuptools
+
# Install requirements
- pip install -r requirements_devel.txt
- npm install
@@ -60,7 +63,7 @@ script:
- gulp lint
# Regular application
- - coverage run --source='.' ./manage.py test
+ - coverage run --source='wger' ./manage.py test
# Code coverage
diff --git a/Procfile b/Procfile
index 968de97..8f351ba 100644
--- a/Procfile
+++ b/Procfile
@@ -1 +1 @@
-web: gunicorn wger.wsgi --log-file -
\ No newline at end of file
+web: python manage.py runserver 0.0.0.0:$PORT
\ No newline at end of file
diff --git a/logfile b/logfile
new file mode 100644
index 0000000..91145fc
--- /dev/null
+++ b/logfile
@@ -0,0 +1,2 @@
+FATAL: pre-existing shared memory block (key 5432001, ID 262144) is still in use
+HINT: If you're sure there are no old server processes still running, remove the shared memory block or just delete the file "postmaster.pid".
diff --git a/wger/config/migrations/0002_auto_20170428_2135.py b/wger/config/migrations/0002_auto_20170428_2135.py
new file mode 100644
index 0000000..bb3ec28
--- /dev/null
+++ b/wger/config/migrations/0002_auto_20170428_2135.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.13 on 2017-04-28 18:35
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('config', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='languageconfig',
+ name='item',
+ field=models.CharField(choices=[('1', 'Exercises'), ('2', 'Ingredients')], editable=False, max_length=2),
+ ),
+ ]
diff --git a/wger/core/migrations/0010_auto_20170428_2135.py b/wger/core/migrations/0010_auto_20170428_2135.py
new file mode 100644
index 0000000..06f2fa6
--- /dev/null
+++ b/wger/core/migrations/0010_auto_20170428_2135.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.13 on 2017-04-28 18:35
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('core', '0009_auto_20160303_2340'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='license',
+ name='full_name',
+ field=models.CharField(help_text='If a license has been localized, e.g. the Creative Commons licenses for the different countries, add them as separate entries here.', max_length=60, verbose_name='Full name'),
+ ),
+ ]
diff --git a/wger/core/templates/form2.html b/wger/core/templates/form2.html
new file mode 100644
index 0000000..ab4851a
--- /dev/null
+++ b/wger/core/templates/form2.html
@@ -0,0 +1,46 @@
+{% extends extend_template %}
+{% load i18n staticfiles wger_extras django_bootstrap_breadcrumbs %}
+
+{# #}
+{# Breadcrumbs #}
+{# #}
+{% block breadcrumbs %}
+ {{ block.super }}
+
+ {% breadcrumb "Exporting and importing workouts enables you & friends to share custom workouts." workout.pk%}
+{% endblock %}
+
+{% block header %}
+
+{{ form.media }}
+
+{% if custom_js %}
+
+{% endif %}
+{% endblock %}
+
+
+{% block title %}{{title}}{% endblock %}
+
+
+{% block content %}
+
+
+
+{% endblock %}
+
+
+
+
+{% block sidebar %}{% if sidebar %}{% include sidebar %}
+{% endif %}{% endblock %}
diff --git a/wger/email/migrations/0002_auto_20170428_2135.py b/wger/email/migrations/0002_auto_20170428_2135.py
new file mode 100644
index 0000000..a5dde33
--- /dev/null
+++ b/wger/email/migrations/0002_auto_20170428_2135.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.13 on 2017-04-28 18:35
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('email', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='log',
+ options={'ordering': ['-date']},
+ ),
+ migrations.AlterField(
+ model_name='log',
+ name='gym',
+ field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='email_log', to='gym.Gym'),
+ ),
+ ]
diff --git a/wger/exercises/migrations/0004_auto_20170428_2135.py b/wger/exercises/migrations/0004_auto_20170428_2135.py
new file mode 100644
index 0000000..80d7907
--- /dev/null
+++ b/wger/exercises/migrations/0004_auto_20170428_2135.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.13 on 2017-04-28 18:35
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('exercises', '0003_auto_20160921_2000'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='exercise',
+ name='equipment',
+ field=models.ManyToManyField(blank=True, to='exercises.Equipment', verbose_name='Equipment'),
+ ),
+ migrations.AlterField(
+ model_name='exercise',
+ name='muscles',
+ field=models.ManyToManyField(blank=True, to='exercises.Muscle', verbose_name='Primary muscles'),
+ ),
+ migrations.AlterField(
+ model_name='exercise',
+ name='muscles_secondary',
+ field=models.ManyToManyField(blank=True, related_name='secondary_muscles', to='exercises.Muscle', verbose_name='Secondary muscles'),
+ ),
+ migrations.AlterField(
+ model_name='exercise',
+ name='status',
+ field=models.CharField(choices=[('1', 'Pending'), ('2', 'Accepted'), ('3', 'Declined')], default='1', editable=False, max_length=2),
+ ),
+ migrations.AlterField(
+ model_name='exerciseimage',
+ name='is_main',
+ field=models.BooleanField(default=False, help_text='Tick the box if you want to set this image as the main one for the exercise (will be shown e.g. in the search). The first image is automatically marked by the system.', verbose_name='Main picture'),
+ ),
+ migrations.AlterField(
+ model_name='exerciseimage',
+ name='status',
+ field=models.CharField(choices=[('1', 'Pending'), ('2', 'Accepted'), ('3', 'Declined')], default='1', editable=False, max_length=2),
+ ),
+ ]
diff --git a/wger/gym/migrations/0007_auto_20170428_2135.py b/wger/gym/migrations/0007_auto_20170428_2135.py
new file mode 100644
index 0000000..e45c985
--- /dev/null
+++ b/wger/gym/migrations/0007_auto_20170428_2135.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.13 on 2017-04-28 18:35
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('gym', '0006_auto_20160214_1013'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='gym',
+ options={'ordering': ['name'], 'permissions': (('gym_trainer', 'Trainer: can see the users for a gym'), ('manage_gym', 'Admin: can manage users for a gym'), ('manage_gyms', 'Admin: can administrate the different gyms'))},
+ ),
+ migrations.AlterField(
+ model_name='contract',
+ name='options',
+ field=models.ManyToManyField(blank=True, to='gym.ContractOption', verbose_name='Options'),
+ ),
+ migrations.AlterField(
+ model_name='gymadminconfig',
+ name='overview_inactive',
+ field=models.BooleanField(default=True, help_text='Receive email overviews of inactive members', verbose_name='Overview of inactive members'),
+ ),
+ migrations.AlterField(
+ model_name='gymconfig',
+ name='weeks_inactive',
+ field=models.PositiveIntegerField(default=4, help_text='Number of weeks since the last time a user logged his presence to be considered inactive', verbose_name='Reminder of inactive members'),
+ ),
+ ]
diff --git a/wger/manager/forms.py b/wger/manager/forms.py
index c8cc6c6..aa7a487 100644
--- a/wger/manager/forms.py
+++ b/wger/manager/forms.py
@@ -76,6 +76,12 @@ class WorkoutCopyForm(Form):
required=False)
+class WorkoutExportForm(Form):
+ comment = CharField(max_length=100,
+ help_text=_('Give a title to this workout export.'),
+ required=False)
+
+
class DayForm(ModelForm):
class Meta:
model = Day
diff --git a/wger/manager/migrations/0008_auto_20170428_2135.py b/wger/manager/migrations/0008_auto_20170428_2135.py
new file mode 100644
index 0000000..beeb8ba
--- /dev/null
+++ b/wger/manager/migrations/0008_auto_20170428_2135.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.13 on 2017-04-28 18:35
+from __future__ import unicode_literals
+
+import django.core.validators
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('manager', '0007_auto_20160311_2258'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='setting',
+ name='reps',
+ field=models.IntegerField(validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(600)], verbose_name='Amount'),
+ ),
+ ]
diff --git a/wger/manager/templates/workout/overview.html b/wger/manager/templates/workout/overview.html
index f8e3721..a787309 100644
--- a/wger/manager/templates/workout/overview.html
+++ b/wger/manager/templates/workout/overview.html
@@ -33,4 +33,5 @@ {{ workout }}
{% trans "Add workout" %}
+
{% endblock %}
diff --git a/wger/manager/templates/workout/view.html b/wger/manager/templates/workout/view.html
index 9e14ae8..a58fefc 100644
--- a/wger/manager/templates/workout/view.html
+++ b/wger/manager/templates/workout/view.html
@@ -251,6 +251,18 @@ {% trans "Download as PDF" %}
{% trans "Make a copy of this workout" %}
+
+
+
+ {% trans "Export this workout" %}
+
+
+
+
+
+ {% trans "Import custom workout" %}
+
+
{% if is_owner %}
diff --git a/wger/manager/urls.py b/wger/manager/urls.py
index 9de289b..ea9a55c 100644
--- a/wger/manager/urls.py
+++ b/wger/manager/urls.py
@@ -52,6 +52,12 @@
url(r'^add$',
workout.add,
name='add'),
+ url(r'^(?P\d+)/export/$',
+ workout.export,
+ name='export'),
+ url(r'^(?P\d+)/imports/$',
+ workout.imports,
+ name='imports'),
url(r'^(?P\d+)/copy/$',
workout.copy_workout,
name='copy'),
diff --git a/wger/manager/views/workout.py b/wger/manager/views/workout.py
index a14e1ee..7390043 100644
--- a/wger/manager/views/workout.py
+++ b/wger/manager/views/workout.py
@@ -19,13 +19,17 @@
import datetime
from django.shortcuts import render, get_object_or_404
-from django.http import HttpResponseRedirect, HttpResponseForbidden
+from django.http import HttpResponseRedirect, HttpResponseForbidden, HttpResponse
from django.template.context_processors import csrf
from django.core.urlresolvers import reverse, reverse_lazy
from django.utils.translation import ugettext_lazy, ugettext as _
from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin
from django.contrib.auth.decorators import login_required
from django.views.generic import DeleteView, UpdateView
+from django.core import serializers
+
+
+import json
from wger.core.models import (
RepetitionUnit,
@@ -41,7 +45,8 @@
from wger.manager.forms import (
WorkoutForm,
WorkoutSessionHiddenFieldsForm,
- WorkoutCopyForm
+ WorkoutCopyForm,
+ WorkoutExportForm
)
from wger.utils.generic_views import (
WgerFormMixin,
@@ -49,6 +54,8 @@
)
from wger.utils.helpers import make_token
+from wger.manager.api import resources
+
logger = logging.getLogger(__name__)
@@ -121,6 +128,46 @@ def view(request, pk):
return render(request, 'workout/view.html', template_data)
+@login_required
+def imports(request, pk):
+ pass
+
+
+@login_required
+def export(request, pk):
+ '''
+ Exports workouts as json
+ '''
+
+ workout = get_object_or_404(Workout, pk=pk)
+ user = workout.user
+ is_owner = request.user == user
+
+ if not is_owner and not user.userprofile.ro_access:
+ return HttpResponseForbidden()
+ # Process request
+ if request.method == 'POST':
+ # workout_export_form = WorkoutExportForm(request.POST)
+
+ data = serializers.serialize('json', Workout.objects.filter(user=request.user))
+ response = HttpResponse(data, content_type='application/force-download')
+ response['Content-Disposition'] = 'attachment; filename="workouts.json"'
+ return response
+ else:
+ workout_export_form = WorkoutExportForm({'comment': workout.comment})
+
+ template_data = {}
+ template_data.update(csrf(request))
+ template_data['title'] = _('Export Workout')
+ template_data['form'] = workout_export_form
+ template_data['form_action'] = reverse('manager:workout:export', kwargs={'pk': workout.id})
+ template_data['form_fields'] = [workout_export_form['comment']]
+ template_data['submit_text'] = _('Export')
+ template_data['extend_template'] = 'base_empty.html' if request.is_ajax() else 'base.html'
+
+ return render(request, 'form2.html', template_data)
+
+
@login_required
def copy_workout(request, pk):
'''
diff --git a/wger/nutrition/migrations/0002_auto_20170428_2135.py b/wger/nutrition/migrations/0002_auto_20170428_2135.py
new file mode 100644
index 0000000..8d4bf55
--- /dev/null
+++ b/wger/nutrition/migrations/0002_auto_20170428_2135.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.13 on 2017-04-28 18:35
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('nutrition', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='ingredient',
+ name='status',
+ field=models.CharField(choices=[('1', 'Pending'), ('2', 'Accepted'), ('3', 'Declined'), ('4', 'Submitted by administrator'), ('5', 'System ingredient')], default='1', editable=False, max_length=2),
+ ),
+ migrations.AlterField(
+ model_name='meal',
+ name='order',
+ field=models.IntegerField(blank=True, editable=False, verbose_name='Order'),
+ ),
+ migrations.AlterField(
+ model_name='mealitem',
+ name='order',
+ field=models.IntegerField(blank=True, editable=False, verbose_name='Order'),
+ ),
+ ]
diff --git a/wger/settings_global.py b/wger/settings_global.py
new file mode 100644
index 0000000..abba0a8
--- /dev/null
+++ b/wger/settings_global.py
@@ -0,0 +1,372 @@
+# -*- 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 re
+import sys
+
+'''
+This file contains the global settings that don't usually need to be changed.
+For a full list of options, visit:
+ https://docs.djangoproject.com/en/dev/ref/settings/
+'''
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+import os
+BASE_DIR = os.path.abspath(os.path.dirname(__file__))
+SITE_ROOT = os.path.realpath(os.path.dirname(__file__))
+
+#
+# Application definition
+#
+SITE_ID = 1
+ROOT_URLCONF = 'wger.urls'
+WSGI_APPLICATION = 'wger.wsgi.application'
+
+INSTALLED_APPS = (
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.sites',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+
+ # Uncomment the next line to enable the admin:
+ 'django.contrib.admin',
+
+ # Apps from wger proper
+ 'wger.core',
+ 'wger.manager',
+ 'wger.weight',
+ 'wger.exercises',
+ 'wger.nutrition',
+ 'wger.software',
+ 'wger.utils',
+ 'wger.config',
+ 'wger.gym',
+ 'wger.email',
+
+ # reCaptcha support, see https://github.com/praekelt/django-recaptcha
+ 'captcha',
+
+ # The sitemaps app
+ 'django.contrib.sitemaps',
+
+ # Django mobile
+ 'django_mobile',
+
+ # thumbnails
+ 'easy_thumbnails',
+
+ # CSS/JS compressor
+ 'compressor',
+
+ # REST-API
+ 'tastypie',
+ 'rest_framework',
+ 'rest_framework.authtoken',
+
+ # Breadcrumbs
+ 'django_bootstrap_breadcrumbs',
+
+ # CORS
+ 'corsheaders',
+
+ # django-bower for installing bower packages
+ 'djangobower',
+)
+
+# added list of external libraries to be installed by bower
+BOWER_INSTALLED_APPS = (
+ 'jquery#2.1.x',
+ 'bootstrap',
+ 'd3',
+ 'shariff',
+ 'tinymce-dist',
+ 'DataTables',
+ 'components-font-awesome',
+ 'tinymce',
+ 'metrics-graphics',
+ 'devbridge-autocomplete#1.2.x',
+ 'sortablejs#1.4.x',
+)
+
+
+MIDDLEWARE_CLASSES = (
+ 'corsheaders.middleware.CorsMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+
+ # Javascript Header. Sends helper headers for AJAX
+ 'wger.utils.middleware.JavascriptAJAXRedirectionMiddleware',
+
+ # Custom authentication middleware. Creates users on-the-fly for certain paths
+ 'wger.utils.middleware.WgerAuthenticationMiddleware',
+
+ # Send an appropriate Header so search engines don't index pages
+ 'wger.utils.middleware.RobotsExclusionMiddleware',
+
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+ 'django.middleware.locale.LocaleMiddleware',
+
+ # Django mobile
+ 'django_mobile.middleware.MobileDetectionMiddleware',
+ 'django_mobile.middleware.SetFlavourMiddleware',
+)
+
+AUTHENTICATION_BACKENDS = (
+ 'django.contrib.auth.backends.ModelBackend',
+ 'wger.utils.helpers.EmailAuthBackend'
+)
+
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ # 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ 'wger.utils.context_processor.processor',
+
+ # Django
+ 'django.contrib.auth.context_processors.auth',
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.i18n',
+ 'django.template.context_processors.media',
+ 'django.template.context_processors.static',
+ 'django.template.context_processors.tz',
+ 'django.contrib.messages.context_processors.messages',
+
+ # Django mobile
+ 'django_mobile.context_processors.flavour',
+
+ # Breadcrumbs
+ 'django.template.context_processors.request'
+ ],
+ 'loaders': [
+ # Django mobile
+ 'django_mobile.loader.Loader',
+
+ 'django.template.loaders.filesystem.Loader',
+ 'django.template.loaders.app_directories.Loader',
+ ],
+ 'debug': False
+ },
+ },
+]
+
+# Store the user messages in the session
+MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
+
+STATICFILES_FINDERS = (
+ 'django.contrib.staticfiles.finders.FileSystemFinder',
+ 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
+ # added BowerFinder to list of static file finders
+ 'djangobower.finders.BowerFinder',
+
+ # Django compressor
+ 'compressor.finders.CompressorFinder',
+)
+
+
+#
+# Email
+#
+EMAIL_SUBJECT_PREFIX = '[wger] '
+# EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
+
+
+#
+# Login
+#
+LOGIN_URL = '/user/login'
+LOGIN_REDIRECT_URL = '/'
+
+
+#
+# Internationalization
+#
+USE_TZ = True
+USE_I18N = True
+USE_L10N = True
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# On Unix systems, a value of None will cause Django to use the same
+# timezone as the operating system.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = None
+
+# Restrict the available languages
+LANGUAGES = (
+ ('en', 'English'),
+ ('de', 'German'),
+ ('bg', 'Bulgarian'),
+ ('es', 'Spanish'),
+ ('ru', 'Russian'),
+ ('nl', 'Dutch'),
+ ('pt', 'Portuguese'),
+ ('el', 'Greek'),
+ ('cs', 'Czech'),
+ ('sv', 'Swedish'),
+ ('no', 'Norwegian'),
+)
+
+# Default language code for this installation.
+LANGUAGE_CODE = 'en'
+
+# All translation files are in one place
+LOCALE_PATHS = (
+ os.path.join(SITE_ROOT, 'locale'),
+)
+
+FLAVOURS_STORAGE_BACKEND = 'session'
+
+
+#
+# Logging
+# See http://docs.python.org/library/logging.config.html
+#
+LOGGING = {
+ 'version': 1,
+ 'disable_existing_loggers': False,
+ 'formatters': {
+ 'simple': {
+ 'format': '%(levelname)s %(asctime)s %(module)s %(message)s'
+ },
+ },
+ 'handlers': {
+ 'console': {
+ 'level': 'DEBUG',
+ 'class': 'logging.StreamHandler',
+ 'formatter': 'simple'
+ },
+ },
+ 'loggers': {
+ 'wger': {
+ 'handlers': ['console'],
+ 'level': 'DEBUG',
+ }
+ }
+}
+
+
+#
+# ReCaptcha
+#
+RECAPTCHA_USE_SSL = True
+
+
+#
+# Cache
+#
+CACHES = {
+ 'default': {
+ 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
+ 'LOCATION': 'wger-cache',
+ 'TIMEOUT': 30 * 24 * 60 * 60, # Cache for a month
+ }
+}
+
+
+#
+# Easy thumbnails
+#
+THUMBNAIL_ALIASES = {
+ '': {
+ 'micro': {'size': (30, 30)},
+ 'micro_cropped': {'size': (30, 30), 'crop': 'smart'},
+
+ 'thumbnail': {'size': (80, 80)},
+ 'thumbnail_cropped': {'size': (80, 80), 'crop': 'smart'},
+
+ 'small': {'size': (200, 200)},
+ 'small_cropped': {'size': (200, 200), 'crop': 'smart'},
+
+ 'medium': {'size': (400, 400)},
+ 'medium_cropped': {'size': (400, 400), 'crop': 'smart'},
+
+ 'large': {'size': (800, 800), 'quality': 90},
+ 'large_cropped': {'size': (800, 800), 'crop': 'smart', 'quality': 90},
+ },
+}
+
+
+#
+# Django compressor
+#
+STATIC_ROOT = ''
+STATIC_URL = '/static/'
+
+# The default is not DEBUG, override if needed
+# COMPRESS_ENABLED = True
+COMPRESS_CSS_FILTERS = (
+ 'compressor.filters.css_default.CssAbsoluteFilter',
+ 'compressor.filters.cssmin.rCSSMinFilter'
+)
+COMPRESS_ROOT = STATIC_ROOT
+
+# BOWER binary
+if sys.platform.startswith('win32'):
+ BOWER_PATH = os.path.join('node_modules', '.bin', 'bower.cmd')
+else:
+ BOWER_PATH = os.path.join('node_modules', '.bin', 'bower')
+
+#
+# Django Rest Framework
+#
+REST_FRAMEWORK = {
+ 'DEFAULT_PERMISSION_CLASSES': ('wger.utils.permissions.WgerPermission',),
+ 'PAGINATE_BY': 20,
+ 'PAGINATE_BY_PARAM': 'limit', # Allow client to override, using `?limit=xxx`.
+ 'TEST_REQUEST_DEFAULT_FORMAT': 'json',
+ 'DEFAULT_AUTHENTICATION_CLASSES': (
+ 'rest_framework.authentication.SessionAuthentication',
+ 'rest_framework.authentication.TokenAuthentication',
+ ),
+ 'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',
+ 'rest_framework.filters.OrderingFilter',)
+}
+
+
+#
+# CORS headers: allow all hosts to access the API
+#
+CORS_ORIGIN_ALLOW_ALL = True
+CORS_URLS_REGEX = r'^/api/.*$'
+
+#
+# Ignore these URLs if they cause 404
+#
+IGNORABLE_404_URLS = (
+ re.compile(r'^/favicon\.ico$'),
+)
+
+#
+# Application specific configuration options
+#
+# Consult docs/settings.rst for more information
+#
+WGER_SETTINGS = {
+ 'USE_RECAPTCHA': False,
+ 'REMOVE_WHITESPACE': False,
+ 'ALLOW_REGISTRATION': True,
+ 'ALLOW_GUEST_USERS': True,
+ 'EMAIL_FROM': 'wger Workout Manager ',
+ 'TWITTER': False
+}
diff --git a/wger/utils/language.py b/wger/utils/language.py
index f8975d5..79078c4 100644
--- a/wger/utils/language.py
+++ b/wger/utils/language.py
@@ -51,7 +51,6 @@ def load_language(language_code=None):
try:
language, is_created = Language.objects.get_or_create(short_name=used_language)
# language = Language.objects.get(short_name=used_language)
-
except ObjectDoesNotExist:
# No luck, load english as our fall-back language
language = Language.objects.get(short_name="en")
diff --git a/workout.txt b/workout.txt
new file mode 100644
index 0000000..07de27d
--- /dev/null
+++ b/workout.txt
@@ -0,0 +1 @@
+{"workouts":
\ No newline at end of file
diff --git a/workouts.txt b/workouts.txt
new file mode 100644
index 0000000..e69de29