Skip to content

Commit

Permalink
Treasure hunt - Test build (#17)
Browse files Browse the repository at this point in the history
* Team List page for admin and Timeout page done (kinda)

* Admin frontend completed with routes

* Redundant (possibly) validation rules removed

* State transition with localStorage complete

* State transition fixes and Basic Model creation

* removed unused tests

* localstorage hehe

* fjbkjdfhasjd

* States fixed yet again (with a bit of localStorage use)

* interface changes

* DB stuff

* Auth

* shrinkwrap mishap

* Edit and list team work

* interface works, almost

* test

* leaning

* backen shii

* Onkon baka

* Onkon lolicon

* Onkon in prison

* Onkon's sentence increased

* Onkon's sentence++

* Onkon's sentence*=2

* why booli ;-;

* nvm i get it ;-;

* i need sleep

* Onkon is slowly turning into a mad man

* Onkon is slowly turning into a mad man

* Onkon was whacked by the jail super

* Onkon's sentence reduced by half

* started ???

* Onkon dropped the soap

* ono

* didnt knwo she was underaged

---------

Co-authored-by: destryptor <sharanya.chakraborty@kgpian.iitkgp.ac.in>
Co-authored-by: Ankan <93087057+ItsAnkan@users.noreply.github.com>
  • Loading branch information
3 people authored Mar 10, 2024
1 parent 81828a7 commit 9f1e940
Show file tree
Hide file tree
Showing 22 changed files with 1,917 additions and 394 deletions.
4 changes: 4 additions & 0 deletions assets/styles/form.scss
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ button:hover {
background-color: #c90c0c;
}

button:disabled {
background-color: var(--light-pink);
}

.item {
display: flex;
flex-direction: column;
Expand Down
17 changes: 17 additions & 0 deletions database/Schemas/Location.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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: [
{
question: { type: String, required: true },
answer: { type: Number, required: true }
}
],
keywords: [{ type: String, required: true }]
}, { collection: 'locations' });

module.exports = mongoose.model('Location', locationSchema);
9 changes: 9 additions & 0 deletions database/Schemas/RiddleQuestion.js
Original file line number Diff line number Diff line change
@@ -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);
27 changes: 27 additions & 0 deletions database/Schemas/Team.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const mongoose = require('mongoose');

const teamSchema = new mongoose.Schema({
_id: { type: Number, required: true },
name: { type: String, required: true },
isAdmin: Boolean,
password: { type: String, requred: 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, default: 0 },
order: [
{
location: { type: Number, required: true },
pointer: { type: Number, required: true },
question: { type: Number, required: true }
}
],
timeout: { type: [Date, null] }
}, { collection: 'event-teams' });

module.exports = mongoose.model('Team', teamSchema);
9 changes: 9 additions & 0 deletions database/Schemas/TeamSession.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const mongoose = require('mongoose');

const sessionSchema = new mongoose.Schema({
_id: { type: String, required: true },
teamId: { type: Number, required: true },
timestamp: { type: Date, default: new Date() }
}, { collection: 'team-session' });

module.exports = mongoose.model('TeamSession', sessionSchema);
85 changes: 84 additions & 1 deletion database/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ const Session = require('./Schemas/Session');
const Questions = require('./Schemas/Questions');
const Records = require('./Schemas/Records');
const Results = require('./Schemas/Results');
// Treasure Hunt stuff
const Location = require('./Schemas/Location');
const Team = require('./Schemas/Team');
const TeamSession = require('./Schemas/TeamSession');

async function createUser (userData) {
const _id = userData.userID ?? (await User.find({ _id: { '$gt': 10000 } })).length + 10001;
Expand Down Expand Up @@ -171,6 +175,76 @@ async function getLiveResults (quizId) {
return await Results.find({ quizId }).lean().sort({ 'points': -1 });
}

// Treasure Hunt Methods

async function getLocations () {
return await Location.find().lean();
}

async function getTeams () {
return await Team.find({ isAdmin: [undefined, false] }).lean();
}

async function getTeamById (_id) {
return await Team.findById(_id);
}

async function validateTeam ({ username: teamId, password }) {
const team = await Team.findById(~~teamId);
if (!team) throw new Error('Team could not be found');
if (team.password === password) return team._id;
else throw new Error('Password does not match');
}

async function updateTeamDetails (ctx) {
const { id, name, members } = ctx;
const team = await Team.findById(id);
team.name = name;
team.members = members;
return await team.save();
}

async function updateTeamStatus (ctx) {
const { _id, status } = ctx;
const team = await Team.findById(_id);
team.status = status;
if (status === 'riddle-timeout') {
team.timeout = new Date(Date.now() + 120 * 1000);
setTimeout(async () => {
team.status = 'riddle-question';
team.timeout = null;
await team.save();
}, 120 * 1000);
} else if (status === 'location-code') {
team.questionsAttempted = ctx.questionNo;
}
return await team.save();
}

async function getTeamFromSessionID (sessionId) {
const session = await TeamSession.findById(sessionId);
const team = await Team.findById(session.teamId);
if (!team) throw new Error('Team Not Found');
else return team;
}

async function createTeamSession (teamId) {
// 3327: You Are My Special
const sessionId = [3, 3, 2, 7].map(i => (Math.random() + 1).toString(36).substring(2, 2 + i)).join('-');
const session = new TeamSession({
_id: sessionId,
teamId: teamId
});
await session.save();
return sessionId;
}

async function removeTeamSession (sessionId) {
// Use this if we want to remove sessions after logout
await Session.findByIdAndDelete(sessionId);
}


module.exports = {
createUser,
editUser,
Expand All @@ -190,5 +264,14 @@ module.exports = {
addLiveRecord,
addLiveResult,
updateLiveResult,
getLiveResults
getLiveResults,
getLocations,
getTeams,
getTeamById,
validateTeam,
updateTeamDetails,
updateTeamStatus,
getTeamFromSessionID,
createTeamSession,
removeTeamSession
};
58 changes: 50 additions & 8 deletions routers/admin-router.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,67 @@ const dbh = require('../database/handler');
const { body, validationResult } = require('express-validator');
const checkAdmin = require('./check-admin');

const teams = require('../src/samples/teams.json');
const riddleQuestions = require('../src/samples/riddleQuestions.json');

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 = await dbh.getTeamById(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')
], 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 },
{ name: req.body.name4, email: req.body.email4, phone: req.body.phone4 }
].filter(i => i.name)
};
// const teamIndex = teams.findIndex(t => t.id === team.id);
// if (teamIndex === -1) {
// teams.push(team);
// }
await dbh.updateTeamDetails(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 });
});

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')
Expand Down
108 changes: 54 additions & 54 deletions routers/auth-router.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const router = require('express').Router();
const dbh = require('../database/handler');
const { body, validationResult } = require('express-validator');

const profile = require('../src/profile.json');
// const profile = require('../src/profile.json');

router.use((req, res, next) => {
if (['/login', '/signup', '/logout'].indexOf(req.path) + 1 && PARAMS.mongoless)
Expand All @@ -22,15 +22,15 @@ router.get('/logout', (req, res) => {
return res.renderFile('auth/logout.njk');
});

router.get('/signup', (req, res) => {
if (req.loggedIn) return res.redirect('/');
return res.renderFile('auth/signup.njk');
});
// router.get('/signup', (req, res) => {
// if (req.loggedIn) return res.redirect('/');
// return res.renderFile('auth/signup.njk');
// });

router.get('/profile', (req, res) => {
if (!req.loggedIn) return res.redirect('/login');
return res.renderFile('auth/profile.njk', { user: req.user, pics: Object.entries(profile) });
});
// router.get('/profile', (req, res) => {
// if (!req.loggedIn) return res.redirect('/login');
// return res.renderFile('auth/profile.njk', { user: req.user, pics: Object.entries(profile) });
// });
// Post requests here

router.post('/login', [
Expand All @@ -47,49 +47,49 @@ router.post('/login', [
const errorMessages = errors.array().map(error => error.msg);
throw new Error(errorMessages[0]);
}
const userData = req.body;
const sessionID = await dbh.createSession(await dbh.validateUser(userData));
const teamData = req.body;
const sessionID = await dbh.createTeamSession(await dbh.validateTeam(teamData));
res.cookie('sessionID', sessionID);
res.send('logged in >w<');
});

router.post('/signup', [
body('name')
.trim()
.notEmpty().withMessage('No Name Provided'),
body('roll')
.trim()
.notEmpty().withMessage('No Roll Provided')
.matches(/^[12][890123][A-Z]{2}[0-9][A-Z0-9]{2}\d\d$/i).withMessage('Please provide a valid roll number'),
body('email')
.trim()
.notEmpty().withMessage('No Email Provided')
.isEmail().withMessage('Please provide a valid email'),
body('phone')
.trim()
.notEmpty().withMessage('No Phone Number Provided')
.isMobilePhone('en-IN').withMessage('Please provide a valid phone number'),
body('username')
.trim()
.notEmpty().withMessage('No Username Provided')
.isLength({ min: 3, max: 32 }).withMessage('Username must be between 3 and 32 characters long.')
.matches(/^\S+$/).withMessage('Username cannot contain whitespaces'),
body('password')
.trim()
.notEmpty().withMessage('No Password Provided')
.isLength({ min: 6, max: 32 }).withMessage('Password must be between 6 and 32 characters long.')
.matches(/^\S+$/).withMessage('Password cannot contain whitespaces')
], async (req, res) => {
if (req.loggedIn) return res.error('How are you signing up when you are already logged in, what is this power !');
const errors = validationResult(req);
if (!errors.isEmpty()) {
const errorMessages = errors.array().map(error => error.msg);
throw new Error(errorMessages[0]);
}
const sessionID = await dbh.createSession(await dbh.createUser(req.body));
res.cookie('sessionID', sessionID);
res.send('Registered Successfully UwU');
});
// router.post('/signup', [
// body('name')
// .trim()
// .notEmpty().withMessage('No Name Provided'),
// body('roll')
// .trim()
// .notEmpty().withMessage('No Roll Provided')
// .matches(/^[12][890123][A-Z]{2}[0-9][A-Z0-9]{2}\d\d$/i).withMessage('Please provide a valid roll number'),
// body('email')
// .trim()
// .notEmpty().withMessage('No Email Provided')
// .isEmail().withMessage('Please provide a valid email'),
// body('phone')
// .trim()
// .notEmpty().withMessage('No Phone Number Provided')
// .isMobilePhone('en-IN').withMessage('Please provide a valid phone number'),
// body('username')
// .trim()
// .notEmpty().withMessage('No Username Provided')
// .isLength({ min: 3, max: 32 }).withMessage('Username must be between 3 and 32 characters long.')
// .matches(/^\S+$/).withMessage('Username cannot contain whitespaces'),
// body('password')
// .trim()
// .notEmpty().withMessage('No Password Provided')
// .isLength({ min: 6, max: 32 }).withMessage('Password must be between 6 and 32 characters long.')
// .matches(/^\S+$/).withMessage('Password cannot contain whitespaces')
// ], async (req, res) => {
// if (req.loggedIn) return res.error('How are you signing up when you are already logged in, what is this power !');
// const errors = validationResult(req);
// if (!errors.isEmpty()) {
// const errorMessages = errors.array().map(error => error.msg);
// throw new Error(errorMessages[0]);
// }
// const sessionID = await dbh.createSession(await dbh.createUser(req.body));
// res.cookie('sessionID', sessionID);
// res.send('Registered Successfully UwU');
// });

app.post('/logout', async (req, res, next) => {
// If we may require them, then...
Expand All @@ -100,12 +100,12 @@ app.post('/logout', async (req, res, next) => {
return res.send('Signed out successfully. Mata ne.');
});

app.post('/edit-profile', async (req, res) => {
if (!req.loggedIn) return res.error('nande koko ni ??');
const response = await dbh.updateImage(req.user.username, profile[req.body.character]);
if (!response) throw new Error('Something went wrong');
return res.send('updated succesfully');
});
// app.post('/edit-profile', async (req, res) => {
// if (!req.loggedIn) return res.error('nande koko ni ??');
// const response = await dbh.updateImage(req.user.username, profile[req.body.character]);
// if (!response) throw new Error('Something went wrong');
// return res.send('updated succesfully');
// });

module.exports = {
route: '/',
Expand Down
Loading

0 comments on commit 9f1e940

Please sign in to comment.