Skip to content

Commit 6d79135

Browse files
#1910 - Student profile returns SIN (#2354)
- Added a new DTO to contain sensitive data and changed the logic to make the student api to not bring the SIN data. - Removed the SIN property from the student profile retrieved by the student. ## Student view ![image](https://github.com/bcgov/SIMS/assets/78114138/2c09f546-1ccb-4994-bd9a-e6f68cc95e01) ## Institution view ![image](https://github.com/bcgov/SIMS/assets/78114138/8e689189-672a-4eaa-9383-0a14d8bf0df1) ## Ministry view ![image](https://github.com/bcgov/SIMS/assets/78114138/db71230f-4d84-4530-8bea-1cb38aa1a5e7)
1 parent 61ff3cf commit 6d79135

File tree

10 files changed

+88
-25
lines changed

10 files changed

+88
-25
lines changed

Diff for: sources/packages/backend/apps/api/src/route-controllers/student/_tests_/e2e/student.students.controller.getStudentProfile.e2e-spec.ts

-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ describe("StudentInstitutionsController(e2e)-getStudentProfile", () => {
6464
},
6565
disabilityStatus: student.disabilityStatus,
6666
validSin: student.sinValidation.isValidSIN,
67-
sin: student.sinValidation.sin,
6867
});
6968
});
7069

Diff for: sources/packages/backend/apps/api/src/route-controllers/student/models/student.dto.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,13 @@ export class StudentProfileAPIOutDTO {
181181
contact: ContactInformationAPIOutDTO;
182182
validSin: boolean;
183183
disabilityStatus: DisabilityStatus;
184+
}
185+
186+
export class InstitutionStudentProfileAPIOutDTO extends StudentProfileAPIOutDTO {
184187
sin: string;
185188
}
186189

