Giter Site home page Giter Site logo

voax / quizzer Goto Github PK

View Code? Open in Web Editor NEW
19.0 3.0 6.0 958 KB

๐Ÿป A pub quiz web application built using the MERN stack with websockets for near real-time quiz action

License: MIT License

HTML 0.51% JavaScript 97.62% Dockerfile 0.09% SCSS 1.73% Shell 0.04%
mongo express reactjs nodejs mern-stack websocket redux immer quizzer pub-quiz

quizzer's Introduction

Quizzer

Made by Ivo Breukers and Oktay Dinler as our final assignment for the DWA course in the first semester of 2019 at the HAN University of Applied Sciences (Arnhem).

Contents

1 Introduction

The Quizzer is a web application that can be used in bars, sports canteens and maybe even prisons to play quizzes as a team. A pub quiz, basically.

There are 3 main roles in this application: The Quizz Master, The Team and The Scoreboard. The idea is that the Quizz Master can host a room which players can join. A game of Quizzer can be played with a minimum of 2 players and a maximum of 6. The game consists of 12 questions per round and can be played indefinitely untill the Quizz Master ends the quiz after the last question of a round. The question, team answers and points are all shown on the scoreboard screen which is updated in near real-time.

2 Wireframes / resources / system reactions

Click here for our wireframes.

3 Communitation protocols

3.1 WebSocket

Client receives:

  • TEAM_APPLIED
  • APPLICATION_ACCEPTED
  • APPLICATION_REJECTED
  • CATEGORIES_SELECTED
  • QUESTION_SELECTED
  • GUESS_SUBMITTED
  • ROOM_CLOSED
  • QUESTION_CLOSED
  • SCOREBOARD_REFRESH

Clients sends:

  • TEAM_APPLIED

3.2 Rest Endpoints

Method Url
GET /categories/
GET /categories/:categoryID/questions
POST /rooms
GET /rooms/:roomCode
PATCH /rooms/:roomCode
DELETE /rooms/:roomCode
GET /rooms/:roomCode/applications
POST /rooms/:roomCode/applications
DELETE /rooms/:roomCode/applications/:applicationId
POST /rooms/:roomCode/teams
PATCH /rooms/:roomCode/teams/:teamID
PUT /rooms/:roomCode/teams/question
PUT /rooms/:roomCode/categories
POST /rooms/:roomCode/scoreboards

4 Data Schema

4.1 Mongoose Schema

4.1.1 Question

Property Type Default Required
question String โŒ โœ”๏ธ
answer String โŒ โœ”๏ธ
category String โŒ โœ”๏ธ
language String โŒ โœ”๏ธ

4.1.2 Team

Property Type Default Required
sessionID String โŒ โœ”๏ธ
name String โŒ โœ”๏ธ
roundPoints Number 0 โŒ
roundScore Number 0 โŒ
guess String โŒ โŒ
guessCorrect Boolean โŒ โŒ

4.1.3 Room

Property Type Default Required
code String โŒ โœ”๏ธ
host String โŒ โœ”๏ธ
language String โŒ โœ”๏ธ
round Number 0 โŒ
questionNo Number 0 โŒ
roundStarted Boolean false โŒ
teams [Team] โŒ โŒ
applications [Team] โŒ โŒ
categories [String] โŒ โŒ
askedQuestions ref:[Question] โŒ โŒ
currentQuestion Question Question โŒ
questionClosed Boolean true โŒ
roomClosed Boolean false โŒ
scoreboards [String] โŒ โŒ
ended Boolean false โŒ
questionCompleted Boolean false โŒ

5 Clientside State

5.1 websocket

{
  connected: false;
}

5.2 team-app

{
  teamID: null,
  roomCode: {
    value: '',
    valid: false,
  },
  team: {
    value: '',
    valid: false,
  },
  roundNo: 0,
  question: {
    open: false,
    number: 0,
    question: '',
    category: '',
  },
  guess: {
    value: '',
    valid: false,
  },
}

5.3 scoreboard

{
  roomCode: null,
  connectedToRoom: false,
  connectingToRoom: false,
  triedConnectingToRoom: false,

  round: null,
  teams: null,
  category: null,
  question: null,
  questionNo: null,
  questionClosed: null,
}

5.4 popup

{
  title: '',
  message: '',
  button: '',
  active: false,
}

