mirror of
https://github.com/michivonah/themepark-assistant.git
synced 2025-12-23 06:26:30 +01:00
Compare commits
No commits in common. "3574559eadf8eb2f525ef327a39e66ac3e762eff" and "807e2dc408d5aa63bafe842b8f9c17938ba54e4f" have entirely different histories.
3574559ead
...
807e2dc408
7 changed files with 7 additions and 170 deletions
|
|
@ -16,11 +16,6 @@ apply changes
|
||||||
npx drizzle-kit push --config=drizzle-dev.config.ts
|
npx drizzle-kit push --config=drizzle-dev.config.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
export sql statements instead of running migration
|
|
||||||
```bash
|
|
||||||
npx drizzle-kit export --config=drizzle-dev.config.ts
|
|
||||||
```
|
|
||||||
|
|
||||||
## SQLite / D1
|
## SQLite / D1
|
||||||
Delete view
|
Delete view
|
||||||
```sql
|
```sql
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { check, integer, text, sqliteTable, sqliteView } from "drizzle-orm/sqlite-core";
|
import { integer, text, sqliteTable, sqliteView } from "drizzle-orm/sqlite-core";
|
||||||
import { eq, sql } from "drizzle-orm";
|
import { eq, sql } from "drizzle-orm";
|
||||||
|
|
||||||
// Tables
|
// Tables
|
||||||
|
|
@ -48,15 +48,9 @@ export const themepark = sqliteTable('themepark', {
|
||||||
|
|
||||||
export const user = sqliteTable('user', {
|
export const user = sqliteTable('user', {
|
||||||
id: integer().primaryKey({ autoIncrement: true }),
|
id: integer().primaryKey({ autoIncrement: true }),
|
||||||
mail: text().notNull().unique(),
|
username: text().notNull(),
|
||||||
isActive: integer({ mode: 'boolean' }).notNull().default(false),
|
isActive: integer({ mode: 'boolean' }).default(false)
|
||||||
createdAt: integer().notNull(),
|
})
|
||||||
lastActive: integer().notNull()
|
|
||||||
},
|
|
||||||
(table) => [
|
|
||||||
check("mail_validation", sql`${table.mail} LIKE '%@%'`)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
// Views
|
// Views
|
||||||
export const subscribedThemeparks = sqliteView('subscribed_themeparks').as((qb) =>
|
export const subscribedThemeparks = sqliteView('subscribed_themeparks').as((qb) =>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
import { Hono } from 'hono'
|
import { Hono } from 'hono'
|
||||||
import { authHandler, initAuthConfig, verifyAuth } from '@hono/auth-js'
|
import { authHandler, initAuthConfig, verifyAuth } from '@hono/auth-js'
|
||||||
import { getUser } from './lib/user-auth'
|
|
||||||
import GitHub from '@auth/core/providers/github'
|
import GitHub from '@auth/core/providers/github'
|
||||||
import notification from './routes/notification'
|
import notification from './routes/notification'
|
||||||
import logbook from './routes/logbook'
|
import logbook from './routes/logbook'
|
||||||
import themepark from './routes/themepark'
|
|
||||||
import cronRouter from './jobs/cron'
|
import cronRouter from './jobs/cron'
|
||||||
|
|
||||||
// create app
|
// create app
|
||||||
|
|
@ -26,15 +24,14 @@ app.use('/auth/*', authHandler())
|
||||||
app.use('/*', verifyAuth())
|
app.use('/*', verifyAuth())
|
||||||
|
|
||||||
// example endpoint
|
// example endpoint
|
||||||
app.get('/protected', async (c) => {
|
app.get('/protected', (c) => {
|
||||||
const user = await getUser(c);
|
const auth = c.get('authUser')
|
||||||
return c.json(user);
|
return c.json(auth)
|
||||||
})
|
})
|
||||||
|
|
||||||
// define routes & export app
|
// define routes & export app
|
||||||
app.route('/notification', notification)
|
app.route('/notification', notification)
|
||||||
app.route('/logbook', logbook)
|
app.route('/logbook', logbook)
|
||||||
app.route('/themepark', themepark)
|
|
||||||
export default {
|
export default {
|
||||||
fetch: app.fetch,
|
fetch: app.fetch,
|
||||||
scheduled: cronRouter,
|
scheduled: cronRouter,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
import { cache } from 'hono/cache'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache unit to use for multiple endpoints as needed
|
|
||||||
*/
|
|
||||||
export const responseCache = cache({
|
|
||||||
cacheName: 'themepark-assistant',
|
|
||||||
cacheControl: 'max-age=86400'
|
|
||||||
});
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
import { getDbContext } from "../db/client";
|
|
||||||
import { Context } from "hono";
|
|
||||||
import { UserSelect } from "../types/user";
|
|
||||||
import { user } from "../db/schema";
|
|
||||||
import { like } from "drizzle-orm";
|
|
||||||
import { DrizzleD1Database } from "drizzle-orm/d1";
|
|
||||||
import { MissingMailError, UserInactiveError, DatabaseError } from "../types/error";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the details of a user from the given context
|
|
||||||
* @param c Request context
|
|
||||||
* @returns Object of the user details as type UserSelect
|
|
||||||
*/
|
|
||||||
export async function getUser(c: Context): Promise<UserSelect>{
|
|
||||||
const db = getDbContext(c);
|
|
||||||
const auth = c.get('authUser');
|
|
||||||
if(!auth.session.user || !auth.session.user.email) throw new MissingMailError();
|
|
||||||
|
|
||||||
const currentUser: UserSelect = c.get('currentUser');
|
|
||||||
if(currentUser) return currentUser;
|
|
||||||
|
|
||||||
const mail = auth.session.user.email;
|
|
||||||
|
|
||||||
let userData: UserSelect[];
|
|
||||||
try{
|
|
||||||
userData = await db.selectDistinct().from(user).limit(1).where(like(user.mail, mail));
|
|
||||||
|
|
||||||
}
|
|
||||||
catch(e){
|
|
||||||
throw new DatabaseError();
|
|
||||||
}
|
|
||||||
|
|
||||||
const dbResult = userData[0] ?? await createUser(db, mail);
|
|
||||||
if(!dbResult.isActive) throw new UserInactiveError();
|
|
||||||
|
|
||||||
c.set('currentUser', dbResult);
|
|
||||||
return dbResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new user in the DB from the given context
|
|
||||||
* @param c Request context
|
|
||||||
* @returns The created user as Object of type UserSelect
|
|
||||||
*/
|
|
||||||
async function createUser(db: DrizzleD1Database, userMail: string): Promise<UserSelect>{
|
|
||||||
let userData: UserSelect[];
|
|
||||||
|
|
||||||
try{
|
|
||||||
userData = await db.insert(user).values(
|
|
||||||
{
|
|
||||||
mail: userMail,
|
|
||||||
isActive: true,
|
|
||||||
createdAt: now(),
|
|
||||||
lastActive: now()
|
|
||||||
}
|
|
||||||
).returning();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch(e){
|
|
||||||
throw new DatabaseError();
|
|
||||||
}
|
|
||||||
|
|
||||||
return userData[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getting the current time
|
|
||||||
* @returns Current unix timestamp
|
|
||||||
*/
|
|
||||||
const now = () => Math.floor(Date.now() / 1000);
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
import { Hono } from 'hono'
|
|
||||||
import { getDbContext } from '../db/client'
|
|
||||||
import { themepark, attraction } from '../db/schema'
|
|
||||||
import { responseCache } from '../lib/cache'
|
|
||||||
import { eq } from 'drizzle-orm'
|
|
||||||
import { DatabaseError } from '../types/error'
|
|
||||||
|
|
||||||
const app = new Hono()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lists all available themeparks with their id, name & countrycode
|
|
||||||
*/
|
|
||||||
app.get('/list', responseCache, async (c) => {
|
|
||||||
const db = getDbContext(c)
|
|
||||||
|
|
||||||
try{
|
|
||||||
const themeparks = await db.select({
|
|
||||||
id: themepark.id,
|
|
||||||
name: themepark.name,
|
|
||||||
countrycode: themepark.countrycode
|
|
||||||
}).from(themepark);
|
|
||||||
|
|
||||||
return c.json(themeparks);
|
|
||||||
}
|
|
||||||
catch{
|
|
||||||
throw new DatabaseError();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lists all attractions from a themepark with their id & name
|
|
||||||
*/
|
|
||||||
app.get('/list/:id/attraction', responseCache, async (c) => {
|
|
||||||
const parkId = parseInt(c.req.param('id'));
|
|
||||||
const db = getDbContext(c)
|
|
||||||
|
|
||||||
try{
|
|
||||||
const attractions = await db.select({
|
|
||||||
id: attraction.id,
|
|
||||||
name: attraction.name,
|
|
||||||
}).from(attraction)
|
|
||||||
.where(eq(attraction.themeparkId, parkId));
|
|
||||||
|
|
||||||
return c.json(attractions);
|
|
||||||
}
|
|
||||||
catch{
|
|
||||||
throw new DatabaseError();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export default app
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
import { HTTPException } from "hono/http-exception";
|
|
||||||
|
|
||||||
export class UserInactiveError extends HTTPException{
|
|
||||||
constructor(){
|
|
||||||
super(403, { message: 'User is currently disabled.' })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MissingMailError extends HTTPException{
|
|
||||||
constructor(){
|
|
||||||
super(400, { message: 'Mail address is missing in authorizaton header.' })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DatabaseError extends HTTPException{
|
|
||||||
constructor(){
|
|
||||||
super(500, { message: 'Internal Database Error' })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue