Live update + class progress

This commit is contained in:
SowinskiBraeden committed 2021-01-13 12:38:17 -08:00
1 parent a404f5a61b
commit 3307307025
14 files changed
+8263 -185

No files matched your search

+2 -2
View File
@@ -1,5 +1,5 @@
# Port to start server on. # Port to start server on.
PORT=5000 PORT=8080
# MongoDB connection URI. # MongoDB connection URI.
DB_URI=mongodb://localhost/knoldus DB_URI=mongodb://localhost/27017
+2 -1
View File
@@ -3,6 +3,7 @@
School Project School Project
This school project is for my teacher to have students This school project is for my teacher to have students
log in and check out their XP and assignments. log in and check out their XP and assignments.
This website application is not available online, this is just a locally run website at our school.
### Requirements : ### Requirements :
1. [Node.js](https://nodejs.org/en/) 1. [Node.js](https://nodejs.org/en/)
@@ -14,7 +15,7 @@ log in and check out their XP and assignments.
3. Run `npm install` to install dependencies. 3. Run `npm install` to install dependencies.
4. Duplicate `.env.example` and rename the new file to `.env`. Edit to your configurations. 4. Duplicate `.env.example` and rename the new file to `.env`. Edit to your configurations.
1. Run `npm start` to boot up server. 1. Run `npm start` to boot up server.
1. Go to http://localhost:5000. Or Whatever you set it to in the `.env` file. 1. Go to http://localhost:8080. Or Whatever you set it to in the `.env` file.
### Accessing the Database ### Accessing the Database
1. Locally this will use any db you set the DB_URI to in the `.env` file. 1. Locally this will use any db you set the DB_URI to in the `.env` file.
+18 -6
View File
@@ -5,9 +5,11 @@ const passport = require('passport');
const flash = require('connect-flash'); const flash = require('connect-flash');
const session = require('express-session'); const session = require('express-session');
const bodyParser = require('body-parser'); const bodyParser = require('body-parser');
var path = require('path'); const http = require('http');
var fs = require('fs'); const path = require('path');
var dotenv = require('dotenv'); const fs = require('fs');
const dotenv = require('dotenv');
const socket = require('socket.io');
dotenv.config(); dotenv.config();
const app = express(); const app = express();
@@ -21,7 +23,7 @@ const db = require('./config/keys').mongoURI;
// Connect to MongoDB // Connect to MongoDB
mongoose mongoose
.connect( .connect(
process.env.DB_URI || 'mongodb://localhost/knoldus', process.env.DB_URI || 'mongodb://localhost/27017',
{ useNewUrlParser: true, useUnifiedTopology: true} { useNewUrlParser: true, useUnifiedTopology: true}
) )
.then(() => console.log('MongoDB Connected')) .then(() => console.log('MongoDB Connected'))
@@ -63,6 +65,16 @@ app.use(function(req, res, next) {
app.use('/', require('./routes/index.js')); app.use('/', require('./routes/index.js'));
app.use('/users', require('./routes/users.js')); app.use('/users', require('./routes/users.js'));
const PORT = process.env.PORT || 5000; const PORT = process.env.PORT || 8080;
const server = app.listen(PORT, function() {
console.log(`Server listening on port ${PORT}`);
});
let io = socket(server);
app.listen(PORT, console.log(`Server started on port ${PORT}`)); io.on('connection', function(socket) {
console.log('connected');
socket.on('add:xp', function(data) {
io.sockets.emit("added:xp", data);
});
});
+20
View File
@@ -0,0 +1,20 @@
const mongoose = require('mongoose');
const CourseSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
description: {
type: String,
required: true
},
grade: {
type: Number,
required: true
}
});
const Course = mongoose.model('Course', CourseSchema);
module.exports = Course;
+3
View File
@@ -20,6 +20,9 @@ const QuestSchema = new mongoose.Schema({
instruction: { instruction: {
type: String, type: String,
required: true required: true
},
referenceClass: {
type: [String]
} }
}); });
+10
View File
@@ -28,6 +28,16 @@ const UserSchema = new mongoose.Schema({
xp: { xp: {
type: Number, type: Number,
default: 0 default: 0
},
class: {
className: {
type: String,
default: null
},
questIndex: {
type: Number,
defualt: 0
}
} }
}); });
+215 -5
View File
@@ -4,6 +4,26 @@
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
"@types/component-emitter": {
"version": "1.2.10",
"resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz",
"integrity": "sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg=="
},
"@types/cookie": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.0.tgz",
"integrity": "sha512-y7mImlc/rNkvCRmg8gC3/lj87S7pTUIJ6QGjwHR9WQJcFs+ZMTOaoPrkdFA/YdbuqVEmEbb5RdhVxMkAcgOnpg=="
},
"@types/cors": {
"version": "2.8.9",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.9.tgz",
"integrity": "sha512-zurD1ibz21BRlAOIKP8yhrxlqKx6L9VCwkB5kMiP6nZAhoF5MvC7qS1qPA7nRcr1GJolfkQC7/EAL4hdYejLtg=="
},
"@types/node": {
"version": "14.14.20",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.20.tgz",
"integrity": "sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A=="
},
"abbrev": { "abbrev": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@@ -185,6 +205,16 @@
} }
} }
}, },
"base64-arraybuffer": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
"integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI="
},
"base64id": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
},
"bcryptjs": { "bcryptjs": {
"version": "2.4.3", "version": "2.4.3",
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
@@ -196,6 +226,15 @@
"integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==", "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==",
"dev": true "dev": true
}, },
"bl": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
"integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==",
"requires": {
"readable-stream": "^2.3.5",
"safe-buffer": "^5.1.1"
}
},
"bluebird": { "bluebird": {
"version": "3.5.1", "version": "3.5.1",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
@@ -566,6 +605,15 @@
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
}, },
"cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"requires": {
"object-assign": "^4",
"vary": "^1"
}
},
"crc": { "crc": {
"version": "3.4.4", "version": "3.4.4",
"resolved": "https://registry.npmjs.org/crc/-/crc-3.4.4.tgz", "resolved": "https://registry.npmjs.org/crc/-/crc-3.4.4.tgz",
@@ -664,6 +712,11 @@
} }
} }
}, },
"denque": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz",
"integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ=="
},
"depd": { "depd": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@@ -741,6 +794,48 @@
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
}, },
"engine.io": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-4.0.6.tgz",
"integrity": "sha512-rf7HAVZpcRrcKEKddgIzYUnwg0g5HE1RvJaTLwkcfJmce4g+po8aMuE6vxzp6JwlK8FEq/vi0KWN6tA585DjaA==",
"requires": {
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~0.4.1",
"cors": "~2.8.5",
"debug": "~4.3.1",
"engine.io-parser": "~4.0.0",
"ws": "~7.4.2"
},
"dependencies": {
"cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
},
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"engine.io-parser": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.2.tgz",
"integrity": "sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/MqJdZbUjW97JU72iYg==",
"requires": {
"base64-arraybuffer": "0.1.4"
}
},
"escape-html": { "escape-html": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -2020,6 +2115,12 @@
"resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
}, },
"memory-pager": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
"optional": true
},
"merge-descriptors": { "merge-descriptors": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@@ -2121,13 +2222,23 @@
} }
}, },
"mongodb": { "mongodb": {
"version": "3.3.2", "version": "3.6.3",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.3.2.tgz", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.3.tgz",
"integrity": "sha512-fqJt3iywelk4yKu/lfwQg163Bjpo5zDKhXiohycvon4iQHbrfflSAz9AIlRE6496Pm/dQKQK5bMigdVo2s6gBg==", "integrity": "sha512-rOZuR0QkodZiM+UbQE5kDsJykBqWi0CL4Ec2i1nrGrUI3KO11r6Fbxskqmq3JK2NH7aW4dcccBuUujAP0ERl5w==",
"requires": { "requires": {
"bson": "^1.1.1", "bl": "^2.2.1",
"bson": "^1.1.4",
"denque": "^1.4.1",
"require_optional": "^1.0.1", "require_optional": "^1.0.1",
"safe-buffer": "^5.1.2" "safe-buffer": "^5.1.2",
"saslprep": "^1.0.0"
},
"dependencies": {
"bson": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.5.tgz",
"integrity": "sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg=="
}
} }
}, },
"mongoose": { "mongoose": {
@@ -2148,6 +2259,16 @@
"sliced": "1.0.1" "sliced": "1.0.1"
}, },
"dependencies": { "dependencies": {
"mongodb": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.3.2.tgz",
"integrity": "sha512-fqJt3iywelk4yKu/lfwQg163Bjpo5zDKhXiohycvon4iQHbrfflSAz9AIlRE6496Pm/dQKQK5bMigdVo2s6gBg==",
"requires": {
"bson": "^1.1.1",
"require_optional": "^1.0.1",
"safe-buffer": "^5.1.2"
}
},
"ms": { "ms": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -2687,6 +2808,15 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
}, },
"saslprep": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
"integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
"optional": true,
"requires": {
"sparse-bitfield": "^3.0.3"
}
},
"semver": { "semver": {
"version": "5.6.0", "version": "5.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
@@ -2899,6 +3029,72 @@
"kind-of": "^3.2.0" "kind-of": "^3.2.0"
} }
}, },
"socket.io": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-3.0.5.tgz",
"integrity": "sha512-5yWQ43P/4IttmPCGKDQ3CVocBiJWGpibyhYJxgUhf69EHMzmK8XW0DkmHIoYdLmZaVZJyiEkUqpeC7rSCIqekw==",
"requires": {
"@types/cookie": "^0.4.0",
"@types/cors": "^2.8.8",
"@types/node": "^14.14.10",
"accepts": "~1.3.4",
"base64id": "~2.0.0",
"debug": "~4.3.1",
"engine.io": "~4.0.6",
"socket.io-adapter": "~2.0.3",
"socket.io-parser": "~4.0.3"
},
"dependencies": {
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"socket.io-adapter": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.0.3.tgz",
"integrity": "sha512-2wo4EXgxOGSFueqvHAdnmi5JLZzWqMArjuP4nqC26AtLh5PoCPsaRbRdah2xhcwTAMooZfjYiNVNkkmmSMaxOQ=="
},
"socket.io-parser": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.3.tgz",
"integrity": "sha512-m4ybFiP4UYVORRt7jcdqf8UWx+ywVdAqqsJyruXxAdD3Sv6MDemijWij34mOWdMJ55bEdIb9jACBhxUgNK6sxw==",
"requires": {
"@types/component-emitter": "^1.2.10",
"component-emitter": "~1.3.0",
"debug": "~4.3.1"
},
"dependencies": {
"component-emitter": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
},
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"source-map-resolve": { "source-map-resolve": {
"version": "0.5.2", "version": "0.5.2",
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
@@ -2918,6 +3114,15 @@
"integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
"dev": true "dev": true
}, },
"sparse-bitfield": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
"integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
"optional": true,
"requires": {
"memory-pager": "^1.0.2"
}
},
"split-string": { "split-string": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
@@ -3281,6 +3486,11 @@
"signal-exit": "^3.0.2" "signal-exit": "^3.0.2"
} }
}, },
"ws": {
"version": "7.4.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz",
"integrity": "sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA=="
},
"xdg-basedir": { "xdg-basedir": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz",
+3 -1
View File
@@ -23,10 +23,12 @@
"express": "^4.16.4", "express": "^4.16.4",
"express-ejs-layouts": "^2.5.0", "express-ejs-layouts": "^2.5.0",
"express-session": "^1.15.6", "express-session": "^1.15.6",
"mongodb": "^3.6.3",
"mongoose": "^5.7.5", "mongoose": "^5.7.5",
"multer": "^1.4.2", "multer": "^1.4.2",
"passport": "^0.4.0", "passport": "^0.4.0",
"passport-local": "^1.0.0" "passport-local": "^1.0.0",
"socket.io": "^3.0.5"
}, },
"devDependencies": { "devDependencies": {
"nodemon": "^1.18.9" "nodemon": "^1.18.9"
+7417
View File
File diff suppressed because it is too large. Load diff
+15 -11
View File
@@ -4,22 +4,26 @@ const { ensureAuthenticated, forwardAuthenticated } = require('../config/auth');
// DB Config // DB Config
const db = require('../config/keys').mongoURI; const db = require('../config/keys').mongoURI;
let MongoClient = require('mongodb').MongoClient; let MongoClient = require('mongodb').MongoClient;
let UserModal = require('../models/User.js'); let UserModal = require('../models/User');
let QuestModal = require('../models/Quest.js') let QuestModal = require('../models/Quest')
let CourseModal = require('../models/Course')
// Welcome Page // Welcome Page
router.get('/', forwardAuthenticated, (req, res) => res.render('welcome')); router.get('/', forwardAuthenticated, (req, res) => res.render('welcome'));
// Dashboard // Dashboard
router.get('/dashboard', ensureAuthenticated, function(req, res) { router.get('/dashboard', ensureAuthenticated, function(req, res) {
// Collects Quest Data //Collects Course Data
QuestModal.find({}, function(err, quests) { CourseModal.find({}, function(err, courses) {
// Collects User Data // Collects Quest Data
UserModal.find({}, function(err, data) { QuestModal.find({}, function(err, quests) {
res.render('dashboard', { // Collects User Data
user : req.user, UserModal.find({}, function(err, data) {
members: data, res.render('dashboard', {
quests: quests user : req.user,
members: data,
quests: quests,
courses: courses
});
}); });
}); });
}); });
+78 -9
View File
@@ -6,6 +6,10 @@ const passport = require('passport');
const MongoClient = require('mongodb').MongoClient; const MongoClient = require('mongodb').MongoClient;
const ObjectId = require('mongodb').ObjectId; const ObjectId = require('mongodb').ObjectId;
const Quest = require('../models/Quest'); const Quest = require('../models/Quest');
const Course = require('../models/Course');
const socket = require('socket.io');
const server = require('../app.js').server;
const io = socket(server);
// Load Profanity filter // Load Profanity filter
const Filter = require('bad-words'); const Filter = require('bad-words');
@@ -16,7 +20,7 @@ const User = require('../models/User');
const { forwardAuthenticated } = require('../config/auth'); const { forwardAuthenticated } = require('../config/auth');
// DB Config // DB Config
const db = require('../config/keys').mongoURI; const url = require('../config/keys').mongoURI;
// Loads libraries for uploading img functions // Loads libraries for uploading img functions
let fs = require('fs'); let fs = require('fs');
@@ -52,6 +56,70 @@ router.get('/register', forwardAuthenticated, (req, res) => res.render('register
// Edit page // Edit page
router.get('/edit', (req, res) => res.render('edit')); router.get('/edit', (req, res) => res.render('edit'));
// Create Course / Class
router.post('/createClass', (req, res, next) => {
const { name, description, grade } = req.body;
let errors = [];
//Checks if Class Already Exists
Course.findOne({ name: name }).then(course => {
if (course) {
errors.push({ msg: 'Course Name Already Exists' })
// Redirect to dashboard page with errors
res.render('dashboard', {
errors,
name,
description,
grade
});
} else {
try {
// Creates new Course Object
const newCourse = new Course({
name: name,
description: description,
grade: grade
});
newCourse
.save()
.then(course => {
req.flash(
'success_msg'
);
// Takes to Dashboard on success
let value = encodeURIComponent('createdClass')
res.redirect('/dashboard?successRate=' + value);
})
.catch(err => console.log(err));
} catch (err) {
if (err) throw err;
}
}
});
});
// Delete User
router.post('/deleteUser', (req, res, next) => {
const id = req.body.delete_id;
// Deletes User
MongoClient.connect(url, {
useUnifiedTopology: true,
useNewUrlParser: true}, function(err, db) {
if (err) throw err;
let dbo = db.db("XPmockDB");
dbo.collection("students").deleteOne({ _id: ObjectId(id) }, function(err, obj) {
if (err) throw err;
db.close();
});
// Takes to Dahsboard on success
let value = encodeURIComponent('deletedUser');
res.redirect('/dashboard?successRate=' + value);
}
);
});
// Create Quest // Create Quest
router.post('/createQuest', (req, res, next) => { router.post('/createQuest', (req, res, next) => {
const { title, amount, expiry, instructions, campaign} = req.body; const { title, amount, expiry, instructions, campaign} = req.body;
@@ -83,7 +151,7 @@ router.post('/createQuest', (req, res, next) => {
}); });
newQuest newQuest
.save() .save()
.then(user => { .then(quest => {
req.flash( req.flash(
'success_msg' 'success_msg'
); );
@@ -128,7 +196,7 @@ router.post('/addXP', (req, res, next) => {
} }
// Updates user xp // Updates user xp
MongoClient.connect(db, { MongoClient.connect(url, {
useUnifiedTopology: true, useUnifiedTopology: true,
useNewUrlParser: true}, function(err, db) { useNewUrlParser: true}, function(err, db) {
if (err) throw err; if (err) throw err;
@@ -138,8 +206,9 @@ router.post('/addXP', (req, res, next) => {
db.close() db.close()
}); });
// Takes to Dahsboard on success // Takes to Dahsboard on success
let value = encodeURIComponent(amount.toString()) let value1 = encodeURIComponent(amount.toString())
res.redirect('/dashboard?successRate=' + value); let value2 = encodeURIComponent(_id_add);
res.redirect('/dashboard?successRate='+value1+'&id='+value2);
} }
); );
} }
@@ -281,7 +350,7 @@ router.post('/edit', upload.single('image'), (req, res, next) => {
}); });
//Updates user and redirects to dashboard //Updates user and redirects to dashboard
MongoClient.connect(db, { MongoClient.connect(url, {
useUnifiedTopology: true, useUnifiedTopology: true,
useNewUrlParser: true}, function(err, db) { useNewUrlParser: true}, function(err, db) {
if (err) throw err; if (err) throw err;
@@ -335,7 +404,7 @@ router.post('/edit', upload.single('image'), (req, res, next) => {
} }
} }
//Updates user and redirects to dashboard //Updates user and redirects to dashboard
MongoClient.connect(db, { MongoClient.connect(url, {
useUnifiedTopology: true, useUnifiedTopology: true,
useNewUrlParser: true}, function(err, db) { useNewUrlParser: true}, function(err, db) {
if (err) throw err; if (err) throw err;
@@ -448,8 +517,8 @@ router.post('/registerTeacher', upload.single('image'), (req, res, next) => {
'success_msg' 'success_msg'
); );
// Takes to Dashboard on success // Takes to Dashboard on success
let value = encodeURIComponent('success') let value = encodeURIComponent('createdTeacher')
res.redirect('/dashboard?createTeacher=' + value); res.redirect('/dashboard?successRate=' + value);
}) })
.catch(err => console.log(err)); .catch(err => console.log(err));
}); });
+92 -11
View File
@@ -1,8 +1,12 @@
<!-- Simple Styling for layout --> <!-- Simple Styling for layout -->
<style> <style>
.members { .members {
position: absolute;
top: 150px;
left: 25px;
width: 230px; width: 230px;
display: inline-block; display: inline-block;
max-height: 30px
} }
.buttons-container { .buttons-container {
position: absolute; position: absolute;
@@ -15,6 +19,19 @@
border-radius: 10px; border-radius: 10px;
background-color: rgba(112, 196, 255, .3); background-color: rgba(112, 196, 255, .3);
} }
.alert {
max-width: 58%;
}
.admin-detail {
position: absolute;
left: 25px;
}
#div-container {
position: absolute;
left: 30%;
margin-left: 25vm;
margin-right: 25vm;
}
#newTeacher-btn { #newTeacher-btn {
margin-left: 25px; margin-left: 25px;
margin-top: 10px; margin-top: 10px;
@@ -73,13 +90,32 @@
font-size: 30px; font-size: 30px;
background: #f6f6f6; background: #f6f6f6;
} }
@media (max-width: 800px) {
.alert {
max-width: 55%;
}
#div-container {
position: absolute;
left: 25px;
top: 125px;
margin-left: 25vm;
margin-right: 25vm;
max-height: 125px;
}
.members {
position: absolute;
left: 24px;
top: 300px;
}
}
</style> </style>
<!-- Header --> <!-- Header -->
<h1 class="mt-4">Site Admin</h1>
<div class='head'> <div class='head'>
<div id='teacher-container'> <div id='teacher-container'>
<div> <div class='admin-detail'>
<h1 class="mt-4">Site Admin</h1>
<p id='welcome' class="lead mb-3">Welcome Admin</p> <p id='welcome' class="lead mb-3">Welcome Admin</p>
</div> </div>
<br> <br>
@@ -87,7 +123,7 @@
<!-- Action Buttons --> <!-- Action Buttons -->
<a id='logout-btn' href="/users/logout" class="btn btn-outline-info btn-sm">Logout</a> <a id='logout-btn' href="/users/logout" class="btn btn-outline-info btn-sm">Logout</a>
<!-- Button trigger modal --> <!-- Button trigger modal -->
<button id="newTeacher-btn" onClick='openModal()' type="button" class="btn btn-outline-info btn-sm"> <button id="newTeacher-btn" onClick='openModal("#exampleModal")' type="button" class="btn btn-outline-info btn-sm">
Create New Teacher Create New Teacher
</button> </button>
<a id='bug-btn' href="https://github.com/Braeden57/XP-System/issues" target="_blank" class='btn btn-outline-info btn-sm'>Report Bug</a> <a id='bug-btn' href="https://github.com/Braeden57/XP-System/issues" target="_blank" class='btn btn-outline-info btn-sm'>Report Bug</a>
@@ -97,8 +133,8 @@
<script> <script>
function openModal() { function openModal(modalName) {
$("#exampleModal").modal() $(modalName).modal()
} }
// Creates unique ID // Creates unique ID
@@ -117,10 +153,10 @@
let id = makeid(8); let id = makeid(8);
if (type == 'error') { if (type == 'error') {
document.getElementById('div-container').innerHTML += '<div id="new-div-'+id+'" style="display: none;" class="alert alert-warning alert-dismissible fade show" role="alert">'; document.getElementById('div-container').innerHTML += '<div id="new-div-'+id+'" style="display: none; clear: right;" class="alert alert-warning alert-dismissible fade show" role="alert">';
} }
if (type == 'message') { if (type == 'message') {
document.getElementById('div-container').innerHTML += '<div id="new-div-'+id+'" style="display: none;" class="alert alert-info alert-dismissible fade show" role="alert">'; document.getElementById('div-container').innerHTML += '<div id="new-div-'+id+'" style="display: none; clear: right;" class="alert alert-info alert-dismissible fade show" role="alert">';
} }
document.getElementById('new-div-'+id).innerHTML += '<div id="message'+id+'">'+message+'</div>'; document.getElementById('new-div-'+id).innerHTML += '<div id="message'+id+'">'+message+'</div>';
document.getElementById('new-div-'+id).innerHTML += '<button id="close-btn-'+id+'" class="close" data-dismiss="alert" aria-label="Close"></button>'; document.getElementById('new-div-'+id).innerHTML += '<button id="close-btn-'+id+'" class="close" data-dismiss="alert" aria-label="Close"></button>';
@@ -135,9 +171,12 @@
window.onload = function () { window.onload = function () {
const queryString = window.location.search; const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString); const urlParams = new URLSearchParams(queryString);
const isSuccess = urlParams.get('createTeacher') const successRate = urlParams.get('successRate')
if(isSuccess == 'success') { if(successRate == 'createdTeacher') {
createDiv('message', 'Successfully Created Teacher') createDiv('message', 'Successfully Created Teacher');
}
if(successRate == 'deletedUser') {
createDiv('message', "Successfully Deleted User");
} }
} }
</script> </script>
@@ -171,7 +210,32 @@
<!-- Alert container --> <!-- Alert container -->
<div id='div-container'></div> <div id='div-container'></div>
<!-- Modal --> <!-- Delete User Warning Modal -->
<div class="modal fade" id="warningModal" tabindex="-1" role="dialog" aria-labelledby="warningModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="warningModalLabel">Are you sure you wish to delete this user?</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form action="/users/deleteUser" method="POST" enctype="multipart/form-data">
<input id='delete_id' type='text' name='delete_id' value='' style='display: none'></input>
<button type="submit" class="btn btn-primary btn-block">
Yes, Continue and Delete This User
</button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
<!-- Create Teacher Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
@@ -264,6 +328,11 @@
<p>XP: <%= member.xp %></p> <p>XP: <%= member.xp %></p>
<p><%= member.role %></p> <p><%= member.role %></p>
<!-- Delete User Option -->
<button id="delete-btn" onClick='deleteUser("<%= member._id %>")' type="button" class="btn btn-outline-warning btn-sm">
Delete User
</button>
</div> </div>
<br> <br>
@@ -294,6 +363,13 @@
// Display Rank // Display Rank
document.getElementById('userRank-<%= member.id %>').innerHTML = currRank; document.getElementById('userRank-<%= member.id %>').innerHTML = currRank;
// Delete User Function
function deleteUser(id) {
document.getElementById('delete_id').value = id;
openModal("#warningModal");
}
</script> </script>
</div> </div>
<% } %> <% } %>
@@ -308,6 +384,11 @@
<p class='lead mb-3'><%= member.email %></p> <p class='lead mb-3'><%= member.email %></p>
<div> <div>
<p><%= member.role %></p> <p><%= member.role %></p>
<!-- Delete User Option -->
<button id="delete-btn" onClick='deleteUser("<%= member._id %>")' type="button" class="btn btn-outline-warning btn-sm">
Delete User
</button>
</div> </div>
<br> <br>
</div> </div>
+191 -58
View File
@@ -2,7 +2,7 @@
<style> <style>
.quests-container { .quests-container {
position: absolute; position: absolute;
width: 650px; width: 625px;
height: 645px; height: 645px;
top: 100px; top: 100px;
left: 450px; left: 450px;
@@ -15,9 +15,13 @@
width: 200px; width: 200px;
} }
.quest-buttons { .quest-buttons {
margin-left: 25px; margin-left: 10px;
margin-top: 10px; margin-top: 10px;
} }
#option1 {
width: 50px;
}
#myProgress { #myProgress {
position: relative; position: relative;
height: 200px; height: 200px;
@@ -40,6 +44,7 @@
width: 100%; width: 100%;
height: 1%; height: 1%;
background-color: #46c7f2; background-color: #46c7f2;
transition: 1s;
} }
#pro-pic { #pro-pic {
position: absolute; position: absolute;
@@ -103,6 +108,24 @@
font-size: 30px; font-size: 30px;
background: #f6f6f6; background: #f6f6f6;
} }
@media (max-width: 800px) {
.quest-all {
position: absolute;
top: 770px;
right: 1145px;
}
#quest-title {
transform: translate(-125px, 0px);
}
.quest-container {
width: 400px;
border-style: solid;
border-color: rgba(0, 0, 0, .2);
border-radius: 15px;
background-color: rgba(0, 0, 0, .2);
}
}
</style> </style>
<div class="student-container"> <div class="student-container">
@@ -123,7 +146,7 @@
<!-- User Data --> <!-- User Data -->
<div> <div>
<h1 id='userRank'></h1> <h1 id='userRank'></h1>
<h1>XP: <%= user.xp %></h1> <h1 id='userXP'>XP: <%= user.xp %></h1>
<p id='XP-Till'></p> <p id='XP-Till'></p>
</div> </div>
<br> <br>
@@ -135,7 +158,7 @@
</div> </div>
</div> </div>
<div> <div class="quest-all">
<h1 id="quest-title">Quests</h1> <h1 id="quest-title">Quests</h1>
<div class='quests-container'> <div class='quests-container'>
<div class='quest-buttons'> <div class='quest-buttons'>
@@ -186,8 +209,29 @@
</div> </div>
</div> </div>
<!-- Quest Display --> <script src="/socket.io/socket.io.js"></script>
<script> <script>
let socket = io.connect('http://localhost:5000');
socket.on("added:xp", function(data) {
if(data.userID == '<%=user._id%>') {
reCalculate(data.addXP);
}
});
window.onload = function() {
calculate();
}
let xp = <%= user.xp %>;
// Passing user _id to edit page script
function passData() {
let url = '/users/edit?name=' + encodeURIComponent('<%= user._id %>');
document.location.href = url;
}
function showHTML() { function showHTML() {
let state = document.getElementById('HTML-Display').style.display; let state = document.getElementById('HTML-Display').style.display;
if (state == "block") { if (state == "block") {
@@ -220,23 +264,6 @@
document.getElementById('JS-Display').style.display = 'block'; document.getElementById('JS-Display').style.display = 'block';
} }
} }
</script>
<!-- Passing user _id to edit page script -->
<script>
function passData() {
let url = '/users/edit?name=' + encodeURIComponent('<%= user._id %>');
document.location.href = url;
}
</script>
<!-- Calculate Rank Data Script -->
<script>
let xp = <%= user.xp %>;
let currRank;
let rankUp;
let remain;
let ranks = [ let ranks = [
{"Digital Noob": 0}, // index 0 {"Digital Noob": 0}, // index 0
@@ -254,51 +281,157 @@
{"Master Digital Crafter": 800} // index 12 {"Master Digital Crafter": 800} // index 12
] ]
// Get current rank // Global old variables
let currRank;
let rankUp;
let remain;
let goal;
let total;
let progress;
let percent;
let indexes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 12] let indexes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 12]
if (xp < 800) {
for(var i = 0; i < ranks.length; i++) { // Initial calculate from 0 to current XP
for (let rank in ranks[i]) { function calculate() {
let nextIndex = indexes[i]; // Get current rank
for (let nextRank in ranks[nextIndex]) { if (xp < 800) {
if (xp >= ranks[i][rank] && xp < ranks[nextIndex][nextRank]) { for(var i = 0; i < ranks.length; i++) {
currRank = rank; for (let rank in ranks[i]) {
currRankXP = ranks[i][rank] let nextIndex = indexes[i];
// Calculate xp till next Rank // Gets rank after current rank
if (i < 12) { for (let nextRank in ranks[nextIndex]) {
i++; // Verifies current XP is > currentRank xp level && current XP < nextRank xp level
let nextRank = ranks[i]; if (xp >= ranks[i][rank] && xp < ranks[nextIndex][nextRank]) {
for (let r in nextRank) { // Sets global old variables
let goal = nextRank[r]; currRank = rank;
rankUp = r; currRankXP = ranks[i][rank]
remain = goal - xp; // Calculate xp till next Rank
// Calculate progress bar if (i < 12) {
let total = goal - currRankXP; i++;
let progress = xp - currRankXP; let nextRank = ranks[i];
let percent = (progress/total)*100; for (let r in nextRank) {
let elem = document.getElementById("myBar"); goal = nextRank[r];
elem.style.height = percent + '%'; rankUp = r;
document.getElementById('percent').innerHTML = progress + '|' + total; remain = goal - xp;
// Calculate progress bar
total = goal - currRankXP;
progress = xp - currRankXP;
percent = (progress/total)*100;
let elem = document.getElementById("myBar");
elem.style.height = percent + '%';
document.getElementById('percent').innerHTML = progress + '|' + total;
}
} }
} }
} }
} }
} }
} else {
// Display data for max level
document.getElementById('percent').innerHTML = '800|800';
currRank = "Master Digital Crafter";
remain = 0;
rankUp = 'No higher Rank, Good Job!';
let elem = document.getElementById("myBar");
let percent = 100;
elem.style.height = percent + '%';
} }
} else {
// Display data for max level // Display Data
document.getElementById('percent').innerHTML = '800|800'; document.getElementById('userRank').innerHTML = currRank;
currRank = "Master Digital Crafter"; document.getElementById('XP-Till').innerHTML = remain + 'XP till your next Rank: ' + rankUp;
remain = 0;
rankUp = 'No higher Rank, Good Job!';
let elem = document.getElementById("myBar");
let percent = 100;
elem.style.height = percent + '%';
} }
// Display Data // Re calculate recaculates all the data from oldXP + addxp to newxp
document.getElementById('userRank').innerHTML = currRank; function reCalculate(addXP) {
document.getElementById('XP-Till').innerHTML = remain + 'XP till your next Rank: ' + rankUp; let newXP = xp + parseInt(addXP);
console.log(newXP);
// Get current rank
if (newXP < 800) {
for(var i = 0; i < ranks.length; i++) {
for (let rank in ranks[i]) {
let nextIndex = indexes[i];
for (let nextRank in ranks[nextIndex]) {
if (newXP >= ranks[i][rank] && newXP < ranks[nextIndex][nextRank]) {
let newCurrRank = rank;
let newCurrRankXP = ranks[i][rank]
// Calculate xp till next Rank
if (i < 12) {
i++;
let newNextRank = ranks[i];
for (let r in newNextRank) {
let newRankUp = r;
let newPercent;
let diff = addXP;
let newProgress = progress+diff
let newRemain;
let newGoal;
let newTotal;
// If new Progress doesnt go over current total
if (newProgress < total) {
// Set new percent and new remain
let diffPercent=(diff/total)*100;
newRemain = remain - diff;
newTotal = total;
let elem = document.getElementById("myBar");
newPercent = percent + diffPercent;
elem.style.height = newPercent + "%";
document.getElementById('percent').innerHTML = newProgress + "|" + total;
// Update Display with new Data
document.getElementById('userXP').innerHTML = "XP: " + newXP;
document.getElementById('XP-Till').innerHTML = newRemain + "XP till your next Rank: " + rankUp;
document.getElementById('userRank').innerHTML = currRank;
// If new progress goes over current total
} else if (newProgress >= total) {
// Set new variables
newGoal = newNextRank[r];
newTotal = newGoal - newCurrRankXP;
newProgress = newXP - newCurrRankXP;
newRemain = newTotal - newProgress;
// Update percent from current percent to new percent
let elem = document.getElementById("myBar");
newPercent = Math.round((newProgress/newTotal)*100);
elem.style.height = newPercent + "%";
// Adds 1 to progress till progress == total
let progressDiff = total-progress;
document.getElementById('percent').innerHTML = newProgress + "|" + newTotal;
// Update Display with new Data
document.getElementById('XP-Till').innerHTML = newRemain + "XP till your next Rank: " + newRankUp;
document.getElementById('userXP').innerHTML = "XP: " + newXP;
document.getElementById('userRank').innerHTML = newCurrRank;
document.getElementById('percent').innerHTML = newProgress + "|" + newTotal;
}
// Set Main Variables to new values
currRank = newCurrRank;
rankUp = newRankUp;
remain = newRemain;
goal = newGoal;
total = newTotal;
progress = newProgress;
percent = newPercent;
xp = newXP;
}
}
}
}
}
}
} else {
// Display data for max level
document.getElementById('percent').innerHTML = '800|800';
currRank = "Master Digital Crafter";
remain = 0;
xp = 800;
rankUp = 'No higher Rank, Good Job!';
let elem = document.getElementById("myBar");
let percent = 100;
elem.style.height = percent + '%';
// Display Data
document.getElementById('userXP').innerHTML = "XP: " + xp;
document.getElementById('userRank').innerHTML = currRank;
document.getElementById('XP-Till').innerHTML = remain + 'XP till your next Rank: ' + rankUp;
}
}
function redirect(id) { function redirect(id) {
let url = '/users/quests?id=' + encodeURIComponent(id); let url = '/users/quests?id=' + encodeURIComponent(id);
+197 -81
View File
@@ -40,6 +40,20 @@
margin-top: 10px; margin-top: 10px;
margin-right: 15px; margin-right: 15px;
} }
.course-container {
position: absolute;
left: 1000px;
background: rgba(0, 0, 0, .2);
border-radius: 24px;
border-style: solid;
border-color: rgba(0, 0, 0, .2);
}
.course-content {
margin-left: 15px;
margin-top: 10px;
margin-right: 15px;
max-width: 200px;
}
.quest { .quest {
color: #e05f3a; color: #e05f3a;
} }
@@ -66,7 +80,7 @@
} }
.buttons-container { .buttons-container {
position: absolute; position: absolute;
top: 425px; top: 380px;
right: 180px; right: 180px;
} }
.button-content { .button-content {
@@ -145,17 +159,9 @@
<button onClick='passData()' class='button-content btn btn-outline-info btn-sm'>Edit</button> <button onClick='passData()' class='button-content btn btn-outline-info btn-sm'>Edit</button>
<a href="https://github.com/Braeden57/XP-System/issues" target="_blank" class='button-content btn btn-outline-info btn-sm'>Report Bug</a> <a href="https://github.com/Braeden57/XP-System/issues" target="_blank" class='button-content btn btn-outline-info btn-sm'>Report Bug</a>
<button class="button-content btn btn-outline-info btn-sm" data-toggle="modal" data-target="#createQuest">New Quest</button> <button class="button-content btn btn-outline-info btn-sm" data-toggle="modal" data-target="#createQuest">New Quest</button>
<button class="button-content btn btn-outline-info btn-sm" data-toggle="modal" data-target="#createClass">New Class</button>
</div> </div>
</div> </div>
<!-- Passing user _id to edit page script -->
<script>
function passData() {
let url = '/users/edit?name=' + encodeURIComponent('<%= user._id %>');
document.location.href = url;
}
</script>
</div> </div>
<br> <br>
@@ -192,7 +198,7 @@
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel"</h5> <h5 class="modal-title" id="exampleModalLabel">Add XP</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span> <span aria-hidden="true">&times;</span>
</button> </button>
@@ -203,10 +209,6 @@
<input id='_id_add' type='text' name='_id_add' value='' style='display: none'></input> <input id='_id_add' type='text' name='_id_add' value='' style='display: none'></input>
<input id="current_xp" type="text" name="current_xp" value="" style="display: none"></input> <input id="current_xp" type="text" name="current_xp" value="" style="display: none"></input>
</div> </div>
<div>
<p>Minimum: 1</p>
<p>Maximum: 50</p>
</div>
<div class="form-group"> <div class="form-group">
<label for="amount">Amount</label> <label for="amount">Amount</label>
<input <input
@@ -214,7 +216,6 @@
name="amount" name="amount"
type="number" type="number"
min="1" min="1"
max="50"
value="" value=""
class="form-control" class="form-control"
> >
@@ -236,7 +237,7 @@
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="createQuestLabel"</h5> <h5 class="modal-title" id="createQuestLabel">Create Quest</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span> <span aria-hidden="true">&times;</span>
</button> </button>
@@ -309,68 +310,63 @@
</div> </div>
</div> </div>
<script> <!-- Create Class Modal -->
// Creates unique ID <div class="modal fade" id="createClass" tabindex="-1" role="dialog" aria-labelledby="createClassLabel" aria-hidden="true">
function makeid(length) { <div class="modal-dialog" role="document">
var result = ''; <div class="modal-content">
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; <div class="modal-header">
var charactersLength = characters.length; <h5 class="modal-title" id="createClassLabel">Create Class</h5>
for ( var i = 0; i < length; i++ ) { <button type="button" class="close" data-dismiss="modal" aria-label="Close">
result += characters.charAt(Math.floor(Math.random() * charactersLength)); <span aria-hidden="true">&times;</span>
} </button>
return result; </div>
} <div class="modal-body">
<form action="/users/createClass" method="POST">
// Create Div <div>
function createDiv(type, message) { <label for="name">Class Name</label>
let id = makeid(8); <input
id="name"
if (type == 'error') { name="name"
document.getElementById('div-container').innerHTML += '<div id="new-div-'+id+'" style="display: none;" class="alert alert-warning alert-dismissible fade show" role="alert">'; type="text"
} value=""
if (type == 'message') { class="form-control"
document.getElementById('div-container').innerHTML += '<div id="new-div-'+id+'" style="display: none;" class="alert alert-info alert-dismissible fade show" role="alert">'; required
} >
document.getElementById('new-div-'+id).innerHTML += '<div id="message'+id+'">'+message+'</div>'; </div>
document.getElementById('new-div-'+id).innerHTML += '<button id="close-btn-'+id+'" class="close" data-dismiss="alert" aria-label="Close"></button>'; <div>
document.getElementById('close-btn-'+id).innerHTML += '<span aria-hidden="true">&times;</span>'; <label for="description">Class Description</label>
document.getElementById('new-div-'+id).style.display = "block"; <textarea
} id="description"
name="description"
// Pass name to Modal value=""
function passName(name, xp, member_id) { class="form-control"
if (xp < 800) { required
document.getElementById("exampleModalLabel").innerHTML = "Give " + name + " XP"; ></textarea>
document.getElementById("_id_add").value = member_id; </div>
document.getElementById("current_xp").value = xp; <div>
$("#exampleModal").modal() <label for="grade">Grade</label>
} <input
if (xp >= 800) { id="grade"
// Construct and show Max XP Alert name="grade"
message = name + ' has reached max XP!'; type="number"
createDiv('message', message); min="8"
} max="12"
} value=""
class="form-control"
// Catching url Parameters required
window.onload = function () { >
const queryString = window.location.search; </div>
const urlParams = new URLSearchParams(queryString); <button type="submit" class="btn btn-primary">
const successRate = urlParams.get('successRate') Create Class
if(successRate == 'addXP > 50') { </button>
createDiv('error', "Can't add more than 50 XP") </form>
} </div>
if(successRate == 'addXP <= 0') { <div class="modal-footer">
createDiv('error', "XP Must be Greater than 0"); <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
} </div>
if(parseInt(successRate) > 0 && parseInt(successRate) < 50 || parseInt(successRate) == 50) { </div>
createDiv('message', "Gave " + successRate + "XP to a Student"); </div>
} </div>
if(successRate == 'createdQuest') {
createDiv('message', "Successfully Created Quest");
}
}
</script>
<div class="members-container"> <div class="members-container">
<!-- List of all site students (not teachers) --> <!-- List of all site students (not teachers) -->
@@ -442,13 +438,126 @@
<!-- List of Quests --> <!-- List of Quests -->
<div class='quest-content'> <div class='quest-content'>
<h2>All Quests</h2> <h2>All Quests</h2>
<ul>
<% quests.forEach(function (quest) { %> <% quests.forEach(function (quest) { %>
<p class='quest'><%= quest.title %></p> <li><button class='list-button btn btn-outline-success mt-2' onclick="redirect('<%= quest._id %>')"><%= quest.title %></button></li>
<% }) %>
</ul>
</div>
</div>
<div class="course-container">
<!-- List of Courses -->
<div class='course-content'>
<h2>All Courses</h2>
<% courses.forEach(function (course) { %>
<div class='course'>
<p><%= course.name %>: Grade <%= course.grade %></p>
</div>
<% }) %> <% }) %>
</div> </div>
</div>
<!-- Script for show/hide user profile data --> <script src="/socket.io/socket.io.js"></script>
<script> <script>
let socket = io.connect('http://localhost:5000');
// Creates unique ID
function makeid(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
function passData() {
let url = '/users/edit?name=' + encodeURIComponent('<%= user._id %>');
document.location.href = url;
}
// Create Div
function createDiv(type, message) {
let id = makeid(8);
if (type == 'error') {
document.getElementById('div-container').innerHTML += '<div id="new-div-'+id+'" style="display: none;" class="alert alert-warning alert-dismissible fade show" role="alert">';
}
if (type == 'message') {
document.getElementById('div-container').innerHTML += '<div id="new-div-'+id+'" style="display: none;" class="alert alert-info alert-dismissible fade show" role="alert">';
}
document.getElementById('new-div-'+id).innerHTML += '<div id="message'+id+'">'+message+'</div>';
document.getElementById('new-div-'+id).innerHTML += '<button id="close-btn-'+id+'" class="close" data-dismiss="alert" aria-label="Close"></button>';
document.getElementById('close-btn-'+id).innerHTML += '<span aria-hidden="true">&times;</span>';
document.getElementById('new-div-'+id).style.display = "block";
}
// Pass name to Modal
function passName(name, xp, member_id) {
if (xp < 800) {
document.getElementById("exampleModalLabel").innerHTML = "Give " + name + " XP";
document.getElementById("_id_add").value = member_id;
document.getElementById("current_xp").value = xp;
$("#exampleModal").modal()
}
if (xp >= 800) {
// Construct and show Max XP Alert
message = name + ' has reached max XP!';
createDiv('message', message);
}
}
let getParameterByName = function() {
let queries = location.search.substring(1).split('&'),
processed = {};
for (let query of queries) {
let [name, value] = query.split('=');
processed[decodeURIComponent(name)] = value? decodeURIComponent(value) : '';
}
return function(name) {
if (typeof processed[name] !== 'undefined')
return processed[name];
else
return null;
};
}();
function updateXP(addXP, id) {
let data = {
userID: id,
addXP: addXP
}
socket.emit('add:xp', data);
}
// Catching url Parameters
window.onload = function () {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const successRate = urlParams.get('successRate')
if(successRate == 'addXP > 50') {
createDiv('error', "Can't add more than 50 XP")
}
if(successRate == 'addXP <= 0') {
createDiv('error', "XP Must be Greater than 0");
}
if(parseInt(successRate) > 0) {
createDiv('message', "Gave " + successRate + "XP to a Student");
updateXP(successRate, getParameterByName('id'));
}
if(successRate == 'createdQuest') {
createDiv('message', "Successfully Created Quest");
}
if(successRate == 'createdClass') {
createDiv('message', "Successfully created Course");
}
}
// Script for show/hide user profile data
function openProfile(id) { function openProfile(id) {
let state = document.getElementById(id).style.display; let state = document.getElementById(id).style.display;
if (state == "block") { if (state == "block") {
@@ -457,4 +566,11 @@
document.getElementById(id).style.display = 'block'; document.getElementById(id).style.display = 'block';
} }
} }
// Script for redirecting to selected Quest
function redirect(id) {
let url = '/users/quests?id=' + encodeURIComponent(id);
document.location.href = url;
}
</script> </script>