mirror of
https://github.com/Akif9748/akf-forum.git
synced 2024-11-22 20:10:40 +03:00
Compare commits
2 commits
fa222ad68d
...
bd722f1651
Author | SHA1 | Date | |
---|---|---|---|
bd722f1651 | |||
3ac99be051 |
12 changed files with 54 additions and 46 deletions
|
@ -55,10 +55,11 @@ Akf-forum has got an API for AJAX (fetch), other clients etc. And, you can learn
|
||||||
- delete admin???
|
- delete admin???
|
||||||
- change category name
|
- change category name
|
||||||
- _id
|
- _id
|
||||||
- add support for transition aroun gravatar
|
- add support for transition around gravatar
|
||||||
|
- forum setup page++
|
||||||
|
|
||||||
### theme to do:
|
### theme to do:
|
||||||
- theme change
|
- add bootstrap for navbar
|
||||||
- routes/api/routes/users.js check,
|
- routes/api/routes/users.js check,
|
||||||
themes/default/extra/footer.ejs check,
|
themes/default/extra/footer.ejs check,
|
||||||
themes/default/extra/meta.ejs check
|
themes/default/extra/meta.ejs check
|
||||||
|
|
11
index.js
11
index.js
|
@ -9,6 +9,7 @@ const
|
||||||
app = express(),
|
app = express(),
|
||||||
{ mw: IP } = require('request-ip'),
|
{ mw: IP } = require('request-ip'),
|
||||||
{ RL } = require('./lib'),
|
{ RL } = require('./lib'),
|
||||||
|
{ themes } = require("./config.json"),
|
||||||
SES = require('express-session'),
|
SES = require('express-session'),
|
||||||
MS = require("connect-mongo"),
|
MS = require("connect-mongo"),
|
||||||
DB = mongoose.connect(process.env.MONGO_DB_URL)
|
DB = mongoose.connect(process.env.MONGO_DB_URL)
|
||||||
|
@ -33,10 +34,14 @@ app.use(express.static("public"), express.json(), express.urlencoded({ extended:
|
||||||
|
|
||||||
|
|
||||||
res.reply = (page, options = {}, status = 200) => res.status(status).render(page, {
|
res.reply = (page, options = {}, status = 200) => res.status(status).render(page, {
|
||||||
|
dataset: {
|
||||||
|
themes,
|
||||||
|
theme: req.user?.theme || def_theme,
|
||||||
|
forum_name,
|
||||||
|
description
|
||||||
|
},
|
||||||
user: req.user,
|
user: req.user,
|
||||||
theme: req.user?.theme || def_theme,
|
...options
|
||||||
lang: req.user?.theme?.language || def_theme.language,
|
|
||||||
forum_name, description, ...options
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "akf-forum",
|
"name": "akf-forum",
|
||||||
"version": "4.22.0",
|
"version": "4.22.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "akf-forum",
|
"name": "akf-forum",
|
||||||
"version": "4.22.0",
|
"version": "4.22.1",
|
||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcrypt": "^5.1.0",
|
"bcrypt": "^5.1.0",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "akf-forum",
|
"name": "akf-forum",
|
||||||
"version": "4.22.0",
|
"version": "4.22.1",
|
||||||
"description": "A Node.js based forum software",
|
"description": "A Node.js based forum software",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const { UserModel, BanModel } = require("../../../models");
|
const { UserModel, BanModel } = require("../../../models");
|
||||||
const { Router } = require("express");
|
const { Router } = require("express");
|
||||||
const multer = require("multer");
|
const multer = require("multer");
|
||||||
|
const { themes } = require("../../../config.json")
|
||||||
const app = Router();
|
const app = Router();
|
||||||
|
|
||||||
app.param("id", async (req, res, next, id) => {
|
app.param("id", async (req, res, next, id) => {
|
||||||
|
@ -37,7 +37,7 @@ app.patch("/:id", async (req, res) => {
|
||||||
if (req.user.id !== member.id && !user.admin) return res.error(403, "You have not got permission for this.");
|
if (req.user.id !== member.id && !user.admin) return res.error(403, "You have not got permission for this.");
|
||||||
if (!Object.keys(req.body).some(Boolean)) return res.error(400, "Missing member informations in request body.");
|
if (!Object.keys(req.body).some(Boolean)) return res.error(400, "Missing member informations in request body.");
|
||||||
|
|
||||||
const { name, about, admin, deleted, hideLastSeen } = req.body;
|
const { name, about, admin, deleted, hideLastSeen, theme } = req.body;
|
||||||
|
|
||||||
if ((admin?.length || "deleted" in req.body) && !req.user.admin) return res.error(403, "You have not got permission for edit 'admin' and 'deleted' information, or bad request.");
|
if ((admin?.length || "deleted" in req.body) && !req.user.admin) return res.error(403, "You have not got permission for edit 'admin' and 'deleted' information, or bad request.");
|
||||||
const { names, desp } = req.app.get("limits");
|
const { names, desp } = req.app.get("limits");
|
||||||
|
@ -51,7 +51,8 @@ app.patch("/:id", async (req, res) => {
|
||||||
if (about.length > desp) return res.error(400, `About must be under ${desp} characters`);
|
if (about.length > desp) return res.error(400, `About must be under ${desp} characters`);
|
||||||
member.about = about;
|
member.about = about;
|
||||||
}
|
}
|
||||||
// if (theme || themes.includes(theme)) member.theme = theme;
|
if (theme || themes.some(t => t.name === theme.name).includes(theme))
|
||||||
|
member.theme = theme;
|
||||||
|
|
||||||
if (typeof admin === "boolean" || ["false", "true"].includes(admin)) member.admin = admin;
|
if (typeof admin === "boolean" || ["false", "true"].includes(admin)) member.admin = admin;
|
||||||
if (deleted === false) member.deleted = false;
|
if (deleted === false) member.deleted = false;
|
||||||
|
@ -78,7 +79,6 @@ app.post("/:id/ban", async (req, res) => {
|
||||||
res.complate(member);
|
res.complate(member);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const storage = multer.diskStorage({
|
const storage = multer.diskStorage({
|
||||||
destination: function (_req, _file, cb) {
|
destination: function (_req, _file, cb) {
|
||||||
cb(null, './public/images/avatars')
|
cb(null, './public/images/avatars')
|
||||||
|
@ -90,7 +90,7 @@ const storage = multer.diskStorage({
|
||||||
|
|
||||||
const upload = multer({ storage })
|
const upload = multer({ storage })
|
||||||
|
|
||||||
app.put("/:id/", upload.single('avatar'), async (req, res) => {
|
app.post("/:id/avatar", upload.single('avatar'), async (req, res) => {
|
||||||
const { member } = req;
|
const { member } = req;
|
||||||
|
|
||||||
if (req.user.id !== member.id && !req.user.admin) return res.error(403, "You have not got permission for this.");
|
if (req.user.id !== member.id && !req.user.admin) return res.error(403, "You have not got permission for this.");
|
||||||
|
|
|
@ -10,31 +10,32 @@ app.post("/", RL(24 * 60 * 60_000, 5), async (req, res) => {
|
||||||
|
|
||||||
req.session.userID = null;
|
req.session.userID = null;
|
||||||
|
|
||||||
let { name, password, about } = req.body;
|
let { name, password, about, email } = req.body;
|
||||||
|
|
||||||
if (!name || !password) return res.error(400, "You forgot entering some values");
|
if (!name || !password || !email) return res.error(400, "You forgot entering some values");
|
||||||
|
if (!email || !emailRegEx.test(email)) return res.error(400, "E-mail is not valid");
|
||||||
const { names } = req.app.get("limits");
|
const { names } = req.app.get("limits");
|
||||||
if (name.length < 3 || name.length > names) return res.error(400, "Name must be between 3 - 25 characters");
|
if (name.length < 3 || name.length > names) return res.error(400, "Name must be between 3 - 25 characters");
|
||||||
if (password.length < 3 || password.length > names) return res.error(400, "Password must be between 3 - 25 characters");
|
if (password.length < 3 || password.length > names) return res.error(400, "Password must be between 3 - 25 characters");
|
||||||
|
|
||||||
if (await UserModel.exists({ name })) return res.error(400, `We have got an user named ${name}!`)
|
if (await UserModel.exists({ name })) return res.error(400, `We have got an user named ${name}!`)
|
||||||
const user = new UserModel({ name });
|
if (await UserModel.exists({ email })) return res.error(400, "E-mail is already in use");
|
||||||
|
|
||||||
|
|
||||||
user.avatar = getGravatar(name, 128);
|
const user = new UserModel({ name, email });
|
||||||
|
user.avatar = getGravatar(email, 128);
|
||||||
|
|
||||||
if (about) {
|
if (about) {
|
||||||
if (about.length > 256) return res.error(400, "about must be under 256 characters");
|
if (about.length > 256) return res.error(400, "about must be under 256 characters");
|
||||||
user.about = about;
|
user.about = about;
|
||||||
}
|
}
|
||||||
|
|
||||||
await user.takeId()
|
await user.takeId();
|
||||||
|
|
||||||
if (user.id === "0")
|
if (user.id === "0")
|
||||||
user.admin = true;
|
user.admin = true;
|
||||||
else if (email_auth) {
|
else if (email_auth) {
|
||||||
const email = req.body.email;
|
|
||||||
if (!email || !emailRegEx.test(email)) return res.error(400, "E-mail is not valid");
|
|
||||||
if (await UserModel.exists({ email })) return res.error(400, "E-mail is already in use");
|
|
||||||
user.email = email;
|
|
||||||
user.email_code = await bcrypt.hash(`${Date.now()}-${Math.floor(Math.random() * 1e20)}`, 10)
|
user.email_code = await bcrypt.hash(`${Date.now()}-${Math.floor(Math.random() * 1e20)}`, 10)
|
||||||
|
|
||||||
transporter.sendMail({
|
transporter.sendMail({
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
form.addEventListener('submit', async e => {
|
form.addEventListener('submit', async e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const res = await fetch('/api/users/<%= member.id %>/', {
|
const res = await fetch('/api/users/<%= member.id %>/avatar', {
|
||||||
method: 'PUT',
|
method: 'POST',
|
||||||
body: new FormData(form)
|
body: new FormData(form)
|
||||||
})
|
})
|
||||||
if (res.error) return alert(res.error);
|
if (res.error) return alert(res.error);
|
||||||
|
|
|
@ -1,29 +1,33 @@
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<% if (user){ %>
|
<% if (user){ %>
|
||||||
<a onclick="invert()" class="btn-primary" style="color:white;"><%=(user.theme.color === "default" ? "black" : "default" ) + " theme!" %></a>
|
<select id="theme_select">
|
||||||
|
<% for(const theme of dataset.themes){%>
|
||||||
|
<option value="<%= theme %>"><%= theme %> theme</option>
|
||||||
|
<% } %>
|
||||||
|
</select>
|
||||||
<script>
|
<script>
|
||||||
async function invert() {
|
const theme_select = document.getElementById("theme_select");
|
||||||
return alert("disabled!")
|
theme_select.querySelector(`option[value=<%= user.theme.name %>]`).selected = true;
|
||||||
|
theme_select.addEventListener("change", async e => {
|
||||||
|
const name = e.target.value;
|
||||||
await fetch('/api/users/<%= user.id %>', {
|
await fetch('/api/users/<%= user.id %>', {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
theme: {color:"<%= user.theme.color === `default` ? `black` : `default` %>"}
|
theme: {
|
||||||
|
name
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
location.reload()
|
location.reload();
|
||||||
}
|
});
|
||||||
</script>
|
</script>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<a href="https://github.com/Akif9748/akf-forum" style="color: white;"> This website is powered by
|
<a href="https://github.com/Akif9748/akf-forum" style="color: white;"> This website is powered by
|
||||||
<span style="color: #ffbf00;">akf-forum</span> </a>
|
<span style="color: #ffbf00;">akf-forum</span>
|
||||||
<div>
|
</a>
|
||||||
<span style="color:white">Coders</span> <br>
|
|
||||||
<div style="text-align:center;">
|
|
||||||
<a href="https://github.com/Akif9748/" style="color: #ffbf00;">Akif</a><br><a href="#" style="color:#ffbf00;">Tokmak</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
|
@ -1,9 +1,9 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title><%= title || forum_name +"-forum" %></title>
|
<title><%= title || dataset.forum_name +"-forum" %></title>
|
||||||
<meta name="description" content="<%= description %>">
|
<meta name="description" content="<%= dataset.description %>">
|
||||||
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||||
<link rel="stylesheet" href="/css/themes/<%= theme.name %>.css" />
|
<link rel="stylesheet" href="/css/themes/<%= dataset.theme.name %>.css" />
|
||||||
<link rel="stylesheet" href="/css/common.css" />
|
<link rel="stylesheet" href="/css/common.css" />
|
||||||
</head>
|
</head>
|
|
@ -1,13 +1,12 @@
|
||||||
|
|
||||||
<% if (user?.admin){ %>
|
<% if (user?.admin){ %>
|
||||||
<div class="admin-bar">
|
<div class="admin-bar">
|
||||||
<a href="/admin" class="admin-bar">You are admin, and you can go your page!</a>
|
<a href="/admin" class="admin-bar">Click here to reach admin panel</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<a class="logo" href="/"><%= forum_name.toUpperCase() %> <span>FORUM</span></a>
|
<a class="logo" href="/"><%= dataset.forum_name.toUpperCase() %> <span>FORUM</span></a>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
|
|
||||||
<% if (user){ %>
|
<% if (user){ %>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<%- include("extra/meta", {title: "Welcome to the "+forum_name+"-forum!" }) %>
|
<%- include("extra/meta", {title: "Welcome to the "+dataset.forum_name+"-forum!" }) %>
|
||||||
|
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -15,9 +15,7 @@
|
||||||
|
|
||||||
|
|
||||||
<form action="/register" method="post">
|
<form action="/register" method="post">
|
||||||
<% if (mail) { %>
|
|
||||||
<input type="email" name="email" placeholder="Email" class="input" required>
|
<input type="email" name="email" placeholder="Email" class="input" required>
|
||||||
<% } %>
|
|
||||||
<input type="text" name="name" placeholder="Username" class="input" required>
|
<input type="text" name="name" placeholder="Username" class="input" required>
|
||||||
<input type="password" name="password" placeholder="Password" class="input" required>
|
<input type="password" name="password" placeholder="Password" class="input" required>
|
||||||
<textarea class="input" name="about" rows="4" placeholder="About you... You can use markdown"></textarea>
|
<textarea class="input" name="about" rows="4" placeholder="About you... You can use markdown"></textarea>
|
||||||
|
|
Loading…
Reference in a new issue