Added state for users.

This commit is contained in:
Akif9748 2022-10-09 21:23:31 +03:00
parent a471f19f04
commit 410859fbe3
9 changed files with 43 additions and 29 deletions

View File

@ -20,7 +20,7 @@ Create a redirect url in discord developer portal:
### EMAIL AUTH:
You can configure it. Just edit `config.json` and `.env` files.
`"email_auth": true` in config.json.
`"email_auth": true, "default_user_state": "APPROVAL"` in config.json.
Add your email credentials to `.env` as `EMAIL_USER` and `EMAIL_PASS`.
Add your email domain to `.env` as `EMAIL_SERVICE`.
@ -60,9 +60,7 @@ Akf-forum has got an API for AJAX (fetch), other clients etc. And, you can learn
- user.state for ban, delete, etc.
- Add a feature list to README.md
- delete admin???
- MODALS'S CSS & JS
- change category name
- click to user message count to view message W/search
## Major Version History
- V4: Caching

View File

@ -16,5 +16,6 @@
"discord_auth": "",
"defaultThreadState": "OPEN",
"email_auth": false,
"default_user_state": "ACTIVE",
"host": "https://akf-forum.glitch.me"
}

View File

@ -35,12 +35,13 @@ app.use(express.static("public"), express.json(), express.urlencoded({ extended:
res.error = (type, error) => res.reply("error", { type, error }, type);
if (req.user && !req.user.approved&& !req.user.admin && !req.url.startsWith("/auth/email")) return res.error(403, "Your account is not approved yet.");
if (req.user?.deleted) {
req.session.destroy();
return res.error(403, "Your account has been deleted.");
}
if (req.user && req.user.state == "APPROVAL" && !req.user.admin && !req.url.startsWith("/auth/email")) return res.error(403, "Your account is not approved yet.");
next();
}
);

1
lib.js
View File

@ -4,6 +4,7 @@ const config = require("./config.json");
require("dotenv").config();
module.exports = {
threadEnum: ["OPEN", "APPROVAL", "DELETED"],
userEnum: ["ACTIVE", "APPROVAL", "DELETED", "BANNED"],
themes: ["default", "black"],
RL(windowMs = 60_000, max = 1) {
return RL({

View File

@ -22,7 +22,7 @@ const schema = new mongoose.Schema({
time: { type: Date, default: Date.now },
edited: { type: Boolean, default: false },
state: { type: String, default: defaultThreadState, enum: threadEnum },
state: { type: String, default: defaultThreadState, enum: threadEnum, uppercase: true },
messages: [String],
views: { type: Number, default: 0 }
});

View File

@ -1,12 +1,13 @@
const mongoose = require("mongoose")
const { def_theme, limits, email_auth } = require("../config.json");
const { def_theme, limits, email_auth, default_user_state } = require("../config.json");
const { userEnum } = require("../lib");
const schema = new mongoose.Schema({
id: { type: String, unique: true },
discordID: { type: String },
name: { type: String, maxlength: limits.names },
avatar: { type: String, default: "/images/avatars/default.jpg" },
time: { type: Date, default: Date.now },
deleted: { type: Boolean, default: false },
edited: { type: Boolean, default: false },
about: { type: String, default: "", maxlength: limits.desp },
admin: { type: Boolean, default: false },
@ -16,11 +17,20 @@ const schema = new mongoose.Schema({
ips: { type: [String], default: [], select: false },
password: { type: String, select: false },
discord_code: { type: String, select: false },
approved: { type: Boolean, default: !email_auth },
state: { type: String, default: default_user_state, enum: userEnum, uppercase: true },
email: { type: String, select: false },
email_code: { type: String, select: false },
});
schema.virtual("deleted").get(function () {
return this.state === "DELETED";
}).set(function (value) {
this.set({ state: value ? "DELETED" : "ACTIVE" });
});
schema.virtual("active").get(function () {
return this.state === "ACTIVE";
})
schema.methods.takeId = async function () {
this.id = String(await model.count() || 0);
return this;
@ -32,6 +42,6 @@ schema.methods.getLink = function (id = this.id) {
const model = mongoose.model('user', schema);
model.get = (id, select) => model.findOne({ id }).select(select);
model.get = (id, select = "") => model.findOne({ id }, select);
module.exports = model;

View File

@ -20,7 +20,7 @@ app.use(async (req, res, next) => {
const user = await UserModel.findOne({ name });
if (!user || user.deleted) return res.error(401, `We don't have any user with name ${name}.`)
if (!user.approved) return res.error(401, "Your account is not approved yet.");
if (!user.active) return res.error(401, "Your account is not approved yet.");
if (!await bcrypt.compare(password, user.password)) return res.error(401, 'Incorrect Password!');

View File

@ -90,7 +90,7 @@ app.get("/email", async (req, res) => {
const { code } = req.query;
if (!code) return res.error(400, "No code provided");
if (code !== req.user.email_code) return res.error(403, "Invalid code");
req.user.approved = true;
req.user.state = "ACTIVE";
await req.user.save();
res.send("Your email has been linked to your forum account.");
});

View File

@ -16,7 +16,7 @@
<% if (!member.discordID && discord && user?.id === member.id) { %>
<a href="<%=discord%>" class="btn-outline-primary">Auth with discord</a>
<% } else if(member.discordID && user?.id === member.id) { %>
<a class="btn-outline-primary" id="un_discord">Unauth with discord!</a>
<a class="btn-outline-primary" id="un_discord">Unauth with discord!</a>
<% } %>
<% if (user?.admin || user?.id === member.id) { %>
<a href="/users/<%=member.id%>/avatar" class="btn-outline-primary">Upload avatar</a>
@ -32,7 +32,7 @@
<h1 class="title" style="text-align:center;">Edit <a class="see" href="/users/<%= member.id %>"><%= member.name %></a></h1>
<div class="content">
<form id="form" class="see" style="box-shadow:none">
<input type="text" name="name" placeholder="<%=member.name%>" class="input" >
<input type="text" name="name" placeholder="<%=member.name%>" class="input">
<textarea class="input" name="about" rows="4" cols="60" name="content" placeholder="<%=member.about%>"></textarea>
<% if (user?.admin){ %>
@ -56,20 +56,23 @@
document.addEventListener("click", async e => {
if (e.target.id == "delete") {
const response = await request("/api/users/<%= member.id %>", "DELETE");
if (!response.deleted) return
if (response.state !== "DELETED") return
alert("User is deleted!");
location.reload()
} else if (e.target.id == "undelete") {
const response = await request("/api/users/<%= member.id %>/", "PATCH", { deleted: false });
if (response.deleted) return;
const response = await request("/api/users/<%= member.id %>/", "PATCH", {
deleted: false
});
if (response.state == "DELETED") return;
alert("User is undeleted successfully!");
location.reload()
} else if (e.target.id == "un_discord") {
const response = await fetch("/auth/discord/", {method:"DELETE"});
const response = await fetch("/auth/discord/", {
method: "DELETE"
});
alert(await response.text());
location.reload()
}
else if (e.target.id == "toogle")
} else if (e.target.id == "toogle")
document.getElementById('user-edit').classList.toggle('no-active')
});
@ -94,15 +97,15 @@
<a id="delete" class="btn-outline-primary">Delete user! </a>
<% } %>
<% if (user?.admin) {%>
<details>
<summary class="btn-outline-primary">IP adresses of user:</summary>
<select>
<% for(const ip of member.ips) { %>
<option><%= ip %></option>
<% } %>
</select>
</details>
<details>
<summary class="btn-outline-primary">IP adresses of user:</summary>
<select>
<% for(const ip of member.ips) { %>
<option><%= ip %></option>
<% } %>
</select>
</details>
<% } %>
<div class="box" style="justify-content:center;">