Commit a1cff8cf authored by Varunkumar Manohar's avatar Varunkumar Manohar
Browse files

Update user roles endpoint to use the acls on subprojects

parent 10ef056c
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);
this.spy.stub(SubProjectDAO, 'get').resolves(this.subproject);
await UserHandler.handler(expReq, expRes, UserOP.Add);
Tx.check200(expRes.statusCode, done);
});
...