Update
This commit is contained in:
1 parent
9163477534
commit
9fa4aa179a
12 files changed
+590
-182
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
# Port to start server on.
|
||||||
|
PORT=5000
|
||||||
|
|
||||||
|
# MongoDB connection URI.
|
||||||
|
DB_URI=mongodb://localhost/knoldus
|
||||||
+8
-1
@@ -1 +1,8 @@
|
|||||||
/test
|
# Dependencies.
|
||||||
|
node_modules/*
|
||||||
|
|
||||||
|
# Tests folder.
|
||||||
|
test/*
|
||||||
|
|
||||||
|
# Enviroment variables
|
||||||
|
.env
|
||||||
@@ -1,5 +1,28 @@
|
|||||||
# XP-System
|
# XP-System
|
||||||
|
|
||||||
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.
|
||||||
(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`.
|
||||||
@@ -7,7 +7,8 @@ const session = require('express-session');
|
|||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
require('dotenv/config');
|
var dotenv = require('dotenv');
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ const db = require('./config/keys').mongoURI;
|
|||||||
// Connect to MongoDB
|
// Connect to MongoDB
|
||||||
mongoose
|
mongoose
|
||||||
.connect(
|
.connect(
|
||||||
db,
|
process.env.DB_URI || 'mongodb://localhost/knoldus',
|
||||||
{ useNewUrlParser: true, useUnifiedTopology: true}
|
{ useNewUrlParser: true, useUnifiedTopology: true}
|
||||||
)
|
)
|
||||||
.then(() => console.log('MongoDB Connected'))
|
.then(() => console.log('MongoDB Connected'))
|
||||||
|
|||||||
+5
-1
@@ -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 = {
|
module.exports = {
|
||||||
mongoURI: dbPassword
|
mongoURI: dbPassword
|
||||||
|
|||||||
@@ -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
@@ -1,19 +1,19 @@
|
|||||||
{
|
{
|
||||||
"_from": "dotenv",
|
"_from": "dotenv@^8.2.0",
|
||||||
"_id": "dotenv@8.2.0",
|
"_id": "dotenv@8.2.0",
|
||||||
"_inBundle": false,
|
"_inBundle": false,
|
||||||
"_integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
|
"_integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
|
||||||
"_location": "/dotenv",
|
"_location": "/dotenv",
|
||||||
"_phantomChildren": {},
|
"_phantomChildren": {},
|
||||||
"_requested": {
|
"_requested": {
|
||||||
"type": "tag",
|
"type": "range",
|
||||||
"registry": true,
|
"registry": true,
|
||||||
"raw": "dotenv",
|
"raw": "dotenv@^8.2.0",
|
||||||
"name": "dotenv",
|
"name": "dotenv",
|
||||||
"escapedName": "dotenv",
|
"escapedName": "dotenv",
|
||||||
"rawSpec": "",
|
"rawSpec": "^8.2.0",
|
||||||
"saveSpec": null,
|
"saveSpec": null,
|
||||||
"fetchSpec": "latest"
|
"fetchSpec": "^8.2.0"
|
||||||
},
|
},
|
||||||
"_requiredBy": [
|
"_requiredBy": [
|
||||||
"#USER",
|
"#USER",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
],
|
],
|
||||||
"_resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
"_resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
||||||
"_shasum": "97e619259ada750eea3e4ea3e26bceea5424b16a",
|
"_shasum": "97e619259ada750eea3e4ea3e26bceea5424b16a",
|
||||||
"_spec": "dotenv",
|
"_spec": "dotenv@^8.2.0",
|
||||||
"_where": "C:\\Users\\flami\\OneDrive\\Desktop\\Projects\\XP-System",
|
"_where": "C:\\Users\\flami\\OneDrive\\Desktop\\Projects\\XP-System",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/motdotla/dotenv/issues"
|
"url": "https://github.com/motdotla/dotenv/issues"
|
||||||
|
|||||||
+15
-6
@@ -1,19 +1,28 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const { ensureAuthenticated, forwardAuthenticated } = require('../config/auth');
|
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
|
// 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) {
|
||||||
UserModel.find({}, function(err, data) {
|
// Collects Quest Data
|
||||||
res.render('dashboard', {
|
QuestModal.find({}, function(err, quests) {
|
||||||
user : req.user,
|
// Collects User Data
|
||||||
members: data
|
UserModal.find({}, function(err, data) {
|
||||||
});
|
res.render('dashboard', {
|
||||||
|
user : req.user,
|
||||||
|
members: data,
|
||||||
|
quests: quests
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
+57
-1
@@ -5,6 +5,7 @@ const bcrypt = require('bcryptjs');
|
|||||||
const passport = require('passport');
|
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');
|
||||||
|
|
||||||
// Load Profanity filter
|
// Load Profanity filter
|
||||||
const Filter = require('bad-words');
|
const Filter = require('bad-words');
|
||||||
@@ -33,6 +34,15 @@ let storage = multer.diskStorage({
|
|||||||
|
|
||||||
let upload = multer({ storage: storage });
|
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
|
// Login Page
|
||||||
router.get('/login', forwardAuthenticated, (req, res) => res.render('login'));
|
router.get('/login', forwardAuthenticated, (req, res) => res.render('login'));
|
||||||
|
|
||||||
@@ -42,6 +52,52 @@ 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 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
|
// Add XP
|
||||||
router.post('/addXP', (req, res, next) => {
|
router.post('/addXP', (req, res, next) => {
|
||||||
const { _id_add, current_xp, amount } = req.body;
|
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) {
|
if (amount < 50 && amount > 0 && current_xp < 800) {
|
||||||
let newXP = current_xp + amount;
|
let newXP = parseInt(current_xp) + parseInt(amount);
|
||||||
if (newXP > 800) {
|
if (newXP > 800) {
|
||||||
newXP = 800;
|
newXP = 800;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -1,5 +1,23 @@
|
|||||||
<!-- Simple Syling for layout -->
|
<!-- Simple Syling for layout -->
|
||||||
<style>
|
<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 {
|
#myProgress {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
@@ -10,7 +28,11 @@
|
|||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
#quest-title {
|
||||||
|
position: absolute;
|
||||||
|
left: 720px;
|
||||||
|
top: 25px;
|
||||||
|
}
|
||||||
#myBar {
|
#myBar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
@@ -19,11 +41,6 @@
|
|||||||
height: 1%;
|
height: 1%;
|
||||||
background-color: #46c7f2;
|
background-color: #46c7f2;
|
||||||
}
|
}
|
||||||
#bug-btn {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 60px;
|
|
||||||
left: 25px;
|
|
||||||
}
|
|
||||||
#pro-pic {
|
#pro-pic {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 25px;
|
top: 25px;
|
||||||
@@ -39,7 +56,7 @@
|
|||||||
.student-container {
|
.student-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 400px;
|
width: 400px;
|
||||||
height: 700px;
|
height: 720px;
|
||||||
top: 25px;
|
top: 25px;
|
||||||
left: 25px;
|
left: 25px;
|
||||||
border: solid #5b94f0 2px;
|
border: solid #5b94f0 2px;
|
||||||
@@ -50,6 +67,42 @@
|
|||||||
.content {
|
.content {
|
||||||
margin-left: 25px;
|
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>
|
</style>
|
||||||
|
|
||||||
<div class="student-container">
|
<div class="student-container">
|
||||||
@@ -78,10 +131,97 @@
|
|||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<a href="/users/logout" class="btn btn-secondary">Logout</a>
|
<a href="/users/logout" class="btn btn-secondary">Logout</a>
|
||||||
<button onClick='passData()' class='btn btn-secondary'>Edit</button>
|
<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>
|
</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 -->
|
<!-- Passing user _id to edit page script -->
|
||||||
<script>
|
<script>
|
||||||
function passData() {
|
function passData() {
|
||||||
@@ -160,4 +300,9 @@
|
|||||||
document.getElementById('userRank').innerHTML = currRank;
|
document.getElementById('userRank').innerHTML = currRank;
|
||||||
document.getElementById('XP-Till').innerHTML = remain + 'XP till your next Rank: ' + rankUp;
|
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>
|
</script>
|
||||||
+250
-156
@@ -5,12 +5,43 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
.head {
|
.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 {
|
.teacher-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 300px;
|
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 {
|
#pro-pic {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -35,14 +66,13 @@
|
|||||||
}
|
}
|
||||||
.buttons-container {
|
.buttons-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 174px;
|
top: 425px;
|
||||||
height: 500px;
|
right: 180px;
|
||||||
top: 25px;
|
}
|
||||||
right: 25px;
|
.button-content {
|
||||||
border: solid #5b94f0 2px;
|
width: 127px;
|
||||||
border-style: solid;
|
margin-left: 25px;
|
||||||
border-radius: 10px;
|
margin-top: 10px;
|
||||||
background-color: rgba(112, 196, 255, .3);
|
|
||||||
}
|
}
|
||||||
#edit-btn {
|
#edit-btn {
|
||||||
width: 127px;
|
width: 127px;
|
||||||
@@ -99,9 +129,9 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Welcome Message & Profile Picture -->
|
<!-- Welcome Message & Profile Picture -->
|
||||||
<h1 class="mt-4">Teacher Dashboard</h1>
|
|
||||||
<div class='head'>
|
<div class='head'>
|
||||||
<div>
|
<div class='head-content'>
|
||||||
|
<h1 class="mt-4">Teacher Dashboard</h1>
|
||||||
<div class="teacher-container">
|
<div class="teacher-container">
|
||||||
<p id='welcome' class="lead mb-3">Welcome <%= user.name %></p>
|
<p id='welcome' class="lead mb-3">Welcome <%= user.name %></p>
|
||||||
<img id='pro-pic' src='data:image/<%=user.image.contentType%>;base64,
|
<img id='pro-pic' src='data:image/<%=user.image.contentType%>;base64,
|
||||||
@@ -111,172 +141,227 @@
|
|||||||
|
|
||||||
<div class="buttons-container">
|
<div class="buttons-container">
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<a id='logout-btn' href="/users/logout" class="btn btn-outline-info btn-sm">Logout</a>
|
<a href="/users/logout" class="button-content btn btn-outline-info btn-sm">Logout</a>
|
||||||
<button id='edit-btn' onClick='passData()' class='btn btn-outline-info btn-sm'>Edit</button>
|
<button onClick='passData()' class='button-content 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="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 -->
|
|
||||||
<script>
|
|
||||||
function passData() {
|
|
||||||
let url = '/users/edit?name=' + encodeURIComponent('<%= user._id %>');
|
|
||||||
|
|
||||||
document.location.href = url;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</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>
|
||||||
|
|
||||||
<!-- Sets Variables for calculating users data -->
|
<!-- Sets Variables for calculating users data -->
|
||||||
<div>
|
<script>
|
||||||
<script>
|
let xp;
|
||||||
let xp;
|
let currRank;
|
||||||
let currRank;
|
let ranks = [
|
||||||
let ranks = [
|
{"Digital Noob": 0}, // index 0
|
||||||
{"Digital Noob": 0}, // index 0
|
{"Digital Novice": 48}, // index 1
|
||||||
{"Digital Novice": 48}, // index 1
|
{"Digital Novice II": 100}, // index 2
|
||||||
{"Digital Novice II": 100}, // index 2
|
{"Digital Amature": 148}, // index 3
|
||||||
{"Digital Amature": 148}, // index 3
|
{"Digital Amature II": 200}, // index 4
|
||||||
{"Digital Amature II": 200}, // index 4
|
{"Digital Apprentice": 248}, // index 5
|
||||||
{"Digital Apprentice": 248}, // index 5
|
{"Digital Apprentice II": 300}, // index 6
|
||||||
{"Digital Apprentice II": 300}, // index 6
|
{"Digital Journeyman": 396}, // index 7
|
||||||
{"Digital Journeyman": 396}, // index 7
|
{"Digital Journeyman II": 476}, // index 8
|
||||||
{"Digital Journeyman II": 476}, // index 8
|
{"Digital Journeyman III": 532}, // index 9
|
||||||
{"Digital Journeyman III": 532}, // index 9
|
{"Digital Crafter": 580}, // index 10
|
||||||
{"Digital Crafter": 580}, // index 10
|
{"Expert Digital Crafter": 648}, // index 11
|
||||||
{"Expert Digital Crafter": 648}, // index 11
|
{"Master Digital Crafter": 800} // index 12
|
||||||
{"Master Digital Crafter": 800} // index 12
|
]
|
||||||
]
|
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]
|
|
||||||
|
|
||||||
// Students should't be on this page sooooo...
|
// Students should't be on this page sooooo...
|
||||||
console.log("Students Shouldnt be here");
|
console.log("Students Shouldnt be here");
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Alert container -->
|
<!-- Alert container -->
|
||||||
<div id='div-container'></div>
|
<div id='div-container'></div>
|
||||||
|
|
||||||
<!-- Modal -->
|
<!-- Add XP 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">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="exampleModalLabel"</h5>
|
<h5 class="modal-title" id="exampleModalLabel"</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">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form action="/users/addXP" method="POST">
|
||||||
|
<div>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>Minimum: 1</p>
|
||||||
|
<p>Maximum: 50</p>
|
||||||
|
</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"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
Add XP
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</form>
|
||||||
<div class="modal-body">
|
</div>
|
||||||
<form action="/users/addXP" method="POST">
|
<div class="modal-footer">
|
||||||
<div>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p>Minimum: 1</p>
|
|
||||||
<p>Maximum: 50</p>
|
|
||||||
</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"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary">
|
|
||||||
Add XP
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<!-- Create Quest Modal -->
|
||||||
// Creates unique ID
|
<div class="modal fade" id="createQuest" tabindex="-1" role="dialog" aria-labelledby="createQuestLabel" 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="createQuestLabel"</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">×</span>
|
||||||
}
|
</button>
|
||||||
return result;
|
</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 = '';
|
||||||
|
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
var charactersLength = characters.length;
|
||||||
|
for ( var i = 0; i < length; i++ ) {
|
||||||
|
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Create Div
|
// Create Div
|
||||||
function createDiv(type, message) {
|
function createDiv(type, message) {
|
||||||
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;" 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">×</span>';
|
|
||||||
document.getElementById('new-div-'+id).style.display = "block";
|
|
||||||
}
|
}
|
||||||
|
if (type == 'message') {
|
||||||
// // Check amount
|
document.getElementById('div-container').innerHTML += '<div id="new-div-'+id+'" style="display: none;" class="alert alert-info alert-dismissible fade show" role="alert">';
|
||||||
// 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) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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">×</span>';
|
||||||
|
document.getElementById('new-div-'+id).style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
// Catching url Parameters
|
// Pass name to Modal
|
||||||
window.onload = function () {
|
function passName(name, xp, member_id) {
|
||||||
const queryString = window.location.search;
|
if (xp < 800) {
|
||||||
const urlParams = new URLSearchParams(queryString);
|
document.getElementById("exampleModalLabel").innerHTML = "Give " + name + " XP";
|
||||||
const successRate = urlParams.get('successRate')
|
document.getElementById("_id_add").value = member_id;
|
||||||
if(successRate == 'addXP > 50') {
|
document.getElementById("current_xp").value = xp;
|
||||||
createDiv('error', "Can't add more than 50 XP")
|
$("#exampleModal").modal()
|
||||||
}
|
|
||||||
if(successRate == 'addXP <= 0') {
|
|
||||||
createDiv('error', "XP Must be Greater than 0");
|
|
||||||
}
|
|
||||||
if(parseInt(successRate) > 0 && parseInt(successRate) < 50 || parseInt(successRate) == 50) {
|
|
||||||
createDiv('message', "Gave " + successRate + "XP to a Student");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
if (xp >= 800) {
|
||||||
|
// Construct and show Max XP Alert
|
||||||
|
message = name + ' has reached max XP!';
|
||||||
|
createDiv('message', message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 && parseInt(successRate) < 50 || parseInt(successRate) == 50) {
|
||||||
|
createDiv('message', "Gave " + successRate + "XP to a Student");
|
||||||
|
}
|
||||||
|
if(successRate == 'createdQuest') {
|
||||||
|
createDiv('message', "Successfully Created Quest");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="members-container">
|
||||||
<!-- List of all site students (not teachers) -->
|
<!-- List of all site students (not teachers) -->
|
||||||
<h2>Studen Members</h2>
|
<h2>Studen Members</h2>
|
||||||
<div class='members'>
|
<div class='members'>
|
||||||
@@ -342,6 +427,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</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 for show/hide user profile data -->
|
||||||
<script>
|
<script>
|
||||||
function openProfile(id) {
|
function openProfile(id) {
|
||||||
|
|||||||
Reference in new issue
Block a user