radusalagean / open-live-trivia-api

Server-side part of the Open Live Trivia project

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Update October 14, 2020: Both the server and the client app are now retired. Feel free to use the sources if you want to deploy your own server-client configuration of this project.

Build Status

open-live-trivia-api

Open Live Trivia is an open-source multiplayer trivia game. This repo hosts the server-side part of the project. For the corresponding client app, please check this link.

Overview

Game rules

  • An entry is displayed every round
  • Every player has 3 free attempts available to submit the correct answer
  • Additional attempts will cost 1 point
  • The answers are case insensitive
  • Every 15 seconds, a new random character is revealed from the answer (defined as a split)
  • Entries range from 10 to 100 points in value (based on their difficulty)
  • Their value decreases as more characters are revealed
  • The first player to submit the correct answer wins the prize and the round is over

Other features

  • Users are able to request the game leaderboard
  • There are 3 right levels that a user can have:
    • Regular - type 0
    • Moderator - type 1
    • Admin - type 2
  • Users are able to report entries which they consider invalid / inappropriate while playing. Those can be reviewed later and then banned / dismissed by moderators or the admin.
  • The admin is the only one able to grant or revoke extra rights to users
  • All registered users are able to delete their accounts permanently

Use Case Diagram

Under the hood

Authentication

Player authentication is achieved through Firebase Auth. The client app will send a token to the server that is valid for one hour. That token is automatically refreshed by the client app when needed, so tokens sent to the server should always be up to date. Upon receiving an authorized request from the client app, the server sends that token through Firebase Admin in order to receive a decrypted payload that contains necessary info such as uid (an unique id associated with the Google Account used to authenticate) and the exp field (the expiration date of the currently used token). The following activity diagram showcases the authentication flow:

Activity Diagram for Authentication View the full resolution version

Game

The communication of game-specific events between the server and the client is based on socket.io. This approach facilitates real-time bidirectional communication between the two systems, which is ideal for the purpose of an online multiplayer game. The following activity diagram showcases the flow of game-specific events between the client and the server, based on the rules mentioned above:

Activity Diagram for the Game View the full resolution version

Usage

Base URL: https://releasetracker.app/open-live-trivia-api/v1/

For requests marked as πŸ”’, you need to have the Authorization header set with your Firebase idToken.

For requests marked as πŸ—, the results will be paginated and pagination-specific query string can be passed to specify the page number. Example: https://releasetracker.app/open-live-trivia-api/v1/user/leaderboard?page=2.

For all POST / PUT requests that have a json body provided, you need to set the application/json value for the Content-Type header.

In the documentation, certain attributes displayed with a colon in the beginning (e.g. :id) need to be replaced with a corresponding value when you are making the call.

Profile image access url: https://releasetracker.app/open-live-trivia-api-static/user-thumbnails/:filename, where:

  • filename = userId + .png

Example: https://releasetracker.app/open-live-trivia-api-static/user-thumbnails/5d1f77e3adc09e1fe5a9aa9e.png

Socket-based events πŸ”Œ

Access url: https://releasetracker.app/open-live-trivia-api/socket.io

Client πŸ“£ -> 🎧 Server events

Event Description
authentication The first event sent by the client after socket connection. Pass the Firebase idToken in order to authenticate.
ATTEMPT An attempt to submit the correct answer for the ongoing round
REACTION An emoji that will broadcast to all the current players
REPORT_ENTRY Report the ongoing entry of this round for further review by moderators or admin
REQUEST_PLAYER_LIST Request the list of currently playing users

Note: Events written in CAPS are game-specific events.

  • Example bodies:
    • authentication:
    {
      "idToken": "YOUR_ID_TOKEN"
    }
    • ATTEMPT:
    {
      "message": "Funcrusher Plus"
    }
    • REACTION
    {
      "emoji": "πŸ˜‡"
    }
    Note: The events not listed in the examples above don't require request bodies.

Server πŸ“£ -> 🎧 Client events

