108 lines
2.5 KiB
TypeScript
108 lines
2.5 KiB
TypeScript
// @ts-nocheck
|
|
import { mutation, query } from "./_generated/server"
|
|
import { v } from "convex/values"
|
|
|
|
export const ensureAdminUser = mutation({
|
|
args: {
|
|
email: v.string(),
|
|
name: v.optional(v.string()),
|
|
},
|
|
handler: async (ctx, args) => {
|
|
const existing = await ctx.db
|
|
.query("adminUsers")
|
|
.withIndex("by_email", (q) => q.eq("email", args.email))
|
|
.unique()
|
|
const now = Date.now()
|
|
|
|
if (existing) {
|
|
await ctx.db.patch(existing._id, {
|
|
active: true,
|
|
name: args.name ?? existing.name,
|
|
updatedAt: now,
|
|
lastLoginAt: now,
|
|
})
|
|
return await ctx.db.get(existing._id)
|
|
}
|
|
|
|
const id = await ctx.db.insert("adminUsers", {
|
|
email: args.email,
|
|
name: args.name,
|
|
role: "admin",
|
|
active: true,
|
|
createdAt: now,
|
|
updatedAt: now,
|
|
lastLoginAt: now,
|
|
})
|
|
return await ctx.db.get(id)
|
|
},
|
|
})
|
|
|
|
export const createSession = mutation({
|
|
args: {
|
|
email: v.string(),
|
|
tokenHash: v.string(),
|
|
expiresAt: v.number(),
|
|
},
|
|
handler: async (ctx, args) => {
|
|
const user = await ctx.db
|
|
.query("adminUsers")
|
|
.withIndex("by_email", (q) => q.eq("email", args.email))
|
|
.unique()
|
|
if (!user) {
|
|
throw new Error("Admin user not found")
|
|
}
|
|
|
|
const id = await ctx.db.insert("adminSessions", {
|
|
adminUserId: user._id,
|
|
tokenHash: args.tokenHash,
|
|
expiresAt: args.expiresAt,
|
|
createdAt: Date.now(),
|
|
})
|
|
return { sessionId: id, user }
|
|
},
|
|
})
|
|
|
|
export const destroySession = mutation({
|
|
args: {
|
|
tokenHash: v.string(),
|
|
},
|
|
handler: async (ctx, args) => {
|
|
const session = await ctx.db
|
|
.query("adminSessions")
|
|
.withIndex("by_tokenHash", (q) => q.eq("tokenHash", args.tokenHash))
|
|
.unique()
|
|
if (session) {
|
|
await ctx.db.delete(session._id)
|
|
}
|
|
return { success: true }
|
|
},
|
|
})
|
|
|
|
export const validateSession = query({
|
|
args: {
|
|
tokenHash: v.string(),
|
|
},
|
|
handler: async (ctx, args) => {
|
|
const session = await ctx.db
|
|
.query("adminSessions")
|
|
.withIndex("by_tokenHash", (q) => q.eq("tokenHash", args.tokenHash))
|
|
.unique()
|
|
if (!session || session.expiresAt < Date.now()) {
|
|
return null
|
|
}
|
|
const user = await ctx.db.get(session.adminUserId)
|
|
if (!user || !user.active) {
|
|
return null
|
|
}
|
|
return {
|
|
user: {
|
|
id: user._id,
|
|
email: user.email,
|
|
name: user.name,
|
|
role: user.role,
|
|
},
|
|
sessionId: session._id,
|
|
expiresAt: session.expiresAt,
|
|
}
|
|
},
|
|
})
|