Skip to content

Technology Stack

Jake edited this page Jul 1, 2023 · 9 revisions

This section explains the technology used in the Major Manager Server and briefly shows how they are used

  • Fast, unopinionated, minimalist web framework for Node.js ideal to use for building RESTful APIs
  • Widely popular framework that is well tested and documented
  • Express provides a middleware system that can be used to execute repeated functionality that occurs between receiving and handling requests. For example, when scores are uploaded for a particular Tournament, Express' middleware confirms that the User uploading the scores is logged in and has been assigned the role of Admin. If these checks both pass, we handle the POST request by executing the uploadPlayerScores function (user.routes.js)
app.post(
  '/api/v1/upload_player_scores/:id',
  [authJwt.verifyToken, authJwt.isAdmin],
  adminController.uploadPlayerScores,
);
  • The major-manager-server uses body-parser, a package used with Express' middleware to parse incoming request. Express with body-parser enables routes, URL parameters and request payloads to be easily defined, read and referenced. The above POST request receives the id of the Tournament that is being updated as a parameter in the request URL via :id. This parameter can then be referenced in the uploadPlayerScores function by calling req.params.id. The above request also receives a JSON object with Players scores. This data can be accessed via a reference to req.body.playerData as seen below in the admin controller (admin.controller.js).
exports.uploadPlayerScores = (req, res) => {
  Admin.addPlayersToPlayersTable(req.body.playerData, (addPlayersErr, addPlayersData) => {
    if (addPlayersErr) {
      res.status(500).send({
        message: 'Error uploading players to players table',
      });
      return;
    }

    Admin.addPlayersToTournamentTable(addPlayersData, req.params.id, req.body.round,
      (addTournamentErr, addTournamentData) => {

Authentication and Authorization

  • The major-manager-server uses JSON Web Tokens for authentication and authorization
  • When a User signs in and their password is confirmed, a token is created which is then sent back to the client. The client then stores this token in their localStorage. In the future, when the client wishes to access information that requires a User to be logged in, the client sends the assigned token to the major-manager-server in lieu of their username and password. To create this token, we use the jsonwebtoken api: (auth.controller.js)
const jwt = require('jsonwebtoken');
const token = jwt.sign({ id: data.id }, config.secret, {
  expiresIn: 604800, // 1 week
});
  • major-manager-server verify's the validity of a token through Express' middleware when necessary. For example, when uploading Player scores for a particular Tournament, the server receives a request to /api/v1/upload_player_scores/:id then verify's the User's token because a User updating scores has to be logged in. authJwt.js
const verifyToken = (req, res, next) => {
  const token = req.headers['x-access-token'];

  if (!token) {
    res.status(403).send({
      message: 'No token provided',
    });
    return;
  }

  jwt.verify(token, config.secret, (err, decoded) => {
    if (err) {
      res.status(401).send({
        message: 'Unauthorized - Session may be expired. Log out and back in',
      });
      return;
    }
    req.userId = decoded.id;
    next();
  });
};
  • To confirm the validity of the provided token, the jsonwebtoken's verify method is passed a token and the secret key
  • The bcrypt library is used for all of the major-manager-server's hashing needs. Passwords stored in the database are hashed with bcrypt's hashSync function. Two passwords can be compared with bcrypt's compareSync function.
const user = new User({
  team_name: req.body.team_name,
  email: req.body.email,
  password: bcrypt.hashSync(req.body.password, 8),
});
const passwordIsValid = bcrypt.compareSync(req.body.password, data.password);

Roles

  • User's have roles assigned to them in order to control read and write access throughout the application
  • Currently, the two roles a User can be assigned are Admin and User
  • An Admin is able to view the Admin page where one can create Tournaments, add Players and their scores to a Tournament, add a winning team to the League Leaderboard table and reset a User's password
  • Users are able to view the League Leaderboard page, view their Profile page and view the Settings page

Data Storage

  • The major-manager-server uses a MySQL database to store all Tournament, Player, User and Role information
  • MySQL databases are known for being stable, scalable and widely used, making it a safe choice for everything the major-manager-server needs
  • Tables used:
players
  • Stores a Players first and last name
players_tournaments
  • Stores a Player's score data for a particular Tournament. The fields in this table are: Player ID, Tournament ID, Player's tier, score and if they made the cut
roles
  • The roles table holds all the different roles used within the application (User, Admin)
tournaments
  • The tournaments table holds the information for a Tournament (ID, Name, Start Date, Round)
user_roles
  • The user_roles table stores each User and what roles they are assigned to
users_tournaments
  • Each row in the users_tournaments table represents a Tournament that a User has signed up for. It holds a unique ID, Tournament ID and User ID
user_tournament_players
  • The user_tournament_players table is used to save what Players are on a particular Team for a given Tournament. The user_tournament_players table has two columns, userTournamentRelationId and playerId. The userTournamentRelationId is a reference to the id of a row from the users_tournaments table. The userTournamentRelationId represents a User's Team for a particular Tournament. Each row of this table signifies what Team a Player belongs to
user_wins
  • The user_wins table stores the winning User of a Tournament. It stores a Tournament ID and User ID
users
  • The users table stores a User's ID, Team Name, Email and Password

Testing

Mocha + Chai 

  • The major-manager-server uses Mocha and Chai to run unit tests. Mocha is a JavaScript test framework that runs on Node.js and in the browser. Chai is a library that enables human-readable assertions for validating expected behavior of the server
  • In the following code block, the describe function defines the group of tests within it, AKA a test suite. The it function defines an individual test within the test suite. The describe and it functions are both provided from Mocha. In this example, we use Chai's http module to attempt to view the publicly accessible endpoint at /api/test/all. After this attempt is executed, we use Chai's assertion library to examine the server's response. In this case, we expect the status of the response to be 200
describe('Protected routes', () => {
  it('should return public page', (done) => {
    chai
      .request(app)
      .get('/api/test/all')
      .then((res) => {
        expect(res).to.have.status(200);
        done();
      }).catch((err) => {
        console.log(err.message);
      });
  });
Clone this wiki locally