Browse Source

v1.0

master
DeadF2K 3 years ago
commit
d9f266b720

+ 19
- 0
.gitignore View File

@@ -0,0 +1,19 @@
node_modules/**/*
.expo/*
npm-debug.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
*.orig.*
web-build/
web-report/
.idea/*
lettalk-release-key.keystore
*.iml
*.pem
trash
*.env
# macOS
.DS_Store

+ 0
- 0
db/posts.db View File


+ 0
- 0
db/sessions.db View File


+ 1
- 0
db/users.db View File

@@ -0,0 +1 @@
{"email":"admin@ghd.de","username":"admin","password":"$2b$10$30zu4TwSjMdjmnGQ.Nr6C./Tu71kEhlUHkHso2bnkKkn7Pm2q.u3e","role":"admin","_id":"VxsdGrHioVlUga4q"}

+ 66
- 0
init.setup View File

@@ -0,0 +1,66 @@
#!/bin/bash

#update sytem
sudo apt-get -y update
sudo apt-get -y upgrade

#enable and start ssh
sudo systemctl enable ssh
sudo systemctl start ssh

#install remote desktop
sudo apt-get -y install xrdp

#install nodejs
sudo apt-get -y install nodejs

#install npm
sudo apt-get -y install npm

#install firefox
sudo apt-get -y install firefox-esr

cd `dirname $0`
echo "`dirname $0`"
#get correct node modules

rm -rf node_modules
npm install express
npm install bcrypt
npm install nedb
npm install express-session
npm install nedb-session-store


#add server.start to autostart if not found
find="`grep server.start /etc/rc.local`"
if [ "$find" = "" ]
then
echo "adding server startup to /etc/rc.local"
cp /etc/rc.local "`pwd`"
sed -i '$d' rc.local
echo "`pwd`/server.start" >> rc.local
echo "exit 0" >> rc.local
sudo mv rc.local /etc/rc.local
else
echo "server startup already in /etc/rc.local"
fi

#add firefox start in kiosk mode after logged in
find="`grep firefox ~/.profile`"
if [ "$find" = "" ]
then
echo "adding firefox start to ~/.profile"
echo "firefox --kiosk http://localhost:8080/info &" >> ~/.profile
else
echo "firefox start already found in ~/.profile"
fi

sudo chmod +x server.start

echo "network/mac adress:`hostname -I`"

#system restart
echo "System will restart in 10s. ^C to cancel"
sleep 10
sudo reboot -h now

+ 1010
- 0
package-lock.json
File diff suppressed because it is too large
View File


+ 14
- 0
package.json View File

@@ -0,0 +1,14 @@
{
"name": "NodeHelp",
"version": "1.0.0",
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1",
"nedb": "^1.8.0",
"nedb-session-store": "^1.1.2"
},
"devDependencies": {
"bcrypt": "^5.0.0",
"express-session": "^1.17.1"
}
}

+ 61
- 0
public/admin-login.html View File

@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin-Page</title>
<link rel="stylesheet" text="text/css" href="styles.css">
<script src="admin.js"></script>
<!--Font Awesome Icons CDN-->
<link href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
</head>
<body>
<div class=main>
<div class="container user-container">
<div class="header">
<h1>Adminseite</h1>
</div>
<div class="ButtonRow">
<button class="logoutButton" id="lgoBtn">Logout</button>
<div class="rightButtons">
<button class="manageButton" id="mngBtn">Manage Posts</button>

<button data-popup-target="#addPopup" id="addBtn">&plus;</button>
<div class="popup" id="addPopup">
<div class="popup-header">
<div class="title">Registration Form</div>
<button data-close-btn class="close-btn">&times;</button>
</div>
<div class="popup-body">
<form class="" id="formNewUser" method="POST">
<div class="regSection">
<input type="email" id="email" required placeholder="e-Mail">
</div>
<div class="regSection">
<input type="text" id="username" required placeholder="Username">
</div>
<div class="ButtonRow">
<button type="submit" value="Create" id="submit">
Submit
</button>
</div>
</form>
</div>
</div>
<div class="" id="overlay"></div>
</div>
</div>
<div class="table" id="table">
</div>
<div class="ButtonRow">
<button class="logoutButton" id="changePwBtn">Change Password</button>
<div class="rightButtons">
<button class="icon-backward , backButton" id="pageDown"></button>
<button class="icon-forward , nextButton" id="pageUp"></button>
</div>
</div>
</div>
</div>
</body>
</html>

+ 189
- 0
public/admin.js View File

@@ -0,0 +1,189 @@
document.addEventListener("DOMContentLoaded", function(){
var form = document.getElementById("formNewUser");
form.addEventListener("submit", function(e){
e.preventDefault();
console.log("Sending Formular")
async function register(){
var email = document.getElementById("email").value;
var username = document.getElementById("username").value;
var bodyContent = {email:email, username:username};
var response = await fetch("/newmod", {
method: "POST",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
},
body:JSON.stringify(bodyContent)
});
var data = await response.json();
console.log(data);
loadMods();
}
register();
});

document.getElementById("changePwBtn").onclick = function(){
window.location = "/new-password";
}

/*changin page*/
var pageUp = document.getElementById("pageUp");
var pageDown = document.getElementById("pageDown");

pageUp.addEventListener("click", () => {
if(maxPages > currentPage+1) {
currentPage++;
loadMods();
}
});

pageDown.addEventListener("click", () => {
if(currentPage > 0){
currentPage--;
loadMods();
}
});

/*logout*/
var lgoBtn = document.getElementById("lgoBtn");
lgoBtn.addEventListener("click", () => {
window.location = "/logout";
});

var maxPages;
var currentPage = 0;
var maxDisplayed = 8;
async function loadMods(){
var response = await fetch("/getmods", {
method: "GET",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
}
})
var data = await response.json();
try{
showMods(data.users.slice(0 + (currentPage * maxDisplayed), maxDisplayed + (currentPage * maxDisplayed)));
console.log(data.users.slice(0 + (currentPage * maxDisplayed), maxDisplayed + (currentPage * maxDisplayed)));
maxPages = data.users.length / 8;
console.log(maxPages, currentPage+1)
}catch(error){
document.getElementById("table").innerHTML = ""; //empty table
}
};
loadMods();

function showMods(pdata){
document.getElementById("table").innerHTML = ""; //empty table
var container = document.getElementById("table"); //insert in table
pdata.forEach(element => {
var row = document.createElement("div");
var status;
var susbuttonstate;
if(element.suspended) {
status = "suspended"
susbuttonstate = "icon-pause"
} else {
status = "notSuspended"
susbuttonstate = "icon-play"
}
row.classList.add("row");
row.innerHTML = `
<div class="col-left">
<h2>${element.username}</h2>
</div>
<div class="col-right">
<button class="${status} susButton" data-username="${element.username}">
<i class="${susbuttonstate} , icon"></i>
</button>
<button class="remButton" data-username="${element.username}">
<i class="icon-trash , icon"></i>
</button>
</div>
`
container.appendChild(row)
});
}

async function toggleSus(pun){
var response = await fetch("/toggleSus", {
method: "POST",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
},
body:JSON.stringify({username:pun})
})
var data = await response.json();
console.log(data);
if(data.suc || !data.suc){
loadMods();
}
};

async function deleteMod(username){
var response = await fetch("/deleteMod", {
method: "POST",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
},
body:JSON.stringify({username:username})
})
var data = await response.json();
console.log(data);
if(data.suc || !data.suc){
loadMods();
}
};

var mngBtn = document.getElementById("mngBtn");
mngBtn.addEventListener("click", () => {
window.location = "/manage-posts";
});


