First Commit
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
import { eq } from 'drizzle-orm'
|
||||
import { createHash, randomUUID } from 'node:crypto'
|
||||
import type { AppDb } from './index.js'
|
||||
import {
|
||||
refreshSessions,
|
||||
userApps,
|
||||
userPermissions,
|
||||
users,
|
||||
} from './schema/index.js'
|
||||
|
||||
export type UserRow = typeof users.$inferSelect
|
||||
|
||||
export function hashToken(token: string): string {
|
||||
return createHash('sha256').update(token).digest('hex')
|
||||
}
|
||||
|
||||
export function listUsers(db: AppDb): UserRow[] {
|
||||
return db.select().from(users).all()
|
||||
}
|
||||
|
||||
export function getUserById(db: AppDb, id: string): UserRow | undefined {
|
||||
return db.select().from(users).where(eq(users.id, id)).get()
|
||||
}
|
||||
|
||||
export function getUserByEmail(
|
||||
db: AppDb,
|
||||
email: string,
|
||||
): UserRow | undefined {
|
||||
return db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.email, email.toLowerCase()))
|
||||
.get()
|
||||
}
|
||||
|
||||
export function getUserApps(db: AppDb, userId: string): string[] {
|
||||
return db
|
||||
.select()
|
||||
.from(userApps)
|
||||
.where(eq(userApps.userId, userId))
|
||||
.all()
|
||||
.map((r) => r.appId)
|
||||
}
|
||||
|
||||
export function getUserPermissions(db: AppDb, userId: string): string[] {
|
||||
return db
|
||||
.select()
|
||||
.from(userPermissions)
|
||||
.where(eq(userPermissions.userId, userId))
|
||||
.all()
|
||||
.map((r) => r.permission)
|
||||
}
|
||||
|
||||
export function createUser(
|
||||
db: AppDb,
|
||||
input: {
|
||||
email: string
|
||||
name: string
|
||||
passwordHash: string
|
||||
isAdmin: boolean
|
||||
},
|
||||
): UserRow {
|
||||
const now = new Date().toISOString()
|
||||
const id = randomUUID()
|
||||
db.insert(users)
|
||||
.values({
|
||||
id,
|
||||
email: input.email.toLowerCase(),
|
||||
name: input.name,
|
||||
passwordHash: input.passwordHash,
|
||||
isAdmin: input.isAdmin,
|
||||
disabled: false,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
})
|
||||
.run()
|
||||
return getUserById(db, id)!
|
||||
}
|
||||
|
||||
export function updateUser(
|
||||
db: AppDb,
|
||||
id: string,
|
||||
patch: {
|
||||
email?: string
|
||||
name?: string
|
||||
passwordHash?: string
|
||||
isAdmin?: boolean
|
||||
disabled?: boolean
|
||||
},
|
||||
): UserRow | undefined {
|
||||
const existing = getUserById(db, id)
|
||||
if (!existing) return undefined
|
||||
const now = new Date().toISOString()
|
||||
db.update(users)
|
||||
.set({
|
||||
email: patch.email?.toLowerCase() ?? existing.email,
|
||||
name: patch.name ?? existing.name,
|
||||
passwordHash: patch.passwordHash ?? existing.passwordHash,
|
||||
isAdmin: patch.isAdmin ?? existing.isAdmin,
|
||||
disabled: patch.disabled ?? existing.disabled,
|
||||
updatedAt: now,
|
||||
})
|
||||
.where(eq(users.id, id))
|
||||
.run()
|
||||
return getUserById(db, id)
|
||||
}
|
||||
|
||||
export function deleteUser(db: AppDb, id: string): boolean {
|
||||
const result = db.delete(users).where(eq(users.id, id)).run()
|
||||
return result.changes > 0
|
||||
}
|
||||
|
||||
export function setUserAccess(
|
||||
db: AppDb,
|
||||
userId: string,
|
||||
apps: string[],
|
||||
permissions: string[],
|
||||
): void {
|
||||
db.delete(userApps).where(eq(userApps.userId, userId)).run()
|
||||
db.delete(userPermissions).where(eq(userPermissions.userId, userId)).run()
|
||||
for (const appId of apps) {
|
||||
db.insert(userApps).values({ userId, appId }).run()
|
||||
}
|
||||
for (const permission of permissions) {
|
||||
db.insert(userPermissions).values({ userId, permission }).run()
|
||||
}
|
||||
db.update(users)
|
||||
.set({ updatedAt: new Date().toISOString() })
|
||||
.where(eq(users.id, userId))
|
||||
.run()
|
||||
}
|
||||
|
||||
export function createRefreshSession(
|
||||
db: AppDb,
|
||||
userId: string,
|
||||
rawToken: string,
|
||||
expiresAt: Date,
|
||||
): void {
|
||||
db.insert(refreshSessions)
|
||||
.values({
|
||||
id: randomUUID(),
|
||||
userId,
|
||||
tokenHash: hashToken(rawToken),
|
||||
expiresAt: expiresAt.toISOString(),
|
||||
revokedAt: null,
|
||||
createdAt: new Date().toISOString(),
|
||||
})
|
||||
.run()
|
||||
}
|
||||
|
||||
export function revokeRefreshSession(db: AppDb, rawToken: string): void {
|
||||
const now = new Date().toISOString()
|
||||
db.update(refreshSessions)
|
||||
.set({ revokedAt: now })
|
||||
.where(eq(refreshSessions.tokenHash, hashToken(rawToken)))
|
||||
.run()
|
||||
}
|
||||
Reference in New Issue
Block a user