mirror of
https://github.com/KeyZox71/knl_meowscendence.git
synced 2026-01-01 06:06:41 +01:00
Merge pull request #55 from KeyZox71/user-management
Adding user management to main
This commit is contained in:
120
doc/user/avatar.md
Normal file
120
doc/user/avatar.md
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
# Avatar
|
||||||
|
|
||||||
|
Available endpoints:
|
||||||
|
- POST `/users/:userId/avatar`
|
||||||
|
- GET `/users/:userId/avatar`
|
||||||
|
- PATCH `/users/:userId/avatar`
|
||||||
|
- DELETE `/users/:userId/avatar`
|
||||||
|
|
||||||
|
Common return:
|
||||||
|
- 500 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "Internal server error"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## POST /users/:userId/avatar
|
||||||
|
|
||||||
|
Used to upload an avatar
|
||||||
|
|
||||||
|
Input needed :
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
<FormData object containing the file>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "Avatar uploaded successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 400 with response (if the file is too large, or file is missing, or it is missing a file name, or it is missing a mime type)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if the user does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## GET /users/:userId/avatar
|
||||||
|
|
||||||
|
Used to download an avatar
|
||||||
|
|
||||||
|
Input needed :
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
<FormData object containing the file>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "Avatar uploaded successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if the user does not exist, or the user does not have an assigned avatar, or the image does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## PATCH /users/:userId/avatar
|
||||||
|
|
||||||
|
Used to modify an avatar
|
||||||
|
|
||||||
|
Input needed :
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
<FormData object containing the file>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "Avatar modified successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 400 with response (if the file is too large, or file is missing, or it is missing a file name, or it is missing a mime type)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if the user does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## DELETE /users/:userId/avatar
|
||||||
|
|
||||||
|
Used to delete an avatar
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "Avatar deleted successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if the user does not exist, or the user does not have an assigned avatar)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
155
doc/user/friend.md
Normal file
155
doc/user/friend.md
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
# Friend
|
||||||
|
|
||||||
|
Available endpoints:
|
||||||
|
- POST `/users/:userId/friends`
|
||||||
|
- GET `/users/:userId/friends`
|
||||||
|
- GET `/users/:userId/friends/count`
|
||||||
|
- DELETE `/users/:userId/friends`
|
||||||
|
- DELETE `/users/:userId/friends/:friendId`
|
||||||
|
|
||||||
|
Common return:
|
||||||
|
- 500 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "Internal server error"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## POST `/users/:userId/friends/:friendId`
|
||||||
|
|
||||||
|
Used to add a friend to an user
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "Friend added successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 400 with response (if no user is specified in header, or friend is the user specified in header, or friend is already added)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if user does not exist, or friend does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 401 with response (if user specified in header is neither admin nor user)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## GET `/users/:userId/friends?iStart=<starting index (included)>&iEnd=<ending index (excluded)>`
|
||||||
|
|
||||||
|
Used to get the friends of an user
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response (list of friend objects (between iStart and iEnd))
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"friends":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"friendName": "<the friend's username>",
|
||||||
|
"friendDisplayName": "<the friend's display name>"
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 400 with response (if iStart/iEnd is missing, or iEnd < iStart)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if user does not exist, or no friends exist in the selected range)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## GET `/users/:userId/friends/count`
|
||||||
|
|
||||||
|
Used to get the number of friends of an user
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"n_friends": <number of friends>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if user does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## DELETE `/users/:userId/friends`
|
||||||
|
|
||||||
|
Used to delete the friends of an user
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "Friends deleted successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 400 with response (if user specified in header is neither admin nor user)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 401 with response (if user specified in header is neither admin nor user)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if user does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## DELETE `/users/:userId/friends/:friendId`
|
||||||
|
|
||||||
|
Used to delete a friend of an user
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "Friend deleted successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 400 with response (if user specified in header is neither admin nor user)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 401 with response (if user specified in header is neither admin nor user)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if user does not exist, or friend does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
148
doc/user/matchHistory.md
Normal file
148
doc/user/matchHistory.md
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
# Match History
|
||||||
|
|
||||||
|
Available endpoints:
|
||||||
|
- POST `/users/:userId/matchHistory`
|
||||||
|
- GET `/users/:userId/matchHistory`
|
||||||
|
- GET `/users/:userId/matchHistory/count`
|
||||||
|
- DELETE `/users/:userId/matchHistory`
|
||||||
|
|
||||||
|
Common return:
|
||||||
|
- 500 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "Internal server error"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## POST `/users/:userId/matchHistory?game=<pong/tetris>`
|
||||||
|
|
||||||
|
Used to add a match result to an user to a specific game
|
||||||
|
|
||||||
|
Input needed :
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"game": "<pong/tetris>"
|
||||||
|
"opponent": "<the opponent's username>", <= item only present if the match involved 2 players
|
||||||
|
"myScore": <my score>,
|
||||||
|
"opponentScore": <the opponent's score>, <= item only present if the match involved 2 players
|
||||||
|
"date": <seconds since Epoch (Date.now() return)>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "Match successfully saved to the blockchain"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 400 with response (if no user is specified in header, or no opponent/p1Score/p2Score is specified in body, or opponent is the user specified in header, or a score is negative, or the game specified is invalid, or the game should involve more players than was specified)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if user does not exist, or opponent does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 401 with response (if user specified in header is neither admin nor user)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## GET `/users/:userId/matchHistory?game=<pong/tetris>&iStart=<starting index (included)>&iEnd=<ending index (excluded)>`
|
||||||
|
|
||||||
|
Used to get the match history of an user for a specific game
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response (list of matches results (between iStart and iEnd))
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"matchHistory":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"score":
|
||||||
|
{
|
||||||
|
"p1": "<the name of the p1>",
|
||||||
|
"p2": "<the name of the p2>", <= item only present if the match involved 2 players
|
||||||
|
"p1Score": "<the score of the p1>",
|
||||||
|
"p2Score": "<the score of the p2>", <= item only present if the match involved 2 players
|
||||||
|
"date": <seconds since Epoch (Date.now() return)>
|
||||||
|
},
|
||||||
|
"tx": "<the transcaction hash>"
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 400 with response (if iStart/iEnd does not exist, or iEnd < iStart, or the game specified is invalid)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if user does not exist, or no matches exist in the selected range)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## GET `/users/:userId/matchHistory/count?game=<pong/tetris>`
|
||||||
|
|
||||||
|
Used to get the number of matches an user played for a specific game
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"n_matches": <number of matches played by the user>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 400 with response (if game does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if user does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## DELETE `/users/:userId/matchHistory?game=<pong/tetris>`
|
||||||
|
|
||||||
|
Used to delete the match history of an user for a specific game
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "Match history deleted successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 400 with response (if user specified in header is neither admin nor user, or the game specified is invalid)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 401 with response (if user specified in header is neither admin nor user)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if user does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
41
doc/user/ping.md
Normal file
41
doc/user/ping.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# ping
|
||||||
|
|
||||||
|
Available endpoints:
|
||||||
|
- POST `/ping`
|
||||||
|
- GET `/ping/:userId`
|
||||||
|
|
||||||
|
Common return:
|
||||||
|
- 500 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "Internal server error"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## POST `/ping`
|
||||||
|
|
||||||
|
Used to send a ping and update the lastSeenTime (can be used for activity time)
|
||||||
|
|
||||||
|
Input needed : just need a valid token
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "last seen time updated successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## GET `/ping/:userId`
|
||||||
|
|
||||||
|
Used to retrive the lastSeenTime of a user
|
||||||
|
|
||||||
|
Input needed : just need a valid token
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"isLogged": "<true/false>"
|
||||||
|
}
|
||||||
|
```
|
||||||
212
doc/user/user.md
Normal file
212
doc/user/user.md
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
# User
|
||||||
|
|
||||||
|
Available endpoints:
|
||||||
|
- POST `/users/:userId`
|
||||||
|
- GET `/users`
|
||||||
|
- GET `/users/count`
|
||||||
|
- GET `/users/:userId`
|
||||||
|
- PATCH `/users/:userId/:member`
|
||||||
|
- DELETE `/users/:userId`
|
||||||
|
- DELETE `/users/:userId/:member`
|
||||||
|
|
||||||
|
Common return:
|
||||||
|
- 500 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "Internal server error"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## POST `/users/:userId`
|
||||||
|
|
||||||
|
Used to create an user
|
||||||
|
|
||||||
|
Input needed :
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"displayName": "<the display name>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "User created successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 400 with response (if no user is specified in header, or user already exists, or no display name is specified in body)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 401 with response (if user specified in header is not admin)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## GET `/users?iStart=<starting index (included)>&iEnd=<ending index (excluded)>`
|
||||||
|
|
||||||
|
Used to get the list of users
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response (list of user objects (between iStart and iEnd))
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"users":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"username": "<the username>",
|
||||||
|
"displayName": "<the display name>",
|
||||||
|
"pong": {
|
||||||
|
"wins": <the number of pong matches won>,
|
||||||
|
"losses": <the number of pong matches lost>
|
||||||
|
},
|
||||||
|
"tetris": {
|
||||||
|
"wins": <the number of tetris matches won>,
|
||||||
|
"losses": <the number of tetris matches lost>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 400 with response (if iStart/iEnd is missing, or iEnd < iStart)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if no users exist in the selected range)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## GET `/users/count`
|
||||||
|
|
||||||
|
Used to get the number of users
|
||||||
|
|
||||||
|
Always returns:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"n_users": <number of users>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## GET `/users/:userId`
|
||||||
|
|
||||||
|
Used to get an user
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response (an user object)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"username": "<the username>",
|
||||||
|
"displayName": "<the display name>",
|
||||||
|
"pong": {
|
||||||
|
"wins": <the number of pong matches won>,
|
||||||
|
"losses": <the number of pong matches lost>
|
||||||
|
},
|
||||||
|
"tetris": {
|
||||||
|
"wins": <the number of tetris matches won>,
|
||||||
|
"losses": <the number of tetris matches lost>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if user does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## PATCH `/users/:userId/:member`
|
||||||
|
|
||||||
|
Used to modify a member of an user (only displayName can be modified)
|
||||||
|
|
||||||
|
Input needed :
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"<the member to modify (must be identical to :member)>": "<the member's new value>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "<:member> modified sucessfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 400 with response (if no user is specified in header, or new value of member to modify is not provided in the body, or member does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if user does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 401 with response (if user specified in header is not admin)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## DELETE `/users/:userId`
|
||||||
|
|
||||||
|
Used to delete an user
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "User deleted successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (user does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## DELETE `/users/:userId/:member`
|
||||||
|
|
||||||
|
Used to delete a member of an user (only displayName can be deleted)
|
||||||
|
|
||||||
|
Can return:
|
||||||
|
- 200 with response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "<:member> deleted successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 401 with response (if user specified in header is neither admin nor user)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 400 with response (if no user is specified in header, or member to delete does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 404 with response (if user does not exist)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "<corresponding error>"
|
||||||
|
}
|
||||||
|
```
|
||||||
@ -4,6 +4,7 @@
|
|||||||
"@fastify/cookie": "^11.0.2",
|
"@fastify/cookie": "^11.0.2",
|
||||||
"@fastify/env": "^5.0.2",
|
"@fastify/env": "^5.0.2",
|
||||||
"@fastify/jwt": "^9.1.0",
|
"@fastify/jwt": "^9.1.0",
|
||||||
|
"@fastify/multipart": "^9.2.1",
|
||||||
"axios": "^1.10.0",
|
"axios": "^1.10.0",
|
||||||
"base32.js": "^0.1.0",
|
"base32.js": "^0.1.0",
|
||||||
"bcrypt": "^6.0.0",
|
"bcrypt": "^6.0.0",
|
||||||
@ -13,6 +14,7 @@
|
|||||||
"fastify-cli": "^7.4.0",
|
"fastify-cli": "^7.4.0",
|
||||||
"pino": "^9.7.0",
|
"pino": "^9.7.0",
|
||||||
"prom-client": "^15.1.3",
|
"prom-client": "^15.1.3",
|
||||||
|
"sharp": "^0.34.4",
|
||||||
"solhint": "^6.0.0"
|
"solhint": "^6.0.0"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
288
pnpm-lock.yaml
generated
288
pnpm-lock.yaml
generated
@ -20,6 +20,9 @@ importers:
|
|||||||
'@fastify/jwt':
|
'@fastify/jwt':
|
||||||
specifier: ^9.1.0
|
specifier: ^9.1.0
|
||||||
version: 9.1.0
|
version: 9.1.0
|
||||||
|
'@fastify/multipart':
|
||||||
|
specifier: ^9.2.1
|
||||||
|
version: 9.2.1
|
||||||
axios:
|
axios:
|
||||||
specifier: ^1.10.0
|
specifier: ^1.10.0
|
||||||
version: 1.10.0
|
version: 1.10.0
|
||||||
@ -47,6 +50,9 @@ importers:
|
|||||||
prom-client:
|
prom-client:
|
||||||
specifier: ^15.1.3
|
specifier: ^15.1.3
|
||||||
version: 15.1.3
|
version: 15.1.3
|
||||||
|
sharp:
|
||||||
|
specifier: ^0.34.4
|
||||||
|
version: 0.34.4
|
||||||
solhint:
|
solhint:
|
||||||
specifier: ^6.0.0
|
specifier: ^6.0.0
|
||||||
version: 6.0.0(typescript@5.8.3)
|
version: 6.0.0(typescript@5.8.3)
|
||||||
@ -88,6 +94,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
|
resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@emnapi/runtime@1.5.0':
|
||||||
|
resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==}
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.25.6':
|
'@esbuild/aix-ppc64@0.25.6':
|
||||||
resolution: {integrity: sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==}
|
resolution: {integrity: sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@ -252,12 +261,18 @@ packages:
|
|||||||
'@fastify/ajv-compiler@4.0.2':
|
'@fastify/ajv-compiler@4.0.2':
|
||||||
resolution: {integrity: sha512-Rkiu/8wIjpsf46Rr+Fitd3HRP+VsxUFDDeag0hs9L0ksfnwx2g7SPQQTFL0E8Qv+rfXzQOxBJnjUB9ITUDjfWQ==}
|
resolution: {integrity: sha512-Rkiu/8wIjpsf46Rr+Fitd3HRP+VsxUFDDeag0hs9L0ksfnwx2g7SPQQTFL0E8Qv+rfXzQOxBJnjUB9ITUDjfWQ==}
|
||||||
|
|
||||||
|
'@fastify/busboy@3.2.0':
|
||||||
|
resolution: {integrity: sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA==}
|
||||||
|
|
||||||
'@fastify/cookie@11.0.2':
|
'@fastify/cookie@11.0.2':
|
||||||
resolution: {integrity: sha512-GWdwdGlgJxyvNv+QcKiGNevSspMQXncjMZ1J8IvuDQk0jvkzgWWZFNC2En3s+nHndZBGV8IbLwOI/sxCZw/mzA==}
|
resolution: {integrity: sha512-GWdwdGlgJxyvNv+QcKiGNevSspMQXncjMZ1J8IvuDQk0jvkzgWWZFNC2En3s+nHndZBGV8IbLwOI/sxCZw/mzA==}
|
||||||
|
|
||||||
'@fastify/deepmerge@2.0.2':
|
'@fastify/deepmerge@2.0.2':
|
||||||
resolution: {integrity: sha512-3wuLdX5iiiYeZWP6bQrjqhrcvBIf0NHbQH1Ur1WbHvoiuTYUEItgygea3zs8aHpiitn0lOB8gX20u1qO+FDm7Q==}
|
resolution: {integrity: sha512-3wuLdX5iiiYeZWP6bQrjqhrcvBIf0NHbQH1Ur1WbHvoiuTYUEItgygea3zs8aHpiitn0lOB8gX20u1qO+FDm7Q==}
|
||||||
|
|
||||||
|
'@fastify/deepmerge@3.1.0':
|
||||||
|
resolution: {integrity: sha512-lCVONBQINyNhM6LLezB6+2afusgEYR4G8xenMsfe+AT+iZ7Ca6upM5Ha8UkZuYSnuMw3GWl/BiPXnLMi/gSxuQ==}
|
||||||
|
|
||||||
'@fastify/env@5.0.2':
|
'@fastify/env@5.0.2':
|
||||||
resolution: {integrity: sha512-4m/jHS3s/G/DBJVODob9sxGUei/Ij8JFbA2PYqBfoihTm+Qqae2xD9xhez68UFZu1d4SNJPIb6uAOwbNvRYw+A==}
|
resolution: {integrity: sha512-4m/jHS3s/G/DBJVODob9sxGUei/Ij8JFbA2PYqBfoihTm+Qqae2xD9xhez68UFZu1d4SNJPIb6uAOwbNvRYw+A==}
|
||||||
|
|
||||||
@ -276,6 +291,9 @@ packages:
|
|||||||
'@fastify/merge-json-schemas@0.2.1':
|
'@fastify/merge-json-schemas@0.2.1':
|
||||||
resolution: {integrity: sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==}
|
resolution: {integrity: sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==}
|
||||||
|
|
||||||
|
'@fastify/multipart@9.2.1':
|
||||||
|
resolution: {integrity: sha512-U4221XDMfzCUtfzsyV1/PkR4MNgKI0158vUUyn/oF2Tl6RxMc+N7XYLr5fZXQiEC+Fmw5zFaTjxsTGTgtDtK+g==}
|
||||||
|
|
||||||
'@fastify/proxy-addr@5.0.0':
|
'@fastify/proxy-addr@5.0.0':
|
||||||
resolution: {integrity: sha512-37qVVA1qZ5sgH7KpHkkC4z9SK6StIsIcOmpjvMPXNb3vx2GQxhZocogVYbr2PbbeLCQxYIPDok307xEvRZOzGA==}
|
resolution: {integrity: sha512-37qVVA1qZ5sgH7KpHkkC4z9SK6StIsIcOmpjvMPXNb3vx2GQxhZocogVYbr2PbbeLCQxYIPDok307xEvRZOzGA==}
|
||||||
|
|
||||||
@ -283,6 +301,132 @@ packages:
|
|||||||
resolution: {integrity: sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==}
|
resolution: {integrity: sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==}
|
||||||
engines: {node: '>=10.10.0'}
|
engines: {node: '>=10.10.0'}
|
||||||
|
|
||||||
|
'@img/colour@1.0.0':
|
||||||
|
resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
'@img/sharp-darwin-arm64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-darwin-x64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-arm64@1.2.3':
|
||||||
|
resolution: {integrity: sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-x64@1.2.3':
|
||||||
|
resolution: {integrity: sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm64@1.2.3':
|
||||||
|
resolution: {integrity: sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm@1.2.3':
|
||||||
|
resolution: {integrity: sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-ppc64@1.2.3':
|
||||||
|
resolution: {integrity: sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-s390x@1.2.3':
|
||||||
|
resolution: {integrity: sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-x64@1.2.3':
|
||||||
|
resolution: {integrity: sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64@1.2.3':
|
||||||
|
resolution: {integrity: sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64@1.2.3':
|
||||||
|
resolution: {integrity: sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm@0.34.4':
|
||||||
|
resolution: {integrity: sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@img/sharp-linux-ppc64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@img/sharp-linux-s390x@0.34.4':
|
||||||
|
resolution: {integrity: sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@img/sharp-linux-x64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-arm64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-x64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@img/sharp-wasm32@0.34.4':
|
||||||
|
resolution: {integrity: sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [wasm32]
|
||||||
|
|
||||||
|
'@img/sharp-win32-arm64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@img/sharp-win32-ia32@0.34.4':
|
||||||
|
resolution: {integrity: sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@img/sharp-win32-x64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
'@isaacs/fs-minipass@4.0.1':
|
'@isaacs/fs-minipass@4.0.1':
|
||||||
resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
|
resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
@ -753,6 +897,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
|
resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
detect-libc@2.1.2:
|
||||||
|
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
dotenv-expand@10.0.0:
|
dotenv-expand@10.0.0:
|
||||||
resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==}
|
resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@ -1452,6 +1600,10 @@ packages:
|
|||||||
set-cookie-parser@2.7.1:
|
set-cookie-parser@2.7.1:
|
||||||
resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
|
resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
|
||||||
|
|
||||||
|
sharp@0.34.4:
|
||||||
|
resolution: {integrity: sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
|
||||||
simple-concat@1.0.1:
|
simple-concat@1.0.1:
|
||||||
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
|
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
|
||||||
|
|
||||||
@ -1667,6 +1819,11 @@ snapshots:
|
|||||||
|
|
||||||
'@babel/helper-validator-identifier@7.27.1': {}
|
'@babel/helper-validator-identifier@7.27.1': {}
|
||||||
|
|
||||||
|
'@emnapi/runtime@1.5.0':
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.7.0
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.25.6':
|
'@esbuild/aix-ppc64@0.25.6':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@ -1753,6 +1910,8 @@ snapshots:
|
|||||||
ajv-formats: 3.0.1(ajv@8.17.1)
|
ajv-formats: 3.0.1(ajv@8.17.1)
|
||||||
fast-uri: 3.0.6
|
fast-uri: 3.0.6
|
||||||
|
|
||||||
|
'@fastify/busboy@3.2.0': {}
|
||||||
|
|
||||||
'@fastify/cookie@11.0.2':
|
'@fastify/cookie@11.0.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
cookie: 1.0.2
|
cookie: 1.0.2
|
||||||
@ -1760,6 +1919,8 @@ snapshots:
|
|||||||
|
|
||||||
'@fastify/deepmerge@2.0.2': {}
|
'@fastify/deepmerge@2.0.2': {}
|
||||||
|
|
||||||
|
'@fastify/deepmerge@3.1.0': {}
|
||||||
|
|
||||||
'@fastify/env@5.0.2':
|
'@fastify/env@5.0.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
env-schema: 6.0.1
|
env-schema: 6.0.1
|
||||||
@ -1785,6 +1946,14 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
dequal: 2.0.3
|
dequal: 2.0.3
|
||||||
|
|
||||||
|
'@fastify/multipart@9.2.1':
|
||||||
|
dependencies:
|
||||||
|
'@fastify/busboy': 3.2.0
|
||||||
|
'@fastify/deepmerge': 3.1.0
|
||||||
|
'@fastify/error': 4.2.0
|
||||||
|
fastify-plugin: 5.0.1
|
||||||
|
secure-json-parse: 4.0.0
|
||||||
|
|
||||||
'@fastify/proxy-addr@5.0.0':
|
'@fastify/proxy-addr@5.0.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@fastify/forwarded': 3.0.0
|
'@fastify/forwarded': 3.0.0
|
||||||
@ -1792,6 +1961,94 @@ snapshots:
|
|||||||
|
|
||||||
'@humanwhocodes/momoa@2.0.4': {}
|
'@humanwhocodes/momoa@2.0.4': {}
|
||||||
|
|
||||||
|
'@img/colour@1.0.0': {}
|
||||||
|
|
||||||
|
'@img/sharp-darwin-arm64@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-darwin-arm64': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-darwin-x64@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-darwin-x64': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-arm64@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-x64@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm64@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-ppc64@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-s390x@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-x64@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm64@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-arm64': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-arm': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-ppc64@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-ppc64': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-s390x@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-s390x': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-x64@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-x64': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-arm64@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-x64@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-wasm32@0.34.4':
|
||||||
|
dependencies:
|
||||||
|
'@emnapi/runtime': 1.5.0
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-win32-arm64@0.34.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-win32-ia32@0.34.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-win32-x64@0.34.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@isaacs/fs-minipass@4.0.1':
|
'@isaacs/fs-minipass@4.0.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
minipass: 7.1.2
|
minipass: 7.1.2
|
||||||
@ -2183,6 +2440,8 @@ snapshots:
|
|||||||
|
|
||||||
detect-libc@2.0.4: {}
|
detect-libc@2.0.4: {}
|
||||||
|
|
||||||
|
detect-libc@2.1.2: {}
|
||||||
|
|
||||||
dotenv-expand@10.0.0: {}
|
dotenv-expand@10.0.0: {}
|
||||||
|
|
||||||
dotenv@16.6.1: {}
|
dotenv@16.6.1: {}
|
||||||
@ -2914,6 +3173,35 @@ snapshots:
|
|||||||
|
|
||||||
set-cookie-parser@2.7.1: {}
|
set-cookie-parser@2.7.1: {}
|
||||||
|
|
||||||
|
sharp@0.34.4:
|
||||||
|
dependencies:
|
||||||
|
'@img/colour': 1.0.0
|
||||||
|
detect-libc: 2.1.2
|
||||||
|
semver: 7.7.2
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-darwin-arm64': 0.34.4
|
||||||
|
'@img/sharp-darwin-x64': 0.34.4
|
||||||
|
'@img/sharp-libvips-darwin-arm64': 1.2.3
|
||||||
|
'@img/sharp-libvips-darwin-x64': 1.2.3
|
||||||
|
'@img/sharp-libvips-linux-arm': 1.2.3
|
||||||
|
'@img/sharp-libvips-linux-arm64': 1.2.3
|
||||||
|
'@img/sharp-libvips-linux-ppc64': 1.2.3
|
||||||
|
'@img/sharp-libvips-linux-s390x': 1.2.3
|
||||||
|
'@img/sharp-libvips-linux-x64': 1.2.3
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64': 1.2.3
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64': 1.2.3
|
||||||
|
'@img/sharp-linux-arm': 0.34.4
|
||||||
|
'@img/sharp-linux-arm64': 0.34.4
|
||||||
|
'@img/sharp-linux-ppc64': 0.34.4
|
||||||
|
'@img/sharp-linux-s390x': 0.34.4
|
||||||
|
'@img/sharp-linux-x64': 0.34.4
|
||||||
|
'@img/sharp-linuxmusl-arm64': 0.34.4
|
||||||
|
'@img/sharp-linuxmusl-x64': 0.34.4
|
||||||
|
'@img/sharp-wasm32': 0.34.4
|
||||||
|
'@img/sharp-win32-arm64': 0.34.4
|
||||||
|
'@img/sharp-win32-ia32': 0.34.4
|
||||||
|
'@img/sharp-win32-x64': 0.34.4
|
||||||
|
|
||||||
simple-concat@1.0.1: {}
|
simple-concat@1.0.1: {}
|
||||||
|
|
||||||
simple-get@4.0.1:
|
simple-get@4.0.1:
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import authDB from '../../utils/authDB';
|
import authDB from '../../utils/authDB.js';
|
||||||
import { authUserRemove } from '../../utils/authUserRemove';
|
import { authUserRemove } from '../../utils/authUserRemove.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import('fastify').FastifyRequest} request
|
* @param {import('fastify').FastifyRequest} request
|
||||||
|
|||||||
@ -9,12 +9,11 @@ import { callAddScore, callLastId } from "../../utils/scoreStore_contract.js";
|
|||||||
*/
|
*/
|
||||||
export async function addTx(request, reply, fastify) {
|
export async function addTx(request, reply, fastify) {
|
||||||
try {
|
try {
|
||||||
const id = await callLastId();
|
const {tx, id} = await callAddScore(request.body.p1, request.body.p2, request.body.p1Score, request.body.p2Score);
|
||||||
const tx = callAddScore(request.body.p1, request.body.p2, request.body.p1Score, request.body.p2Score);
|
|
||||||
|
|
||||||
tx.then(tx => {
|
|
||||||
scoreDB.addTx(id, tx.hash);
|
scoreDB.addTx(id, tx.hash);
|
||||||
});
|
// tx.then(tx => {
|
||||||
|
// });
|
||||||
|
|
||||||
return reply.code(200).send({
|
return reply.code(200).send({
|
||||||
id: Number(id)
|
id: Number(id)
|
||||||
|
|||||||
@ -20,7 +20,7 @@ export default async function(fastify, options) {
|
|||||||
required: ['p1', 'p2', 'p1Score', 'p2Score'],
|
required: ['p1', 'p2', 'p1Score', 'p2Score'],
|
||||||
properties: {
|
properties: {
|
||||||
p1: { type: 'string', minLength: 1 },
|
p1: { type: 'string', minLength: 1 },
|
||||||
p2: { type: 'string', minLength: 1 },
|
p2: { type: 'string', minLength: 0 },
|
||||||
p1Score: { type: 'integer', minimum: 0 },
|
p1Score: { type: 'integer', minimum: 0 },
|
||||||
p2Score: { type: 'integer', minimum: 0 },
|
p2Score: { type: 'integer', minimum: 0 },
|
||||||
}
|
}
|
||||||
|
|||||||
18
src/api/user/dAvatar.js
Normal file
18
src/api/user/dAvatar.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export async function dAvatar(request, reply, fastify, getUserInfo, getAvatarId, deleteAvatarId, deleteImage) {
|
||||||
|
try {
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!getUserInfo.get(userId)) {
|
||||||
|
return reply.cose(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
const imageId = getAvatarId.get(userId);
|
||||||
|
if (imageId.avatarId === -1) {
|
||||||
|
return reply.code(404).send({ error: "User does not have an avatar" });
|
||||||
|
}
|
||||||
|
deleteImage.run(imageId.avatarId);
|
||||||
|
deleteAvatarId.run(userId);
|
||||||
|
return reply.code(200).send({ msg: "Avatar deleted successfully" });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/api/user/dFriend.js
Normal file
23
src/api/user/dFriend.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
export async function dFriend(request, reply, fastify, getUserInfo, getFriend, deleteFriend) {
|
||||||
|
try {
|
||||||
|
if (!request.user) {
|
||||||
|
return reply.code(400).send({ error: "Please specify a user" });
|
||||||
|
}
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!getUserInfo.get(userId)) {
|
||||||
|
return reply.code(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
if (request.user !== 'admin' && request.user !== userId) {
|
||||||
|
return reply.code(401).send({ error: "Unauthorized" });
|
||||||
|
}
|
||||||
|
const friendId = request.params.friendId;
|
||||||
|
if (!getFriend.get(userId, friendId)) {
|
||||||
|
return reply.code(404).send({ error: "Friend does not exist" });
|
||||||
|
}
|
||||||
|
deleteFriend.run(userId, friendId);
|
||||||
|
return reply.code(200).send({ msg: "Friend deleted successfully" });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/api/user/dFriends.js
Normal file
19
src/api/user/dFriends.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
export async function dFriends(request, reply, fastify, getUserInfo, deleteFriends) {
|
||||||
|
try {
|
||||||
|
if (!request.user) {
|
||||||
|
return reply.code(400).send({ error: "Please specify a user" });
|
||||||
|
}
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!getUserInfo.get(userId)) {
|
||||||
|
return reply.code(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
if (request.user !== 'admin' && request.user !== userId) {
|
||||||
|
return reply.code(401).send({ error: "Unauthorized" });
|
||||||
|
}
|
||||||
|
deleteFriends.run(userId);
|
||||||
|
return reply.code(200).send({ msg: "Friends deleted successfully" });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/api/user/dMatchHistory.js
Normal file
29
src/api/user/dMatchHistory.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
export async function dMatchHistory(request, reply, fastify, getUserInfo, deleteMatchHistory, deleteStatsPong, deleteStatsTetris) {
|
||||||
|
try {
|
||||||
|
if (!request.user) {
|
||||||
|
return reply.code(400).send({ error: "Please specify a user" });
|
||||||
|
}
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!getUserInfo.get(userId)) {
|
||||||
|
return reply.code(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
if (request.user !== 'admin' && request.user !== userId) {
|
||||||
|
return reply.code(401).send({ error: "Unauthorized" });
|
||||||
|
}
|
||||||
|
const { game } = request.query;
|
||||||
|
if (game !== 'pong' && game !== 'tetris') {
|
||||||
|
return reply.code(400).send({ error: "Specified game does not exist" });
|
||||||
|
}
|
||||||
|
deleteMatchHistory.run(game, userId);
|
||||||
|
if (game === 'pong') {
|
||||||
|
deleteStatsPong.run(userId);
|
||||||
|
}
|
||||||
|
else if (game === 'tetris') {
|
||||||
|
deleteStatsTetris.run(userId);
|
||||||
|
}
|
||||||
|
return reply.code(200).send({ msg: "Match history deleted successfully" });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/api/user/dMember.js
Normal file
25
src/api/user/dMember.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
export async function dMember(request, reply, fastify, getUserInfo, changeDisplayName) {
|
||||||
|
try {
|
||||||
|
if (!request.user) {
|
||||||
|
return reply.code(400).send({ error: "Please specify a user" });
|
||||||
|
}
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!getUserInfo.get(userId)) {
|
||||||
|
return reply.code(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
const user = request.user;
|
||||||
|
const member = request.params.member;
|
||||||
|
if (user === 'admin' || user === request.params.userId) {
|
||||||
|
if (member === 'displayName') {
|
||||||
|
changeDisplayName.run("", request.params.userId);
|
||||||
|
return reply.code(200).send({ msg: "Display name deleted successfully" });
|
||||||
|
}
|
||||||
|
return reply.code(400).send({ msg: "Member does not exist" })
|
||||||
|
} else {
|
||||||
|
return reply.code(401).send({ error: 'You dont have the right to delete this' });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/api/user/dUser.js
Normal file
15
src/api/user/dUser.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export async function dUser(request, reply, fastify, getUserInfo, deleteMatchHistory, deleteFriends, deleteUser) {
|
||||||
|
try {
|
||||||
|
if (!getUserInfo.get(request.params.userId)) {
|
||||||
|
return reply.code(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
deleteMatchHistory.run('pong', request.params.userId);
|
||||||
|
deleteMatchHistory.run('tetris', request.params.userId);
|
||||||
|
deleteFriends.run(request.params.userId);
|
||||||
|
deleteUser.run(request.params.userId);
|
||||||
|
return reply.code(200).send({ msg: "User deleted successfully" });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,60 +1,148 @@
|
|||||||
import fastifyJWT from '@fastify/jwt';
|
import fastifyJWT from '@fastify/jwt';
|
||||||
import fastifyCookie from '@fastify/cookie';
|
import fastifyCookie from '@fastify/cookie';
|
||||||
import Database from 'better-sqlite3';
|
import Database from 'better-sqlite3';
|
||||||
|
import multipart from '@fastify/multipart';
|
||||||
|
|
||||||
var env = process.env.NODE_ENV || 'development';
|
import { gUsers } from './gUsers.js';
|
||||||
|
import { gUser } from './gUser.js';
|
||||||
|
import { gNumberUsers } from './gNumberUsers.js';
|
||||||
|
import { gFriends } from './gFriends.js';
|
||||||
|
import { gNumberFriends } from './gNumberFriends.js';
|
||||||
|
import { gMatchHistory } from './gMatchHistory.js';
|
||||||
|
import { gNumberMatches } from './gNumberMatches.js';
|
||||||
|
import { pUser } from './pUser.js';
|
||||||
|
import { pFriend } from './pFriend.js';
|
||||||
|
import { pMatchHistory } from './pMatchHistory.js';
|
||||||
|
import { uMember } from './uMember.js';
|
||||||
|
import { dUser } from './dUser.js';
|
||||||
|
import { dMember } from './dMember.js';
|
||||||
|
import { dFriends } from './dFriends.js';
|
||||||
|
import { dFriend } from './dFriend.js';
|
||||||
|
import { dMatchHistory } from './dMatchHistory.js';
|
||||||
|
import { pAvatar } from './pAvatar.js';
|
||||||
|
import { gAvatar } from './gAvatar.js';
|
||||||
|
import { uAvatar } from './uAvatar.js';
|
||||||
|
import { dAvatar } from './dAvatar.js';
|
||||||
|
import { pPing } from './pPing.js';
|
||||||
|
import { gPing } from './gPing.js';
|
||||||
|
|
||||||
|
const env = process.env.NODE_ENV || 'development';
|
||||||
|
|
||||||
let database;
|
let database;
|
||||||
|
|
||||||
if (!env || env === 'development') {
|
if (!env || env === 'development') {
|
||||||
database = new Database(":memory:", { verbose: console.log });
|
database = new Database(':memory:', { verbose: console.log });
|
||||||
} else {
|
} else {
|
||||||
var dbPath = process.env.DB_PATH || '/db/db.sqlite'
|
const dbPath = process.env.DB_PATH || '/db/db.sqlite'
|
||||||
database = new Database(dbPath);
|
database = new Database(dbPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepareDB() {
|
function prepareDB() {
|
||||||
database.exec(`
|
database.exec(`
|
||||||
CREATE TABLE IF NOT EXISTS userData (
|
CREATE TABLE IF NOT EXISTS userData (
|
||||||
username TEXT PRIMARY KEY,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
displayName TEXT
|
username TEXT,
|
||||||
|
displayName TEXT,
|
||||||
|
avatarId INTEGER,
|
||||||
|
pongWins INTEGER,
|
||||||
|
pongLosses INTEGER,
|
||||||
|
tetrisWins INTEGER,
|
||||||
|
tetrisLosses INTEGER,
|
||||||
|
UNIQUE(username),
|
||||||
|
CHECK(pongWins >= 0),
|
||||||
|
CHECK(pongLosses >= 0),
|
||||||
|
CHECK(tetrisWins >= 0),
|
||||||
|
CHECK(tetrisLosses >= 0)
|
||||||
) STRICT
|
) STRICT
|
||||||
`);
|
`);
|
||||||
database.exec(`
|
database.exec(`
|
||||||
CREATE TABLE IF NOT EXISTS friends (
|
CREATE TABLE IF NOT EXISTS friends (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
username TEXT,
|
username TEXT,
|
||||||
friendName TEXT,
|
friendName TEXT,
|
||||||
UNIQUE(username, friendName),
|
UNIQUE(username, friendName),
|
||||||
CHECK(username != friendName)
|
CHECK(username != friendName)
|
||||||
)
|
) STRICT
|
||||||
|
`);
|
||||||
|
database.exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS matchHistory (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
game TEXT,
|
||||||
|
date INTEGER,
|
||||||
|
player1 TEXT,
|
||||||
|
player2 TEXT,
|
||||||
|
matchId INTEGER,
|
||||||
|
CHECK(game = 'pong' OR game = 'tetris'),
|
||||||
|
CHECK(date >= 0),
|
||||||
|
CHECK(player1 != player2)
|
||||||
|
) STRICT
|
||||||
|
`);
|
||||||
|
database.exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS activityTime (
|
||||||
|
username TEXT PRIMARY KEY,
|
||||||
|
time TEXT
|
||||||
|
) STRICT
|
||||||
|
`);
|
||||||
|
database.exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS images (
|
||||||
|
imageId INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
fileName TEXT,
|
||||||
|
mimeType TEXT,
|
||||||
|
data BLOB
|
||||||
|
) STRICT
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareDB();
|
prepareDB();
|
||||||
|
|
||||||
// POST
|
// POST
|
||||||
const createUser = database.prepare('INSERT INTO userData (username, displayName) VALUES (?, ?);');
|
const createUser = database.prepare('INSERT INTO userData (username, displayName, avatarId, pongWins, pongLosses, tetrisWins, tetrisLosses) VALUES (?, ?, -1, 0, 0, 0, 0);');
|
||||||
const addFriend = database.prepare('INSERT INTO friends (username, friendName) VALUES (?, ?);');
|
const addFriend = database.prepare('INSERT INTO friends (username, friendName) VALUES (?, ?);');
|
||||||
|
const addMatch = database.prepare('INSERT INTO matchHistory (game, date, player1, player2, matchId) VALUES (?, ?, ?, ?, ?);');
|
||||||
|
const incWinsPong = database.prepare('UPDATE userData SET pongWins = pongWins + 1 WHERE username = ?;');
|
||||||
|
const incLossesPong = database.prepare('UPDATE userData SET pongLosses = pongLosses + 1 WHERE username = ?');
|
||||||
|
const incWinsTetris = database.prepare('UPDATE userData SET tetrisWins = tetrisWins + 1 WHERE username = ?;');
|
||||||
|
const incLossesTetris = database.prepare('UPDATE userData SET tetrisLosses = tetrisLosses + 1 WHERE username = ?');
|
||||||
|
const setAvatarId = database.prepare('UPDATE userData SET avatarId = ? WHERE username = ?;');
|
||||||
|
const postImage = database.prepare('INSERT INTO images (fileName, mimeType, data) VALUES (?, ?, ?);');
|
||||||
|
const setActivityTime = database.prepare(`
|
||||||
|
INSERT INTO activityTime (username, time)
|
||||||
|
VALUES (?, ?)
|
||||||
|
ON CONFLICT(username) DO UPDATE SET time = excluded.time;
|
||||||
|
`);
|
||||||
|
|
||||||
// PATCH
|
// PATCH
|
||||||
const changeDisplayName = database.prepare('UPDATE userData SET displayName = ? WHERE username = ?;');
|
const changeDisplayName = database.prepare('UPDATE userData SET displayName = ? WHERE username = ?;');
|
||||||
|
const changeAvatarId = database.prepare('UPDATE userData SET avatarId = ? WHERE username = ?;');
|
||||||
|
|
||||||
// GET
|
// GET
|
||||||
const getUserInfo = database.prepare('SELECT * FROM userData WHERE username = ?;');
|
const getUserData = database.prepare('SELECT username, displayName, pongWins, pongLosses, tetrisWins, tetrisLosses FROM userData LIMIT ? OFFSET ?;');
|
||||||
const getUserData = database.prepare('SELECT * FROM userData;');
|
const getUserInfo = database.prepare('SELECT username, displayName, pongWins, pongLosses, tetrisWins, tetrisLosses FROM userData WHERE username = ?;');
|
||||||
const getFriends = database.prepare('SELECT friendName FROM friends WHERE username = ?;');
|
const getFriends = database.prepare('SELECT friendName FROM friends WHERE username = ? LIMIT ? OFFSET ?;');
|
||||||
// const isFriend = database.prepare('SELECT 1 FROM friends WHERE username = ? AND friendName = ?;');
|
const getFriend = database.prepare('SELECT friendName FROM friends WHERE username = ? AND friendName = ?;');
|
||||||
|
const getMatchHistory = database.prepare('SELECT matchId, date FROM matchHistory WHERE game = ? AND ? IN (player1, player2) LIMIT ? OFFSET ?;');
|
||||||
|
const getNumberUsers = database.prepare('SELECT COUNT (DISTINCT username) AS n_users FROM userData;');
|
||||||
|
const getNumberFriends = database.prepare('SELECT COUNT (DISTINCT friendName) AS n_friends FROM friends WHERE username = ?;');
|
||||||
|
const getNumberMatches = database.prepare('SELECT COUNT (DISTINCT id) AS n_matches FROM matchHistory WHERE game = ? AND ? IN (player1, player2);');
|
||||||
|
const getAvatarId = database.prepare('SELECT avatarId FROM userData WHERE username = ?;');
|
||||||
|
const getImage = database.prepare('SELECT fileName, mimeType, data FROM images WHERE imageId = ?;');
|
||||||
|
const getActivityTime = database.prepare('SELECT time FROM activityTime WHERE username = ?;')
|
||||||
|
|
||||||
// DELETE
|
// DELETE
|
||||||
const deleteUser = database.prepare('DELETE FROM userData WHERE username = ?;');
|
const deleteUser = database.prepare('DELETE FROM userData WHERE username = ?;');
|
||||||
const deleteFriend = database.prepare('DELETE FROM friends WHERE username = ? AND friendName = ?;');
|
const deleteFriend = database.prepare('DELETE FROM friends WHERE username = ? AND friendName = ?;');
|
||||||
const deleteFriends = database.prepare('DELETE FROM friends WHERE username = ?;');
|
const deleteFriends = database.prepare('DELETE FROM friends WHERE username = ?;');
|
||||||
|
const deleteMatchHistory = database.prepare('DELETE FROM matchHistory WHERE game = ? AND ? IN (player1, player2);');
|
||||||
|
const deleteStatsPong = database.prepare('UPDATE userData SET pongWins = 0, pongLosses = 0 WHERE username = ?;');
|
||||||
|
const deleteStatsTetris = database.prepare('UPDATE userData SET tetrisWins = 0, tetrisLosses = 0 WHERE username = ?;');
|
||||||
|
const deleteAvatarId = database.prepare('UPDATE userData SET avatarId = -1 WHERE username = ?;');
|
||||||
|
const deleteImage = database.prepare('DELETE FROM images WHERE imageId = ?;');
|
||||||
|
|
||||||
|
const querySchema = { type: 'object', required: ['iStart', 'iEnd'], properties: { iStart: { type: 'integer', minimum: 0 }, iEnd: { type: 'integer', minimum: 0 } } };
|
||||||
|
const bodySchemaMember = { type: 'object', properties: { displayName: { type: 'string' } } };
|
||||||
|
const querySchemaMatchHistory = { type: 'object', required: ['game', 'iStart', 'iEnd'], properties: { game: { type: 'string' }, iStart: { type: 'integer', minimum: 0 }, iEnd: { type: 'integer', minimum: 0 } } };
|
||||||
|
const bodySchemaMatchHistory = { type: 'object', required: ['game', 'date', 'myScore'], properties: { game: { type: 'string' }, date: { type: 'integer', minimum: 0 }, opponent: { type: 'string' }, myScore: { type: 'integer', minimum: 0 }, opponentScore: { type: 'integer', minimum: 0 } } };
|
||||||
|
const querySchemaMatchHistoryGame = { type: 'object', required: ['game'], properties: { game: { type: 'string' } } };
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import('fastify').FastifyInstance} fastify
|
|
||||||
* @param {import('fastify').FastifyPluginOptions} options
|
|
||||||
*/
|
|
||||||
export default async function(fastify, options) {
|
export default async function(fastify, options) {
|
||||||
fastify.register(fastifyJWT, {
|
fastify.register(fastifyJWT, {
|
||||||
secret: process.env.JWT_SECRET || '123456789101112131415161718192021',
|
secret: process.env.JWT_SECRET || '123456789101112131415161718192021',
|
||||||
@ -63,8 +151,9 @@ export default async function(fastify, options) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
fastify.register(fastifyCookie);
|
fastify.register(fastifyCookie);
|
||||||
|
fastify.register(multipart, { limits: { fileSize: 2 * 1024 * 1024 + 1 } });
|
||||||
|
|
||||||
fastify.decorate("authenticate", async function(request, reply) {
|
fastify.decorate('authenticate', async function(request, reply) {
|
||||||
try {
|
try {
|
||||||
const jwt = await request.jwtVerify();
|
const jwt = await request.jwtVerify();
|
||||||
request.user = jwt.user;
|
request.user = jwt.user;
|
||||||
@ -73,11 +162,11 @@ export default async function(fastify, options) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.decorate("authenticateAdmin", async function(request, reply) {
|
fastify.decorate('authenticateAdmin', async function(request, reply) {
|
||||||
try {
|
try {
|
||||||
const jwt = await request.jwtVerify();
|
const jwt = await request.jwtVerify();
|
||||||
if (jwt.user !== 'admin') {
|
if (jwt.user !== 'admin') {
|
||||||
throw ("");
|
throw ('You lack administrator privileges');
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reply.code(401).send({ error: 'Unauthorized' });
|
reply.code(401).send({ error: 'Unauthorized' });
|
||||||
@ -85,166 +174,76 @@ export default async function(fastify, options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// GET
|
// GET
|
||||||
fastify.get('/users', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
fastify.get('/users', { preHandler: [fastify.authenticate], schema: { querystring: querySchema } }, async (request, reply) => {
|
||||||
try {
|
return gUsers(request, reply, fastify, getUserData);
|
||||||
const users = getUserData.all();
|
});
|
||||||
|
fastify.get('/users/count', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
||||||
return reply.code(200).send({ users });
|
return gNumberUsers(request, reply, fastify, getNumberUsers);
|
||||||
} catch (err) {
|
|
||||||
fastify.log.error(err);
|
|
||||||
return reply.code(500).send({ error: "Internal server error" });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
fastify.get('/users/:userId', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
fastify.get('/users/:userId', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
||||||
try {
|
return gUser(request, reply, fastify, getUserInfo);
|
||||||
const info = getUserInfo.get(request.params.userId);
|
|
||||||
|
|
||||||
return reply.code(200).send({ info });
|
|
||||||
} catch (err) {
|
|
||||||
fastify.log.error(err);
|
|
||||||
return reply.code(500).send({ error: "Internal server error" });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
fastify.get('/users/:userId/friends', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
fastify.get('/users/:userId/friends', { preHandler: [fastify.authenticate], schema: { querystring: querySchema } }, async (request, reply) => {
|
||||||
try {
|
return gFriends(request, reply, fastify, getUserInfo, getFriends);
|
||||||
const userId = request.params.userId;
|
});
|
||||||
|
fastify.get('/users/:userId/friends/count', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
||||||
if (!getUserInfo.get(userId)) {
|
return gNumberFriends(request, reply, fastify, getUserInfo, getNumberFriends);
|
||||||
return reply.code(404).send({ error: "User does not exist" });
|
});
|
||||||
}
|
fastify.get('/users/:userId/matchHistory', { preHandler: [fastify.authenticate], schema: { querystring: querySchemaMatchHistory } }, async (request, reply) => {
|
||||||
|
return gMatchHistory(request, reply, fastify, getUserInfo, getMatchHistory);
|
||||||
if (userId == request.user || request.user == 'admin') {
|
});
|
||||||
const friends = getFriends.all(userId);
|
fastify.get('/users/:userId/matchHistory/count', { preHandler: [fastify.authenticate], schema: { query: querySchemaMatchHistoryGame } }, async (request, reply) => {
|
||||||
|
return gNumberMatches(request, reply, fastify, getUserInfo, getNumberMatches);
|
||||||
if (!friends) {
|
});
|
||||||
return reply.code(404).send({ error: "User does not have friends D:" });
|
fastify.get('/users/:userId/avatar', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
||||||
}
|
return gAvatar(request, reply, fastify, getUserInfo, getAvatarId, getImage);
|
||||||
return reply.code(200).send({ friends });
|
});
|
||||||
}
|
fastify.get('/ping/:userId', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
||||||
} catch (err) {
|
return gPing(request, reply, fastify, getActivityTime);
|
||||||
fastify.log.error(err);
|
|
||||||
return reply.code(500).send({ error: "Internal server error" });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// POST
|
// POST
|
||||||
fastify.post('/users/:userId', { preHandler: [fastify.authenticateAdmin] }, async (request, reply) => {
|
fastify.post('/users/:userId', { preHandler: [fastify.authenticateAdmin] }, async (request, reply) => {
|
||||||
try {
|
return pUser(request, reply, fastify, getUserInfo, createUser);
|
||||||
const userId = request.params.userId;
|
|
||||||
|
|
||||||
if (getUserInfo.get(userId)) {
|
|
||||||
return reply.code(400).send({ error: "User already exist" });
|
|
||||||
}
|
|
||||||
createUser.run(userId, userId);
|
|
||||||
return reply.code(200).send({ msg: "User created sucessfully" });
|
|
||||||
} catch (err) {
|
|
||||||
fastify.log.error(err);
|
|
||||||
return reply.code(500).send({ error: "Internal server error" });
|
|
||||||
}
|
|
||||||
})
|
|
||||||
fastify.post('/users/:userId/friends', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
|
||||||
try {
|
|
||||||
const userId = request.params.userId;
|
|
||||||
if (request.user != 'admin' && request.user != userId) {
|
|
||||||
return reply.code(401).send({ error: "Unauthorized" });
|
|
||||||
}
|
|
||||||
if (!request.body || !request.body.user) {
|
|
||||||
return reply.code(400).send({ error: "Please specify a user" });
|
|
||||||
}
|
|
||||||
if (!getUserInfo.get(userId)) {
|
|
||||||
return reply.code(404).send({ error: "User does not exist" });
|
|
||||||
}
|
|
||||||
if (!getUserInfo.get(request.body.user)) {
|
|
||||||
return reply.code(404).send({ error: "Friend does not exist" });
|
|
||||||
}
|
|
||||||
if (request.body.user === userId) {
|
|
||||||
return reply.code(400).send({ error: "You can't add yourself :D" });
|
|
||||||
}
|
|
||||||
addFriend.run(userId, request.body.user)
|
|
||||||
return reply.code(200).send({ msg: "Friend added sucessfully" });
|
|
||||||
} catch (err) {
|
|
||||||
fastify.log.error(err);
|
|
||||||
return reply.code(500).send({ error: "Internal server error" });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
fastify.post('/users/:userId/friends/:friendId', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
||||||
|
return pFriend(request, reply, fastify, getUserInfo, getFriend, addFriend);
|
||||||
|
});
|
||||||
|
fastify.post('/users/:userId/matchHistory', { preHandler: [fastify.authenticate], schema: { body: bodySchemaMatchHistory } }, async (request, reply) => {
|
||||||
|
return pMatchHistory(request, reply, fastify, getUserInfo, addMatch, incWinsPong, incLossesPong, incWinsTetris, incLossesTetris);
|
||||||
|
});
|
||||||
|
fastify.post('/users/:userId/avatar', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
||||||
|
return pAvatar(request, reply, fastify, getUserInfo, setAvatarId, postImage);
|
||||||
|
});
|
||||||
|
fastify.post('/ping', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
||||||
|
return pPing(request, reply, fastify, setActivityTime);
|
||||||
|
})
|
||||||
|
|
||||||
// PATCH
|
// PATCH
|
||||||
fastify.patch('/users/:userId/:member', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
fastify.patch('/users/:userId/avatar', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
||||||
try {
|
return uAvatar(request, reply, fastify, getUserInfo, setAvatarId, getAvatarId, deleteAvatarId, postImage, deleteImage);
|
||||||
const userId = request.params.userId;
|
});
|
||||||
if (request.user != 'admin' && request.user != userId) {
|
fastify.patch('/users/:userId/:member', { preHandler: [fastify.authenticate], schema: { body: bodySchemaMember } }, async (request, reply) => {
|
||||||
return reply.code(401).send({ error: "Unauthorized" });
|
return uMember(request, reply, fastify, getUserInfo, changeDisplayName, changeAvatarId);
|
||||||
}
|
});
|
||||||
if (!getUserInfo.get(userId)) {
|
|
||||||
return reply.code(404).send({ error: "User does not exist" });
|
|
||||||
}
|
|
||||||
const member = request.params.member;
|
|
||||||
|
|
||||||
if (member === 'displayName') {
|
|
||||||
if (!request.body || !request.body.displayName) {
|
|
||||||
return reply.code(400).send({ error: "Please specify a displayName" });
|
|
||||||
}
|
|
||||||
|
|
||||||
changeDisplayName.run(request.body.displayName, userId);
|
|
||||||
return reply.code(200).send({ msg: "displayName modified sucessfully" });
|
|
||||||
}
|
|
||||||
return reply.code(400).send({ error: "Member does not exist" })
|
|
||||||
} catch (err) {
|
|
||||||
fastify.log.error(err);
|
|
||||||
return reply.code(500).send({ error: "Internal server error" });
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// DELETE
|
// DELETE
|
||||||
/**
|
|
||||||
* @description Can be used to delete a user from the db
|
|
||||||
*/
|
|
||||||
fastify.delete('/users/:userId', { preHandler: [fastify.authenticateAdmin] }, async (request, reply) => {
|
fastify.delete('/users/:userId', { preHandler: [fastify.authenticateAdmin] }, async (request, reply) => {
|
||||||
try {
|
return dUser(request, reply, fastify, getUserInfo, deleteMatchHistory, deleteFriends, deleteUser);
|
||||||
if (!getUserInfo(request.params.userId)) {
|
|
||||||
return reply.code(404).send({ error: "User does not exist" });
|
|
||||||
}
|
|
||||||
deleteUser.run(request.params.userId);
|
|
||||||
deleteFriends.run(request.params.userId);
|
|
||||||
} catch (err) {
|
|
||||||
fastify.log.error(err);
|
|
||||||
return reply.code(500).send({ error: "Internal server error" });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
fastify.delete('/users/:userId/:member', { preHandler: fastify.authenticate }, async (request, reply) => {
|
fastify.delete('/users/:userId/:member', { preHandler: fastify.authenticate }, async (request, reply) => {
|
||||||
try {
|
return dMember(request, reply, fastify, getUserInfo, changeDisplayName);
|
||||||
const user = request.user;
|
});
|
||||||
const member = request.params.member;
|
fastify.delete('/users/:userId/friends', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
||||||
if (user == 'admin' || user == request.params.userId) {
|
return dFriends(request, reply, fastify, getUserInfo, deleteFriends);
|
||||||
if (member == 'displayName') {
|
|
||||||
changeDisplayName.run("", request.params.userId);
|
|
||||||
return reply.code(200).send({ msg: "displayName cleared sucessfully" });
|
|
||||||
}
|
|
||||||
return reply.code(400).send({ msg: "member does not exist" })
|
|
||||||
} else {
|
|
||||||
return reply.code(401).send({ error: 'You dont have the right to delete this' });
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
fastify.log.error(err);
|
|
||||||
return reply.code(500).send({ error: "Internal server error" });
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
fastify.delete('/users/:userId/friends/:friendId', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
fastify.delete('/users/:userId/friends/:friendId', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
||||||
try {
|
return dFriend(request, reply, fastify, getUserInfo, getFriend, deleteFriend);
|
||||||
const userId = request.params.userId;
|
});
|
||||||
const friendId = request.params.friendId;
|
fastify.delete('/users/:userId/matchHistory', { preHandler: [fastify.authenticate], schema: { query: querySchemaMatchHistoryGame } }, async (request, reply) => {
|
||||||
if (!getUserInfo.get(userId)) {
|
return dMatchHistory(request, reply, fastify, getUserInfo, deleteMatchHistory, deleteStatsPong, deleteStatsTetris);
|
||||||
return reply.code(404).send({ error: "User does not exist" });
|
});
|
||||||
}
|
fastify.delete('/users/:userId/avatar', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
||||||
if (request.user != 'admin' && request.user != userId) {
|
return dAvatar(request, reply, fastify, getUserInfo, getAvatarId, deleteAvatarId, deleteImage);
|
||||||
return reply.code(401).send({ error: "Unauthorized" });
|
|
||||||
}
|
|
||||||
deleteFriend.run(userId, friendId);
|
|
||||||
return reply.code(200).send({ msg: "Friend remove sucessfully" });
|
|
||||||
} catch (err) {
|
|
||||||
fastify.log.error(err);
|
|
||||||
return reply.code(500).send({ error: "Internal server error" });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/api/user/gAvatar.js
Normal file
20
src/api/user/gAvatar.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
export async function gAvatar(request, reply, fastify, getUserInfo, getAvatarId, getImage) {
|
||||||
|
try {
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!getUserInfo.get(userId)) {
|
||||||
|
return reply.code(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
const imageId = getAvatarId.get(userId);
|
||||||
|
if (imageId.avatarId === -1) {
|
||||||
|
return reply.code(404).send({ error: "User does not have an avatar" });
|
||||||
|
}
|
||||||
|
const image = getImage.get(imageId.avatarId);
|
||||||
|
if (!image) {
|
||||||
|
return reply.code(404).send({ error: "Avatar does not exist" });
|
||||||
|
}
|
||||||
|
return reply.code(200).type(image.mimeType).send(image.data);
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/api/user/gFriends.js
Normal file
26
src/api/user/gFriends.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
export async function gFriends(request, reply, fastify, getUserInfo, getFriends) {
|
||||||
|
try {
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!getUserInfo.get(userId)) {
|
||||||
|
return reply.code(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
const { iStart, iEnd } = request.query;
|
||||||
|
if (Number(iEnd) < Number(iStart)) {
|
||||||
|
return reply.code(400).send({ error: "Starting index cannot be strictly inferior to ending index" });
|
||||||
|
}
|
||||||
|
const friendNames = getFriends.all(userId, Number(iEnd) - Number(iStart), Number(iStart));
|
||||||
|
if (!friendNames.length) {
|
||||||
|
return reply.code(404).send({ error: "No friends exist in the selected range" });
|
||||||
|
}
|
||||||
|
const promises = friendNames.map(async (friendName) => {
|
||||||
|
const friend = getUserInfo.get(friendName.friendName);
|
||||||
|
friendName.friendDisplayName = friend.displayName;
|
||||||
|
return friendName;
|
||||||
|
});
|
||||||
|
const friends = await Promise.all(promises);
|
||||||
|
return reply.code(200).send({ friends });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/api/user/gMatchHistory.js
Normal file
37
src/api/user/gMatchHistory.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
export async function gMatchHistory(request, reply, fastify, getUserInfo, getMatchHistory) {
|
||||||
|
try {
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!getUserInfo.get(userId)) {
|
||||||
|
return reply.code(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
const { game, iStart, iEnd } = request.query;
|
||||||
|
if (game !== 'pong' && game !== 'tetris') {
|
||||||
|
return reply.code(400).send({ error: "Specified game does not exist" });
|
||||||
|
}
|
||||||
|
if (Number(iEnd) < Number(iStart)) {
|
||||||
|
return reply.code(400).send({ error: "Starting index cannot be strictly inferior to ending index" });
|
||||||
|
}
|
||||||
|
const matchHistoryId = getMatchHistory.all(game, userId, Number(iEnd) - Number(iStart), Number(iStart));
|
||||||
|
if (!matchHistoryId.length) {
|
||||||
|
return reply.code(404).send({ error: "No matches exist in the selected range" });
|
||||||
|
}
|
||||||
|
const promises = matchHistoryId.map(async (match) => {
|
||||||
|
const res = await fetch(`http://localhost:3003/${match.matchId}`, { method: "GET" });
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error('Failed to fetch item from blockchain API');
|
||||||
|
}
|
||||||
|
const resJson = await res.json();
|
||||||
|
resJson.score.date = match.date;
|
||||||
|
if (resJson.score.p2 === "" && resJson.score.p2Score === 0) {
|
||||||
|
delete resJson.score.p2;
|
||||||
|
delete resJson.score.p2Score;
|
||||||
|
}
|
||||||
|
return resJson;
|
||||||
|
});
|
||||||
|
const matchHistory = await Promise.all(promises);
|
||||||
|
return reply.code(200).send({ matchHistory });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/api/user/gNumberFriends.js
Normal file
13
src/api/user/gNumberFriends.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export async function gNumberFriends(request, reply, fastify, getUserInfo, getNumberFriends) {
|
||||||
|
try {
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!getUserInfo.get(userId)) {
|
||||||
|
return reply.code(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
const row = getNumberFriends.get(userId);
|
||||||
|
return reply.code(200).send({ n_friends: row.n_friends });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/api/user/gNumberMatches.js
Normal file
17
src/api/user/gNumberMatches.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
export async function gNumberMatches(request, reply, fastify, getUserInfo, getNumberMatches) {
|
||||||
|
try {
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!getUserInfo.get(userId)) {
|
||||||
|
return reply.code(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
const { game } = request.query;
|
||||||
|
if (game !== 'pong' && game !== 'tetris') {
|
||||||
|
return reply.code(400).send({ error: "Specified game does not exist" });
|
||||||
|
}
|
||||||
|
const row = getNumberMatches.get(game, userId);
|
||||||
|
return reply.code(200).send({ n_matches: row.n_matches });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/api/user/gNumberUsers.js
Normal file
9
src/api/user/gNumberUsers.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export async function gNumberUsers(request, reply, fastify, getNumberUsers) {
|
||||||
|
try {
|
||||||
|
const row = getNumberUsers.get();
|
||||||
|
return reply.code(200).send({ n_users: row.n_users });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/api/user/gPing.js
Normal file
28
src/api/user/gPing.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* @param {import('fastify').FastifyRequest} request
|
||||||
|
* @param {import('fastify').FastifyReply} reply
|
||||||
|
* @param {import('fastify').FastifyInstance} fastify
|
||||||
|
*/
|
||||||
|
export async function gPing(request, reply, fastify, getActivityTime) {
|
||||||
|
try {
|
||||||
|
const user = request.params.userId;
|
||||||
|
const time = getActivityTime.get(user);
|
||||||
|
|
||||||
|
if (!time || !time.time) {
|
||||||
|
return reply.code(404).send({ error: "User not found or no activity time recorded" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastSeenTime = new Date(time.time);
|
||||||
|
const now = new Date();
|
||||||
|
const oneMinuteAgo = new Date(now.getTime() - 60000); // 60,000 ms = 1 minute
|
||||||
|
|
||||||
|
const isActiveInLastMinute = lastSeenTime >= oneMinuteAgo;
|
||||||
|
|
||||||
|
return reply.code(200).send({
|
||||||
|
isLogged: isActiveInLastMinute
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/api/user/gUser.js
Normal file
13
src/api/user/gUser.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export async function gUser(request, reply, fastify, getUserInfo) {
|
||||||
|
try {
|
||||||
|
const userId = request.params.userId;
|
||||||
|
const userInfo = getUserInfo.get(userId);
|
||||||
|
if (!userInfo) {
|
||||||
|
return reply.code(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
return reply.code(200).send({ username: userInfo.username, displayName: userInfo.displayName, pong: { wins: userInfo.pongWins, losses: userInfo.pongLosses }, tetris: { wins: userInfo.tetrisWins, losses: userInfo.tetrisLosses } });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/api/user/gUsers.js
Normal file
28
src/api/user/gUsers.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
export async function gUsers(request, reply, fastify, getUserData) {
|
||||||
|
try {
|
||||||
|
const { iStart, iEnd } = request.query;
|
||||||
|
if (Number(iEnd) < Number(iStart)) {
|
||||||
|
return reply.code(400).send({ error: "Starting index cannot be strictly inferior to ending index" });
|
||||||
|
}
|
||||||
|
const users = getUserData.all(Number(iEnd) - Number(iStart), Number(iStart));
|
||||||
|
if (!users.length) {
|
||||||
|
return reply.code(404).send({ error: "No users exist in the selected range" });
|
||||||
|
}
|
||||||
|
const usersFormat = users.map(obj => ({
|
||||||
|
username: obj.username,
|
||||||
|
displayName: obj.displayName,
|
||||||
|
pong: {
|
||||||
|
wins: obj.pongWins,
|
||||||
|
losses: obj.pongLosses
|
||||||
|
},
|
||||||
|
tetris: {
|
||||||
|
wins: obj.tetrisWins,
|
||||||
|
losses: obj.tetrisLosses
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
return reply.code(200).send({ usersFormat });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
39
src/api/user/pAvatar.js
Normal file
39
src/api/user/pAvatar.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import sharp from 'sharp';
|
||||||
|
|
||||||
|
export async function pAvatar(request, reply, fastify, getUserInfo, setAvatarId, postImage) {
|
||||||
|
try {
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!getUserInfo.get(userId)) {
|
||||||
|
return reply.cose(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
const parts = request.parts();
|
||||||
|
for await (const part of parts) {
|
||||||
|
if (part.file) {
|
||||||
|
let size = 0;
|
||||||
|
const chunks = [];
|
||||||
|
for await (const chunk of part.file) {
|
||||||
|
size += chunk.length;
|
||||||
|
chunks.push(chunk);
|
||||||
|
}
|
||||||
|
if (size === 5 * 1024 * 1024 + 1) {
|
||||||
|
return reply.code(400).send({ error: "File too large" });
|
||||||
|
}
|
||||||
|
const buffer = Buffer.concat(chunks);
|
||||||
|
if (!part.filename || part.filename.trim() === '') {
|
||||||
|
return reply.code(400).send({ error: "Missing filename" });
|
||||||
|
}
|
||||||
|
if (!part.mimetype || part.mimetype.trim() === '') {
|
||||||
|
return reply.code(400).send({ error: "Missing mimetype" });
|
||||||
|
}
|
||||||
|
const webpBuffer = await sharp(buffer).toFormat('webp').toBuffer();
|
||||||
|
const imageId = postImage.run(part.filename, part.mimetype, webpBuffer);
|
||||||
|
setAvatarId.run(imageId.lastInsertRowid, userId);
|
||||||
|
return reply.code(200).send({ msg: "Avatar uploaded successfully" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reply.code(400).send({ error: "No avatar uploaded" });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/api/user/pFriend.js
Normal file
29
src/api/user/pFriend.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
export async function pFriend(request, reply, fastify, getUserInfo, getFriend, addFriend) {
|
||||||
|
try {
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!request.user) {
|
||||||
|
return reply.code(400).send({ error: "Please specify a user" });
|
||||||
|
}
|
||||||
|
if (request.user !== 'admin' && request.user !== userId) {
|
||||||
|
return reply.code(401).send({ error: "Unauthorized" });
|
||||||
|
}
|
||||||
|
if (!getUserInfo.get(userId)) {
|
||||||
|
return reply.code(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
const friendId = request.params.friendId;
|
||||||
|
if (!getUserInfo.get(friendId)) {
|
||||||
|
return reply.code(404).send({ error: "Friend does not exist" });
|
||||||
|
}
|
||||||
|
if (friendId === userId) {
|
||||||
|
return reply.code(400).send({ error: "You can't add yourself :D" });
|
||||||
|
}
|
||||||
|
if (getFriend.get(userId, friendId)) {
|
||||||
|
return reply.code(400).send({ error: "Friend already added" });
|
||||||
|
}
|
||||||
|
addFriend.run(userId, friendId)
|
||||||
|
return reply.code(200).send({ msg: "Friend added successfully" });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
66
src/api/user/pMatchHistory.js
Normal file
66
src/api/user/pMatchHistory.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
async function fetchSave(request, reply, userId, addMatch) {
|
||||||
|
let opponentName = '';
|
||||||
|
let opponentScore = 0;
|
||||||
|
if (request.body.opponent && request.body.opponentScore) {
|
||||||
|
opponentName = request.body.opponent;
|
||||||
|
opponentScore = request.body.opponentScore;
|
||||||
|
}
|
||||||
|
const res = await fetch('http://localhost:3003/', { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ p1: userId, p2: opponentName, p1Score: request.body.myScore, p2Score: opponentScore }) });
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error('Internal server error');
|
||||||
|
}
|
||||||
|
const data = await res.json();
|
||||||
|
addMatch.run(request.body.game, request.body.date, userId, opponentName, data.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function pMatchHistory(request, reply, fastify, getUserInfo, addMatch, incWinsPong, incLossesPong, incWinsTetris, incLossesTetris) {
|
||||||
|
try {
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!request.user) {
|
||||||
|
return reply.code(400).send({ error: "Please specify a user" });
|
||||||
|
}
|
||||||
|
if (request.user !== 'admin' && request.user !== userId) {
|
||||||
|
return reply.code(401).send({ error: "Unauthorized" });
|
||||||
|
}
|
||||||
|
if (request.body.game !== 'pong' && request.body.game !== 'tetris') {
|
||||||
|
return reply.code(400).send({ error: "Specified game does not exist" });
|
||||||
|
}
|
||||||
|
if (request.body.game === 'pong' && (!request.body.opponent || !request.body.opponentScore)) {
|
||||||
|
return reply.code(400).send({ error: "Game requires two players" });
|
||||||
|
}
|
||||||
|
if (!getUserInfo.get(userId)) {
|
||||||
|
return reply.code(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
if (request.body.opponent) {
|
||||||
|
if (!getUserInfo.get(request.body.opponent)) {
|
||||||
|
return reply.code(404).send({ error: "Opponent does not exist" });
|
||||||
|
}
|
||||||
|
if (request.body.opponent === userId) {
|
||||||
|
return reply.code(400).send({ error: "Do you have dementia ? You cannot have played a match against yourself gramps" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await fetchSave(request, reply, userId, addMatch);
|
||||||
|
if (request.body.game === 'pong') {
|
||||||
|
if (request.body.myScore > request.body.opponentScore) {
|
||||||
|
incWinsPong.run(userId);
|
||||||
|
incLossesPong.run(request.body.opponent);
|
||||||
|
} else if (request.body.myScore < request.body.opponentScore) {
|
||||||
|
incWinsPong.run(request.body.opponent);
|
||||||
|
incLossesPong.run(userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (request.body.game === 'tetris' && request.body.opponent && request.body.opponentScore) {
|
||||||
|
if (request.body.myScore > request.body.opponentScore) {
|
||||||
|
incWinsTetris.run(userId);
|
||||||
|
incLossesTetris.run(request.body.opponent);
|
||||||
|
} else if (request.body.myScore < request.body.opponentScore) {
|
||||||
|
incWinsTetris.run(request.body.opponent);
|
||||||
|
incLossesTetris.run(userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reply.code(200).send({ msg: "Match successfully saved to the blockchain" });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/api/user/pPing.js
Normal file
21
src/api/user/pPing.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* @param {import('fastify').FastifyRequest} request
|
||||||
|
* @param {import('fastify').FastifyReply} request
|
||||||
|
* @param {import('fastify').Fastify} fastify
|
||||||
|
*/
|
||||||
|
export async function pPing(request, reply, fastify, setActivityTime) {
|
||||||
|
try {
|
||||||
|
const user = request.user;
|
||||||
|
const currentTime = new Date().toISOString();
|
||||||
|
|
||||||
|
setActivityTime.run(user, currentTime);
|
||||||
|
|
||||||
|
return reply.code(200)
|
||||||
|
.send({
|
||||||
|
msg: "last seen time updated successfully"
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/api/user/pUser.js
Normal file
22
src/api/user/pUser.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
export async function pUser(request, reply, fastify, getUserInfo, createUser) {
|
||||||
|
try {
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!request.user || !request.user.user) {
|
||||||
|
return reply.code(400).send({ error: "Please specify a user" });
|
||||||
|
}
|
||||||
|
if (request.user.user !== 'admin') {
|
||||||
|
return reply.code(401).send({ error: "Unauthorized" });
|
||||||
|
}
|
||||||
|
if (getUserInfo.get(userId)) {
|
||||||
|
return reply.code(400).send({ error: "User already exist" });
|
||||||
|
}
|
||||||
|
if (!request.body || !request.body.displayName) {
|
||||||
|
return reply.code(400).send({ error: "Please specify a display name" });
|
||||||
|
}
|
||||||
|
createUser.run(userId, request.body.displayName);
|
||||||
|
return reply.code(200).send({ msg: "User created successfully" });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/api/user/uAvatar.js
Normal file
45
src/api/user/uAvatar.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import sharp from 'sharp';
|
||||||
|
|
||||||
|
export async function uAvatar(request, reply, fastify, getUserInfo, setAvatarId, getAvatarId, deleteAvatarId, postImage, deleteImage) {
|
||||||
|
try {
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!getUserInfo.get(userId)) {
|
||||||
|
return reply.cose(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
deleteAvatarId.run(userId);
|
||||||
|
const parts = request.parts();
|
||||||
|
for await (const part of parts) {
|
||||||
|
if (part.file) {
|
||||||
|
let size = 0;
|
||||||
|
const chunks = [];
|
||||||
|
for await (const chunk of part.file) {
|
||||||
|
size += chunk.length;
|
||||||
|
chunks.push(chunk);
|
||||||
|
}
|
||||||
|
if (size === 5 * 1024 * 1024 + 1) {
|
||||||
|
return reply.code(400).send({ error: "File too large" });
|
||||||
|
}
|
||||||
|
const buffer = Buffer.concat(chunks);
|
||||||
|
if (!part.filename || part.filename.trim() === '') {
|
||||||
|
return reply.code(400).send({ error: "Missing filename" });
|
||||||
|
}
|
||||||
|
if (!part.mimetype || part.mimetype.trim() === '') {
|
||||||
|
return reply.code(400).send({ error: "Missing mimetype" });
|
||||||
|
}
|
||||||
|
const webpBuffer = await sharp(buffer).toFormat('webp').toBuffer();
|
||||||
|
const imageId = postImage.run(part.filename, part.mimetype, webpBuffer);
|
||||||
|
const oldImageId = getAvatarId.get(userId);
|
||||||
|
if (oldImageId.avatarId !== -1) {
|
||||||
|
deleteImage.run(oldImageId.avatarId);
|
||||||
|
deleteAvatarId.run(userId);
|
||||||
|
}
|
||||||
|
setAvatarId.run(imageId.lastInsertRowid, userId);
|
||||||
|
return reply.code(200).send({ msg: "Avatar modified successfully" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reply.code(400).send({ error: "No avatar modified" });
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/api/user/uMember.js
Normal file
26
src/api/user/uMember.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
export async function uMember(request, reply, fastify, getUserInfo, changeDisplayName, changeAvatarId) {
|
||||||
|
try {
|
||||||
|
const userId = request.params.userId;
|
||||||
|
if (!request.user) {
|
||||||
|
return reply.code(400).send({ error: "Please specify a user" });
|
||||||
|
}
|
||||||
|
if (request.user !== 'admin' && request.user !== userId) {
|
||||||
|
return reply.code(401).send({ error: "Unauthorized" });
|
||||||
|
}
|
||||||
|
if (!getUserInfo.get(userId)) {
|
||||||
|
return reply.code(404).send({ error: "User does not exist" });
|
||||||
|
}
|
||||||
|
const member = request.params.member;
|
||||||
|
if (member === 'displayName') {
|
||||||
|
if (!request.body || !request.body.displayName) {
|
||||||
|
return reply.code(400).send({ error: "Please specify a displayName" });
|
||||||
|
}
|
||||||
|
changeDisplayName.run(request.body.displayName, userId);
|
||||||
|
return reply.code(200).send({ msg: "Display name modified successfully" });
|
||||||
|
}
|
||||||
|
return reply.code(400).send({ error: "Member does not exist" })
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
return reply.code(500).send({ error: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -29,7 +29,7 @@ async function loadContract() {
|
|||||||
async function callGetScore(id) {
|
async function callGetScore(id) {
|
||||||
try {
|
try {
|
||||||
const contract = await loadContract();
|
const contract = await loadContract();
|
||||||
const result = await contract.getScore(id);
|
const result = await contract.getScore(id - 1);
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error calling view function:', error);
|
console.error('Error calling view function:', error);
|
||||||
@ -54,8 +54,9 @@ async function callAddScore(p1, p2, p1Score, p2Score) {
|
|||||||
const tx = await contract.addScore(p1, p2, p1Score, p2Score);
|
const tx = await contract.addScore(p1, p2, p1Score, p2Score);
|
||||||
console.log('Transaction sent:', tx.hash);
|
console.log('Transaction sent:', tx.hash);
|
||||||
await tx.wait(); // Wait for the transaction to be mined
|
await tx.wait(); // Wait for the transaction to be mined
|
||||||
|
const id = await callLastId();
|
||||||
console.log('Transaction confirmed');
|
console.log('Transaction confirmed');
|
||||||
return tx;
|
return { tx, id };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error calling addScore function:', error);
|
console.error('Error calling addScore function:', error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
Reference in New Issue
Block a user