Skip to content

Commit 4301b7f

Browse files
authored
Merge pull request #2277 from bcgov/feature/egc-219
EGC-219: Submit GRAD Data During the Summer Period
2 parents 63c7087 + c1ff87a commit 4301b7f

File tree

6 files changed

+363
-36
lines changed

6 files changed

+363
-36
lines changed

backend/src/components/grad.js

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,15 @@ async function uploadFileXLS(req, res) {
7373
payload.courseSessionOverride = true;
7474
}
7575

76-
// const token = getAccessToken(req);
76+
const token = getAccessToken(req);
7777
let data;
78-
79-
// MAKE CALLOUTS HERE
80-
// if (req.params.schoolID){
81-
// data = await postData(token, payload, `${config.get('grad:rootURL')}/${req.params.schoolID}/file`, req.session?.correlationID);
82-
// } else {
83-
// data = await postData(token, payload, `${config.get('grad:rootURL')}/district/${req.params.districtID}/file`, req.session?.correlationID);
84-
// }
85-
// data.eventType = CONSTANTS.EVENT_TYPE.GDC_FILE_UPLOAD_EVENT;
86-
// broadcastUtil.publishGdcEvents(data, CONSTANTS.GDC_UPLOAD_TOPIC);
78+
if (req.params.schoolID){
79+
data = await postData(token, payload, `${config.get('grad:rootURL')}/${req.params.schoolID}/excel-upload`, req.session?.correlationID);
80+
} else {
81+
data = await postData(token, payload, `${config.get('grad:rootURL')}/district/${req.params.districtID}/excel-upload`, req.session?.correlationID);
82+
}
83+
data.eventType = CONSTANTS.EVENT_TYPE.GDC_FILE_UPLOAD_EVENT;
84+
broadcastUtil.publishGdcEvents(data, CONSTANTS.GDC_UPLOAD_TOPIC);
8785
return res.status(HttpStatus.OK).json(data);
8886
} catch (e) {
8987
if (e.status === 400) {
@@ -94,6 +92,32 @@ async function uploadFileXLS(req, res) {
9492
}
9593
}
9694

95+
async function processSummerStudents(req, res) {
96+
try {
97+
let createUpdateUser = getCreateOrUpdateUserValue(req);
98+
const payload = {
99+
fileName: req.body.fileName,
100+
summerStudents: req.body.summerStudents,
101+
createUser: createUpdateUser,
102+
updateUser: createUpdateUser
103+
};
104+
const token = getAccessToken(req);
105+
let data;
106+
if (req.params.schoolID){
107+
data = await postData(token, payload, `${config.get('grad:rootURL')}/${req.params.schoolID}/process`, req.session?.correlationID);
108+
} else {
109+
data = await postData(token, payload, `${config.get('grad:rootURL')}/district/${req.params.districtID}/process`, req.session?.correlationID);
110+
}
111+
return res.status(HttpStatus.OK).json(data);
112+
} catch (e) {
113+
if (e.status === 400) {
114+
return res.status(HttpStatus.BAD_REQUEST).json(e.data.subErrors[0].message);
115+
}
116+
log.error('processSummerStudents Error', e.stack);
117+
return handleExceptionResponse(e, res);
118+
}
119+
}
120+
97121
async function downloadErrorReport(req, res) {
98122
try {
99123
const token = getAccessToken(req);
@@ -569,5 +593,6 @@ module.exports = {
569593
getSubmissionMetrics,
570594
getErrorMetrics,
571595
uploadFileXLS,
572-
getActiveReportingPeriod
596+
getActiveReportingPeriod,
597+
processSummerStudents
573598
};

backend/src/routes/grad.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const isValidBackendToken = auth.isValidBackendToken();
66
const { validateAccessToken, checkEdxUserPermission, findSchoolID_params, findInstituteInformation_query, findDistrictID_params, checkEDXUserAccessToRequestedInstitute, loadIncomingFileset, checkUserHasAccessToIncomingFileset } = require('../components/permissionUtils');
77
const { scanFilePayload } = require('../components/fileUtils');
88
const { uploadFile, uploadFileXLS, getErrorFilesetStudentPaginated, getFilesetsPaginated, downloadErrorReport,
9-
getCurrentGradStudentsPaginated, getStudentFilesetByPenFilesetId, getSubmissionMetrics, getErrorMetrics, getActiveReportingPeriod
9+
getCurrentGradStudentsPaginated, getStudentFilesetByPenFilesetId, getSubmissionMetrics, getErrorMetrics, getActiveReportingPeriod, processSummerStudents
1010
} = require('../components/grad');
1111
const { PERMISSION } = require('../util/Permission');
1212
const validate = require('../components/validator');
@@ -15,7 +15,9 @@ const constants = require('../util/constants');
1515
const { gradFileUploadSchema, gradErrorFilesetStudentPaginatedSchema, gradDistrictFilesetPaginatedSchema, gradSchoolFilesetPaginatedSchema,
1616
gradDistrictFileUploadSchema, gradSchoolPenFilesetPaginatedSchema, gradSchoolFilesetByPenSchema, gradDistrictPenFilesetPaginatedSchema,
1717
gradDistrictFilesetByPenSchema,
18-
gradSchoolFilesetMetricSchema
18+
gradSchoolFilesetMetricSchema,
19+
gradProcessSchoolSummerStudentsSchema,
20+
gradProcessDistrictSummerStudentsSchema
1921
} = require('../validations/grad');
2022

2123
router.get('/validation-issue-type-codes', passport.authenticate('jwt', {session: false}, undefined), isValidBackendToken,
@@ -74,4 +76,13 @@ router.get('/fileset/district/:districtID/pen/:pen', passport.authenticate('jwt'
7476

7577
router.get('/active-reporting-period', passport.authenticate('jwt', {session: false}, undefined), isValidBackendToken, validateAccessToken, getActiveReportingPeriod);
7678

79+
80+
router.post('/school/:schoolID/process', passport.authenticate('jwt', {session: false}, undefined), isValidBackendToken, validateAccessToken,
81+
checkEdxUserPermission(PERMISSION.GRAD_SCH_UPLOAD), validate(gradProcessSchoolSummerStudentsSchema), findSchoolID_params, checkEDXUserAccessToRequestedInstitute, processSummerStudents);
82+
83+
router.post('/district/:districtID/process', passport.authenticate('jwt', {session: false}, undefined), isValidBackendToken, validateAccessToken,
84+
checkEdxUserPermission(PERMISSION.GRAD_DIS_UPLOAD), validate(gradProcessDistrictSummerStudentsSchema), findDistrictID_params, checkEDXUserAccessToRequestedInstitute, processSummerStudents);
85+
86+
87+
7788
module.exports = router;

backend/src/validations/grad.js

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { object, string, number, boolean} = require('yup');
1+
const { object, string, number, boolean, array} = require('yup');
22
const {baseRequestSchema} = require('./base');
33

44
const gradFileUploadSchema = object({
@@ -130,6 +130,54 @@ const gradDistrictFilesetByPenSchema = object({
130130
})
131131
}).noUnknown();
132132

133+
const gradProcessSchoolSummerStudentsSchema = object({
134+
body:object({
135+
fileName: string().nonNullable(),
136+
summerStudents: array().of(object({
137+
schoolCode: string().nonNullable(),
138+
pen: string().nonNullable(),
139+
legalSurname: string().nonNullable(),
140+
legalMiddleName: string().nullable(),
141+
legalFirstName: string().nullable(),
142+
dob: string().nullable(),
143+
studentGrade: string().nullable(),
144+
course: string().nullable(),
145+
sessionDate: string().nullable(),
146+
finalPercent: string().nullable(),
147+
finalLetterGrade: string().nullable(),
148+
noOfCredits: string().nullable(),
149+
}))
150+
}).concat(baseRequestSchema).noUnknown(),
151+
params: object({
152+
schoolID: string().nonNullable()
153+
}).noUnknown(),
154+
query: object().noUnknown()
155+
}).noUnknown();
156+
157+
const gradProcessDistrictSummerStudentsSchema = object({
158+
body:object({
159+
fileName: string().nonNullable(),
160+
summerStudents: array().of(object({
161+
schoolCode: string().nonNullable(),
162+
pen: string().nonNullable(),
163+
legalSurname: string().nonNullable(),
164+
legalMiddleName: string().nullable(),
165+
legalFirstName: string().nullable(),
166+
dob: string().nullable(),
167+
studentGrade: string().nullable(),
168+
course: string().nullable(),
169+
sessionDate: string().nullable(),
170+
finalPercent: string().nullable(),
171+
finalLetterGrade: string().nullable(),
172+
noOfCredits: string().nullable(),
173+
}))
174+
}).concat(baseRequestSchema).noUnknown(),
175+
params: object({
176+
districtID: string().nonNullable()
177+
}).noUnknown(),
178+
query: object().noUnknown()
179+
}).noUnknown();
180+
133181
module.exports = {
134182
gradFileUploadSchema,
135183
gradDistrictFilesetPaginatedSchema,
@@ -140,5 +188,7 @@ module.exports = {
140188
gradSchoolFilesetByPenSchema,
141189
gradDistrictFilesetByPenSchema,
142190
gradDistrictPenFilesetPaginatedSchema,
143-
gradSchoolFilesetMetricSchema
191+
gradSchoolFilesetMetricSchema,
192+
gradProcessSchoolSummerStudentsSchema,
193+
gradProcessDistrictSummerStudentsSchema
144194
};
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
<template>
2+
3+
<v-card
4+
id="previewCard"
5+
>
6+
<v-card-title
7+
id="previewCardTitle"
8+
class="sheetHeader pt-1 pb-1"
9+
>
10+
<v-row no-gutters>
11+
<v-col class="d-flex justify-start">
12+
Preview of Summer Course Data
13+
</v-col>
14+
<v-col class="d-flex justify-end">
15+
<v-btn
16+
id="cancel"
17+
color="white"
18+
text="Close"
19+
size="30"
20+
icon="mdi-close"
21+
variant="tonal"
22+
@click="cancel"
23+
/>
24+
</v-col>
25+
</v-row>
26+
</v-card-title>
27+
<v-divider />
28+
<v-card-text>
29+
<span>Below is a preview of your uploaded data from file: <b>{{fileName}}</b>. Please review the data before processing the data. See the Summary of Uploaded data table for status and error reporting.</span>
30+
31+
<v-data-table
32+
:headers="headers"
33+
:items="data"
34+
v-model:page="pageNumber"
35+
v-model:items-per-page="pageSize"
36+
/>
37+
38+
<v-row>
39+
<v-col
40+
class="d-flex justify-end"
41+
>
42+
<v-btn
43+
id="waitForReporting"
44+
color="#003366"
45+
text="Wait until the next Reporting Cycle"
46+
class="mr-2 mb-1"
47+
variant="elevated"
48+
@click="cancel"
49+
/>
50+
51+
<v-btn
52+
id="processData"
53+
color="#003366"
54+
text="Process Data"
55+
class="mr-2 mb-1"
56+
variant="outlined"
57+
@click="processStudents"
58+
/>
59+
</v-col>
60+
</v-row>
61+
62+
</v-card-text>
63+
</v-card>
64+
</template>
65+
66+
<script>
67+
import alertMixin from '../../mixins/alertMixin';
68+
import ApiService from '../../common/apiService';
69+
import {ApiRoutes} from '../../utils/constants';
70+
71+
export default {
72+
name: 'PreviewStudents',
73+
components: {
74+
},
75+
mixins: [alertMixin],
76+
props: {
77+
headers: {
78+
type: Array,
79+
required: true,
80+
default: null
81+
},
82+
data: {
83+
type: Array,
84+
required: true,
85+
default: null
86+
},
87+
fileName: {
88+
type: String,
89+
required: true,
90+
default: null
91+
},
92+
schoolID: {
93+
type: String,
94+
required: false,
95+
default: null
96+
},
97+
districtID: {
98+
type: String,
99+
required: false,
100+
default: null
101+
},
102+
},
103+
emits: ['reload', 'close'],
104+
data() {
105+
return {
106+
pageNumber: 1,
107+
pageSize: 25,
108+
};
109+
},
110+
computed: {
111+
112+
},
113+
watch: {
114+
},
115+
async created() {
116+
117+
},
118+
beforeUnmount() {
119+
120+
},
121+
methods: {
122+
cancel() {
123+
this.$emit('close');
124+
},
125+
async processStudents() {
126+
let body = {
127+
fileName: this.fileName,
128+
summerStudents: this.data
129+
}
130+
await ApiService.apiAxios.post(ApiRoutes.gdc.BASE_URL + '/school/' + this.schoolID + '/process', body)
131+
.then(() => {
132+
this.$emit('close');
133+
}).catch(error => {
134+
console.error(error);
135+
this.setFailureAlert('An error occurred while trying to process students. Please try again later.');
136+
});
137+
138+
}
139+
}
140+
};
141+
</script>
142+
143+
<style scoped>
144+
.header-text {
145+
color: #7f7f7f;
146+
}
147+
148+
:deep(.v-table__wrapper){
149+
overflow: unset;
150+
}
151+
152+
:deep(.v-data-table-footer__items-per-page) {
153+
display: none;
154+
}
155+
156+
157+
</style>
158+
159+
160+

0 commit comments

Comments
 (0)