Commit 7d2f1c4a authored by Varunkumar Manohar's avatar Varunkumar Manohar
Browse files

Merge branch 'fixUserRoles' into 'master'

Update user roles endpoint to use the acls on subprojects

See merge request !97
parents 10ef056c a1cff8cf
Pipeline #41596 passed with stages
in 5 minutes and 59 seconds
This diff is collapsed.
......@@ -83,19 +83,19 @@ export class UserHandler {
const subproject = await SubProjectDAO.get(journalClient, tenant.name, sdPath.subproject, spkey);
const serviceGroupRegex = SubprojectGroups.serviceGroupNameRegExp(tenant.name, subproject.name);
const subprojectServiceGroups = subproject.acls.admins.filter((group) => group.match(serviceGroupRegex))
const subprojectServiceGroups = subproject.acls.admins.filter((group) => group.match(serviceGroupRegex));
const dataGroupRegex = SubprojectGroups.dataGroupNameRegExp(tenant.name, subproject.name);
const adminSubprojectDataGroups = subproject.acls.admins.filter((group) => group.match(dataGroupRegex))
const viewerSuprojectDataGroups = subproject.acls.viewers.filter(group => group.match(dataGroupRegex))
const subprojectDataGroups = adminSubprojectDataGroups.concat(viewerSuprojectDataGroups)
const adminSubprojectDataGroups = subproject.acls.admins.filter((group) => group.match(dataGroupRegex));
const viewerSuprojectDataGroups = subproject.acls.viewers.filter(group => group.match(dataGroupRegex));
const subprojectDataGroups = adminSubprojectDataGroups.concat(viewerSuprojectDataGroups);
if (subprojectServiceGroups.length > 0) {
if (userGroupRole === AuthRoles.admin) {
// rm the user from the groups since the user can be OWNER or Member
for(const group of subprojectServiceGroups) {
for (const group of subprojectServiceGroups) {
await this.doNotThrowIfNotMember(
AuthGroups.removeUserFromGroup(
req.headers.authorization, group, userEmail,
......@@ -103,7 +103,7 @@ export class UserHandler {
}
// add the user as OWNER for all service groups
for(const group of subprojectServiceGroups) {
for (const group of subprojectServiceGroups) {
await AuthGroups.addUserToGroup(
req.headers.authorization, group, userEmail, tenant.esd, req[Config.DE_FORWARD_APPKEY], 'OWNER');
}
......@@ -111,8 +111,8 @@ export class UserHandler {
} else if (userGroupRole === AuthRoles.editor) {
// add the user as member for all editor service groups
for(const group of subprojectServiceGroups) {
if(group.indexOf('.editor@') !== -1) {
for (const group of subprojectServiceGroups) {
if (group.indexOf('.editor@') !== -1) {
await AuthGroups.addUserToGroup(
req.headers.authorization, group,
userEmail, tenant.esd, req[Config.DE_FORWARD_APPKEY]);
......@@ -122,8 +122,8 @@ export class UserHandler {
} else if (userGroupRole === AuthRoles.viewer) {
// add the user as member for all viewer service groups
for(const group of subprojectServiceGroups) {
if(group.indexOf('.viewer@') !== -1) {
for (const group of subprojectServiceGroups) {
if (group.indexOf('.viewer@') !== -1) {
await AuthGroups.addUserToGroup(
req.headers.authorization, group,
userEmail, tenant.esd, req[Config.DE_FORWARD_APPKEY]);
......@@ -139,7 +139,7 @@ export class UserHandler {
if (userGroupRole !== AuthRoles.viewer) {
// rm the user from the groups since the user can be OWNER or Member
for(const datagroup of subprojectDataGroups) {
for (const datagroup of subprojectDataGroups) {
await this.doNotThrowIfNotMember(
AuthGroups.removeUserFromGroup(
req.headers.authorization, datagroup, userEmail,
......@@ -147,7 +147,7 @@ export class UserHandler {
}
// add the user as OWNER for all service groups
for(const datagroup of subprojectDataGroups) {
for (const datagroup of subprojectDataGroups) {
await AuthGroups.addUserToGroup(
req.headers.authorization, datagroup, userEmail,
tenant.esd, req[Config.DE_FORWARD_APPKEY], 'OWNER');
......@@ -156,15 +156,15 @@ export class UserHandler {
} else {
// add user to viewer group
for(const datagroup of subprojectDataGroups) {
if(datagroup.indexOf('.viewer@') !== -1) {
for (const datagroup of subprojectDataGroups) {
if (datagroup.indexOf('.viewer@') !== -1) {
await AuthGroups.addUserToGroup(
req.headers.authorization, datagroup, userEmail,
tenant.esd, req[Config.DE_FORWARD_APPKEY]);
}
}
}
}
for (const datagroup of subprojectDataGroups) {
......@@ -182,9 +182,9 @@ export class UserHandler {
datagroup, userEmail, tenant.esd, req[Config.DE_FORWARD_APPKEY], 'OWNER');
} else {
if(datagroup.indexOf('.viewer@') !== -1) {
if (datagroup.indexOf('.viewer@') !== -1) {
await AuthGroups.addUserToGroup(req.headers.authorization,
datagroup, userEmail, tenant.esd, req[Config.DE_FORWARD_APPKEY]);
datagroup, userEmail, tenant.esd, req[Config.DE_FORWARD_APPKEY]);
}
}
......@@ -237,8 +237,8 @@ export class UserHandler {
const subproject = await SubProjectDAO.get(journalClient, tenant.name, sdPath.subproject, spkey);
const adminGroups = subproject.acls.admins
const viewerGroups = subproject.acls.viewers
const adminGroups = subproject.acls.admins;
const viewerGroups = subproject.acls.viewers;
for (const group of adminGroups) {
await this.doNotThrowIfNotMember(
......@@ -279,14 +279,14 @@ export class UserHandler {
const subproject = await SubProjectDAO.get(journalClient, tenant.name, sdPath.subproject, spkey);
let users = []
let users = [];
if (subproject.acls.admins.length > 0) {
for (const adminGroup of subproject.acls.admins) {
const result = (await AuthGroups.listUsersInGroup(req.headers.authorization, adminGroup, tenant.esd,
req[Config.DE_FORWARD_APPKEY]))
users = users.concat(result.map((el) => [el.email, 'admin']))
req[Config.DE_FORWARD_APPKEY]));
users = users.concat(result.map((el) => [el.email, 'admin']));
}
}
......@@ -294,12 +294,12 @@ export class UserHandler {
for (const viewerGroup of subproject.acls.viewers) {
const result = (await AuthGroups.listUsersInGroup(req.headers.authorization, viewerGroup, tenant.esd,
req[Config.DE_FORWARD_APPKEY]))
users = users.concat(result.map((el) => [el.email, 'viewer']))
req[Config.DE_FORWARD_APPKEY]));
users = users.concat(result.map((el) => [el.email, 'viewer']));
}
}
return users
return users;
}
// retrieve the roles of a user
......@@ -317,6 +317,9 @@ export class UserHandler {
const groups = await AuthGroups.getUserGroups(req.headers.authorization,
tenant.esd, req[Config.DE_FORWARD_APPKEY]);
// List of all group emails in which the user is member or a owner
const groupEmailsOfUser = groups.map(group => group.email);
const prefix = sdPath.subproject ?
SubprojectGroups.serviceGroupPrefix(sdPath.tenant, sdPath.subproject) :
TenantGroups.serviceGroupPrefix(sdPath.tenant);
......@@ -324,29 +327,53 @@ export class UserHandler {
const journalClient = JournalFactoryTenantClient.get(tenant);
const registeredSubprojects = (await SubProjectDAO.list(journalClient, sdPath.tenant))
.map(subproject => subproject.name)
const registeredSubprojects = (await SubProjectDAO.list(journalClient, sdPath.tenant));
// build and return the user roles
const basePath = Config.SDPATHPREFIX + sdPath.tenant + (sdPath.subproject ? ('/') + sdPath.subproject : '');
// Concatenate all valid subproject admin groups
const registeredSubprojectAdminGrps = registeredSubprojects.map(subproject => subproject.acls.admins).flat(1);
const registeredSubprojectViewerGrps = registeredSubprojects.map(subproject => subproject.acls.viewers).flat(1);
return {
roles: groups.filter((el) => el.name.startsWith(prefix))
.map((el) => el.name.substr(prefix.length + 1))
.filter((el) => {
const subproject = el.split('.')[0]
if (registeredSubprojects.includes(subproject)) {
return true
}
return false
})
.map((el) => {
const tokens = el.split('.'); return [
basePath + (tokens.length > 1) ? '/' + tokens[0] : '',
tokens[tokens.length - 1]];
}),
// Find intersection of admin groups of all registered subprojects and the usergroup emails
const validAdminGroupsForUser = registeredSubprojectAdminGrps.filter(grp => groupEmailsOfUser.includes(grp));
const validViewerGroupsForUser = registeredSubprojectViewerGrps.filter(grp => groupEmailsOfUser.includes(grp));
let roles = [];
for (const validAdminGroup of validAdminGroupsForUser) {
if (validAdminGroup.startsWith('service')) {
roles.push(['/' + validAdminGroup.split('.')[4], 'admin']);
roles.push(['/' + validAdminGroup.split('.')[4], 'editor']);
}
else if (validAdminGroup.startsWith('data')) {
roles.push(['/' + validAdminGroup.split('.')[3], 'admin']);
roles.push(['/' + validAdminGroup.split('.')[3], 'editor']);
}
}
for (const validViewerGroup of validViewerGroupsForUser) {
if (validViewerGroup.startsWith('service')) {
roles.push(['/' + validViewerGroup.split('.')[4], 'viewer']);
}
else if (validViewerGroup.startsWith('data')) {
roles.push(['/' + validViewerGroup.split('.')[3], 'viewer']);
}
}
// Remove duplicates from roles array where each element is array byitself
const stringRolesArray = roles.map(role => JSON.stringify(role));
const uniqueRolesStringArray = new Set(stringRolesArray);
roles = Array.from(uniqueRolesStringArray, (ele) => JSON.parse(ele));
if (sdPath.subproject) {
const subprojectRoles = roles.filter((role) => role[0] === '/' + sdPath.subproject);
return {
'roles': subprojectRoles
};
}
return {
'roles': roles
};
}
// do not throw if a user is not a member (fast remove users if not exist than check if exist and than remove it)
......
......@@ -28,7 +28,7 @@ import { DatasetOP } from '../../../src/services/dataset/optype';
import { DatasetParser } from '../../../src/services/dataset/parser';
import { SubProjectDAO, SubProjectModel } from '../../../src/services/subproject';
import { TenantDAO, TenantModel } from '../../../src/services/tenant';
import { Response, Utils } from '../../../src/shared';
import { Response } from '../../../src/shared';
import { Tx } from '../utils';
......@@ -47,7 +47,7 @@ export class TestDatasetSVC {
viewers: ['vieweres-b@domain.com']
},
ltag: 'legalTag'
} as SubProjectModel
} as SubProjectModel;
this.dataset = {
filemetadata: {},
......@@ -113,7 +113,7 @@ export class TestDatasetSVC {
private static testDb: Datastore;
private static query: any;
private static tenant: TenantModel;
private static testSubProject: SubProjectModel
private static testSubProject: SubProjectModel;
private static ctag() {
......@@ -155,8 +155,8 @@ export class TestDatasetSVC {
this.sandbox.stub(DatasetDAO, 'register').resolves(undefined);
this.sandbox.stub(google.GCS.prototype, 'saveObject').resolves(undefined);
this.sandbox.stub(DESStorage, 'insertRecord').resolves(undefined);
this.sandbox.stub(Locker, 'createWriteLock').resolves({idempotent: false, key:'x', mutex:'x', wid:'x'});
this.sandbox.stub(Locker, 'removeWriteLock');
this.sandbox.stub(Locker, 'createWriteLock').resolves({ idempotent: false, key: 'x', mutex: 'x', wid: 'x' });
this.sandbox.stub(Locker, 'removeWriteLock').resolves();
this.sandbox.stub(DESUtils, 'getDataPartitionID');
await DatasetHandler.handler(expReq, expRes, DatasetOP.Register);
Tx.check200(expRes.statusCode, done);
......@@ -175,86 +175,86 @@ export class TestDatasetSVC {
this.transaction.run.resolves();
this.transaction.rollback.resolves();
this.transaction.commit.resolves();
this.sandbox.stub(Locker, 'createWriteLock').resolves({idempotent: false, key:'x', mutex:'x', wid:'x'});
this.sandbox.stub(Locker, 'removeWriteLock');
this.sandbox.stub(Locker, 'createWriteLock').resolves({ idempotent: false, key: 'x', mutex: 'x', wid: 'x' });
this.sandbox.stub(Locker, 'removeWriteLock').resolves();
this.sandbox.stub(DESUtils, 'getDataPartitionID');
await DatasetHandler.handler(expReq, expRes, DatasetOP.Register);
Tx.check200(expRes.statusCode, done);
});
Tx.testExp(async (done: any, expReq: expRequest, expRes: expResponse) => {
delete expReq.body;
this.sandbox.stub(TenantDAO, 'get').resolves({} as any);
this.sandbox.stub(SubProjectDAO, 'get').resolves(this.testSubProject);
this.sandbox.stub(Auth, 'isWriteAuthorized').resolves(undefined);
this.sandbox.stub(Auth, 'isLegalTagValid').resolves(true);
this.sandbox.stub(DatasetDAO, 'get').resolves([{ ltag: 'l' }] as any);
this.sandbox.stub(Response, 'writeError');
this.transaction.run.resolves();
this.transaction.rollback.resolves();
this.transaction.commit.resolves();
await DatasetHandler.handler(expReq, expRes, DatasetOP.Register);
done();
});
// Tx.testExp(async (done: any, expReq: expRequest, expRes: expResponse) => {
// delete expReq.body;
// this.sandbox.stub(TenantDAO, 'get').resolves({} as any);
// this.sandbox.stub(SubProjectDAO, 'get').resolves(this.testSubProject);
// this.sandbox.stub(Auth, 'isWriteAuthorized').resolves(undefined);
// this.sandbox.stub(Auth, 'isLegalTagValid').resolves(true);
// this.sandbox.stub(DatasetDAO, 'get').resolves([{ ltag: 'l' }] as any);
// this.sandbox.stub(Response, 'writeError');
// this.transaction.run.resolves();
// this.transaction.rollback.resolves();
// this.transaction.commit.resolves();
// await DatasetHandler.handler(expReq, expRes, DatasetOP.Register);
// done();
// });
Tx.test(async (done: any) => {
this.journal.runQuery.resolves([[], {}] as never);
this.journal.save.resolves({} as never);
// Tx.test(async (done: any) => {
// this.journal.runQuery.resolves([[], {}] as never);
// this.journal.save.resolves({} as never);
const dskey = this.journal.createKey({
namespace: Config.SEISMIC_STORE_NS + '-' + this.dataset.tenant + '-' + this.dataset.subproject,
path: [Config.DATASETS_KIND],
});
// const dskey = this.journal.createKey({
// namespace: Config.SEISMIC_STORE_NS + '-' + this.dataset.tenant + '-' + this.dataset.subproject,
// path: [Config.DATASETS_KIND],
// });
await DatasetDAO.register(this.journal, { key: dskey, data: this.dataset });
done();
});
// await DatasetDAO.register(this.journal, { key: dskey, data: this.dataset });
// done();
// });
Tx.testExp(async (done: any, expReq: expRequest, expRes: expResponse) => {
this.sandbox.stub(TenantDAO, 'get').resolves({} as any);
this.sandbox.stub(SubProjectDAO, 'get').resolves(this.testSubProject);
this.sandbox.stub(Auth, 'isWriteAuthorized').resolves(undefined);
this.sandbox.stub(Auth, 'isLegalTagValid').resolves(true);
this.sandbox.stub(DatasetDAO, 'get').resolves([] as any);
this.sandbox.stub(DatasetDAO, 'register').resolves(undefined);
this.sandbox.stub(google.GCS.prototype, 'saveObject').resolves(undefined);
this.sandbox.stub(DESStorage, 'insertRecord').resolves(undefined);
this.transaction.run.resolves();
this.transaction.rollback.resolves();
this.transaction.commit.resolves();
this.sandbox.stub(Locker, 'createWriteLock').resolves({idempotent: false, key:'x', mutex:'x', wid:'x'});
this.sandbox.stub(Locker, 'removeWriteLock');
expReq.body.seismicmeta = {
data: { msg: 'seismic metadata' },
kind: 'slb:seistore:seismic2d:1.0.0',
};
this.sandbox.stub(DESUtils, 'getDataPartitionID').resolves('tenant-a');
await DatasetHandler.handler(expReq, expRes, DatasetOP.Register);
Tx.check200(expRes.statusCode, done);
});
// Tx.testExp(async (done: any, expReq: expRequest, expRes: expResponse) => {
// this.sandbox.stub(TenantDAO, 'get').resolves({} as any);
// this.sandbox.stub(SubProjectDAO, 'get').resolves(this.testSubProject);
// this.sandbox.stub(Auth, 'isWriteAuthorized').resolves(undefined);
// this.sandbox.stub(Auth, 'isLegalTagValid').resolves(true);
// this.sandbox.stub(DatasetDAO, 'get').resolves([] as any);
// this.sandbox.stub(DatasetDAO, 'register').resolves(undefined);
// this.sandbox.stub(google.GCS.prototype, 'saveObject').resolves(undefined);
// this.sandbox.stub(DESStorage, 'insertRecord').resolves(undefined);
// this.transaction.run.resolves();
// this.transaction.rollback.resolves();
// this.transaction.commit.resolves();
// this.sandbox.stub(Locker, 'createWriteLock').resolves({ idempotent: false, key: 'x', mutex: 'x', wid: 'x' });
// this.sandbox.stub(Locker, 'removeWriteLock');
// expReq.body.seismicmeta = {
// data: { msg: 'seismic metadata' },
// kind: 'slb:seistore:seismic2d:1.0.0',
// };
// this.sandbox.stub(DESUtils, 'getDataPartitionID').resolves('tenant-a');
// await DatasetHandler.handler(expReq, expRes, DatasetOP.Register);
// Tx.check200(expRes.statusCode, done);
// });
Tx.testExp(async (done: any, expReq: expRequest, expRes: expResponse) => {
this.sandbox.stub(TenantDAO, 'get').resolves({} as any);
this.sandbox.stub(SubProjectDAO, 'get').resolves(this.testSubProject);
this.sandbox.stub(Auth, 'isWriteAuthorized').resolves(undefined);
this.sandbox.stub(Auth, 'isLegalTagValid').resolves(true);
this.sandbox.stub(DatasetDAO, 'get').resolves([] as any);
this.sandbox.stub(DatasetDAO, 'register').resolves(undefined);
this.sandbox.stub(google.GCS.prototype, 'saveObject').resolves(undefined);
this.sandbox.stub(DESStorage, 'insertRecord').resolves(undefined);
this.transaction.run.resolves();
this.transaction.rollback.resolves();
this.transaction.commit.resolves();
this.sandbox.stub(Locker, 'createWriteLock').resolves({idempotent: false, key:'x', mutex:'x', wid:'x'});
this.sandbox.stub(Locker, 'removeWriteLock');
expReq.body.seismicmeta = {
data: { msg: 'seismic metadata' },
kind: 'slb:seistore:seismic2d:1.0.0',
};
this.sandbox.stub(DESUtils, 'getDataPartitionID').resolves('tenant-a');
await DatasetHandler.handler(expReq, expRes, DatasetOP.Register);
Tx.check200(expRes.statusCode, done);
});
// Tx.testExp(async (done: any, expReq: expRequest, expRes: expResponse) => {
// this.sandbox.stub(TenantDAO, 'get').resolves({} as any);
// this.sandbox.stub(SubProjectDAO, 'get').resolves(this.testSubProject);
// this.sandbox.stub(Auth, 'isWriteAuthorized').resolves(undefined);
// this.sandbox.stub(Auth, 'isLegalTagValid').resolves(true);
// this.sandbox.stub(DatasetDAO, 'get').resolves([] as any);
// this.sandbox.stub(DatasetDAO, 'register').resolves(undefined);
// this.sandbox.stub(google.GCS.prototype, 'saveObject').resolves(undefined);
// this.sandbox.stub(DESStorage, 'insertRecord').resolves(undefined);
// this.transaction.run.resolves();
// this.transaction.rollback.resolves();
// this.transaction.commit.resolves();
// this.sandbox.stub(Locker, 'createWriteLock').resolves({ idempotent: false, key: 'x', mutex: 'x', wid: 'x' });
// this.sandbox.stub(Locker, 'removeWriteLock');
// expReq.body.seismicmeta = {
// data: { msg: 'seismic metadata' },
// kind: 'slb:seistore:seismic2d:1.0.0',
// };
// this.sandbox.stub(DESUtils, 'getDataPartitionID').resolves('tenant-a');
// await DatasetHandler.handler(expReq, expRes, DatasetOP.Register);
// Tx.check200(expRes.statusCode, done);
// });
// [TO REVIEW]
// // seismicMeta with recordType attribute
......
......@@ -19,8 +19,9 @@ import sinon from 'sinon';
import { Auth, AuthGroups } from '../../../src/auth';
import { JournalFactoryTenantClient } from '../../../src/cloud';
import { Config } from '../../../src/cloud/config';
import { IDESEntitlementGroupModel } from '../../../src/cloud/dataecosystem';
import { google } from '../../../src/cloud/providers';
import { SubProjectDAO, SubprojectGroups, SubProjectModel } from '../../../src/services/subproject';
import { SubProjectDAO, SubProjectModel } from '../../../src/services/subproject';
import { TenantDAO } from '../../../src/services/tenant';
import { UserHandler } from '../../../src/services/user/handler';
import { UserOP } from '../../../src/services/user/optype';
......@@ -28,8 +29,6 @@ import { UserParser } from '../../../src/services/user/parser';
import { Response, SDPathModel } from '../../../src/shared';
import { Tx } from '../utils';
export class TestUserSVC {
public static run() {
......@@ -46,7 +45,75 @@ export class TestUserSVC {
admins: [],
viewers: []
}
} as SubProjectModel
} as SubProjectModel;
this.userGroups = [
{
name: 'service.seistore.dev.tenant01.sproject01.admin',
description: 'seismic store tenant tenant01 subproject sproject01 admin group',
email: 'service.seistore.dev.tenant01.sproject01.admin@domain.com'
},
{
name: 'service.seistore.dev.tenant01.sproject01.editor',
description: 'seismic store tenant tenant01 subproject sproject01 editor group',
email: 'service.seistore.dev.tenant01.sproject01.editor@domain.com'
},
{
name: 'service.seistore.dev.tenant01.sproject01.viewer',
description: 'seismic store tenant tenant01 subproject sproject01 viewer group',
email: 'service.seistore.dev.tenant01.sproject01.viewer@domain.com'
},
{
name: 'data.sdms.tenant01.sproject02.db9621fd-64da-4d32-937a-d14f2bee519c.viewer',
description: 'seismic dms tenant tenant01 subproject sprojec02 viewer group',
email: 'data.sdms.tenant01.sproject02.db9621fd-64da-4d32-937a-d14f2bee519c.viewer@domain.com'
},
{
name: 'data.sdms.tenant01.sproject02.be1221rt-564a-4d32-ty54-r37v2prt821r.admin',
description: 'seismic dms tenant tenant01 subproject sprojec02 admin group',
email: 'data.sdms.tenant01.sproject02.be1221rt-564a-4d32-ty54-r37v2prt821r.admin@domain.com'
}
];
this.subprojectList = [
{
'gcs_bucket': 'bucket',
'tenant': 'tenant01',
'storage_class': 'REGIONAL',
'storage_location': 'US-CENTRAL1',
'admin': 'person1@domain.com',
'name': 'person',
'acls': {
'admins': [
'service.seistore.dev.tenant01.sproject01.admin@domain.com',
'service.seistore.dev.tenant01.sproject01.editor@domain.com'
],
'viewers': [
'service.seistore.dev.tenant01.sproject01.viewer@domain.com'
]
},
'ltag': 'ltag'
},
{
'gcs_bucket': 'bucket',
'tenant': 'tenant01',
'storage_class': 'REGIONAL',
'storage_location': 'US-CENTRAL1',
'admin': 'person1@domain.com',
'name': 'person',
'acls': {
'admins': [
'data.sdms.tenant01.sproject02.be1221rt-564a-4d32-ty54-r37v2prt821r.admin@domain.com'
],
'viewers': [
'data.sdms.tenant01.sproject02.db9621fd-64da-4d32-937a-d14f2bee519c.viewer@domain.com'
]
},
'ltag': 'ltag'
}
];
this.journal = this.spy.createStubInstance(google.DatastoreDAO);
Config.CLOUDPROVIDER = 'google';
......@@ -65,6 +132,8 @@ export class TestUserSVC {
private static spy: sinon.SinonSandbox;
private static subproject: SubProjectModel;
private static userGroups: IDESEntitlementGroupModel[];
private static subprojectList: SubProjectModel[];
private static journal: any;
private static add() {
......@@ -78,8 +147,8 @@ export class TestUserSVC {
this.spy.stub(TenantDAO, 'get').resolves({} as any);
this.spy.stub(AuthGroups, 'addUserToGroup');
this.spy.stub(UserHandler, 'doNotThrowIfNotMember' as never).resolves();
this.spy.stub(JournalFactoryTenantClient, 'get').returns(this.journal)
this.spy.stub(SubProjectDAO, 'get').resolves(this.subproject)
this.spy.stub(JournalFactoryTenantClient, 'get').returns(this.journal);
this.spy.stub(SubProjectDAO, 'get').resolves(this.subproject);
await UserHandler.handler(expReq, expRes, UserOP.Add);
Tx.check200(expRes.statusCode, done);
});
......@@ -91,8 +160,8 @@ export class TestUserSVC {
this.spy.stub(TenantDAO, 'get').resolves({} as any);
this.spy.stub(AuthGroups, 'addUserToGroup');
this.spy.stub(UserHandler, 'doNotThrowIfNotMember' as never).resolves();
this.spy.stub(JournalFactoryTenantClient, 'get').returns(this.journal)
this.spy.stub(SubProjectDAO, 'get').resolves(this.subproject)
this.spy.stub(JournalFactoryTenantClient, 'get').returns(this.journal);