Fixed mod deletion and implemented database transactions support in backend

This commit is contained in:
Gu://em_ 2025-05-17 13:33:40 +02:00
parent 5af16b593c
commit 58268a94a9
7 changed files with 49 additions and 22 deletions

View file

@ -29,7 +29,7 @@ async function createMod(req, res) {
async function modifyMod(req, res) { async function modifyMod(req, res) {
try { try {
// Authorize // Authorize
authorizeModModification(req); await authorizeModModification(req);
// Query // Query
const mod_data = req.body; const mod_data = req.body;
const query_result = await mod_service.modifyMod(mod_data); const query_result = await mod_service.modifyMod(mod_data);

View file

@ -53,7 +53,7 @@ async function initDatabase() {
author TINYTEXT NOT NULL, author TINYTEXT NOT NULL,
description TINYTEXT NOT NULL, description TINYTEXT NOT NULL,
FOREIGN KEY (author) REFERENCES Users(username) FOREIGN KEY (author) REFERENCES Users(username) ON DELETE CASCADE
);`); );`);
// Mods complementary infos // Mods complementary infos
@ -66,7 +66,7 @@ async function initDatabase() {
creation_date TINYTEXT NOT NULL, creation_date TINYTEXT NOT NULL,
downloads_count INT NOT NULL, downloads_count INT NOT NULL,
FOREIGN KEY (mod) REFERENCES Mods(name) FOREIGN KEY (mod) REFERENCES Mods(name) ON DELETE CASCADE
);`); );`);
// Mods tags // Mods tags
@ -74,7 +74,7 @@ async function initDatabase() {
mod TINYTEXT NOT NULL, mod TINYTEXT NOT NULL,
tag TINYTEXT NOT NULL, tag TINYTEXT NOT NULL,
FOREIGN KEY (mod) REFERENCES Mods(name) FOREIGN KEY (mod) REFERENCES Mods(name) ON DELETE CASCADE
);`); );`);
// Mods versions // Mods versions
@ -89,7 +89,7 @@ async function initDatabase() {
environment TINYTEXT NOT NULL, environment TINYTEXT NOT NULL,
url TINYTEXT NOT NULL, url TINYTEXT NOT NULL,
FOREIGN KEY (mod) REFERENCES Mods(name) FOREIGN KEY (mod) REFERENCES Mods(name) ON DELETE CASCADE
);`); );`);
// User favorites (mods) // User favorites (mods)
@ -97,8 +97,8 @@ async function initDatabase() {
username TINYTEXT NOT NULL, username TINYTEXT NOT NULL,
mod TINYTEXT NOT NULL, mod TINYTEXT NOT NULL,
FOREIGN KEY (username) REFERENCES Users(username), FOREIGN KEY (username) REFERENCES Users(username) ON DELETE CASCADE,
FOREIGN KEY (mod) REFERENCES Mods(name) FOREIGN KEY (mod) REFERENCES Mods(name) ON DELETE CASCADE
);`); );`);
} }

View file

