import { v } from "convex/values"; import { query, mutation, action } from "./_generated/server"; export const getCurrentUser = query({ args: { token: v.optional(v.string()) }, handler: async (ctx, args) => { if (!args.token) return null; const session = await ctx.db .query("sessions") .withIndex("by_token", (q) => q.eq("token", args.token!)) .first(); if (!session) return null; const user = await ctx.db.get(session.userId); return user || null; }, }); export const login = mutation({ args: { email: v.string(), passwordHash: v.string() }, handler: async (ctx, args) => { const account = await ctx.db .query("accounts") .withIndex("by_provider_email", (q) => q.eq("provider", "password").eq("providerId", args.email) ) .first(); if (!account) throw new Error("Погрешна е-пошта или лозинка"); const user = await ctx.db.get(account.userId); if (!user) throw new Error("Корисникот не е пронајден"); if (account.secret !== args.passwordHash) throw new Error("Погрешна е-пошта или лозинка"); const token = crypto.randomUUID(); await ctx.db.insert("sessions", { userId: user._id, token, expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1000, createdAt: Date.now(), }); return { token, user }; }, }); export const register = mutation({ args: { name: v.string(), email: v.string(), passwordHash: v.string(), role: v.string(), phone: v.optional(v.string()), }, handler: async (ctx, args) => { const existing = await ctx.db .query("accounts") .withIndex("by_provider_email", (q) => q.eq("provider", "password").eq("providerId", args.email) ) .first(); if (existing) throw new Error("Е-поштата е веќе регистрирана"); const userId = await ctx.db.insert("users", { name: args.name, email: args.email, phone: args.phone, role: args.role, reviewCount: 0, createdAt: Date.now(), }); await ctx.db.insert("accounts", { userId, provider: "password", providerId: args.email, secret: args.passwordHash, createdAt: Date.now(), }); const token = crypto.randomUUID(); await ctx.db.insert("sessions", { userId, token, expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1000, createdAt: Date.now(), }); const user = await ctx.db.get(userId); return { token, user }; }, }); export const logout = mutation({ args: { token: v.string() }, handler: async (ctx, args) => { const session = await ctx.db .query("sessions") .withIndex("by_token", (q) => q.eq("token", args.token)) .first(); if (session) { await ctx.db.delete(session._id); } }, }); export const hashPassword = action({ args: { password: v.string() }, handler: async (_ctx, args) => { const encoder = new TextEncoder(); const data = encoder.encode(args.password); const hashBuffer = await crypto.subtle.digest("SHA-256", data); const hashArray = Array.from(new Uint8Array(hashBuffer)); return hashArray.map((b) => b.toString(16).padStart(2, "0")).join(""); }, });