Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
T
tdt4242-base-APU
Manage
Activity
Members
Labels
Plan
Issues
0
Issue boards
Milestones
Wiki
Code
Merge requests
0
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Tor Martin Frøberg Wang
tdt4242-base-APU
Commits
78845177
Commit
78845177
authored
4 years ago
by
Tobias Ørstad
Browse files
Options
Downloads
Patches
Plain Diff
Add view for accessing leaderboard scores
parent
6ef52866
No related branches found
Branches containing commit
No related tags found
3 merge requests
!5
Ad ci/cs setup
,
!4
Dev
,
!1
Leaderboards
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
backend/secfit/workouts/urls.py
+2
-2
2 additions, 2 deletions
backend/secfit/workouts/urls.py
backend/secfit/workouts/views.py
+35
-11
35 additions, 11 deletions
backend/secfit/workouts/views.py
frontend/www/scripts/exercise.js
+172
-161
172 additions, 161 deletions
frontend/www/scripts/exercise.js
with
209 additions
and
174 deletions
backend/secfit/workouts/urls.py
+
2
−
2
View file @
78845177
...
...
@@ -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
(),
...
...
This diff is collapsed.
Click to expand it.
backend/secfit/workouts/views.py
+
35
−
11
View file @
78845177
...
...
@@ -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
(
...
...
This diff is collapsed.
Click to expand it.
frontend/www/scripts/exercise.js
+
172
−
161
View file @
78845177
...
...
@@ -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
();
});
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment