ok turns out this is something that should be configured on the db columns, ideally not in the queries, makes sense to me https://stackoverflow.com/a/36768933 https://dev.mysql.com/doc/refman/5.7/en/case-sensitivity.html

This commit is contained in:
Ean Milligan
2026-04-23 02:53:07 -04:00
parent 353e6e978d
commit 1f4c4723d3
3 changed files with 28 additions and 32 deletions

View File

@@ -16,8 +16,8 @@ console.log('Tables dropped');
console.log('Attempting to create table users');
await dbClient.execute(`
CREATE TABLE users (
id varchar(20) NOT NULL,
name varchar(20) NOT NULL,
id varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
name varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
hash varchar(60) NOT NULL,
email varchar(255) NULL,
deleteCode varchar(20) NULL,
@@ -31,8 +31,8 @@ console.log('Table created');
console.log('Attempting to create table plans');
await dbClient.execute(`
CREATE TABLE plans (
id varchar(20) NOT NULL,
ownerId varchar(20) NOT NULL,
id varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
ownerId varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
name varchar(200) NOT NULL,
folder varchar(200) NOT NULL,
lastUpdated timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,

44
mod.ts
View File

@@ -43,7 +43,7 @@ Deno.serve({ port: config.api.port }, async (req) => {
} else if (path.startsWith('/home/')) {
// SSR "home page"
const userId = path.replace('/home/', '');
const userMatch = await dbClient.query('SELECT name FROM users WHERE BINARY id = ?', [userId]).catch(() => {
const userMatch = await dbClient.query('SELECT name FROM users WHERE id = ?', [userId]).catch(() => {
failed = true;
});
if (failed) return buildPage("Couldn't read DB. Please try again.");
@@ -53,7 +53,7 @@ Deno.serve({ port: config.api.port }, async (req) => {
} else if (path.startsWith('/read/')) {
const planId = path.replace('/read/', '');
const plans = await dbClient.query('SELECT name, folder, data FROM plans WHERE BINARY id = ? AND deleted = 0', [planId]).catch(() => {
const plans = await dbClient.query('SELECT name, folder, data FROM plans WHERE id = ? AND deleted = 0', [planId]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB.");
@@ -62,14 +62,14 @@ Deno.serve({ port: config.api.port }, async (req) => {
return genericResponse(STATUS_CODE.OK, JSON.stringify(plans[0]));
} else if (path.startsWith('/list/')) {
const userId = path.replace('/list/', '');
const userMatch = await dbClient.query('SELECT id FROM users WHERE BINARY id = ?', [userId]).catch(() => {
const userMatch = await dbClient.query('SELECT id FROM users WHERE id = ?', [userId]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB.");
if (!userMatch.length) return genericResponse(STATUS_CODE.NotFound, 'User ID does not exist.');
const plans = await dbClient
.query('SELECT id, name, folder, lastUpdated FROM plans WHERE BINARY ownerId = ? AND deleted = 0 ORDER BY folder ASC,name ASC', [userId])
.query('SELECT id, name, folder, lastUpdated FROM plans WHERE ownerId = ? AND deleted = 0 ORDER BY folder ASC,name ASC', [userId])
.catch(() => {
failed = true;
});
@@ -82,7 +82,7 @@ Deno.serve({ port: config.api.port }, async (req) => {
return genericResponse(STATUS_CODE.OK, JSON.stringify(plans));
} else if (path.startsWith('/export/')) {
const userId = path.replace('/export/', '');
const userMatch = await dbClient.query('SELECT id FROM users WHERE BINARY id = ?', [userId]).catch(() => {
const userMatch = await dbClient.query('SELECT id FROM users WHERE id = ?', [userId]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB.");
@@ -94,7 +94,7 @@ Deno.serve({ port: config.api.port }, async (req) => {
} else if (req.method === 'POST' && path === '/enroll') {
const body = await req.json();
const userNameMatches = await dbClient.query('SELECT name FROM users WHERE BINARY name = ?', [body.name]).catch(() => {
const userNameMatches = await dbClient.query('SELECT name FROM users WHERE name = ?', [body.name]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB.");
@@ -123,7 +123,7 @@ Deno.serve({ port: config.api.port }, async (req) => {
} else {
const body = await req.json();
const loginMatch = await dbClient.query('SELECT id, hash, email, deleteCode FROM users WHERE BINARY name = ?', [body.name]).catch(() => {
const loginMatch = await dbClient.query('SELECT id, hash, email, deleteCode FROM users WHERE name = ?', [body.name]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB.");
@@ -155,28 +155,28 @@ Deno.serve({ port: config.api.port }, async (req) => {
case 'PUT':
if (path.startsWith('/undelete/')) {
const planId = path.replace('/undelete/', '');
const planMatch = await dbClient.query('SELECT ownerId FROM plans WHERE BINARY id = ?', [planId]).catch(() => {
const planMatch = await dbClient.query('SELECT ownerId FROM plans WHERE id = ?', [planId]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB.");
if (!planMatch.length) return genericResponse(STATUS_CODE.NotFound, 'Plan ID does not exist.');
if (planMatch[0].ownerId !== id) return genericResponse(STATUS_CODE.Forbidden, "You don't own this plan.");
await dbClient.execute('UPDATE plans SET deleted = 0, lastUpdated = ? WHERE BINARY id = ?', [new Date(), planId]).catch(() => {
await dbClient.execute('UPDATE plans SET deleted = 0, lastUpdated = ? WHERE id = ?', [new Date(), planId]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't update DB.");
return genericResponse(STATUS_CODE.OK, 'Plan restored.');
} else if (path.startsWith('/update/')) {
const planId = path.replace('/update/', '');
const planMatch = await dbClient.query('SELECT ownerId FROM plans WHERE BINARY id = ?', [planId]).catch(() => {
const planMatch = await dbClient.query('SELECT ownerId FROM plans WHERE id = ?', [planId]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB.");
if (!planMatch.length) return genericResponse(STATUS_CODE.NotFound, 'Plan ID does not exist.');
if (planMatch[0].ownerId !== id) return genericResponse(STATUS_CODE.Forbidden, "You don't own this plan.");
await dbClient.execute('UPDATE plans SET data = ?, lastUpdated = ? WHERE BINARY id = ?', [body.data, new Date(), planId]).catch(() => {
await dbClient.execute('UPDATE plans SET data = ?, lastUpdated = ? WHERE id = ?', [body.data, new Date(), planId]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't update DB.");
@@ -185,14 +185,14 @@ Deno.serve({ port: config.api.port }, async (req) => {
if (body.planName.trim().length > 200) return genericResponse(STATUS_CODE.BadRequest, 'Name too long.');
const planId = path.replace('/rename/', '');
const planMatch = await dbClient.query('SELECT ownerId FROM plans WHERE BINARY id = ?', [planId]).catch(() => {
const planMatch = await dbClient.query('SELECT ownerId FROM plans WHERE id = ?', [planId]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB.");
if (!planMatch.length) return genericResponse(STATUS_CODE.NotFound, 'Plan ID does not exist.');
if (planMatch[0].ownerId !== id) return genericResponse(STATUS_CODE.Forbidden, "You don't own this plan.");
await dbClient.execute('UPDATE plans SET name = ?, lastUpdated = ? WHERE BINARY id = ?', [body.planName, new Date(), planId]).catch(() => {
await dbClient.execute('UPDATE plans SET name = ?, lastUpdated = ? WHERE id = ?', [body.planName, new Date(), planId]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't update DB.");
@@ -201,14 +201,14 @@ Deno.serve({ port: config.api.port }, async (req) => {
if (body.folder.trim().length > 200) return genericResponse(STATUS_CODE.BadRequest, 'Folder name too long.');
const planId = path.replace('/move/', '');
const planMatch = await dbClient.query('SELECT ownerId FROM plans WHERE BINARY id = ?', [planId]).catch(() => {
const planMatch = await dbClient.query('SELECT ownerId FROM plans WHERE id = ?', [planId]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB.");
if (!planMatch.length) return genericResponse(STATUS_CODE.NotFound, 'Plan ID does not exist.');
if (planMatch[0].ownerId !== id) return genericResponse(STATUS_CODE.Forbidden, "You don't own this plan.");
await dbClient.execute('UPDATE plans SET folder = ?, lastUpdated = ? WHERE BINARY id = ?', [body.folder, new Date(), planId]).catch(() => {
await dbClient.execute('UPDATE plans SET folder = ?, lastUpdated = ? WHERE id = ?', [body.folder, new Date(), planId]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't update DB.");
@@ -218,12 +218,12 @@ Deno.serve({ port: config.api.port }, async (req) => {
case 'DELETE':
if (path === '/unenroll') {
if (!hasEmail || body.deleteCode.trim() === deleteCode) {
await dbClient.execute('DELETE FROM plans WHERE BINARY ownerId = ?', [id]).catch(() => {
await dbClient.execute('DELETE FROM plans WHERE ownerId = ?', [id]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't delete plans.");
await dbClient.execute('DELETE FROM users WHERE BINARY id = ?', [id]).catch(() => {
await dbClient.execute('DELETE FROM users WHERE id = ?', [id]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't delete user.");
@@ -231,7 +231,7 @@ Deno.serve({ port: config.api.port }, async (req) => {
return genericResponse(STATUS_CODE.OK, 'Deleted user and plans.');
} else if (hasEmail && !deleteCode) {
const newDeleteCode = nanoid();
await dbClient.execute('UPDATE users SET deleteCode = ? WHERE BINARY id = ?', [newDeleteCode, id]).catch(() => {
await dbClient.execute('UPDATE users SET deleteCode = ? WHERE id = ?', [newDeleteCode, id]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't set deleteCode.");
@@ -282,21 +282,21 @@ Deno.serve({ port: config.api.port }, async (req) => {
}
} else if (path.startsWith('/delete/')) {
const planId = path.replace('/delete/', '');
const planMatch = await dbClient.query('SELECT ownerId FROM plans WHERE BINARY id = ?', [planId]).catch(() => {
const planMatch = await dbClient.query('SELECT ownerId FROM plans WHERE id = ?', [planId]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB.");
if (!planMatch.length) return genericResponse(STATUS_CODE.NotFound, 'Plan ID does not exist.');
if (planMatch[0].ownerId !== id) return genericResponse(STATUS_CODE.Forbidden, "You don't own this plan.");
await dbClient.execute('UPDATE plans SET deleted = 1, lastUpdated = ? WHERE BINARY id = ?', [new Date(), planId]).catch(() => {
await dbClient.execute('UPDATE plans SET deleted = 1, lastUpdated = ? WHERE id = ?', [new Date(), planId]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't update DB.");
return genericResponse(STATUS_CODE.OK, 'Plan deleted.');
} else if (path.startsWith('/perm-delete/')) {
const planId = path.replace('/perm-delete/', '');
const planMatch = await dbClient.query('SELECT ownerId, deleted FROM plans WHERE BINARY id = ?', [planId]).catch(() => {
const planMatch = await dbClient.query('SELECT ownerId, deleted FROM plans WHERE id = ?', [planId]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB.");
@@ -304,7 +304,7 @@ Deno.serve({ port: config.api.port }, async (req) => {
if (planMatch[0].ownerId !== id) return genericResponse(STATUS_CODE.Forbidden, "You don't own this plan.");
if (!planMatch[0].deleted) return genericResponse(STATUS_CODE.Forbidden, 'Plan must be marked as deleted to perm delete.');
await dbClient.execute('DELETE FROM plans WHERE BINARY id = ? AND deleted = 1', [planId]).catch(() => {
await dbClient.execute('DELETE FROM plans WHERE id = ? AND deleted = 1', [planId]).catch(() => {
failed = true;
});
if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't update DB.");

View File

@@ -21,18 +21,14 @@ export default async (userId: string, userName: string) => {
let failed = false;
const plans: Plan[] = await dbClient
.query('SELECT id, name, folder, lastUpdated FROM plans WHERE BINARY ownerId = ? AND deleted = 0 GROUP BY folder,name,id ORDER BY folder ASC,name ASC', [
userId,
])
.query('SELECT id, name, folder, lastUpdated FROM plans WHERE ownerId = ? AND deleted = 0 GROUP BY folder,name,id ORDER BY folder ASC,name ASC', [userId])
.catch((e) => {
failed = true;
});
if (failed) return "Couldn't read DB.";
const deletedPlans: Plan[] = await dbClient
.query('SELECT id, name, folder, lastUpdated FROM plans WHERE BINARY ownerId = ? AND deleted = 1 GROUP BY folder,name,id ORDER BY folder ASC,name ASC', [
userId,
])
.query('SELECT id, name, folder, lastUpdated FROM plans WHERE ownerId = ? AND deleted = 1 GROUP BY folder,name,id ORDER BY folder ASC,name ASC', [userId])
.catch(() => {
failed = true;
});