Event Description
authenticated Sent to the client which authenticated successfully
unauthorized Sent to the client which failed to authenticate
WELCOME The first event sent by the server when a client is connected and authenticated
PEER_JOIN Broadcasted to all connected clients when a new client is connected and successfully authenticated
PEER_ATTEMPT Broadcasted to all connected clients when a client sent an attempt to the server
INSUFFICIENT_FUNDS Sent to the client who previously sent an attempt that he was unable to pay for
COIN_DIFF Sent to the client who previously sent an attempt if there was a change in his coin bank (like the price paid for the attempt and / or the reward received for the correct answer)
PEER_REACTION Broadcasted to all connected clients when a client sent a reaction to the server
ROUND Broadcasted to all connected clients when a new round starts
SPLIT Broadcasted to all connected clients when a new split starts
REVEAL Broadcasted to all connected clients when the last split finishes and no one submitted the right answer
ENTRY_REPORTED_OK Sent to the client who previously reported an entry, if the entry report was saved successfully
ENTRY_REPORTED_ERROR Sent to the client who previously reported an entry, if the entry report failed to save
PLAYER_LIST Sent to the client who previously requested a list of all the current players
PEER_LEFT Broadcasted to all connected clients when a client left the game session
  • Examples bodies:
    • unauthorized:
    {
      "message": "User id not found for the specified token, you need to register first"
    }
    • WELCOME
    {
      "gameState": 1,
      "userCoins": 100,
      "entryId": 121885,
      "category": "we governed that state",
      "clue": "Pat Brown,Pete Wilson",
      "answer": "C____o___a",
      "currentValue": 14,
      "elapsedSplitSeconds": 7,
      "totalSplitSeconds": 15,
      "freeAttemptsLeft": 2,
      "entryReported": false,
      "players": 1,
      "attempts": [
        {
          "userId": "5d1f2052a93b8d38b87750d3",
          "username": "Radu",
          "message": "test attempt",
          "correct": false
        }
      ]
    }
    • PEER_JOIN
    {
      "userId": "5d1f2052a93b8d38b87750d3",
      "username": "Radu"
    }
    • PEER_ATTEMPT
    {
      "userId": "5d1f2052a93b8d38b87750d3",
      "username": "Radu",
      "message": "test attempt",
      "correct": false
    }
    • COIN_DIFF
    {
      "coinDiff": 6
    }
    • PEER_REACTION
    {
      "userId": "5d1f2052a93b8d38b87750d3",
      "username": "Radu",
      "emoji": "πŸ‘Ύ"
    }
    • ROUND
    {
      "entryId": 121885,
      "category": "we governed that state",
      "clue": "Pat Brown,Pete Wilson",
      "answer": "__________",
      "currentValue": 20
    }
    • SPLIT
    {
      "answer": "C_li_ornia",
      "currentValue": 4
    }
    • REVEAL
    {
      "answer": "California"
    }
    • PLAYER_LIST
    {
      "players": [
        {
          "_id": "5d1f2052a93b8d38b87750d3",
          "username": "Radu",
          "rights": 0,
          "coins": 106,
          "joined": "2019-07-05T10:41:44.203Z"
        }
      ]
    }
    • PEER_LEFT
    {
      "userId": "5d1f2052a93b8d38b87750d3",
      "username": "Radu" 
    }

Users πŸ‘€

Register πŸ”’

POST user/register

Request Body Parameters:

  • username - String (required)

Example Request Body:

{
  "username": "Radu"
}

Example Response Body 201 CREATED:

{
  "_id": "5d1f2052a93b8d38b87750d3",
  "username": "Radu",
  "rights": 0,
  "coins": 100,
  "joined": "2019-07-05T10:41:44.203Z"
}

Specific restrictions:

  • Max username length: 50 characters
  • Usernames must be unique (otherwise, 409 CONFLICT will be returned)
  • Usernames are considered unique on a case insensitive basis (e.g. if Radu is registered, trying to register radu will result in a conflict error)
  • Note: spaces are allowed in usernames

Login πŸ”’

POST user/login

Example Response Body 200 OK:

