Skip to content
Snippets Groups Projects
Commit 78845177 authored by Tobias Ørstad's avatar Tobias Ørstad
Browse files

Add view for accessing leaderboard scores

parent 6ef52866
No related branches found
No related tags found
3 merge requests!5Ad ci/cs setup,!4Dev,!1Leaderboards
......@@ -28,10 +28,10 @@ urlpatterns = format_suffix_patterns(
name="exercise-instance-list",
),
path(
"api/leaderboards/",
"api/leaderboards/<int:pk>/",
views.Leaderboards.as_view(),
name="leaderboards",
)
),
path(
"api/exercise-instances/<int:pk>/",
views.ExerciseInstanceDetail.as_view(),
......
......@@ -6,10 +6,11 @@ from rest_framework import permissions
from rest_framework.parsers import (
JSONParser,
)
import json
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse
from django.db.models import Q
from django.db.models import Q, Sum, F, IntegerField
from rest_framework import filters
from workouts.parsers import MultipartJsonParser
from workouts.permissions import (
......@@ -209,11 +210,6 @@ class ExerciseDetail(
permission_classes = [permissions.IsAuthenticated]
def get(self, request, *args, **kwargs):
print("heiheihei")
print(request.data)
print(request.query_params)
print(request.GET)
print(request.path)
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
......@@ -232,13 +228,41 @@ class Leaderboards(
generics.GenericAPIView,
):
permission_classes = [permissions.IsAuthenticated]
def get(self, request, *args, **kwargs):
path = request.path
exercise_id = path.split("/")[-1]
print(exercise_id)
#ExerciseInstance.objects.filter(Q(exercise__pk=1) & Q(workout__visibility='PU')).values('workout__owner__pk').annotate(amount=Sum(F("sets") * F("number"), output_field=IntegerField()))
path = self.request.path
e_id = path.split("/")[-2]
return {"hei":"Haakon"}
if self.request.user:
leaderboardNumbers = ExerciseInstance.objects.filter(Q(exercise__pk=e_id) & Q(workout__visibility='PU')).values('workout__owner__pk').annotate(amount=Sum(F("sets") * F("number"), output_field=IntegerField())).order_by('-amount')
leaderboardResult = []
# Iterates through the top 5 entries in the leaderboard and formats it correctly
for i in range(0, min(5, len(leaderboardNumbers))):
leaderboardResult.append({"name": User.objects.get(pk=leaderboardNumbers[i]['workout__owner__pk']).username, "value": leaderboardNumbers[i]['amount']})
# Applies the rank to the leaderboard entry; if two or more users have the score they get the same rank
if i > 0 and leaderboardNumbers[i-1]["amount"] == leaderboardNumbers[i]["amount"]:
leaderboardResult[i]["rank"] = leaderboardResult[i-1]["rank"]
else:
leaderboardResult[i]["rank"] = i+1
# Finds the user in the leaderboard list. If the user is not in the leaderboard list,
# the user is automatically given a score of 0 and the worst rank
currentLoggedInUser = self.request.user
for j in range(0, len(leaderboardNumbers)):
if leaderboardNumbers[j]['workout__owner__pk'] == currentLoggedInUser.pk:
leaderboardResult.append({"name": currentLoggedInUser.username, "value": leaderboardNumbers[j]["amount"], "rank": j+1})
break
else:
leaderboardResult.append({"name": currentLoggedInUser.username, "value": 0, "rank": len(leaderboardNumbers) + 1})
return Response(json.dumps(leaderboardResult))
class ExerciseInstanceList(
......
......@@ -4,196 +4,207 @@ let deleteButton;
let editButton;
let oldFormData;
function handleCancelButtonDuringEdit() {
setReadOnly(true, "#form-exercise");
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");
if (oldFormData.has("name")) form.name.value = oldFormData.get("name");
if (oldFormData.has("description")) form.description.value = oldFormData.get("description");
if (oldFormData.has("unit")) form.unit.value = oldFormData.get("unit");
oldFormData.delete("name");
oldFormData.delete("description");
oldFormData.delete("unit");
setReadOnly(true, "#form-exercise");
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");
if (oldFormData.has("name")) form.name.value = oldFormData.get("name");
if (oldFormData.has("description"))
form.description.value = oldFormData.get("description");
if (oldFormData.has("unit")) form.unit.value = oldFormData.get("unit");
oldFormData.delete("name");
oldFormData.delete("description");
oldFormData.delete("unit");
}
function handleCancelButtonDuringCreate() {
window.location.replace("exercises.html");
window.location.replace("exercises.html");
}
async function createExercise() {
let form = document.querySelector("#form-exercise");
let formData = new FormData(form);
let body = {"name": formData.get("name"),
"description": formData.get("description"),
"unit": formData.get("unit")};
let response = await sendRequest("POST", `${HOST}/api/exercises/`, body);
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);
}
let form = document.querySelector("#form-exercise");
let formData = new FormData(form);
let body = {
name: formData.get("name"),
description: formData.get("description"),
unit: formData.get("unit"),
};
let response = await sendRequest("POST", `${HOST}/api/exercises/`, body);
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() {
setReadOnly(false, "#form-exercise");
setReadOnly(false, "#form-exercise");
editButton.className += " hide";
okButton.className = okButton.className.replace(" hide", "");
cancelButton.className = cancelButton.className.replace(" hide", "");
deleteButton.className = deleteButton.className.replace(" hide", "");
editButton.className += " hide";
okButton.className = okButton.className.replace(" hide", "");
cancelButton.className = cancelButton.className.replace(" hide", "");
deleteButton.className = deleteButton.className.replace(" hide", "");
cancelButton.addEventListener("click", handleCancelButtonDuringEdit);
cancelButton.addEventListener("click", handleCancelButtonDuringEdit);
let form = document.querySelector("#form-exercise");
oldFormData = new FormData(form);
let form = document.querySelector("#form-exercise");
oldFormData = new FormData(form);
}
async function deleteExercise(id) {
let response = await sendRequest("DELETE", `${HOST}/api/exercises/${id}/`);
if (!response.ok) {
let data = await response.json();
let alert = createAlert(`Could not delete exercise ${id}`, data);
document.body.prepend(alert);
} else {
window.location.replace("exercises.html");
}
let response = await sendRequest("DELETE", `${HOST}/api/exercises/${id}/`);
if (!response.ok) {
let data = await response.json();
let alert = createAlert(`Could not delete exercise ${id}`, data);
document.body.prepend(alert);
} else {
window.location.replace("exercises.html");
}
}
async function retrieveExercise(id) {
let response = await sendRequest("GET", `${HOST}/api/exercises/${id}/`);
console.log(response.ok);
if (!response.ok) {
let data = await response.json();
let alert = createAlert("Could not retrieve exercise data!", data);
document.body.prepend(alert);
} else {
let exerciseData = await response.json();
let form = document.querySelector("#form-exercise");
let formData = new FormData(form);
for (let key of formData.keys()) {
let selector = `input[name="${key}"], textarea[name="${key}"]`;
let input = form.querySelector(selector);
let newVal = exerciseData[key];
input.value = newVal;
}
let response = await sendRequest("GET", `${HOST}/api/exercises/${id}/`);
console.log(response.ok);
if (!response.ok) {
let data = await response.json();
let alert = createAlert("Could not retrieve exercise data!", data);
document.body.prepend(alert);
} else {
let exerciseData = await response.json();
let form = document.querySelector("#form-exercise");
let formData = new FormData(form);
for (let key of formData.keys()) {
let selector = `input[name="${key}"], textarea[name="${key}"]`;
let input = form.querySelector(selector);
let newVal = exerciseData[key];
input.value = newVal;
}
}
}
async function updateExercise(id) {
let form = document.querySelector("#form-exercise");
let formData = new FormData(form);
let body = {"name": formData.get("name"),
"description": formData.get("description"),
"unit": formData.get("unit")};
let response = await sendRequest("PUT", `${HOST}/api/exercises/${id}/`, body);
if (!response.ok) {
let data = await response.json();
let alert = createAlert(`Could not update exercise ${id}`, data);
document.body.prepend(alert);
} else {
// duplicate code from handleCancelButtonDuringEdit
// 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("unit");
}
let form = document.querySelector("#form-exercise");
let formData = new FormData(form);
let body = {
name: formData.get("name"),
description: formData.get("description"),
unit: formData.get("unit"),
};
let response = await sendRequest("PUT", `${HOST}/api/exercises/${id}/`, body);
if (!response.ok) {
let data = await response.json();
let alert = createAlert(`Could not update exercise ${id}`, data);
document.body.prepend(alert);
} else {
// duplicate code from handleCancelButtonDuringEdit
// 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("unit");
}
}
async function fetchLeaderBoards() {
//let response = await sendRequest("GET", `${HOST}/api/leaderboards/${id}`);
//Placeholder response and status:
let response = [{"name": "Mark", "value": 301, "rank": 1},
{"name": "Anton", "value": 245, "rank": 2},
{"name": "John", "value": 112, "rank": 3},
{"name": "Joe", "value": 84, "rank": 4},
{"name": "Larry", "value": 80, "rank": 5},
{"name": "Glaum", "value": 1, "rank": 85}];
response.ok = true;
if (response.ok) {
let table = document.getElementById("leaderboardstable");
let row, cell;
//The users own score will always be placed last in the JSON response
let userIndex = response.length - 1;
for (let i = 0; i < response.length-1; i++) {
row = table.insertRow();
cell = row.insertCell();
cell.textContent = response[i].rank;
cell = row.insertCell();
cell.textContent = response[i].name;
cell = row.insertCell();
cell.textContent = response[i].value;
}
//If the user is not in top 5, the users score will also be rendered
if(response[userIndex].rank > 5){
row = table.insertRow();
cell = row.insertCell();
cell.textContent = response[userIndex].rank;
cell = row.insertCell();
cell.textContent = response[userIndex].name;
cell = row.insertCell();
cell.textContent = response[userIndex].value;
}
let response = await sendRequest("GET", `${HOST}/api/leaderboards/${id}/`);
console.log(response.ok);
//Placeholder response and status:
let response = [
{ name: "Mark", value: 301, rank: 1 },
{ name: "Anton", value: 245, rank: 2 },
{ name: "John", value: 112, rank: 3 },
{ name: "Joe", value: 84, rank: 4 },
{ name: "Larry", value: 80, rank: 5 },
{ name: "Glaum", value: 1, rank: 85 },
];
response.ok = true;
if (response.ok) {
let table = document.getElementById("leaderboardstable");
let row, cell;
//The users own score will always be placed last in the JSON response
let userIndex = response.length - 1;
for (let i = 0; i < response.length - 1; i++) {
row = table.insertRow();
cell = row.insertCell();
cell.textContent = response[i].rank;
cell = row.insertCell();
cell.textContent = response[i].name;
cell = row.insertCell();
cell.textContent = response[i].value;
}
//If the user is not in top 5, the users score will also be rendered
if (response[userIndex].rank > 5) {
row = table.insertRow();
cell = row.insertCell();
cell.textContent = response[userIndex].rank;
cell = row.insertCell();
cell.textContent = response[userIndex].name;
cell = row.insertCell();
cell.textContent = response[userIndex].value;
}
}
return response;
return response;
}
window.addEventListener("DOMContentLoaded", async () => {
cancelButton = document.querySelector("#btn-cancel-exercise");
okButton = document.querySelector("#btn-ok-exercise");
deleteButton = document.querySelector("#btn-delete-exercise");
editButton = document.querySelector("#btn-edit-exercise");
oldFormData = null;
const urlParams = new URLSearchParams(window.location.search);
// view/edit
if (urlParams.has('id')) {
const exerciseId = urlParams.get('id');
await retrieveExercise(exerciseId);
editButton.addEventListener("click", handleEditExerciseButtonClick);
deleteButton.addEventListener("click", (async (id) => await deleteExercise(id)).bind(undefined, exerciseId));
okButton.addEventListener("click", (async (id) => await updateExercise(id)).bind(undefined, exerciseId));
}
//create
else {
setReadOnly(false, "#form-exercise");
editButton.className += " hide";
okButton.className = okButton.className.replace(" hide", "");
cancelButton.className = cancelButton.className.replace(" hide", "");
okButton.addEventListener("click", async () => await createExercise());
cancelButton.addEventListener("click", handleCancelButtonDuringCreate);
}
cancelButton = document.querySelector("#btn-cancel-exercise");
okButton = document.querySelector("#btn-ok-exercise");
deleteButton = document.querySelector("#btn-delete-exercise");
editButton = document.querySelector("#btn-edit-exercise");
oldFormData = null;
const urlParams = new URLSearchParams(window.location.search);
// view/edit
if (urlParams.has("id")) {
const exerciseId = urlParams.get("id");
await retrieveExercise(exerciseId);
editButton.addEventListener("click", handleEditExerciseButtonClick);
deleteButton.addEventListener(
"click",
(async (id) => await deleteExercise(id)).bind(undefined, exerciseId)
);
okButton.addEventListener(
"click",
(async (id) => await updateExercise(id)).bind(undefined, exerciseId)
);
}
//create
else {
setReadOnly(false, "#form-exercise");
editButton.className += " hide";
okButton.className = okButton.className.replace(" hide", "");
cancelButton.className = cancelButton.className.replace(" hide", "");
okButton.addEventListener("click", async () => await createExercise());
cancelButton.addEventListener("click", handleCancelButtonDuringCreate);
}
await fetchLeaderBoards();
});
\ No newline at end of file
await fetchLeaderBoards();
});
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