document.addEventListener("click", function(e){
if(e.target && e.target.classList.contains("susButton")){
var un = e.target.getAttribute("data-username");
toggleSus(un);
}else if(e.target && e.target.classList.contains("remButton")){
var username = e.target.getAttribute("data-username");
deleteMod(username);
}
})


/*-----New User Popup-----*/
const openPopupBtns = document.querySelectorAll("[data-popup-target]");
const closePopupBtns = document.querySelectorAll("[data-close-btn]");
const overlay = document.getElementById("overlay");

openPopupBtns.forEach(btn => {
btn.addEventListener("click", () => {
const popup = document.querySelector(btn.dataset.popupTarget);
openPopup(popup);
})
});

closePopupBtns.forEach(btn => {
btn.addEventListener("click", () => {
const popup = btn.closest(".popup")
closePopup(popup);
})
});

function openPopup(popup) {
if (popup == null) return
popup.classList.add("active");
overlay.classList.add("active");
}

function closePopup(popup) {
if (popup == null) return
popup.classList.remove("active");
overlay.classList.remove("active");
}
});

+ 37
- 0
public/change-pw.html View File

@@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=2.0">
<title>Change Password</title>
<link rel="stylesheet" text="text/css" href="styles.css">
<script src="change-pw.js"></script>
</head>
<body>
<div class="main">
<div class="container">
<div class="header">
<h1>Change Password</h1>
</div>
<form name="login" method="post" id="loginform">
<div class="datasec">
<input class="password" type="password" name="password" id="old_pw" required placeholder="Old Password">
</div>
<div class="datasec">
<input class="password" type="password" name="password" id="new_pw_1" required placeholder="New Password">
</div>
<div class="datasec">
<input class="password" type="password" name="password" id="new_pw_2" required placeholder="Confirm Password">
</div>
<div class="buttons-container">
<button class="button"
type="submit"
name="submit">
<span id="loginText">Change Password</span>
</button>
</div>
</form>
</div>
</div>
</body>
</html>

+ 30
- 0
public/change-pw.js View File

@@ -0,0 +1,30 @@
//write code in next section
//will run when DOM is loaded
document.addEventListener("DOMContentLoaded", function(){
var form = document.getElementById("loginform");
async function login() {
var old_pw = document.getElementById("old_pw").value;
var new_pw_1 = document.getElementById("new_pw_1").value;
var new_pw_2 = document.getElementById("new_pw_2").value;
var body = {old_password:old_pw, new_password_1:new_pw_1, new_password_2:new_pw_2};
var response = await fetch("/changepw", {
method:"POST",
headers:{
"Accept":"application/json",
"Content-Type":"application/json"
},
body:JSON.stringify(body)
})
var data = await response.json();
console.log("Data: ");
console.log(data);
if(data.suc){
window.location = "/main"
}
}
form.addEventListener("submit", function(e){
e.preventDefault();
login();
});
});

+ 37
- 0
public/index.html View File

@@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=2.0">
<title>Login</title>
<link rel="stylesheet" text="text/css" href="styles.css">
<script src="login.js"></script>
</head>
<body>
<div class="main">
<div class="container">
<div class="header">
<h1>Login</h1>
</div>
<form name="login" method="post" id="loginform">
<div class="datasec">
<input class="username" type="text" name="username" id="un" required placeholder="Username" autocomplete="off">
</div>
<div class="datasec">
<input class="password" type="password" name="password" id="pw" required placeholder="Password">
</div>
<div class="buttons-container">
<button class="button"
type="submit"
name="submit">
<span id="loginText">Log In</span>
</button>
</div>
</form>
<button class="button" id="prev">
<span>Preview</span>
</button>
</div>
</div>
</body>
</html>

+ 31
- 0
public/info-page.html View File

@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>InfoTafel</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='stylesheet' type='text/css' media='screen' href='styles.css'>
<script src='info-page.js'></script>
<link href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div class="TitleRow" id="topper">
<div class="titleDiv"></div>
<div class="titleDiv">
<h1>Infoseite</h1>
<h3>Brought to you by Th-Nürnberg</h3>
</div>
<div class="titleDiv">
<h2 id="clock"></h2>
</div>
</div>
<div id="content">
</div>
<div id="lower">
</div>
</body>
</html>

+ 84
- 0
public/info-page.js View File

@@ -0,0 +1,84 @@
document.addEventListener("DOMContentLoaded", function(){
var SwitchTime = 10; // in Seconds

document.getElementById("topper").onclick = function(){
window.location = "/main";
}

var maxPages;
var currentPage = 0;
var maxDisplayed = 6;
async function loadPosts(){
var response = await fetch("/getliveposts", {
method: "GET",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
}
})
var data = await response.json();
//console.log(data);
try{
showPosts(data.posts.slice(0 + (currentPage * maxDisplayed), maxDisplayed + (currentPage * maxDisplayed)));
//console.log(data.posts.slice(0 + (currentPage * maxDisplayed), maxDisplayed + (currentPage * maxDisplayed)));
maxPages = data.posts.length / maxDisplayed;
//console.log(maxPages, currentPage+1)
}catch(error){
document.getElementById("content").innerHTML = ""; //empty content
}
};
loadPosts();

function showPosts(pdata){
var container = document.getElementById("content"); //insert in content
container.innerHTML = "" //empty content
pdata.forEach(element => {
var post = document.createElement("div");
post.classList.add("post");
post.style.backgroundColor = element.bcolor;
post.innerHTML = `
<div class="title" style="background-color:${element.bcolor};">
<h2 class="preview-title" >${element.title}</h2>
</div>
<div class="body">
${element.text}
</div>
`
container.appendChild(post)
});
}

function startTime() {
var today = new Date();
var h = today.getHours();
var m = today.getMinutes();
var s = today.getSeconds();
h = checkTime(h);
m = checkTime(m);
s = checkTime(s);
document.getElementById('clock').innerHTML =
h + ":" + m + ":" + s;
var t = setTimeout(startTime, 500);
}
function checkTime(i) {
if (i < 10) {i = "0" + i}; // add zero in front of numbers < 10
return i;
}
startTime();

function changePage(){
if(maxPages > currentPage+1) {
currentPage++;
}
else{
currentPage = 0;
loadPosts();
}

loadPosts();
setTimeout(changePage, SwitchTime*1000);
}
changePage();
});


+ 50
- 0
public/login.js View File

@@ -0,0 +1,50 @@
//write code in next section
//will run when DOM is loaded
document.addEventListener("DOMContentLoaded", function(){
var form = document.getElementById("loginform");
async function login() {
var un = document.getElementById("un").value;
var pw = document.getElementById("pw").value;
var body = {username:un, password:pw};
var response = await fetch("/login", {
method:"POST",
headers:{
"Accept":"application/json",
"Content-Type":"application/json"
},
body:JSON.stringify(body)
})
var data = await response.json();
console.log("Data: ");
console.log(data);
if(data.suc){
window.location = "/main"
} else {
var loginText = document.getElementById("loginText");
var inputs = document.getElementsByTagName("input")
var inputList = Array.prototype.slice.call(inputs);

loginText.classList.add("fadeout");
setTimeout(function() {
loginText.innerText = "Try Again";
loginText.classList.remove("fadeout");
}, 350);
console.log(inputs);
inputList.forEach(element => {
element.style.borderBottom="1px solid #F00";
if(element.getAttribute("type") === "password"){
element.value = "";
element.focus();
}
});
}
}
form.addEventListener("submit", function(e){
e.preventDefault();
login();
});
var prevBtn = document.getElementById("prev")
prevBtn.addEventListener("click", function(){
window.location ="/info"
})
});

+ 36
- 0
public/manage-post.html View File

