File size: 4,144 Bytes
eeb9404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
 * Admin Workspaces API
 * GET — list all workspaces with stats
 * POST — create a new workspace
 */

import { NextRequest, NextResponse } from 'next/server';
import { requireAuth, verifyInstanceApiKey } from '@/lib/auth/session';
import {
  listWorkspaces,
  createWorkspace,
  grantWorkspaceAccess,
  getUserByEmail,
  getSystemDatabase,
  getWorkspaceProjectCount,
} from '@/lib/auth/system-database';

function getWorkspaceDeploymentCount(workspaceId: string): number {
  try {
    const sysDb = getSystemDatabase();
    const row = sysDb.prepare('SELECT COUNT(*) as count FROM deployment_routing WHERE workspace_id = ?').get(workspaceId) as { count: number };
    return row.count;
  } catch { return 0; }
}

function getWorkspaceMemberCount(workspaceId: string): number {
  try {
    const sysDb = getSystemDatabase();
    const row = sysDb.prepare('SELECT COUNT(*) as count FROM workspace_access WHERE workspace_id = ?').get(workspaceId) as { count: number };
    return row.count;
  } catch { return 0; }
}

function getWorkspaceOwnerEmail(ownerId: string): string | null {
  try {
    const sysDb = getSystemDatabase();
    const row = sysDb.prepare('SELECT email FROM users WHERE id = ?').get(ownerId) as { email: string } | undefined;
    return row?.email ?? null;
  } catch { return null; }
}

export async function GET(request: NextRequest) {
  try {
    const apiSession = verifyInstanceApiKey(request);
    const session = apiSession || await requireAuth();
    if (!session.isAdmin) {
      return NextResponse.json({ error: 'Admin access required' }, { status: 403 });
    }

    const workspaces = listWorkspaces();

    const enriched = workspaces.map(ws => ({
      id: ws.id,
      name: ws.name,
      ownerId: ws.owner_id,
      ownerEmail: getWorkspaceOwnerEmail(ws.owner_id),
      maxProjects: ws.max_projects,
      maxDeployments: ws.max_deployments,
      maxStorageMb: ws.max_storage_mb,
      memberCount: getWorkspaceMemberCount(ws.id),
      projectCount: getWorkspaceProjectCount(ws.id),
      deploymentCount: getWorkspaceDeploymentCount(ws.id),
      createdAt: ws.created_at,
      updatedAt: ws.updated_at,
    }));

    return NextResponse.json({ workspaces: enriched });
  } catch (error) {
    if (error instanceof Error && error.message === 'Unauthorized') {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }
    return NextResponse.json({ error: 'Failed to list workspaces' }, { status: 500 });
  }
}

export async function POST(request: NextRequest) {
  try {
    const apiSession = verifyInstanceApiKey(request);
    const session = apiSession || await requireAuth();
    if (!session.isAdmin) {
      return NextResponse.json({ error: 'Admin access required' }, { status: 403 });
    }

    const body = await request.json();
    const { name, ownerId, ownerEmail } = body;

    if (!name) {
      return NextResponse.json({ error: 'Workspace name is required' }, { status: 400 });
    }

    // Resolve owner: either by ownerId directly or by email lookup
    let resolvedOwnerId = ownerId;
    if (!resolvedOwnerId && ownerEmail) {
      const user = getUserByEmail(ownerEmail);
      if (!user) {
        return NextResponse.json({ error: `No user found with email: ${ownerEmail}` }, { status: 404 });
      }
      resolvedOwnerId = user.id;
    }

    if (!resolvedOwnerId) {
      return NextResponse.json({ error: 'Owner is required (provide ownerId or ownerEmail)' }, { status: 400 });
    }

    const workspaceId = createWorkspace(name, resolvedOwnerId);

    // createWorkspace already inserts owner into workspace_access, but grantWorkspaceAccess
    // uses INSERT OR REPLACE so calling it again with owner role is idempotent and ensures role.
    grantWorkspaceAccess(resolvedOwnerId, workspaceId, 'owner');

    return NextResponse.json({ id: workspaceId }, { status: 201 });
  } catch (error) {
    if (error instanceof Error && error.message === 'Unauthorized') {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }
    return NextResponse.json({ error: 'Failed to create workspace' }, { status: 500 });
  }
}