@ -1,3 +1,5 @@
//! Not implemented
class MySQLDatabase { class MySQLDatabase {
constructor(config) { constructor(config) {
const mysql = require("mysql2/promise"); const mysql = require("mysql2/promise");

View file

@ -25,6 +25,7 @@ class SQLiteDatabase {
} }
} }
// Runs with a result (ex: SELECT)
async query(sql, params = []) { async query(sql, params = []) {
try { try {
if (params.length > 0) { if (params.length > 0) {
@ -38,15 +39,17 @@ class SQLiteDatabase {
} }
} }
// One time queries (ex: CREATE TABLE)
async exec(sql) { async exec(sql) {
try { try {
return this.db.exec(sql); return this.db.exec(sql);
} catch (err) { } catch (err) {
console.error("Error executing statement:", err)} console.error("Error executing statement:", err)}
throw err;
} }
async prepare(sql, params = []) { // Queries with no results (ex: INSERT)
async run(sql, params = []) {
try { try {
if (params.length > 0) { if (params.length > 0) {
return this.db.prepare(sql).run(params); return this.db.prepare(sql).run(params);
@ -55,6 +58,27 @@ class SQLiteDatabase {
} }
} catch (err) { } catch (err) {
console.error("Error executing prepared statement:", err)} console.error("Error executing prepared statement:", err)}
throw err;
}
// Prepare a query for run or for transaction
async prepare(sql) {
try {
return this.db.prepare(sql);
} catch (err) {
console.error("Error preparing statement:", err)}
throw err;
}
// Run a prepared transaction
async transaction(prepared_sql, items) {
try {
this.db.transaction((items) => {
for (const item of items) prepared_sql.run(item);
})
} catch (err) {
console.error("Error executing prepared statement:", err)}
throw err;
} }
async exists(table, attribute, value) { async exists(table, attribute, value) {
@ -62,6 +86,7 @@ class SQLiteDatabase {
return this.db.prepare(`SELECT COUNT(*) FROM ${table} WHERE ${attribute} = ?`).get(value)['COUNT(*)'] > 0; return this.db.prepare(`SELECT COUNT(*) FROM ${table} WHERE ${attribute} = ?`).get(value)['COUNT(*)'] > 0;
} catch (err) { } catch (err) {
console.error("Error checking item existence"); console.error("Error checking item existence");
throw err;
} }
} }

View file

@ -15,7 +15,7 @@ async function authenticateToken(req) {
try { try {
req.token_infos = await verifyToken(token); req.token_infos = await verifyToken(token);
console.debug("Authorizing token from", req.token_infos); // console.debug("Authorizing token from", req.token_infos);
} catch (err) { } catch (err) {
throw new AppError(403, "Forbidden: Error verifying the authorization token"); throw new AppError(403, "Forbidden: Error verifying the authorization token");
} }

View file

@ -58,12 +58,12 @@ async function createMod(name, display_name, author, description, mod_infos) {
const { full_description, license, links, creation_date, tags } = mod_infos; const { full_description, license, links, creation_date, tags } = mod_infos;
// Mods table // Mods table
await db.prepare("INSERT INTO Mods (name, display_name, author, description) \ await db.run("INSERT INTO Mods (name, display_name, author, description) \
VALUES (?, ?, ?, ?)", VALUES (?, ?, ?, ?)",
[name, display_name, author, description]); [name, display_name, author, description]);
// ModInfos table // ModInfos table
await db.prepare(`INSERT INTO ModInfos (mod, full_description, license, links, creation_date, downloads_count) await db.run(`INSERT INTO ModInfos (mod, full_description, license, links, creation_date, downloads_count)
VALUES (?, ?, ?, ?, ?, ?)`, VALUES (?, ?, ?, ?, ?, ?)`,
[name, full_description, license.type, links.toString(), creation_date, 0]); [name, full_description, license.type, links.toString(), creation_date, 0]);
@ -75,7 +75,7 @@ async function createMod(name, display_name, author, description, mod_infos) {
// License // License
if (license.type == "custom") { if (license.type == "custom") {
await db.prepare(`UPDATE ModInfos SET custom_license = ? await db.run(`UPDATE ModInfos SET custom_license = ?
WHERE mod = ?`, WHERE mod = ?`,
[license.content, name]); [license.content, name]);
} }
@ -90,7 +90,7 @@ async function createMod(name, display_name, author, description, mod_infos) {
async function addVersion(mod, version_number, channel, changelog, release_date, game_version, platform, environment, url) { async function addVersion(mod, version_number, channel, changelog, release_date, game_version, platform, environment, url) {
await db.prepare(`INSERT INTO ModVersions (mod, version_number, channel, changelog, release_date, game_version, environment, platform, url) await db.run(`INSERT INTO ModVersions (mod, version_number, channel, changelog, release_date, game_version, environment, platform, url)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);`, VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);`,
[mod, version_number, channel, changelog, release_date, game_version, environment, platform, url]); [mod, version_number, channel, changelog, release_date, game_version, environment, platform, url]);
return; return;
@ -130,12 +130,12 @@ async function updateMod(name, display_name, author, description) {
// --- Delete --- // --- Delete ---
async function deleteMod(name) { async function deleteMod(name) {
await db.prepare("DELETE FROM Mods WHERE name = ?", [name]); await db.run("DELETE FROM Mods WHERE name = ?", [name]);
return; return;
} }
async function deleteVersion(name, version_number, game_version, platform, environment) { async function deleteVersion(name, version_number, game_version, platform, environment) {
await db.prepare(`DELETE FROM ModVersions WHERE mod = ? await db.run(`DELETE FROM ModVersions WHERE mod = ?
AND version_number = ? AND version_number = ?
AND game_version = ? AND game_version = ?
AND platform = ? AND platform = ?
@ -159,12 +159,12 @@ async function deleteTags(mod, tags) {
// --- Utils --- // --- Utils ---
async function updateModAttribute(name, attribute, value) { async function updateModAttribute(name, attribute, value) {
await db.prepare(`UPDATE Mods SET ${attribute} = ? WHERE name = ?`, [value, name]); await db.run(`UPDATE Mods SET ${attribute} = ? WHERE name = ?`, [value, name]);
return; return;
} }
async function updateModInfosAttribute(name, attribute, value) { async function updateModInfosAttribute(name, attribute, value) {
await db.prepare(`UPDATE ModInfos SET ${attribute} = ? WHERE name = ?`, [value, name]); await db.run(`UPDATE ModInfos SET ${attribute} = ? WHERE name = ?`, [value, name]);
return; return;
} }

View file

@ -35,7 +35,7 @@ async function exists(name) {
async function createUser( username, email, password, displayName, profilePicture, settings ) { async function createUser( username, email, password, displayName, profilePicture, settings ) {
// Create user // Create user
await db.prepare(`INSERT INTO Users (username, email, password, display_name, role ) await db.run(`INSERT INTO Users (username, email, password, display_name, role )
VALUES (?, ?, ?, ?, ? )`, VALUES (?, ?, ?, ?, ? )`,
[username, email, password, displayName, "user"]); [username, email, password, displayName, "user"]);
@ -86,11 +86,11 @@ async function updateUser(username, display_name, email, profile_picture, settin
} }
async function updateUserPassword(username, password) { async function updateUserPassword(username, password) {
await db.prepare(`UPDATE Users SET password = ? WHERE username = ?`, [password, username]); await db.run(`UPDATE Users SET password = ? WHERE username = ?`, [password, username]);
} }
async function updateUserAttribute(username, attribute, value) { async function updateUserAttribute(username, attribute, value) {
await db.prepare(`UPDATE Users SET ${attribute} = ? WHERE username = ?`, [value, username]); await db.run(`UPDATE Users SET ${attribute} = ? WHERE username = ?`, [value, username]);
return; return;
} }
@ -98,7 +98,7 @@ async function updateUserAttribute(username, attribute, value) {
// --- Delete --- // --- Delete ---
async function deleteUser(username) { async function deleteUser(username) {
await db.prepare("DELETE FROM Users WHERE username = ?", [username]); await db.run("DELETE FROM Users WHERE username = ?", [username]);
return; return;
} }