Skip to content

Commit

Permalink
Merge pull request #23 from andela/ft-export-import-workout-159356725
Browse files Browse the repository at this point in the history
Ft export import workout 159356725
  • Loading branch information
oagutu committed Aug 23, 2018
2 parents 51c6dd4 + 9ebda48 commit 107e7b8
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 43 deletions.
72 changes: 52 additions & 20 deletions wger/manager/templates/workout/overview.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,63 @@


{% block content %}
<div class="list-group">
{% for workout in workouts %}
<a href="{{ workout.get_absolute_url }}" class="list-group-item">
<span class="glyphicon glyphicon-chevron-right pull-right"></span>
<div class="list-group">
{% for workout in workouts %}
<a href="{{ workout.get_absolute_url }}" class="list-group-item">
<span class="glyphicon glyphicon-chevron-right pull-right"></span>

{% if workout == current_workout %}
<span class="badge">
{% if workout == current_workout %}
<span class="badge">
<em>{% trans "active" %}</em>
</span>
{% endif %}

<h4 class="list-group-item-heading">{{ workout }}</h4>
<p class="list-group-item-text">{{ workout.creation_date }}</p>
</a>
{% empty %}
<a href="{% url 'manager:workout:add' %}" class="list-group-item">
{% trans "No workouts found." %}<br>{% trans "Add one now." %}
</a>
{% endfor %}
</div>
{% endif %}

<h4 class="list-group-item-heading">{{ workout }}</h4>
<p class="list-group-item-text">{{ workout.creation_date }}</p>
</a>
{% empty %}
<a href="{% url 'manager:workout:add' %}" class="list-group-item">
{% trans "No workouts found." %}<br>{% trans "Add one now." %}
</a>
{% endfor %}
</div>
{% endblock %}


{% block options %}
<a href="{% url 'manager:workout:add' %}" class="btn btn-success btn-sm">
{% trans "Add workout" %}
</a>
<div class="container-fluid">
<a href="{% url 'manager:workout:add' %}" class="btn btn-success btn-sm">
{% trans "Add workout" %}
</a>
<a href="{% url 'manager:workout:workout_export'%}" class="btn btn-success btn-sm">
{% trans "Export workouts" %}
</a>
<a href="#" data-toggle="modal" data-target="#importModal" class="btn btn-success btn-sm">
{% trans "Import workouts" %}
</a>
<div id="importModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Import workouts (json)</h4>
</div>
<div class="modal-body">
<form action="{% url 'manager:workout:workout_import' %}" method="post"
enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group row">
<div class="col-sm-8">
<input type="file" required class="form-control-file" name="csv_file" accept=".json"/>
</div>
</div>
<input type="submit" value="Import" class="btn btn-success btn-sm"/>
</form>
</div>
</div>
</div>
</div>

</div>

{% endblock %}
28 changes: 28 additions & 0 deletions wger/manager/tests/test_workout.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,31 @@ class WorkoutApiTestCase(api_base_test.ApiBaseResourceTestCase):
private_resource = True
special_endpoints = ('canonical_representation',)
data = {'comment': 'A new comment'}


class WorkoutExportTestCase(WorkoutManagerTestCase):
'''
Tests the workout export
'''

def get_workout_overview(self):
'''
Test workout export endpoint
'''
response = self.client.get(reverse('manager:workout:workout_export'))
self.assertEqual(response.status_code, 200)
self.assertEquals(response.get('Content-Disposition'),
"attachment; filename=workouts.json")


class WorkoutImportTestCase(WorkoutManagerTestCase):
'''
Tests the workout import
'''

def get_workout_overview(self):
'''
Test workout import endpoint
'''
response = self.client.post(reverse('manager:workout:workout_import'))
self.assertEqual(response.status_code, 200)
37 changes: 19 additions & 18 deletions wger/manager/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
name='delete')
]


# sub patterns for workouts
patterns_workout = [
url(r'^overview$',
Expand All @@ -52,6 +51,12 @@
url(r'^add$',
workout.add,
name='add'),
url(r'^workout_export$',
workout.workout_export,
name='workout_export'),
url(r'^workout_import$',
workout.workout_import,
name='workout_import'),
url(r'^(?P<pk>\d+)/copy/$',
workout.copy_workout,
name='copy'),
Expand Down Expand Up @@ -85,9 +90,10 @@
url(r'^(?P<pk>\d+)/ical$',
ical.export,
name='ical'),
url(r'^(?P<id>\d+)/pdf/log/(?P<images>[01]+)/(?P<comments>[01]+)/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})$',
url(
r'^(?P<id>\d+)/pdf/log/(?P<images>[01]+)/(?P<comments>[01]+)/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})$',
pdf.workout_log,
name='pdf-log'), #JS!
name='pdf-log'), # JS!
url(r'^(?P<id>\d+)/pdf/log/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})$',
pdf.workout_log,
name='pdf-log'),
Expand All @@ -97,9 +103,10 @@
url(r'^(?P<id>\d+)/pdf/log$',
pdf.workout_log,
name='pdf-log'),
url(r'^(?P<id>\d+)/pdf/table/(?P<images>[01]+)/(?P<comments>[01]+)/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})$',
url(
r'^(?P<id>\d+)/pdf/table/(?P<images>[01]+)/(?P<comments>[01]+)/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})$',
pdf.workout_view,
name='pdf-table'), #JS!
name='pdf-table'), # JS!
url(r'^(?P<id>\d+)/pdf/table/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})$',
pdf.workout_view,
name='pdf-table'),
Expand All @@ -114,7 +121,6 @@
name='timer'),
]