@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Manage-Posts</title>
<link rel="stylesheet" text="text/css" href="styles.css">
<script src="manage-post.js"></script>
<!--Font Awesome Icons CDN-->
<link href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
</head>
<body>
<div class=main>
<div class="container user-container">
<div class="header">
<h1>Manage Posts</h1>
</div>
<div class="ButtonRow">
<button class="logoutButton" id="lgoBtn">Logout</button>
<div class="rightButtons">
<button class="manageButton" id="mngBtn">Manage Group</button>
</div>
</div>
<div class="table" id="table">
</div>
<div class="ButtonRow">
<div></div>
<div class="rightButtons">
<button class="icon-backward , backButton" id="pageDown"></button>
<button class="icon-forward , nextButton" id="pageUp"></button>
</div>
</div>
</div>
</div>
</body>
</html>

+ 161
- 0
public/manage-post.js View File

@@ -0,0 +1,161 @@
document.addEventListener("DOMContentLoaded", function(){
/*changin page*/
var pageUp = document.getElementById("pageUp");
var pageDown = document.getElementById("pageDown");
var reviewButtons = document.getElementsByClassName('editButton');

pageUp.addEventListener("click", () => {
if(maxPages > currentPage+1) {
currentPage++;
loadPosts();
}
});

pageDown.addEventListener("click", () => {
if(currentPage > 0){
currentPage--;
loadPosts();
}
});

/*logout*/
var lgoBtn = document.getElementById("lgoBtn");
lgoBtn.addEventListener("click", () => {
window.location = "/logout";
});
var mngBtn = document.getElementById("mngBtn");
mngBtn.addEventListener("click", () => {
window.location = "/main";
});

async function toggleSus(postid){
var response = await fetch("/toggleShow", {
method: "POST",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
},
body:JSON.stringify({postid:postid})
})
var data = await response.json();
console.log(data);
if(data.suc || !data.suc){
loadPosts();
}
};

async function deletePost(postid){
var response = await fetch("/deletePost", {
method: "POST",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
},
body:JSON.stringify({postid:postid})
})
var data = await response.json();
console.log(data);
if(data.suc || !data.suc){
loadPosts();
}
};


document.addEventListener("click", function(e){
if(e.target && e.target.classList.contains("susButton")){
var postid = e.target.getAttribute("data-username");
toggleSus(postid);
}else if(e.target && e.target.classList.contains("remButton")){
var postid = e.target.getAttribute("data-username");
deletePost(postid);
}
})

/*Show Elements*/
var maxPages;
var currentPage = 0;
var maxDisplayed = 8;
async function loadPosts(){
var response = await fetch("/getposts", {
method: "GET",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
}
})
var data = await response.json();
try{
showPosts(data.users.slice(0 + (currentPage * maxDisplayed), maxDisplayed + (currentPage * maxDisplayed)));
console.log(data.users.slice(0 + (currentPage * maxDisplayed), maxDisplayed + (currentPage * maxDisplayed)));
maxPages = data.users.length / 8;
console.log(maxPages, currentPage+1)
reviewButtons = document.getElementsByClassName('editButton');
console.log(reviewButtons.length);
addButtons();
}catch(error){
document.getElementById("table").innerHTML = ""; //empty table
}
};
loadPosts();

function showPosts(pdata){
document.getElementById("table").innerHTML = ""; //empty table
var container = document.getElementById("table"); //insert in table
pdata.forEach(element => {
var row = document.createElement("div");
var status;
var susbuttonstate;
if(!element.showpost) {
status = "hidden"
susbuttonstate = "icon-eye-close"
} else {
status = "shown"
susbuttonstate = "icon-eye-open"
}
row.classList.add("row");
row.innerHTML = `
<div class="col-left">
<h2>${element.title}</h2>
</div>
<div class="col-right">
<button class="editButton" data-username="${element.postid}">
<i class="icon-file-text-alt , icon"></i>
</button>
<button class="${status} susButton" data-username="${element.postid}">
<i class="${susbuttonstate} , icon"></i>
</button>
<button class="remButton" data-username="${element.postid}">
<i class="icon-trash , icon"></i>
</button>
</div>
`
container.appendChild(row)
});
}
async function reviewPost(postid){
var response = await fetch("/updatePostID", {
method: "POST",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
},
body:JSON.stringify({postid:postid})
})
var data = await response.json();
if(data || !data)
{
window.location = "/post-review";
}
};
function addButtons(){
for(let i = 0; i < reviewButtons.length; i++){
reviewButtons[i].addEventListener('click', function(){
reviewPost(this.dataset.username)
})
}
}
});

+ 60
- 0
public/mod-login.html View File

@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mod-Page</title>
<link rel="stylesheet" text="text/css" href="styles.css">
<script src="mod.js"></script>
<!--Font Awesome Icons CDN-->
<link href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
</head>
<body>
<div class=main>
<div class="container user-container">
<div class="header">
<h1>Modseite</h1>
</div>
<div class="ButtonRow">
<button class="logoutButton" id="lgoBtn">Logout</button>
<div class="rightButtons">
<button class="manageButton" id="mngBtn">Manage Posts</button>
<button data-popup-target="#addPopup" id="addBtn">&plus;</button>
<div class="popup" id="addPopup">
<div class="popup-header">
<div class="title">Registration Form</div>
<button data-close-btn class="close-btn">&times;</button>
</div>
<div class="popup-body">
<form class="" id="formNewUser" method="POST">
<div class="regSection">
<input type="email" id="email" required placeholder="e-Mail">
</div>
<div class="regSection">
<input type="text" id="username" required placeholder="Username">
</div>
<div class="btn">
<button type="submit" value="Create" id="submit">
<span>Submit</span>
</button>
</div>
</form>
</div>
</div>
<div class="" id="overlay"></div>
</div>
</div>
<div class="table" id="table">
</div>
<div class="ButtonRow">
<button class="logoutButton" id="changePwBtn">Change Password</button>
<div class="rightButtons">
<button class="icon-backward , backButton" id="pageDown"></button>
<button class="icon-forward , nextButton" id="pageUp"></button>
</div>
</div>
</div>
</div>
</body>
</html>

+ 189
- 0
public/mod.js View File

@@ -0,0 +1,189 @@
document.addEventListener("DOMContentLoaded", function(){
var form = document.getElementById("formNewUser");
form.addEventListener("submit", function(e){
e.preventDefault();
console.log("Sending Formular")
async function register(){
var email = document.getElementById("email").value;
var username = document.getElementById("username").value;
var bodyContent = {email:email, username:username};
var response = await fetch("/newuser", {
method: "POST",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
},
body:JSON.stringify(bodyContent)
});
var data = await response.json();
console.log(data);
loadUsers();
}
register();
});

document.getElementById("changePwBtn").onclick = function(){
window.location = "/new-password";
}

/*changin page*/
var pageUp = document.getElementById("pageUp");
var pageDown = document.getElementById("pageDown");

pageUp.addEventListener("click", () => {
if(maxPages > currentPage+1) {
currentPage++;
loadUsers();
}
});

pageDown.addEventListener("click", () => {
if(currentPage > 0){
currentPage--;
loadUsers();
}
});

/*logout*/
var lgoBtn = document.getElementById("lgoBtn");
lgoBtn.addEventListener("click", () => {
window.location = "/logout";
});

var mngBtn = document.getElementById("mngBtn");
mngBtn.addEventListener("click", () => {
window.location = "/manage-posts";
});

var maxPages;
var currentPage = 0;
var maxDisplayed = 8;
async function loadUsers(){
var response = await fetch("/getusers", {
method: "GET",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
}
})
var data = await response.json();
try{
showUsers(data.users.slice(0 + (currentPage * maxDisplayed), maxDisplayed + (currentPage * maxDisplayed)));
console.log(data.users.slice(0 + (currentPage * maxDisplayed), maxDisplayed + (currentPage * maxDisplayed)));
maxPages = data.users.length / 8;
console.log(maxPages, currentPage+1)
}catch(error){
document.getElementById("table").innerHTML = ""; //empty table
}
};
loadUsers();

