Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Course Admission API #774

Merged
merged 9 commits into from
Jan 6, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/api/AdmissionManagement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default class AdmissionManagement extends CommonHyperledger {
*/
async submitSignedAdmissionsProposal(signedProposal: SignedProposalMessage): Promise<APIResponse<UnsignedTransactionMessage>> {
return await this._axios
.post(`/admissions/proposal/submit`, signedProposal)
.post(`/admissions/signed_proposal`, signedProposal)
.then((response: AxiosResponse) => {
return {
statusCode: response.status,
Expand Down Expand Up @@ -163,7 +163,7 @@ export default class AdmissionManagement extends CommonHyperledger {
*/
async getUnsignedCourseAdmissionAddProposal(courseAdmission: CourseAdmission): Promise<APIResponse<UnsignedProposalMessage>> {
return await this._axios
.post(`/admissions/courses/proposal/add`, courseAdmission)
.post(`/admissions/courses/unsigned_add_proposal`, courseAdmission)
.then((response: AxiosResponse) => {
return {
statusCode: response.status,
Expand Down Expand Up @@ -207,7 +207,7 @@ export default class AdmissionManagement extends CommonHyperledger {
*/
async getUnsignedCourseAdmissionDropProposal(admissionId: string): Promise<APIResponse<UnsignedProposalMessage>> {
return await this._axios
.post(`/admissions/courses/proposal/drop`, { admissionId })
.post(`/admissions/courses/unsigned_drop_proposal`, { admissionId })
.then((response: AxiosResponse) => {
return {
statusCode: response.status,
Expand Down
8 changes: 3 additions & 5 deletions src/api/abstractions/FrontendSigning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export async function updateMatriculation(
);
}

export async function addCourseAdmission(addAdmission: CourseAdmission, protoUrl?: string) {
export async function addCourseAdmission(enrollmentId: string, addAdmission: CourseAdmission, protoUrl?: string) {
const genericHandler = new GenericResponseHandler("add admission");

const genericHandler2 = new GenericResponseHandler("transaction");
Expand All @@ -78,7 +78,7 @@ export async function addCourseAdmission(addAdmission: CourseAdmission, protoUrl
return genericHandler.handleResponse(arg);
},
async (payload: ProposalPayload) => {
return await validateCourseAdmissionProposal(payload, undefined, addAdmission);
return validateCourseAdmissionProposal(payload, undefined, addAdmission, enrollmentId);
},
async (message: SignedProposalMessage) => {
return await admissionManagement.submitSignedAdmissionsProposal(message);
Expand All @@ -87,7 +87,7 @@ export async function addCourseAdmission(addAdmission: CourseAdmission, protoUrl
return genericHandler2.handleResponse(response);
},
(transaction: TransactionMessage) => {
return admissionsTransactionValidator(transaction, undefined, addAdmission);
return admissionsTransactionValidator(transaction, undefined, addAdmission, enrollmentId);
},
async (message: SignedTransactionMessage) => {
return await admissionManagement.submitSignedAdmissionsTransaction(message);
Expand Down Expand Up @@ -149,7 +149,6 @@ async function abstractHandler(
const privateKey = await useStore()
.getters.privateKey()
.catch(() => {
console.log("a");
return undefined;
});

Expand All @@ -158,7 +157,6 @@ async function abstractHandler(
const certificate = await useStore()
.getters.certificate()
.catch(() => {
console.log("b");
return undefined;
});

Expand Down
18 changes: 6 additions & 12 deletions src/api/helpers/ProposalPayloadValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { ProposalPayload } from "../api_models/common/Proposal";
import { isEqual } from "lodash";
import { UC4Identifier } from "./UC4Identifier";
import CourseAdmission from "../api_models/admission_management/CourseAdmission";
import CertificateManagement from "../CertificateManagement";
import GenericResponseHandler from "@/use/helpers/GenericResponseHandler";

export function validateMatriculationProposal(
proposalPayload: ProposalPayload,
Expand Down Expand Up @@ -54,11 +52,12 @@ export function validateMatriculationProposal(
return false;
}

export async function validateCourseAdmissionProposal(
export function validateCourseAdmissionProposal(
proposalPayload: ProposalPayload,
admissionId?: string,
courseAdmission?: CourseAdmission
): Promise<boolean> {
courseAdmission?: CourseAdmission,
enrollmentId?: string
): boolean {
if (!admissionId && !courseAdmission) return false;

const name = proposalPayload.input.input.args[0];
Expand All @@ -68,12 +67,8 @@ export async function validateCourseAdmissionProposal(
if (name !== UC4Identifier.CONTRACT_APPROVAL + UC4Identifier.SEPERATOR + UC4Identifier.TRANSACTION_APPROVAL) return false;
if (contractToApprove !== UC4Identifier.CONTRACT_ADMISSION) return false;

const certificateManagement = new CertificateManagement();
const response = await certificateManagement.getOwnEnrollmentId();
const enrollmentId = new GenericResponseHandler("enrollment id").handleResponse(response).id;

if (transactionToApprove === UC4Identifier.TRANSACTION_ADD_ADMISSION) {
if (!courseAdmission) return false;
if (!courseAdmission || !enrollmentId) return false;

const jsonString = proposalPayload.input.input.args[3];
const paramsArray: string[] = JSON.parse(jsonString);
Expand All @@ -82,9 +77,8 @@ export async function validateCourseAdmissionProposal(
if (paramsArray.length > 1) return false;

let result = proposalAdmission.courseId === courseAdmission.courseId;
result = result && proposalAdmission.moduleId === proposalAdmission.moduleId;
result = result && proposalAdmission.moduleId === courseAdmission.moduleId;
result = result && proposalAdmission.enrollmentId === enrollmentId;

return result;
}

Expand Down
5 changes: 3 additions & 2 deletions src/api/helpers/TransactionValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,16 @@ export function matriculationTransactionValidator(
export function admissionsTransactionValidator(
transaction: TransactionMessage,
admissionId?: string,
courseAdmission?: CourseAdmission
courseAdmission?: CourseAdmission,
enrollmentId?: string
): boolean {
if (!(transaction.data.actions.length === 1)) {
return false;
}

const payload: ProposalPayload = transaction.data.actions[0].payload.chainCodeProposalPayload;

if (!validateCourseAdmissionProposal(payload, admissionId, courseAdmission)) {
if (!validateCourseAdmissionProposal(payload, admissionId, courseAdmission, enrollmentId)) {
return false;
}

Expand Down
15 changes: 15 additions & 0 deletions src/use/helpers/Versions.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import AdmissionManagement from "@/api/AdmissionManagement";
import AuthenticationManagement from "@/api/AuthenticationManagement";
import CertificateManagement from "@/api/CertificateManagement";
import CourseManagement from "@/api/CourseManagement";
Expand Down Expand Up @@ -35,6 +36,9 @@ export async function getVersions(): Promise<version[]> {
const examinationRegulationManagementVersion = await ExaminationRegulationManagement.getVersion();
const hlfExamRegVersion = await ExaminationRegulationManagement.getHyperledgerVersion();

const admissionsManagementVersion = await AdmissionManagement.getVersion();
const hlfAdmissionVersion = await AdmissionManagement.getHyperledgerVersion();

versions.push({
name: "Frontend",
version: frontEndVersion,
Expand Down Expand Up @@ -98,5 +102,16 @@ export async function getVersions(): Promise<version[]> {
hlVersions: hlfExamRegVersion,
});

versions.push({
name: "Admissions Management",
version: admissionsManagementVersion,
link:
"https://github.com/upb-uc4/University-Credits-4.0/blob/" +
"admission-" +
admissionsManagementVersion +
"/product_code/admission_service/CHANGELOG.md",
hlVersions: hlfAdmissionVersion,
});

return versions;
}
2 changes: 1 addition & 1 deletion tests/fixtures/course.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
"endDate" : "2000-01-01",
"lecturerId" : "lecturer",
"maxParticipants" : 10,
"moduleIds": ["M.1275.01159"]
"moduleIds": ["M.1275.01158"]
}
42 changes: 29 additions & 13 deletions tests/unit/api/admissionManagement.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,24 @@ import AdmissionManagement from "@/api/AdmissionManagement";
import { Account } from "@/entities/Account";
import { Role } from "@/entities/Role";
import { readFileSync } from "fs";
import MachineUserAuthenticationManagement from "tests/helper/MachineUserAuthenticationManagement";
import { getRandomizedUserAndAuthUser } from "tests/helper/Users";
import UnsignedProposalMessage from "@/api/api_models/common/UnsignedProposalMessage";
import { arrayBufferToBase64, createCSR, createKeyPair, deriveKeyFromPassword, wrapKey } from "@/use/crypto/certificates";
import MachineUserAuthenticationManagement from "../../helper/MachineUserAuthenticationManagement";
import { getRandomizedUserAndAuthUser } from "../../helper/Users";
import {
arrayBufferToBase64,
base64ToArrayBuffer,
createCSR,
createKeyPair,
deriveKeyFromPassword,
unwrapKey,
wrapKey,
} from "@/use/crypto/certificates";
import CourseAdmission from "@/api/api_models/admission_management/CourseAdmission";
import CourseManagement from "@/api/CourseManagement";
import { getRandomizedCourse } from "tests/helper/Courses";
import { getRandomizedCourse } from "../../helper/Courses";
import { addCourseAdmission, dropCourseAdmission, updateMatriculation } from "@/api/abstractions/FrontendSigning";
import { useStore } from "@/use/store/store";
import EncryptedPrivateKey from "@/api/api_models/certificate_management/EncryptedPrivateKey";
import { MutationTypes } from "@/use/store/mutation-types";

let userManagement: UserManagement;
let certManagement: CertificateManagement;
Expand All @@ -32,13 +42,18 @@ const course = getRandomizedCourse();
const protoURL = "public/hlf-proto.json";
const EXAM_REG_1 = "Bachelor Computer Science v3";

jest.setTimeout(30000);
jest.setTimeout(60000);
bastihav marked this conversation as resolved.
Show resolved Hide resolved

describe("Admissions management", () => {
beforeAll(async () => {
const success = await MachineUserAuthenticationManagement._getRefreshToken(adminAuth);
userManagement = new UserManagement();

useStore().commit(MutationTypes.SET_DECRYPT_PRIVATE_KEY_MODAL, async (encKey: EncryptedPrivateKey) => {
const wrappingKey = await deriveKeyFromPassword(encryptionPassword, encKey.salt);
return await unwrapKey(base64ToArrayBuffer(encKey.key), wrappingKey.key, base64ToArrayBuffer(encKey.iv));
});

expect(success.returnValue.login).not.toEqual("");
});

Expand All @@ -57,6 +72,7 @@ describe("Admissions management", () => {
});

test("Fetch course id of course", async () => {
await new Promise((r) => setTimeout(r, 3000));
const courseManagement = new CourseManagement();
const response = await courseManagement.getCourses(course.courseName);
expect(response.statusCode).toBe(200);
Expand Down Expand Up @@ -111,12 +127,12 @@ describe("Admissions management", () => {
const admission: CourseAdmission = {
admissionId: "",
courseId,
enrollmentId,
enrollmentId: "",
moduleId,
timestamp: "",
};

const result = await addCourseAdmission(admission, protoURL);
const result = await addCourseAdmission(enrollmentId, admission, protoURL);

expect(result).toBe(true);
});
Expand All @@ -126,9 +142,9 @@ describe("Admissions management", () => {
expect(response.statusCode).toBe(200);
expect(response.returnValue.length).toEqual(1);

expect(response.returnValue[0].courseId).toEqual(courseAdmission.courseId);
expect(response.returnValue[0].enrollmentId).toEqual(courseAdmission.enrollmentId);
expect(response.returnValue[0].moduleId).toEqual(courseAdmission.moduleId);
expect(response.returnValue[0].courseId).toEqual(courseId);
expect(response.returnValue[0].enrollmentId).toEqual(enrollmentId);
expect(response.returnValue[0].moduleId).toEqual(moduleId);

courseAdmission = response.returnValue[0];
});
Expand All @@ -151,8 +167,8 @@ describe("Admissions management", () => {
userManagement = new UserManagement();
const courseManagement = new CourseManagement();

const success = await userManagement.deleteUser(student.username);
const success2 = await courseManagement.deleteCourse(course.courseId);
const success = await userManagement.forceDeleteUser(student.username);
const success2 = await courseManagement.deleteCourse(courseId);

expect(success.returnValue).toBe(true);
expect(success2.returnValue).toBe(true);
Expand Down
36 changes: 26 additions & 10 deletions tests/unit/proposalValidation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,35 +113,51 @@ describe("Proposal Validation Tests", () => {
});

test("Test Admission Proposal Validation addCourseAdmission", async () => {
const addCourseAdmissionProposalB64 = "";
const addCourseAdmissionProposalB64 =
"CrcJCmsIAxABGgwIgdPj/gUQgKzPvAIiCW15Y2hhbm5lbCpAYjU2YzFkNGYzZTJlZTI3NzFmNDU3YjdmZjM5MTA3NThmZWJhYTEzZGMxZjk1YWE0Y2VjNDQ1Yjk4ZTVmNzZlODoKEggSBnVjNC1jYxLHCAqqCAoHb3JnMU1TUBKeCC0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlDM0RDQ0FvS2dBd0lCQWdJVUtlcXlXcXFaVWlnOG9jRklmbTk2cjgvTC9YMHdDZ1lJS29aSXpqMEVBd0l3ClhqRUxNQWtHQTFVRUJoTUNSRVV4RERBS0JnTlZCQWdNQTA1U1Z6RVNNQkFHQTFVRUJ3d0pVR0ZrWlhKaWIzSnUKTVF3d0NnWURWUVFLREFOVlF6UXhEREFLQmdOVkJBc01BMVZETkRFUk1BOEdBMVVFQXd3SWNtTmhMVzl5WnpFdwpIaGNOTWpBeE1qRTFNVFkwTmpBd1doY05NakV4TWpFMU1UWTFNVEF3V2pCRk1ROHdEUVlEVlFRTEV3WmpiR2xsCmJuUXhNakF3QmdOVkJBTVRLV1p5YjI1MFpXNWtMWE5wWjI1cGJtY3RkR1Z6ZEdWeUxXbHVabTh0WVdSa1FXUnQKYVhOemFXOXVNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVJb3BmYzNHVmNxdCtHcVdmQ21SOApCZDVsY1ZRQXBOK25HOTVaK1FhZXRGNVJVRHllMnViZFB0V1VlT0s5TnFrSk1oVWJ5ZGtSTDVvL0RoRmFiYlZhCjY2T0NBVFV3Z2dFeE1BNEdBMVVkRHdFQi93UUVBd0lEcURBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3REFZRFZSMFRBUUgvQkFJd0FEQWRCZ05WSFE0RUZnUVUzZTJLUzhodmRUM1FNSU1JQ0pRMwphK3htL1Nvd0h3WURWUjBqQkJnd0ZvQVVwU3JzY29PYzBTOWNrdHlhUE50elpZaEFkRVV3TkFZRFZSMFJCQzB3Cks0SXBabkp2Ym5SbGJtUXRjMmxuYm1sdVp5MTBaWE4wWlhJdGFXNW1ieTFoWkdSQlpHMXBjM05wYjI0d2ZBWUkKS2dNRUJRWUhDQUVFY0hzaVlYUjBjbk1pT25zaWFHWXVRV1ptYVd4cFlYUnBiMjRpT2lJaUxDSm9aaTVGYm5KdgpiR3h0Wlc1MFNVUWlPaUptY205dWRHVnVaQzF6YVdkdWFXNW5MWFJsYzNSbGNpMXBibVp2TFdGa1pFRmtiV2x6CmMybHZiaUlzSW1obUxsUjVjR1VpT2lKamJHbGxiblFpZlgwd0NnWUlLb1pJemowRUF3SURTQUF3UlFJaEFNanMKck85dTI2MXpKdFYxTzl6TDFyUmNLMHhjVFpZMW9yMkZaWTU0NkNYNUFpQnZtSW5LN3lsR1dvU21hTldTdVovSwpxTUtISE81SHM1QXR0TGpLTlRUL2NBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoSGI9/QOyOaL66/z6CIVh+vVeVHR5u0HA1IxLAAgq9Agq6AggBEggSBnVjNC1jYxqrAgofVUM0LkFwcHJvdmFsOmFwcHJvdmVUcmFuc2FjdGlvbgoNVUM0LkFkbWlzc2lvbgoMYWRkQWRtaXNzaW9uCuoBWyJ7XCJhZG1pc3Npb25JZFwiOlwiZnJvbnRlbmQtc2lnbmluZy10ZXN0ZXItaW5mby1hZGRBZG1pc3Npb246QzFcIixcImVucm9sbG1lbnRJZFwiOlwiZnJvbnRlbmQtc2lnbmluZy10ZXN0ZXItaW5mby1hZGRBZG1pc3Npb25cIixcImNvdXJzZUlkXCI6XCJDMVwiLFwibW9kdWxlSWRcIjpcIk1hdHJpY3VsYXRpb25UZXN0TW9kdWxlLjFcIixcInRpbWVzdGFtcFwiOlwiMjAyMC0xMi0zMVQyMzo1OTo1OVwifSJd";

const addCourseAdmissionProposal = await decodeProposal(addCourseAdmissionProposalB64, protoURL);

if (!addCourseAdmissionProposal) fail("Could not decode Add Course Admission Proposal");

const addCourseAdmission: CourseAdmission = {
admissionId: "",
courseId: "",
enrollmentId: "",
moduleId: "",
timestamp: "",
admissionId: "frontend-signing-tester-info-addAdmission:C1",
courseId: "C1",
enrollmentId: "frontend-signing-tester-info-addAdmission",
moduleId: "MatriculationTestModule.1",
timestamp: "2020-12-31T23:59:59",
};

expect(validateCourseAdmissionProposal(addCourseAdmissionProposal.payload, undefined, addCourseAdmission)).toBe(true);
expect(
validateCourseAdmissionProposal(
addCourseAdmissionProposal.payload,
undefined,
addCourseAdmission,
addCourseAdmission.enrollmentId
)
).toBe(true);

addCourseAdmission.courseId = "this is a different id";

expect(validateCourseAdmissionProposal(addCourseAdmissionProposal.payload, undefined, addCourseAdmission)).toBe(false);
expect(
validateCourseAdmissionProposal(
addCourseAdmissionProposal.payload,
undefined,
addCourseAdmission,
addCourseAdmission.enrollmentId
)
).toBe(false);
});

test("Test Admission Proposal Validation dropCourseAdmission", async () => {
const dropCourseAdmissionProposalB64 = "";
const dropCourseAdmissionProposalB64 =
"CroJCmoIAxABGgsI4eLj/gUQgL/WBiIJbXljaGFubmVsKkAxMTUwMzEyNjMxNDI2ZmQxMTkyNDZjYmQwMjI0YjcyN2FhZGEwNDkzNDhhM2ZkYTUyNzNlNTA5YTQzMjQ0YzY2OgoSCBIGdWM0LWNjEssICq4ICgdvcmcxTVNQEqIILS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMzekNDQW9XZ0F3SUJBZ0lVZjJ5d3dwMnM4TFAzT1ExRE1uOTdEd1NONEhnd0NnWUlLb1pJemowRUF3SXcKWGpFTE1Ba0dBMVVFQmhNQ1JFVXhEREFLQmdOVkJBZ01BMDVTVnpFU01CQUdBMVVFQnd3SlVHRmtaWEppYjNKdQpNUXd3Q2dZRFZRUUtEQU5WUXpReEREQUtCZ05WQkFzTUExVkROREVSTUE4R0ExVUVBd3dJY21OaExXOXlaekV3CkhoY05NakF4TWpFMU1UY3hPVEF3V2hjTk1qRXhNakUxTVRjeU5EQXdXakJHTVE4d0RRWURWUVFMRXdaamJHbGwKYm5ReE16QXhCZ05WQkFNVEttWnliMjUwWlc1a0xYTnBaMjVwYm1jdGRHVnpkR1Z5TFdsdVptOHRaSEp2Y0VGawpiV2x6YzJsdmJqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJHTitmRlBmWlhNdFJHLzlKTUdlCkduT1d5VTV1UkF0Wk9EdHl6MjJFRndDenR1Y2NpSnZZOTM0anZxblhRWmtZWEVnaDZEVFFZRGt6Y1NIU0UrMVUKTk5TamdnRTNNSUlCTXpBT0JnTlZIUThCQWY4RUJBTUNBNmd3SFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFRwpDQ3NHQVFVRkJ3TUNNQXdHQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZCNW9lZ3dnWmptYjRadERRWnA2CnE0Q0plRVF0TUI4R0ExVWRJd1FZTUJhQUZHRCtCbEYrTWRHR2d4STFXWk9NMkhXMDF6d2JNRFVHQTFVZEVRUXUKTUN5Q0ttWnliMjUwWlc1a0xYTnBaMjVwYm1jdGRHVnpkR1Z5TFdsdVptOHRaSEp2Y0VGa2JXbHpjMmx2YmpCOQpCZ2dxQXdRRkJnY0lBUVJ4ZXlKaGRIUnljeUk2ZXlKb1ppNUJabVpwYkdsaGRHbHZiaUk2SWlJc0ltaG1Ma1Z1CmNtOXNiRzFsYm5SSlJDSTZJbVp5YjI1MFpXNWtMWE5wWjI1cGJtY3RkR1Z6ZEdWeUxXbHVabTh0WkhKdmNFRmsKYldsemMybHZiaUlzSW1obUxsUjVjR1VpT2lKamJHbGxiblFpZlgwd0NnWUlLb1pJemowRUF3SURTQUF3UlFJaApBTThZbWo3SUFYYnNSbWh4UGR0U0JwTDY2UUU2ckZrRzQ4UTczOFpLZWJ2eUFpQXJHQVl1ZHVTR3ZqR0lZUDNNCnFCemtKSWZrSGpoT1BNRFBvcUdHMDJFSUR3PT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoSGPBqO1aiUSFuuwt8sb+ZEyQpvi7JM42dKhKGAQqDAQqAAQgBEggSBnVjNC1jYxpyCh9VQzQuQXBwcm92YWw6YXBwcm92ZVRyYW5zYWN0aW9uCg1VQzQuQWRtaXNzaW9uCg1kcm9wQWRtaXNzaW9uCjFbImZyb250ZW5kLXNpZ25pbmctdGVzdGVyLWluZm8tZHJvcEFkbWlzc2lvbjpDMSJd";

const dropCourseAdmissionProposal = await decodeProposal(dropCourseAdmissionProposalB64, protoURL);

if (!dropCourseAdmissionProposal) fail("Could not decode Drop Course Admission Proposal");

let admissionId = "";
let admissionId = "frontend-signing-tester-info-dropAdmission:C1";

expect(validateCourseAdmissionProposal(dropCourseAdmissionProposal.payload, admissionId)).toBe(true);

Expand Down
Loading