5.5 loader

{
  active: false,
  text: '',
}

5.6 qm (Quizz Master)

{
  roomCode: null,
  language: null,

  selectedTeamApplication: null,
  teamApplications: [],
  approvedTeamApplications: [],
  roomClosed: false,

  round: 0,
  roundStarted: false,
  selectedCategory: null,
  categories: [],
  selectedCategories: [],

  question: 0,
  questions: [],
  questionsAsked: [],
  currentQuestion: null,
  questionClosed: true,
  selectedQuestion: null,

  approvingATeamGuess: false,
},

6 Server Structure

6.1 Middleware

6.1.1 catch-errors.js

module.exports = (fn: (req, res, next) => Promise ): (req, res, next) => void

This module exports a router wrapper for async route handlers. It allows the user to use async route handlers without having to use try/catch. When this wrapper 'catches' an error it passes to next(error).

6.1.2 error-handler.js

module.exports = ({ defaultStatusCode: Number, defaultMessage: String }): (err, req, res, next) => void

This module exports a basic error handler middleware creator. If the user does not pass both initial arguments it will use the statusCode and message props from the object passed from next(). Furthermore the closure will also log the error using console.error to the console.

6.1.3 http-ws-upgrade.js

module.exports = (sessionParser): (wss): (request, socket, head) => void

An application specific function for this project which is used to prevent users who do not have a role connecting to our WebSocket server.

6.1.4 role.js

module.exports.isRole = (...conditions: any): (req, res, next) => void

The isRole function export is a middleware creator function. This function takes a 0.* arguments which are used to check for the users's session.role value.

However if the type is a function it will be passed the req object and whether the function returns true or false it will respond with an error or next() it.

If any condition results into false it will execute the following code:

res.status(400).json({
  message: 'You are not allowed to perform this action.',
});

To combine multiple role middleware you can simply put them in an array. To use it like an array in your route handlers you can simply use the spread operator:

const isHost = isRole(req => req.room && req.sessionID === req.room.host)
const isQM = isRole('QM')

const isQMAndHost = [isQuizzMaster, isHost]

//                       spread like so
router.get('/protected', ...isQMAndHost, (req, res) => {...})
// or
app.use('/protected', ...isQMAndHost)

6.1.5 socket.js

module.exports.sessionHasWSConnect = (errorMsg: String): (req, res, next) => void

The returned middleware closure checks for whether the request is already connected to the WebSocket server. If the user is already connected it will respond with a 400 status code and with the passed in errorMsg parameter.

6.2 Mongoose methods

6.2.1 Room

6.2.2 .pingTeams(msg: String)

Ping the WebSocket for all team connections with the given msg.

6.2.3 .pingScoreboards(msg: String)

Ping the WebSocket for all scoreboard connections with the given msg.

6.2.4 .pingApplications(msg: String)

Ping the WebSocket for all team-application connections with the given msg.

6.2.5 .pingHost(msg: String)

Ping the host's WebSocket connection with the given msg.

6.2.6 async .calculateRP()

This method determines the winnner(s) and respectively gives all the teams their points.

6.2.7 async .nextRound()

Updates roundStarted to false and questionNo to 0. Then it will call calculateRP()

6.2.8 async .nextQuestion()

  1. Updates for all teams their .roundScore property if .guessCorrect is true
  2. Sets currentQuestion to null and questionCompleted to true
  3. calls .nextRound() if the current question is >= MAX_QUESTIONS_PER_ROUND defined in server/.env

6.2.9 async .startRound(categories)

Increments round , updates questionNo to 0, categories to categories, roundStarted to true and updates the team's roundScore to 0. Then it will ping the teams with 'CATEGORIES_SELECTED' and returns roundStarted, round and questionNo.

6.2.10 async .startQuestion(question)

Increments questionNo , updates questionCompleted to false, questionClosed to false, currentQuestion to question, adds the question._id to the askedQuestions array, next it updates the team's guess to '' and guessCorrect to false. Then it will ping the teams with 'QUESTION_SELECTED' and the scoreboards with 'SCOREBOARD_REFRESH'. Then it returns questionClosed and questionNo.

6.3 Team

6.3.1 .ping(msg)

Ping the team's WebSocket connection with the given msg.

quizzer's People

Contributors

aod avatar dependabot[bot] avatar ivobreukers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.