{
  "_id": "5d1f2052a93b8d38b87750d3",
  "username": "Radu",
  "rights": 0,
  "coins": 100,
  "joined": "2019-07-05T10:41:44.203Z"
}

Delete user πŸ”’

DELETE user/delete

Example Response Body 200 OK:

{
  "message": "Account removed successfully"
}

Specific restrictions:

  • Admins are not allowed to remove their accounts

Username availability

GET user/availability/:username

Request URL parameters:

  • username - candidate username (required)

Response codes:

  • 200 OK - Username is available for registration
  • 409 CONFLICT - Username is unavailable for registration

Update user rights πŸ”’ ADMIN

PUT user/rights/:user_id/:rights_level

Request URL parameters:

  • user_id - the id of the target user (required)
  • rights_level - one of the following values: (required)
    • 0 - Regular
    • 1 - Moderator
    • 2 - Admin

Example Response Body 200 OK:

{
  "message": "Chad's rights changed to type 1"
}

Leaderboard πŸ”’ πŸ—

GET user/leaderboard

Example Response Body 200 OK:

{
  "page": 1,
  "pages": 1,
  "itemsCount": 1,
  "perPage": 20,
  "items": [
    {
      "_id": "5d1f2968a93b8d38b87750d4",
      "rights": 2,
      "coins": 100,
      "lastSeen": "2019-07-05T10:41:44.203Z",
      "joined": "2019-07-05T10:41:44.203Z",
      "username": "Radu",
      "playing": true
    }
  ]
}

Me πŸ”’

GET user/me

Example Response Body 200 OK:

{
  "_id": "5d1f2052a93b8d38b87750d3",
  "username": "Radu",
  "rights": 0,
  "coins": 100,
  "joined": "2019-07-05T10:41:44.203Z"
}

Entry reports 🚩

Query reports πŸ”’ MODERATOR / ADMIN πŸ—

GET reported_entry/get_reports

Request URL query string parameters:

  • banned - Boolean (optional)

Example Response Body 200 OK:

{
  "page": 1,
  "pages": 1,
  "itemsCount": 1,
  "perPage": 10,
  "items": [
    {
      "reporters": [
        {
          "_id": "5d1f2968a93b8d38b87750d4",
          "username": "Radu"
        }
      ],
      "banned": false,
      "_id": "5d1f379a78c6e7342c49488e",
      "lastReported": "2019-07-05T11:42:18.216Z",
      "entryId": 34770,
      "category": "life science",
      "clue": "The monera kingdom consists of bacteria & the blue-green species of this",
      "answer": "Algae"
    }
  ]
}

Note: Entries currently running in the game will be excluded from the results.

Ban reported entry πŸ”’ MODERATOR / ADMIN

PUT reported_entry/ban/:report_id

Request URL parameters:

  • report_id - the id of the target report (required)

Example Response Body 200 OK:

{
  "message": "The entry has been banned successfully"
}

Unban reported entry πŸ”’ MODERATOR / ADMIN

PUT reported_entry/unban/:report_id

Request URL parameters:

  • report_id - the id of the target report (required)

Example Response Body 200 OK:

{
  "message": "The entry has been unbanned successfully"
}

Dismiss reported entry πŸ”’ MODERATOR / ADMIN

PUT reported_entry/dismiss/:report_id

Request URL parameters:

  • report_id - the id of the target report (required)

Example Response Body 200 OK:

{
  "message": "Entry report dismissed successfully"
}

System βš™οΈ

Disconnect everyone πŸ”’ ADMIN

POST system/disconnect_everyone

Example Response Body 200 OK:

{
  "message": "Sent the disconnect signal to 10 clients"
}

Info

GET system/info

Example Response Body 200 OK:

{
  "serverVersion": "1.0.0",
  "minAppVersionCode": 1,
  "latestAppVersionCode": 1,
  "isTriviaServiceRunning": true
}

License

Apache License 2.0, see the LICENSE file for details.

About

Server-side part of the Open Live Trivia project

License:Apache License 2.0


Languages

Language:JavaScript 100.0%