Skip to content

Commit

Permalink
SIMSBIOHUB-430: Submission View - Published / Unpublished Tabs (#225)
Browse files Browse the repository at this point in the history
- Create new tabs for submissions that have completed reviews, but are either unpublished or published.
- Tabs to differentiate between unpublished and published states of submissions.
  • Loading branch information
KjartanE authored Jan 12, 2024
1 parent 825aee2 commit a108222
Show file tree
Hide file tree
Showing 10 changed files with 713 additions and 6 deletions.
103 changes: 103 additions & 0 deletions api/src/paths/administrative/submission/published.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import chai, { expect } from 'chai';
import { describe } from 'mocha';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import * as db from '../../../database/db';
import { HTTPError } from '../../../errors/http-error';
import { SECURITY_APPLIED_STATUS } from '../../../repositories/security-repository';
import { SubmissionRecordWithSecurityAndRootFeatureType } from '../../../repositories/submission-repository';
import { SubmissionService } from '../../../services/submission-service';
import { getMockDBConnection, getRequestHandlerMocks } from '../../../__mocks__/db';
import { getPublishedSubmissionsForAdmins } from './published';

chai.use(sinonChai);

describe('getPublishedSubmissionsForAdmins', () => {
afterEach(() => {
sinon.restore();
});

it('re-throws any error that is thrown', async () => {
const mockDBConnection = getMockDBConnection({
open: () => {
throw new Error('test error');
}
});

sinon.stub(db, 'getDBConnection').returns(mockDBConnection);

const { mockReq, mockRes, mockNext } = getRequestHandlerMocks();

const requestHandler = getPublishedSubmissionsForAdmins();

try {
await requestHandler(mockReq, mockRes, mockNext);
expect.fail();
} catch (actualError) {
expect((actualError as HTTPError).message).to.equal('test error');
}
});

it('should return an array of Reviewed submission objects', async () => {
const dbConnectionObj = getMockDBConnection({
commit: sinon.stub(),
rollback: sinon.stub(),
release: sinon.stub()
});

sinon.stub(db, 'getDBConnection').returns(dbConnectionObj);

const mockResponse: SubmissionRecordWithSecurityAndRootFeatureType[] = [
{
submission_id: 1,
uuid: '123-456-789',
security_review_timestamp: '2023-12-12',
submitted_timestamp: '2023-12-12',
publish_timestamp: '2023-12-12',
source_system: 'SIMS',
name: 'name',
description: 'description',
create_date: '2023-12-12',
create_user: 1,
update_date: null,
update_user: null,
revision_count: 0,
security: SECURITY_APPLIED_STATUS.SECURED,
root_feature_type_id: 1,
root_feature_type_name: 'dataset'
},
{
submission_id: 2,
uuid: '789-456-123',
security_review_timestamp: '2023-12-12',
submitted_timestamp: '2023-12-12',
source_system: 'SIMS',
publish_timestamp: '2023-12-12',
name: 'name',
description: 'description',
create_date: '2023-12-12',
create_user: 1,
update_date: '2023-12-12',
update_user: 1,
revision_count: 1,
security: SECURITY_APPLIED_STATUS.PARTIALLY_SECURED,
root_feature_type_id: 1,
root_feature_type_name: 'dataset'
}
];

const { mockReq, mockRes, mockNext } = getRequestHandlerMocks();

const getReviewedSubmissionsStub = sinon
.stub(SubmissionService.prototype, 'getPublishedSubmissionsForAdmins')
.resolves(mockResponse);

const requestHandler = getPublishedSubmissionsForAdmins();

await requestHandler(mockReq, mockRes, mockNext);

expect(getReviewedSubmissionsStub).to.have.been.calledOnce;
expect(mockRes.statusValue).to.equal(200);
expect(mockRes.jsonValue).to.eql(mockResponse);
});
});
157 changes: 157 additions & 0 deletions api/src/paths/administrative/submission/published.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { RequestHandler } from 'express';
import { Operation } from 'express-openapi';
import { SYSTEM_ROLE } from '../../../constants/roles';
import { getDBConnection } from '../../../database/db';
import { defaultErrorResponses } from '../../../openapi/schemas/http-responses';
import { SECURITY_APPLIED_STATUS } from '../../../repositories/security-repository';
import { authorizeRequestHandler } from '../../../request-handlers/security/authorization';
import { SubmissionService } from '../../../services/submission-service';
import { getLogger } from '../../../utils/logger';

const defaultLog = getLogger('paths/administrative/submission/published');

export const GET: Operation = [
authorizeRequestHandler(() => {
return {
and: [
{
validSystemRoles: [SYSTEM_ROLE.SYSTEM_ADMIN, SYSTEM_ROLE.DATA_ADMINISTRATOR],
discriminator: 'SystemRole'
}
]
};
}),
getPublishedSubmissionsForAdmins()
];

GET.apiDoc = {
description: 'Get a list of submissions that have completed security review (are published).',
tags: ['admin'],
security: [
{
Bearer: []
}
],
responses: {
200: {
description: 'List of submissions that have completed security review.',
content: {
'application/json': {
schema: {
type: 'array',
items: {
type: 'object',
required: [
'submission_id',
'uuid',
'security_review_timestamp',
'submitted_timestamp',
'source_system',
'name',
'description',
'create_date',
'create_user',
'update_date',
'update_user',
'revision_count',
'security',
'root_feature_type_id',
'root_feature_type_name'
],
properties: {
submission_id: {
type: 'integer',
minimum: 1
},
uuid: {
type: 'string',
format: 'uuid'
},
security_review_timestamp: {
type: 'string',
nullable: true
},
source_system: {
type: 'string'
},
name: {
type: 'string',
maxLength: 200
},
description: {
type: 'string',
maxLength: 3000
},
create_date: {
type: 'string'
},
create_user: {
type: 'integer',
minimum: 1
},
update_date: {
type: 'string',
nullable: true
},
update_user: {
type: 'integer',
minimum: 1,
nullable: true
},
revision_count: {
type: 'integer',
minimum: 0
},
security: {
type: 'string',
enum: [
SECURITY_APPLIED_STATUS.PENDING,
SECURITY_APPLIED_STATUS.UNSECURED,
SECURITY_APPLIED_STATUS.SECURED,
SECURITY_APPLIED_STATUS.PARTIALLY_SECURED
]
},
root_feature_type_id: {
type: 'integer',
minimum: 1
},
root_feature_type_name: {
type: 'string'
}
}
}
}
}
}
},
...defaultErrorResponses
}
};

/**
* Get all published submissions for admins.
*
* @returns {RequestHandler}
*/
export function getPublishedSubmissionsForAdmins(): RequestHandler {
return async (req, res) => {
const connection = getDBConnection(req['keycloak_token']);

try {
await connection.open();

const service = new SubmissionService(connection);
const response = await service.getPublishedSubmissionsForAdmins();

await connection.commit();

return res.status(200).json(response);
} catch (error) {
defaultLog.error({ label: 'getPublishedSubmissionsForAdmins', message: 'error', error });
await connection.rollback();
throw error;
} finally {
connection.release();
}
};
}
54 changes: 52 additions & 2 deletions api/src/repositories/submission-repository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,7 @@ describe('SubmissionRepository', () => {
source_system: 'SIMS',
name: 'name',
description: 'description',
publish_timestamp: '2023-12-12',
publish_timestamp: null,
create_date: '2023-12-12',
create_user: 1,
update_date: null,
Expand All @@ -984,7 +984,7 @@ describe('SubmissionRepository', () => {
source_system: 'SIMS',
name: 'name',
description: 'description',
publish_timestamp: '2023-12-12',
publish_timestamp: null,
create_date: '2023-12-12',
create_user: 1,
update_date: '2023-12-12',
Expand All @@ -1005,6 +1005,56 @@ describe('SubmissionRepository', () => {
});
});

describe('getPublishedSubmissionsForAdmins', () => {
beforeEach(() => {
sinon.restore();
});

it('should succeed with valid data', async () => {
const mockSubmissionRecords: SubmissionRecord[] = [
{
submission_id: 1,
uuid: '123-456-789',
security_review_timestamp: '2023-12-12',
submitted_timestamp: '2023-12-12',
source_system: 'SIMS',
name: 'name',
description: 'description',
publish_timestamp: '2023-12-12',
create_date: '2023-12-12',
create_user: 1,
update_date: null,
update_user: null,
revision_count: 0
},
{
submission_id: 2,
uuid: '789-456-123',
security_review_timestamp: '2023-12-12',
submitted_timestamp: '2023-12-12',
source_system: 'SIMS',
name: 'name',
description: 'description',
publish_timestamp: '2023-12-12',
create_date: '2023-12-12',
create_user: 1,
update_date: '2023-12-12',
update_user: 1,
revision_count: 1
}
];

const mockResponse = { rowCount: 2, rows: mockSubmissionRecords } as unknown as Promise<QueryResult<any>>;

const mockDBConnection = getMockDBConnection({ sql: async () => mockResponse });

const submissionRepository = new SubmissionRepository(mockDBConnection);

const response = await submissionRepository.getPublishedSubmissionsForAdmins();

expect(response).to.eql(mockSubmissionRecords);
});
});
describe('getReviewedSubmissionsWithSecurity', () => {
beforeEach(() => {
sinon.restore();
Expand Down
Loading

0 comments on commit a108222

Please sign in to comment.