feat(app): wire dashboard administration flows
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
|
||||
import { AppConnection } from '../ts/reception/classes.appconnection.js';
|
||||
import { AppConnectionManager } from '../ts/reception/classes.appconnectionmanager.js';
|
||||
import { User } from '../ts/reception/classes.user.js';
|
||||
|
||||
const createTestAppConnectionManager = (optionsArg: {
|
||||
allowedScopes?: string[];
|
||||
grantedScopes?: string[];
|
||||
} = {}) => {
|
||||
const activities: Array<{ userId: string; action: string; description: string; metadata?: any }> = [];
|
||||
const alerts: Array<{ eventType: string; organizationId?: string; relatedEntityId?: string }> = [];
|
||||
|
||||
const user = new User();
|
||||
user.id = 'user-1';
|
||||
user.data = {
|
||||
name: 'Admin User',
|
||||
username: 'admin@example.com',
|
||||
email: 'admin@example.com',
|
||||
status: 'active',
|
||||
connectedOrgs: ['org-1'],
|
||||
};
|
||||
|
||||
const app = {
|
||||
id: 'app-1',
|
||||
type: 'global',
|
||||
data: {
|
||||
name: 'Finance App',
|
||||
oauthCredentials: {
|
||||
allowedScopes: optionsArg.allowedScopes || ['openid', 'roles', 'billing'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const organization = {
|
||||
id: 'org-1',
|
||||
data: {
|
||||
name: 'Lossless GmbH',
|
||||
slug: 'lossless',
|
||||
},
|
||||
checkIfUserIsAdmin: async () => true,
|
||||
};
|
||||
|
||||
const connection = new AppConnection();
|
||||
connection.id = 'connection-1';
|
||||
connection.data = {
|
||||
organizationId: organization.id,
|
||||
appId: app.id,
|
||||
appType: 'global',
|
||||
status: 'active',
|
||||
connectedAt: Date.now(),
|
||||
connectedByUserId: user.id,
|
||||
grantedScopes: optionsArg.grantedScopes || ['openid', 'roles', 'billing'],
|
||||
roleMappings: [],
|
||||
};
|
||||
connection.save = async () => undefined;
|
||||
|
||||
const reception = {
|
||||
db: { smartdataDb: {} },
|
||||
typedrouter: { addTypedRouter: () => undefined },
|
||||
organizationmanager: {
|
||||
COrganization: {
|
||||
getInstance: async () => organization,
|
||||
},
|
||||
getAvailableRoleKeys: async () => ['owner', 'admin', 'viewer', 'finance'],
|
||||
validateRoleKey: (roleKeyArg: string) => roleKeyArg.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, ''),
|
||||
},
|
||||
appManager: {
|
||||
getAppById: async () => app,
|
||||
},
|
||||
activityLogManager: {
|
||||
logActivity: async (userId: string, action: string, description: string, metadata?: any) => {
|
||||
activities.push({ userId, action, description, metadata });
|
||||
},
|
||||
},
|
||||
alertManager: {
|
||||
createAlertsForEvent: async (options: { eventType: string; organizationId?: string; relatedEntityId?: string }) => {
|
||||
alerts.push(options);
|
||||
return [];
|
||||
},
|
||||
},
|
||||
} as any;
|
||||
|
||||
const manager = new AppConnectionManager(reception);
|
||||
(manager as any).CAppConnection = {
|
||||
getInstance: async () => connection,
|
||||
};
|
||||
|
||||
return {
|
||||
manager,
|
||||
user,
|
||||
connection,
|
||||
activities,
|
||||
alerts,
|
||||
};
|
||||
};
|
||||
|
||||
tap.test('rejects app role mappings with unsupported app scopes', async () => {
|
||||
const { manager, user, connection, activities } = createTestAppConnectionManager({
|
||||
allowedScopes: ['openid', 'roles'],
|
||||
grantedScopes: ['openid', 'roles', 'billing'],
|
||||
});
|
||||
|
||||
await expect(manager.updateAppRoleMappings({
|
||||
user,
|
||||
organizationId: 'org-1',
|
||||
appId: 'app-1',
|
||||
roleMappings: [{
|
||||
orgRoleKey: 'finance',
|
||||
appRoles: [],
|
||||
permissions: [],
|
||||
scopes: ['billing'],
|
||||
}],
|
||||
})).rejects.toThrow();
|
||||
|
||||
expect(connection.data.roleMappings).toEqual([]);
|
||||
expect(activities).toEqual([]);
|
||||
});
|
||||
|
||||
tap.test('rejects app role mappings with ungranted connection scopes', async () => {
|
||||
const { manager, user, connection, activities } = createTestAppConnectionManager({
|
||||
allowedScopes: ['openid', 'roles', 'billing'],
|
||||
grantedScopes: ['openid', 'roles'],
|
||||
});
|
||||
|
||||
await expect(manager.updateAppRoleMappings({
|
||||
user,
|
||||
organizationId: 'org-1',
|
||||
appId: 'app-1',
|
||||
roleMappings: [{
|
||||
orgRoleKey: 'finance',
|
||||
appRoles: [],
|
||||
permissions: [],
|
||||
scopes: ['billing'],
|
||||
}],
|
||||
})).rejects.toThrow();
|
||||
|
||||
expect(connection.data.roleMappings).toEqual([]);
|
||||
expect(activities).toEqual([]);
|
||||
});
|
||||
|
||||
tap.test('updates app role mappings and writes audit activity', async () => {
|
||||
const { manager, user, connection, activities, alerts } = createTestAppConnectionManager();
|
||||
|
||||
await manager.updateAppRoleMappings({
|
||||
user,
|
||||
organizationId: 'org-1',
|
||||
appId: 'app-1',
|
||||
roleMappings: [{
|
||||
orgRoleKey: ' Finance ',
|
||||
appRoles: ['accountant', 'accountant', ''],
|
||||
permissions: ['invoices:read'],
|
||||
scopes: ['billing'],
|
||||
}],
|
||||
});
|
||||
|
||||
expect(connection.data.roleMappings).toEqual([{
|
||||
orgRoleKey: 'finance',
|
||||
appRoles: ['accountant'],
|
||||
permissions: ['invoices:read'],
|
||||
scopes: ['billing'],
|
||||
}]);
|
||||
expect(activities[0].action).toEqual('org_app_role_mappings_updated');
|
||||
expect(activities[0].metadata.targetId).toEqual(connection.id);
|
||||
expect(alerts[0].eventType).toEqual('org_app_role_mappings_updated');
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
Reference in New Issue
Block a user