import { test } from "node:test"; import assert from "node:assert/strict"; import path from "node:path"; import { fileURLToPath } from "node:url"; import dotenv from "dotenv"; import getPool from "../lib/server/db"; import { joinGroup, requireActiveGroup } from "../lib/server/groups"; import { setGroupSettings } from "../lib/server/group-settings"; import { transferOwnership } from "../lib/server/group-members"; import { cleanupTestData, uniqueInviteCode } from "./test-helpers"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const envLoaded = dotenv.config({ path: path.resolve(__dirname, "../../../.env") }); const hasDb = Boolean(process.env.DATABASE_URL); test("join policy enforcement and join requests", async t => { if (!hasDb) { t.skip("DATABASE_URL not set"); return; } if (envLoaded.error) t.diagnostic(String(envLoaded.error)); const pool = getPool(); const client = await pool.connect(); let ownerId: number | null = null; let memberId: number | null = null; let groupId: number | null = null; const inviteCode = uniqueInviteCode("J"); try { const ownerRes = await client.query( "insert into users(email, password_hash) values($1,$2) returning id", [`owner_${Date.now()}@example.com`, "hash"] ); ownerId = Number(ownerRes.rows[0].id); const memberRes = await client.query( "insert into users(email, password_hash) values($1,$2) returning id", [`member_${Date.now()}@example.com`, "hash"] ); memberId = Number(memberRes.rows[0].id); const groupRes = await client.query( "insert into groups(name, invite_code, created_by) values($1,$2,$3) returning id", ["Join Policy Group", inviteCode, ownerId] ); groupId = Number(groupRes.rows[0].id); await client.query( "insert into group_members(group_id, user_id, role) values($1,$2,'GROUP_OWNER')", [groupId, ownerId] ); await setGroupSettings({ userId: ownerId, groupId, allowMemberTagManage: false, joinPolicy: "NOT_ACCEPTING" }); await assert.rejects( () => joinGroup(memberId!, inviteCode), { message: "JOIN_NOT_ACCEPTING" } ); await setGroupSettings({ userId: ownerId, groupId, allowMemberTagManage: false, joinPolicy: "APPROVAL_REQUIRED" }); await assert.rejects( () => joinGroup(memberId!, inviteCode), { message: "JOIN_PENDING" } ); const pendingRes = await client.query( "select status from group_join_requests where group_id=$1 and user_id=$2", [groupId, memberId] ); assert.equal(pendingRes.rows[0]?.status, "PENDING"); await client.query("delete from group_join_requests where group_id=$1 and user_id=$2", [groupId, memberId]); await setGroupSettings({ userId: ownerId, groupId, allowMemberTagManage: false, joinPolicy: "AUTO_ACCEPT" }); const group = await joinGroup(memberId!, inviteCode); assert.equal(Number(group.id), groupId); const memberRows = await client.query( "select role from group_members where group_id=$1 and user_id=$2", [groupId, memberId] ); assert.equal(memberRows.rows[0]?.role, "MEMBER"); } finally { await cleanupTestData(client, { userIds: [ownerId, memberId], groupId }); client.release(); } }); test("ownership transfer updates roles", async t => { if (!hasDb) { t.skip("DATABASE_URL not set"); return; } if (envLoaded.error) t.diagnostic(String(envLoaded.error)); const pool = getPool(); const client = await pool.connect(); let ownerId: number | null = null; let memberId: number | null = null; let groupId: number | null = null; try { const ownerRes = await client.query( "insert into users(email, password_hash) values($1,$2) returning id", [`owner2_${Date.now()}@example.com`, "hash"] ); ownerId = Number(ownerRes.rows[0].id); const memberRes = await client.query( "insert into users(email, password_hash) values($1,$2) returning id", [`member2_${Date.now()}@example.com`, "hash"] ); memberId = Number(memberRes.rows[0].id); const groupRes = await client.query( "insert into groups(name, invite_code, created_by) values($1,$2,$3) returning id", ["Ownership Group", uniqueInviteCode("O"), ownerId] ); groupId = Number(groupRes.rows[0].id); await client.query( "insert into group_members(group_id, user_id, role) values($1,$2,'GROUP_OWNER')", [groupId, ownerId] ); await client.query( "insert into group_members(group_id, user_id, role) values($1,$2,'MEMBER')", [groupId, memberId] ); await transferOwnership({ actorUserId: ownerId, groupId, newOwnerUserId: memberId, requestId: `req_${Date.now()}` }); const roles = await client.query( "select user_id, role from group_members where group_id=$1", [groupId] ); const roleMap = new Map(roles.rows.map(row => [Number(row.user_id), row.role])); assert.equal(roleMap.get(ownerId), "GROUP_ADMIN"); assert.equal(roleMap.get(memberId), "GROUP_OWNER"); } finally { await cleanupTestData(client, { userIds: [ownerId, memberId], groupId }); client.release(); } });