Initial commit: deardiary project setup
This commit is contained in:
166
backend/src/routes/entries.ts
Normal file
166
backend/src/routes/entries.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import { Hono } from 'hono';
|
||||
import { HonoEnv } from '../lib/types';
|
||||
|
||||
export const entriesRoutes = new Hono<HonoEnv>();
|
||||
|
||||
entriesRoutes.post('/', async (c) => {
|
||||
const userId = c.get('userId');
|
||||
const prisma = c.get('prisma');
|
||||
const mediaDir = c.env.MEDIA_DIR || './data/media';
|
||||
|
||||
const body = await c.req.json();
|
||||
const { date, type, content, metadata } = body;
|
||||
|
||||
if (!date || !type || !content) {
|
||||
return c.json({ data: null, error: { code: 'VALIDATION_ERROR', message: 'date, type, and content are required' } }, 400);
|
||||
}
|
||||
|
||||
const validTypes = ['text', 'voice', 'photo', 'health', 'location'];
|
||||
if (!validTypes.includes(type)) {
|
||||
return c.json({ data: null, error: { code: 'VALIDATION_ERROR', message: `type must be one of: ${validTypes.join(', ')}` } }, 400);
|
||||
}
|
||||
|
||||
const entry = await prisma.entry.create({
|
||||
data: {
|
||||
userId,
|
||||
date,
|
||||
type,
|
||||
content,
|
||||
metadata: metadata ? JSON.stringify(metadata) : null,
|
||||
},
|
||||
});
|
||||
|
||||
return c.json({ data: entry, error: null }, 201);
|
||||
});
|
||||
|
||||
entriesRoutes.get('/:id', async (c) => {
|
||||
const userId = c.get('userId');
|
||||
const { id } = c.req.param();
|
||||
const prisma = c.get('prisma');
|
||||
|
||||
const entry = await prisma.entry.findFirst({
|
||||
where: { id, userId },
|
||||
});
|
||||
|
||||
if (!entry) {
|
||||
return c.json({ data: null, error: { code: 'NOT_FOUND', message: 'Entry not found' } }, 404);
|
||||
}
|
||||
|
||||
return c.json({ data: entry, error: null });
|
||||
});
|
||||
|
||||
entriesRoutes.put('/:id', async (c) => {
|
||||
const userId = c.get('userId');
|
||||
const { id } = c.req.param();
|
||||
const prisma = c.get('prisma');
|
||||
|
||||
const body = await c.req.json();
|
||||
const { content, metadata } = body;
|
||||
|
||||
const existing = await prisma.entry.findFirst({
|
||||
where: { id, userId },
|
||||
});
|
||||
|
||||
if (!existing) {
|
||||
return c.json({ data: null, error: { code: 'NOT_FOUND', message: 'Entry not found' } }, 404);
|
||||
}
|
||||
|
||||
const entry = await prisma.entry.update({
|
||||
where: { id },
|
||||
data: {
|
||||
content: content ?? existing.content,
|
||||
metadata: metadata !== undefined ? JSON.stringify(metadata) : existing.metadata,
|
||||
},
|
||||
});
|
||||
|
||||
return c.json({ data: entry, error: null });
|
||||
});
|
||||
|
||||
entriesRoutes.delete('/:id', async (c) => {
|
||||
const userId = c.get('userId');
|
||||
const { id } = c.req.param();
|
||||
const prisma = c.get('prisma');
|
||||
|
||||
const existing = await prisma.entry.findFirst({
|
||||
where: { id, userId },
|
||||
});
|
||||
|
||||
if (!existing) {
|
||||
return c.json({ data: null, error: { code: 'NOT_FOUND', message: 'Entry not found' } }, 404);
|
||||
}
|
||||
|
||||
await prisma.entry.delete({ where: { id } });
|
||||
|
||||
return c.json({ data: { deleted: true }, error: null });
|
||||
});
|
||||
|
||||
entriesRoutes.post('/:id/photo', async (c) => {
|
||||
const userId = c.get('userId');
|
||||
const { id } = c.req.param();
|
||||
const prisma = c.get('prisma');
|
||||
const mediaDir = c.env.MEDIA_DIR || './data/media';
|
||||
|
||||
const entry = await prisma.entry.findFirst({
|
||||
where: { id, userId },
|
||||
});
|
||||
|
||||
if (!entry) {
|
||||
return c.json({ data: null, error: { code: 'NOT_FOUND', message: 'Entry not found' } }, 404);
|
||||
}
|
||||
|
||||
const body = await c.req.parseBody();
|
||||
const file = body.file;
|
||||
|
||||
if (!file || !(file instanceof File)) {
|
||||
return c.json({ data: null, error: { code: 'VALIDATION_ERROR', message: 'No file provided' } }, 400);
|
||||
}
|
||||
|
||||
const ext = file.name.split('.').pop() || 'jpg';
|
||||
const fileName = `${id}.${ext}`;
|
||||
const userMediaDir = `${mediaDir}/${userId}/${entry.date}`;
|
||||
const filePath = `${userMediaDir}/${fileName}`;
|
||||
|
||||
await Bun.write(filePath, file);
|
||||
|
||||
await prisma.entry.update({
|
||||
where: { id },
|
||||
data: { mediaPath: filePath },
|
||||
});
|
||||
|
||||
return c.json({ data: { mediaPath: filePath }, error: null }, 201);
|
||||
});
|
||||
|
||||
entriesRoutes.post('/:id/voice', async (c) => {
|
||||
const userId = c.get('userId');
|
||||
const { id } = c.req.param();
|
||||
const prisma = c.get('prisma');
|
||||
const mediaDir = c.env.MEDIA_DIR || './data/media';
|
||||
|
||||
const entry = await prisma.entry.findFirst({
|
||||
where: { id, userId },
|
||||
});
|
||||
|
||||
if (!entry) {
|
||||
return c.json({ data: null, error: { code: 'NOT_FOUND', message: 'Entry not found' } }, 404);
|
||||
}
|
||||
|
||||
const body = await c.req.parseBody();
|
||||
const file = body.file;
|
||||
|
||||
if (!file || !(file instanceof File)) {
|
||||
return c.json({ data: null, error: { code: 'VALIDATION_ERROR', message: 'No audio file provided' } }, 400);
|
||||
}
|
||||
|
||||
const fileName = `${id}.webm`;
|
||||
const userMediaDir = `${mediaDir}/${userId}/${entry.date}`;
|
||||
const filePath = `${userMediaDir}/${fileName}`;
|
||||
|
||||
await Bun.write(filePath, file);
|
||||
|
||||
await prisma.entry.update({
|
||||
where: { id },
|
||||
data: { mediaPath: filePath },
|
||||
});
|
||||
|
||||
return c.json({ data: { mediaPath: filePath }, error: null }, 201);
|
||||
});
|
||||
Reference in New Issue
Block a user