This commit is contained in:
SowinskiBraeden committed 2021-01-04 10:18:19 -08:00
1 parent 9163477534
commit 9fa4aa179a
12 files changed
+473 -65

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
# Port to start server on.
PORT=5000
# MongoDB connection URI.
DB_URI=mongodb://localhost/knoldus
+8 -1
View File
@@ -1 +1,8 @@
/test
# Dependencies.
node_modules/*
# Tests folder.
test/*
# Enviroment variables
.env
+24 -1
View File
@@ -1,5 +1,28 @@
# XP-System
School Project
This school project is for my teacher to have students
log in and check out their XP and assignments.
(Still not done)!
### Requirements :
1. [Node.js](https://nodejs.org/en/)
1. [MongoDB](https://docs.mongodb.com/manual/administration/install-community/)
### Getting Started with Code :
1. [Set Up MongoDB](#setting-up-mongodb) and start mongodb
2. Clone repo from https://github.com/Braeden57/XP-System.git
3. Run `npm install` to install dependencies.
4. Duplicate `.env.example` and rename the new file to `.env`. Edit to your configurations.
1. Run `npm start` to boot up server.
1. Go to http://localhost:5000.
### Setting up MongoDB
1. Install mongodb via brew. `brew install mongodb`
1. Start mongodb via brew. `brew services restart mongodb`
2. Or Install mongodb compass https://www.mongodb.com/try/download/compass
### Accessing the Database
1. Locally this will use the knoldus db (or whatever you specify manually)
1. launch mongo via your command-line: `mongo`
1. Use `show dbs` to see all that are available. You should see `knoldus` in the list.
1. Lets use that db: `use knoldus`.
+3 -2
View File
@@ -7,7 +7,8 @@ const session = require('express-session');
const bodyParser = require('body-parser');
var path = require('path');
var fs = require('fs');
require('dotenv/config');
var dotenv = require('dotenv');
dotenv.config();
const app = express();
@@ -20,7 +21,7 @@ const db = require('./config/keys').mongoURI;
// Connect to MongoDB
mongoose
.connect(
db,
process.env.DB_URI || 'mongodb://localhost/knoldus',
{ useNewUrlParser: true, useUnifiedTopology: true}
)
.then(() => console.log('MongoDB Connected'))
+5 -1
View File
@@ -1,4 +1,8 @@
let dbPassword = 'mongodb+srv://client:backyardpassclient@backyard-pass-data.nbikf.mongodb.net/XPmockDB?retryWrites=true&w=majority';
const dotenv = require('dotenv');
// Load environment variables into process
dotenv.config()
let dbPassword = process.env.DB_URI;
module.exports = {
mongoURI: dbPassword
+28
View File
@@ -0,0 +1,28 @@
const mongoose = require('mongoose');
const QuestSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
campaign: {
type: String,
required: true
},
expiry: {
type: Date,
default: Date.now
},
xp: {
type: Number,
required: true
},
instruction: {
type: String,
required: true
}
});
const Quest = mongoose.model('Quest', QuestSchema);
module.exports = Quest;
+6 -6
View File
@@ -1,19 +1,19 @@
{
"_from": "dotenv",
"_from": "dotenv@^8.2.0",
"_id": "dotenv@8.2.0",
"_inBundle": false,
"_integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
"_location": "/dotenv",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"type": "range",
"registry": true,
"raw": "dotenv",
"raw": "dotenv@^8.2.0",
"name": "dotenv",
"escapedName": "dotenv",
"rawSpec": "",
"rawSpec": "^8.2.0",
"saveSpec": null,
"fetchSpec": "latest"
"fetchSpec": "^8.2.0"
},
"_requiredBy": [
"#USER",
@@ -21,7 +21,7 @@
],
"_resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
"_shasum": "97e619259ada750eea3e4ea3e26bceea5424b16a",
"_spec": "dotenv",
"_spec": "dotenv@^8.2.0",
"_where": "C:\\Users\\flami\\OneDrive\\Desktop\\Projects\\XP-System",
"bugs": {
"url": "https://github.com/motdotla/dotenv/issues"
+12 -3
View File
@@ -1,17 +1,26 @@
const express = require('express');
const router = express.Router();
const { ensureAuthenticated, forwardAuthenticated } = require('../config/auth');
var UserModel = require('../models/User.js');
// DB Config
const db = require('../config/keys').mongoURI;
let MongoClient = require('mongodb').MongoClient;
let UserModal = require('../models/User.js');
let QuestModal = require('../models/Quest.js')
// Welcome Page
router.get('/', forwardAuthenticated, (req, res) => res.render('welcome'));
// Dashboard
router.get('/dashboard', ensureAuthenticated, function(req, res) {
UserModel.find({}, function(err, data) {
// Collects Quest Data
QuestModal.find({}, function(err, quests) {
// Collects User Data
UserModal.find({}, function(err, data) {
res.render('dashboard', {
user : req.user,
members: data
members: data,
quests: quests
});
});
});
});
+57 -1
View File
@@ -5,6 +5,7 @@ const bcrypt = require('bcryptjs');
const passport = require('passport');
const MongoClient = require('mongodb').MongoClient;
const ObjectId = require('mongodb').ObjectId;
const Quest = require('../models/Quest');
// Load Profanity filter
const Filter = require('bad-words');
@@ -33,6 +34,15 @@ let storage = multer.diskStorage({
let upload = multer({ storage: storage });
let questsList;
// Collects Quest Data
Quest.find({}, function(err, quests) {
questsList = quests;
});
// Show Quest page
router.get('/quests', (req, res) => res.render('quests', { quests: questsList }));
// Login Page
router.get('/login', forwardAuthenticated, (req, res) => res.render('login'));
@@ -42,6 +52,52 @@ router.get('/register', forwardAuthenticated, (req, res) => res.render('register
// Edit page
router.get('/edit', (req, res) => res.render('edit'));
// Create Quest
router.post('/createQuest', (req, res, next) => {
const { title, amount, instructions, campaign} = req.body;
let errors = [];
// Checks if Quest with title exists
Quest.findOne({ title: title }).then(quest => {
if (quest) {
errors.push({ msg: 'Quest Already Exists' });
// Redirect to dashboard page with errors
res.render('dashboard', {
errors,
name,
email,
password,
password2
});
} else {
try {
// Creates new User Object
const newQuest = new Quest({
title: title,
campaign: campaign,
xp: amount,
instruction: instructions
});
newQuest
.save()
.then(user => {
req.flash(
'success_msg'
);
// Takes to Dashboard on success
let value = encodeURIComponent('createdQuest')
res.redirect('/dashboard?successRate=' + value);
})
.catch(err => console.log(err));
} catch (err) {
if (err) throw err;
}
}
});
});
// Add XP
router.post('/addXP', (req, res, next) => {
const { _id_add, current_xp, amount } = req.body;
@@ -59,7 +115,7 @@ router.post('/addXP', (req, res, next) => {
}
if (amount < 50 && amount > 0 && current_xp < 800) {
let newXP = current_xp + amount;
let newXP = parseInt(current_xp) + parseInt(amount);
if (newXP > 800) {
newXP = 800;
}
+36
View File
@@ -0,0 +1,36 @@
<style>
#back {
position: absolute;
left: 10px;
top: 10px;
}
#div-container {
position: absolute;
left: 300px;
top: 50px;
}
</style>
<script>
// Catch url Parameter
window.onload = function () {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const id = urlParams.get('id');
<% quests.forEach(function (quest) { %>
if('<%= quest._id %>' == id) {
document.getElementById('div-container').innerHTML += '<div id="quest">';
document.getElementById('quest').innerHTML += '<h1 class="title"><%= quest.title %></h1>';
document.getElementById('quest').innerHTML += '<h2 class="title">Campaign: <%= quest.campaign %></h2>'
document.getElementById('quest').innerHTML += '<p class="info">XP: <%= quest.xp %></p>';
document.getElementById('quest').innerHTML += '<p class="info">Expires: <%= quest.expiry %></p>';
document.getElementById('quest').innerHTML += '<h3 class="info">Instructions: <%= quest.instruction %></h3>';
}
<% }) %>
}
</script>
<a id='back' href="/dashboard" class="btn btn-secondary">Back to Dashboard</a>
<!-- Quest container -->
<div id='div-container'></div>
+153 -8
View File
@@ -1,5 +1,23 @@
<!-- Simple Syling for layout -->
<style>
.quests-container {
position: absolute;
width: 650px;
height: 645px;
top: 100px;
left: 450px;
border-style: solid;
border-color: rgba(0, 0, 0, .2);
border-radius: 15px;
background-color: rgba(0, 0, 0, .2);
}
.menu-buttons {
width: 200px;
}
.quest-buttons {
margin-left: 25px;
margin-top: 10px;
}
#myProgress {
position: relative;
height: 200px;
@@ -10,7 +28,11 @@
border-radius: 12px;
overflow: hidden;
}
#quest-title {
position: absolute;
left: 720px;
top: 25px;
}
#myBar {
position: absolute;
bottom: 0px;
@@ -19,11 +41,6 @@
height: 1%;
background-color: #46c7f2;
}
#bug-btn {
position: absolute;
bottom: 60px;
left: 25px;
}
#pro-pic {
position: absolute;
top: 25px;
@@ -39,7 +56,7 @@
.student-container {
position: absolute;
width: 400px;
height: 700px;
height: 720px;
top: 25px;
left: 25px;
border: solid #5b94f0 2px;
@@ -50,6 +67,42 @@
.content {
margin-left: 25px;
}
.list-button {
margin-left: 25px;
margin-top: 25px;
}
.quest-box {
margin-top: 15px;
margin-left: 30px;
transition: .2s;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
li {
font: 200 20px/1.5 Helvetica, Verdana, sans-serif;
border-bottom: 1px solid #ccc;
}
li:last-child {
border: none;
}
li a {
text-decoration: none;
color: #000;
display: block;
width: 200px;
-webkit-transition: font-size 0.3s ease, background-color 0.3s ease;
-moz-transition: font-size 0.3s ease, background-color 0.3s ease;
-o-transition: font-size 0.3s ease, background-color 0.3s ease;
-ms-transition: font-size 0.3s ease, background-color 0.3s ease;
transition: font-size 0.3s ease, background-color 0.3s ease;
}
li a:hover {
font-size: 30px;
background: #f6f6f6;
}
</style>
<div class="student-container">
@@ -78,10 +131,97 @@
<!-- Action Buttons -->
<a href="/users/logout" class="btn btn-secondary">Logout</a>
<button onClick='passData()' class='btn btn-secondary'>Edit</button>
<a id='bug-btn' href="https://github.com/Braeden57/XP-System/issues" target="_blank" class='btn btn-danger'>Report Bug</a>
<a href="https://github.com/Braeden57/XP-System/issues" target="_blank" class='btn btn-danger'>Report Bug</a>
</div>
</div>
<div>
<h1 id="quest-title">Quests</h1>
<div class='quests-container'>
<div class='quest-buttons'>
<div class="btn-group btn-group-toggle" data-toggle="buttons">
<label onClick="showHTML()" class="menu-buttons btn btn-info active">
<input type="radio" name="options" id="option1" autocomplete="off" checked> HTML
</label>
<label onClick="showCSS()" class="menu-buttons btn btn-info">
<input type="radio" name="options" id="option2" autocomplete="off"> CSS
</label>
<label onClick="showJS()" class="menu-buttons btn btn-info">
<input type="radio" name="options" id="option3" autocomplete="off"> JavaScript
</label>
</div>
</div>
<div class='quests-content'>
<div style="display: none;" id="HTML-Display">
<ul>
<% quests.forEach(function (quest) { %>
<% if(quest.campaign == "HTML") { %>
<!-- Creates Quest Button link -->
<li><button class='list-button btn btn-outline-success mt-2' onclick="redirect('<%= quest._id %>')"><%= quest.title %></button></li>
<% } %>
<% }) %>
</ul>
</div>
<div style="display: none;" id="CSS-Display">
<ul>
<% quests.forEach(function (quest) { %>
<% if(quest.campaign == "CSS") { %>
<!-- Creates Quest Button link -->
<li><button class='list-button btn btn-outline-success mt-2' onclick="redirect('<%= quest._id %>')"><%= quest.title %></button></li>
<% } %>
<% }) %>
</ul>
</div>
<div style="display: none;" id="JS-Display">
<ul>
<% quests.forEach(function (quest) { %>
<% if(quest.campaign == "JS") { %>
<!-- Creates Quest Button link -->
<li><button class='list-button btn btn-outline-success mt-2' onclick="redirect('<%= quest._id %>')"><%= quest.title %></button></li>
<% } %>
<% }) %>
</ul>
</div>
</div>
</div>
</div>
<!-- Quest Display -->
<script>
function showHTML() {
let state = document.getElementById('HTML-Display').style.display;
if (state == "block") {
document.getElementById('HTML-Display').style.display = 'none';
} else {
document.getElementById('JS-Display').style.display = 'none';
document.getElementById('CSS-Display').style.display = 'none';
document.getElementById('HTML-Display').style.display = 'block';
}
}
function showCSS() {
let state = document.getElementById('CSS-Display').style.display;
if (state == "block") {
document.getElementById('CSS-Display').style.display = 'none';
} else {
document.getElementById('HTML-Display').style.display = 'none';
document.getElementById('JS-Display').style.display = 'none';
document.getElementById('CSS-Display').style.display = 'block';
}
}
function showJS() {
let state = document.getElementById('JS-Display').style.display;
if (state == "block") {
document.getElementById('JS-Display').style.display = 'none';
} else {
document.getElementById('HTML-Display').style.display = 'none';
document.getElementById('CSS-Display').style.display = 'none';
document.getElementById('JS-Display').style.display = 'block';
}
}
</script>
<!-- Passing user _id to edit page script -->
<script>
function passData() {
@@ -160,4 +300,9 @@
document.getElementById('userRank').innerHTML = currRank;
document.getElementById('XP-Till').innerHTML = remain + 'XP till your next Rank: ' + rankUp;
function redirect(id) {
let url = '/users/quests?id=' + encodeURIComponent(id);
document.location.href = url;
}
</script>
+136 -42
View File
@@ -5,12 +5,43 @@
display: inline-block;
}
.head {
margin-bottom: 100px;
position: absolute;
width: 345px;
height: 600px;
top: 25px;
left: 25px;
border: solid #5b94f0 2px;
border-style: solid;
border-radius: 10px;
background-color: rgba(112, 196, 255, .3);
}
.head-content {
position: absolute;
left: 15px;
}
.teacher-container {
position: absolute;
width: 300px;
left: 205px;
}
.members-container {
position: absolute;
left: 400px;
}
.quests-container {
position: absolute;
left: 800px;
background: rgba(0, 0, 0, .2);
border-radius: 24px;
border-style: solid;
border-color: rgba(0, 0, 0, .2);
}
.quest-content {
margin-left: 15px;
margin-top: 10px;
margin-right: 15px;
}
.quest {
color: #e05f3a;
}
#pro-pic {
position: absolute;
@@ -35,14 +66,13 @@
}
.buttons-container {
position: absolute;
width: 174px;
height: 500px;
top: 25px;
right: 25px;
border: solid #5b94f0 2px;
border-style: solid;
border-radius: 10px;
background-color: rgba(112, 196, 255, .3);
top: 425px;
right: 180px;
}
.button-content {
width: 127px;
margin-left: 25px;
margin-top: 10px;
}
#edit-btn {
width: 127px;
@@ -99,9 +129,9 @@
</style>
<!-- Welcome Message & Profile Picture -->
<h1 class="mt-4">Teacher Dashboard</h1>
<div class='head'>
<div>
<div class='head-content'>
<h1 class="mt-4">Teacher Dashboard</h1>
<div class="teacher-container">
<p id='welcome' class="lead mb-3">Welcome <%= user.name %></p>
<img id='pro-pic' src='data:image/<%=user.image.contentType%>;base64,
@@ -111,9 +141,11 @@
<div class="buttons-container">
<!-- Action Buttons -->
<a id='logout-btn' href="/users/logout" class="btn btn-outline-info btn-sm">Logout</a>
<button id='edit-btn' onClick='passData()' class='btn btn-outline-info btn-sm'>Edit</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 href="/users/logout" class="button-content btn btn-outline-info btn-sm">Logout</a>
<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>
<button class="button-content btn btn-outline-info btn-sm" data-toggle="modal" data-target="#createQuest">New Quest</button>
</div>
</div>
<!-- Passing user _id to edit page script -->
@@ -124,13 +156,11 @@
document.location.href = url;
}
</script>
</div>
</div>
<br>
<!-- Sets Variables for calculating users data -->
<div>
<script>
<script>
let xp;
let currRank;
let ranks = [
@@ -152,13 +182,13 @@
// Students should't be on this page sooooo...
console.log("Students Shouldnt be here");
</script>
</script>
<!-- Alert container -->
<div id='div-container'></div>
<!-- Alert container -->
<div id='div-container'></div>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<!-- Add XP Modal -->
<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-content">
<div class="modal-header">
@@ -199,9 +229,76 @@
</div>
</div>
</div>
</div>
</div>
<script>
<!-- Create Quest Modal -->
<div class="modal fade" id="createQuest" tabindex="-1" role="dialog" aria-labelledby="createQuestLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="createQuestLabel"</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/createQuest" method="POST">
<div>
<label for="title">Title</label>
<input
id="title"
name="title"
type="text"
value=""
class="form-control"
required
>
</div>
<div class="form-group">
<label for="amount">Amount</label>
<input
id="amount"
name="amount"
type="number"
min="1"
max="50"
value=""
class="form-control"
required
>
</div>
<div>
<label for="instructions">Instructions</label>
<textarea
id="instructions"
name="instructions"
value=""
class="form-control"
required
></textarea>
</div>
<div>
<label for="campaign">Campaign</label>
<select required name="campaign" id="campaign">
<option value="">--Please choose an option--</option>
<option value="HTML">HTML</option>
<option value="CSS">CSS</option>
<option value="JS">JavaScript</option>
</select>
</div>
<button type="submit" class="btn btn-primary">
Create Quest
</button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<script>
// Creates unique ID
function makeid(length) {
var result = '';
@@ -229,22 +326,6 @@
document.getElementById('new-div-'+id).style.display = "block";
}
// // Check amount
// function amountCheck(_id) {
// const amount = document.getElementById("amount").value;
// if (amount > 50) {
// createDiv('error', "Can't add more than 50 XP");
// }
// if (amount == 0 || amount < 0) {
// createDiv('error', "XP Must be more than 0");
// }
//
// if (amount > 0 && amount < 50) {
//
// createDiv('message', "Succesfully added XP");
// }
// }
// Pass name to Modal
function passName(name, xp, member_id) {
if (xp < 800) {
@@ -274,9 +355,13 @@
if(parseInt(successRate) > 0 && parseInt(successRate) < 50 || parseInt(successRate) == 50) {
createDiv('message', "Gave " + successRate + "XP to a Student");
}
if(successRate == 'createdQuest') {
createDiv('message', "Successfully Created Quest");
}
</script>
}
</script>
<div class="members-container">
<!-- List of all site students (not teachers) -->
<h2>Studen Members</h2>
<div class='members'>
@@ -342,6 +427,15 @@
</div>
</div>
<div class="quests-container">
<!-- List of Quests -->
<div class='quest-content'>
<h2>All Quests</h2>
<% quests.forEach(function (quest) { %>
<p class='quest'><%= quest.title %></p>
<% }) %>
</div>
<!-- Script for show/hide user profile data -->
<script>
function openProfile(id) {