# sub patterns for workout sessions
patterns_session = [
url(r'^(?P<workout_pk>\d+)/add/(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})$',
Expand All @@ -128,7 +134,6 @@
name='delete'),
]


# sub patterns for workout days
patterns_day = [
url(r'^(?P<pk>\d+)/edit/$',
Expand Down Expand Up @@ -164,7 +169,6 @@
name='edit'),
]


# sub patterns for schedules
patterns_schedule = [
url(r'^overview$',
Expand Down Expand Up @@ -220,7 +224,6 @@
name='pdf-table'),
]


# sub patterns for schedule steps
patterns_step = [
url(r'^(?P<schedule_pk>\d+)/step/add$',
Expand All @@ -234,14 +237,12 @@
name='delete'),
]



urlpatterns = [
url(r'^', include(patterns_workout, namespace="workout")),
url(r'^log/', include(patterns_log, namespace="log")),
url(r'^day/', include(patterns_day, namespace="day")),
url(r'^set/', include(patterns_set, namespace="set")),
url(r'^session/', include(patterns_session, namespace="session")),
url(r'^schedule/', include(patterns_schedule, namespace="schedule")),
url(r'^schedule/step/', include(patterns_step, namespace="step")),
url(r'^', include(patterns_workout, namespace="workout")),
url(r'^log/', include(patterns_log, namespace="log")),
url(r'^day/', include(patterns_day, namespace="day")),
url(r'^set/', include(patterns_set, namespace="set")),
url(r'^session/', include(patterns_session, namespace="session")),
url(r'^schedule/', include(patterns_schedule, namespace="schedule")),
url(r'^schedule/step/', include(patterns_step, namespace="step")),
]
83 changes: 78 additions & 5 deletions wger/manager/views/workout.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,31 @@
import logging
import uuid
import datetime
import json
from django.contrib import messages

from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect, HttpResponseForbidden
from django.http import HttpResponseRedirect, HttpResponseForbidden, HttpResponse, JsonResponse
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.mixins import LoginRequiredMixin
from django.contrib.auth.decorators import login_required
from django.views.generic import DeleteView, UpdateView

from wger.exercises.models import Exercise
from wger.core.models import (
RepetitionUnit,
WeightUnit
WeightUnit,
DaysOfWeek
)
from wger.manager.models import (
Workout,
WorkoutSession,
WorkoutLog,
Schedule,
Day
Day,
Set
)
from wger.manager.forms import (
WorkoutForm,
Expand All @@ -49,7 +54,6 @@
)
from wger.utils.helpers import make_token


logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -215,6 +219,75 @@ def add(request):
return HttpResponseRedirect(workout.get_absolute_url())


@login_required
def workout_export(request):
# Filter all the workouts of the user
workouts = Workout.objects.filter(user=request.user)
# Create a dict to store json data exported
get_json_data = {}
for workout in workouts:
# Loop through each workout in the listed items
workout_data = {}
workout_data['creation_date'] = str(workout.creation_date)
workout_data['comment'] = workout.comment
days = Day.objects.filter(training=workout.id)
# loop through all items in the days received of each workout
for day in days:
# Store the data received in workout_data dictionary
workout_days = [record.day_of_week for record in day.day.all()]
workout_data['description'] = day.description
workout_data['workout_days'] = workout_days
sets = Set.objects.filter(exerciseday=day.id)
for each_set in sets:
# Also save the exercises received in workout_data dictionary
exercises = [exercise.name for exercise in each_set.exercises.all()]
workout_data['exercises'] = exercises
# Add all the data in the json file to be exported in according to primary key
get_json_data[str(workout.pk)] = workout_data
# Get json response to download the file
data = JsonResponse(get_json_data)
response = HttpResponse(data, content_type='application/force-download')
response['Content-Disposition'] = 'attachment; filename="workouts.json"'
return response


@login_required
def workout_import(request):
if request.POST and request.FILES:
my_json_file = request.FILES['csv_file'].file
data = my_json_file.read()
# Load json data to workout after decoding
# Make sure that '' is replaced with ""
workouts = json.loads(data.decode('utf8').replace("'", '"'))
for workout in workouts:
# create workouts for the user
new_workout = Workout(
creation_date=workouts[workout]['creation_date'],
comment=workouts[workout]["comment"],
user=request.user)
new_workout.save()
# Check if workouts does not have dates
# If it does not exist, then create data
if 'workout_days' in workouts[workout]:
day = Day(training=new_workout, description=workouts[workout]["description"])
day.save()
for day_name in workouts[workout]["workout_days"]:
day.day.add(
DaysOfWeek.objects.filter(day_of_week=day_name).first()
)
# Create exercises if workouts have them
if 'exercises' in workouts[workout]:
workout_set = Set(exerciseday=day)
workout_set.save()
for exercise in workouts[workout]["exercises"]:
workout_set.exercises.add(
Exercise.objects.filter(name=exercise).first()
)
messages.success(request, _(
'Your workouts have been imported successfully.'))
return HttpResponseRedirect(reverse('manager:workout:overview'))


class WorkoutDeleteView(WgerDeleteMixin, LoginRequiredMixin, DeleteView):
'''
Generic view to delete a workout routine
Expand Down

0 comments on commit 107e7b8

Please sign in to comment.