function showUsers(pdata){
document.getElementById("table").innerHTML = ""; //empty table
var container = document.getElementById("table"); //insert in table
pdata.forEach(element => {
var row = document.createElement("div");
var status;
var susbuttonstate;
if(element.suspended) {
status = "suspended"
susbuttonstate = "icon-pause"
} else {
status = "notSuspended"
susbuttonstate = "icon-play"
}
row.classList.add("row");
row.innerHTML = `
<div class="col-left">
<h2>${element.username}</h2>
</div>
<div class="col-right">
<button class="${status} susButton" data-username="${element.username}">
<i class="${susbuttonstate} , icon"></i>
</button>
<button class="remButton" data-username="${element.username}">
<i class="icon-trash , icon"></i>
</button>
</div>
`
container.appendChild(row)
});
}

async function toggleSus(pun){
var response = await fetch("/toggleSus", {
method: "POST",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
},
body:JSON.stringify({username:pun})
})
var data = await response.json();
console.log(data);
if(data.suc || !data.suc){
loadUsers();
}
};

async function deleteUser(username){
var response = await fetch("/deleteUser", {
method: "POST",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
},
body:JSON.stringify({username:username})
})
var data = await response.json();
console.log(data);
if(data.suc || !data.suc){
loadUsers();
}
};


document.addEventListener("click", function(e){
if(e.target && e.target.classList.contains("susButton")){
var un = e.target.getAttribute("data-username");
toggleSus(un);
}else if(e.target && e.target.classList.contains("remButton")){
var username = e.target.getAttribute("data-username");
deleteUser(username);
}
})


/*-----New User Popup-----*/
const openPopupBtns = document.querySelectorAll("[data-popup-target]");
const closePopupBtns = document.querySelectorAll("[data-close-btn]");
const overlay = document.getElementById("overlay");

openPopupBtns.forEach(btn => {
btn.addEventListener("click", () => {
const popup = document.querySelector(btn.dataset.popupTarget);
openPopup(popup);
})
});

closePopupBtns.forEach(btn => {
btn.addEventListener("click", () => {
const popup = btn.closest(".popup")
closePopup(popup);
})
});

function openPopup(popup) {
if (popup == null) return
popup.classList.add("active");
overlay.classList.add("active");
}

function closePopup(popup) {
if (popup == null) return
popup.classList.remove("active");
overlay.classList.remove("active");
}
});

+ 75
- 0
public/new-Postv2.html View File

@@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Post Editor</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='stylesheet' type='text/css' media='screen' href='styles.css'>
<script src='new-Postv2.js'></script>
<link href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
</head>
<body>
<div class="main">
<div class="container postContainer" id="box">
<div class=topper>
<button id="cancelBtn" title="Cancel">&times;</button>
</div>
<div class="editor">
<div class="editor-menubar">
<button class="editor-button icon-picture" data-popup-target="#addPopup" data-attribute="insertImage" title="Add Image"></button>
<div class="" id="overlay"></div>
<div class="popup" id="addPopup">
<div class="popup-header">
<div class="title">Add Picture</div>
<button data-close-btn class="close-btn">&times;</button>
</div>
<div class="popup-body">
<div class="" id="formNewUser">
<div class="regSection">
<input type="text" id="url" required placeholder="URL">
</div>
<div class="btn">
<button type="submit" value="Create" id="add">
<span>Add</span>
</button>
</div>
</div>
</div>
</div>
<button class="editor-button icon-bold" data-attribute="bold" title="Bold"></button>
<button class="editor-button icon-italic" data-attribute="italic" title="Italic"></button>
<button class="editor-button icon-underline" data-attribute="underline" title="Underline"></button>
<button class="editor-button icon-superscript" data-attribute="superscript" title="Superscript"></button>
<button class="editor-button icon-subscript" data-attribute="subscript" title="Subscript"></button>
<input class="color-select" data-attribute="forecolor" type="color" id="forecolor" title="Text Colour">
</div>
<div id="title-text">
<div class="canvas" id="title-canvas" contenteditable=true data-text="Title"></div>
<div class="canvas" id="editor-canvas" contenteditable=true data-text="Content"></div>
</div>
<div class="editor-menubar">
<button class="editor-button icon-undo" data-attribute="undo" title="Undo"></button>
<button class="editor-button icon-repeat" data-attribute="redo" title="Redo"></button>
<button class="editor-button icon-align-left" data-attribute="justifyleft" title="Justify Left"></button>
<button class="editor-button icon-align-center" data-attribute="justifycenter" title="Justify Center"></button>
<button class="editor-button icon-align-right" data-attribute="justifyright" title="Justify Right"></button>
<input class="color-select" data-attribute="backcolor" type="color" id="backcolor" title="Background Colour" value="#ffffff">
</div>
</div>
<div class="lower">
<div class="calendar">
<label for="start">Start date:</label>
<input class="calendar-element" type="date" id="startDate" value=2020-01-01 min=2020-01-01>
</div>
<div class="calendar">
<label for="start">End date:</label>
<input class="calendar-element" type="date" id="endDate" value=2020-01-01 min=2020-01-01>
</div>
<button id="submit-post">Submit</button>
</div>
</div>
</div>
</body>
</html>

+ 118
- 0
public/new-Postv2.js View File

@@ -0,0 +1,118 @@
document.addEventListener("DOMContentLoaded", function(){
const editorButtons = document.getElementsByClassName('editor-button');
const setAttribute = (element) => {
document.execCommand(element.dataset.attribute, false);
};

for(let i = 0; i <editorButtons.length; i++) {
editorButtons[i].addEventListener('click', function(){
setAttribute(this);
});
}

document.getElementById("cancelBtn").onclick = function(){
window.location = "/main";
}

document.getElementById("add").onclick = function(){
document.execCommand("insertImage", false, document.getElementById("url").value);
}

document.getElementById("forecolor").onchange = function(){setColor(this);}
const setColor = (element) => {
console.log(element);
document.execCommand(element.dataset.attribute, false, element.value);
};


const backColor = document.getElementById("backcolor");
const helo = document.getElementsByClassName("canvas");
backColor.addEventListener('change', function(){
console.log(this);
for(let i = 0; i <helo.length; i++) {
helo[i].style.backgroundColor = backColor.value;
};
});

document.getElementById("submit-post").onclick = function(){
if(document.getElementById('title-canvas').innerHTML && document.getElementById('editor-canvas').innerHTML)
{
const title = document.getElementById('title-canvas').innerHTML;
const content = document.getElementById('editor-canvas').innerHTML;
const date_begin = document.getElementById('startDate').value;
const date_end = document.getElementById('endDate').value;
const bcolor = document.getElementById('backcolor').value;
var bodyContent = {title:title, text:content, startDate:date_begin, endDate:date_end, bcolor:bcolor};
send(bodyContent);
}
};

async function send(bodyContent){
console.log(bodyContent);
var response = await fetch("/newpost", {
method: "POST",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
},
body:JSON.stringify(bodyContent)
});
var data = await response.json();
console.log(data);
console.log(helo);
window.location = "/main";
}

/*-----New User Popup-----*/
const openPopupBtns = document.querySelectorAll("[data-popup-target]");
const closePopupBtns = document.querySelectorAll("[data-close-btn]");
const overlay = document.getElementById("overlay");

openPopupBtns.forEach(btn => {
btn.addEventListener("click", () => {
const popup = document.querySelector(btn.dataset.popupTarget);
openPopup(popup);
})
});

closePopupBtns.forEach(btn => {
btn.addEventListener("click", () => {
const popup = btn.closest(".popup")
closePopup(popup);
})
});

function openPopup(popup) {
if (popup == null) return
popup.classList.add("active");
overlay.classList.add("active");
}

function closePopup(popup) {
if (popup == null) return
popup.classList.remove("active");
overlay.classList.remove("active");
}

document.getElementById("startDate").onchange = function(){
document.getElementById("endDate").min = document.getElementById("startDate").value;
var end = new Date(document.getElementById("startDate").value);
end.setDate(end.getDate() +7);
var endDate = end.toISOString().slice(0,10);
document.getElementById("endDate").value = endDate;
}

function date(){
var today = new Date().toISOString().slice(0,10);
var end = new Date();
end.setDate(end.getDate() + 7)
var endDate = end.toISOString().slice(0,10);

document.getElementById("startDate").value = today;
document.getElementById("startDate").min = today;
document.getElementById("endDate").value = endDate;
document.getElementById("endDate").min = today;
};
date()
});

