Files
app/ts/reception/classes.appconnectionmanager.ts
T

188 lines
6.1 KiB
TypeScript
Raw Normal View History

import * as plugins from '../plugins.js';
import type { Reception } from './classes.reception.js';
import { AppConnection } from './classes.appconnection.js';
export class AppConnectionManager {
public receptionRef: Reception;
public get db() {
return this.receptionRef.db.smartdataDb;
}
public typedrouter = new plugins.typedrequest.TypedRouter();
public CAppConnection = plugins.smartdata.setDefaultManagerForDoc(this, AppConnection);
constructor(receptionRefArg: Reception) {
this.receptionRef = receptionRefArg;
this.receptionRef.typedrouter.addTypedRouter(this.typedrouter);
// Handler: Get app connections for an organization
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_GetAppConnections>(
'getAppConnections',
async (requestArg) => {
// Verify JWT and get user
const jwtData = await this.receptionRef.jwtManager.verifyJWTAndGetData(requestArg.jwt);
const user = await this.receptionRef.userManager.CUser.getInstance({
id: jwtData.data.userId,
});
// Check user has access to the organization
const organization = await this.receptionRef.organizationmanager.COrganization.getInstance({
id: requestArg.organizationId,
});
if (!organization) {
throw new plugins.typedrequest.TypedResponseError('Organization not found');
}
const role = await this.receptionRef.roleManager.CRole.getInstance({
data: {
organizationId: organization.id,
userId: user.id,
},
});
if (!role) {
throw new plugins.typedrequest.TypedResponseError(
'User not authorized for this organization'
);
}
// Get all connections for this organization
const connections = await this.CAppConnection.getInstances({
'data.organizationId': requestArg.organizationId,
});
const connectionObjects = await Promise.all(
connections.map(async (conn) => await conn.createSavableObject())
);
return {
connections: connectionObjects,
};
}
)
);
// Handler: Toggle app connection (connect/disconnect)
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_ToggleAppConnection>(
'toggleAppConnection',
async (requestArg) => {
// Verify JWT and get user
const jwtData = await this.receptionRef.jwtManager.verifyJWTAndGetData(requestArg.jwt);
const user = await this.receptionRef.userManager.CUser.getInstance({
id: jwtData.data.userId,
});
// Check user has admin access to the organization
const organization = await this.receptionRef.organizationmanager.COrganization.getInstance({
id: requestArg.organizationId,
});
if (!organization) {
throw new plugins.typedrequest.TypedResponseError('Organization not found');
}
const isAdmin = await organization.checkIfUserIsAdmin(user);
if (!isAdmin) {
throw new plugins.typedrequest.TypedResponseError(
'Only organization admins can manage app connections'
);
}
// Get the app
const app = await this.receptionRef.appManager.getAppById(requestArg.appId);
if (!app) {
throw new plugins.typedrequest.TypedResponseError('App not found');
}
// Find existing connection
let connection = await this.CAppConnection.getInstance({
'data.organizationId': requestArg.organizationId,
'data.appId': requestArg.appId,
});
if (requestArg.action === 'connect') {
if (connection && connection.isActive()) {
// Already connected
return {
success: true,
connection: await connection.createSavableObject(),
};
}
if (connection) {
// Reconnect existing connection
await connection.reconnect(user.id);
} else {
// Create new connection
connection = new AppConnection();
connection.id = plugins.smartunique.shortId();
connection.data = {
organizationId: requestArg.organizationId,
appId: requestArg.appId,
appType: app.type,
status: 'active',
connectedAt: Date.now(),
connectedByUserId: user.id,
grantedScopes: app.data.oauthCredentials?.allowedScopes || [],
};
await connection.save();
}
return {
success: true,
connection: await connection.createSavableObject(),
};
} else {
// Disconnect
if (!connection) {
return {
success: true,
};
}
await connection.disconnect();
return {
success: true,
connection: await connection.createSavableObject(),
};
}
}
)
);
}
/**
* Get all connections for an organization
*/
public async getConnectionsForOrganization(organizationId: string): Promise<AppConnection[]> {
return await this.CAppConnection.getInstances({
'data.organizationId': organizationId,
});
}
/**
* Get connection for a specific app and organization
*/
public async getConnection(
organizationId: string,
appId: string
): Promise<AppConnection | null> {
return await this.CAppConnection.getInstance({
'data.organizationId': organizationId,
'data.appId': appId,
});
}
/**
* Check if an app is connected to an organization
*/
public async isAppConnected(organizationId: string, appId: string): Promise<boolean> {
const connection = await this.getConnection(organizationId, appId);
return connection?.isActive() || false;
}
}