Add complete Cospend expense sharing feature
- Add MongoDB models for Payment and PaymentSplit with proper splitting logic - Implement API routes for CRUD operations and balance calculations - Create dashboard with balance overview and recent activity - Add payment creation form with file upload (using $IMAGE_DIR) - Implement shallow routing with modal side panel for payment details - Support multiple split methods: equal, full payment, custom proportions - Add responsive design for desktop and mobile - Integrate with existing Authentik authentication 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
63
src/routes/api/cospend/upload/+server.ts
Normal file
63
src/routes/api/cospend/upload/+server.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { error, json } from '@sveltejs/kit';
|
||||
import { writeFileSync, mkdirSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { randomUUID } from 'crypto';
|
||||
import { IMAGE_DIR } from '$env/static/private';
|
||||
|
||||
export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
const auth = await locals.auth();
|
||||
if (!auth || !auth.user?.nickname) {
|
||||
throw error(401, 'Not logged in');
|
||||
}
|
||||
|
||||
try {
|
||||
const formData = await request.formData();
|
||||
const image = formData.get('image') as File;
|
||||
|
||||
if (!image) {
|
||||
throw error(400, 'No image provided');
|
||||
}
|
||||
|
||||
const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp'];
|
||||
if (!allowedTypes.includes(image.type)) {
|
||||
throw error(400, 'Invalid file type. Only JPEG, PNG, and WebP are allowed.');
|
||||
}
|
||||
|
||||
if (image.size > 5 * 1024 * 1024) {
|
||||
throw error(400, 'File too large. Maximum size is 5MB.');
|
||||
}
|
||||
|
||||
const extension = image.type.split('/')[1];
|
||||
const filename = `${randomUUID()}.${extension}`;
|
||||
|
||||
if (!IMAGE_DIR) {
|
||||
throw error(500, 'IMAGE_DIR environment variable not configured');
|
||||
}
|
||||
|
||||
// Ensure cospend directory exists in IMAGE_DIR
|
||||
const uploadsDir = join(IMAGE_DIR, 'cospend');
|
||||
try {
|
||||
mkdirSync(uploadsDir, { recursive: true });
|
||||
} catch (err) {
|
||||
// Directory might already exist
|
||||
}
|
||||
|
||||
const filepath = join(uploadsDir, filename);
|
||||
const buffer = await image.arrayBuffer();
|
||||
|
||||
writeFileSync(filepath, new Uint8Array(buffer));
|
||||
|
||||
const publicPath = `/cospend/${filename}`;
|
||||
|
||||
return json({
|
||||
success: true,
|
||||
path: publicPath
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
if (err.status) throw err;
|
||||
console.error('Upload error:', err);
|
||||
throw error(500, 'Failed to upload file');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user