+ 28
- 0
public/post-review.html View File

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Post Editor</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='stylesheet' type='text/css' media='screen' href='styles.css'>
<script src='post-review.js'></script>
<link href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
</head>
<body>
<div class="main">
<div class="container postContainer" id="box">
<div class=topper>
<button id="cancelBtn" title="Cancel">&times;</button>
</div>
<div id="title-text">
<div class="canvas" id="title-canvas" data-text="Title"></div>
<div class="canvas" id="editor-canvas" data-text="Content"></div>
</div>
<div class="lower">
<button id="submit-post"></button>
</div>
</div>
</div>
</body>
</html>

+ 49
- 0
public/post-review.js View File

@@ -0,0 +1,49 @@
document.addEventListener("DOMContentLoaded", function(){
document.getElementById("cancelBtn").onclick = function(){
window.location = "/main";
}

var id;
async function loadPost(){
var response = await fetch("/getReviewPost", {
method: "GET",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
}
})
var data = await response.json();
id = data.post[0].postid;
document.getElementsByClassName("canvas")[0].style.backgroundColor = data.post[0].bcolor;
document.getElementsByClassName("canvas")[1].style.backgroundColor = data.post[0].bcolor;
document.getElementById("title-canvas").innerHTML = data.post[0].title;
document.getElementById("editor-canvas").innerHTML = data.post[0].text;

if(data.post[0].showpost) {
document.getElementById("submit-post").innerHTML = "Suspend Post"
} else {
document.getElementById("submit-post").innerHTML = "Confirm Post"
}
};
loadPost();
document.getElementById("submit-post").onclick = function(){
toggleShow(id);
}

async function toggleShow(pun){
var response = await fetch("/toggleShow", {
method: "POST",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
},
body:JSON.stringify({postid:pun})
})
var data = await response.json();
console.log(data);
if(data.suc || !data.suc){
window.location = "/main"
}
};
});

+ 553
- 0
public/styles.css View File

@@ -0,0 +1,553 @@
:root {
--border-prop: 0px solid #F2F;
--header-height: 10%;
--prime-color: rgb(71, 17, 221);
--container-bg: rgba(30, 30, 50, 0.644);
--text-color: rgba(255,255,255, 1);
--row-color: rgba(0, 0, 100, 0.3);
--button-prim: rgba(255,255,255,0.1);
--button-sec: rgba(255, 255, 255, 0.4);
--popup-border: 2px solid rgb(11, 11, 128);
--popup-stripe: 3px solid rgba(0,0,50,0.5);
--title-size: 60px;
--text-size: 30px;
--smal-text: 20px;
}

div{
border: 0px #F2F;
border-style: dashed;
}

html, body {
width: 100%;
height: 100%;
background: var(--prime-color);
margin: 0;
}

header{
height: var(--header-height);
padding-top: 30px;
display: flex;
justify-content: center;
}

/*text*/
h1, h2, h3, .title, label{
font-size: var(--title-size);
padding: 0px;
margin: 0px;
font-family: Arial;
color: var(--text-color);
}

h2, label{
font-size: var(--text-size);
}

h3{
font-size: var(--smal-text);
}



input {
width: 100%;
font-family: Arial;
font-size: 2em;
color: rgb(255, 255, 255);
padding: 0;
padding-bottom: 5px;
background: none;
border: none;
border-bottom: 1px solid #ffffff;
margin-bottom: 15px;
margin-top: 15px
}

input:focus {
outline: 0;
}

.main {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}

.container{
width: 400px;
border: var(--border-prop);
background-color: var(--container-bg);
padding: 20px;

display: flex;
flex-direction: column;
}

.user-container{
width: 50%;
min-height: 35em;
}

.header {
border: var(--border-prop);
font-size: 25px;
text-align: center;
margin-bottom: 25px;
}

.datasec {
border: var(--border-prop);
font-family: Arial;
font-size: 30px;
color: white;
}

/* buttons */

.buttons-container {
border: var(--border-prop);
display: flex;
justify-content: center;
width: 100%;
}

.button {
display: inline-block;
border-radius: 0;
background-color: #303030;
border: none;
/*text*/
color: #FFFFFF;
text-align: center;
font-size: var(--text-size);
padding: 10px;
width: 100%;
cursor: pointer;
}

.button span{
cursor: pointer;
display: inline-block;
position: relative;
transition: 1s;
}

.button span::after {
content: '\00bb';
position: absolute;
opacity: 0;
top: 0;
right: -20px;
transition: .5s;
}

.button:hover span {
padding-right: 25px;
}

.button:hover span::after{
opacity: 1;
right: 0;
}

.susButton , .remButton, .nextButton, .manageButton, #addBtn{
margin-left: 5px;
}

.icon{
pointer-events: none;
}

/* end of buttons*/

#loginText {
transition: 0.35s;
}

.fadeout {
opacity: 0;
}

#loginform {
border: var(--border-prop);
margin-bottom: 10px;
}

/*
border: 1px #F2F;
border-style: dashed;
*/


/* User/Mod Table */

.table{
min-height: 32em;
}

.row{
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
background-color: var(--row-color);
margin-top: 10px;
margin-bottom: 10px;
padding-left: 10px;
padding-right: 10px;
}

.col-left , .col-right{
display: flex;
padding: 0;
margin: 0;
}

/* End of Table */

/* Page Selector */

.rightButtons{
display: flex;
margin-left: 10px;
}

.ButtonRow{
display: flex;
flex-direction: row;
justify-content: space-between;
padding-right: 10px;
}

/* End of Page Selector*/

/*-----POPUP-----*/
.popup{
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
transition: 50ms ease-in-out;
border: var(--popup-border);
z-index: 10; /*lay ontop of everything*/
background-color: var(--prime-color);
width: 500px;
max-width: 80%;
min-height: 18em;
display: flex;
flex-direction: column;
justify-content: space-evenly;
}

.popup.active{
transform: translate(-50%, -50%) scale(1);
}

.popup-header{
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: var(--popup-stripe);
}

.popup-header .title{
font-size: var(--text-size);
font-weight: bold;
}

.popup-header .close-btn{
cursor: pointer;
border: none;
outline: none;
background: none;
font-size: var(--title-size);
font-weight: bold;
color: white;
}

.popup-body{
display: flex;
justify-content: center;
padding: 10px;
}

#overlay{
position: fixed;
opacity: 0;
transition: 50ms ease-in-out;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0,0,0,.75);
pointer-events: none;
}

