diff --git a/backend/secfit/workouts/models.py b/backend/secfit/workouts/models.py index 0f6214f2d9919d17fe68e93416a183a52209bda6..f8c0c3da0ced2482915e36d3c8c3adf6010f00ca 100644 --- a/backend/secfit/workouts/models.py +++ b/backend/secfit/workouts/models.py @@ -92,6 +92,28 @@ class Exercise(models.Model): def __str__(self): return self.name +class Goal(models.Model): + """Django model for an exercise type that users can create. + + Each exercise instance must have an exercise type, e.g., Pushups, Crunches, or Lunges. + + Attributes: + name: Name of the exercise type + description: Description of the exercise type + duration: Duration of one unit of the exercise + calories: Calories spent per minute + muscleGroup: What major muscle group is used in the exercise + unit: Name of the unit for the exercise type (e.g., reps, seconds) + """ + + name = models.CharField(max_length=100) + description = models.TextField() + date = models.DateTimeField() + exercise = models.TextField() + + def __str__(self): + return self.name + class ExerciseInstance(models.Model): """Django model for an instance of an exercise. diff --git a/backend/secfit/workouts/serializers.py b/backend/secfit/workouts/serializers.py index 6abbe31ffd71c5e9cbba140e34a03176b127a4bf..b21342d0102c8dd857208351b0e528202b8207dd 100644 --- a/backend/secfit/workouts/serializers.py +++ b/backend/secfit/workouts/serializers.py @@ -2,7 +2,7 @@ """ from rest_framework import serializers from rest_framework.serializers import HyperlinkedRelatedField -from workouts.models import Workout, Exercise, ExerciseInstance, WorkoutFile, RememberMe +from workouts.models import Workout, Exercise, ExerciseInstance, Goal, WorkoutFile, RememberMe class ExerciseInstanceSerializer(serializers.HyperlinkedModelSerializer): @@ -215,6 +215,21 @@ class ExerciseSerializer(serializers.HyperlinkedModelSerializer): model = Exercise fields = ["url", "id", "name", "description", "duration", "calories", "muscleGroup", "unit", "instances"] +class GoalSerializer(serializers.HyperlinkedModelSerializer): + """Serializer for an Exercise. Hyperlinks are used for relationships by default. + + Serialized fields: url, id, name, description, duration, calories, muscle group, unit, instances + + Attributes: + instances: Associated exercise instances with this Exercise type. Hyperlinks. + """ + + + + class Meta: + model = Goal + fields = ["id", "name", "description", "date", "exercise"] + class RememberMeSerializer(serializers.HyperlinkedModelSerializer): """Serializer for an RememberMe. Hyperlinks are used for relationships by default. diff --git a/backend/secfit/workouts/urls.py b/backend/secfit/workouts/urls.py index 7c46a3f1ff311edc25dd455bb85780c1a1644738..a58f81843ae0504442f7fbed4991dec9f423c9fd 100644 --- a/backend/secfit/workouts/urls.py +++ b/backend/secfit/workouts/urls.py @@ -16,6 +16,7 @@ urlpatterns = format_suffix_patterns( views.WorkoutDetail.as_view(), name="workout-detail", ), + path("api/goal/", views.GoalList.as_view(), name="goal-list"), path("api/exercises/", views.ExerciseList.as_view(), name="exercise-list"), path( "api/exercises/<int:pk>/", diff --git a/backend/secfit/workouts/views.py b/backend/secfit/workouts/views.py index efddf40454376b23d233f9fe2cecaf9da43fddb8..db217e00e7a9936bff7827b4b8a63cb7fb022219 100644 --- a/backend/secfit/workouts/views.py +++ b/backend/secfit/workouts/views.py @@ -22,8 +22,8 @@ from workouts.permissions import ( IsWorkoutPublic, ) from workouts.mixins import CreateListModelMixin -from workouts.models import Workout, Exercise, ExerciseInstance, WorkoutFile -from workouts.serializers import WorkoutSerializer, ExerciseSerializer +from workouts.models import Workout, Exercise, ExerciseInstance, Goal, WorkoutFile +from workouts.serializers import WorkoutSerializer, ExerciseSerializer, GoalSerializer from workouts.serializers import RememberMeSerializer from workouts.serializers import ExerciseInstanceSerializer, WorkoutFileSerializer from django.core.exceptions import PermissionDenied @@ -41,6 +41,7 @@ def api_root(request, format=None): { "users": reverse("user-list", request=request, format=format), "workouts": reverse("workout-list", request=request, format=format), + "goals": reverse("goal-list", request=request, format=format), "exercises": reverse("exercise-list", request=request, format=format), "exercise-instances": reverse( "exercise-instance-list", request=request, format=format @@ -221,6 +222,53 @@ class ExerciseDetail( def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs) +class GoalList( + mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView +): + """Class defining the web response for the creation of an Exercise, or + a list of Exercises. + + HTTP methods: GET, POST + """ + + queryset = Goal.objects.all() + serializer_class = GoalSerializer + permission_classes = [permissions.IsAuthenticated] + + def get(self, request, *args, **kwargs): + return self.list(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + return self.create(request, *args, **kwargs) + + +class GoalDetail( + mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + generics.GenericAPIView, +): + """Class defining the web response for the details of an individual Exercise. + + HTTP methods: GET, PUT, PATCH, DELETE + """ + + queryset = Goal.objects.all() + serializer_class = GoalSerializer + permission_classes = [permissions.IsAuthenticated] + + def get(self, request, *args, **kwargs): + return self.retrieve(request, *args, **kwargs) + + def put(self, request, *args, **kwargs): + return self.update(request, *args, **kwargs) + + def patch(self, request, *args, **kwargs): + return self.partial_update(request, *args, **kwargs) + + def delete(self, request, *args, **kwargs): + return self.destroy(request, *args, **kwargs) + class ExerciseInstanceList( mixins.ListModelMixin, diff --git a/frontend/www/goal.html b/frontend/www/goal.html index eb439d4f73b51a67f9755ac77dfc5b9544ef6f63..db8c6534288d4e62543e0f3f4b145a81d1411ee4 100644 --- a/frontend/www/goal.html +++ b/frontend/www/goal.html @@ -37,7 +37,7 @@ <div class="col-lg-6"></div> <div class="col-lg-6"> <label for="inputMuscles" class="form-label">Connect to exercise</label> - <select class="form-select" id="exercise-content" name="muscleGroup" disabled="true"> + <select class="form-select" id="exercise-content" name="exercise" disabled="true"> </select> </div> <div class="col-lg-6"></div> diff --git a/frontend/www/scripts/goal.js b/frontend/www/scripts/goal.js index 3cfd9deb698276a78b4a13eb5214f55b82c8acd3..7b869187aaffee753eb68ace3af0a22b2c875376 100644 --- a/frontend/www/scripts/goal.js +++ b/frontend/www/scripts/goal.js @@ -63,25 +63,26 @@ function handleCancelButtonDuringCreate() { } async function createExercise() { - document.querySelector("select").removeAttribute("disabled") + let form = document.querySelector("#form-exercise"); let formData = new FormData(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")}; + "date": formData.get("date"), + "exercise": formData.get("exercise")}; - let response = await sendRequest("POST", `${HOST}/api/exercises/`, body); + console.log("HEELO", body) + + let response = await sendRequest("POST", `${HOST}/api/goal/`, body); + + if (response.ok) { + window.location.replace("goals.html"); + } else { + let data = await response.json(); + let alert = createAlert("Could not create new goal!", data); + document.body.prepend(alert); + } - if (response.ok) { - window.location.replace("exercises.html"); - } else { - let data = await response.json(); - let alert = createAlert("Could not create new exercise!", data); - document.body.prepend(alert); - } } function handleEditExerciseButtonClick() { diff --git a/frontend/www/scripts/goals.js b/frontend/www/scripts/goals.js index 9a3ab387979bb6b6d341a9ff300f858e1ec6b932..b7304e62b7457ce80b8f0a9e001dd462fc9cf54a 100644 --- a/frontend/www/scripts/goals.js +++ b/frontend/www/scripts/goals.js @@ -31,11 +31,26 @@ function createExercise() { window.location.replace("goal.html"); } +async function init() { + let response = await sendRequest("GET", `${HOST}/api/goal/`); + + if (response.ok) { + let data = await response.json(); + data.results.map((goal) => {console.log(goal)}); + }else{ + console.log("ERROR") + } + + return response; +} + + window.addEventListener("DOMContentLoaded", async () => { let createButton = document.querySelector("#btn-create-goal"); createButton.addEventListener("click", createExercise); let response = await fetchExerciseTypes(); + await init(); if (!response.ok) { let data = await response.json();