init slovocast API later.

This commit is contained in:
Dave Smith-Hayes 2024-02-16 18:19:58 -05:00
commit 2258b651de
16 changed files with 248 additions and 0 deletions

16
docker-compose.yml Normal file
View File

@ -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:

0
frontend/.gitkeep Normal file
View File

4
server/.env Normal file
View File

@ -0,0 +1,4 @@
DATABASE_HOST=localhost
DATABASE_USER=user
DATABASE_PASSWORD=password
DATABASE_SCHEMA=slovocast

1
server/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

11
server/README.md Normal file
View File

@ -0,0 +1,11 @@
To install dependencies:
```sh
bun install
```
To run:
```sh
bun run dev
```
open http://localhost:3000

BIN
server/bun.lockb Executable file

Binary file not shown.

13
server/package.json Normal file
View File

@ -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"
}
}

View File

@ -0,0 +1 @@
DROP TABLE IF EXISTS users;

10
server/sql/users.sql Normal file
View File

@ -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`)
);

61
server/src/index.ts Normal file
View File

@ -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;

View File

@ -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<Connection> {
return this.pool.getConnection();
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,8 @@
type User = {
username: string,
password: string,
name: string,
};
export default User;

38
server/src/routes/user.ts Normal file
View File

@ -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<User>();
} else {
user = await c.req.formData<User>();
}
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;

27
server/src/setup.ts Normal file
View File

@ -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);
})

10
server/tsconfig.json Normal file
View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"strict": true,
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx"
},
"paths": {
"@slovo/*": [ "./src/*" ]
}
}