#overlay.active{
opacity: 1;
pointer-events: all;
}

.popup-body{
display: fixed;
justify-items: center;
}

#formNewUser{
width: 50%;
}

input {
width: 100%;
font-family: Arial;
font-size: var(--text-size);
color: white;
padding: 0;
padding-bottom: 5px;
background: none;
border: none;
border-bottom: 1px solid #ffffff;
margin-bottom: 15px;
margin-top: 15px
}

input:focus {
outline: 0;
}

/*-----POPUP-END-----*/

/* New Post Section*/


[contentEditable=true]:empty:not(:focus):before{
content:attr(data-text);
color: rgba(0,0,0,0.5);
}

.preview-title{
color: #000;
}

.editor{
display: flex;
flex-flow: row;
justify-content: center;
}

.editor-menubar{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

button, .color-select{
color: #ffffff;
font-size: var(--text-size);
padding-left: 10px;
padding-right: 10px;
background-color: var(--button-prim);
cursor: pointer;
transition: all 250ms;
border: none;
min-width: 50px;
min-height: 50px;
}

button:hover{
background-color: var(--button-sec);
}

button:focus{
outline: none;
}

.regSection{
font-size: var(--text-size);
}

.canvas{
background-color: rgba(255,255,255,1);
width: 46.3rem;
height: 30rem;
padding: 2.5rem;
font-size: var(--text-size);
color: #000;
font-family: arial;
line-height: 1.5em;
}

.canvas:focus{
outline: none;
}

#title-canvas, #editor-canvas{
height: 5rem;
font-size: var(--title-size);
align-self: center;
text-align: center;
text-justify: center;
padding: 10px;
border-bottom: .5rem solid #000 ;
}

#editor-canvas{
text-align: left;
text-justify: left;
height: 30rem;
font-size: var(--smal-text);
}

#box{
display: flex;
flex-direction: column;
}

#cancelBtn{
padding: 0;
font-size: var(--title-size);
line-height: 1.8rem;
}

.postContainer{
width: 60em;
}

.lower{
display: flex;
flex-flow: row;
justify-content: center;
align-items: center;
}

.topper{
display: flex;
flex-flow: row;
justify-content: flex-end;
align-items: flex-end;
}

.calendar{
color: #ffffff;
font-size: var(--text-size);
padding: 1rem;
transition: all 250ms;
display: flex;
flex-flow: column;
align-items: center;
justify-content: center;
margin-left: .5rem;
margin-right: .5rem;
}

.calendar-element{
border: none;
}

.calendar-element:focus{
outline: none;
}

#title-text{
width: 100%;
display: flex;
flex-flow: column;
}

#submit-post{
margin-left: .5rem;
}

.color-select{
background-color: var(--button-prim);
padding-left: 0px;
padding-right: 0px;
display: flex;
justify-content: center;
margin: 0px;
}

.color-select:hover{
background-color: var(--button-sec);
}

.editor-button{
min-width: 50px;
max-width: 50px;
min-height: 50px;
max-height: 50px;
}

/* End of New Post*/

/* Preview */

.TitleRow{
max-width: 100%;
display: flex;
flex-direction: row;
justify-content: space-evenly;
background-color: var(--container-bg);
padding-right: 10px;
padding-bottom: 10px;
align-items: center;
margin-bottom: 5px;
}

.titleDiv{
min-width: 25%;
}

#topper{
height: 10%;
text-align: center;
top: 0px;
}

#content{
width: 100%;
height: 85%;
display: flex;
justify-content: center;
flex-wrap: wrap;
}

@keyframes fadein {
0% {
opacity: 0;
}
}

.post{
animation: fadein 2s ease;

min-width: 30%;
max-width: 45%;
min-height: 28%;
max-height: 45%;
padding: 2vh;
margin: 5px;
border-width: 0px;
border-color: var(--prime);
color: black;
}

.hidden{
color: red;
}

/* End of Preview */


+ 38
- 0
public/user-login.html View File

@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>User-Page</title>
<link rel="stylesheet" text="text/css" href="styles.css">
<script src="user.js"></script>
<!--Font Awesome Icons CDN-->
<link href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
</head>
<body>
<div class=main>
<div class="container user-container">
<div class="header">
<h1>Benutzerseite</h1>
</div>
<div class="ButtonRow">
<button class="logoutButton" id="lgoBtn">Logout</button>

<button onclick="location.href='/newPost'" id="addBtn">&plus;</button>
<div class="" id="overlay"></div>
</div>
<div class="table" id="table">
</div>
<div class="ButtonRow">
<button class="logoutButton" id="changePwBtn">Change Password</button>
<div class="rightButtons">
<button class="icon-backward , backButton" id="pageDown"></button>
<button class="icon-forward , nextButton" id="pageUp"></button>
</div>
</div>
</div>
</div>
</body>
</html>

+ 143
- 0
public/user.js View File

@@ -0,0 +1,143 @@
document.addEventListener("DOMContentLoaded", function(){
/*changin page*/
var pageUp = document.getElementById("pageUp");
var pageDown = document.getElementById("pageDown");
var reviewButtons = document.getElementsByClassName('editButton');


document.getElementById("changePwBtn").onclick = function(){
window.location = "/new-password";
}

pageUp.addEventListener("click", () => {
if(maxPages > currentPage+1) {
currentPage++;
loadPosts();
}
});

pageDown.addEventListener("click", () => {
if(currentPage > 0){
currentPage--;
loadPosts();
}
});

async function deletePost(postid){
var response = await fetch("/deletePost", {
method: "POST",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
},
body:JSON.stringify({postid:postid})
})
var data = await response.json();
console.log(data);
if(data.suc || !data.suc){
loadPosts();
}
};

document.addEventListener("click", function(e){
if(e.target && e.target.classList.contains("remButton")){
var postid = e.target.getAttribute("data-username");
deletePost(postid);
}
})

/*logout*/
var lgoBtn = document.getElementById("lgoBtn");
lgoBtn.addEventListener("click", () => {
window.location = "/logout";
});

/*NewPost*/
var addBtn = document.getElementById("addBtn");
addBtn.addEventListener("click", () => {
window.location = "/newPost";
});

/*Show Elements*/
var maxPages;
var currentPage = 0;
var maxDisplayed = 8;
async function loadPosts(){
var response = await fetch("/getposts", {
method: "GET",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
}
})
var data = await response.json();
try{
showPosts(data.users.slice(0 + (currentPage * maxDisplayed), maxDisplayed + (currentPage * maxDisplayed)));
console.log(data.users.slice(0 + (currentPage * maxDisplayed), maxDisplayed + (currentPage * maxDisplayed)));
maxPages = data.users.length / 8;
console.log(maxPages, currentPage+1)
reviewButtons = document.getElementsByClassName('editButton');
console.log(reviewButtons.length);
addButtons();
}catch(error){
document.getElementById("table").innerHTML = ""; //empty table
}
};
loadPosts();

function showPosts(pdata){
document.getElementById("table").innerHTML = ""; //empty table
var container = document.getElementById("table"); //insert in table
pdata.forEach(element => {
var row = document.createElement("div");
var status;
if(!element.showpost) {
status = "hidden icon-eye-close"
} else {
status = "shown icon-eye-open"
}
row.classList.add("row");
row.innerHTML = `
<div class="col-left">
<h2>${element.title}</h2>
</div>
<div class="col-right">
<button class="editButton" data-username="${element.postid}">
<i class="icon-file-text-alt , icon"></i>
</button>
<button class="${status} susButton">
</button>
<button class="remButton" data-username="${element.postid}">
<i class="icon-trash , icon"></i>
</button>
</div>
`
container.appendChild(row)
});
}
async function reviewPost(postid){
var response = await fetch("/updatePostID", {
method: "POST",
headers: {
"Accept":"application/json",
"Content-Type":"application/json"
},
body:JSON.stringify({postid:postid})
})
var data = await response.json();
if(data || !data)
{
window.location = "/post-review";
}
};
function addButtons(){
for(let i = 0; i < reviewButtons.length; i++){
reviewButtons[i].addEventListener('click', function(){
reviewPost(this.dataset.username)
})
}
}
});

