72 lines
2.7 KiB
TypeScript
72 lines
2.7 KiB
TypeScript
|
|
/**
|
|||
|
|
* Project Share Routes – invite users to projects
|
|||
|
|
*/
|
|||
|
|
import type { FastifyInstance } from 'fastify';
|
|||
|
|
import type { DatabaseInterface } from '../database/DatabaseInterface.js';
|
|||
|
|
import { requireAuth } from '../auth/authMiddleware.js';
|
|||
|
|
import type { AuthService } from '../auth/AuthService.js';
|
|||
|
|
|
|||
|
|
export function registerShareRoutes(fastify: FastifyInstance, db: DatabaseInterface, authService: AuthService) {
|
|||
|
|
// List shares for a project
|
|||
|
|
fastify.get('/api/projects/:projectId/shares', async (request, reply) => {
|
|||
|
|
const user = requireAuth(request, reply, authService);
|
|||
|
|
if (!user) return;
|
|||
|
|
const { projectId } = request.params as { projectId: string };
|
|||
|
|
return db.listProjectShares(projectId);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Create a share / invite by email
|
|||
|
|
fastify.post('/api/projects/:projectId/shares', async (request, reply) => {
|
|||
|
|
const user = requireAuth(request, reply, authService);
|
|||
|
|
if (!user) return;
|
|||
|
|
const { projectId } = request.params as { projectId: string };
|
|||
|
|
const body = request.body as { email: string };
|
|||
|
|
if (!body.email) return reply.code(400).send({ error: 'Email is required' });
|
|||
|
|
const share = db.createProjectShare({
|
|||
|
|
project_id: projectId,
|
|||
|
|
shared_by_user_id: user.id,
|
|||
|
|
shared_with_email: body.email,
|
|||
|
|
});
|
|||
|
|
// Create a notification for the invited user if they exist
|
|||
|
|
const invitedUser = db.getUserByEmail(body.email);
|
|||
|
|
if (invitedUser) {
|
|||
|
|
db.createNotification({
|
|||
|
|
user_id: invitedUser.id,
|
|||
|
|
project_id: projectId,
|
|||
|
|
type: 'share',
|
|||
|
|
title: 'Projekt-Einladung',
|
|||
|
|
message: `${user.name} hat Sie zum Projekt eingeladen`,
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
return share;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Get share by token (public, no auth required)
|
|||
|
|
fastify.get('/api/shares/:token', async (request, reply) => {
|
|||
|
|
const { token } = request.params as { token: string };
|
|||
|
|
const share = db.getProjectShareByToken(token);
|
|||
|
|
if (!share) return reply.code(404).send({ error: 'Share not found' });
|
|||
|
|
return share;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Accept a share by token
|
|||
|
|
fastify.put('/api/shares/:token/accept', async (request, reply) => {
|
|||
|
|
const user = requireAuth(request, reply, authService);
|
|||
|
|
if (!user) return;
|
|||
|
|
const { token } = request.params as { token: string };
|
|||
|
|
const ok = db.acceptProjectShare(token);
|
|||
|
|
if (!ok) return reply.code(404).send({ error: 'Share not found' });
|
|||
|
|
return { success: true };
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Revoke a share
|
|||
|
|
fastify.delete('/api/shares/:id', async (request, reply) => {
|
|||
|
|
const user = requireAuth(request, reply, authService);
|
|||
|
|
if (!user) return;
|
|||
|
|
const { id } = request.params as { id: string };
|
|||
|
|
const ok = db.deleteProjectShare(id);
|
|||
|
|
if (!ok) return reply.code(404).send({ error: 'Share not found' });
|
|||
|
|
return { success: true };
|
|||
|
|
});
|
|||
|
|
}
|