1.0.0
This commit is contained in:
@@ -13,14 +13,12 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
const formData = await request.formData();
|
||||
const registrationEnabled = formData.get('registration_enabled') === 'on';
|
||||
|
||||
// Check if setting exists
|
||||
const existingSetting = await db.select()
|
||||
.from(siteSettings)
|
||||
.where(eq(siteSettings.key, 'registration_enabled'))
|
||||
.get();
|
||||
|
||||
if (existingSetting) {
|
||||
// Update
|
||||
await db.update(siteSettings)
|
||||
.set({
|
||||
value: registrationEnabled ? 'true' : 'false',
|
||||
@@ -28,7 +26,6 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
})
|
||||
.where(eq(siteSettings.key, 'registration_enabled'));
|
||||
} else {
|
||||
// Insert
|
||||
await db.insert(siteSettings).values({
|
||||
id: nanoid(),
|
||||
key: 'registration_enabled',
|
||||
|
||||
@@ -6,11 +6,9 @@ import { eq, count, sql } from 'drizzle-orm';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
export const POST: APIRoute = async ({ request, cookies, redirect }) => {
|
||||
// Check if this is the first user
|
||||
const userCountResult = await db.select({ count: count() }).from(users).get();
|
||||
const isFirstUser = userCountResult ? userCountResult.count === 0 : true;
|
||||
|
||||
// If not first user, check if registration is enabled
|
||||
if (!isFirstUser) {
|
||||
const registrationSetting = await db.select()
|
||||
.from(siteSettings)
|
||||
@@ -33,7 +31,6 @@ export const POST: APIRoute = async ({ request, cookies, redirect }) => {
|
||||
return new Response('Missing fields', { status: 400 });
|
||||
}
|
||||
|
||||
// Check if user exists
|
||||
const existingUser = await db.select().from(users).where(eq(users.email, email)).get();
|
||||
if (existingUser) {
|
||||
return new Response('User already exists', { status: 400 });
|
||||
@@ -42,7 +39,6 @@ export const POST: APIRoute = async ({ request, cookies, redirect }) => {
|
||||
const passwordHash = await hashPassword(password);
|
||||
const userId = nanoid();
|
||||
|
||||
// Create user
|
||||
await db.insert(users).values({
|
||||
id: userId,
|
||||
name,
|
||||
@@ -51,21 +47,18 @@ export const POST: APIRoute = async ({ request, cookies, redirect }) => {
|
||||
isSiteAdmin: isFirstUser,
|
||||
});
|
||||
|
||||
// Create default organization
|
||||
const orgId = nanoid();
|
||||
await db.insert(organizations).values({
|
||||
id: orgId,
|
||||
name: `${name}'s Organization`,
|
||||
});
|
||||
|
||||
// Add user to organization
|
||||
await db.insert(members).values({
|
||||
userId,
|
||||
organizationId: orgId,
|
||||
role: 'owner',
|
||||
});
|
||||
|
||||
// Create session
|
||||
const { sessionId, expiresAt } = await createSession(userId);
|
||||
|
||||
cookies.set('session_id', sessionId, {
|
||||
|
||||
@@ -11,7 +11,6 @@ export const POST: APIRoute = async ({ locals, redirect, params }) => {
|
||||
|
||||
const { id } = params;
|
||||
|
||||
// Get user's organization
|
||||
const userOrg = await db.select()
|
||||
.from(members)
|
||||
.where(eq(members.userId, user.id))
|
||||
@@ -26,7 +25,6 @@ export const POST: APIRoute = async ({ locals, redirect, params }) => {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
// Check if category has time entries
|
||||
const hasEntries = await db.select()
|
||||
.from(timeEntries)
|
||||
.where(eq(timeEntries.categoryId, id!))
|
||||
@@ -36,7 +34,6 @@ export const POST: APIRoute = async ({ locals, redirect, params }) => {
|
||||
return new Response('Cannot delete category with time entries', { status: 400 });
|
||||
}
|
||||
|
||||
// Delete category
|
||||
await db.delete(categories)
|
||||
.where(and(
|
||||
eq(categories.id, id!),
|
||||
|
||||
@@ -18,7 +18,6 @@ export const POST: APIRoute = async ({ request, locals, redirect, params }) => {
|
||||
return new Response('Name is required', { status: 400 });
|
||||
}
|
||||
|
||||
// Get user's organization
|
||||
const userOrg = await db.select()
|
||||
.from(members)
|
||||
.where(eq(members.userId, user.id))
|
||||
@@ -33,7 +32,6 @@ export const POST: APIRoute = async ({ request, locals, redirect, params }) => {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
// Update category
|
||||
await db.update(categories)
|
||||
.set({
|
||||
name,
|
||||
|
||||
@@ -18,7 +18,6 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
return new Response('Name is required', { status: 400 });
|
||||
}
|
||||
|
||||
// Get user's first organization
|
||||
const userOrg = await db.select()
|
||||
.from(members)
|
||||
.where(eq(members.userId, user.id))
|
||||
@@ -28,7 +27,6 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
return new Response('No organization found', { status: 400 });
|
||||
}
|
||||
|
||||
// Create category
|
||||
await db.insert(categories).values({
|
||||
id: nanoid(),
|
||||
organizationId: userOrg.organizationId,
|
||||
|
||||
@@ -18,7 +18,6 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
return new Response('Name is required', { status: 400 });
|
||||
}
|
||||
|
||||
// Get user's first organization
|
||||
const userOrg = await db.select()
|
||||
.from(members)
|
||||
.where(eq(members.userId, user.id))
|
||||
@@ -28,7 +27,6 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
return new Response('No organization found', { status: 400 });
|
||||
}
|
||||
|
||||
// Create client
|
||||
await db.insert(clients).values({
|
||||
id: nanoid(),
|
||||
organizationId: userOrg.organizationId,
|
||||
|
||||
@@ -16,14 +16,12 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
return new Response('Name is required', { status: 400 });
|
||||
}
|
||||
|
||||
// Create organization
|
||||
const orgId = nanoid();
|
||||
await db.insert(organizations).values({
|
||||
id: orgId,
|
||||
name,
|
||||
});
|
||||
|
||||
// Add user as owner
|
||||
await db.insert(members).values({
|
||||
userId: user.id,
|
||||
organizationId: orgId,
|
||||
|
||||
@@ -9,7 +9,6 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
// Check if user is admin
|
||||
const userMembership = await db.select()
|
||||
.from(members)
|
||||
.where(eq(members.userId, user.id))
|
||||
@@ -31,7 +30,6 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
return new Response('Invalid role', { status: 400 });
|
||||
}
|
||||
|
||||
// Can't change owner's role
|
||||
const targetMember = await db.select()
|
||||
.from(members)
|
||||
.where(and(
|
||||
@@ -48,7 +46,6 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
return new Response('Cannot change owner role', { status: 403 });
|
||||
}
|
||||
|
||||
// Update role
|
||||
await db.update(members)
|
||||
.set({ role: newRole })
|
||||
.where(and(
|
||||
|
||||
@@ -9,7 +9,6 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
// Check if user is admin
|
||||
const userMembership = await db.select()
|
||||
.from(members)
|
||||
.where(eq(members.userId, user.id))
|
||||
@@ -31,7 +30,6 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
return new Response('Invalid role', { status: 400 });
|
||||
}
|
||||
|
||||
// Find user by email
|
||||
const invitedUser = await db.select()
|
||||
.from(users)
|
||||
.where(eq(users.email, email))
|
||||
@@ -41,7 +39,6 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
return new Response('User not found. They must create an account first.', { status: 404 });
|
||||
}
|
||||
|
||||
// Check if already a member
|
||||
const existingMember = await db.select()
|
||||
.from(members)
|
||||
.where(and(
|
||||
@@ -54,7 +51,6 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
return new Response('User is already a member', { status: 400 });
|
||||
}
|
||||
|
||||
// Add to organization
|
||||
await db.insert(members).values({
|
||||
userId: invitedUser.id,
|
||||
organizationId: userMembership.organizationId,
|
||||
|
||||
@@ -9,7 +9,6 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
// Check if user is admin
|
||||
const userMembership = await db.select()
|
||||
.from(members)
|
||||
.where(eq(members.userId, user.id))
|
||||
@@ -26,12 +25,10 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
return new Response('Missing user ID', { status: 400 });
|
||||
}
|
||||
|
||||
// Can't remove self
|
||||
if (targetUserId === user.id) {
|
||||
return new Response('Cannot remove yourself', { status: 403 });
|
||||
}
|
||||
|
||||
// Can't remove owner
|
||||
const targetMember = await db.select()
|
||||
.from(members)
|
||||
.where(and(
|
||||
@@ -48,7 +45,6 @@ export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
return new Response('Cannot remove owner', { status: 403 });
|
||||
}
|
||||
|
||||
// Remove member
|
||||
await db.delete(members)
|
||||
.where(and(
|
||||
eq(members.userId, targetUserId),
|
||||
|
||||
@@ -14,7 +14,6 @@ export const POST: APIRoute = async ({ params, locals, redirect }) => {
|
||||
return new Response(JSON.stringify({ error: 'Entry ID required' }), { status: 400 });
|
||||
}
|
||||
|
||||
// Verify the entry belongs to the user
|
||||
const entry = await db.select()
|
||||
.from(timeEntries)
|
||||
.where(and(
|
||||
@@ -27,7 +26,6 @@ export const POST: APIRoute = async ({ params, locals, redirect }) => {
|
||||
return new Response(JSON.stringify({ error: 'Entry not found' }), { status: 404 });
|
||||
}
|
||||
|
||||
// Delete the entry
|
||||
await db.delete(timeEntries)
|
||||
.where(eq(timeEntries.id, entryId))
|
||||
.run();
|
||||
|
||||
@@ -21,7 +21,6 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
||||
return new Response('Category is required', { status: 400 });
|
||||
}
|
||||
|
||||
// Check for running entry
|
||||
const runningEntry = await db.select().from(timeEntries).where(
|
||||
and(
|
||||
eq(timeEntries.userId, locals.user.id),
|
||||
@@ -33,13 +32,11 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
||||
return new Response('Timer already running', { status: 400 });
|
||||
}
|
||||
|
||||
// Get default org (first one)
|
||||
const member = await db.select().from(members).where(eq(members.userId, locals.user.id)).limit(1).get();
|
||||
if (!member) {
|
||||
return new Response('No organization found', { status: 400 });
|
||||
}
|
||||
|
||||
// Verify category belongs to user's organization
|
||||
const category = await db.select().from(categories).where(
|
||||
and(
|
||||
eq(categories.id, categoryId),
|
||||
@@ -64,7 +61,6 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
||||
description,
|
||||
});
|
||||
|
||||
// Add tags if provided
|
||||
if (tags.length > 0) {
|
||||
await db.insert(timeEntryTags).values(
|
||||
tags.map((tagId: string) => ({
|
||||
|
||||
Reference in New Issue
Block a user