+ 573
- 0
server.js View File

@@ -0,0 +1,573 @@
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
const bcrypt = require("bcrypt");
const Datastore = require("nedb");
const session = require("express-session");
const NedbSessionStore = require("nedb-session-store")(session);

app.listen(8080, () => {
console.log("Server online on port 8080");
})

app.use(session({
secret: process.env.SECRET || 'ENTER YOUR SECRET KEY IN ENV VARIABLES!',
resave: false,
saveUninitialized: false,
unset: "destroy",
cookie: {
path: '/',
httpOnly: true,
maxAge: 3600000 //cookie time in ms (=1h)
},
store: new NedbSessionStore({
filename: 'db/sessions.db'
})
}))

app.use(express.static("public"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));



/*--------------------------------------------------PAGE REQUESTS--------------------------------------------------*/

app.get("/", (req, res) => {
res.send("index.html");
});

app.get("/info", (req, res) => {
res.sendFile(__dirname + '/public/info-page.html')
});

app.get("/main", (req, res) => {
if(req.session.isLoggedIn && req.session.userRole === "admin"){
res.sendFile(__dirname + '/public/admin-login.html')
}else if(req.session.isLoggedIn && req.session.userRole === "mod") {
res.sendFile(__dirname + '/public/mod-login.html')
}else if(req.session.isLoggedIn && req.session.userRole === "user") {
res.sendFile(__dirname + '/public/user-login.html')
}else {
req.session = null;
res.redirect("/");
}
});

app.get("/newPost", (req, res) => {
if(req.session.isLoggedIn && req.session.userRole === "user"){
res.sendFile(__dirname + '/public/new-Postv2.html')
} else {
req.session = null;
res.redirect("/");
}
});

app.get("/manage-posts", (req, res) => {
if(req.session.isLoggedIn && (req.session.userRole === "mod" || req.session.userRole === "admin")){
res.sendFile(__dirname + '/public/manage-post.html')
} else {
req.session = null;
res.redirect("/");
}
});

app.get("/new-password", (req, res) => {
if(req.session.isLoggedIn){
res.sendFile(__dirname + '/public/change-pw.html')
} else {
req.session = null;
res.redirect("/");
}
});

app.post("/updatePostID", (req, res) => {
if(req.session.isLoggedIn){
req.session.revpost = req.body.postid;
res.json({suc:true});
//res.sendFile(__dirname + '/public/post-review.html')
} else {
res.json({suc:false});
}
});

app.get("/post-review", (req, res) => {
if(req.session.isLoggedIn ){
res.sendFile(__dirname + '/public/post-review.html')
} else {
req.session = null;
res.redirect("/");
}
});

/*--------------------------------------------------GETTER FUNCTIONS--------------------------------------------------*/

app.get("/getmods", (req, res) => {
if(req.session.isLoggedIn && req.session.userRole === "admin"){
const db = new Datastore("db/users.db");
db.loadDatabase();
db.find({role:"mod"}, (err, docs) => {
if(docs.length > 0) {
let resArray = [];
docs.forEach(element => {
resArray.push({
username:element.username,
suspended:element.suspended
})
});
res.json({suc:true, users:resArray})
} else {
res.json({suc:false});
}

})
} else {
res.json({suc:false});
}
});

app.get("/getusers", (req, res) => {
if(req.session.isLoggedIn && req.session.userRole === "mod"){
const db = new Datastore("db/users.db");
db.loadDatabase();
db.find({role:"user" , group: req.session.userid }, (err, docs) => {
if(docs.length > 0) {
let resArray = [];
docs.forEach(element => {
resArray.push({
username:element.username,
suspended:element.suspended
})
});
res.json({suc:true, users:resArray})
} else {
res.json({suc:false});
}

})
} else {
res.json({suc:false});
}
});

app.get("/getReviewPost", (req, res) => {
if(req.session.isLoggedIn){
const db = new Datastore("db/posts.db");
db.loadDatabase();
db.find({_id:req.session.revpost}, (err, docs) => {
if(docs.length === 1) {
let post = [];
post.push({
postid:docs[0]._id,
username:docs[0].creatorName,
showpost:docs[0].showpost,
title:docs[0].title,
text:docs[0].text,
bcolor:docs[0].bcolor,
startdate:docs[0].startDate,
enddate:docs[0].endDate,
})
res.json({suc:true, post:post})
} else {
res.json({suc:false});
}
})
} else {
res.json({suc:false});
}
});

app.get("/getposts", (req, res) => {
if(req.session.isLoggedIn){
const db_post = new Datastore("db/posts.db");
db_post.loadDatabase();
switch(req.session.userRole)
{
case "admin":
db_post.find({}, (err, docs) => {
if(docs.length > 0) {
let resArray = [];
docs.forEach(element => {
resArray.push({
creator: element.creatorName,
postid: element._id,
title:element.title,
text:element.text,
showpost:element.showpost,
startDate:element.startDate,
endDate:element.endDate,
})
});
res.json({suc:true, users:resArray})
} else {
res.json({suc:false});
}
});
break;
case "mod":
db_post.find({creatorGroup:req.session.userid}, (err, docs) => {
if(docs.length > 0) {
let resArray = [];
docs.forEach(element => {
resArray.push({
creator: element.creatorName,
postid: element._id,
title:element.title,
text:element.text,
showpost:element.showpost,
startDate:element.startDate,
endDate:element.endDate,
})
});
res.json({suc:true, users:resArray})
} else {
res.json({suc:false});
}
});
break;
case "user":
db_post.find({creatorId:req.session.userid}, (err, docs) => {
if(docs.length > 0) {
let resArray = [];
docs.forEach(element => {
resArray.push({
title:element.title,
showpost:element.showpost,
postid:element._id
})
});
res.json({suc:true, users:resArray})
} else {
res.json({suc:false});
}});
break;
}
}
});

app.get("/getliveposts", (req, res) => {
const now = new Date();
const db_post = new Datastore("db/posts.db");
db_post.loadDatabase();
const db_users = new Datastore("db/users.db");
db_users.loadDatabase();
db_post.find({}, (err, docs) => {
if(docs.length > 0) {
let resArray = [];
docs.forEach(element => {
if(element.showpost){
var start = new Date(element.startDate) - now;
var end = new Date(element.endDate) - now;
if(start < 0 && end > 0){
db_users.find({_id:element.creatorId}, (err2, docs2) =>{
docs2.forEach(element2 => {
if(!element2.suspended)
{
db_users.find({_id:element.creatorGroup}, (err3, docs3) =>{
docs3.forEach(element3 => {
if(!element3.suspended)
{
resArray.push({
title:element.title,
text:element.text,
bcolor:element.bcolor
})
}
})
})
}
})
})
}
}
});
setTimeout(function(){ res.json({suc:true, posts:resArray}); }, 100); //delay to resolve timing issue
} else {
res.json({suc:false});
}
});
});

/*--------------------------------------------------FUNCTIONS--------------------------------------------------*/