187-
export class AESTStudentProfileAPIOutDTO extends StudentProfileAPIOutDTO {
190+
export class AESTStudentProfileAPIOutDTO extends InstitutionStudentProfileAPIOutDTO {
188191
hasRestriction: boolean;
189192
}
190193

Diff for: sources/packages/backend/apps/api/src/route-controllers/student/student.aest.controller.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -242,13 +242,18 @@ export class StudentAESTController extends BaseController {
242242
@Param("studentId", ParseIntPipe) studentId: number,
243243
): Promise<AESTStudentProfileAPIOutDTO> {
244244
const [student, studentRestrictions] = await Promise.all([
245-
this.studentControllerService.getStudentProfile(studentId),
245+
this.studentControllerService.getStudentProfile(studentId, {
246+
withSensitiveData: true,
247+
}),
246248
this.studentRestrictionService.getStudentRestrictionsById(studentId, {
247249
onlyActive: true,
248250
}),
249251
]);
250252

251-
return { ...student, hasRestriction: !!studentRestrictions.length };
253+
return {
254+
...student,
255+
hasRestriction: !!studentRestrictions.length,
256+
};
252257
}
253258

254259
/**

Diff for: sources/packages/backend/apps/api/src/route-controllers/student/student.controller.service.ts

+30-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
StudentProfileAPIOutDTO,
2121
StudentFileDetailsAPIOutDTO,
2222
StudentUploadFileAPIOutDTO,
23+
InstitutionStudentProfileAPIOutDTO,
2324
} from "./models/student.dto";
2425
import { transformAddressDetailsForAddressBlockForm } from "../utils/address-utils";
2526

@@ -113,14 +114,36 @@ export class StudentControllerService {
113114
* @param studentId student id to retrieve the data.
114115
* @returns student profile details.
115116
*/
116-
async getStudentProfile(studentId: number): Promise<StudentProfileAPIOutDTO> {
117+
async getStudentProfile(studentId: number): Promise<StudentProfileAPIOutDTO>;
118+
/**
119+
* Get the student information that represents the profile.
120+
* @param studentId student id to retrieve the data.
121+
* @param options options:
122+
* - `withSensitiveData` boolean option to return sensitive data such as SIN.
123+
* @returns student profile details.
124+
*/
125+
async getStudentProfile(
126+
studentId: number,
127+
options: { withSensitiveData: true },
128+
): Promise<InstitutionStudentProfileAPIOutDTO>;
129+
/**
130+
* Get the student information that represents the profile.
131+
* @param studentId student id to retrieve the data.
132+
* @param options options:
133+
* - `withSensitiveData` boolean option to return sensitive data such as SIN.
134+
* @returns student profile details.
135+
*/
136+
async getStudentProfile(
137+
studentId: number,
138+
options?: { withSensitiveData: true },
139+
): Promise<StudentProfileAPIOutDTO | InstitutionStudentProfileAPIOutDTO> {
117140
const student = await this.studentService.getStudentById(studentId);
118141
if (!student) {
119142
throw new NotFoundException("Student not found.");
120143
}
121144

122145
const address = student.contactInfo.address ?? ({} as AddressInfo);
123-
return {
146+
const studentProfile = {
124147
firstName: student.user.firstName,
125148
lastName: student.user.lastName,
126149
fullName: getUserFullName(student.user),
@@ -133,8 +156,12 @@ export class StudentControllerService {
133156
},
134157
disabilityStatus: student.disabilityStatus,
135158
validSin: student.sinValidation.isValidSIN,
136-
sin: student.sinValidation.sin,
137159
};
160+
161+
if (options?.withSensitiveData) {
162+
return { ...studentProfile, sin: student.sinValidation.sin };
163+
}
164+
return studentProfile;
138165
}
139166

140167
/**

Diff for: sources/packages/backend/apps/api/src/route-controllers/student/student.institutions.controller.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ export class StudentInstitutionsController extends BaseController {
8282
async getStudentProfile(
8383
@Param("studentId", ParseIntPipe) studentId: number,
8484
): Promise<StudentProfileAPIOutDTO> {
85-
return this.studentControllerService.getStudentProfile(studentId);
85+
return this.studentControllerService.getStudentProfile(studentId, {
86+
withSensitiveData: true,
87+
});
8688
}
8789

8890
/**

Diff for: sources/packages/web/src/components/common/students/StudentProfile.vue

+11-4
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,15 @@
9898
import { onMounted, ref, defineComponent } from "vue";
9999
import { StudentService } from "@/services/StudentService";
100100
import { useFormatters } from "@/composables";
101-
import { StudentProfile } from "@/types";
102101
import { AddressAPIOutDTO } from "@/services/http/dto";
102+
import { StudentProfile } from "@/types";
103+
104+
/**
105+
* Used to combine institution and ministry DTOs and make SIN explicitly mandatory.
106+
*/
107+
interface SharedStudentProfile extends Omit<StudentProfile, "sin"> {
108+
sin: string;
109+
}
103110
104111
export default defineComponent({
105112
props: {
@@ -109,13 +116,13 @@ export default defineComponent({
109116
},
110117
},
111118
setup(props) {
112-
const studentDetail = ref({} as StudentProfile);
119+
const studentDetail = ref({} as SharedStudentProfile);
113120
const address = ref({} as AddressAPIOutDTO);
114121
const { sinDisplayFormat, emptyStringFiller } = useFormatters();
115122
onMounted(async () => {
116-
studentDetail.value = await StudentService.shared.getStudentProfile(
123+
studentDetail.value = (await StudentService.shared.getStudentProfile(
117124
props.studentId,
118-
);
125+
)) as SharedStudentProfile;
119126
address.value = studentDetail.value.contact.address;
120127
});
121128
return {

Diff for: sources/packages/web/src/services/http/StudentApi.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
CreateSINValidationAPIInDTO,
1313
UpdateSINValidationAPIInDTO,
1414
SearchStudentAPIInDTO,
15+
InstitutionStudentProfileAPIOutDTO,
16+
AESTStudentProfileAPIOutDTO,
1517
} from "@/services/http/dto";
1618

1719
export class StudentApi extends HttpBaseClient {
@@ -45,10 +47,12 @@ export class StudentApi extends HttpBaseClient {
4547
*/
4648
async getStudentProfile(
4749
studentId?: number,
48-
): Promise<StudentProfileAPIOutDTO> {
49-
return this.getCall<StudentProfileAPIOutDTO>(
50-
this.addClientRoot(`student/${studentId ?? ""}`),
51-
);
50+
): Promise<
51+
| StudentProfileAPIOutDTO
52+
| InstitutionStudentProfileAPIOutDTO
53+
| AESTStudentProfileAPIOutDTO
54+
> {
55+
return this.getCall(this.addClientRoot(`student/${studentId ?? ""}`));
5256
}
5357

5458
/**

Diff for: sources/packages/web/src/services/http/dto/Student.dto.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,17 @@ export interface StudentProfileAPIOutDTO {
4444
contact: ContactInformationAPIOutDTO;
4545
validSin: boolean;
4646
disabilityStatus: DisabilityStatus;
47-
sin: string;
4847
sinConsent: boolean;
49-
hasRestriction?: boolean;
48+
}
49+
50+
export interface InstitutionStudentProfileAPIOutDTO
51+
extends StudentProfileAPIOutDTO {
52+
sin: string;
53+
}
54+
55+
export interface AESTStudentProfileAPIOutDTO
56+
extends InstitutionStudentProfileAPIOutDTO {
57+
hasRestriction: boolean;
5058
}
5159

5260
/**

Diff for: sources/packages/web/src/types/contracts/StudentContract.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
import {
22
AddressDetailsFormAPIDTO,
3+
AESTStudentProfileAPIOutDTO,
4+
InstitutionStudentProfileAPIOutDTO,
35
SINValidationsAPIOutDTO,
46
StudentProfileAPIOutDTO,
57
} from "@/services/http/dto";
68
import { IdentityProviders } from "@/types";
79

8-
export interface StudentProfile extends StudentProfileAPIOutDTO {
9-
birthDateFormatted: string;
10-
}
10+
export type StudentProfile =
11+
| (
12+
| StudentProfileAPIOutDTO
13+
| InstitutionStudentProfileAPIOutDTO
14+
| AESTStudentProfileAPIOutDTO
15+
) & {
16+
birthDateFormatted: string;
17+
};
1118

1219
/**
1320
* Disability status of student.

Diff for: sources/packages/web/src/views/aest/student/StudentDetails.vue

+5-4
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ import { onMounted, ref, defineComponent } from "vue";
4040
import { StudentService } from "@/services/StudentService";
4141
import { AESTRoutesConst } from "@/constants/routes/RouteConstants";
4242
import StudentRestrictionChip from "@/components/generic/StudentRestrictionChip.vue";
43-
import { StudentRestrictionStatus, StudentProfile } from "@/types";
43+
import { StudentRestrictionStatus } from "@/types";
44+
import { AESTStudentProfileAPIOutDTO } from "@/services/http/dto";
4445
4546
export default defineComponent({
4647
components: { StudentRestrictionChip },
@@ -51,7 +52,7 @@ export default defineComponent({
5152
},
5253
},
5354
setup(props) {
54-
const studentDetails = ref({} as StudentProfile);
55+
const studentDetails = ref({} as AESTStudentProfileAPIOutDTO);
5556
const items = ref([
5657
{
5758
label: "Profile",
@@ -112,9 +113,9 @@ export default defineComponent({
112113
]);
113114
114115
onMounted(async () => {
115-
studentDetails.value = await StudentService.shared.getStudentProfile(
116+
studentDetails.value = (await StudentService.shared.getStudentProfile(
116117
props.studentId,
117-
);
118+
)) as AESTStudentProfileAPIOutDTO;
118119
});
119120
120121
return {

0 commit comments

Comments
 (0)