93 lines
5.1 KiB
JavaScript
93 lines
5.1 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { execFileSync } from 'node:child_process';
|
|
import { mkdtempSync, rmSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import LibDashStore from '../src/index.js';
|
|
import { BetterSqlite3Provider } from '../src/providers/sqlite3/index.js';
|
|
|
|
async function open(tempDir) {
|
|
const provider = new BetterSqlite3Provider({ filename: join(tempDir, 'test.db'), storageDir: join(tempDir, 'storage') });
|
|
await provider.initialize();
|
|
return { provider, store: await new LibDashStore(provider) };
|
|
}
|
|
|
|
const tempDir = mkdtempSync(join(tmpdir(), 'test-cu-roles-'));
|
|
try {
|
|
console.log('--- Testing companyuser roles + autoinvite ---');
|
|
let { provider, store } = await open(tempDir);
|
|
|
|
const adminId = await store.google_auth.add('admin@example.com');
|
|
const userId = await store.google_auth.add('user@example.com');
|
|
const company = await store.company.create({ name: 'Roles Corp', iso639: 'de', taxrate: 19, reducedtaxrate: 7, googleAuthId: adminId });
|
|
await store.google_auth.setSelectedCompany(adminId, company.id);
|
|
|
|
// creator is admin
|
|
let members = await store.companyuser.list(adminId);
|
|
assert.deepEqual(members.map((m) => [m.email, m.role]), [['admin@example.com', 'admin']]);
|
|
assert.equal((await store.company.list(adminId))[0].role, 'admin');
|
|
|
|
// non-member cannot select the company
|
|
await assert.rejects(store.google_auth.setSelectedCompany(userId, company.id), /Not authorized/);
|
|
|
|
// admin adds existing user
|
|
await assert.rejects(store.companyuser.addByEmail(adminId, { email: 'nobody@example.com' }), /User not found/);
|
|
await assert.rejects(store.companyuser.addByEmail(adminId, { email: 'user@example.com', role: 'root' }), /Invalid role/);
|
|
const added = await store.companyuser.addByEmail(adminId, { email: 'User@Example.com' });
|
|
assert.equal(added.role, 'user');
|
|
await assert.rejects(store.companyuser.addByEmail(adminId, { email: 'user@example.com' }), /already in company/);
|
|
|
|
// user can now select it, but is not admin
|
|
await store.google_auth.setSelectedCompany(userId, company.id);
|
|
await assert.rejects(store.companyuser.list(userId), /Not authorized/);
|
|
await assert.rejects(store.companyuser.addByEmail(userId, { email: 'admin@example.com' }), /Not authorized/);
|
|
await assert.rejects(store.companyuser.setRole(userId, added.id, 'admin'), /Not authorized/);
|
|
await assert.rejects(store.companyuser.remove(userId, added.id), /Not authorized/);
|
|
await assert.rejects(store.autoinvite.add(userId, { email: 'x@example.com' }), /Not authorized/);
|
|
|
|
// last admin guard
|
|
const adminCu = members[0].id;
|
|
await assert.rejects(store.companyuser.setRole(adminId, adminCu, 'user'), /last admin/);
|
|
await assert.rejects(store.companyuser.remove(adminId, adminCu), /last admin/);
|
|
await store.companyuser.setRole(adminId, added.id, 'admin');
|
|
await store.companyuser.setRole(adminId, adminCu, 'user');
|
|
await store.companyuser.setRole(userId, adminCu, 'admin');
|
|
await store.companyuser.setRole(userId, added.id, 'user');
|
|
await assert.rejects(store.companyuser.setRole(adminId, 99999, 'user'), /Company user not found/);
|
|
|
|
// autoinvite
|
|
await assert.rejects(store.autoinvite.add(adminId, { email: 'user@example.com' }), /already registered/);
|
|
await assert.rejects(store.autoinvite.add(adminId, { email: 'bad' }), /Invalid email/);
|
|
await store.autoinvite.add(adminId, { email: 'New@Example.com', role: 'admin' });
|
|
await assert.rejects(store.autoinvite.add(adminId, { email: 'new@example.com' }), /already exists/);
|
|
await store.autoinvite.add(adminId, { email: 'gone@example.com' });
|
|
assert.equal((await store.autoinvite.list(adminId)).length, 2);
|
|
await store.autoinvite.remove(adminId, (await store.autoinvite.list(adminId)).find((i) => i.email === 'gone@example.com').id);
|
|
await assert.rejects(store.autoinvite.remove(adminId, 99999), /Invitation not found/);
|
|
|
|
const newId = await store.google_auth.add('new@example.com');
|
|
assert.deepEqual(await store.autoinvite.list(adminId), []);
|
|
await store.google_auth.setSelectedCompany(newId, company.id);
|
|
members = await store.companyuser.list(adminId);
|
|
assert.equal(members.find((m) => m.email === 'new@example.com').role, 'admin');
|
|
|
|
// remove clears selection
|
|
const userCu = members.find((m) => m.email === 'user@example.com');
|
|
await store.companyuser.remove(adminId, userCu.id);
|
|
assert.equal((await store.google_auth.getById(userId)).selectedCompanyId, null);
|
|
|
|
// downgrade → upgrade through the migration engine
|
|
await provider.close?.();
|
|
const env = { ...process.env, DB_PROVIDER: 'sqlite', SQLITE_PATH: join(tempDir, 'test.db') };
|
|
execFileSync('node', ['scripts/downgrade.js', '5'], { env, stdio: 'inherit' });
|
|
({ provider, store } = await open(tempDir).catch((e) => { throw e; }));
|
|
// opening upgrades to latest again; roles reset to admin for all members
|
|
const rows = (await provider.query('SELECT role FROM companyuser')).rows;
|
|
assert.ok(rows.length > 0 && rows.every((r) => r.role === 'admin'));
|
|
assert.deepEqual((await provider.query('SELECT * FROM autoinvite')).rows, []);
|
|
await provider.close?.();
|
|
console.log('OK');
|
|
} finally {
|
|
rmSync(tempDir, { recursive: true, force: true });
|
|
}
|