app.post("/login", (req, res) => {
const db = new Datastore("db/users.db");
db.loadDatabase();
const un = req.body.username;
const pw = req.body.password;
if(un && pw){
db.find({username:un}, (err, docs) => {
if(docs.length === 1){
const userRole = docs[0].role;
bcrypt.compare(pw, docs[0].password, (err2, result) => {
if(result){
req.session.userRole = userRole;
req.session.userid = docs[0]._id;
req.session.gr = docs[0].group;
req.session.un = docs[0].username;
req.session.revpost = 0;
req.session.isLoggedIn = true;
if(userRole === "admin") {
res.json({suc:true, redirect:"admin"}) //login to admin page
} else if(userRole === "mod"){
res.json({suc:true, redirect:"mod"}) //login to mod page
} else if(userRole === "user"){
res.json({suc:true, redirect:"user"}) //login to user page
}
} else { res.json({suc:false}); }
})
} else { res.json({suc:false}); }
})
} else { res.json({suc:false}); }
});

app.get("/logout", (req, res) => {
req.session = null;
res.redirect("/");
});

app.post("/changepw", (req, res) => {
const db = new Datastore("db/users.db");
db.loadDatabase();
const old_pw = req.body.old_password;
const new_pw_1 = req.body.new_password_1;
const new_pw_2 = req.body.new_password_2;
if(old_pw && (new_pw_1 === new_pw_2)){
db.find({_id:req.session.userid}, (err, docs) => {
if(docs.length === 1){
bcrypt.compare(old_pw, docs[0].password, (err2, result) => {
if(result){
bcrypt.hash(new_pw_1, 10, (err3, hash) => {
db.update({_id: docs[0]._id}, {$set: {password: hash}}, (err4, num) =>{
res.json({suc:true});
});
})
} else { res.json({suc:false}); }
})
} else { res.json({suc:false}); }
})
} else { res.json({suc:false}); }
})

app.post("/newmod", (req, res) => {
if(req.session.isLoggedIn && req.session.userRole === "admin"){
const nun = req.body.username;
const nemail = req.body.email;
const db = new Datastore("db/users.db");
db.loadDatabase();
db.find({username:nun}, (err, docs) => {
if(docs.length === 0){
db.find({email:nemail}, (err2, docs2) => {
if(docs2.length === 0){
bcrypt.hash(nun, 10, (err3, hash) => {
db.insert({email: nemail,
username: nun,
password: hash,
role: "mod",
suspended: false
}, (err4, doc) => {
res.json({suc:true});
});
});
} else {
res.json({suc:false});
}
});
} else {
res.json({suc:false});
}
});
} else {
res.json({suc:false});
}
})

app.post("/newuser", (req, res) => {
if(req.session.isLoggedIn && req.session.userRole === "mod"){
const nun = req.body.username;
const nemail = req.body.email;
const db = new Datastore("db/users.db");
db.loadDatabase();
db.find({username:nun}, (err, docs) => {
if(docs.length === 0){
db.find({email:nemail}, (err2, docs2) => {
if(docs2.length === 0){
bcrypt.hash(nun, 10, (err3, hash) => {
db.insert({
email: nemail,
username: nun,
password: hash,
role: "user",
group: req.session.userid,
suspended: false
}, (err4, doc) => {
res.json({suc:true});
});
});
} else {
res.json({suc:false});
}
});
} else {
res.json({suc:false});
}
});
} else {
res.json({suc:false});
}
})

app.post("/newpost", (req, res) => {
if(req.session.isLoggedIn && req.session.userRole === "user"){
const db = new Datastore("db/posts.db");
db.loadDatabase();
db.insert({
creatorId:req.session.userid ,
creatorName:req.session.un ,
creatorGroup:req.session.gr ,
showpost:false ,
startDate:req.body.startDate ,
endDate:req.body.endDate ,
title:req.body.title ,
text:req.body.text,
bcolor:req.body.bcolor
}, (err, doc) => {
res.json({suc:true});
});
}
});

app.post("/toggleSus", (req, res) => {
if(req.session.isLoggedIn && (req.session.userRole === "admin" || req.session.userRole === "mod")){
const db = new Datastore("db/users.db");
db.loadDatabase();
db.find({username:req.body.username}, (err, docs) => {
if(docs.length === 1) {
var now = !docs[0].suspended;
db.update({_id: docs[0]._id}, {$set: {suspended: now}}, (err2, num) =>{
res.json({suc:true});
})
} else {
res.json({suc:false});
}

})
} else {
res.json({suc:false});
}
});

app.post("/toggleShow", (req, res) => {
if(req.session.isLoggedIn && (req.session.userRole === "mod" || req.session.userRole === "admin")){
const db = new Datastore("db/posts.db");
db.loadDatabase();
db.find({_id:req.body.postid}, (err, docs) => {
if(docs.length === 1) {
var now = !docs[0].showpost;
db.update({_id: docs[0]._id}, {$set: {showpost: now}}, (err2, num) =>{
res.json({suc:true});
})
} else {
res.json({suc:false});
}
})
} else {
res.json({suc:false});
}
});

app.post("/deleteMod", (req, res) => {
if(req.session.isLoggedIn && req.session.userRole === "admin") {
const db = new Datastore("db/users.db");
db.loadDatabase();
db.find({username:req.body.username}, (err, docs) => {
if(docs.length === 1) {
deleteMod(docs[0]._id);
setTimeout(function(){ res.json({suc:true}); }, 1000); //delay to resolve timing issue
} else {
res.json({suc:false});
}
})
} else {
res.json({suc:false});
}
});

app.post("/deleteUser", (req, res) => {
if(req.session.isLoggedIn && req.session.userRole === "mod"){
const db = new Datastore("db/users.db");
db.loadDatabase();
db.find({username:req.body.username}, (err, docs) => {
if(docs.length === 1) {
deleteUser(docs[0]._id);
setTimeout(function(){ res.json({suc:true}); }, 1000); //delay to resolve timing issue
} else {
res.json({suc:false});
}
})
} else {
res.json({suc:false});
}
});

app.post("/deletePost", (req, res) => {
if(req.session.isLoggedIn){
const db = new Datastore("db/posts.db");
db.loadDatabase();
db.find({_id:req.body.postid}, (err, docs) => {
if(docs.length === 1) {
deletePost(docs[0]._id);
setTimeout(function(){ res.json({suc:true}); }, 1000); //delay to resolve timing issue
} else {
res.json({suc:false});
}
})
} else {
res.json({suc:false});
}
});

/*--------------------------------------------------FUNCTIONS--------------------------------------------------*/

function deleteMod(modID){
const db_users = new Datastore("db/users.db");
db_users.loadDatabase();
db_users.find({group:modID}, (err, docs) => {
docs.forEach(element => {
deleteUser(element._id);
if(docs.indexOf(element) === docs.length-1)
db_users.find({_id:modID}, (err2, docs2) => {
console.log("deleted mod: ", docs2[0]._id);
db_users.remove({_id: docs2[0]._id});
})
});
})
}

function deleteUser(userID){
const db_posts = new Datastore("db/posts.db");
db_posts.loadDatabase();
db_posts.find({creatorId:userID}, (err, docs) => {
docs.forEach(element => {
deletePost(element._id);
});
})
const db_users = new Datastore("db/users.db");
db_users.loadDatabase();
db_users.find({_id:userID}, (err, docs) => {
console.log("deleted user: ", docs[0]._id);
db_users.remove({_id: docs[0]._id})

})
}

function deletePost(postID){
const db_posts = new Datastore("db/posts.db");
db_posts.loadDatabase();
db_posts.find({_id:postID}, (err, docs) => {
console.log("deleted post: ", docs[0]._id);
db_posts.remove({_id: docs[0]._id});
})
}

+ 4
- 0
server.start View File

@@ -0,0 +1,4 @@
#!/bin/bash

cd `dirname $0`
node server.js

Loading…
Cancel
Save