Skip to content

Commit

Permalink
chore: refactor seed + add transactions tables
Browse files Browse the repository at this point in the history
  • Loading branch information
AxonDesigns committed Dec 10, 2024
1 parent 47a558c commit 5235e6a
Show file tree
Hide file tree
Showing 9 changed files with 244 additions and 79 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"db:submit": "drizzle-kit generate --config=./drizzle.config.ts && drizzle-kit migrate --config=./drizzle.config.ts",
"db:push": "drizzle-kit push --config=./drizzle.config.ts",
"db:studio": "drizzle-kit studio --config=./drizzle.config.ts",
"db:seed": "tsx src/db/index.ts",
"db:seed": "tsx src/db/seed.ts",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
Expand Down Expand Up @@ -44,4 +44,4 @@
"tsx": "^4.19.2",
"typescript": "^5.6.3"
}
}
}
64 changes: 0 additions & 64 deletions src/db/index.ts

This file was deleted.

45 changes: 45 additions & 0 deletions src/db/schema/transactions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { char, decimal, mysqlTable, timestamp, varchar } from "drizzle-orm/mysql-core";
import { randomUUID } from "node:crypto";
import { usersTable } from "./users";
import { sql } from "drizzle-orm";

export const transactionsTable = mysqlTable("transactions", {
id: char("id", { length: 36 }).primaryKey().$default(() => randomUUID()),
status: varchar("status", { length: 255 }).notNull(),
totalAmount: decimal("total_amount", { precision: 10, scale: 2 }).notNull(),
paidAmount: decimal("paid_amount", { precision: 10, scale: 2 }).notNull().default(sql`0.00`),
pendingAmount: decimal("pending_amount", { precision: 10, scale: 2 }).notNull().default(sql`0.00`),
tax: decimal("tax", { precision: 10, scale: 2 }).default(sql`0.00`),
fee: decimal("fee", { precision: 10, scale: 2 }).default(sql`0.00`),
location: varchar("location", { length: 255 }).notNull(),
description: varchar("description", { length: 255 }).notNull(),
employeeId: char("employee_id", { length: 36 }).references(() => usersTable.id).notNull(),
categoryId: char("category_id", { length: 36 }).references(() => transactionCategoriesTable.id).notNull(),
createdAt: timestamp("created_at").notNull().defaultNow(),
updatedAt: timestamp("updated_at").notNull().defaultNow().onUpdateNow(),
});

export const transactionPaymentsTable = mysqlTable("transaction_payments", {
id: char("id", { length: 36 }).primaryKey().$default(() => randomUUID()),
amount: decimal("amount", { precision: 10, scale: 2 }).notNull(),
description: varchar("description", { length: 255 }).notNull(),
currency: varchar("currency", { length: 255 }).notNull(),
method: char("method", { length: 36 }).references(() => paymentMethodsTable.id).notNull(),
transactionId: char("transaction_id", { length: 36 }).references(() => transactionsTable.id).notNull(),
createdAt: timestamp("created_at").notNull().defaultNow(),
updatedAt: timestamp("updated_at").notNull().defaultNow().onUpdateNow(),
});

export const transactionCategoriesTable = mysqlTable("transaction_categories", {
id: char("id", { length: 36 }).primaryKey().$default(() => randomUUID()),
name: varchar("name", { length: 255 }).notNull().unique(),
createdAt: timestamp("created_at").notNull().defaultNow(),
updatedAt: timestamp("updated_at").notNull().defaultNow().onUpdateNow(),
});

export const paymentMethodsTable = mysqlTable("payment_methods", {
id: char("id", { length: 36 }).primaryKey().$default(() => randomUUID()),
name: varchar("name", { length: 255 }).notNull().unique(),
createdAt: timestamp("created_at").notNull().defaultNow(),
updatedAt: timestamp("updated_at").notNull().defaultNow().onUpdateNow(),
});
175 changes: 175 additions & 0 deletions src/db/seed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { db } from '@/db/database';
import { rolesTable } from '@/db/schema/roles';
import { usersTable } from '@/db/schema/users';
import { genSalt, hash } from 'bcrypt';
import { eq, or } from 'drizzle-orm';
import { paymentMethodsTable, transactionCategoriesTable } from './schema/transactions';

