From 2258b651deb2417b100d80f2a6785dc0be9e1e74 Mon Sep 17 00:00:00 2001 From: Dave Smith-Hayes Date: Fri, 16 Feb 2024 18:19:58 -0500 Subject: [PATCH] init slovocast API later. --- docker-compose.yml | 16 +++++++ frontend/.gitkeep | 0 server/.env | 4 ++ server/.gitignore | 1 + server/README.md | 11 +++++ server/bun.lockb | Bin 0 -> 7268 bytes server/package.json | 13 ++++++ server/sql/drop_tables.sql | 1 + server/sql/users.sql | 10 +++++ server/src/index.ts | 61 ++++++++++++++++++++++++++ server/src/infrastructure/database.ts | 36 +++++++++++++++ server/src/models/Channel.ts | 12 +++++ server/src/models/User.ts | 8 ++++ server/src/routes/user.ts | 38 ++++++++++++++++ server/src/setup.ts | 27 ++++++++++++ server/tsconfig.json | 10 +++++ 16 files changed, 248 insertions(+) create mode 100644 docker-compose.yml create mode 100644 frontend/.gitkeep create mode 100644 server/.env create mode 100644 server/.gitignore create mode 100644 server/README.md create mode 100755 server/bun.lockb create mode 100644 server/package.json create mode 100644 server/sql/drop_tables.sql create mode 100644 server/sql/users.sql create mode 100644 server/src/index.ts create mode 100644 server/src/infrastructure/database.ts create mode 100644 server/src/models/Channel.ts create mode 100644 server/src/models/User.ts create mode 100644 server/src/routes/user.ts create mode 100644 server/src/setup.ts create mode 100644 server/tsconfig.json diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f542aff --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,16 @@ +version: '3.9' + +services: + database: + image: mariadb:latest + environment: + ROOT_MYSQL_PASSWORD: password + MYSQL_USER: user + MYSQL_PASSWORD: password + MYSQL_DATABASE: slovocast + ports: + - "3306:3306" + volumes: + - slovocast_db:/var/lib/mysql +volumes: + slovocast_db: diff --git a/frontend/.gitkeep b/frontend/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server/.env b/server/.env new file mode 100644 index 0000000..738da5f --- /dev/null +++ b/server/.env @@ -0,0 +1,4 @@ +DATABASE_HOST=localhost +DATABASE_USER=user +DATABASE_PASSWORD=password +DATABASE_SCHEMA=slovocast diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/server/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/server/README.md b/server/README.md new file mode 100644 index 0000000..6dd13e7 --- /dev/null +++ b/server/README.md @@ -0,0 +1,11 @@ +To install dependencies: +```sh +bun install +``` + +To run: +```sh +bun run dev +``` + +open http://localhost:3000 diff --git a/server/bun.lockb b/server/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..766be32f1bb449246685f7329488bc9f93663f8d GIT binary patch literal 7268 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 literal 0 HcmV?d00001 diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..4019037 --- /dev/null +++ b/server/package.json @@ -0,0 +1,13 @@ +{ + "scripts": { + "dev": "bun run --hot src/index.ts" + }, + "dependencies": { + "hono": "^4.0.3", + "mariadb": "^3.2.3", + "podcast": "^2.0.1" + }, + "devDependencies": { + "@types/bun": "latest" + } +} diff --git a/server/sql/drop_tables.sql b/server/sql/drop_tables.sql new file mode 100644 index 0000000..c99ddcd --- /dev/null +++ b/server/sql/drop_tables.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS users; diff --git a/server/sql/users.sql b/server/sql/users.sql new file mode 100644 index 0000000..316eeed --- /dev/null +++ b/server/sql/users.sql @@ -0,0 +1,10 @@ +CREATE TABLE users ( + id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, + username VARCHAR(255) NOT NULL, + password VARCHAR(255) NOT NULL, + + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + PRIMARY KEY(`id`) +); diff --git a/server/src/index.ts b/server/src/index.ts new file mode 100644 index 0000000..22719bf --- /dev/null +++ b/server/src/index.ts @@ -0,0 +1,61 @@ +import { Context, Hono } from 'hono'; +import { Connection, createPool } from 'mariadb'; + +import User from './models/User'; + +const app = new Hono(); + +// +// bootstrap resources +// + +// mariadb +const databasePool = createPool({ + host: process.env.DATABASE_HOST, + user: process.env.DATABASE_USER, + password: process.env.DATABASE_PASSWORD, + database: process.env.DATABASE_SCHEMA +}); + +app.onError((err: Error, c: Context) => { + console.log(err.message); + c.status(500); + + if (process.env.MODE == 'development') { + return c.json({ err }); + } + + return c.json({ message: "An error occurred." }); +}) + +// +// set routes +// + +// Welcome message +app.get('/', async (c: Context) => { + return c.json({ + message: "Hello from Slovocast" + }); +}); + +// User actions +import users from './routes/user'; +app.route("/users", users); + +// Channel Actions + // add episode + // edit episode + // regenerate feed +app.get('/:channel', (c: Context) => { + return c.json({ + channel: { + name: "Name", + } + }); +}); + + +// feed actions +console.log("Running app on :3000"); +export default app; diff --git a/server/src/infrastructure/database.ts b/server/src/infrastructure/database.ts new file mode 100644 index 0000000..df0549a --- /dev/null +++ b/server/src/infrastructure/database.ts @@ -0,0 +1,36 @@ +import { Connection, Pool, createPool } from 'mariadb'; + +type ConnectionConfig = { + host: string, + user: string, + password: string, + database: string, + port: number, +}; + +export default class Database { + private static instance: Database; + private pool: Pool; + + private constructor(config: ConnectionConfig) { + this.pool = createPool(config); + } + + public static getInstance(): Database { + if (!Database.instance) { + Database.instance = new Database({ + host: process.env.DATABASE_HOST as string, + user: process.env.DATABASE_USER as string, + password: process.env.DATABASE_PASSWORD as string, + database: process.env.DATABASE_SCHEMA as string, + port: 3306 + }); + } + + return Database.instance; + } + + public async getConnection(): Promise { + return this.pool.getConnection(); + } +} diff --git a/server/src/models/Channel.ts b/server/src/models/Channel.ts new file mode 100644 index 0000000..64adf08 --- /dev/null +++ b/server/src/models/Channel.ts @@ -0,0 +1,12 @@ +export default class Channel { + private name: string; + private slug: string; + + private constructor(name: string) { + this.name = name; + } + + public static generateSlug(name: string): string { + return name; + } +} diff --git a/server/src/models/User.ts b/server/src/models/User.ts new file mode 100644 index 0000000..96f8b7f --- /dev/null +++ b/server/src/models/User.ts @@ -0,0 +1,8 @@ +type User = { + username: string, + password: string, + + name: string, +}; + +export default User; diff --git a/server/src/routes/user.ts b/server/src/routes/user.ts new file mode 100644 index 0000000..64ba7c7 --- /dev/null +++ b/server/src/routes/user.ts @@ -0,0 +1,38 @@ +import { Hono, Context } from 'hono'; +import { Connection } from 'mariadb'; +import User from '@slovo/models/User'; +import Database from '@slovo/infrastructure/database'; + +const app = new Hono(); + +// add routes and methods here +app.post('/register', async (c: Context) => { + // check if form (from the web app) or JSON (from a blank API call); + let user: User; + if (c.req.header('Content-Type') == 'application/json') { + user = await c.req.json(); + } else { + user = await c.req.formData(); + } + + + const conn: Connection = await Database.getInstance().getConnection(); + const query = `INSERT INTO users (username, password) VALUES (?, ?)`; + + try { + const results = await conn.query(query, [ user.username, user.password ]); + + console.log(results); + return c.json({ + message: "Registration successful.", + }); + } catch (e) { + console.error(e); + c.status(500); + return c.json({ + message: "Error registering user." + }); + } +}); + +export default app; diff --git a/server/src/setup.ts b/server/src/setup.ts new file mode 100644 index 0000000..1275cb8 --- /dev/null +++ b/server/src/setup.ts @@ -0,0 +1,27 @@ +import { createPool } from "mariadb"; + +async function run() { + const pool = createPool({ + host: process.env.DATABASE_HOST, + user: process.env.DATABASE_USER, + password: process.env.DATABASE_PASSWORD, + database: process.env.DATABASE_SCHEMA + }); + + const createUserBuffer: string = await Bun.file('./sql/users.sql').text(); + const conn = await pool.getConnection(); + const results = await conn.query(createUserBuffer); + + return results; +} + +run() + .then(r => { + console.log(r); + process.exit(0); + }) + .catch(e => { + console.error(e); + process.exit(1); + }) + diff --git a/server/tsconfig.json b/server/tsconfig.json new file mode 100644 index 0000000..98da342 --- /dev/null +++ b/server/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "strict": true, + "jsx": "react-jsx", + "jsxImportSource": "hono/jsx" + }, + "paths": { + "@slovo/*": [ "./src/*" ] + } +}