@obe-loms/coms-parser 1.0.2 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/helper/matchTarget.js +9 -0
- package/index.d.ts +1 -0
- package/index.js +10 -0
- package/main.js +50 -0
- package/package.json +2 -2
- package/parser/assessmentdata.js +149 -0
- package/parser/classList.js +36 -0
- package/parser/coaep.js +73 -0
- package/parser/courseOffering.js +84 -0
- package/parser/curriculum.js +83 -0
- package/parser/xls.js +42 -0
- package/relay/uploadAssessmentData.js +24 -0
- package/relay/uploadCOAEP.js +24 -0
- package/relay/uploadClassList.js +25 -0
- package/relay/uploadCourseOffering.js +26 -0
- package/relay/uploadCurriculum.js +26 -0
- package/relay/uploadEnrolledStudent.js +20 -0
- package/types/assessmentdata.js +1 -0
- package/types/classList.js +1 -0
- package/types/coaep.js +1 -0
- package/types/courseOffering.js +1 -0
- package/types/curriculum.js +1 -0
- package/bundle.js +0 -32
- package/helper/matchTarget.d.ts +0 -4
- package/main.d.ts +0 -26
- package/parser/assessmentdata.d.ts +0 -4
- package/parser/classList.d.ts +0 -6
- package/parser/coaep.d.ts +0 -4
- package/parser/courseOffering.d.ts +0 -2
- package/parser/curriculum.d.ts +0 -2
- package/parser/xls.d.ts +0 -1
- package/relay/uploadAssessmentData.d.ts +0 -1
- package/relay/uploadCOAEP.d.ts +0 -1
- package/relay/uploadClassList.d.ts +0 -1
- package/relay/uploadCourseOffering.d.ts +0 -1
- package/relay/uploadCurriculum.d.ts +0 -1
- package/relay/uploadEnrolledStudent.d.ts +0 -1
- package/types/assessmentdata.d.ts +0 -25
- package/types/classList.d.ts +0 -6
- package/types/coaep.d.ts +0 -19
- package/types/courseOffering.d.ts +0 -12
- package/types/curriculum.d.ts +0 -12
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function performaceTarget(target) {
|
|
2
|
+
if (!target)
|
|
3
|
+
return { performance_target: null, passing_score: null };
|
|
4
|
+
const matches = target.match(/\d+/g);
|
|
5
|
+
return {
|
|
6
|
+
performance_target: matches?.[0] ? parseInt(matches[0], 10) : null,
|
|
7
|
+
passing_score: matches?.[1] ? parseInt(matches[1], 10) : null
|
|
8
|
+
};
|
|
9
|
+
}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import Client from "./main";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
const client = new Client('http://localhost:3000/api/v1');
|
|
5
|
+
const filePath = path.join(__dirname, "../Test.csv");
|
|
6
|
+
const buffer = fs.readFileSync(filePath);
|
|
7
|
+
const file = new File([buffer], 'Test.csv', { type: 'text/csv' });
|
|
8
|
+
client.Parser().assessmentData(file)
|
|
9
|
+
.then(result => console.log(result))
|
|
10
|
+
.catch(err => console.error("Error uploading COAEP:", err));
|
package/main.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { uploadCurriculum } from "./relay/uploadCurriculum";
|
|
2
|
+
import { uploadCourseOffering } from "./relay/uploadCourseOffering";
|
|
3
|
+
import { uploadCOAEP } from "./relay/uploadCOAEP";
|
|
4
|
+
import { uploadEnrolledStudent } from "./relay/uploadEnrolledStudent";
|
|
5
|
+
import { uploadClassList } from "./relay/uploadClassList";
|
|
6
|
+
import { uploadAssessmentData } from "./relay/uploadAssessmentData";
|
|
7
|
+
export default class Client {
|
|
8
|
+
BASE_URL;
|
|
9
|
+
constructor(url) {
|
|
10
|
+
this.BASE_URL = url;
|
|
11
|
+
}
|
|
12
|
+
Parser() {
|
|
13
|
+
return {
|
|
14
|
+
/**
|
|
15
|
+
* Parse the official curriculum data from the registrar to a digestible format
|
|
16
|
+
* @param curriculum file from registrar
|
|
17
|
+
* @returns status 201
|
|
18
|
+
*/
|
|
19
|
+
curriculum: async (xls) => {
|
|
20
|
+
const res = await uploadCurriculum(this.BASE_URL, xls);
|
|
21
|
+
return res;
|
|
22
|
+
},
|
|
23
|
+
/**
|
|
24
|
+
* Parse the course offering data
|
|
25
|
+
* @param offering file from registrar
|
|
26
|
+
* @returns status 201
|
|
27
|
+
*/
|
|
28
|
+
courseOffering: async (xls) => {
|
|
29
|
+
const res = await uploadCourseOffering(this.BASE_URL, xls);
|
|
30
|
+
return res;
|
|
31
|
+
},
|
|
32
|
+
coaep: async (xls, course_id) => {
|
|
33
|
+
const res = await uploadCOAEP(this.BASE_URL, xls, course_id);
|
|
34
|
+
return res;
|
|
35
|
+
},
|
|
36
|
+
enrolledStudent: async (xls) => {
|
|
37
|
+
const res = await uploadEnrolledStudent(this.BASE_URL, xls);
|
|
38
|
+
return res;
|
|
39
|
+
},
|
|
40
|
+
classlist: async (xls, subj_code, period_id) => {
|
|
41
|
+
const res = await uploadClassList(this.BASE_URL, xls, subj_code, period_id);
|
|
42
|
+
return res;
|
|
43
|
+
},
|
|
44
|
+
assessmentData: async (xls) => {
|
|
45
|
+
const res = await uploadAssessmentData(this.BASE_URL, xls);
|
|
46
|
+
return res;
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obe-loms/coms-parser",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"license": "ISC",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"papaparse": "^5.5.3",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"typescript": "^5.9.2"
|
|
19
19
|
},
|
|
20
20
|
"main": "./bundle.js",
|
|
21
|
-
"types": "./main.
|
|
21
|
+
"types": "./main.js",
|
|
22
22
|
"publishConfig": {
|
|
23
23
|
"access": "public"
|
|
24
24
|
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import Papa from "papaparse";
|
|
2
|
+
export function parseAssessmentCsv(csv) {
|
|
3
|
+
const { data } = Papa.parse(csv, { skipEmptyLines: true });
|
|
4
|
+
const rows = data.filter((r) => r.length > 0);
|
|
5
|
+
const facultyRow = rows.find((r) => r.some((c) => c?.includes("Faculty")));
|
|
6
|
+
const facultyIdx = facultyRow
|
|
7
|
+
? facultyRow.findIndex((c) => c?.includes("Faculty"))
|
|
8
|
+
: -1;
|
|
9
|
+
const faculty = facultyIdx !== -1 && facultyRow
|
|
10
|
+
? facultyRow[facultyIdx + 2]?.replace(/"/g, "").trim() ?? ""
|
|
11
|
+
: "";
|
|
12
|
+
const semRow = rows.find((r) => r.some((c) => c?.includes("Semester")));
|
|
13
|
+
const semIdx = semRow ? semRow.findIndex((c) => c?.includes("Semester")) : -1;
|
|
14
|
+
const semesterStr = semIdx !== -1 && semRow ? semRow[semIdx + 2]?.trim() ?? "" : "";
|
|
15
|
+
const semester = semesterStr.includes("1st")
|
|
16
|
+
? 1
|
|
17
|
+
: semesterStr.includes("2nd")
|
|
18
|
+
? 2
|
|
19
|
+
: 0;
|
|
20
|
+
const courseRow = rows.find((r) => r.some((c) => c?.includes("Course & Sec")));
|
|
21
|
+
const courseIdx = courseRow
|
|
22
|
+
? courseRow.findIndex((c) => c?.includes("Course & Sec"))
|
|
23
|
+
: -1;
|
|
24
|
+
const rawCourseSection = courseIdx !== -1 && courseRow ? courseRow[courseIdx + 2]?.trim() ?? "" : "";
|
|
25
|
+
let courseCode = "";
|
|
26
|
+
let section = "";
|
|
27
|
+
if (rawCourseSection) {
|
|
28
|
+
const match = rawCourseSection.match(/^([A-Za-z0-9]+)-?([A-Za-z]+)?/);
|
|
29
|
+
if (match) {
|
|
30
|
+
courseCode = match[1] ?? "";
|
|
31
|
+
if (match[2]) {
|
|
32
|
+
section = match[2].replace(/^OC/i, "");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const syRow = rows.find((r) => r.some((c) => c?.includes("School Year")));
|
|
37
|
+
const syIdx = syRow ? syRow.findIndex((c) => c?.includes("School Year")) : -1;
|
|
38
|
+
const syStr = syIdx !== -1 && syRow ? syRow[syIdx + 2]?.trim() ?? "" : "";
|
|
39
|
+
let sy = 0;
|
|
40
|
+
if (syStr) {
|
|
41
|
+
const match = syStr.match(/(\d{4})-(\d{4})/);
|
|
42
|
+
if (match) {
|
|
43
|
+
const first = (match[1] ?? "").slice(2);
|
|
44
|
+
const second = (match[2] ?? "").slice(2);
|
|
45
|
+
sy = parseInt(first + second, 10);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const classAssignment = {
|
|
49
|
+
faculty,
|
|
50
|
+
course: courseCode,
|
|
51
|
+
section: section,
|
|
52
|
+
semester: semester,
|
|
53
|
+
sy,
|
|
54
|
+
};
|
|
55
|
+
const coRowIndex = rows.findIndex((r) => r.some((c) => c?.trim() === "CO #"));
|
|
56
|
+
if (coRowIndex === -1)
|
|
57
|
+
throw new Error("CO header row not found in CSV");
|
|
58
|
+
const iloRow = rows[coRowIndex + 1];
|
|
59
|
+
if (!iloRow)
|
|
60
|
+
throw new Error("ILO header row not found in CSV");
|
|
61
|
+
const iloGroups = {};
|
|
62
|
+
let coCounter = 1;
|
|
63
|
+
let iloCounter = 1;
|
|
64
|
+
for (let i = 3; i < iloRow.length; i++) {
|
|
65
|
+
const val = iloRow[i];
|
|
66
|
+
if (!val)
|
|
67
|
+
continue;
|
|
68
|
+
const coKey = `co${coCounter}`;
|
|
69
|
+
if (!iloGroups[coKey])
|
|
70
|
+
iloGroups[coKey] = [];
|
|
71
|
+
iloGroups[coKey].push(`ilo${iloCounter}`);
|
|
72
|
+
iloCounter++;
|
|
73
|
+
if (iloCounter > 3) {
|
|
74
|
+
coCounter++;
|
|
75
|
+
iloCounter = 1;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const studentHeaderIndex = rows.findIndex((r) => r.includes("Name of Students"));
|
|
79
|
+
if (studentHeaderIndex === -1)
|
|
80
|
+
throw new Error("Student header row not found in CSV");
|
|
81
|
+
const headerRow = rows[studentHeaderIndex];
|
|
82
|
+
if (!headerRow)
|
|
83
|
+
throw new Error("Student header row is missing");
|
|
84
|
+
const nameColIndex = headerRow.findIndex((c) => c?.includes("Name of Students"));
|
|
85
|
+
if (nameColIndex === -1)
|
|
86
|
+
throw new Error("Name of Students column not found in CSV");
|
|
87
|
+
const firstScoreColIndex = nameColIndex + 2;
|
|
88
|
+
const students = [];
|
|
89
|
+
for (let i = studentHeaderIndex + 1; i < rows.length; i++) {
|
|
90
|
+
const row = rows[i];
|
|
91
|
+
if (!row)
|
|
92
|
+
continue;
|
|
93
|
+
if (row.some((c) => c?.toUpperCase().includes("TOTAL STUDENTS") ||
|
|
94
|
+
c?.toUpperCase().includes("ACHIEVED THE MINIMUM") ||
|
|
95
|
+
c?.toUpperCase().includes("INACTIVE") ||
|
|
96
|
+
c?.toUpperCase().includes("AVERAGE"))) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (!row[nameColIndex])
|
|
100
|
+
continue;
|
|
101
|
+
const name = row[nameColIndex].replace(/"/g, "").trim();
|
|
102
|
+
const scores = row
|
|
103
|
+
.slice(firstScoreColIndex)
|
|
104
|
+
.map((s) => (s === null ? null : !isNaN(Number(s)) ? parseFloat(s) : 0));
|
|
105
|
+
let scoreIndex = 0;
|
|
106
|
+
const coaep = {};
|
|
107
|
+
Object.entries(iloGroups).forEach(([coKey, iloKeys]) => {
|
|
108
|
+
const transmuted = {};
|
|
109
|
+
iloKeys.forEach((iloKey) => {
|
|
110
|
+
transmuted[iloKey] = scores[scoreIndex] ?? 0;
|
|
111
|
+
scoreIndex++;
|
|
112
|
+
});
|
|
113
|
+
coaep[coKey] = { transmuted_score: transmuted };
|
|
114
|
+
});
|
|
115
|
+
students.push({ student_name: name, coaep });
|
|
116
|
+
}
|
|
117
|
+
const achievedRow = rows.find((r) => r.some((c) => c?.includes("ACHIEVED THE MINIMUM")));
|
|
118
|
+
const avgRow = rows.find((r) => r.some((c) => c?.includes("AVERAGE")));
|
|
119
|
+
const achieved = achievedRow
|
|
120
|
+
? achievedRow
|
|
121
|
+
.slice(firstScoreColIndex)
|
|
122
|
+
.map((s) => (s && !isNaN(Number(s)) ? parseInt(s) : 0))
|
|
123
|
+
: [];
|
|
124
|
+
const averages = avgRow
|
|
125
|
+
? avgRow
|
|
126
|
+
.slice(firstScoreColIndex)
|
|
127
|
+
.map((s) => s && s !== "#DIV/0!" && !isNaN(Number(s)) ? parseInt(s) : 0)
|
|
128
|
+
: [];
|
|
129
|
+
const total = {};
|
|
130
|
+
let totalIndex = 0;
|
|
131
|
+
Object.entries(iloGroups).forEach(([coKey, iloKeys]) => {
|
|
132
|
+
if (!total[coKey])
|
|
133
|
+
total[coKey] = {};
|
|
134
|
+
iloKeys.forEach((iloKey) => {
|
|
135
|
+
total[coKey][iloKey] = {
|
|
136
|
+
achievedMinimum: achieved[totalIndex] ?? 0,
|
|
137
|
+
average: averages[totalIndex] ?? 0,
|
|
138
|
+
};
|
|
139
|
+
totalIndex++;
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
return {
|
|
143
|
+
assessmentData: {
|
|
144
|
+
classAssignment,
|
|
145
|
+
student: students,
|
|
146
|
+
total,
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import Papa from "papaparse";
|
|
2
|
+
export function parseClassList(csvData) {
|
|
3
|
+
const rows = Papa.parse(csvData, {
|
|
4
|
+
skipEmptyLines: true,
|
|
5
|
+
}).data;
|
|
6
|
+
let section = "";
|
|
7
|
+
let course_id = "";
|
|
8
|
+
let subj_code = "";
|
|
9
|
+
const enrolledCourses = [];
|
|
10
|
+
rows.forEach((row) => {
|
|
11
|
+
const cells = row.map((c) => (c ?? "").toString().trim());
|
|
12
|
+
const firstCell = cells[0] ?? "";
|
|
13
|
+
if (firstCell.startsWith("Course No:")) {
|
|
14
|
+
// "Course No: 3093 BIT324L-OBa"
|
|
15
|
+
const courseLine = firstCell.replace("Course No:", "").trim();
|
|
16
|
+
const parts = courseLine.split(/\s+/);
|
|
17
|
+
subj_code = parts[0] ?? ""; // 3093
|
|
18
|
+
const [course, sec] = (parts[1] ?? "").split("-");
|
|
19
|
+
course_id = course ?? ""; // BIT999L
|
|
20
|
+
const sectionMatch = (sec ?? "").match(/[a-z]$/);
|
|
21
|
+
section = sectionMatch ? sectionMatch[0] : "";
|
|
22
|
+
}
|
|
23
|
+
if (/^\d+$/.test(firstCell)) {
|
|
24
|
+
const student_no = cells[2] ?? "";
|
|
25
|
+
enrolledCourses.push({
|
|
26
|
+
subj_code,
|
|
27
|
+
student_no,
|
|
28
|
+
course_id,
|
|
29
|
+
section,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
enrolledCourses
|
|
35
|
+
};
|
|
36
|
+
}
|
package/parser/coaep.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import Papa from "papaparse";
|
|
2
|
+
import { performaceTarget } from "../helper/matchTarget";
|
|
3
|
+
export function parseCOAEP(csvString) {
|
|
4
|
+
const rows = Papa.parse(csvString, {
|
|
5
|
+
skipEmptyLines: false
|
|
6
|
+
}).data;
|
|
7
|
+
const data = {
|
|
8
|
+
COAEP: {
|
|
9
|
+
faculty: null,
|
|
10
|
+
course: null,
|
|
11
|
+
sy: null,
|
|
12
|
+
semester: null,
|
|
13
|
+
co: []
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
rows.forEach(row => {
|
|
17
|
+
if (row[1]?.includes("Name of Faculty:")) {
|
|
18
|
+
data.COAEP.faculty = row[2]?.trim() || null;
|
|
19
|
+
}
|
|
20
|
+
if (row.includes("School Year")) {
|
|
21
|
+
const idx = row.indexOf("School Year");
|
|
22
|
+
data.COAEP.sy = row[idx + 1]?.trim() || null;
|
|
23
|
+
}
|
|
24
|
+
if (row[1]?.includes("Course:")) {
|
|
25
|
+
const courseStr = row[2]?.trim() || "";
|
|
26
|
+
data.COAEP.course = courseStr || null;
|
|
27
|
+
}
|
|
28
|
+
if (row.includes("Semester")) {
|
|
29
|
+
const idx = row.indexOf("Semester");
|
|
30
|
+
const semStr = row[idx + 1]?.trim() || "";
|
|
31
|
+
const semNum = semStr.match(/\d+/)?.[0];
|
|
32
|
+
data.COAEP.semester = semNum ? parseInt(semNum, 10) : null;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
let currentCO = null;
|
|
36
|
+
rows.forEach(row => {
|
|
37
|
+
const col0 = row[0]?.trim() || "";
|
|
38
|
+
const col1 = row[1]?.trim() || "";
|
|
39
|
+
const col3 = row[3]?.trim() || "";
|
|
40
|
+
if (col0 && /^\d+$/.test(col0)) {
|
|
41
|
+
if (currentCO) {
|
|
42
|
+
data.COAEP.co.push(currentCO);
|
|
43
|
+
}
|
|
44
|
+
const stmt = col1;
|
|
45
|
+
const verb = stmt.trim().split(/\s+/)[0] ?? "";
|
|
46
|
+
currentCO = {
|
|
47
|
+
statement: stmt,
|
|
48
|
+
verb: verb,
|
|
49
|
+
ilo: []
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (currentCO && col3) {
|
|
53
|
+
const iloStatement = col3
|
|
54
|
+
.replace(/^ILO\d+\s*/, "")
|
|
55
|
+
.replace(/\s+/g, " ")
|
|
56
|
+
.trim();
|
|
57
|
+
const assessmentTool = (row[4]?.replace(/\s+/g, " ").trim()) || "";
|
|
58
|
+
const perfTargetStr = (row[5]?.replace(/\s+/g, " ").trim()) || "";
|
|
59
|
+
const { performance_target, passing_score } = performaceTarget(perfTargetStr);
|
|
60
|
+
currentCO.ilo.push({
|
|
61
|
+
statement: iloStatement,
|
|
62
|
+
verb: iloStatement.split(/\s+/)[0] ?? "",
|
|
63
|
+
assessment_tool: assessmentTool,
|
|
64
|
+
performance_target,
|
|
65
|
+
passing_score
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
if (currentCO) {
|
|
70
|
+
data.COAEP.co.push(currentCO);
|
|
71
|
+
}
|
|
72
|
+
return data;
|
|
73
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import Papa from "papaparse";
|
|
2
|
+
export function parseCourseOffering(csvData) {
|
|
3
|
+
let semester = "";
|
|
4
|
+
let school_year = "";
|
|
5
|
+
const cleanRows = [];
|
|
6
|
+
// Parse CSV data
|
|
7
|
+
const parsed = Papa.parse(csvData, {
|
|
8
|
+
header: false,
|
|
9
|
+
skipEmptyLines: true,
|
|
10
|
+
delimiter: ","
|
|
11
|
+
});
|
|
12
|
+
const rows = parsed.data;
|
|
13
|
+
// Extract semester and school year from header rows
|
|
14
|
+
for (let i = 0; i < Math.min(5, rows.length); i++) {
|
|
15
|
+
const row = rows[i];
|
|
16
|
+
if (row && row.length > 0) {
|
|
17
|
+
const cellContent = row[0]?.toString() || "";
|
|
18
|
+
// Look for semester and school year pattern like "Second Sem S/Y 2024-2025"
|
|
19
|
+
const semesterMatch = cellContent.match(/(First|Second)\s+Sem\s+S\/Y\s+(\d{4}-\d{4})/i);
|
|
20
|
+
if (semesterMatch) {
|
|
21
|
+
// Convert semester to number: First = "1", Second = "2"
|
|
22
|
+
semester = semesterMatch[1]?.toLowerCase() === "first" ? "1" : "2";
|
|
23
|
+
// Convert school year format: "2024-2025" -> "2425"
|
|
24
|
+
if (semesterMatch[2]) {
|
|
25
|
+
const yearMatch = semesterMatch[2].match(/(\d{2})(\d{2})-(\d{2})(\d{2})/);
|
|
26
|
+
if (yearMatch && yearMatch[2] && yearMatch[4]) {
|
|
27
|
+
school_year = yearMatch[2] + yearMatch[4]; // Extract last 2 digits of each year
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Find the header row (should contain "CODE", "COURSE NO", etc.)
|
|
34
|
+
let headerRowIndex = -1;
|
|
35
|
+
for (let i = 0; i < rows.length; i++) {
|
|
36
|
+
const row = rows[i];
|
|
37
|
+
if (row && row.some(cell => cell?.toString().toUpperCase().includes("CODE"))) {
|
|
38
|
+
headerRowIndex = i;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (headerRowIndex === -1) {
|
|
43
|
+
throw new Error("Could not find header row in CSV data");
|
|
44
|
+
}
|
|
45
|
+
// Process data rows (starting after header)
|
|
46
|
+
for (let i = headerRowIndex + 1; i < rows.length; i++) {
|
|
47
|
+
const row = rows[i];
|
|
48
|
+
if (!row || row.length < 8)
|
|
49
|
+
continue; // Skip incomplete rows
|
|
50
|
+
// Extract data from each column
|
|
51
|
+
const code = row[0]?.toString().trim() || "";
|
|
52
|
+
const course_no = row[1]?.toString().trim() || "";
|
|
53
|
+
const course_desc = row[2]?.toString().trim() || "";
|
|
54
|
+
const unitStr = row[3]?.toString().trim() || "";
|
|
55
|
+
const time = row[4]?.toString().trim() || "";
|
|
56
|
+
const days = row[5]?.toString().trim() || "";
|
|
57
|
+
const faculty = row[6]?.toString().trim() || "";
|
|
58
|
+
const room = row[7]?.toString().trim() || "";
|
|
59
|
+
// Skip rows without essential data (must have subject code)
|
|
60
|
+
if (!code)
|
|
61
|
+
continue;
|
|
62
|
+
// Parse unit as number
|
|
63
|
+
let unit = 0;
|
|
64
|
+
const unitMatch = unitStr.match(/(\d+)/);
|
|
65
|
+
if (unitMatch && unitMatch[1]) {
|
|
66
|
+
unit = parseInt(unitMatch[1], 10);
|
|
67
|
+
}
|
|
68
|
+
// Create course offering object
|
|
69
|
+
const offering = {
|
|
70
|
+
sem: semester,
|
|
71
|
+
school_year: school_year,
|
|
72
|
+
code: code,
|
|
73
|
+
course_no: course_no,
|
|
74
|
+
course_desc: course_desc,
|
|
75
|
+
unit: unit,
|
|
76
|
+
time: time,
|
|
77
|
+
days: days,
|
|
78
|
+
faculty: faculty,
|
|
79
|
+
room: room
|
|
80
|
+
};
|
|
81
|
+
cleanRows.push(offering);
|
|
82
|
+
}
|
|
83
|
+
return cleanRows;
|
|
84
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import Papa from "papaparse";
|
|
2
|
+
export function parseCurriculum(csvData) {
|
|
3
|
+
let curr_id = "";
|
|
4
|
+
let program_name = "";
|
|
5
|
+
let revision_no = 0;
|
|
6
|
+
let year_level = null;
|
|
7
|
+
const cleanRows = [];
|
|
8
|
+
Papa.parse(csvData, {
|
|
9
|
+
skipEmptyLines: true,
|
|
10
|
+
complete: (result) => {
|
|
11
|
+
result.data.forEach((row) => {
|
|
12
|
+
const cells = row.map((c) => (c ?? "").toString().trim());
|
|
13
|
+
const firstCell = cells[0] ?? "";
|
|
14
|
+
//Metadata
|
|
15
|
+
if (firstCell.includes("Rev#")) {
|
|
16
|
+
const metaMatch = firstCell.match(/([A-Z0-9]+)\s*-\s*.*:\s*(.*?)\s+Rev#\s*(\d+)/i);
|
|
17
|
+
if (metaMatch) {
|
|
18
|
+
curr_id = metaMatch[1]?.trim() ?? "";
|
|
19
|
+
program_name = metaMatch[2]?.trim() ?? "";
|
|
20
|
+
revision_no = parseInt(metaMatch[3] ?? "0", 10);
|
|
21
|
+
}
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
//Year level
|
|
25
|
+
if (/FIRST YEAR/i.test(firstCell)) {
|
|
26
|
+
year_level = 1;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (/SECOND YEAR/i.test(firstCell)) {
|
|
30
|
+
year_level = 2;
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (/THIRD YEAR/i.test(firstCell)) {
|
|
34
|
+
year_level = 3;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (/FOURTH YEAR/i.test(firstCell)) {
|
|
38
|
+
year_level = 4;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (/FIFTH YEAR/i.test(firstCell)) {
|
|
42
|
+
year_level = 5;
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
//skip semester header
|
|
46
|
+
if (/First Semester/i.test(firstCell) || /Second Semester/i.test(firstCell) || /Summer/i.test(firstCell)) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
// CSV columns:
|
|
50
|
+
// First Sem: 0=id, 1=desc, 2=units?, 3=lec, 4=lab
|
|
51
|
+
// Second Sem: 6=id, 7=desc, 8=lec, 9=lab
|
|
52
|
+
// Summer Sem: 12=id, 13=desc, 14=lec, 15=lab
|
|
53
|
+
const semesterBlocks = [
|
|
54
|
+
{ sem: 1, offset: 0 }, // first semester columns start at index 0
|
|
55
|
+
{ sem: 2, offset: 6 }, // second semester columns start at index 6
|
|
56
|
+
{ sem: 3, offset: 12 }, // summer semester columns start at index 12
|
|
57
|
+
];
|
|
58
|
+
semesterBlocks.forEach(({ sem, offset }) => {
|
|
59
|
+
const course_id = cells[offset] ?? "";
|
|
60
|
+
const course_desc = cells[offset + 1] ?? "";
|
|
61
|
+
const total_units = cells[offset + 2] ?? "";
|
|
62
|
+
const lec_unit = cells[offset + 3] ?? "";
|
|
63
|
+
const lab_unit = cells[offset + 4] ?? "";
|
|
64
|
+
if (course_id && year_level) {
|
|
65
|
+
cleanRows.push({
|
|
66
|
+
curr_id,
|
|
67
|
+
program_name,
|
|
68
|
+
revision_no,
|
|
69
|
+
year_level,
|
|
70
|
+
sem,
|
|
71
|
+
course_id,
|
|
72
|
+
course_desc,
|
|
73
|
+
total_units,
|
|
74
|
+
lec_unit,
|
|
75
|
+
lab_unit,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
return cleanRows;
|
|
83
|
+
}
|
package/parser/xls.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as XLSX from "xlsx";
|
|
2
|
+
export function convertToCSVFile(xls) {
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
const reader = new FileReader();
|
|
5
|
+
reader.onload = (evt) => {
|
|
6
|
+
const data = evt.target?.result;
|
|
7
|
+
if (!data) {
|
|
8
|
+
reject(new Error("Failed to read file"));
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
const workbook = XLSX.read(data, { type: "array" });
|
|
13
|
+
const sheetName = workbook.SheetNames[0];
|
|
14
|
+
if (!sheetName) {
|
|
15
|
+
reject(new Error("No sheets found in workbook"));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const workSheet = workbook.Sheets[sheetName];
|
|
19
|
+
if (!workSheet) {
|
|
20
|
+
reject(new Error("No sheets found in worksheet"));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const csvString = XLSX.utils.sheet_to_csv(workSheet);
|
|
24
|
+
// Create a new File from the CSV string
|
|
25
|
+
// Use the original filename but replace extension with .csv
|
|
26
|
+
const csvFileName = xls.name.replace(/\.[^/.]+$/, ".csv");
|
|
27
|
+
const csvFile = new File([csvString], csvFileName, {
|
|
28
|
+
type: "text/csv",
|
|
29
|
+
lastModified: Date.now(),
|
|
30
|
+
});
|
|
31
|
+
resolve(csvFile);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
reject(error);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
reader.onerror = () => {
|
|
38
|
+
reject(new Error("File reading failed"));
|
|
39
|
+
};
|
|
40
|
+
reader.readAsArrayBuffer(xls);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { parseAssessmentCsv } from "../parser/assessmentdata";
|
|
2
|
+
import { convertToCSVFile } from "../parser/xls";
|
|
3
|
+
export async function uploadAssessmentData(url, xls) {
|
|
4
|
+
try {
|
|
5
|
+
const csv = await convertToCSVFile(xls);
|
|
6
|
+
const data = await csv.text();
|
|
7
|
+
const parsed = parseAssessmentCsv(data);
|
|
8
|
+
const res = await fetch(`${url}/assessment-data/upload`, {
|
|
9
|
+
method: "POST",
|
|
10
|
+
headers: {
|
|
11
|
+
"Content-Type": "application/json"
|
|
12
|
+
},
|
|
13
|
+
body: JSON.stringify(parsed)
|
|
14
|
+
});
|
|
15
|
+
if (!res.ok) {
|
|
16
|
+
const errorData = await res.json();
|
|
17
|
+
throw errorData;
|
|
18
|
+
}
|
|
19
|
+
return res.json();
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { parseCOAEP } from "../parser/coaep";
|
|
2
|
+
import { convertToCSVFile } from "../parser/xls";
|
|
3
|
+
export async function uploadCOAEP(url, xls, course_id) {
|
|
4
|
+
try {
|
|
5
|
+
const csv = await convertToCSVFile(xls);
|
|
6
|
+
const data = await csv.text();
|
|
7
|
+
const parsed = parseCOAEP(data);
|
|
8
|
+
const res = await fetch(`${url}/coaeps/upload?course_id=${course_id}`, {
|
|
9
|
+
method: "POST",
|
|
10
|
+
headers: {
|
|
11
|
+
"Content-Type": "application/json"
|
|
12
|
+
},
|
|
13
|
+
body: JSON.stringify(parsed)
|
|
14
|
+
});
|
|
15
|
+
if (!res.ok) {
|
|
16
|
+
const errorData = await res.json();
|
|
17
|
+
throw errorData;
|
|
18
|
+
}
|
|
19
|
+
return res.json();
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { parseClassList } from "../parser/classList";
|
|
2
|
+
import { convertToCSVFile } from "../parser/xls";
|
|
3
|
+
export async function uploadClassList(url, xls, subj_code, period_id) {
|
|
4
|
+
try {
|
|
5
|
+
const csv = await convertToCSVFile(xls);
|
|
6
|
+
const data = await csv.text();
|
|
7
|
+
const parsed = parseClassList(data);
|
|
8
|
+
const query = `subj_code=${subj_code}&period_id=${period_id}`;
|
|
9
|
+
const res = await fetch(`${url}/enrolled-courses/upload?${query}`, {
|
|
10
|
+
method: "POST",
|
|
11
|
+
headers: {
|
|
12
|
+
"Content-Type": "application/json",
|
|
13
|
+
},
|
|
14
|
+
body: JSON.stringify(parsed),
|
|
15
|
+
});
|
|
16
|
+
if (!res.ok) {
|
|
17
|
+
const errorData = await res.json();
|
|
18
|
+
throw errorData;
|
|
19
|
+
}
|
|
20
|
+
return res.json();
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import Papa from "papaparse";
|
|
2
|
+
import { convertToCSVFile } from "../parser/xls";
|
|
3
|
+
import { parseCourseOffering } from "../parser/courseOffering";
|
|
4
|
+
export async function uploadCourseOffering(url, xls) {
|
|
5
|
+
try {
|
|
6
|
+
const csv = await convertToCSVFile(xls);
|
|
7
|
+
const data = await csv.text();
|
|
8
|
+
const parsed = parseCourseOffering(data);
|
|
9
|
+
const sanitized = Papa.unparse(parsed);
|
|
10
|
+
const sanitizedCsv = new File([sanitized], csv.name, { type: "text/csv" });
|
|
11
|
+
const formData = new FormData();
|
|
12
|
+
formData.append("csvFile", sanitizedCsv);
|
|
13
|
+
const res = await fetch(`${url}/course-offerings/upload`, {
|
|
14
|
+
method: "POST",
|
|
15
|
+
body: formData
|
|
16
|
+
});
|
|
17
|
+
if (!res.ok) {
|
|
18
|
+
const errorData = await res.json();
|
|
19
|
+
throw errorData;
|
|
20
|
+
}
|
|
21
|
+
return res.json();
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { parseCurriculum } from "../parser/curriculum";
|
|
2
|
+
import Papa from "papaparse";
|
|
3
|
+
import { convertToCSVFile } from "../parser/xls";
|
|
4
|
+
export async function uploadCurriculum(url, xls) {
|
|
5
|
+
try {
|
|
6
|
+
const csv = await convertToCSVFile(xls);
|
|
7
|
+
const data = await csv.text();
|
|
8
|
+
const parsed = parseCurriculum(data);
|
|
9
|
+
const sanitized = Papa.unparse(parsed);
|
|
10
|
+
const sanitizedCsv = new File([sanitized], csv.name, { type: "text/csv" });
|
|
11
|
+
const formData = new FormData();
|
|
12
|
+
formData.append("csvFile", sanitizedCsv);
|
|
13
|
+
const res = await fetch(`${url}/curr-courses/upload`, {
|
|
14
|
+
method: "POST",
|
|
15
|
+
body: formData
|
|
16
|
+
});
|
|
17
|
+
if (!res.ok) {
|
|
18
|
+
const errorData = await res.json();
|
|
19
|
+
throw errorData;
|
|
20
|
+
}
|
|
21
|
+
return res.json();
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { convertToCSVFile } from "../parser/xls";
|
|
2
|
+
export async function uploadEnrolledStudent(url, xls) {
|
|
3
|
+
try {
|
|
4
|
+
const csv = await convertToCSVFile(xls);
|
|
5
|
+
const formData = new FormData();
|
|
6
|
+
formData.append("csvFile", csv);
|
|
7
|
+
const res = await fetch(`${url}/enrolled-students/upload`, {
|
|
8
|
+
method: "POST",
|
|
9
|
+
body: formData
|
|
10
|
+
});
|
|
11
|
+
if (!res.ok) {
|
|
12
|
+
const errorData = await res.json();
|
|
13
|
+
throw errorData;
|
|
14
|
+
}
|
|
15
|
+
return res.json();
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/types/coaep.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/bundle.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import _0x4aefdc from 'papaparse';
|
|
2
|
-
import * as _0x3a54cb from 'xlsx';
|
|
3
|
-
|
|
4
|
-
function parseCurriculum(_0x4c65e8){let _0x532c63='',_0xecac9d='',_0x16b58a=0x0,_0xe9b69a=null;const _0x33f16a=[];return _0x4aefdc['parse'](_0x4c65e8,{'skipEmptyLines':!![],'complete':_0x1478a1=>{_0x1478a1['data']['forEach'](_0x28775c=>{const _0x4444a7=_0x28775c['map'](_0x11b3b5=>(_0x11b3b5??'')['toString']()['trim']()),_0x3fa8fa=_0x4444a7[0x0]??'';if(_0x3fa8fa['includes']('Rev#')){const _0x181c1e=_0x3fa8fa['match'](/([A-Z0-9]+)\s*-\s*.*:\s*(.*?)\s+Rev#\s*(\d+)/i);_0x181c1e&&(_0x532c63=_0x181c1e[0x1]?.['trim']()??'',_0xecac9d=_0x181c1e[0x2]?.['trim']()??'',_0x16b58a=parseInt(_0x181c1e[0x3]??'0',0xa));return;}if(/FIRST YEAR/i['test'](_0x3fa8fa)){_0xe9b69a=0x1;return;}if(/SECOND YEAR/i['test'](_0x3fa8fa)){_0xe9b69a=0x2;return;}if(/THIRD YEAR/i['test'](_0x3fa8fa)){_0xe9b69a=0x3;return;}if(/FOURTH YEAR/i['test'](_0x3fa8fa)){_0xe9b69a=0x4;return;}if(/FIFTH YEAR/i['test'](_0x3fa8fa)){_0xe9b69a=0x5;return;}if(/First Semester/i['test'](_0x3fa8fa)||/Second Semester/i['test'](_0x3fa8fa)||/Summer/i['test'](_0x3fa8fa))return;const _0x3aec97=[{'sem':0x1,'offset':0x0},{'sem':0x2,'offset':0x6},{'sem':0x3,'offset':0xc}];_0x3aec97['forEach'](({sem:_0x2be394,offset:_0x3163f5})=>{const _0x160e39=_0x4444a7[_0x3163f5]??'',_0x113034=_0x4444a7[_0x3163f5+0x1]??'',_0x464c9c=_0x4444a7[_0x3163f5+0x2]??'',_0x4ac04a=_0x4444a7[_0x3163f5+0x3]??'',_0x83279e=_0x4444a7[_0x3163f5+0x4]??'';_0x160e39&&_0xe9b69a&&_0x33f16a['push']({'curr_id':_0x532c63,'program_name':_0xecac9d,'revision_no':_0x16b58a,'year_level':_0xe9b69a,'sem':_0x2be394,'course_id':_0x160e39,'course_desc':_0x113034,'total_units':_0x464c9c,'lec_unit':_0x4ac04a,'lab_unit':_0x83279e});});});}}),_0x33f16a;}
|
|
5
|
-
|
|
6
|
-
function convertToCSVFile(_0x363188){return new Promise((_0x54b1f0,_0x3d665f)=>{const _0x275734=new FileReader();_0x275734['onload']=_0x249c5a=>{const _0x4aec9b=_0x249c5a['target']?.['result'];if(!_0x4aec9b){_0x3d665f(new Error('Failed\x20to\x20read\x20file'));return;}try{const _0x5ea1db=_0x3a54cb['read'](_0x4aec9b,{'type':'array'}),_0x15658c=_0x5ea1db['SheetNames'][0x0];if(!_0x15658c){_0x3d665f(new Error('No\x20sheets\x20found\x20in\x20workbook'));return;}const _0x360159=_0x5ea1db['Sheets'][_0x15658c];if(!_0x360159){_0x3d665f(new Error('No\x20sheets\x20found\x20in\x20worksheet'));return;}const _0x4c4ca3=_0x3a54cb['utils']['sheet_to_csv'](_0x360159),_0x3b7fde=_0x363188['name']['replace'](/\.[^/.]+$/,'.csv'),_0xa9ac15=new File([_0x4c4ca3],_0x3b7fde,{'type':'text/csv','lastModified':Date['now']()});_0x54b1f0(_0xa9ac15);}catch(_0x2f6040){_0x3d665f(_0x2f6040);}},_0x275734['onerror']=()=>{_0x3d665f(new Error('File\x20reading\x20failed'));},_0x275734['readAsArrayBuffer'](_0x363188);});}
|
|
7
|
-
|
|
8
|
-
async function uploadCurriculum(_0xebe15b,_0x4124d2){try{const _0x2c7bbb=await convertToCSVFile(_0x4124d2),_0x164574=await _0x2c7bbb['text'](),_0x2ee9f6=parseCurriculum(_0x164574),_0x6c5083=_0x4aefdc['unparse'](_0x2ee9f6),_0x51e71d=new File([_0x6c5083],_0x2c7bbb['name'],{'type':'text/csv'}),_0x1e14f0=new FormData();_0x1e14f0['append']('csvFile',_0x51e71d);const _0x343ad=await fetch(_0xebe15b+'/curr-courses/upload',{'method':'POST','body':_0x1e14f0});if(!_0x343ad['ok']){const _0x14883e=await _0x343ad['json']();throw _0x14883e;}return _0x343ad['json']();}catch(_0x247d1b){throw _0x247d1b;}}
|
|
9
|
-
|
|
10
|
-
function parseCourseOffering(_0x18f1b6){let _0x500854='',_0x132bd0='';const _0x5157db=[],_0x51d487=_0x4aefdc['parse'](_0x18f1b6,{'header':![],'skipEmptyLines':!![],'delimiter':','}),_0x19c02f=_0x51d487['data'];for(let _0x4ddba9=0x0;_0x4ddba9<Math['min'](0x5,_0x19c02f['length']);_0x4ddba9++){const _0x25c86f=_0x19c02f[_0x4ddba9];if(_0x25c86f&&_0x25c86f['length']>0x0){const _0x2aded9=_0x25c86f[0x0]?.['toString']()||'',_0x2142dd=_0x2aded9['match'](/(First|Second)\s+Sem\s+S\/Y\s+(\d{4}-\d{4})/i);if(_0x2142dd){_0x500854=_0x2142dd[0x1]?.['toLowerCase']()==='first'?'1':'2';if(_0x2142dd[0x2]){const _0x3bf9e9=_0x2142dd[0x2]['match'](/(\d{2})(\d{2})-(\d{2})(\d{2})/);_0x3bf9e9&&_0x3bf9e9[0x2]&&_0x3bf9e9[0x4]&&(_0x132bd0=_0x3bf9e9[0x2]+_0x3bf9e9[0x4]);}}}}let _0x93e96f=-1;for(let _0x441493=0x0;_0x441493<_0x19c02f['length'];_0x441493++){const _0x5b00b2=_0x19c02f[_0x441493];if(_0x5b00b2&&_0x5b00b2['some'](_0x5e2093=>_0x5e2093?.['toString']()['toUpperCase']()['includes']('CODE'))){_0x93e96f=_0x441493;break;}}if(_0x93e96f===-1)throw new Error('Could\x20not\x20find\x20header\x20row\x20in\x20CSV\x20data');for(let _0xb6ccbd=_0x93e96f+0x1;_0xb6ccbd<_0x19c02f['length'];_0xb6ccbd++){const _0x4fb315=_0x19c02f[_0xb6ccbd];if(!_0x4fb315||_0x4fb315['length']<0x8)continue;const _0x4b35b3=_0x4fb315[0x0]?.['toString']()['trim']()||'',_0x16913b=_0x4fb315[0x1]?.['toString']()['trim']()||'',_0x1be4cd=_0x4fb315[0x2]?.['toString']()['trim']()||'',_0x3e388e=_0x4fb315[0x3]?.['toString']()['trim']()||'',_0xdffe43=_0x4fb315[0x4]?.['toString']()['trim']()||'',_0x270364=_0x4fb315[0x5]?.['toString']()['trim']()||'',_0x2a11fc=_0x4fb315[0x6]?.['toString']()['trim']()||'',_0x4b008a=_0x4fb315[0x7]?.['toString']()['trim']()||'';if(!_0x4b35b3)continue;let _0x324f53=0x0;const _0x5bbae8=_0x3e388e['match'](/(\d+)/);_0x5bbae8&&_0x5bbae8[0x1]&&(_0x324f53=parseInt(_0x5bbae8[0x1],0xa));const _0x35f188={'sem':_0x500854,'school_year':_0x132bd0,'code':_0x4b35b3,'course_no':_0x16913b,'course_desc':_0x1be4cd,'unit':_0x324f53,'time':_0xdffe43,'days':_0x270364,'faculty':_0x2a11fc,'room':_0x4b008a};_0x5157db['push'](_0x35f188);}return _0x5157db;}
|
|
11
|
-
|
|
12
|
-
async function uploadCourseOffering(_0x1af96e,_0x5c2f3f){try{const _0x185371=await convertToCSVFile(_0x5c2f3f),_0x16c596=await _0x185371['text'](),_0xb8bcc6=parseCourseOffering(_0x16c596),_0x31692a=_0x4aefdc['unparse'](_0xb8bcc6),_0x4bad21=new File([_0x31692a],_0x185371['name'],{'type':'text/csv'}),_0x2e5b59=new FormData();_0x2e5b59['append']('csvFile',_0x4bad21);const _0x250590=await fetch(_0x1af96e+'/course-offerings/upload',{'method':'POST','body':_0x2e5b59});if(!_0x250590['ok']){const _0x13f373=await _0x250590['json']();throw _0x13f373;}return _0x250590['json']();}catch(_0x2a61a2){throw _0x2a61a2;}}
|
|
13
|
-
|
|
14
|
-
function performaceTarget(_0x166638){if(!_0x166638)return {'performance_target':null,'passing_score':null};const _0x1805d3=_0x166638['match'](/\d+/g);return {'performance_target':_0x1805d3?.[0x0]?parseInt(_0x1805d3[0x0],0xa):null,'passing_score':_0x1805d3?.[0x1]?parseInt(_0x1805d3[0x1],0xa):null};}
|
|
15
|
-
|
|
16
|
-
function parseCOAEP(_0xef4e57){const _0x3aa3c3=_0x4aefdc['parse'](_0xef4e57,{'skipEmptyLines':![]})['data'],_0x5edb43={'COAEP':{'faculty':null,'course':null,'sy':null,'semester':null,'co':[]}};_0x3aa3c3['forEach'](_0x43565d=>{_0x43565d[0x1]?.['includes']('Name\x20of\x20Faculty:')&&(_0x5edb43['COAEP']['faculty']=_0x43565d[0x2]?.['trim']()||null);if(_0x43565d['includes']('School\x20Year')){const _0x32eed8=_0x43565d['indexOf']('School\x20Year');_0x5edb43['COAEP']['sy']=_0x43565d[_0x32eed8+0x1]?.['trim']()||null;}if(_0x43565d[0x1]?.['includes']('Course:')){const _0x68e409=_0x43565d[0x2]?.['trim']()||'';_0x5edb43['COAEP']['course']=_0x68e409||null;}if(_0x43565d['includes']('Semester')){const _0x4defae=_0x43565d['indexOf']('Semester'),_0x4ca9ae=_0x43565d[_0x4defae+0x1]?.['trim']()||'',_0x367fb9=_0x4ca9ae['match'](/\d+/)?.[0x0];_0x5edb43['COAEP']['semester']=_0x367fb9?parseInt(_0x367fb9,0xa):null;}});let _0x162ebd=null;return _0x3aa3c3['forEach'](_0x4a55ed=>{const _0x10cd55=_0x4a55ed[0x0]?.['trim']()||'',_0x27a1f5=_0x4a55ed[0x1]?.['trim']()||'',_0x17f175=_0x4a55ed[0x3]?.['trim']()||'';if(_0x10cd55&&/^\d+$/['test'](_0x10cd55)){_0x162ebd&&_0x5edb43['COAEP']['co']['push'](_0x162ebd);const _0x1a80a8=_0x27a1f5,_0x42affd=_0x1a80a8['trim']()['split'](/\s+/)[0x0]??'';_0x162ebd={'statement':_0x1a80a8,'verb':_0x42affd,'ilo':[]};}if(_0x162ebd&&_0x17f175){const _0x1d5bcc=_0x17f175['replace'](/^ILO\d+\s*/,'')['replace'](/\s+/g,'\x20')['trim'](),_0x55bdda=_0x4a55ed[0x4]?.['replace'](/\s+/g,'\x20')['trim']()||'',_0x5d052a=_0x4a55ed[0x5]?.['replace'](/\s+/g,'\x20')['trim']()||'',{performance_target:_0x4a0bf1,passing_score:_0x766931}=performaceTarget(_0x5d052a);_0x162ebd['ilo']['push']({'statement':_0x1d5bcc,'verb':_0x1d5bcc['split'](/\s+/)[0x0]??'','assessment_tool':_0x55bdda,'performance_target':_0x4a0bf1,'passing_score':_0x766931});}}),_0x162ebd&&_0x5edb43['COAEP']['co']['push'](_0x162ebd),_0x5edb43;}
|
|
17
|
-
|
|
18
|
-
async function uploadCOAEP(_0x7ba016,_0x5f27bd,_0x5b17df){try{const _0x5c036f=await convertToCSVFile(_0x5f27bd),_0xa8fad=await _0x5c036f['text'](),_0x24b0e9=parseCOAEP(_0xa8fad),_0x5be2e2=await fetch(_0x7ba016+'/coaeps/upload?course_id='+_0x5b17df,{'method':'POST','headers':{'Content-Type':'application/json'},'body':JSON['stringify'](_0x24b0e9)});if(!_0x5be2e2['ok']){const _0x5a0c58=await _0x5be2e2['json']();throw _0x5a0c58;}return _0x5be2e2['json']();}catch(_0xfbd41b){throw _0xfbd41b;}}
|
|
19
|
-
|
|
20
|
-
async function uploadEnrolledStudent(_0x47e15a,_0xea8db8){try{const _0x296b37=await convertToCSVFile(_0xea8db8),_0x4d48c8=new FormData();_0x4d48c8['append']('csvFile',_0x296b37);const _0x25e5c4=await fetch(_0x47e15a+'/enrolled-students/upload',{'method':'POST','body':_0x4d48c8});if(!_0x25e5c4['ok']){const _0x3def63=await _0x25e5c4['json']();throw _0x3def63;}return _0x25e5c4['json']();}catch(_0x54671d){throw _0x54671d;}}
|
|
21
|
-
|
|
22
|
-
function parseClassList(_0x4245cf){const _0x307729=_0x4aefdc['parse'](_0x4245cf,{'skipEmptyLines':!![]})['data'];let _0x2777cc='',_0x4ed981='',_0x1968e2='';const _0x54300a=[];return _0x307729['forEach'](_0x514569=>{const _0x552e27=_0x514569['map'](_0x4c415b=>(_0x4c415b??'')['toString']()['trim']()),_0x2a0f60=_0x552e27[0x0]??'';if(_0x2a0f60['startsWith']('Course\x20No:')){const _0x547b8b=_0x2a0f60['replace']('Course\x20No:','')['trim'](),_0x3b97bd=_0x547b8b['split'](/\s+/);_0x1968e2=_0x3b97bd[0x0]??'';const [_0x5296bb,_0xa8f3a4]=(_0x3b97bd[0x1]??'')['split']('-');_0x4ed981=_0x5296bb??'';const _0x15b407=(_0xa8f3a4??'')['match'](/[a-z]$/);_0x2777cc=_0x15b407?_0x15b407[0x0]:'';}if(/^\d+$/['test'](_0x2a0f60)){const _0x70a4cc=_0x552e27[0x2]??'';_0x54300a['push']({'subj_code':_0x1968e2,'student_no':_0x70a4cc,'course_id':_0x4ed981,'section':_0x2777cc});}}),{'enrolledCourses':_0x54300a};}
|
|
23
|
-
|
|
24
|
-
async function uploadClassList(_0x35a693,_0x298214,_0x5d569b,_0x56c7a8){try{const _0x394e86=await convertToCSVFile(_0x298214),_0x22e8f1=await _0x394e86['text'](),_0x578e2a=parseClassList(_0x22e8f1),_0x52bd95='subj_code='+_0x5d569b+'&period_id='+_0x56c7a8,_0x28eae3=await fetch(_0x35a693+'/enrolled-courses/upload?'+_0x52bd95,{'method':'POST','headers':{'Content-Type':'application/json'},'body':JSON['stringify'](_0x578e2a)});if(!_0x28eae3['ok']){const _0x4625cd=await _0x28eae3['json']();throw _0x4625cd;}return _0x28eae3['json']();}catch(_0x1573b5){throw _0x1573b5;}}
|
|
25
|
-
|
|
26
|
-
function parseAssessmentCsv(_0x6ccf99){const {data:_0x452d2f}=_0x4aefdc['parse'](_0x6ccf99,{'skipEmptyLines':!![]}),_0x1530d8=_0x452d2f['filter'](_0xc34218=>_0xc34218['length']>0x0),_0x5510f5=_0x1530d8['find'](_0x2fe06e=>_0x2fe06e['some'](_0x47579b=>_0x47579b?.['includes']('Faculty'))),_0x53dad8=_0x5510f5?_0x5510f5['findIndex'](_0x1769af=>_0x1769af?.['includes']('Faculty')):-1,_0x2cf537=_0x53dad8!==-1&&_0x5510f5?_0x5510f5[_0x53dad8+0x2]?.['replace'](/"/g,'')['trim']()??'':'',_0x9769cc=_0x1530d8['find'](_0x57fe3f=>_0x57fe3f['some'](_0x3bb155=>_0x3bb155?.['includes']('Semester'))),_0x41d9e1=_0x9769cc?_0x9769cc['findIndex'](_0xf0c7ab=>_0xf0c7ab?.['includes']('Semester')):-1,_0x2f6f28=_0x41d9e1!==-1&&_0x9769cc?_0x9769cc[_0x41d9e1+0x2]?.['trim']()??'':'',_0x46e8df=_0x2f6f28['includes']('1st')?0x1:_0x2f6f28['includes']('2nd')?0x2:0x0,_0x229be6=_0x1530d8['find'](_0x1f03d8=>_0x1f03d8['some'](_0x2457d8=>_0x2457d8?.['includes']('Course\x20&\x20Sec'))),_0x4bdd6a=_0x229be6?_0x229be6['findIndex'](_0x1f4484=>_0x1f4484?.['includes']('Course\x20&\x20Sec')):-1,_0x25080e=_0x4bdd6a!==-1&&_0x229be6?_0x229be6[_0x4bdd6a+0x2]?.['trim']()??'':'';let _0x4cee11='',_0x4f89f6='';if(_0x25080e){const _0xc59b77=_0x25080e['match'](/^([A-Za-z0-9]+)-?([A-Za-z]+)?/);_0xc59b77&&(_0x4cee11=_0xc59b77[0x1]??'',_0xc59b77[0x2]&&(_0x4f89f6=_0xc59b77[0x2]['replace'](/^OC/i,'')));}const _0x83877=_0x1530d8['find'](_0x1e700d=>_0x1e700d['some'](_0x5cb693=>_0x5cb693?.['includes']('School\x20Year'))),_0x36112d=_0x83877?_0x83877['findIndex'](_0x1a3860=>_0x1a3860?.['includes']('School\x20Year')):-1,_0x54d909=_0x36112d!==-1&&_0x83877?_0x83877[_0x36112d+0x2]?.['trim']()??'':'';let _0x5029fe=0x0;if(_0x54d909){const _0x5cacf1=_0x54d909['match'](/(\d{4})-(\d{4})/);if(_0x5cacf1){const _0x4c9a7d=(_0x5cacf1[0x1]??'')['slice'](0x2),_0xb9fd87=(_0x5cacf1[0x2]??'')['slice'](0x2);_0x5029fe=parseInt(_0x4c9a7d+_0xb9fd87,0xa);}}const _0x19f17f={'faculty':_0x2cf537,'course':_0x4cee11,'section':_0x4f89f6,'semester':_0x46e8df,'sy':_0x5029fe},_0x387a0d=_0x1530d8['findIndex'](_0x2de900=>_0x2de900['some'](_0x4314a4=>_0x4314a4?.['trim']()==='CO\x20#'));if(_0x387a0d===-1)throw new Error('CO\x20header\x20row\x20not\x20found\x20in\x20CSV');const _0x23767a=_0x1530d8[_0x387a0d+0x1];if(!_0x23767a)throw new Error('ILO\x20header\x20row\x20not\x20found\x20in\x20CSV');const _0x4b1a9e={};let _0x2392af=0x1,_0x85b509=0x1;for(let _0x1cd4a6=0x3;_0x1cd4a6<_0x23767a['length'];_0x1cd4a6++){const _0x476dc0=_0x23767a[_0x1cd4a6];if(!_0x476dc0)continue;const _0x426311='co'+_0x2392af;if(!_0x4b1a9e[_0x426311])_0x4b1a9e[_0x426311]=[];_0x4b1a9e[_0x426311]['push']('ilo'+_0x85b509),_0x85b509++,_0x85b509>0x3&&(_0x2392af++,_0x85b509=0x1);}const _0x2e696a=_0x1530d8['findIndex'](_0x25a0a4=>_0x25a0a4['includes']('Name\x20of\x20Students'));if(_0x2e696a===-1)throw new Error('Student\x20header\x20row\x20not\x20found\x20in\x20CSV');const _0x2f3cc8=_0x1530d8[_0x2e696a];if(!_0x2f3cc8)throw new Error('Student\x20header\x20row\x20is\x20missing');const _0x55db5d=_0x2f3cc8['findIndex'](_0xb5fe31=>_0xb5fe31?.['includes']('Name\x20of\x20Students'));if(_0x55db5d===-1)throw new Error('Name\x20of\x20Students\x20column\x20not\x20found\x20in\x20CSV');const _0x1c3380=_0x55db5d+0x2,_0x4ec9fb=[];for(let _0x3ab645=_0x2e696a+0x1;_0x3ab645<_0x1530d8['length'];_0x3ab645++){const _0x1706d8=_0x1530d8[_0x3ab645];if(!_0x1706d8)continue;if(_0x1706d8['some'](_0x1bbda4=>_0x1bbda4?.['toUpperCase']()['includes']('TOTAL\x20STUDENTS')||_0x1bbda4?.['toUpperCase']()['includes']('ACHIEVED\x20THE\x20MINIMUM')||_0x1bbda4?.['toUpperCase']()['includes']('INACTIVE')||_0x1bbda4?.['toUpperCase']()['includes']('AVERAGE')))continue;if(!_0x1706d8[_0x55db5d])continue;const _0x1ec0b1=_0x1706d8[_0x55db5d]['replace'](/"/g,'')['trim'](),_0xb629b0=_0x1706d8['slice'](_0x1c3380)['map'](_0x738f31=>_0x738f31&&!isNaN(Number(_0x738f31))?parseFloat(_0x738f31):0x0);let _0x15955a=0x0;const _0x5afeff={};Object['entries'](_0x4b1a9e)['forEach'](([_0x34d167,_0x5d6070])=>{const _0x235b49={};_0x5d6070['forEach'](_0x2420f6=>{_0x235b49[_0x2420f6]=_0xb629b0[_0x15955a]??0x0,_0x15955a++;}),_0x5afeff[_0x34d167]={'transmuted_score':_0x235b49};}),_0x4ec9fb['push']({'student_name':_0x1ec0b1,'coaep':_0x5afeff});}const _0xa8d442=_0x1530d8['find'](_0xfad513=>_0xfad513['some'](_0x4ca460=>_0x4ca460?.['includes']('ACHIEVED\x20THE\x20MINIMUM'))),_0x2ce0bb=_0x1530d8['find'](_0x279d36=>_0x279d36['some'](_0x3e88da=>_0x3e88da?.['includes']('AVERAGE'))),_0x264722=_0xa8d442?_0xa8d442['slice'](_0x1c3380)['map'](_0x41a423=>_0x41a423&&!isNaN(Number(_0x41a423))?parseInt(_0x41a423):0x0):[],_0x4fca45=_0x2ce0bb?_0x2ce0bb['slice'](_0x1c3380)['map'](_0x884b2f=>_0x884b2f&&_0x884b2f!=='#DIV/0!'&&!isNaN(Number(_0x884b2f))?parseInt(_0x884b2f):0x0):[],_0x1b5552={};let _0x46a635=0x0;return Object['entries'](_0x4b1a9e)['forEach'](([_0x3e328f,_0x2bf3d6])=>{if(!_0x1b5552[_0x3e328f])_0x1b5552[_0x3e328f]={};_0x2bf3d6['forEach'](_0x1df0b4=>{_0x1b5552[_0x3e328f][_0x1df0b4]={'achievedMinimum':_0x264722[_0x46a635]??0x0,'average':_0x4fca45[_0x46a635]??0x0},_0x46a635++;});}),{'assessmentData':{'classAssignment':_0x19f17f,'student':_0x4ec9fb,'total':_0x1b5552}};}
|
|
27
|
-
|
|
28
|
-
async function uploadAssessmentData(_0x5098cc,_0x17f81a){try{const _0x3162d6=await convertToCSVFile(_0x17f81a),_0x514dd0=await _0x3162d6['text'](),_0x3c3293=parseAssessmentCsv(_0x514dd0),_0x3d6168=await fetch(_0x5098cc+'/assessment-data/upload',{'method':'POST','headers':{'Content-Type':'application/json'},'body':JSON['stringify'](_0x3c3293)});if(!_0x3d6168['ok']){const _0x176ff0=await _0x3d6168['json']();throw _0x176ff0;}return _0x3d6168['json']();}catch(_0x46e975){throw _0x46e975;}}
|
|
29
|
-
|
|
30
|
-
class Client{['BASE_URL'];constructor(_0x3ba46e){this['BASE_URL']=_0x3ba46e;}['Parser'](){return {'curriculum':async _0x50f405=>{const _0xf45838=await uploadCurriculum(this['BASE_URL'],_0x50f405);return _0xf45838;},'courseOffering':async _0x23d699=>{const _0x47aba4=await uploadCourseOffering(this['BASE_URL'],_0x23d699);return _0x47aba4;},'coaep':async(_0xf03ba,_0x29adf2)=>{const _0x47e74c=await uploadCOAEP(this['BASE_URL'],_0xf03ba,_0x29adf2);return _0x47e74c;},'enrolledStudent':async _0x2baa0c=>{const _0x24ffd0=await uploadEnrolledStudent(this['BASE_URL'],_0x2baa0c);return _0x24ffd0;},'classlist':async(_0x5de9f2,_0x425a85,_0x5674a6)=>{const _0x1db0ae=await uploadClassList(this['BASE_URL'],_0x5de9f2,_0x425a85,_0x5674a6);return _0x1db0ae;},'assessmentData':async _0x53afdf=>{const _0x58ea89=await uploadAssessmentData(this['BASE_URL'],_0x53afdf);return _0x58ea89;}};}}
|
|
31
|
-
|
|
32
|
-
export { Client as default };
|
package/helper/matchTarget.d.ts
DELETED
package/main.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export default class Client {
|
|
2
|
-
private BASE_URL;
|
|
3
|
-
constructor(url: string);
|
|
4
|
-
Parser(): {
|
|
5
|
-
/**
|
|
6
|
-
* Parse the official curriculum data from the registrar to a digestible format
|
|
7
|
-
* @param curriculum file from registrar
|
|
8
|
-
* @returns status 201
|
|
9
|
-
*/
|
|
10
|
-
curriculum: (xls: File) => Promise<Record<string, unknown>>;
|
|
11
|
-
/**
|
|
12
|
-
* Parse the course offering data
|
|
13
|
-
* @param offering file from registrar
|
|
14
|
-
* @returns status 201
|
|
15
|
-
*/
|
|
16
|
-
courseOffering: (xls: File) => Promise<Record<string, unknown>>;
|
|
17
|
-
coaep: (xls: File, course_id: string) => Promise<Record<string, unknown>>;
|
|
18
|
-
enrolledStudent: (xls: File) => Promise<Record<string, unknown>>;
|
|
19
|
-
classlist: (
|
|
20
|
-
xls: File,
|
|
21
|
-
subj_code: number,
|
|
22
|
-
period_id: number
|
|
23
|
-
) => Promise<Record<string, unknown>>;
|
|
24
|
-
assessmentData: (xls: File) => Promise<Record<string, unknown>>;
|
|
25
|
-
};
|
|
26
|
-
}
|
package/parser/classList.d.ts
DELETED
package/parser/coaep.d.ts
DELETED
package/parser/curriculum.d.ts
DELETED
package/parser/xls.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function convertToCSVFile(xls: File): Promise<File>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function uploadAssessmentData(url: string, xls: File): Promise<Record<string, unknown>>;
|
package/relay/uploadCOAEP.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function uploadCOAEP(url: string, xls: File, course_id: string): Promise<Record<string, unknown>>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function uploadClassList(url: string, xls: File, subj_code: number, period_id: number): Promise<Record<string, unknown>>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function uploadCourseOffering(url: string, xls: File): Promise<Record<string, unknown>>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function uploadCurriculum(url: string, xls: File): Promise<Record<string, unknown>>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function uploadEnrolledStudent(url: string, xls: File): Promise<Record<string, unknown>>;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export type TransmutedScore = Record<string, number>;
|
|
2
|
-
export type Coaep = Record<string, {
|
|
3
|
-
transmuted_score: TransmutedScore;
|
|
4
|
-
}>;
|
|
5
|
-
export type Student = {
|
|
6
|
-
student_name: string;
|
|
7
|
-
coaep: Coaep;
|
|
8
|
-
};
|
|
9
|
-
export type ClassAssignment = {
|
|
10
|
-
faculty: string;
|
|
11
|
-
course: string;
|
|
12
|
-
section: string;
|
|
13
|
-
semester: number;
|
|
14
|
-
sy: number;
|
|
15
|
-
};
|
|
16
|
-
export type TotalIlo = {
|
|
17
|
-
achievedMinimum: number;
|
|
18
|
-
average: number;
|
|
19
|
-
};
|
|
20
|
-
export type Total = Record<string, Record<string, TotalIlo>>;
|
|
21
|
-
export type AssessmentData = {
|
|
22
|
-
classAssignment: ClassAssignment;
|
|
23
|
-
student: Student[];
|
|
24
|
-
total: Total;
|
|
25
|
-
};
|
package/types/classList.d.ts
DELETED
package/types/coaep.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export interface ILO {
|
|
2
|
-
statement: string;
|
|
3
|
-
verb: string;
|
|
4
|
-
assessment_tool: string;
|
|
5
|
-
performance_target: number | null;
|
|
6
|
-
passing_score: number | null;
|
|
7
|
-
}
|
|
8
|
-
export interface CO {
|
|
9
|
-
statement: string;
|
|
10
|
-
verb: string;
|
|
11
|
-
ilo: ILO[];
|
|
12
|
-
}
|
|
13
|
-
export interface COAEP {
|
|
14
|
-
faculty: string | null;
|
|
15
|
-
course: string | null;
|
|
16
|
-
sy: string | null;
|
|
17
|
-
semester: number | null;
|
|
18
|
-
co: CO[];
|
|
19
|
-
}
|
package/types/curriculum.d.ts
DELETED