better folder system
|
@ -6,14 +6,14 @@ A Node.js based forum software.
|
||||||
- Run `npm i` to install **dependencies**.
|
- Run `npm i` to install **dependencies**.
|
||||||
- Enter your database credentials in `.env`.
|
- Enter your database credentials in `.env`.
|
||||||
- Run `npm start` for run it.
|
- Run `npm start` for run it.
|
||||||
- Go /setup page for setup your forum.
|
- Go `/setup` page for setup your forum.
|
||||||
|
|
||||||
### Extra (If you are not use `setup` page)
|
### Extra (If you are not use `setup` page)
|
||||||
Run `node util/reset` to **reset the database** for duplicate key errors, and run `node util/admin` for give admin perms to first member.
|
Run `node util/reset` to **reset the database** for duplicate key errors, and run `node util/admin` for give admin perms to first member.
|
||||||
Edit `config.json` for default theme color (`black` or `white`) of users, and forum name, meta description, character limits, discord auth enabler, global ratelimit.
|
Edit `config.json` for default theme for users, forum name, meta description, character limits, discord auth enabler, global ratelimit etc.
|
||||||
|
|
||||||
### How to install theme:
|
### How to install theme:
|
||||||
- Copy your theme to `themes` folder.
|
- Copy your theme to `src/themes` folder.
|
||||||
Additional note for themes: If a theme has not got any .ejs file, it will use default theme's .ejs files. default theme is in themes folder, named as `common`.
|
Additional note for themes: If a theme has not got any .ejs file, it will use default theme's .ejs files. default theme is in themes folder, named as `common`.
|
||||||
|
|
||||||
### DISCORD AUTH:
|
### DISCORD AUTH:
|
||||||
|
@ -62,7 +62,8 @@ Akf-forum has got an API for AJAX (fetch), other clients etc. And, you can learn
|
||||||
- add support for transition around gravatar
|
- add support for transition around gravatar
|
||||||
- BETTER SETUP PAGE
|
- BETTER SETUP PAGE
|
||||||
- add used open source libraries to README.md
|
- add used open source libraries to README.md
|
||||||
- better folder system
|
- send public to common/public
|
||||||
|
- new screenshoots
|
||||||
### front-end
|
### front-end
|
||||||
- text alling center body
|
- text alling center body
|
||||||
- add a css file for CodeMirror in threads / send message ok
|
- add a css file for CodeMirror in threads / send message ok
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "akf-forum",
|
"name": "akf-forum",
|
||||||
"version": "5.2.2",
|
"version": "5.2.2",
|
||||||
"description": "A Node.js based forum software",
|
"description": "A Node.js based forum software",
|
||||||
"main": "index.js",
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node .",
|
"start": "node .",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
require("dotenv").config();
|
require("dotenv").config();
|
||||||
const
|
const
|
||||||
{ def_theme, forum_name, description, limits, global_ratelimit: RLS, discord_auth, host } = require("./config.json"),
|
{ def_theme, forum_name, description, limits, global_ratelimit: RLS, discord_auth, host } = require("../config.json"),
|
||||||
{ UserModel, BanModel } = require("./models"),
|
{ UserModel, BanModel } = require("./models"),
|
||||||
port = process.env.PORT || 3000,
|
port = process.env.PORT || 3000,
|
||||||
mongoose = require("mongoose"),
|
mongoose = require("mongoose"),
|
||||||
|
@ -25,11 +25,11 @@ app.set("limits", limits);
|
||||||
|
|
||||||
if (RLS.enabled) app.use(RL(RLS.windowMs, RLS.max));
|
if (RLS.enabled) app.use(RL(RLS.windowMs, RLS.max));
|
||||||
|
|
||||||
for (const theme of fs.readdirSync("./themes"))
|
for (const theme of fs.readdirSync(join(__dirname, "themes")))
|
||||||
app.use(`/themes/${theme}`, express.static(`./themes/${theme}/public/`));
|
app.use(`/themes/${theme}`, express.static(join(__dirname, "themes", theme, "public")));
|
||||||
|
|
||||||
|
|
||||||
app.use(express.static("public"), express.json(), express.urlencoded({ extended: true }), IP(),
|
app.use(express.static(join(__dirname, "public")), express.json(), express.urlencoded({ extended: true }), IP(),
|
||||||
SES({ secret: process.env.SECRET, store: MS.create({ clientPromise: DB, stringify: false }), resave: false, saveUninitialized: false }),
|
SES({ secret: process.env.SECRET, store: MS.create({ clientPromise: DB, stringify: false }), resave: false, saveUninitialized: false }),
|
||||||
async (req, res, next) => {
|
async (req, res, next) => {
|
||||||
if (app.ips.includes(req.clientIp)) return res.status(403).send("You are banned from this forum.");
|
if (app.ips.includes(req.clientIp)) return res.status(403).send("You are banned from this forum.");
|
||||||
|
@ -73,7 +73,7 @@ app.use(express.static("public"), express.json(), express.urlencoded({ extended:
|
||||||
if (discord_auth)
|
if (discord_auth)
|
||||||
app.set("discord_auth", `https://discord.com/api/oauth2/authorize?client_id=${discord_auth}&redirect_uri=${host}%2Fauth%2Fdiscord&response_type=code&scope=identify`);
|
app.set("discord_auth", `https://discord.com/api/oauth2/authorize?client_id=${discord_auth}&redirect_uri=${host}%2Fauth%2Fdiscord&response_type=code&scope=identify`);
|
||||||
|
|
||||||
for (const file of fs.readdirSync("./routes"))
|
for (const file of fs.readdirSync(join(__dirname, "routes")))
|
||||||
app.use("/" + file.replace(".js", ""), require(`./routes/${file}`));
|
app.use("/" + file.replace(".js", ""), require(`./routes/${file}`));
|
||||||
|
|
||||||
app.all("*", (req, res) => res.error(404, "This page does not exist on this forum."));
|
app.all("*", (req, res) => res.error(404, "This page does not exist on this forum."));
|
|
@ -1,12 +1,12 @@
|
||||||
const RL = require('express-rate-limit');
|
const RL = require('express-rate-limit');
|
||||||
const nodemailer = require("nodemailer");
|
const nodemailer = require("nodemailer");
|
||||||
const config = require("./config.json");
|
const config = require("../config.json");
|
||||||
const crypto = require("crypto");
|
const crypto = require("crypto");
|
||||||
const { readdirSync } = require('fs');
|
const { readdirSync } = require('fs');
|
||||||
|
const { join } = require('path');
|
||||||
require("dotenv").config();
|
require("dotenv").config();
|
||||||
module.exports = {
|
module.exports = {
|
||||||
themes: readdirSync("./themes").filter(f => f !== "common").map(f => require(`./themes/${f}`)),
|
themes: readdirSync(join(__dirname, "themes")).filter(f => f !== "common").map(f => require(`./themes/${f}`)),
|
||||||
threadEnum: ["OPEN", "APPROVAL", "DELETED"],
|
threadEnum: ["OPEN", "APPROVAL", "DELETED"],
|
||||||
userEnum: ["ACTIVE", "APPROVAL", "DELETED", "BANNED"],
|
userEnum: ["ACTIVE", "APPROVAL", "DELETED", "BANNED"],
|
||||||
RL(windowMs = 60_000, max = 1) {
|
RL(windowMs = 60_000, max = 1) {
|
|
@ -1,6 +1,6 @@
|
||||||
const mongoose = require("mongoose");
|
const mongoose = require("mongoose");
|
||||||
const cache = require("./cache");
|
const cache = require("./cache");
|
||||||
const { limits } = require("../config.json");
|
const { limits } = require("../../config.json");
|
||||||
|
|
||||||
const schema = new mongoose.Schema({
|
const schema = new mongoose.Schema({
|
||||||
id: { type: String, unique: true },
|
id: { type: String, unique: true },
|
|
@ -1,7 +1,7 @@
|
||||||
const mongoose = require("mongoose");
|
const mongoose = require("mongoose");
|
||||||
const cache = require("./cache")
|
const cache = require("./cache")
|
||||||
const MessageModel = require("./Message");
|
const MessageModel = require("./Message");
|
||||||
const { limits, default_thread_state } = require("../config.json");
|
const { limits, default_thread_state } = require("../../config.json");
|
||||||
const { threadEnum } = require("../lib");
|
const { threadEnum } = require("../lib");
|
||||||
const schema = new mongoose.Schema({
|
const schema = new mongoose.Schema({
|
||||||
id: { type: String, unique: true },
|
id: { type: String, unique: true },
|
|
@ -1,5 +1,5 @@
|
||||||
const mongoose = require("mongoose")
|
const mongoose = require("mongoose")
|
||||||
const { def_theme, limits, default_user_state } = require("../config.json");
|
const { def_theme, limits, default_user_state } = require("../../config.json");
|
||||||
const { userEnum } = require("../lib");
|
const { userEnum } = require("../lib");
|
||||||
|
|
||||||
const schema = new mongoose.Schema({
|
const schema = new mongoose.Schema({
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
BIN
src/public/images/avatars/0.jpg
Normal file
After Width: | Height: | Size: 704 KiB |
BIN
src/public/images/avatars/1.jpg
Normal file
After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
@ -3,7 +3,7 @@ const app = Router();
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const bcrypt = require("bcrypt");
|
const bcrypt = require("bcrypt");
|
||||||
const { UserModel } = require("../../models");
|
const { UserModel } = require("../../models");
|
||||||
|
const{join}=require("path");
|
||||||
|
|
||||||
app.use(async (req, res, next) => {
|
app.use(async (req, res, next) => {
|
||||||
res.error = (status, error) => res.status(status).json({ error });
|
res.error = (status, error) => res.status(status).json({ error });
|
||||||
|
@ -31,7 +31,7 @@ app.use(async (req, res, next) => {
|
||||||
|
|
||||||
app.get("/me", (req, res) => res.complate(req.user))
|
app.get("/me", (req, res) => res.complate(req.user))
|
||||||
|
|
||||||
for (const file of fs.readdirSync("./routes/api/routes"))
|
for (const file of fs.readdirSync(join(__dirname, "routes")))
|
||||||
app.use("/" + file.replace(".js", ""), require(`./routes/${file}`));
|
app.use("/" + file.replace(".js", ""), require(`./routes/${file}`));
|
||||||
|
|
||||||
app.all("*", (req, res) => res.error(400, "Bad request"));
|
app.all("*", (req, res) => res.error(400, "Bad request"));
|
|
@ -16,10 +16,10 @@ app.get("/", (req, res) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
app.put("/", (req, res) => {
|
app.put("/", (req, res) => {
|
||||||
const write= req.query.text ? req.body : JSON.stringify(req.body, null, 4)
|
const write = req.query.text ? req.body : JSON.stringify(req.body, null, 4)
|
||||||
fs.writeFileSync("./config.json",write );
|
fs.writeFileSync("./config.json", write);
|
||||||
require.cache[require.resolve("../../../config.json")] = require("../../../config.json");
|
require.cache[require.resolve("../../../../config.json")] = require("../../../../config.json");
|
||||||
res.complate(require("../../../config.json"));
|
res.complate(require("../../../../config.json"));
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = app;
|
module.exports = app;
|
|
@ -3,7 +3,7 @@ const { Router } = require("express");
|
||||||
const multer = require("multer");
|
const multer = require("multer");
|
||||||
const { themes } = require("../../../lib")
|
const { themes } = require("../../../lib")
|
||||||
const app = Router();
|
const app = Router();
|
||||||
|
const { join } = require("path");
|
||||||
app.param("id", async (req, res, next, id) => {
|
app.param("id", async (req, res, next, id) => {
|
||||||
req.member = await UserModel.get(id, req.user.admin ? "+lastSeen +ips" : "");
|
req.member = await UserModel.get(id, req.user.admin ? "+lastSeen +ips" : "");
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ app.post("/:id/ban", async (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const storage = multer.diskStorage({
|
const storage = multer.diskStorage({
|
||||||
destination:'./public/images/avatars',
|
destination: join(__dirname, "..", "..", "..", "public", "images", "avatars"),
|
||||||
filename: function (req, _file, cb) {
|
filename: function (req, _file, cb) {
|
||||||
cb(null, req.member.id + ".jpg")
|
cb(null, req.member.id + ".jpg")
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@ const { Router } = require("express")
|
||||||
const { UserModel } = require("../models");
|
const { UserModel } = require("../models");
|
||||||
const fetch = require("node-fetch");
|
const fetch = require("node-fetch");
|
||||||
const app = Router();
|
const app = Router();
|
||||||
const { host, discord_auth, email_auth } = require("../config.json")
|
const { host, discord_auth, email_auth } = require("../../config.json")
|
||||||
|
|
||||||
app.get("/discord", async (req, res) => {
|
app.get("/discord", async (req, res) => {
|
||||||
const client_id = discord_auth;
|
const client_id = discord_auth;
|
|
@ -3,7 +3,7 @@ const { Router } = require("express")
|
||||||
const bcrypt = require("bcrypt");
|
const bcrypt = require("bcrypt");
|
||||||
const { RL, transporter, emailRegEx, getGravatar } = require('../lib');
|
const { RL, transporter, emailRegEx, getGravatar } = require('../lib');
|
||||||
const app = Router();
|
const app = Router();
|
||||||
const { email_auth, forum_name, host } = require("../config.json");
|
const { email_auth, forum_name, host } = require("../../config.json");
|
||||||
app.get("/", (req, res) => res.reply("register", { user: null, discord: req.app.get("discord_auth"), mail: email_auth }));
|
app.get("/", (req, res) => res.reply("register", { user: null, discord: req.app.get("discord_auth"), mail: email_auth }));
|
||||||
|
|
||||||
app.post("/", RL(24 * 60 * 60_000, 5), async (req, res) => {
|
app.post("/", RL(24 * 60 * 60_000, 5), async (req, res) => {
|
|
@ -27,7 +27,7 @@ app.post("/", async (req, res) => {
|
||||||
original[key] = content[key];
|
original[key] = content[key];
|
||||||
|
|
||||||
fs.writeFileSync("./config.json", JSON.stringify(original, null, 4));
|
fs.writeFileSync("./config.json", JSON.stringify(original, null, 4));
|
||||||
require.cache[require.resolve("../config.json")] = require("../config.json");
|
require.cache[require.resolve("../../config.json")] = require("../../config.json");
|
||||||
res.redirect("/register");
|
res.redirect("/register");
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,7 +3,7 @@ require("dotenv").config();
|
||||||
|
|
||||||
mongoose.connect(process.env.MONGO_DB_URL, () => console.log("Database is connected"));
|
mongoose.connect(process.env.MONGO_DB_URL, () => console.log("Database is connected"));
|
||||||
|
|
||||||
const { UserModel } = require("../models");
|
const { UserModel } = require("../src/models");
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|
||||||
const member = await UserModel.get("0");
|
const member = await UserModel.get("0");
|
||||||
|
|
|
@ -3,6 +3,6 @@ require("dotenv").config();
|
||||||
|
|
||||||
mongoose.connect(process.env.MONGO_DB_URL, () => console.log("Database is connected"));
|
mongoose.connect(process.env.MONGO_DB_URL, () => console.log("Database is connected"));
|
||||||
|
|
||||||
const Models = require("../models");
|
const Models = require("../src/models");
|
||||||
|
|
||||||
Object.values(Models).forEach(model => model.collection.drop().then(console.log));
|
Object.values(Models).forEach(model => model.collection.drop().then(console.log));
|
||||||
|
|