169 lines
4.6 KiB
TypeScript
169 lines
4.6 KiB
TypeScript
import { json } from '@sveltejs/kit';
|
|
import type { RequestHandler } from './$types';
|
|
|
|
/**
|
|
* GET: Retrieve the Matrix Space ID for an org
|
|
*/
|
|
export const GET: RequestHandler = async ({ url, locals }) => {
|
|
const session = await locals.safeGetSession();
|
|
if (!session.user) {
|
|
return json({ error: 'Unauthorized' }, { status: 401 });
|
|
}
|
|
|
|
const orgId = url.searchParams.get('org_id');
|
|
if (!orgId) {
|
|
return json({ error: 'org_id is required' }, { status: 400 });
|
|
}
|
|
|
|
const { data, error } = await locals.supabase
|
|
.from('organizations')
|
|
.select('matrix_space_id')
|
|
.eq('id', orgId)
|
|
.single();
|
|
|
|
if (error) {
|
|
return json({ error: error.message }, { status: 500 });
|
|
}
|
|
|
|
return json({ spaceId: data?.matrix_space_id ?? null });
|
|
};
|
|
|
|
/**
|
|
* POST: Create a Matrix Space for an org, or link an existing one.
|
|
*
|
|
* Body options:
|
|
* - { org_id, action: "create", homeserver_url, access_token, org_name }
|
|
* Creates a new Space on the homeserver and stores the ID.
|
|
* - { org_id, action: "link", space_id }
|
|
* Links an existing Matrix Space ID to the org.
|
|
*/
|
|
export const POST: RequestHandler = async ({ request, locals }) => {
|
|
const session = await locals.safeGetSession();
|
|
if (!session.user) {
|
|
return json({ error: 'Unauthorized' }, { status: 401 });
|
|
}
|
|
|
|
const body = await request.json();
|
|
const { org_id, action } = body;
|
|
|
|
if (!org_id || !action) {
|
|
return json({ error: 'org_id and action are required' }, { status: 400 });
|
|
}
|
|
|
|
if (action === 'create') {
|
|
const { homeserver_url, access_token, org_name } = body;
|
|
if (!homeserver_url || !access_token || !org_name) {
|
|
return json({ error: 'homeserver_url, access_token, and org_name are required for create' }, { status: 400 });
|
|
}
|
|
|
|
try {
|
|
// Create a Matrix Space via the Client-Server API
|
|
const createRes = await fetch(`${homeserver_url}/_matrix/client/v3/createRoom`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${access_token}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
name: org_name,
|
|
topic: `Organization space for ${org_name}`,
|
|
visibility: 'private',
|
|
creation_content: {
|
|
type: 'm.space',
|
|
},
|
|
initial_state: [
|
|
{
|
|
type: 'm.room.guest_access',
|
|
state_key: '',
|
|
content: { guest_access: 'can_join' },
|
|
},
|
|
],
|
|
power_level_content_override: {
|
|
invite: 50,
|
|
kick: 50,
|
|
ban: 50,
|
|
events_default: 0,
|
|
state_default: 50,
|
|
},
|
|
}),
|
|
});
|
|
|
|
if (!createRes.ok) {
|
|
const err = await createRes.json().catch(() => ({}));
|
|
return json({ error: err.error || 'Failed to create Matrix Space' }, { status: 500 });
|
|
}
|
|
|
|
const { room_id: spaceId } = await createRes.json();
|
|
|
|
// Also create default #general room inside the space
|
|
const generalRes = await fetch(`${homeserver_url}/_matrix/client/v3/createRoom`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${access_token}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
name: 'General',
|
|
topic: 'General discussion',
|
|
visibility: 'private',
|
|
preset: 'private_chat',
|
|
}),
|
|
});
|
|
|
|
if (generalRes.ok) {
|
|
const { room_id: generalRoomId } = await generalRes.json();
|
|
|
|
// Add #general as a child of the space
|
|
await fetch(
|
|
`${homeserver_url}/_matrix/client/v3/rooms/${encodeURIComponent(spaceId)}/state/m.space.child/${encodeURIComponent(generalRoomId)}`,
|
|
{
|
|
method: 'PUT',
|
|
headers: {
|
|
'Authorization': `Bearer ${access_token}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
via: [new URL(homeserver_url).hostname],
|
|
}),
|
|
}
|
|
);
|
|
}
|
|
|
|
// Store space ID in org record
|
|
const { error: updateError } = await locals.supabase
|
|
.from('organizations')
|
|
.update({ matrix_space_id: spaceId })
|
|
.eq('id', org_id);
|
|
|
|
if (updateError) {
|
|
return json({ error: updateError.message }, { status: 500 });
|
|
}
|
|
|
|
return json({ spaceId, created: true });
|
|
} catch (e: any) {
|
|
console.error('Failed to create Matrix Space:', e);
|
|
return json({ error: e.message || 'Failed to create Matrix Space' }, { status: 500 });
|
|
}
|
|
}
|
|
|
|
if (action === 'link') {
|
|
const { space_id } = body;
|
|
if (!space_id) {
|
|
return json({ error: 'space_id is required for link action' }, { status: 400 });
|
|
}
|
|
|
|
const { error: updateError } = await locals.supabase
|
|
.from('organizations')
|
|
.update({ matrix_space_id: space_id })
|
|
.eq('id', org_id);
|
|
|
|
if (updateError) {
|
|
return json({ error: updateError.message }, { status: 500 });
|
|
}
|
|
|
|
return json({ spaceId: space_id, linked: true });
|
|
}
|
|
|
|
return json({ error: 'Invalid action. Use "create" or "link".' }, { status: 400 });
|
|
};
|