async function seedUsers() {
await db.transaction(async (tx) => {
const existentAdminRole = await tx.select().from(rolesTable).where(eq(rolesTable.name, "admin"));
const existentUserRole = await tx.select().from(rolesTable).where(eq(rolesTable.name, "user"));

const roles = [];
if (existentAdminRole.length === 0) {
roles.push({
name: "admin",
description: "Administrator",
});
}

if (existentUserRole.length === 0) {
roles.push({
name: "user",
description: "User",
});
}

if (roles.length === 0) return;

const savedIds = await tx.insert(rolesTable).values(roles).$returningId();
const savedRoles = await tx.select().from(rolesTable).where(or(...savedIds.map((savedId) => eq(rolesTable.id, savedId.id))));
console.log(savedRoles);
});

await db.transaction(async (tx) => {
const exists = await tx.select().from(usersTable).where(eq(usersTable.email, 'admin@admin.com'));
if (exists.length > 0) return;

const roles = await tx.select({ id: rolesTable.id }).from(rolesTable).where(eq(rolesTable.name, 'admin'));

if (roles.length === 0) {
console.error('Admin role not found!');
return;
}

const savedId = await tx.insert(usersTable).values({
name: 'Admin',
email: 'admin@admin.com',
roleId: roles[0].id,
password: await hash(process.env.ADMIN_PASSWORD!, await genSalt()),
}).$returningId();

const savedUser = await tx.select().from(usersTable).where(eq(usersTable.id, savedId[0].id));
if (savedUser.length === 0) {
console.error('Admin user not found!');
return;
}
console.log(savedUser[0]);
});
}

async function seedPaymentMethods() {
// Cash
await db.transaction(async (tx) => {
const existent = await tx.select().from(paymentMethodsTable).where(eq(paymentMethodsTable.name, "Cash"));
if (existent.length > 0) return;
await tx.insert(paymentMethodsTable).values({
name: "Cash",
});
});

// Credit Card
await db.transaction(async (tx) => {
const existent = await tx.select().from(paymentMethodsTable).where(eq(paymentMethodsTable.name, "Credit Card"));
if (existent.length > 0) return;
await tx.insert(paymentMethodsTable).values({
name: "Credit Card",
});
});

// Debit Card
await db.transaction(async (tx) => {
const existent = await tx.select().from(paymentMethodsTable).where(eq(paymentMethodsTable.name, "Debit Card"));
if (existent.length > 0) return;
await tx.insert(paymentMethodsTable).values({
name: "Debit Card",
});
});
}

async function seedTransactionCategories() {
// Food
await db.transaction(async (tx) => {
const existent = await tx.select().from(transactionCategoriesTable).where(eq(transactionCategoriesTable.name, "Food"));
if (existent.length > 0) return;
await tx.insert(transactionCategoriesTable).values({
name: "Food",
});
});

//Transportation
await db.transaction(async (tx) => {
const existent = await tx.select().from(transactionCategoriesTable).where(eq(transactionCategoriesTable.name, "Transportation"));
if (existent.length > 0) return;
await tx.insert(transactionCategoriesTable).values({
name: "Transportation",
});
});

//Entertainment
await db.transaction(async (tx) => {
const existent = await tx.select().from(transactionCategoriesTable).where(eq(transactionCategoriesTable.name, "Entertainment"));
if (existent.length > 0) return;
await tx.insert(transactionCategoriesTable).values({
name: "Entertainment",
});
});

// Health
await db.transaction(async (tx) => {
const existent = await tx.select().from(transactionCategoriesTable).where(eq(transactionCategoriesTable.name, "Health"));
if (existent.length > 0) return;
await tx.insert(transactionCategoriesTable).values({
name: "Health",
});
});

// Cleaning
await db.transaction(async (tx) => {
const existent = await tx.select().from(transactionCategoriesTable).where(eq(transactionCategoriesTable.name, "Cleaning"));
if (existent.length > 0) return;
await tx.insert(transactionCategoriesTable).values({
name: "Cleaning",
});
});

// Technology
await db.transaction(async (tx) => {
const existent = await tx.select().from(transactionCategoriesTable).where(eq(transactionCategoriesTable.name, "Technology"));
if (existent.length > 0) return;
await tx.insert(transactionCategoriesTable).values({
name: "Technology",
});
});

// Stationery
await db.transaction(async (tx) => {
const existent = await tx.select().from(transactionCategoriesTable).where(eq(transactionCategoriesTable.name, "Stationery"));
if (existent.length > 0) return;
await tx.insert(transactionCategoriesTable).values({
name: "Stationery",
});
});

// Other
await db.transaction(async (tx) => {
const existent = await tx.select().from(transactionCategoriesTable).where(eq(transactionCategoriesTable.name, "Other"));
if (existent.length > 0) return;
await tx.insert(transactionCategoriesTable).values({
name: "Other",
});
});
}

