Skip to content

Commit

Permalink
Add /modelExtraction endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
Mythicaeda committed Jun 25, 2024
1 parent 79b2f86 commit 7e87472
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import initApiPlaygroundRoutes from './packages/api-playground/api-playground.js
import initAuthRoutes from './packages/auth/routes.js';
import { DbMerlin } from './packages/db/db.js';
import initFileRoutes from './packages/files/files.js';
import initHasuraRoutes from './packages/hasura/hasura-events.js';
import initHealthRoutes from './packages/health/health.js';
import initSwaggerRoutes from './packages/swagger/swagger.js';
import cookieParser from 'cookie-parser';
Expand Down Expand Up @@ -44,6 +45,7 @@ async function main(): Promise<void> {
initAuthRoutes(app, authHandler);
initFileRoutes(app);
initHealthRoutes(app);
initHasuraRoutes(app);
initSwaggerRoutes(app);

app.listen(PORT, () => {
Expand Down
124 changes: 124 additions & 0 deletions src/packages/hasura/hasura-events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import type { Express } from 'express';
import { adminOnlyAuth } from '../auth/middleware.js';
import rateLimit from 'express-rate-limit';
import getLogger from '../../logger.js';
import { getEnv } from '../../env.js';
import { generateJwt, decodeJwt } from '../auth/functions.js';

export default (app: Express) => {
const logger = getLogger('packages/hasura/hasura-events');
const { RATE_LIMITER_LOGIN_MAX } = getEnv();

const refreshLimiter = rateLimit({
legacyHeaders: false,
max: RATE_LIMITER_LOGIN_MAX,
standardHeaders: true,
windowMs: 15 * 60 * 1000, // 15 minutes
});

/**
* @swagger
* /modelExtraction:
* post:
* security:
* - bearerAuth: []
* consumes:
* - application/json
* produces:
* - application/json
* parameters:
* - in: header
* name: x-hasura-role
* schema:
* type: string
* required: false
* requestBody:
* content:
* application/json:
* schema:
* type: object
* properties:
* missionModelId:
* type: integer
* responses:
* 200:
* description: ExtractionResponse
* 403:
* description: Unauthorized error
* 401:
* description: Unauthenticated error
* summary: Request extraction of a Mission Model's JAR
* tags:
* - Hasura
*/
app.post('/modelExtraction', refreshLimiter, adminOnlyAuth, async (req, res) => {
const { jwtPayload } = decodeJwt(req.get('authorization'));
const username = jwtPayload?.username as string;

const { body } = req;
const { missionModelId } = body;

// Invoke endpoints using the Hasura Metadata API
const { HASURA_METADATA_API_URL: metadataURL } = getEnv();

// Generate a temporary token that has Hasura Admin access
const tempToken = generateJwt(username, 'admin', ['admin'], '10s');

const headers = {
Authorization: `Bearer ${tempToken}`,
'Content-Type': 'application/json',
'x-hasura-role': 'admin',
'x-hasura-user-id': username,
};

const generateBody = (name: string) =>
JSON.stringify({
args: {
name: `refresh${name}`,
payload: { id: missionModelId },
source: 'Aerie',
},
type: 'pg_invoke_event_trigger',
});

const extract = async (name: string) => {
return await fetch(metadataURL, {
body: generateBody(name),
headers,
method: 'POST',
})
.then(response => {
if (!response.ok) {
logger.error(`Bad status received when extracting ${name}: [${response.status}] ${response.statusText}`);
return {
error: `Bad status received when extracting ${name}: [${response.status}] ${response.statusText}`,
status: response.status,
statusText: response.statusText,
};
}
return response.json();
})
.catch(error => {
logger.error(`Error connecting to Hasura metadata API at ${metadataURL}. Full error below:\n${error}`);
return { error: `Error connecting to metadata API at ${metadataURL}` };
});
};

const [activityTypeResp, modelParameterResp, resourceTypeResp] = await Promise.all([
extract('ActivityTypes'),
extract('ModelParameters'),
extract('ResourceTypes'),
]);

logger.info(`POST /modelExtraction: Extraction triggered for model: ${missionModelId}`);

res.json({
message: `Extraction triggered for model: ${missionModelId}`,
response: {
activity_types: activityTypeResp,
model_parameters: modelParameterResp,
resource_types: resourceTypeResp,
},
});
});
};

0 comments on commit 7e87472

Please sign in to comment.