Fixed a number of issues
This commit is contained in:
71
src/pages/api/clients/[id]/delete.ts
Normal file
71
src/pages/api/clients/[id]/delete.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import type { APIRoute } from 'astro';
|
||||
import { db } from '../../../../db';
|
||||
import { clients, members, timeEntries, timeEntryTags } from '../../../../db/schema';
|
||||
import { eq, and, inArray } from 'drizzle-orm';
|
||||
|
||||
export const POST: APIRoute = async ({ params, locals, redirect }) => {
|
||||
const user = locals.user;
|
||||
if (!user) {
|
||||
return redirect('/login');
|
||||
}
|
||||
|
||||
const { id } = params;
|
||||
if (!id) {
|
||||
return new Response('Client ID is required', { status: 400 });
|
||||
}
|
||||
|
||||
try {
|
||||
// Get the client to check organization ownership
|
||||
const client = await db.select()
|
||||
.from(clients)
|
||||
.where(eq(clients.id, id))
|
||||
.get();
|
||||
|
||||
if (!client) {
|
||||
return new Response('Client not found', { status: 404 });
|
||||
}
|
||||
|
||||
// Verify user is a member of the organization
|
||||
const membership = await db.select()
|
||||
.from(members)
|
||||
.where(and(
|
||||
eq(members.userId, user.id),
|
||||
eq(members.organizationId, client.organizationId)
|
||||
))
|
||||
.get();
|
||||
|
||||
if (!membership) {
|
||||
return new Response('Not authorized', { status: 403 });
|
||||
}
|
||||
|
||||
// Find all time entries for this client to clean up tags
|
||||
const clientEntries = await db.select({ id: timeEntries.id })
|
||||
.from(timeEntries)
|
||||
.where(eq(timeEntries.clientId, id))
|
||||
.all();
|
||||
|
||||
const entryIds = clientEntries.map(e => e.id);
|
||||
|
||||
if (entryIds.length > 0) {
|
||||
// Delete tags associated with these entries
|
||||
await db.delete(timeEntryTags)
|
||||
.where(inArray(timeEntryTags.timeEntryId, entryIds))
|
||||
.run();
|
||||
|
||||
// Delete the time entries
|
||||
await db.delete(timeEntries)
|
||||
.where(eq(timeEntries.clientId, id))
|
||||
.run();
|
||||
}
|
||||
|
||||
// Delete the client
|
||||
await db.delete(clients)
|
||||
.where(eq(clients.id, id))
|
||||
.run();
|
||||
|
||||
return redirect('/dashboard/clients');
|
||||
} catch (error) {
|
||||
console.error('Error deleting client:', error);
|
||||
return new Response('Failed to delete client', { status: 500 });
|
||||
}
|
||||
};
|
||||
68
src/pages/api/clients/[id]/update.ts
Normal file
68
src/pages/api/clients/[id]/update.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import { db } from "../../../../db";
|
||||
import { clients, members } from "../../../../db/schema";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
|
||||
export const POST: APIRoute = async ({ request, params, locals, redirect }) => {
|
||||
const user = locals.user;
|
||||
if (!user) {
|
||||
return redirect("/login");
|
||||
}
|
||||
|
||||
const { id } = params;
|
||||
if (!id) {
|
||||
return new Response("Client ID is required", { status: 400 });
|
||||
}
|
||||
|
||||
const formData = await request.formData();
|
||||
const name = formData.get("name") as string;
|
||||
const email = formData.get("email") as string;
|
||||
|
||||
if (!name || name.trim().length === 0) {
|
||||
return new Response("Client name is required", { status: 400 });
|
||||
}
|
||||
|
||||
try {
|
||||
// Get the client to check organization ownership
|
||||
const client = await db
|
||||
.select()
|
||||
.from(clients)
|
||||
.where(eq(clients.id, id))
|
||||
.get();
|
||||
|
||||
if (!client) {
|
||||
return new Response("Client not found", { status: 404 });
|
||||
}
|
||||
|
||||
// Verify user is a member of the organization
|
||||
const membership = await db
|
||||
.select()
|
||||
.from(members)
|
||||
.where(
|
||||
and(
|
||||
eq(members.userId, user.id),
|
||||
eq(members.organizationId, client.organizationId),
|
||||
),
|
||||
)
|
||||
.get();
|
||||
|
||||
if (!membership) {
|
||||
return new Response("Not authorized", { status: 403 });
|
||||
}
|
||||
|
||||
// Update client
|
||||
await db
|
||||
.update(clients)
|
||||
.set({
|
||||
name: name.trim(),
|
||||
email: email?.trim() || null,
|
||||
})
|
||||
.where(eq(clients.id, id))
|
||||
.run();
|
||||
|
||||
return redirect(`/dashboard/clients/${id}`);
|
||||
} catch (error) {
|
||||
console.error("Error updating client:", error);
|
||||
return new Response("Failed to update client", { status: 500 });
|
||||
}
|
||||
};
|
||||
@@ -1,47 +1,59 @@
|
||||
import type { APIRoute } from 'astro';
|
||||
import { db } from '../../../db';
|
||||
import { organizations, members } from '../../../db/schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import type { APIRoute } from "astro";
|
||||
import { db } from "../../../db";
|
||||
import { organizations, members } from "../../../db/schema";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
|
||||
export const POST: APIRoute = async ({ request, locals, redirect }) => {
|
||||
const user = locals.user;
|
||||
if (!user) {
|
||||
return redirect('/login');
|
||||
return redirect("/login");
|
||||
}
|
||||
|
||||
const formData = await request.formData();
|
||||
const organizationId = formData.get('organizationId') as string;
|
||||
const name = formData.get('name') as string;
|
||||
const organizationId = formData.get("organizationId") as string;
|
||||
const name = formData.get("name") as string;
|
||||
|
||||
if (!organizationId || !name || name.trim().length === 0) {
|
||||
return new Response('Organization ID and name are required', { status: 400 });
|
||||
return new Response("Organization ID and name are required", {
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
// Verify user is admin/owner of this organization
|
||||
const membership = await db.select()
|
||||
const membership = await db
|
||||
.select()
|
||||
.from(members)
|
||||
.where(eq(members.userId, user.id))
|
||||
.where(
|
||||
and(
|
||||
eq(members.userId, user.id),
|
||||
eq(members.organizationId, organizationId),
|
||||
),
|
||||
)
|
||||
.get();
|
||||
|
||||
if (!membership || membership.organizationId !== organizationId) {
|
||||
return new Response('Not authorized', { status: 403 });
|
||||
if (!membership) {
|
||||
return new Response("Not authorized", { status: 403 });
|
||||
}
|
||||
|
||||
const isAdmin = membership.role === 'owner' || membership.role === 'admin';
|
||||
const isAdmin = membership.role === "owner" || membership.role === "admin";
|
||||
if (!isAdmin) {
|
||||
return new Response('Only owners and admins can update organization settings', { status: 403 });
|
||||
return new Response(
|
||||
"Only owners and admins can update organization settings",
|
||||
{ status: 403 },
|
||||
);
|
||||
}
|
||||
|
||||
// Update organization name
|
||||
await db.update(organizations)
|
||||
await db
|
||||
.update(organizations)
|
||||
.set({ name: name.trim() })
|
||||
.where(eq(organizations.id, organizationId))
|
||||
.run();
|
||||
|
||||
return redirect('/dashboard/team/settings?success=org-name');
|
||||
return redirect("/dashboard/team/settings?success=org-name");
|
||||
} catch (error) {
|
||||
console.error('Error updating organization name:', error);
|
||||
return new Response('Failed to update organization name', { status: 500 });
|
||||
console.error("Error updating organization name:", error);
|
||||
return new Response("Failed to update organization name", { status: 500 });
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user