async function main() {

await seedUsers();
console.log('Users and roles seeded!');
await seedPaymentMethods();
console.log('Payment methods seeded!');
await seedTransactionCategories();
console.log('Transaction categories seeded!');
}

main();
11 changes: 8 additions & 3 deletions src/handlers/session.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { Request, Response } from "express";
import { verify } from "jsonwebtoken";

export const getSession = async (req: Request, res: Response) => {
export const getUserFromToken = async (req: Request, res: Response) => {
const accessToken = req.cookies.access_token;

if (!accessToken) {
res.status(401).json({ errors: ["Unauthorized"] });
return;
}

const payload = verify(accessToken, process.env.ACCESS_TOKEN_SECRET as string);
res.json(payload);
try {
const payload = verify(accessToken, process.env.ACCESS_TOKEN_SECRET as string);
res.json(payload);
} catch (error) {
res.clearCookie("access_token");
res.status(500).json({ errors: ["Token is invalid"] });
}
}
12 changes: 8 additions & 4 deletions src/handlers/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ export const userSelectFields = {

const selectUsers = (expand: boolean) => {
if (expand) {
return db.select(userSelectExpandedFields).from(usersTable).innerJoin(rolesTable, eq(usersTable.roleId, rolesTable.id));
return db.select(userSelectExpandedFields).from(usersTable)
.innerJoin(rolesTable, eq(usersTable.roleId, rolesTable.id));
}

return db.select(userSelectFields).from(usersTable);
Expand All @@ -48,7 +49,8 @@ export const getUsers = async (req: Request, res: Response) => {
}
const { limit, offset, expand } = matchedData(req) as { limit?: number, offset?: number, expand?: boolean };

const foundUsers = await selectUsers(expand !== undefined).limit(limit ?? 20).offset(offset ?? 0);
const foundUsers = await selectUsers(expand !== undefined)
.limit(limit ?? 20).offset(offset ?? 0);

console.log(req.cookies.access_token);

Expand All @@ -69,7 +71,8 @@ export const createUser = async (req: Request, res: Response) => {
expand?: boolean
};

const existentUser = await db.select().from(usersTable).where(eq(usersTable.email, email));
const existentUser = await db.select().from(usersTable)
.where(eq(usersTable.email, email));
if (existentUser.length > 0) {
res.status(400).json({ errors: ["Email already exists"] });
return;
Expand All @@ -88,7 +91,8 @@ export const createUser = async (req: Request, res: Response) => {
password: await hash(password, await genSalt()),
}).$returningId();

const createdUsers = await selectUsers(expand !== undefined).where(eq(usersTable.id, createdIds[0].id));
const createdUsers = await selectUsers(expand !== undefined)
.where(eq(usersTable.id, createdIds[0].id));

res.status(201).json(createdUsers[0]);
};
Expand Down
6 changes: 3 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ app.use(bodyParser.urlencoded({ extended: false }));
app.disable('x-powered-by');

app.use("/api/users", usersRoute);
app.use("/api/login", loginRoute);
app.use("/api/logout", logoutRoute);
app.use("/api/current-user", sessionRoute);
app.use("/api/auth/login", loginRoute);
app.use("/api/auth/logout", logoutRoute);
app.use("/api/auth/me", sessionRoute);

app.get("/", (req, res) => {
console.log(req.cookies)
Expand Down
4 changes: 2 additions & 2 deletions src/routes/session.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { getSession } from "@/handlers/session";
import { getUserFromToken } from "@/handlers/session";
import { Router } from "express";

const router = Router();

router.get(
"/",
getSession
getUserFromToken
);

export default router;
Loading

0 comments on commit 5235e6a

Please sign in to comment.