Skip to content
Snippets Groups Projects
Commit f742d804 authored by Ole-Christian Bjerkeset's avatar Ole-Christian Bjerkeset
Browse files

Merge branch 'refactor/backend-workouts' into 'master'

Refactor/backend workouts

See merge request !6
parents afe079ec 6f23f39a
No related branches found
No related tags found
1 merge request!6Refactor/backend workouts
Pipeline #172308 passed
...@@ -5,4 +5,5 @@ backend/secfit/db.sqlite3 ...@@ -5,4 +5,5 @@ backend/secfit/db.sqlite3
backend/secfit/htmlcov/ backend/secfit/htmlcov/
backend/secfit/.coverage backend/secfit/.coverage
backend/secfit/.coveragerc backend/secfit/.coveragerc
.vscode
.idea .idea
...@@ -2,30 +2,12 @@ ...@@ -2,30 +2,12 @@
log workouts (Workout), which contain instances (ExerciseInstance) of various log workouts (Workout), which contain instances (ExerciseInstance) of various
type of exercises (Exercise). The user can also upload files (WorkoutFile) . type of exercises (Exercise). The user can also upload files (WorkoutFile) .
""" """
import os
from django.db import models from django.db import models
from django.core.files.storage import FileSystemStorage
from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
# Create your models here.
class OverwriteStorage(FileSystemStorage):
"""Filesystem storage for overwriting files. Currently unused."""
def get_available_name(self, name, max_length=None):
"""https://djangosnippets.org/snippets/976/
Returns a filename that's free on the target storage system, and
available for new content to be written to.
Args:
name (str): Name of the file
max_length (int, optional): Maximum length of a file name. Defaults to None.
"""
if self.exists(name):
os.remove(os.path.join(settings.MEDIA_ROOT, name))
# Create your models here.
class Workout(models.Model): class Workout(models.Model):
"""Django model for a workout that users can log. """Django model for a workout that users can log.
...@@ -48,24 +30,29 @@ class Workout(models.Model): ...@@ -48,24 +30,29 @@ class Workout(models.Model):
) )
# Visibility levels # Visibility levels
PUBLIC = "PU" # Visible to all authenticated users # Visible to all authenticated users
COACH = "CO" # Visible only to owner and their coach PUBLIC = "PU"
PRIVATE = "PR" # Visible only to owner # Visible only to owner and their coach
COACH = "CO"
# Visible only to owner
PRIVATE = "PR"
# Choices for visibility level
VISIBILITY_CHOICES = [ VISIBILITY_CHOICES = [
(PUBLIC, "Public"), (PUBLIC, "Public"),
(COACH, "Coach"), (COACH, "Coach"),
(PRIVATE, "Private"), (PRIVATE, "Private"),
] # Choices for visibility level ]
visibility = models.CharField( visibility = models.CharField(
max_length=2, choices=VISIBILITY_CHOICES, default=COACH max_length=2, choices=VISIBILITY_CHOICES, default=COACH
) )
class Meta: class Meta:
"""Orders the object by date descendingly"""
ordering = ["-date"] ordering = ["-date"]
def __str__(self): def __str__(self):
return self.name return str(self.name)
class Exercise(models.Model): class Exercise(models.Model):
...@@ -90,7 +77,7 @@ class Exercise(models.Model): ...@@ -90,7 +77,7 @@ class Exercise(models.Model):
unit = models.CharField(max_length=50) unit = models.CharField(max_length=50)
def __str__(self): def __str__(self):
return self.name return str(self.name)
class ExerciseInstance(models.Model): class ExerciseInstance(models.Model):
...@@ -139,7 +126,8 @@ class WorkoutFile(models.Model): ...@@ -139,7 +126,8 @@ class WorkoutFile(models.Model):
file: The actual file that's being uploaded file: The actual file that's being uploaded
""" """
workout = models.ForeignKey(Workout, on_delete=models.CASCADE, related_name="files") workout = models.ForeignKey(
Workout, on_delete=models.CASCADE, related_name="files")
owner = models.ForeignKey( owner = models.ForeignKey(
get_user_model(), on_delete=models.CASCADE, related_name="workout_files" get_user_model(), on_delete=models.CASCADE, related_name="workout_files"
) )
...@@ -156,4 +144,4 @@ class RememberMe(models.Model): ...@@ -156,4 +144,4 @@ class RememberMe(models.Model):
remember_me = models.CharField(max_length=500) remember_me = models.CharField(max_length=500)
def __str__(self): def __str__(self):
return self.remember_me return str(self.remember_me)
...@@ -19,6 +19,7 @@ class ExerciseInstanceSerializer(serializers.HyperlinkedModelSerializer): ...@@ -19,6 +19,7 @@ class ExerciseInstanceSerializer(serializers.HyperlinkedModelSerializer):
) )
class Meta: class Meta:
"""serialized fields for the model ExerciseInstance"""
model = ExerciseInstance model = ExerciseInstance
fields = ["url", "id", "exercise", "sets", "number", "workout"] fields = ["url", "id", "exercise", "sets", "number", "workout"]
...@@ -39,6 +40,7 @@ class WorkoutFileSerializer(serializers.HyperlinkedModelSerializer): ...@@ -39,6 +40,7 @@ class WorkoutFileSerializer(serializers.HyperlinkedModelSerializer):
) )
class Meta: class Meta:
"""serialized fields for the model WorkoutFile"""
model = WorkoutFile model = WorkoutFile
fields = ["url", "id", "owner", "file", "workout"] fields = ["url", "id", "owner", "file", "workout"]
...@@ -66,6 +68,7 @@ class WorkoutSerializer(serializers.HyperlinkedModelSerializer): ...@@ -66,6 +68,7 @@ class WorkoutSerializer(serializers.HyperlinkedModelSerializer):
files = WorkoutFileSerializer(many=True, required=False) files = WorkoutFileSerializer(many=True, required=False)
class Meta: class Meta:
"""serialized fields for the Workout. Owner is read only and cant be modified"""
model = Workout model = Workout
fields = [ fields = [
"url", "url",
...@@ -101,10 +104,12 @@ class WorkoutSerializer(serializers.HyperlinkedModelSerializer): ...@@ -101,10 +104,12 @@ class WorkoutSerializer(serializers.HyperlinkedModelSerializer):
workout = Workout.objects.create(**validated_data) workout = Workout.objects.create(**validated_data)
for exercise_instance_data in exercise_instances_data: for exercise_instance_data in exercise_instances_data:
ExerciseInstance.objects.create(workout=workout, **exercise_instance_data) ExerciseInstance.objects.create(
workout=workout, **exercise_instance_data)
for file_data in files_data: for file_data in files_data:
WorkoutFile.objects.create( WorkoutFile.objects.create(
workout=workout, owner=workout.owner, file=file_data.get("file") workout=workout, owner=workout.owner, file=file_data.get(
"file")
) )
return workout return workout
...@@ -122,67 +127,17 @@ class WorkoutSerializer(serializers.HyperlinkedModelSerializer): ...@@ -122,67 +127,17 @@ class WorkoutSerializer(serializers.HyperlinkedModelSerializer):
Returns: Returns:
Workout: Updated Workout instance Workout: Updated Workout instance
""" """
exercise_instances_data = validated_data.pop("exercise_instances")
exercise_instances = instance.exercise_instances
instance.name = validated_data.get("name", instance.name) instance.name = validated_data.get("name", instance.name)
instance.notes = validated_data.get("notes", instance.notes) instance.notes = validated_data.get("notes", instance.notes)
instance.visibility = validated_data.get("visibility", instance.visibility) instance.visibility = validated_data.get(
"visibility", instance.visibility)
instance.date = validated_data.get("date", instance.date) instance.date = validated_data.get("date", instance.date)
instance.save() instance.save()
# Handle ExerciseInstances handle_exercise_instance(validated_data, instance)
# This updates existing exercise instances without adding or deleting object. handle_workout_files(validated_data, instance)
# zip() will yield n 2-tuples, where n is
# min(len(exercise_instance), len(exercise_instance_data))
for exercise_instance, exercise_instance_data in zip(
exercise_instances.all(), exercise_instances_data
):
exercise_instance.exercise = exercise_instance_data.get(
"exercise", exercise_instance.exercise
)
exercise_instance.number = exercise_instance_data.get(
"number", exercise_instance.number
)
exercise_instance.sets = exercise_instance_data.get(
"sets", exercise_instance.sets
)
exercise_instance.save()
# If new exercise instances have been added to the workout, then create them
if len(exercise_instances_data) > len(exercise_instances.all()):
for i in range(len(exercise_instances.all()), len(exercise_instances_data)):
exercise_instance_data = exercise_instances_data[i]
ExerciseInstance.objects.create(
workout=instance, **exercise_instance_data
)
# Else if exercise instances have been removed from the workout, then delete them
elif len(exercise_instances_data) < len(exercise_instances.all()):
for i in range(len(exercise_instances_data), len(exercise_instances.all())):
exercise_instances.all()[i].delete()
# Handle WorkoutFiles
if "files" in validated_data:
files_data = validated_data.pop("files")
files = instance.files
for file, file_data in zip(files.all(), files_data):
file.file = file_data.get("file", file.file)
# If new files have been added, creating new WorkoutFiles
if len(files_data) > len(files.all()):
for i in range(len(files.all()), len(files_data)):
WorkoutFile.objects.create(
workout=instance,
owner=instance.owner,
file=files_data[i].get("file"),
)
# Else if files have been removed, delete WorkoutFiles
elif len(files_data) < len(files.all()):
for i in range(len(files_data), len(files.all())):
files.all()[i].delete()
return instance return instance
...@@ -198,6 +153,64 @@ class WorkoutSerializer(serializers.HyperlinkedModelSerializer): ...@@ -198,6 +153,64 @@ class WorkoutSerializer(serializers.HyperlinkedModelSerializer):
return obj.owner.username return obj.owner.username
def handle_exercise_instance(validated_data, instance):
"""This updates existing exercise instances without adding or deleting object.
zip() will yield n 2-tuples, where n is
min(len(exercise_instance), len(exercise_instance_data))
"""
exercise_instances_data = validated_data.pop("exercise_instances")
exercise_instances = instance.exercise_instances
for exercise_instance, exercise_instance_data in zip(
exercise_instances.all(), exercise_instances_data
):
exercise_instance.exercise = exercise_instance_data.get(
"exercise", exercise_instance.exercise
)
exercise_instance.number = exercise_instance_data.get(
"number", exercise_instance.number
)
exercise_instance.sets = exercise_instance_data.get(
"sets", exercise_instance.sets
)
exercise_instance.save()
# If new exercise instances have been added to the workout, then create them
if len(exercise_instances_data) > len(exercise_instances.all()):
for i in range(len(exercise_instances.all()), len(exercise_instances_data)):
exercise_instance_data = exercise_instances_data[i]
ExerciseInstance.objects.create(
workout=instance, **exercise_instance_data
)
# Else if exercise instances have been removed from the workout, then delete them
elif len(exercise_instances_data) < len(exercise_instances.all()):
for i in range(len(exercise_instances_data), len(exercise_instances.all())):
exercise_instances.all()[i].delete()
def handle_workout_files(validated_data, instance):
"""Handles the updating of exercises in a workout instance."""
if "files" in validated_data:
files_data = validated_data.pop("files")
files = instance.files
for file, file_data in zip(files.all(), files_data):
file.file = file_data.get("file", file.file)
# If new files have been added, creating new WorkoutFiles
if len(files_data) > len(files.all()):
for i in range(len(files.all()), len(files_data)):
WorkoutFile.objects.create(
workout=instance,
owner=instance.owner,
file=files_data[i].get("file"),
)
# Else if files have been removed, delete WorkoutFiles
elif len(files_data) < len(files.all()):
for i in range(len(files_data), len(files.all())):
files.all()[i].delete()
class ExerciseSerializer(serializers.HyperlinkedModelSerializer): class ExerciseSerializer(serializers.HyperlinkedModelSerializer):
"""Serializer for an Exercise. Hyperlinks are used for relationships by default. """Serializer for an Exercise. Hyperlinks are used for relationships by default.
...@@ -212,8 +225,18 @@ class ExerciseSerializer(serializers.HyperlinkedModelSerializer): ...@@ -212,8 +225,18 @@ class ExerciseSerializer(serializers.HyperlinkedModelSerializer):
) )
class Meta: class Meta:
"""serialized fields for the model Exercise"""
model = Exercise model = Exercise
fields = ["url", "id", "name", "description", "duration", "calories", "muscleGroup", "unit", "instances"] fields = [
"url",
"id",
"name",
"description",
"duration",
"calories",
"muscleGroup",
"unit",
"instances"]
class RememberMeSerializer(serializers.HyperlinkedModelSerializer): class RememberMeSerializer(serializers.HyperlinkedModelSerializer):
...@@ -226,5 +249,6 @@ class RememberMeSerializer(serializers.HyperlinkedModelSerializer): ...@@ -226,5 +249,6 @@ class RememberMeSerializer(serializers.HyperlinkedModelSerializer):
""" """
class Meta: class Meta:
"""serialized fields for the model RememberMe"""
model = RememberMe model = RememberMe
fields = ["remember_me"] fields = ["remember_me"]
"""Contains views for the workouts application. These are mostly class-based views. """Contains views for the workouts application. These are mostly class-based views.
""" """
from rest_framework import generics, mixins import base64
from rest_framework import permissions import pickle
from collections import namedtuple
from rest_framework.parsers import ( from rest_framework import generics, mixins, permissions, filters
JSONParser, from rest_framework.parsers import JSONParser
)
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.reverse import reverse from rest_framework.reverse import reverse
from django.db.models import Q from django.db.models import Q
from rest_framework import filters from django.core.exceptions import PermissionDenied
from django.core.signing import Signer
from workouts.parsers import MultipartJsonParser from workouts.parsers import MultipartJsonParser
from workouts.permissions import ( from workouts.permissions import (
IsOwner, IsOwner,
...@@ -23,20 +23,19 @@ from workouts.permissions import ( ...@@ -23,20 +23,19 @@ from workouts.permissions import (
) )
from workouts.mixins import CreateListModelMixin from workouts.mixins import CreateListModelMixin
from workouts.models import Workout, Exercise, ExerciseInstance, WorkoutFile from workouts.models import Workout, Exercise, ExerciseInstance, WorkoutFile
from workouts.serializers import WorkoutSerializer, ExerciseSerializer from workouts.serializers import (
from workouts.serializers import RememberMeSerializer WorkoutSerializer,
from workouts.serializers import ExerciseInstanceSerializer, WorkoutFileSerializer ExerciseSerializer,
from django.core.exceptions import PermissionDenied RememberMeSerializer,
ExerciseInstanceSerializer,
WorkoutFileSerializer
)
from rest_framework_simplejwt.tokens import RefreshToken from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework.response import Response
import json
from collections import namedtuple
import base64, pickle
from django.core.signing import Signer
@api_view(["GET"]) @api_view(["GET"])
def api_root(request, format=None): def api_root(request, format=None):
"""The API root view"""
return Response( return Response(
{ {
"users": reverse("user-list", request=request, format=format), "users": reverse("user-list", request=request, format=format),
...@@ -54,13 +53,16 @@ def api_root(request, format=None): ...@@ -54,13 +53,16 @@ def api_root(request, format=None):
) )
# Allow users to save a persistent session in their browser
class RememberMe( class RememberMe(
mixins.ListModelMixin, mixins.ListModelMixin,
mixins.CreateModelMixin, mixins.CreateModelMixin,
mixins.DestroyModelMixin, mixins.DestroyModelMixin,
generics.GenericAPIView, generics.GenericAPIView,
): ):
"""Allow users to save a persistent session in their browser.
HTTP methods: GET, POST
"""
serializer_class = RememberMeSerializer serializer_class = RememberMeSerializer
...@@ -68,13 +70,13 @@ class RememberMe( ...@@ -68,13 +70,13 @@ class RememberMe(
if request.user.is_authenticated == False: if request.user.is_authenticated == False:
raise PermissionDenied raise PermissionDenied
else: else:
return Response({"remember_me": self.rememberme()}) return Response({"remember_me": self.remember_me()})
def post(self, request): def post(self, request):
cookieObject = namedtuple("Cookies", request.COOKIES.keys())( cookie_object = namedtuple("Cookies", request.COOKIES.keys())(
*request.COOKIES.values() *request.COOKIES.values()
) )
user = self.get_user(cookieObject) user = self.get_user(cookie_object)
refresh = RefreshToken.for_user(user) refresh = RefreshToken.for_user(user)
return Response( return Response(
{ {
...@@ -83,15 +85,15 @@ class RememberMe( ...@@ -83,15 +85,15 @@ class RememberMe(
} }
) )
def get_user(self, cookieObject): def get_user(self, cookie_object):
decode = base64.b64decode(cookieObject.remember_me) decode = base64.b64decode(cookie_object.remember_me)
user, sign = pickle.loads(decode) user, sign = pickle.loads(decode)
# Validate signature # Validate signature
if sign == self.sign_user(user): if sign == self.sign_user(user):
return user return user
def rememberme(self): def remember_me(self):
creds = [self.request.user, self.sign_user(str(self.request.user))] creds = [self.request.user, self.sign_user(str(self.request.user))]
return base64.b64encode(pickle.dumps(creds)) return base64.b64encode(pickle.dumps(creds))
...@@ -111,13 +113,15 @@ class WorkoutList( ...@@ -111,13 +113,15 @@ class WorkoutList(
""" """
serializer_class = WorkoutSerializer serializer_class = WorkoutSerializer
# User must be authenticated to create/view workouts
permission_classes = [ permission_classes = [
permissions.IsAuthenticated permissions.IsAuthenticated
] # User must be authenticated to create/view workouts ]
# For parsing JSON and Multi-part requests
parser_classes = [ parser_classes = [
MultipartJsonParser, MultipartJsonParser,
JSONParser, JSONParser,
] # For parsing JSON and Multi-part requests ]
filter_backends = [filters.OrderingFilter] filter_backends = [filters.OrderingFilter]
ordering_fields = ["name", "date", "owner__username"] ordering_fields = ["name", "date", "owner__username"]
...@@ -131,18 +135,18 @@ class WorkoutList( ...@@ -131,18 +135,18 @@ class WorkoutList(
serializer.save(owner=self.request.user) serializer.save(owner=self.request.user)
def get_queryset(self): def get_queryset(self):
qs = Workout.objects.none() queryset = Workout.objects.none()
if self.request.user: if self.request.user:
# A workout should be visible to the requesting user if any of the following hold: # A workout should be visible to the requesting user if any of the following hold:
# - The workout has public visibility # - The workout has public visibility
# - The owner of the workout is the requesting user # - The owner of the workout is the requesting user
# - The workout has coach visibility and the requesting user is the owner's coach # - The workout has coach visibility and the requesting user is the owner's coach
qs = Workout.objects.filter( queryset = Workout.objects.filter(
Q(visibility="PU") Q(visibility="PU")
| (Q(visibility="CO") & Q(owner__coach=self.request.user)) | (Q(visibility="CO") & Q(owner__coach=self.request.user))
).distinct() ).distinct()
return qs return queryset
class WorkoutDetail( class WorkoutDetail(
...@@ -228,7 +232,10 @@ class ExerciseInstanceList( ...@@ -228,7 +232,10 @@ class ExerciseInstanceList(
CreateListModelMixin, CreateListModelMixin,
generics.GenericAPIView, generics.GenericAPIView,
): ):
"""Class defining the web response for the creation""" """Class defining the web response for the creation
HTTP methods: GET, POST
"""
serializer_class = ExerciseInstanceSerializer serializer_class = ExerciseInstanceSerializer
permission_classes = [permissions.IsAuthenticated & IsOwnerOfWorkout] permission_classes = [permissions.IsAuthenticated & IsOwnerOfWorkout]
...@@ -259,6 +266,12 @@ class ExerciseInstanceDetail( ...@@ -259,6 +266,12 @@ class ExerciseInstanceDetail(
mixins.DestroyModelMixin, mixins.DestroyModelMixin,
generics.GenericAPIView, generics.GenericAPIView,
): ):
"""Class defining the web response for the modification, deletion and getting
exercise instance details.
HTTP methods: GET, PUT, PATCH, DELETE
"""
serializer_class = ExerciseInstanceSerializer serializer_class = ExerciseInstanceSerializer
permission_classes = [ permission_classes = [
permissions.IsAuthenticated permissions.IsAuthenticated
...@@ -287,6 +300,10 @@ class WorkoutFileList( ...@@ -287,6 +300,10 @@ class WorkoutFileList(
CreateListModelMixin, CreateListModelMixin,
generics.GenericAPIView, generics.GenericAPIView,
): ):
"""Class defining the web response for the getting and creating list for workout files.
HTTP methods: GET, POST
"""
queryset = WorkoutFile.objects.all() queryset = WorkoutFile.objects.all()
serializer_class = WorkoutFileSerializer serializer_class = WorkoutFileSerializer
...@@ -323,6 +340,10 @@ class WorkoutFileDetail( ...@@ -323,6 +340,10 @@ class WorkoutFileDetail(
mixins.DestroyModelMixin, mixins.DestroyModelMixin,
generics.GenericAPIView, generics.GenericAPIView,
): ):
"""Class defining the web response for the getting deleting workout file details.
HTTP methods: GET, POST
"""
queryset = WorkoutFile.objects.all() queryset = WorkoutFile.objects.all()
serializer_class = WorkoutFileSerializer serializer_class = WorkoutFileSerializer
......
...@@ -31,49 +31,57 @@ class MuscleGroup { ...@@ -31,49 +31,57 @@ class MuscleGroup {
} }
} }
function deleteFormData() {
setReadOnly(true, "#form-exercise");
okButton.className += " hide";
deleteButton.className += " hide";
cancelButton.className += " hide";
editButton.className = editButton.className.replace(" hide", "");
cancelButton.removeEventListener("click", handleCancelButtonDuringEdit);
oldFormData.delete("name");
oldFormData.delete("description");
oldFormData.delete("duration");
oldFormData.delete("calories");
oldFormData.delete("muscleGroup");
oldFormData.delete("unit");
}
function handleCancelButtonDuringEdit() { function handleCancelButtonDuringEdit() {
setReadOnly(true, "#form-exercise");
document.querySelector("select").setAttribute("disabled", "") document.querySelector("select").setAttribute("disabled", "")
okButton.className += " hide";
deleteButton.className += " hide";
cancelButton.className += " hide";
editButton.className = editButton.className.replace(" hide", "");
cancelButton.removeEventListener("click", handleCancelButtonDuringEdit);
let form = document.querySelector("#form-exercise"); let form = document.querySelector("#form-exercise");
if (oldFormData.has("name")) form.name.value = oldFormData.get("name"); if (oldFormData.has("name")) form.name.value = oldFormData.get("name");
if (oldFormData.has("description")) form.description.value = oldFormData.get("description"); if (oldFormData.has("description")) form.description.value = oldFormData.get("description");
if (oldFormData.has("duration")) form.duration.value = oldFormData.get("duration"); if (oldFormData.has("duration")) form.duration.value = oldFormData.get("duration");
if (oldFormData.has("calories")) form.calories.value = oldFormData.get("calories"); if (oldFormData.has("calories")) form.calories.value = oldFormData.get("calories");
if (oldFormData.has("muscleGroup")) form.muscleGroup.value = oldFormData.get("muscleGroup"); if (oldFormData.has("muscleGroup")) form.muscleGroup.value = oldFormData.get("muscleGroup");
if (oldFormData.has("unit")) form.unit.value = oldFormData.get("unit"); if (oldFormData.has("unit")) form.unit.value = oldFormData.get("unit");
oldFormData.delete("name");
oldFormData.delete("description");
oldFormData.delete("duration");
oldFormData.delete("calories");
oldFormData.delete("muscleGroup");
oldFormData.delete("unit");
deleteFormData();
} }
function handleCancelButtonDuringCreate() { function handleCancelButtonDuringCreate() {
window.location.replace("exercises.html"); window.location.replace("exercises.html");
} }
function addFormData(form) {
let formData = new FormData(form);
let selectedMuscleGroup = new MuscleGroup(formData.get("muscleGroup"));
let updatedMuscleGroup = selectedMuscleGroup.getMuscleGroupType()
return {"name": formData.get("name"),
"description": formData.get("description"),
"duration": formData.get("duration"),
"calories": formData.get("calories"),
"muscleGroup": updatedMuscleGroup ? updatedMuscleGroup : formData.get("muscleGroup"),
"unit": formData.get("unit")};
}
async function createExercise() { async function createExercise() {
document.querySelector("select").removeAttribute("disabled") document.querySelector("select").removeAttribute("disabled")
let form = document.querySelector("#form-exercise"); let form = document.querySelector("#form-exercise");
let formData = new FormData(form); let response = await sendRequest("POST", `${HOST}/api/exercises/`, addFormData(form));
let body = {"name": formData.get("name"),
"description": formData.get("description"),
"duration": formData.get("duration"),
"calories": formData.get("calories"),
"muscleGroup": formData.get("muscleGroup"),
"unit": formData.get("unit")};
let response = await sendRequest("POST", `${HOST}/api/exercises/`, body);
if (response.ok) { if (response.ok) {
window.location.replace("exercises.html"); window.location.replace("exercises.html");
...@@ -139,20 +147,10 @@ async function retrieveExercise(id) { ...@@ -139,20 +147,10 @@ async function retrieveExercise(id) {
async function updateExercise(id) { async function updateExercise(id) {
let form = document.querySelector("#form-exercise"); let form = document.querySelector("#form-exercise");
let formData = new FormData(form);
let muscleGroupSelector = document.querySelector("select") let muscleGroupSelector = document.querySelector("select")
muscleGroupSelector.removeAttribute("disabled") muscleGroupSelector.removeAttribute("disabled")
let selectedMuscleGroup = new MuscleGroup(formData.get("muscleGroup")); let response = await sendRequest("PUT", `${HOST}/api/exercises/${id}/`, addFormData(form));
let body = {"name": formData.get("name"),
"description": formData.get("description"),
"duration": formData.get("duration"),
"calories": formData.get("calories"),
"muscleGroup": selectedMuscleGroup.getMuscleGroupType(),
"unit": formData.get("unit")};
let response = await sendRequest("PUT", `${HOST}/api/exercises/${id}/`, body);
if (!response.ok) { if (!response.ok) {
let data = await response.json(); let data = await response.json();
...@@ -160,22 +158,7 @@ async function updateExercise(id) { ...@@ -160,22 +158,7 @@ async function updateExercise(id) {
document.body.prepend(alert); document.body.prepend(alert);
} else { } else {
muscleGroupSelector.setAttribute("disabled", "") muscleGroupSelector.setAttribute("disabled", "")
// duplicate code from handleCancelButtonDuringEdit deleteFormData()
// you should refactor this
setReadOnly(true, "#form-exercise");
okButton.className += " hide";
deleteButton.className += " hide";
cancelButton.className += " hide";
editButton.className = editButton.className.replace(" hide", "");
cancelButton.removeEventListener("click", handleCancelButtonDuringEdit);
oldFormData.delete("name");
oldFormData.delete("description");
oldFormData.delete("duration");
oldFormData.delete("calories");
oldFormData.delete("muscleGroup");
oldFormData.delete("unit");
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment