diff --git a/api/public/swagger.yaml b/api/public/swagger.yaml index c9b00c6..947aa3f 100644 --- a/api/public/swagger.yaml +++ b/api/public/swagger.yaml @@ -114,7 +114,7 @@ components: sessionId: type: string description: "The SessionId is the name of the temporary folder used to store the outputs.\nFor SAS, this would be the SASWORK folder. Can be used to poll job status.\nThis session ID should be used to poll job status." - example: '{ sessionId: ''20241028074744-54132-1730101664824'' }' + example: 20241028074744-54132-1730101664824 required: - sessionId type: object @@ -585,6 +585,14 @@ components: - needsToUpdatePassword type: object additionalProperties: false + SessionState: + enum: + - initialising + - pending + - running + - completed + - failed + type: string ExecutePostRequestPayload: properties: _program: @@ -598,7 +606,7 @@ components: sessionId: type: string description: "The SessionId is the name of the temporary folder used to store the outputs.\nFor SAS, this would be the SASWORK folder. Can be used to poll program status.\nThis session ID should be used to poll program status." - example: '{ sessionId: ''20241028074744-54132-1730101664824'' }' + example: 20241028074744-54132-1730101664824 required: - sessionId type: object @@ -1841,6 +1849,29 @@ paths: - bearerAuth: [] parameters: [] + '/SASjsApi/session/{sessionId}/state': + get: + operationId: SessionState + responses: + '200': + description: Ok + content: + application/json: + schema: + $ref: '#/components/schemas/SessionState' + summary: 'Get session state (initialising, pending, running, completed, failed).' + tags: + - Session + security: + - + bearerAuth: [] + parameters: + - + in: path + name: sessionId + required: true + schema: + type: string /SASjsApi/stp/execute: get: operationId: ExecuteGetRequest diff --git a/api/src/controllers/internal/Session.ts b/api/src/controllers/internal/Session.ts index c14310e..616c3c7 100644 --- a/api/src/controllers/internal/Session.ts +++ b/api/src/controllers/internal/Session.ts @@ -67,6 +67,10 @@ export class SessionController { return session } + + public getSessionById(id: string) { + return this.sessions.find((session) => session.id === id) + } } export class SASSessionController extends SessionController { diff --git a/api/src/controllers/session.ts b/api/src/controllers/session.ts index f0cd049..0f5cfef 100644 --- a/api/src/controllers/session.ts +++ b/api/src/controllers/session.ts @@ -1,6 +1,8 @@ import express from 'express' import { Request, Security, Route, Tags, Example, Get } from 'tsoa' import { UserResponse } from './user' +import { getSessionController } from './internal' +import { SessionState } from '../types' interface SessionResponse extends UserResponse { needsToUpdatePassword: boolean @@ -26,6 +28,15 @@ export class SessionController { ): Promise { return session(request) } + + /** + * @summary Get session state (initialising, pending, running, completed, failed). + * @example completed + */ + @Get('/:sessionId/state') + public async sessionState(sessionId: string): Promise { + return sessionState(sessionId) + } } const session = (req: express.Request) => ({ @@ -35,3 +46,23 @@ const session = (req: express.Request) => ({ isAdmin: req.user!.isAdmin, needsToUpdatePassword: req.user!.needsToUpdatePassword }) + +const sessionState = (sessionId: string): SessionState => { + for (let runTime of process.runTimes) { + // get session controller for each available runTime + const sessionController = getSessionController(runTime) + + // get session by sessionId + const session = sessionController.getSessionById(sessionId) + + // return session state if session was found + if (session) { + return session.state + } + } + + throw { + code: 404, + message: `Session with ID '${sessionId}' was not found.` + } +} diff --git a/api/src/routes/api/session.ts b/api/src/routes/api/session.ts index 09d0d87..e866832 100644 --- a/api/src/routes/api/session.ts +++ b/api/src/routes/api/session.ts @@ -1,16 +1,37 @@ import express from 'express' import { SessionController } from '../../controllers' +import { sessionIdValidation } from '../../utils' const sessionRouter = express.Router() +const controller = new SessionController() + sessionRouter.get('/', async (req, res) => { - const controller = new SessionController() try { const response = await controller.session(req) + res.send(response) } catch (err: any) { res.status(403).send(err.toString()) } }) +sessionRouter.get('/:sessionId/state', async (req, res) => { + const { error, value: params } = sessionIdValidation(req.params) + if (error) return res.status(400).send(error.details[0].message) + + try { + const response = await controller.sessionState(params.sessionId) + + res.status(200) + res.send(response) + } catch (err: any) { + const statusCode = err.code + + delete err.code + + res.status(statusCode).send(err) + } +}) + export default sessionRouter diff --git a/api/src/utils/validation.ts b/api/src/utils/validation.ts index a4fe696..4ba5dab 100644 --- a/api/src/utils/validation.ts +++ b/api/src/utils/validation.ts @@ -201,3 +201,8 @@ export const triggerProgramValidation = (data: any): Joi.ValidationResult => }) .pattern(/^/, Joi.alternatives(Joi.string(), Joi.number())) .validate(data) + +export const sessionIdValidation = (data: any): Joi.ValidationResult => + Joi.object({ + sessionId: Joi.string().required() + }).validate(data)