Added API endpoints and dockerfile

This commit is contained in:
Lukian 2025-03-24 10:17:37 +01:00
parent 924e55b4f3
commit 5ddad2ed61
31 changed files with 3885 additions and 942 deletions

3
back/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/node_modules
.env
package-lock.json

72
back/api/channels.js Normal file
View file

@ -0,0 +1,72 @@
const express = require('express');
const jwt = require('jsonwebtoken');
const { getConnection, getUser, getChannels, getChannel, addChannel, getMessages, addMessage } = require('../libs/mysql');
const router = express.Router();
router.get('/', async (req, res) => {
const connection = await getConnection();
const channels = await getChannels(connection);
connection.end();
res.send(channels);
});
router.get('/:id', async (req, res) => {
const id = req.params.id;
const connection = await getConnection();
const channel = await getChannel(connection, id);
connection.end();
if (channel[0]) {
res.send(channel[0]);
} else {
res.send('No channel found');
}
});
router.get('/:id/messages', async (req, res) => {
const id = req.params.id;
const connection = await getConnection();
const channel = await getChannel(connection, id);
if (!channel[0]) {
connection.end();
return res.send('No channel found');
}
const messages = await getMessages(connection, id);
connection.end();
res.send(messages);
});
router.post('/:id/messages/send', async (req, res) => {
const { token, message } = req.body;
const id = req.params.id;
const connection = await getConnection();
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const user = await getUser(connection, decoded.id);
if (!user[0]) {
connection.end();
return res.status(401).send({ error: 'Invalid token' });
}
await addMessage(connection, id, user[0].id, message.replace("\"", "'"));
connection.end();
res.send({ message: 'Message sent' });
});
router.post('/add', async (req, res) => {
const { name, description, token } = req.body;
const connection = await getConnection();
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const user = await getUser(connection, decoded.id);
if (!user[0]) {
connection.end();
return res.status(401).send({ error: 'Invalid token' });
}
await addChannel(connection, name, description);
connection.end();
res.send({ message: 'Channel added' });
});
module.exports = router;

24
back/api/connect.js Normal file
View file

@ -0,0 +1,24 @@
const express = require('express');
const sha256 = require("sha256");
const jwt = require('jsonwebtoken');
const { getConnection, getUserByUsername } = require('../libs/mysql');
const router = express.Router();
router.post('/', async (req, res) => {
const { username, password } = req.body;
const connection = await getConnection();
const users = await getUserByUsername(connection, username);
connection.end();
if (users[0]) {
if (users[0].password === sha256(password)) {
const token = jwt.sign({ id: users[0].id }, process.env.JWT_SECRET, {
expiresIn: 1000 * 60 * 60 * 24 * 7,
});
res.send({ token: token });
}
}
res.status(401).send({ error: 'Invalid username or password' });
});
module.exports = router;

28
back/api/users.js Normal file
View file

@ -0,0 +1,28 @@
const express = require('express');
const sha256 = require("sha256");
const { getConnection, getUser, addUser } = require('../libs/mysql');
const router = express.Router();
router.get('/:id', async (req, res) => {
const id = req.params.id;
const connection = await getConnection();
const users = await getUser(connection, id);
connection.end();
if (users[0]) {
res.send(users[0]);
} else {
res.send('No user found');
}
});
router.post('/add', async (req, res) => {
const { username, password } = req.body;
const connection = await getConnection();
const hash = sha256(password);
await addUser(connection, username, hash);
connection.end();
res.send({ message: 'User added' });
});
module.exports = router;

3
back/config.json Normal file
View file

@ -0,0 +1,3 @@
{
"port": 80
}

39
back/index.js Normal file
View file

@ -0,0 +1,39 @@
const express = require("express");
const fs = require("fs");
const path = require("path");
const config = require("./config");
const cookieParser = require("cookie-parser");
const cors = require("cors");
require("dotenv").config();
const app = express();
const port = config.port || 3000;
app.use(express.json());
app.use(cookieParser());
app.use(cors());
function loadRoutes(folderName) {
const routesPath = path.join(__dirname, folderName);
const files = fs.readdirSync(routesPath);
files.forEach((file) => {
if (fs.lstatSync(path.join(routesPath, file)).isDirectory()) {
loadRoutes(`${folderName}/${file}`);
return;
}
const filePath = path.join(routesPath, file);
const route = require(filePath);
app.use(`/${folderName}/${file.split(".")[0]}`, route);
});
}
loadRoutes("api");
app.use(express.static("public"));
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "public", "index.html"));
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});

134
back/libs/mysql.js Normal file
View file

@ -0,0 +1,134 @@
const mysql = require("mysql");
function getConnection() {
return mysql.createConnection({
host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
});
}
function getUser(connection, id) {
return new Promise((resolve, reject) => {
connection.query(
`SELECT * FROM users WHERE id = ${id}`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
}
);
});
}
function getUserByUsername(connection, username) {
return new Promise((resolve, reject) => {
connection.query(
`SELECT * FROM users WHERE username = '${username}'`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
}
);
});
}
function addUser(connection, username, password) {
return new Promise((resolve, reject) => {
connection.query(
`INSERT INTO users (username, password) VALUES ('${username}', '${password}')`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
}
);
});
}
function getChannels(connection) {
return new Promise((resolve, reject) => {
connection.query(
`SELECT * FROM channels`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
}
);
});
}
function getChannel(connection, id) {
return new Promise((resolve, reject) => {
connection.query(
`SELECT * FROM channels WHERE id = ${id}`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
}
);
});
}
function addChannel(connection, name, description) {
return new Promise((resolve, reject) => {
connection.query(
`INSERT INTO channels (name, description) VALUES ('${name}', '${description}')`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
}
);
});
}
function getMessages(connection, channel_id) {
return new Promise((resolve, reject) => {
connection.query(
`SELECT messages.id, user_id, username, content, date FROM messages JOIN users ON messages.user_id = users.id WHERE channel_id = ${channel_id}`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
}
);
});
}
function addMessage(connection, channel_id, user_id, message) {
return new Promise((resolve, reject) => {
connection.query(
`INSERT INTO messages (channel_id, user_id, content, date) VALUES (${channel_id}, ${user_id}, "${message}", ${Math.floor(Date.now() / 1000)})`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
}
);
});
}
module.exports = {
getConnection,
getUser,
getUserByUsername,
addUser,
getChannels,
getChannel,
addChannel,
getMessages,
addMessage
};

25
back/package.json Normal file
View file

@ -0,0 +1,25 @@
{
"name": "api-template",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "nodemon index.js",
"start": "node index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^1.6.5",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"fs": "^0.0.1-security",
"https": "^1.0.0",
"jsonwebtoken": "^9.0.2",
"mysql": "^2.18.1",
"sha256": "^0.2.0"
}
}