Skip to content

Commit

Permalink
Merge pull request #11 from rushi-tekdi/main
Browse files Browse the repository at this point in the history
Task #227604 Task #227601 Sunbird Asessments Integration in Middleware
  • Loading branch information
rushi-tekdi authored Sep 26, 2024
2 parents 0e8b894 + 4329c6e commit 0da4122
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 5 deletions.
118 changes: 116 additions & 2 deletions src/common/middleware/apiConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ const rolesGroup = {
team_leader: ['team_leader'],
teacher: ['teacher'],
student: ['student'],
restricted: ['admin', 'team_leader'],
content_restricted: ['admin', 'team_leader'],
admin_team_leader: ['admin', 'team_leader'],
admin_team_leader_teacher: ['admin', 'teacher', 'team_leader'],
team_leader_teacher: ['teacher', 'team_leader'],
Expand All @@ -73,16 +75,19 @@ const createPrivilegeGroup = (entity: string) => {
read: [`${entity}.read`],
update: [`${entity}.update`],
delete: [`${entity}.delete`],
review: [`${entity}.review`],
approve: [`${entity}.approve`],
};
};
const privilegeGroup = {
tracking: createPrivilegeGroup('tracking'),
content: createPrivilegeGroup('content'),
users: createPrivilegeGroup('users'),
cohort: createPrivilegeGroup('cohort'),
cohortmembers: createPrivilegeGroup('cohortmembers'),
attendance: createPrivilegeGroup('attendance'),
};
const createRouteObject = (methods: any) => {
const createRouteObject = (methods: any, redirectUrl: string | null = null) => {
const allMethods = Object.keys(methods); // Extract method names (e.g., 'get', 'patch', 'delete')

const methodObject = allMethods.reduce((acc, method) => {
Expand All @@ -100,6 +105,7 @@ const createRouteObject = (methods: any) => {
return {
method: allMethods,
...methodObject,
redirectUrl, // Optionally include redirectUrl if it's passed
};
};

Expand Down Expand Up @@ -484,6 +490,104 @@ export const apiList = {
},
}),

//sunbird knowlg and inQuiry service
//public
'/api/question/v2/list': createRouteObject({ post: {} }, '/question/v5/list'),
'/action/questionset/v2/read/:identifier': createRouteObject(
{ get: {} },
'/questionset/v5/read/:identifier',
),
'/action/questionset/v2/hierarchy/:identifier': createRouteObject(
{ get: {} },
'/questionset/v5/hierarchy/:identifier',
),
'/action/questionset/v2/comment/read/:identifier': createRouteObject(
{ get: {} },
'/questionset/v5/comment/read/:identifier',
),
'/api/channel/v1/read/:identifier': createRouteObject(
{ get: {} },
'/channel/v3/read/:identifier',
),
'/api/framework/v1/read/:identifier': createRouteObject(
{ get: {} },
'/framework/v3/read/:identifier',
),
'/action/composite/v3/search': createRouteObject({ post: {} }, '/v3/search'),
//secure
'/action/questionset/v2/create': createRouteObject(
{
post: {
PRIVILEGE_CHECK: privilegeGroup.content.create,
ROLE_CHECK: rolesGroup.content_restricted,
},
},
'/questionset/v5/create',
),
'/action/questionset/v2/update/:identifier': createRouteObject(
{
patch: {
PRIVILEGE_CHECK: privilegeGroup.content.update,
ROLE_CHECK: rolesGroup.content_restricted,
},
},
'/questionset/v5/update/:identifier',
),
'/action/questionset/v2/review/:identifier': createRouteObject(
{
post: {
PRIVILEGE_CHECK: privilegeGroup.content.review,
ROLE_CHECK: rolesGroup.content_restricted,
},
},
'/questionset/v5/review/:identifier',
),
'/action/questionset/v2/publish/:identifier': createRouteObject(
{
post: {
PRIVILEGE_CHECK: privilegeGroup.content.approve,
ROLE_CHECK: rolesGroup.content_restricted,
},
},
'/questionset/v5/publish/:identifier',
),
'/action/questionset/v2/retire/:identifier': createRouteObject(
{
delete: {
PRIVILEGE_CHECK: privilegeGroup.content.delete,
ROLE_CHECK: rolesGroup.content_restricted,
},
},
'/questionset/v5/retire/:identifier',
),
'/action/questionset/v2/hierarchy/update': createRouteObject(
{
patch: {
PRIVILEGE_CHECK: privilegeGroup.content.update,
ROLE_CHECK: rolesGroup.content_restricted,
},
},
'/questionset/v5/hierarchy/update',
),
'/action/questionset/v2/reject/:identifier': createRouteObject(
{
post: {
PRIVILEGE_CHECK: privilegeGroup.content.update,
ROLE_CHECK: rolesGroup.content_restricted,
},
},
'/questionset/v5/reject/:identifier',
),
'/action/questionset/v2/comment/update/:identifier': createRouteObject(
{
patch: {
PRIVILEGE_CHECK: privilegeGroup.content.update,
ROLE_CHECK: rolesGroup.content_restricted,
},
},
'/questionset/v5/comment/update/:identifier',
),

//attendance service
'/api/v1/attendance': createRouteObject({
post: {
Expand All @@ -510,10 +614,20 @@ export const apiList = {
},
}),
};
console.log('api list', JSON.stringify(apiList, null, 2));
export const urlPatterns = Object.keys(apiList);

//add public api
export const publicAPI = ['/user/v1/auth/login'];
export const publicAPI = [
'/user/v1/auth/login',
'/api/question/v2/list',
'/action/questionset/v2/read/:identifier',
'/action/questionset/v2/hierarchy/:identifier',
'/action/questionset/v2/comment/read/:identifier',
'/api/channel/v1/read/:identifier',
'/api/framework/v1/read/:identifier',
'/action/composite/v3/search',
];

function convertToRegex(pattern) {
const regexString = pattern.replace(/:[^\s/]+/g, '([\\w-]+)');
Expand Down
32 changes: 29 additions & 3 deletions src/common/middleware/middleware.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ export class MiddlewareServices {
// custom jwt.strategy will get executed
await guard.canActivate(context);
}

// check API is whitelisted
if (apiList[reqUrl]) {
if (!apiList[reqUrl][req.method.toLowerCase()]) {
console.log('not whitelist');
throw new HttpException(
'SHIKSHA_API_WHITELIST: URL not whitelisted',
HttpStatus.FORBIDDEN,
Expand Down Expand Up @@ -114,9 +114,28 @@ export class MiddlewareServices {

async forwardRequest(req: Request, res: Response) {
const microserviceUrl = this.getMicroserviceUrl(req.originalUrl);
let forwardUrl = req.originalUrl;
//replace forwardUrl if redirectUrl present
//check for dynamic url
const originalUrl = req.originalUrl;
let reqUrl = originalUrl.split('?')[0];
const withPattern = this.matchUrl(reqUrl);
reqUrl = withPattern || reqUrl;
if (apiList[reqUrl]?.redirectUrl) {
if (reqUrl.includes(':')) {
const forwardUrlParts = forwardUrl.split('/');
const dynamicId = forwardUrlParts[forwardUrlParts.length - 1];
const redirectUrlParts = apiList[reqUrl].redirectUrl.split('/');
// Replace the last endpoint with the new string
redirectUrlParts[redirectUrlParts.length - 1] = dynamicId;
forwardUrl = redirectUrlParts.join('/');
} else {
forwardUrl = apiList[reqUrl].redirectUrl;
}
}
const config = {
method: req.method,
url: `${microserviceUrl}${req.originalUrl}`,
url: `${microserviceUrl}${forwardUrl}`,
headers: req.headers,
data: req.body,
};
Expand All @@ -138,6 +157,13 @@ export class MiddlewareServices {
'/queue': 'NOTIFICATION_SERVICE',
'/v1/tracking': 'TRACKING_SERVICE',
'/api/v1/attendance': 'ATTENDANCE_SERVICE',

//sunbird knowlg and inquiry
'/api/question': 'ASSESSMENT_SERVICE',
'/action/questionset': 'ASSESSMENT_SERVICE',
'/api/channel': 'CONTENT_SERVICE',
'/api/framework': 'TAXONOMY_SERVICE',
'/action/composite': 'SEARCH_SERVICE',
};

// Iterate over the mapping to find the correct service based on the URL prefix
Expand Down Expand Up @@ -298,7 +324,7 @@ export class MiddlewareServices {
try {
if (checksToExecute.length == 0) {
const response = await this.forwardRequest(req, res);
console.log('response in middleware', response);
//console.log('response in middleware', response);
return res.json(response);
}
await Promise.allSettled(checksToExecute).then(
Expand Down

0 comments on commit 0da4122

Please sign in to comment.