From 249f8aa07ecd01acc53891b151c6744c3cda440a Mon Sep 17 00:00:00 2001 From: destryptor Date: Fri, 1 Mar 2024 12:52:13 +0530 Subject: [PATCH 01/35] Team List page for admin and Timeout page done (kinda) --- routers/live-router.js | 22 ++--- templates/admin/live-info.njk | 0 templates/admin/team-edit.njk | 0 templates/admin/team-list.njk | 152 ++++++++++++++++++++++++++++++++++ templates/live/interface.njk | 85 +++++++++++++++++++ templates/live/landing.njk | 16 ++-- templates/live/timeout.njk | 50 +++++++++++ 7 files changed, 307 insertions(+), 18 deletions(-) create mode 100644 templates/admin/live-info.njk create mode 100644 templates/admin/team-edit.njk create mode 100644 templates/admin/team-list.njk create mode 100644 templates/live/interface.njk create mode 100644 templates/live/timeout.njk diff --git a/routers/live-router.js b/routers/live-router.js index 8ce084d..9adfe80 100644 --- a/routers/live-router.js +++ b/routers/live-router.js @@ -12,21 +12,23 @@ router.use((req, res, next) => { router.get('/', async (req, res) => { if (req.isAdmin) { - handlerContext.quiz = await dbh.getLiveQuiz('2023-09-03'); - handlerContext.quizTitle = handlerContext.quiz.title; - handlerContext.quizId = handlerContext.quiz._id; - const questions = handlerContext.quiz.questions; - return res.renderFile('live/master.njk', { - questions, - qAmt: questions.length, - id: 'live' + return res.renderFile('admin/team-list.njk', { + teams }); } else { - if (!handlerContext.quizStarted) return res.redirect('/'); - return res.renderFile('live/participant.njk'); + // if (!handlerContext.quizStarted) return res.redirect('/'); + return res.renderFile('live/interface.njk', { + team, + locationQuestion + }); + // return res.renderFile('live/interface.njk'); } }); +router.get('/timeout', async (req, res) => { + return res.renderFile('live/timeout.njk'); +}); + router.get('/results', async (req, res) => { if (req.isAdmin) { const results = await dbh.getLiveResults(handlerContext.quizId); diff --git a/templates/admin/live-info.njk b/templates/admin/live-info.njk new file mode 100644 index 0000000..e69de29 diff --git a/templates/admin/team-edit.njk b/templates/admin/team-edit.njk new file mode 100644 index 0000000..e69de29 diff --git a/templates/admin/team-list.njk b/templates/admin/team-list.njk new file mode 100644 index 0000000..c4160fb --- /dev/null +++ b/templates/admin/team-list.njk @@ -0,0 +1,152 @@ +{% extends 'admin/_admin.njk' %} + +{% set thispage = 'teamlist' %} +{% set pagetitle = 'Team Management' %} + +{% set scripts = ['https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js'] %} + +{% block pagecontent %} +

Teams Management Page

+   Registered Teams: {{ teams | length }}  
+ {% for team in teams %} +
+
+ {% for key, value in team %} + {% if key == 'members' %} +
+ {{ key | capitalize }}: +
+ {% for member in value %} +
+ Name: {{ member.name }}
+ Email: {{ member.email }}
+ Phone: {{ member.phone }}
+
+ {% endfor %} +
+ +
+ {% else %} + {{ key | capitalize }}: {{ value }}
+ {% endif %} + {% endfor %} +
+ +
+ +
+
+ {% endfor %} + +{% endblock %} + +{% block customcss %} + +{% endblock %} + +{% block customjs %} + +{% endblock %} \ No newline at end of file diff --git a/templates/live/interface.njk b/templates/live/interface.njk new file mode 100644 index 0000000..7a026c4 --- /dev/null +++ b/templates/live/interface.njk @@ -0,0 +1,85 @@ +{% extends '_base.njk' %} +{% import '_form.njk' as forms %} + +{% set thispage = 'events' %} +{% set pagetitle = 'Treasure Hunt' %} + +{% set scripts = ['https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js'] %} + +{% block pagecontent %} +
+
+

Treasure Hunt

+
+

Team ID: {{ team.ID }}

+

Team Name: {{ team.name }}

+

+
+

Question

+

{{ location_question.question }}

+
+ {% call forms.form() %} + {{ forms.field('_id','TeamID', _id, type='hidden')}} + {{ forms.field('answer','Answer')}} + + {% endcall %} +
+ + + +
+{% endblock %} + +{% block customcss %} + + {{ forms.formCss() }} +{% endblock %} + +{% block customjs %} + {{ forms.formFunction() }} + +{% endblock %} \ No newline at end of file diff --git a/templates/live/landing.njk b/templates/live/landing.njk index 9f4aff9..842c045 100644 --- a/templates/live/landing.njk +++ b/templates/live/landing.njk @@ -3,14 +3,14 @@ {% set pagetitle = 'Open Campus Anime Quiz' %} {% block extrajs %} - + socket.on('start', req => { + document.getElementById('content').innerHTML = '

Treasure Hunt Has Started, Please wait while we redirect you ^_^

' + setTimeout(() => window.location.href = window.location.href, 3000); + }) + {% endblock %} -{% set scripts = ['/socket.io/socket.io.js'] %} +{% set scripts = ['/socket.io/socket.io.js'] %} \ No newline at end of file diff --git a/templates/live/timeout.njk b/templates/live/timeout.njk new file mode 100644 index 0000000..d3d2e84 --- /dev/null +++ b/templates/live/timeout.njk @@ -0,0 +1,50 @@ +{% extends '_base.njk' %} + +{% set thispage = 'events' %} +{% set pagetitle = 'Wrong Answer' %} + +{% block pagecontent %} +
+
+

Wrong Answer!

+

Try again in 2 mins

+
+
+{% endblock %} + +{% block customcss %} + +{% endblock %} + +{% block customjs %} + +{% endblock %} \ No newline at end of file From ffae7720a5174e435943801a077d60be4610789a Mon Sep 17 00:00:00 2001 From: destryptor Date: Fri, 1 Mar 2024 15:38:56 +0530 Subject: [PATCH 02/35] Admin frontend completed with routes --- routers/admin-router.js | 120 ++++++++++++++++++++++++++++++++++ routers/live-router.js | 47 +++++++++++++ templates/admin/team-edit.njk | 76 +++++++++++++++++++++ templates/admin/team-list.njk | 6 +- templates/live/interface.njk | 2 +- 5 files changed, 248 insertions(+), 3 deletions(-) diff --git a/routers/admin-router.js b/routers/admin-router.js index 19a9b36..dd20820 100644 --- a/routers/admin-router.js +++ b/routers/admin-router.js @@ -3,12 +3,132 @@ const dbh = require('../database/handler'); const { body, validationResult } = require('express-validator'); const checkAdmin = require('./check-admin'); +const teams = [ + { + id: 1, + name: 'Team 1', + members: [ + { name: 'User 1', email: 'user4@example.com', phone: '123-456-7890' }, + { name: 'User 2', email: 'user5@example.com', phone: '987-654-3210' }, + { name: 'User 3', email: 'user6@example.com', phone: '555-555-5555' } + ] + }, + { + id: 2, + name: 'Team 2', + members: [ + { name: 'User 4', email: 'user4@example.com', phone: '123-456-7890' }, + { name: 'User 5', email: 'user5@example.com', phone: '987-654-3210' }, + { name: 'User 6', email: 'user6@example.com', phone: '555-555-5555' } + ] + }, + { + id: 3, + name: 'Team 3', + members: [ + { name: 'User 7', email: 'user7@example.com', phone: '111-222-3333' }, + { name: 'User 8', email: 'user8@example.com', phone: '444-555-6666' }, + { name: 'User 9', email: 'user9@example.com', phone: '777-888-9999' } + ] + } +]; + +const team = { + id: 1, + name: 'Team 1' +}; + +const locationQuestion = { + id: 1, + question: 'Where is the best waifu', + answer: 'Oregairu' +}; + +const riddleQuestion = { + id: 1, + question: 'Who is the best waifu', + answer: 'Shizuka Hiratsuka' +}; + router.use('/', checkAdmin); router.get('/', (req, res) => { res.renderFile('admin/_admin.njk'); }); +router.get('/edit-team', async (req, res) => { + const teamID = parseInt(req.query.teamID); + const team = teams.find(team => team.id === teamID); + return res.renderFile('admin/team-edit.njk', { + team + }); +}); + +router.patch('/edit-team', [ + body('id') + .isNumeric() + .trim() + .notEmpty().withMessage('No ID Provided'), + body('teamName') + .trim() + .notEmpty().withMessage('No Name Provided'), + body('name1') + .trim() + .notEmpty().withMessage('No Name Provided'), + body('name2') + .trim() + .notEmpty().withMessage('No Name Provided'), + body('name3') + .trim() + .notEmpty().withMessage('No Name Provided'), + body('email1') + .trim() + .notEmpty().withMessage('No Email Provided') + .isEmail().withMessage('Please provide a valid email'), + body('email2') + .trim() + .notEmpty().withMessage('No Email Provided') + .isEmail().withMessage('Please provide a valid email'), + body('email3') + .trim() + .notEmpty().withMessage('No Email Provided') + .isEmail().withMessage('Please provide a valid email'), + body('phone1') + .trim() + .notEmpty().withMessage('No Phone Number Provided') + .isMobilePhone('en-IN').withMessage('Please provide a valid phone number'), + body('phone2') + .trim() + .notEmpty().withMessage('No Phone Number Provided') + .isMobilePhone('en-IN').withMessage('Please provide a valid phone number'), + body('phone3') + .trim() + .notEmpty().withMessage('No Phone Number Provided') + .isMobilePhone('en-IN').withMessage('Please provide a valid phone number') +], async (req, res) => { + const errors = validationResult(req); + if (!errors.isEmpty()) { + const errorMessages = errors.array().map(error => error.msg); + throw new Error(errorMessages[0]); + } + // const team = { + // id: req.body.id, + // name: req.body.teamName, + // members: [ + // { name: req.body.name1, email: req.body.email1, phone: req.body.phone1 }, + // { name: req.body.name2, email: req.body.email2, phone: req.body.phone2 }, + // { name: req.body.name3, email: req.body.email3, phone: req.body.phone3 } + // ] + // }; + // const teamIndex = teams.findIndex(t => t.id === team.id); + // if (teamIndex === -1) { + // teams.push(team); + // } + // teams[teamIndex] = team; + return res.status(200).send('Edited Successfully'); +}); + + router.get('/list-users', async (req, res) => { const users = await dbh.getUsers(); res.renderFile('admin/user-list.njk', { users }); diff --git a/routers/live-router.js b/routers/live-router.js index 9adfe80..1f9a8b2 100644 --- a/routers/live-router.js +++ b/routers/live-router.js @@ -10,6 +10,53 @@ router.use((req, res, next) => { return next(); }); +const teams = [ + { + id: 1, + name: 'Team 1', + members: [ + { name: 'User 1', email: 'user4@example.com', phone: '123-456-7890' }, + { name: 'User 2', email: 'user5@example.com', phone: '987-654-3210' }, + { name: 'User 3', email: 'user6@example.com', phone: '555-555-5555' } + ] + }, + { + id: 2, + name: 'Team 2', + members: [ + { name: 'User 4', email: 'user4@example.com', phone: '123-456-7890' }, + { name: 'User 5', email: 'user5@example.com', phone: '987-654-3210' }, + { name: 'User 6', email: 'user6@example.com', phone: '555-555-5555' } + ] + }, + { + id: 3, + name: 'Team 3', + members: [ + { name: 'User 7', email: 'user7@example.com', phone: '111-222-3333' }, + { name: 'User 8', email: 'user8@example.com', phone: '444-555-6666' }, + { name: 'User 9', email: 'user9@example.com', phone: '777-888-9999' } + ] + } +]; + +const team = { + id: 1, + name: 'Team 1' +}; + +const locationQuestion = { + id: 1, + question: 'Where is the best waifu', + answer: 'Oregairu' +}; + +const riddleQuestion = { + id: 1, + question: 'Who is the best waifu', + answer: 'Shizuka Hiratsuka' +}; + router.get('/', async (req, res) => { if (req.isAdmin) { return res.renderFile('admin/team-list.njk', { diff --git a/templates/admin/team-edit.njk b/templates/admin/team-edit.njk index e69de29..a0e8dd2 100644 --- a/templates/admin/team-edit.njk +++ b/templates/admin/team-edit.njk @@ -0,0 +1,76 @@ +{% extends 'admin/_admin.njk' %} +{% import '_form.njk' as forms %} + +{% set thispage = 'editteam' %} +{% set pagetitle = 'Edit Team' %} + +{% set scripts = ['https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js'] %} + +{% block pagecontent %} + {% call forms.form() %} + {{ forms.heading('h1','Edit Team') }} +
+ {{ forms.field('id','ID', team.id)}} +
+ {{ forms.field('teamName','Name', team.name)}} +
+ {% for member in team.members %} +
+ {{ forms.field('name'+loop.index,'Name', member.name)}} + {{ forms.field('email'+loop.index,'Email', member.email, type='email')}} + {{ forms.field('phone'+loop.index,'Phone number', member.phone)}} + +
+ {% endfor %} + + + {% endcall %} +{% endblock %} + +{% block customcss %} + {{ forms.formCss() }} + +{% endblock %} + +{% block customjs %} + {{ forms.formFunction() }} + +{% endblock %} \ No newline at end of file diff --git a/templates/admin/team-list.njk b/templates/admin/team-list.njk index c4160fb..42e0b0b 100644 --- a/templates/admin/team-list.njk +++ b/templates/admin/team-list.njk @@ -33,7 +33,7 @@
- +
{% endfor %} @@ -55,6 +55,7 @@ align-self:center; } .card1{ + margin: auto; flex:80%; width:40%; padding-left:5px; @@ -146,7 +147,8 @@ {% block customjs %} {% endblock %} \ No newline at end of file diff --git a/templates/live/interface.njk b/templates/live/interface.njk index 7a026c4..29a2dbd 100644 --- a/templates/live/interface.njk +++ b/templates/live/interface.njk @@ -16,7 +16,7 @@

Question

-

{{ location_question.question }}

+

{{ locationQuestion.question }}

{% call forms.form() %} {{ forms.field('_id','TeamID', _id, type='hidden')}} From 5d3a0efa204e739362d0db0aeeb36ea489d2c4fb Mon Sep 17 00:00:00 2001 From: destryptor Date: Fri, 1 Mar 2024 21:25:44 +0530 Subject: [PATCH 03/35] Redundant (possibly) validation rules removed --- routers/admin-router.js | 35 +---------------------------------- templates/admin/team-edit.njk | 2 +- 2 files changed, 2 insertions(+), 35 deletions(-) diff --git a/routers/admin-router.js b/routers/admin-router.js index dd20820..6673cdf 100644 --- a/routers/admin-router.js +++ b/routers/admin-router.js @@ -71,40 +71,7 @@ router.patch('/edit-team', [ .notEmpty().withMessage('No ID Provided'), body('teamName') .trim() - .notEmpty().withMessage('No Name Provided'), - body('name1') - .trim() - .notEmpty().withMessage('No Name Provided'), - body('name2') - .trim() - .notEmpty().withMessage('No Name Provided'), - body('name3') - .trim() - .notEmpty().withMessage('No Name Provided'), - body('email1') - .trim() - .notEmpty().withMessage('No Email Provided') - .isEmail().withMessage('Please provide a valid email'), - body('email2') - .trim() - .notEmpty().withMessage('No Email Provided') - .isEmail().withMessage('Please provide a valid email'), - body('email3') - .trim() - .notEmpty().withMessage('No Email Provided') - .isEmail().withMessage('Please provide a valid email'), - body('phone1') - .trim() - .notEmpty().withMessage('No Phone Number Provided') - .isMobilePhone('en-IN').withMessage('Please provide a valid phone number'), - body('phone2') - .trim() - .notEmpty().withMessage('No Phone Number Provided') - .isMobilePhone('en-IN').withMessage('Please provide a valid phone number'), - body('phone3') - .trim() - .notEmpty().withMessage('No Phone Number Provided') - .isMobilePhone('en-IN').withMessage('Please provide a valid phone number') + .notEmpty().withMessage('No Name Provided') ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { diff --git a/templates/admin/team-edit.njk b/templates/admin/team-edit.njk index a0e8dd2..a88661e 100644 --- a/templates/admin/team-edit.njk +++ b/templates/admin/team-edit.njk @@ -61,8 +61,8 @@ const data = getData(); try { const response = await axios.patch('/admin/edit-team', data); - console.log(response); if (response.status === 200) { + alert('Team updated successfully!'); window.location.href = '/live'; } else { console.error('Error updating team:', response); From fc99f2acfa898460cd2dbac1c526de2ac43233eb Mon Sep 17 00:00:00 2001 From: destryptor Date: Sat, 2 Mar 2024 19:23:30 +0530 Subject: [PATCH 04/35] State transition with localStorage complete --- routers/live-router.js | 47 +++++++- templates/live/interface.njk | 217 +++++++++++++++++++++++++++++++---- templates/live/timeout.njk | 50 -------- 3 files changed, 237 insertions(+), 77 deletions(-) delete mode 100644 templates/live/timeout.njk diff --git a/routers/live-router.js b/routers/live-router.js index 1f9a8b2..a9be281 100644 --- a/routers/live-router.js +++ b/routers/live-router.js @@ -1,6 +1,6 @@ const router = require('express').Router(); const dbh = require('../database/handler'); - +const { body, validationResult } = require('express-validator'); const checker = require('../src/checker.js'); const handlerContext = {}; @@ -48,7 +48,8 @@ const team = { const locationQuestion = { id: 1, question: 'Where is the best waifu', - answer: 'Oregairu' + answer: 'Oregairu', + location: 'ABC123' }; const riddleQuestion = { @@ -72,8 +73,46 @@ router.get('/', async (req, res) => { } }); -router.get('/timeout', async (req, res) => { - return res.renderFile('live/timeout.njk'); +router.patch('/location-submit-answer', async (req, res) => { + const teamID = parseInt(req.body.id); + const questionID = parseInt(req.body.question); + const answer = req.body.locationanswer; + const location = req.body.locationcode; + + // console.log(teamID); + // console.log(questionID); + // console.log(answer); + // console.log(location); + + // FIND QUESTION WITH ID IN LOCAL STORAGE + const question = locationQuestion; + if (question.answer === answer && question.location === location) { + // MARK QUESTION AS COMPLETED FOR TEAM BY FINDING TEAM BY ID AND ADDING QUESTION TO COMPLETED QUESTIONS LIST + return res.send('correct'); + } else if (question.answer !== answer) { + return res.status(400).send('incorrect answer'); + } else { + return res.status(400).send('incorrect location'); + } +}); + +router.patch('/riddle-submit-answer', async (req, res) => { + const teamID = parseInt(req.body.id); + const questionID = parseInt(req.body.question); + const answer = req.body.riddleanswer; + + // console.log(teamID); + // console.log(questionID); + // console.log(answer); + + // FIND QUESTION WITH ID IN LOCAL STORAGE + const question = riddleQuestion; + if (question.answer === answer) { + // MARK QUESTION AS COMPLETED FOR TEAM BY FINDING TEAM BY ID AND ADDING QUESTION TO COMPLETED QUESTIONS LIST + return res.send('correct'); + } else { + return res.status(400).send('incorrect answer'); + } }); router.get('/results', async (req, res) => { diff --git a/templates/live/interface.njk b/templates/live/interface.njk index 29a2dbd..0e13eb8 100644 --- a/templates/live/interface.njk +++ b/templates/live/interface.njk @@ -7,34 +7,84 @@ {% set scripts = ['https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js'] %} {% block pagecontent %} -
-
-

Treasure Hunt

+
+
+
+
+
+

Wrong Answer!

+

Try again in

+
+
+

Treasure Hunt

-

Team ID: {{ team.ID }}

+

Team ID: {{ team.id }}

Team Name: {{ team.name }}

Question

{{ locationQuestion.question }}

- {% call forms.form() %} - {{ forms.field('_id','TeamID', _id, type='hidden')}} - {{ forms.field('answer','Answer')}} - - {% endcall %} -
-
- - -
{% endblock %} {% block customcss %} {{ forms.formCss() }} {% endblock %} @@ -75,11 +149,108 @@ axios.defaults.withCredentials = true; axios.defaults.headers.common['X-CSRF-TOKEN'] = '{{ csrfToken }}'; + let state = localStorage.getItem('state') || 'location-question'; + localStorage.setItem('state', state); + + function renderForm() { + const locationForm = document.getElementById('location-form'); + const riddleForm = document.getElementById('riddle-form'); + const messageBox = document.getElementById("message-box"); + const messageCover = document.getElementById("message-cover"); + const countdown = document.getElementById("countdown"); + const timeoutContainer = document.getElementById('timeout'); + const interfaceContainer = document.getElementById('interface-container'); + + interfaceContainer.style.display = state.includes('question') ? 'block' : 'none'; + locationForm.style.display = state === 'location-question' ? 'block' : 'none'; + riddleForm.style.display = state === 'riddle-question' ? 'block' : 'none'; + messageBox.innerHTML = ''; + messageCover.style.display = 'none'; + timeoutContainer.style.display = 'none'; + + + if (state === 'location-timeout' || state === 'riddle-timeout') { + interfaceContainer.style.display = 'none'; + timeoutContainer.style.display = 'block'; + let timeleft = localStorage.getItem('timeleft') || 120; + timeleft = parseInt(timeleft); + const countdownInterval = setInterval(() => { + if (timeleft <= 0) { + clearInterval(countdownInterval); + localStorage.removeItem('timeleft'); + state = state.includes('location') ? 'location-question' : 'riddle-question'; + localStorage.setItem('state', state); + renderForm(); + } else { + const minutes = Math.floor(timeleft / 60); + const seconds = timeleft % 60; + countdown.textContent = (minutes === 0 ? "" : minutes + " min ") + (seconds === 0 ? "" : seconds + " s"); + timeleft -= 1; + localStorage.setItem('timeleft', timeleft); + } + }, 1000); + } + } + + document.addEventListener("DOMContentLoaded", function() { + renderForm(); + document.getElementById("location-submit-button").addEventListener("click", function(event) { + event.preventDefault(); + submit(); + }); + document.getElementById("riddle-submit-button").addEventListener("click", function(event) { + event.preventDefault(); + submit(); + }); + }); + async function submit() { - event.preventDefault(); const data = getData(); - data.answer = data.answer.toUpperCase(); - console.log(data.answer); + try { + let response; + if (state === 'location-question') { + response = await axios.patch('/live/location-submit-answer', data); + } else if (state === 'riddle-question') { + response = await axios.patch('/live/riddle-submit-answer', data); + } + + if (response && response.status === 200) { + const messageBox = document.getElementById("message-box"); + messageBox.innerHTML = '

Correct Answer!

'; + const messageCover = document.getElementById("message-cover"); + messageCover.style.display = 'block'; + setTimeout(() => { + messageCover.style.display = "none"; + state = state === 'location-question' ? 'riddle-question' : 'location-question'; + localStorage.setItem('state', state); + renderForm(); + }, 10000); + } + } catch (error) { + console.error(error); + if (error.response && error.response.data === 'incorrect answer') { + const messageBox = document.getElementById("message-box"); + messageBox.innerHTML = '

Incorrect Answer!

'; + const messageCover = document.getElementById("message-cover"); + messageCover.style.display = 'block'; + setTimeout(() => { + messageCover.style.display = "none"; + state = state.includes('location') ? 'location-timeout' : 'riddle-timeout'; + localStorage.setItem('state', state); + renderForm(); + }, 10000); + } else if (error.response && error.response.data === 'incorrect location') { + const messageBox = document.getElementById("message-box"); + messageBox.innerHTML = '

Incorrect Location Code!

'; + const messageCover = document.getElementById("message-cover"); + messageCover.style.display = 'block'; + setTimeout(() => { + messageCover.style.display = "none"; + }, 10000); + state = 'location-question'; + localStorage.setItem('state', state); + } + } } -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/live/timeout.njk b/templates/live/timeout.njk deleted file mode 100644 index d3d2e84..0000000 --- a/templates/live/timeout.njk +++ /dev/null @@ -1,50 +0,0 @@ -{% extends '_base.njk' %} - -{% set thispage = 'events' %} -{% set pagetitle = 'Wrong Answer' %} - -{% block pagecontent %} -
-
-

Wrong Answer!

-

Try again in 2 mins

-
-
-{% endblock %} - -{% block customcss %} - -{% endblock %} - -{% block customjs %} - -{% endblock %} \ No newline at end of file From 5f45dcb8419f7c92b6033d648060a49c37294b86 Mon Sep 17 00:00:00 2001 From: destryptor Date: Wed, 6 Mar 2024 23:45:50 +0530 Subject: [PATCH 05/35] State transition fixes and Basic Model creation --- database/Schemas/LocationQuestion.js | 10 + database/Schemas/RiddleQuestion.js | 9 + database/Schemas/Team.js | 23 ++ routers/live-router.js | 25 +- templates/live/interface.njk | 473 +++++++++++++++------------ 5 files changed, 321 insertions(+), 219 deletions(-) create mode 100644 database/Schemas/LocationQuestion.js create mode 100644 database/Schemas/RiddleQuestion.js create mode 100644 database/Schemas/Team.js diff --git a/database/Schemas/LocationQuestion.js b/database/Schemas/LocationQuestion.js new file mode 100644 index 0000000..c81c867 --- /dev/null +++ b/database/Schemas/LocationQuestion.js @@ -0,0 +1,10 @@ +const mongoose = require('mongoose'); + +const locationQuestionSchema = new mongoose.Schema({ + _id: { type: String, required: true }, + question: { type: String, required: true }, + answer: { type: String, required: true }, + locationCode: { type: String, required: true } +}, { collection: 'location-questions' }); + +module.exports = mongoose.model('LocationQuestion', locationQuestionSchema); diff --git a/database/Schemas/RiddleQuestion.js b/database/Schemas/RiddleQuestion.js new file mode 100644 index 0000000..a852caa --- /dev/null +++ b/database/Schemas/RiddleQuestion.js @@ -0,0 +1,9 @@ +const mongoose = require('mongoose'); + +const riddleQuestionSchema = new mongoose.Schema({ + _id: { type: String, required: true }, + question: { type: String, required: true }, + answer: { type: String, required: true } +}, { collection: 'riddle-questions' }); + +module.exports = mongoose.model('RiddleQuestion', riddleQuestionSchema); diff --git a/database/Schemas/Team.js b/database/Schemas/Team.js new file mode 100644 index 0000000..74d6fb0 --- /dev/null +++ b/database/Schemas/Team.js @@ -0,0 +1,23 @@ +const mongoose = require('mongoose'); + +const teamSchema = new mongoose.Schema({ + _id: { type: Number, required: true }, + name: { type: String, required: true }, + members: [ + { + name: { type: String, required: true }, + email: { type: String, required: true }, + phone: { type: String, required: true } + } + ], + status: { type: String, required: true }, + questionsAttempted: { type: Number, required: true }, + questions: [ + { + type: Number, + required: true + } + ] +}, { collection: 'event-teams' }); + +module.exports = mongoose.model('Team', teamSchema); diff --git a/routers/live-router.js b/routers/live-router.js index a9be281..c96d8e3 100644 --- a/routers/live-router.js +++ b/routers/live-router.js @@ -48,8 +48,7 @@ const team = { const locationQuestion = { id: 1, question: 'Where is the best waifu', - answer: 'Oregairu', - location: 'ABC123' + answer: 'Oregairu' }; const riddleQuestion = { @@ -58,6 +57,8 @@ const riddleQuestion = { answer: 'Shizuka Hiratsuka' }; +const locationCode = 'ABC123'; + router.get('/', async (req, res) => { if (req.isAdmin) { return res.renderFile('admin/team-list.njk', { @@ -73,6 +74,20 @@ router.get('/', async (req, res) => { } }); +router.patch('/location-code', async (req, res) => { + const teamID = parseInt(req.body.id); + const location = req.body.locationcode; + // console.log(teamID); + // console.log(location); + // FIND TEAM BY ID IN LOCAL STORAGE + // MARK TEAM AS COMPLETED FOR LOCATION BY FINDING TEAM BY ID AND ADDING LOCATION TO COMPLETED LOCATIONS LIST + if (location === locationCode) { + return res.send('correct'); + } else { + return res.status(400).send('incorrect location'); + } +}); + router.patch('/location-submit-answer', async (req, res) => { const teamID = parseInt(req.body.id); const questionID = parseInt(req.body.question); @@ -86,13 +101,11 @@ router.patch('/location-submit-answer', async (req, res) => { // FIND QUESTION WITH ID IN LOCAL STORAGE const question = locationQuestion; - if (question.answer === answer && question.location === location) { + if (question.answer === answer) { // MARK QUESTION AS COMPLETED FOR TEAM BY FINDING TEAM BY ID AND ADDING QUESTION TO COMPLETED QUESTIONS LIST return res.send('correct'); - } else if (question.answer !== answer) { - return res.status(400).send('incorrect answer'); } else { - return res.status(400).send('incorrect location'); + return res.status(400).send('incorrect answer'); } }); diff --git a/templates/live/interface.njk b/templates/live/interface.njk index 0e13eb8..3d23adf 100644 --- a/templates/live/interface.njk +++ b/templates/live/interface.njk @@ -7,250 +7,297 @@ {% set scripts = ['https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js'] %} {% block pagecontent %} -
-
+
+
+
+
+
+

Wrong Answer!

+

Try again in

+
+
+

Treasure Hunt

+
+

Team ID: {{ team.id }}

+

Team Name: {{ team.name }}

-
-
-

Wrong Answer!

-

Try again in

+
+
+ {% call forms.form() %} + {{ forms.heading('h2', 'Enter the Location Code') }} + {{ forms.field('id','TeamID', team.id , type='hidden')}} + {{ forms.field('name', 'Team Name', team.name, type='hidden') }} + {{ forms.field('locationcode','Location Code') }} + + {% endcall %}
-
-

Treasure Hunt

-
-

Team ID: {{ team.id }}

-

Team Name: {{ team.name }}

-

+

Question

{{ locationQuestion.question }}

-
-
- {% call forms.form() %} - {{ forms.field('id','TeamID', team.id , type='hidden')}} - {{ forms.field('name', 'Team Name', team.name, type='hidden') }} - {{ forms.field('question', 'Question', locationQuestion.id, type='hidden') }} - {{ forms.field('locationanswer','Answer') }} - {{ forms.field('location','Location', locationQuestion.location, type='hidden') }} - {{ forms.field('locationcode', "Location Code") }} - - {% endcall %} -
-
- {% call forms.form() %} - {{ forms.field('id','TeamID', team.id , type='hidden')}} - {{ forms.field('name', 'Team Name', team.name, type='hidden') }} - {{ forms.field('question', 'Question', locationQuestion.id, type='hidden') }} - {{ forms.field('riddleanswer','Answer') }} - - {% endcall %} -
+ {% call forms.form() %} + {{ forms.field('id','TeamID', team.id , type='hidden')}} + {{ forms.field('name', 'Team Name', team.name, type='hidden') }} + {{ forms.field('question', 'Question', locationQuestion.id, type='hidden') }} + {{ forms.field('locationanswer','Answer') }} + {{ forms.field('location','Location', locationQuestion.location, type='hidden') }} + + {% endcall %} +
+
+
+

Question

+

{{ locationQuestion.question }}

+ {% call forms.form() %} + {{ forms.field('id','TeamID', team.id , type='hidden')}} + {{ forms.field('name', 'Team Name', team.name, type='hidden') }} + {{ forms.field('question', 'Question', locationQuestion.id, type='hidden') }} + {{ forms.field('riddleanswer','Answer') }} + + {% endcall %}
+
+
{% endblock %} {% block customcss %} - - {{ forms.formCss() }} + +{{ forms.formCss() }} {% endblock %} {% block customjs %} - {{ forms.formFunction() }} - -{% endblock %} + } + +{% endblock %} \ No newline at end of file From fdde2ef02640532b6ed24301a91cc3badfc971f5 Mon Sep 17 00:00:00 2001 From: Ankan <93087057+ItsAnkan@users.noreply.github.com> Date: Thu, 7 Mar 2024 11:42:52 +0530 Subject: [PATCH 06/35] removed unused tests --- routers/admin-router.js | 16 ++-- routers/live-router.js | 17 ++++- templates/admin/team-edit.njk | 30 ++++++-- templates/admin/team-list.njk | 29 +++++++ templates/live/interface.njk | 54 +++++++------ test/site-adminuser.js | 138 +++++++++++++++++----------------- 6 files changed, 178 insertions(+), 106 deletions(-) diff --git a/routers/admin-router.js b/routers/admin-router.js index 6673cdf..f33b35e 100644 --- a/routers/admin-router.js +++ b/routers/admin-router.js @@ -101,14 +101,14 @@ router.get('/list-users', async (req, res) => { res.renderFile('admin/user-list.njk', { users }); }); -router.get('/edit-user', async (req, res) => { - const username = req.query.username; - if (!username) return res.redirect('/admin/list-users'); - const data = (await dbh.getUserByUsername(username)).toObject(); - delete data.salt; - delete data.hash; - res.renderFile('admin/user-edit.njk', { ...data }); -}); +// router.get('/edit-user', async (req, res) => { +// const username = req.query.username; +// if (!username) return res.redirect('/admin/list-users'); +// const data = (await dbh.getUserByUsername(username)).toObject(); +// delete data.salt; +// delete data.hash; +// res.renderFile('admin/user-edit.njk', { ...data }); +// }); router.patch('/edit-user', [ body('name') diff --git a/routers/live-router.js b/routers/live-router.js index a9be281..e242332 100644 --- a/routers/live-router.js +++ b/routers/live-router.js @@ -67,7 +67,8 @@ router.get('/', async (req, res) => { // if (!handlerContext.quizStarted) return res.redirect('/'); return res.renderFile('live/interface.njk', { team, - locationQuestion + locationQuestion, + started: handlerContext.huntStarted }); // return res.renderFile('live/interface.njk'); } @@ -115,6 +116,20 @@ router.patch('/riddle-submit-answer', async (req, res) => { } }); +router.post('/start-hunt', (req, res) => { + if (!req.isAdmin) return res.status(403).send('Forbidden: Admin permissions not detected.'); + handlerContext.huntStarted = true; + return res.send('Hunt Started'); +}); + +router.post('/end-hunt', (req, res) => { + if (!req.isAdmin) return res.status(403).send('Forbidden: Admin permissions not detected.'); + handlerContext.huntStarted = false; + return res.send('Hunt Ended'); +}); + +// --------------------------------------------------------------------- + router.get('/results', async (req, res) => { if (req.isAdmin) { const results = await dbh.getLiveResults(handlerContext.quizId); diff --git a/templates/admin/team-edit.njk b/templates/admin/team-edit.njk index a88661e..1f703a4 100644 --- a/templates/admin/team-edit.njk +++ b/templates/admin/team-edit.njk @@ -33,6 +33,9 @@ .members { margin: 20px 0px; } + .form-container { + width: 80%; + } {% endblock %} @@ -43,23 +46,40 @@ axios.defaults.headers.common['X-CSRF-TOKEN'] = '{{ csrfToken }}'; function addMember() { + const count = document.getElementsByClassName('members').length; + if (count >= 4) { + return; + } const member = document.createElement('div'); + member.className = 'members'; member.innerHTML = ` - {{ forms.field('name','Name', '', type='text')}} - {{ forms.field('email','Email', '', type='email')}} - {{ forms.field('phone','Phone number', '', type='text')}} + {{ forms.field('name${count+1}','Name', '', type='text')}} + {{ forms.field('email${count+1}','Email', '', type='email')}} + {{ forms.field('phone${count+1}','Phone number', '', type='text')}} + `; document.querySelector('form').insertBefore(member, document.getElementById('addmember')); } function removeMember(e) { e.parentElement.remove(); + updateIds(); + } + + function updateIds () { + // if a member oher then last member is removed, the id's might get messy + [...document.getElementsByClassName('members')].map((ele, index) => { + [...ele.children].slice(0, -1).map((e) => { + e.children[0].id = e.children[0].id.slice(0, -1) + (index + 1); + }); + }) } async function update() { event.preventDefault(); const data = getData(); - try { + console.log(data); + {# try { const response = await axios.patch('/admin/edit-team', data); if (response.status === 200) { alert('Team updated successfully!'); @@ -70,7 +90,7 @@ } catch (error) { console.error('Error updating team:', error); return alert(error.response.data); - } + } #} } {% endblock %} \ No newline at end of file diff --git a/templates/admin/team-list.njk b/templates/admin/team-list.njk index 42e0b0b..93f52d8 100644 --- a/templates/admin/team-list.njk +++ b/templates/admin/team-list.njk @@ -8,6 +8,7 @@ {% block pagecontent %}

Teams Management Page

  Registered Teams: {{ teams | length }}  
+ {% for team in teams %}
@@ -96,6 +97,24 @@ width: 7em; height: 2.5em; } + #control-btn { + align-self: center; + margin: 15px 0px; + width: 50%; + background-color: var(--red); + color: white; + border: 0px; + padding: 12px 0; + font-size: 18px; + font-weight: 600; + border-radius: 5px; + cursor: pointer; + transition: 0.3s; + } + + #control-btn:hover { + background-color: #c90c0c; + } @media (max-width: 600px) { button{ width:4rem; @@ -146,6 +165,16 @@ {% block customjs %} {% endblock %} \ No newline at end of file From 4332bd8c6d97cced17574e6ad6c1cae8ba231021 Mon Sep 17 00:00:00 2001 From: Ankan <93087057+ItsAnkan@users.noreply.github.com> Date: Fri, 8 Mar 2024 23:24:14 +0530 Subject: [PATCH 08/35] fjbkjdfhasjd --- database/Schemas/LocationQuestion.js | 10 ------ database/Schemas/Locations.js | 18 ++++++++++ database/Schemas/Team.js | 12 +++++-- routers/admin-router.js | 50 ++-------------------------- templates/admin/team-edit.njk | 3 -- templates/admin/team-list.njk | 2 +- templates/live/interface.njk | 20 +++++------ 7 files changed, 41 insertions(+), 74 deletions(-) delete mode 100644 database/Schemas/LocationQuestion.js create mode 100644 database/Schemas/Locations.js diff --git a/database/Schemas/LocationQuestion.js b/database/Schemas/LocationQuestion.js deleted file mode 100644 index c81c867..0000000 --- a/database/Schemas/LocationQuestion.js +++ /dev/null @@ -1,10 +0,0 @@ -const mongoose = require('mongoose'); - -const locationQuestionSchema = new mongoose.Schema({ - _id: { type: String, required: true }, - question: { type: String, required: true }, - answer: { type: String, required: true }, - locationCode: { type: String, required: true } -}, { collection: 'location-questions' }); - -module.exports = mongoose.model('LocationQuestion', locationQuestionSchema); diff --git a/database/Schemas/Locations.js b/database/Schemas/Locations.js new file mode 100644 index 0000000..c794b7e --- /dev/null +++ b/database/Schemas/Locations.js @@ -0,0 +1,18 @@ +const mongoose = require('mongoose'); + +const locationSchema = new mongoose.Schema({ + _id: { type: String, required: true }, + name: { type: String, required: true }, + pointerQuestion: [{ type: String, required: true }], + code: { type: String, required: true }, + questions: [ + { + number: { type: Number, required: true }, + question: { type: String, required: true }, + answer: { type: Number, required: true } + } + ], + keywords: [{ type: String, required: true }] +}, { collection: 'locations' }); + +module.exports = mongoose.model('Location', locationSchema); diff --git a/database/Schemas/Team.js b/database/Schemas/Team.js index 733b3fc..c0532fd 100644 --- a/database/Schemas/Team.js +++ b/database/Schemas/Team.js @@ -12,10 +12,16 @@ const teamSchema = new mongoose.Schema({ ], status: { type: String, required: true }, questionsAttempted: { type: Number, required: true, default: 0 }, - questions: [ + order: [ { - type: Number, - required: true + location: { + type: Number, + required: true + }, + question: { + type: Number, + required: true + } } ] }, { collection: 'event-teams' }); diff --git a/routers/admin-router.js b/routers/admin-router.js index f33b35e..cae76f8 100644 --- a/routers/admin-router.js +++ b/routers/admin-router.js @@ -3,52 +3,8 @@ const dbh = require('../database/handler'); const { body, validationResult } = require('express-validator'); const checkAdmin = require('./check-admin'); -const teams = [ - { - id: 1, - name: 'Team 1', - members: [ - { name: 'User 1', email: 'user4@example.com', phone: '123-456-7890' }, - { name: 'User 2', email: 'user5@example.com', phone: '987-654-3210' }, - { name: 'User 3', email: 'user6@example.com', phone: '555-555-5555' } - ] - }, - { - id: 2, - name: 'Team 2', - members: [ - { name: 'User 4', email: 'user4@example.com', phone: '123-456-7890' }, - { name: 'User 5', email: 'user5@example.com', phone: '987-654-3210' }, - { name: 'User 6', email: 'user6@example.com', phone: '555-555-5555' } - ] - }, - { - id: 3, - name: 'Team 3', - members: [ - { name: 'User 7', email: 'user7@example.com', phone: '111-222-3333' }, - { name: 'User 8', email: 'user8@example.com', phone: '444-555-6666' }, - { name: 'User 9', email: 'user9@example.com', phone: '777-888-9999' } - ] - } -]; - -const team = { - id: 1, - name: 'Team 1' -}; - -const locationQuestion = { - id: 1, - question: 'Where is the best waifu', - answer: 'Oregairu' -}; - -const riddleQuestion = { - id: 1, - question: 'Who is the best waifu', - answer: 'Shizuka Hiratsuka' -}; +const teams = require('../src/samples/teams.json'); +const riddleQuestions = require('../src/samples/riddleQuestions.json'); router.use('/', checkAdmin); @@ -58,7 +14,7 @@ router.get('/', (req, res) => { router.get('/edit-team', async (req, res) => { const teamID = parseInt(req.query.teamID); - const team = teams.find(team => team.id === teamID); + const team = teams.find(team => team._id === teamID); return res.renderFile('admin/team-edit.njk', { team }); diff --git a/templates/admin/team-edit.njk b/templates/admin/team-edit.njk index 1f703a4..1f718b7 100644 --- a/templates/admin/team-edit.njk +++ b/templates/admin/team-edit.njk @@ -33,9 +33,6 @@ .members { margin: 20px 0px; } - .form-container { - width: 80%; - } {% endblock %} diff --git a/templates/admin/team-list.njk b/templates/admin/team-list.njk index 93f52d8..c46c819 100644 --- a/templates/admin/team-list.njk +++ b/templates/admin/team-list.njk @@ -34,7 +34,7 @@
- +
{% endfor %} diff --git a/templates/live/interface.njk b/templates/live/interface.njk index 7479802..7663aec 100644 --- a/templates/live/interface.njk +++ b/templates/live/interface.njk @@ -24,11 +24,11 @@
{% call forms.form() %} - {{ forms.heading('h2', 'Enter the Location Code') }} - {{ forms.field('id','TeamID', team.id , type='hidden')}} - {{ forms.field('name', 'Team Name', team.name, type='hidden') }} - {{ forms.field('locationcode','Location Code') }} - + {{ forms.heading('h2', 'Enter the Location Code') }} + {{ forms.field('id','TeamID', team.id , type='hidden')}} + {{ forms.field('name', 'Team Name', team.name, type='hidden') }} + {{ forms.field('locationcode','Location Code') }} + {% endcall %}
@@ -37,11 +37,11 @@

{{ locationQuestion.question }}

{% call forms.form() %} - {{ forms.field('id','TeamID', team.id , type='hidden')}} - {{ forms.field('name', 'Team Name', team.name, type='hidden') }} - {{ forms.field('question', 'Question', locationQuestion.id, type='hidden') }} - {{ forms.field('locationanswer','Answer') }} - {{ forms.field('location','Location', locationQuestion.location, type='hidden') }} + {{ forms.field('id','TeamID', team.id , type='hidden')}} + {{ forms.field('name', 'Team Name', team.name, type='hidden') }} + {{ forms.field('question', 'Question', locationQuestion.id, type='hidden') }} + {{ forms.field('locationanswer','Answer') }} + {{ forms.field('location','Location', locationQuestion.location, type='hidden') }} {% endcall %}
From 33073d47e5a992a9d660d638d33cde04c1a5ac0c Mon Sep 17 00:00:00 2001 From: destryptor Date: Sat, 9 Mar 2024 00:24:59 +0530 Subject: [PATCH 09/35] States fixed yet again (with a bit of localStorage use) --- routers/live-router.js | 40 ------------ templates/live/interface.njk | 115 ++++++++++++++++------------------- 2 files changed, 53 insertions(+), 102 deletions(-) diff --git a/routers/live-router.js b/routers/live-router.js index f26fe60..2c1490d 100644 --- a/routers/live-router.js +++ b/routers/live-router.js @@ -63,46 +63,6 @@ router.patch('/location-code', async (req, res) => { } }); -router.patch('/location-submit-answer', async (req, res) => { - const teamID = parseInt(req.body.id); - const questionID = parseInt(req.body.question); - const answer = req.body.locationanswer; - const location = req.body.locationcode; - - // console.log(teamID); - // console.log(questionID); - // console.log(answer); - // console.log(location); - - // FIND QUESTION WITH ID IN LOCAL STORAGE - const question = locationQuestion; - if (question.answer === answer) { - // MARK QUESTION AS COMPLETED FOR TEAM BY FINDING TEAM BY ID AND ADDING QUESTION TO COMPLETED QUESTIONS LIST - return res.send('correct'); - } else { - return res.status(400).send('incorrect answer'); - } -}); - -router.patch('/riddle-submit-answer', async (req, res) => { - const teamID = parseInt(req.body.id); - const questionID = parseInt(req.body.question); - const answer = req.body.riddleanswer; - - // console.log(teamID); - // console.log(questionID); - // console.log(answer); - - // FIND QUESTION WITH ID IN LOCAL STORAGE - const question = riddleQuestion; - if (question.answer === answer) { - // MARK QUESTION AS COMPLETED FOR TEAM BY FINDING TEAM BY ID AND ADDING QUESTION TO COMPLETED QUESTIONS LIST - return res.send('correct'); - } else { - return res.status(400).send('incorrect answer'); - } -}); - router.post('/start-hunt', (req, res) => { if (!req.isAdmin) return res.status(403).send('Forbidden: Admin permissions not detected.'); handlerContext.huntStarted = true; diff --git a/templates/live/interface.njk b/templates/live/interface.njk index 7663aec..b7fabba 100644 --- a/templates/live/interface.njk +++ b/templates/live/interface.njk @@ -23,15 +23,6 @@
- {% call forms.form() %} - {{ forms.heading('h2', 'Enter the Location Code') }} - {{ forms.field('id','TeamID', team.id , type='hidden')}} - {{ forms.field('name', 'Team Name', team.name, type='hidden') }} - {{ forms.field('locationcode','Location Code') }} - - {% endcall %} -
-

Question

{{ locationQuestion.question }}

@@ -40,7 +31,7 @@ {{ forms.field('id','TeamID', team.id , type='hidden')}} {{ forms.field('name', 'Team Name', team.name, type='hidden') }} {{ forms.field('question', 'Question', locationQuestion.id, type='hidden') }} - {{ forms.field('locationanswer','Answer') }} + {{ forms.field('locationcode', 'Location Code') }} {{ forms.field('location','Location', locationQuestion.location, type='hidden') }} {% endcall %} @@ -48,12 +39,12 @@

Question

-

{{ locationQuestion.question }}

+

{% call forms.form() %} {{ forms.field('id','TeamID', team.id , type='hidden')}} {{ forms.field('name', 'Team Name', team.name, type='hidden') }} - {{ forms.field('question', 'Question', locationQuestion.id, type='hidden') }} + {{ forms.field('riddlequestion', 'Question', locationQuestion.id, type='hidden') }} {{ forms.field('riddleanswer','Answer') }} {% endcall %} @@ -182,7 +173,6 @@ function renderForm() { const locationCode = document.getElementById('location-code'); - const locationForm = document.getElementById('location-form'); const riddleForm = document.getElementById('riddle-form'); const messageBox = document.getElementById("message-box"); const messageCover = document.getElementById("message-cover"); @@ -190,9 +180,13 @@ const timeoutContainer = document.getElementById('timeout'); const interfaceContainer = document.getElementById('interface-container'); + const riddleQuestion = JSON.parse(localStorage.getItem('questions'))[0]; + if (riddleQuestion) { + document.getElementById('riddle-question').textContent = riddleQuestion.question; + } + interfaceContainer.style.display = (state.includes('question') || state.includes('code')) ? 'block' : 'none'; locationCode.style.display = state === 'location-code' ? 'block' : 'none'; - locationForm.style.display = state === 'location-question' ? 'block' : 'none'; riddleForm.style.display = state === 'riddle-question' ? 'block' : 'none'; messageBox.innerHTML = ''; messageCover.style.display = 'none'; @@ -223,7 +217,6 @@ } document.addEventListener("DOMContentLoaded", function () { - renderForm(); document.getElementById("location-submit-button").addEventListener("click", function (event) { event.preventDefault(); submit(); @@ -232,71 +225,69 @@ event.preventDefault(); submit(); }); - document.getElementById("location-code-submit-button").addEventListener("click", function (event) { - event.preventDefault(); - submit(); - }); + renderForm(); }); async function submit() { const data = getData(); + const answer = document.getElementById('riddleanswer').value; try { let response; - if (state === 'location-question') { - response = await axios.patch('/live/location-submit-answer', data); - } else if (state === 'riddle-question') { - response = await axios.patch('/live/riddle-submit-answer', data); - } else if (state === 'location-code') { - response = await axios.patch('/live/location-code', data); - } + if (state === 'location-code') { + try { + response = await axios.patch('/live/location-code', data); - if (response && response.status === 200) { - if (state == 'location-question' || state == 'riddle-question') { + if (response && response.status === 200) { + const messageBox = document.getElementById("message-box"); + messageBox.innerHTML = '

Correct Location!

'; + const messageCover = document.getElementById("message-cover"); + messageCover.style.display = 'block'; + setTimeout(() => { + messageCover.style.display = "none"; + state = 'riddle-question'; + localStorage.setItem('state', state); + renderForm(); + }, 10000); + } + } catch (error) { + if (error.response && error.response.status === 400) { + const messageBox = document.getElementById("message-box"); + messageBox.innerHTML = '

Incorrect Location Code!

'; + const messageCover = document.getElementById("message-cover"); + messageCover.style.display = 'block'; + setTimeout(() => { + messageCover.style.display = "none"; + }, 10000); + } + } + } else { + const riddleQuestion = JSON.parse(localStorage.getItem('questions'))[0]; + if(answer === riddleQuestion.answer) { const messageBox = document.getElementById("message-box"); messageBox.innerHTML = '

Correct Answer!

'; const messageCover = document.getElementById("message-cover"); messageCover.style.display = 'block'; setTimeout(() => { messageCover.style.display = "none"; - if (state === 'location-question') { - state = 'riddle-question'; - } else if (state === 'riddle-question') { state = 'location-code'; - } - localStorage.setItem('state', state); - renderForm(); + localStorage.setItem('state', state); + renderForm(); + }, 10000); + } else { + const messageBox = document.getElementById("message-box"); + messageBox.innerHTML = '

Incorrect Answer!

'; + const messageCover = document.getElementById("message-cover"); + messageCover.style.display = 'block'; + setTimeout(() => { + messageCover.style.display = "none"; + state = 'riddle-timeout'; + localStorage.setItem('state', state); + renderForm(); }, 10000); } - else { - state = 'location-question' - localStorage.setItem('state', state); - renderForm(); - } - } + } } catch (error) { console.error(error); - if (error.response && error.response.data === 'incorrect answer') { - const messageBox = document.getElementById("message-box"); - messageBox.innerHTML = '

Incorrect Answer!

'; - const messageCover = document.getElementById("message-cover"); - messageCover.style.display = 'block'; - setTimeout(() => { - messageCover.style.display = "none"; - state = state.includes('location') ? 'location-question' : 'riddle-timeout'; - localStorage.setItem('state', state); - renderForm(); - }, 10000); - } else if (error.response && error.response.data === 'incorrect location') { - const messageBox = document.getElementById("message-box"); - messageBox.innerHTML = '

Incorrect Location Code!

'; - const messageCover = document.getElementById("message-cover"); - messageCover.style.display = 'block'; - setTimeout(() => { - messageCover.style.display = "none"; - }, 10000); - state = 'location-code'; - localStorage.setItem('state', state); - } } } window.onload = async () => { From e114af42929da81dc3296aac78704b1ac0fb806f Mon Sep 17 00:00:00 2001 From: Ankan <93087057+ItsAnkan@users.noreply.github.com> Date: Sat, 9 Mar 2024 14:49:42 +0530 Subject: [PATCH 10/35] interface changes --- database/Schemas/Locations.js | 1 - database/Schemas/Team.js | 1 + routers/live-router.js | 56 ++--- src/samples/locations.json | 342 ++++++++++++++++++++++++++++ src/samples/teams.json | 411 ++++++++++++++++++++++++++++++++-- templates/live/interface.njk | 141 ++++++------ 6 files changed, 839 insertions(+), 113 deletions(-) create mode 100644 src/samples/locations.json diff --git a/database/Schemas/Locations.js b/database/Schemas/Locations.js index c794b7e..1dd3f1b 100644 --- a/database/Schemas/Locations.js +++ b/database/Schemas/Locations.js @@ -7,7 +7,6 @@ const locationSchema = new mongoose.Schema({ code: { type: String, required: true }, questions: [ { - number: { type: Number, required: true }, question: { type: String, required: true }, answer: { type: Number, required: true } } diff --git a/database/Schemas/Team.js b/database/Schemas/Team.js index c0532fd..e9c4303 100644 --- a/database/Schemas/Team.js +++ b/database/Schemas/Team.js @@ -3,6 +3,7 @@ const mongoose = require('mongoose'); const teamSchema = new mongoose.Schema({ _id: { type: Number, required: true }, name: { type: String, required: true }, + password: { type: String, requred: true }, members: [ { name: { type: String, required: true }, diff --git a/routers/live-router.js b/routers/live-router.js index 2c1490d..bf5f9fc 100644 --- a/routers/live-router.js +++ b/routers/live-router.js @@ -4,6 +4,7 @@ const { body, validationResult } = require('express-validator'); const checker = require('../src/checker.js'); const teams = require('../src/samples/teams.json'); +const locations = require('../src/samples/locations.json'); const riddleQuestions = require('../src/samples/riddleQuestions.json'); const handlerContext = {}; @@ -15,15 +16,15 @@ router.use((req, res, next) => { const team = teams[1]; -const locationQuestion = { - id: 1, - question: 'Where is the best waifu', - answer: 'Oregairu' -}; +// const locationQuestion = { +// id: 1, +// question: 'Where is the best waifu', +// answer: 'Oregairu' +// }; -const riddleQuestion = riddleQuestions[0]; +// const riddleQuestion = riddleQuestions[0]; -const locationCode = 'ABC123'; +// const locationCode = 'ABC123'; router.get('/', async (req, res) => { if (req.isAdmin) { @@ -34,35 +35,40 @@ router.get('/', async (req, res) => { // if (!handlerContext.quizStarted) return res.redirect('/'); return res.renderFile('live/interface.njk', { team, - locationQuestion, started: handlerContext.huntStarted }); // return res.renderFile('live/interface.njk'); } }); -router.post('/get-questions', (req, res) => { +router.post('/get-data', (req, res) => { const teamID = req.body.teamID; - console.log(teamID); - return res.status(200).send(JSON.stringify( - teams.find((e) => e._id === teamID).questions.map((id) => riddleQuestions.find((q) => q.id === id)) - )); + const team = teams.find((e) => e._id === teamID); + return res.status(200).send(JSON.stringify({ + team, + locations: team.order.map((o) => locations.find((l) => l._id === o.location)) + })); }); -router.patch('/location-code', async (req, res) => { - const teamID = parseInt(req.body.id); - const location = req.body.locationcode; - // console.log(teamID); - // console.log(location); - // FIND TEAM BY ID IN LOCAL STORAGE - // MARK TEAM AS COMPLETED FOR LOCATION BY FINDING TEAM BY ID AND ADDING LOCATION TO COMPLETED LOCATIONS LIST - if (location === locationCode) { - return res.send('correct'); - } else { - return res.status(400).send('incorrect location'); - } +router.post('/get-attempted', (req, res) => { + const teamID = req.body.teamID; + return res.status(200).send(teams.find((e) => e._id === teamID).questionsAttempted); }); +// router.patch('/location-code', async (req, res) => { +// const teamID = parseInt(req.body.id); +// const location = req.body.locationcode; +// // console.log(teamID); +// // console.log(location); +// // FIND TEAM BY ID IN LOCAL STORAGE +// // MARK TEAM AS COMPLETED FOR LOCATION BY FINDING TEAM BY ID AND ADDING LOCATION TO COMPLETED LOCATIONS LIST +// if (location === locationCode) { +// return res.send('correct'); +// } else { +// return res.status(400).send('incorrect location'); +// } +// }); + router.post('/start-hunt', (req, res) => { if (!req.isAdmin) return res.status(403).send('Forbidden: Admin permissions not detected.'); handlerContext.huntStarted = true; diff --git a/src/samples/locations.json b/src/samples/locations.json new file mode 100644 index 0000000..e36fdc5 --- /dev/null +++ b/src/samples/locations.json @@ -0,0 +1,342 @@ +[ + { + "_id": 0, + "name": "XYZ Location 1", + "pointerQuestion": [ + "Go To Location 1" + ], + "code": "a1b2c3", + "questions": [ + { + "question": "Who is the protagonist of Attack on Titan?", + "answer": 0 + }, + { + "question": "What is the name of Narutos sensei?", + "answer": 1 + }, + { + "question": "Which anime features a character named Luffy?", + "answer": 2 + } + ], + "keywords": [ + "Eren", + "Kakashi", + "One Piece", + "Titan", + "Naruto", + "Monkey D. Luffy", + "Shinobi", + "Shounen", + "Shingeki no Kyojin", + "Ninja" + ] + }, + { + "_id": 1, + "name": "XYZ Location 2", + "pointerQuestion": [ + "Go To Location 2" + ], + "code": "x4y5z6", + "questions": [ + { + "question": "In Death Note, who is the main antagonist?", + "answer": 0 + }, + { + "question": "What is the name of the academy in My Hero Academia?", + "answer": 1 + }, + { + "question": "Who is the creator of Fullmetal Alchemist?", + "answer": 2 + } + ], + "keywords": [ + "Light", + "UA", + "Arakawa", + "Death", + "Hero", + "Alchemy", + "Notebook", + "Hero Academia", + "Edward Elric", + "Bakugo" + ] + }, + { + "_id": 2, + "name": "XYZ Location 3", + "pointerQuestion": [ + "Go To Location 3" + ], + "code": "p7q8r9", + "questions": [ + { + "question": "What is the name of the protagonist in Dragon Ball Z?", + "answer": 0 + }, + { + "question": "Which anime features a character named Pikachu?", + "answer": 1 + }, + { + "question": "What is the title of the anime about a shinigami named Ryuk?", + "answer": 2 + } + ], + "keywords": [ + "Goku", + "Pokémon", + "Dragon", + "Ball", + "Z", + "Pikachu", + "Ash", + "Shinigami", + "Ryuk", + "Death" + ] + }, + { + "_id": 3, + "name": "XYZ Location 4", + "pointerQuestion": [ + "Go To Location 4" + ], + "code": "m2n1o5", + "questions": [ + { + "question": "Who is the main character in Sword Art Online?", + "answer": 0 + }, + { + "question": "What is the name of the mysterious organization in Attack on Titan?", + "answer": 1 + }, + { + "question": "Which anime features a character named Vegeta?", + "answer": 2 + } + ], + "keywords": [ + "Kirito", + "Survey Corps", + "Vegeta", + "Sword", + "Art", + "Online", + "Titan", + "Organization", + "Eldia", + "Saiyan" + ] + }, + { + "_id": 4, + "name": "XYZ Location 5", + "pointerQuestion": [ + "Go To Location 5" + ], + "code": "j3k4l8", + "questions": [ + { + "question": "What is the name of the demon sword in Soul Eater?", + "answer": 0 + }, + { + "question": "Who is the captain of Straw Hat Pirates in One Piece?", + "answer": 1 + }, + { + "question": "What is the name of the world in Attack on Titan?", + "answer": 2 + } + ], + "keywords": [ + "Soul", + "Luffy", + "Blade", + "Pirates", + "Straw Hat", + "Blair", + "Eldia", + "Soul Eater", + "Death", + "Demon" + ] + }, + { + "_id": 5, + "name": "XYZ Location 6", + "pointerQuestion": [ + "Go To Location 6" + ], + "code": "h9i0g7", + "questions": [ + { + "question": "What is the name of Narutos rival?", + "answer": 0 + }, + { + "question": "Which anime features a character named Naruto?", + "answer": 1 + }, + { + "question": "Who is the teacher of Monkey D. Luffy in One Piece?", + "answer": 2 + } + ], + "keywords": [ + "Sasuke", + "Naruto", + "Rival", + "Uzumaki", + "Zoro", + "Ninja", + "Pirate", + "Luffy", + "Swordsman", + "Roronoa" + ] + }, + { + "_id": 6, + "name": "XYZ Location 7", + "pointerQuestion": [ + "Go To Location 7" + ], + "code": "u5v6w2", + "questions": [ + { + "question": "What is the name of the captain of the 11th Division in Bleach?", + "answer": 0 + }, + { + "question": "Which anime revolves around a game called Gungi?", + "answer": 1 + }, + { + "question": "What is the name of the protagonist in One Punch Man?", + "answer": 2 + } + ], + "keywords": [ + "Kenpachi Zaraki", + "Bleach", + "Captain", + "Gungi", + "Game", + "Saitama", + "One Punch", + "Hero", + "Strongest", + "S-Class" + ] + }, + { + "_id": 7, + "name": "XYZ Location 8", + "pointerQuestion": [ + "Go To Location 8" + ], + "code": "f8e7d6", + "questions": [ + { + "question": "Who is the creator of Naruto?", + "answer": 0 + }, + { + "question": "What is the name of the black cat in Soul Eater?", + "answer": 1 + }, + { + "question": "Which anime features a character named Gon?", + "answer": 2 + } + ], + "keywords": [ + "Masashi Kishimoto", + "Blair", + "Gon", + "Manga", + "Anime", + "Hunter", + "X", + "Hunter", + "Nen", + "Adventurer" + ] + }, + { + "_id": 8, + "name": "XYZ Location 9", + "pointerQuestion": [ + "Go To Location 9" + ], + "code": "t4s3r2", + "questions": [ + { + "question": "Who is the main character in 'Fairy Tail'?", + "answer": 0 + }, + { + "question": "What is the name of the school in 'Naruto'?", + "answer": 1 + }, + { + "question": "Who is the main character in One Piece?", + "answer": 2 + } + ], + "keywords": [ + "Natsu", + "Ninja", + "Konoha", + "Luffy", + "Guild", + "Magic", + "Wizard", + "Zoro", + "Dragon", + "Pirate" + ] + }, + { + "_id": 9, + "name": "XYZ Location 10", + "pointerQuestion": [ + "Go To Location 10" + ], + "code": "v1w2x3", + "questions": [ + { + "question": "Which anime features a character named Edward Elric?", + "answer": 0 + }, + { + "question": "What is the name of the village in Naruto?", + "answer": 1 + }, + { + "question": "Who is the captain of the 10th Division in Bleach?", + "answer": 2 + } + ], + "keywords": [ + "Fullmetal Alchemist", + "Konoha", + "Edward", + "Elric", + "Alchemist", + "Naruto", + "Soul Society", + "Captain", + "Toshiro Hitsugaya", + "Ice" + ] + } +] \ No newline at end of file diff --git a/src/samples/teams.json b/src/samples/teams.json index 7c0d802..fb49c02 100644 --- a/src/samples/teams.json +++ b/src/samples/teams.json @@ -26,64 +26,427 @@ ], "status": "finding", "questionsAttempted": 0, - "questions": [1, 4, 7] + "order": [ + { + "location": 0, + "pointer": 0, + "question": 0 + }, + { + "location": 1, + "pointer": 0, + "question": 1 + }, + { + "location": 2, + "pointer": 0, + "question": 2 + } + ] }, { "_id": 2, "name": "Team 2", "members": [ { - "name": "Eva", - "email": "eva@example.com", - "phone": "9876543211" + "name": "Ella", + "email": "ella@example.com", + "phone": "4567890123" }, { "name": "Frank", "email": "frank@example.com", - "phone": "1234567891" + "phone": "6543210987" }, { - "name": "Grace", - "email": "grace@example.com", - "phone": "5551234568" + "name": "George", + "email": "george@example.com", + "phone": "1235556789" }, { - "name": "Henry", - "email": "henry@example.com", - "phone": "1239874560" + "name": "Hannah", + "email": "hannah@example.com", + "phone": "3219876543" } ], "status": "finding", "questionsAttempted": 0, - "questions": [2, 5, 8] + "order": [ + { + "location": 3, + "pointer": 0, + "question": 1 + }, + { + "location": 4, + "pointer": 0, + "question": 2 + }, + { + "location": 5, + "pointer": 0, + "question": 0 + } + ] }, { "_id": 3, "name": "Team 3", "members": [ { - "name": "Ivy", - "email": "ivy@example.com", - "phone": "1234567892" + "name": "Ian", + "email": "ian@example.com", + "phone": "7890123456" }, { "name": "Jack", "email": "jack@example.com", - "phone": "0987654322" + "phone": "3210987654" + }, + { + "name": "Karen", + "email": "karen@example.com", + "phone": "5678901234" + }, + { + "name": "Lily", + "email": "lily@example.com", + "phone": "5432167890" + } + ], + "status": "finding", + "questionsAttempted": 0, + "order": [ + { + "location": 6, + "pointer": 0, + "question": 2 + }, + { + "location": 7, + "pointer": 0, + "question": 0 + }, + { + "location": 8, + "pointer": 0, + "question": 1 + } + ] + }, + { + "_id": 4, + "name": "Team 4", + "members": [ + { + "name": "Mike", + "email": "mike@example.com", + "phone": "9012345678" + }, + { + "name": "Nancy", + "email": "nancy@example.com", + "phone": "1098765432" + }, + { + "name": "Oscar", + "email": "oscar@example.com", + "phone": "8901234567" + }, + { + "name": "Paul", + "email": "paul@example.com", + "phone": "4321098765" + } + ], + "status": "finding", + "questionsAttempted": 0, + "order": [ + { + "location": 9, + "pointer": 0, + "question": 0 + }, + { + "location": 0, + "pointer": 0, + "question": 1 + }, + { + "location": 1, + "pointer": 0, + "question": 2 + } + ] + }, + { + "_id": 5, + "name": "Team 5", + "members": [ + { + "name": "Quinn", + "email": "quinn@example.com", + "phone": "3456789012" + }, + { + "name": "Rachel", + "email": "rachel@example.com", + "phone": "2109876543" + }, + { + "name": "Sam", + "email": "sam@example.com", + "phone": "6789012345" + }, + { + "name": "Tim", + "email": "tim@example.com", + "phone": "9876543210" + } + ], + "status": "finding", + "questionsAttempted": 0, + "order": [ + { + "location": 2, + "pointer": 0, + "question": 0 }, { - "name": "Kevin", - "email": "kevin@example.com", - "phone": "5551234569" + "location": 3, + "pointer": 0, + "question": 1 }, { - "name": "Linda", - "email": "linda@example.com", - "phone": "7894561230" + "location": 4, + "pointer": 0, + "question": 2 + } + ] + }, + { + "_id": 6, + "name": "Team 6", + "members": [ + { + "name": "Xavier", + "email": "xavier@example.com", + "phone": "1234567890" + }, + { + "name": "Yvonne", + "email": "yvonne@example.com", + "phone": "0987654321" + }, + { + "name": "Zach", + "email": "zach@example.com", + "phone": "5551234567" + }, + { + "name": "Walter", + "email": "walter@example.com", + "phone": "9876543210" } ], "status": "finding", "questionsAttempted": 0, - "questions": [3, 6, 9] + "order": [ + { + "location": 5, + "pointer": 0, + "question": 1 + }, + { + "location": 6, + "pointer": 0, + "question": 0 + }, + { + "location": 7, + "pointer": 0, + "question": 2 + } + ] + }, + { + "_id": 7, + "name": "Team 7", + "members": [ + { + "name": "Xander", + "email": "xander@example.com", + "phone": "6789012345" + }, + { + "name": "Yasmine", + "email": "yasmine@example.com", + "phone": "5432109876" + }, + { + "name": "Zack", + "email": "zack@example.com", + "phone": "8901234567" + }, + { + "name": "Alice", + "email": "alice2@example.com", + "phone": "2345678901" + } + ], + "status": "finding", + "questionsAttempted": 0, + "order": [ + { + "location": 5, + "pointer": 0, + "question": 2 + }, + { + "location": 6, + "pointer": 0, + "question": 0 + }, + { + "location": 7, + "pointer": 0, + "question": 1 + } + ] + }, + { + "_id": 8, + "name": "Team 8", + "members": [ + { + "name": "Ben", + "email": "ben@example.com", + "phone": "7654321098" + }, + { + "name": "Charlotte", + "email": "charlotte@example.com", + "phone": "5432109876" + }, + { + "name": "David", + "email": "david@example.com", + "phone": "6789012345" + }, + { + "name": "Emma", + "email": "emma@example.com", + "phone": "4567890123" + } + ], + "status": "finding", + "questionsAttempted": 0, + "order": [ + { + "location": 8, + "pointer": 0, + "question": 2 + }, + { + "location": 9, + "pointer": 0, + "question": 0 + }, + { + "location": 0, + "pointer": 0, + "question": 1 + } + ] + }, + { + "_id": 9, + "name": "Team 9", + "members": [ + { + "name": "Fred", + "email": "fred@example.com", + "phone": "8901234567" + }, + { + "name": "Grace", + "email": "grace@example.com", + "phone": "3456789012" + }, + { + "name": "Henry", + "email": "henry@example.com", + "phone": "6543210987" + }, + { + "name": "Isabel", + "email": "isabel@example.com", + "phone": "2345678901" + } + ], + "status": "finding", + "questionsAttempted": 0, + "order": [ + { + "location": 1, + "pointer": 0, + "question": 0 + }, + { + "location": 2, + "pointer": 0, + "question": 1 + }, + { + "location": 3, + "pointer": 0, + "question": 2 + } + ] + }, + { + "_id": 10, + "name": "Team 10", + "members": [ + { + "name": "Jack", + "email": "jack2@example.com", + "phone": "9876543210" + }, + { + "name": "Karen", + "email": "karen2@example.com", + "phone": "6789012345" + }, + { + "name": "Liam", + "email": "liam@example.com", + "phone": "4567890123" + }, + { + "name": "Mia", + "email": "mia@example.com", + "phone": "1234567890" + } + ], + "status": "finding", + "questionsAttempted": 0, + "order": [ + { + "location": 4, + "pointer": 0, + "question": 0 + }, + { + "location": 5, + "pointer": 0, + "question": 1 + }, + { + "location": 6, + "pointer": 0, + "question": 2 + } + ] } -] +] \ No newline at end of file diff --git a/templates/live/interface.njk b/templates/live/interface.njk index b7fabba..301e7f7 100644 --- a/templates/live/interface.njk +++ b/templates/live/interface.njk @@ -10,7 +10,11 @@
-
+
+

Dummy

+
+{{ loadingscreen('container') }} +