@obe-loms/coms-parser 1.1.3 → 1.2.0
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/bundle.js +32 -0
- package/helper/matchTarget.d.ts +4 -0
- package/main.d.ts +22 -0
- package/package.json +3 -2
- package/parser/assessmentdata.d.ts +4 -0
- package/parser/classList.d.ts +6 -0
- package/parser/coaep.d.ts +4 -0
- package/parser/courseOffering.d.ts +2 -0
- package/parser/curriculum.d.ts +2 -0
- package/parser/xls.d.ts +1 -0
- package/relay/uploadAssessmentData.d.ts +1 -0
- package/relay/uploadCOAEP.d.ts +1 -0
- package/relay/uploadClassList.d.ts +1 -0
- package/relay/uploadCourseOffering.d.ts +1 -0
- package/relay/uploadCurriculum.d.ts +1 -0
- package/relay/uploadEnrolledStudent.d.ts +1 -0
- package/types/assessmentdata.d.ts +25 -0
- package/types/classList.d.ts +6 -0
- package/types/coaep.d.ts +19 -0
- package/types/courseOffering.d.ts +12 -0
- package/types/curriculum.d.ts +12 -0
- package/helper/matchTarget.js +0 -9
- package/index.d.ts +0 -1
- package/index.js +0 -10
- package/main.js +0 -50
- package/parser/assessmentdata.js +0 -149
- package/parser/classList.js +0 -36
- package/parser/coaep.js +0 -73
- package/parser/courseOffering.js +0 -84
- package/parser/curriculum.js +0 -83
- package/parser/xls.js +0 -42
- package/relay/uploadAssessmentData.js +0 -24
- package/relay/uploadCOAEP.js +0 -24
- package/relay/uploadClassList.js +0 -25
- package/relay/uploadCourseOffering.js +0 -26
- package/relay/uploadCurriculum.js +0 -26
- package/relay/uploadEnrolledStudent.js +0 -20
- package/types/assessmentdata.js +0 -1
- package/types/classList.js +0 -1
- package/types/coaep.js +0 -1
- package/types/courseOffering.js +0 -1
- package/types/curriculum.js +0 -1
package/bundle.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import _0x1ec977 from 'papaparse';
|
|
2
|
+
import * as _0x2ad8be from 'xlsx';
|
|
3
|
+
|
|
4
|
+
function parseCurriculum(_0x5d82bf){let _0x59a6bd='',_0x35b239='',_0x1388e7=0x0,_0xfefd8c=null;const _0x4d735a=[];return _0x1ec977['parse'](_0x5d82bf,{'skipEmptyLines':!![],'complete':_0xccc6ec=>{_0xccc6ec['data']['forEach'](_0x53943b=>{const _0xa56a40=_0x53943b['map'](_0x22f4ed=>(_0x22f4ed??'')['toString']()['trim']()),_0x1da509=_0xa56a40[0x0]??'';if(_0x1da509['includes']('Rev#')){const _0xb6caf3=_0x1da509['match'](/([A-Z0-9]+)\s*-\s*.*:\s*(.*?)\s+Rev#\s*(\d+)/i);_0xb6caf3&&(_0x59a6bd=_0xb6caf3[0x1]?.['trim']()??'',_0x35b239=_0xb6caf3[0x2]?.['trim']()??'',_0x1388e7=parseInt(_0xb6caf3[0x3]??'0',0xa));return;}if(/FIRST YEAR/i['test'](_0x1da509)){_0xfefd8c=0x1;return;}if(/SECOND YEAR/i['test'](_0x1da509)){_0xfefd8c=0x2;return;}if(/THIRD YEAR/i['test'](_0x1da509)){_0xfefd8c=0x3;return;}if(/FOURTH YEAR/i['test'](_0x1da509)){_0xfefd8c=0x4;return;}if(/FIFTH YEAR/i['test'](_0x1da509)){_0xfefd8c=0x5;return;}if(/First Semester/i['test'](_0x1da509)||/Second Semester/i['test'](_0x1da509)||/Summer/i['test'](_0x1da509))return;const _0x5107f0=[{'sem':0x1,'offset':0x0},{'sem':0x2,'offset':0x6},{'sem':0x3,'offset':0xc}];_0x5107f0['forEach'](({sem:_0x2182f1,offset:_0x59a35e})=>{const _0x540bce=_0xa56a40[_0x59a35e]??'',_0x3c78d7=_0xa56a40[_0x59a35e+0x1]??'',_0x5ead34=_0xa56a40[_0x59a35e+0x2]??'',_0x27aaff=_0xa56a40[_0x59a35e+0x3]??'',_0x245556=_0xa56a40[_0x59a35e+0x4]??'';_0x540bce&&_0xfefd8c&&_0x4d735a['push']({'curr_id':_0x59a6bd,'program_name':_0x35b239,'revision_no':_0x1388e7,'year_level':_0xfefd8c,'sem':_0x2182f1,'course_id':_0x540bce,'course_desc':_0x3c78d7,'total_units':_0x5ead34,'lec_unit':_0x27aaff,'lab_unit':_0x245556});});});}}),_0x4d735a;}
|
|
5
|
+
|
|
6
|
+
function convertToCSVFile(_0x17e0df){return new Promise((_0x577897,_0x34e47c)=>{const _0x3e2a3d=new FileReader();_0x3e2a3d['onload']=_0x4e7687=>{const _0x3900af=_0x4e7687['target']?.['result'];if(!_0x3900af){_0x34e47c(new Error('Failed\x20to\x20read\x20file'));return;}try{const _0x150a94=_0x2ad8be['read'](_0x3900af,{'type':'array'}),_0x212e6f=_0x150a94['SheetNames'][0x0];if(!_0x212e6f){_0x34e47c(new Error('No\x20sheets\x20found\x20in\x20workbook'));return;}const _0x3dca89=_0x150a94['Sheets'][_0x212e6f];if(!_0x3dca89){_0x34e47c(new Error('No\x20sheets\x20found\x20in\x20worksheet'));return;}const _0x5f14ed=_0x2ad8be['utils']['sheet_to_csv'](_0x3dca89,{'strip':!![]}),_0x2653b6=_0x17e0df['name']['replace'](/\.[^/.]+$/,'.csv'),_0x496c55=new File([_0x5f14ed],_0x2653b6,{'type':'text/csv','lastModified':Date['now']()});_0x577897(_0x496c55);}catch(_0x1eef71){_0x34e47c(_0x1eef71);}},_0x3e2a3d['onerror']=()=>{_0x34e47c(new Error('File\x20reading\x20failed'));},_0x3e2a3d['readAsArrayBuffer'](_0x17e0df);});}
|
|
7
|
+
|
|
8
|
+
async function uploadCurriculum(_0x161e1e,_0x554065){try{const _0x3fc73a=await convertToCSVFile(_0x554065),_0xb2dbde=await _0x3fc73a['text'](),_0x26492e=parseCurriculum(_0xb2dbde),_0x45f21=_0x1ec977['unparse'](_0x26492e),_0x19d6a1=new File([_0x45f21],_0x3fc73a['name'],{'type':'text/csv'}),_0x54cb50=new FormData();_0x54cb50['append']('csvFile',_0x19d6a1);const _0x1b2fb6=await fetch(_0x161e1e+'/curr-courses/upload',{'method':'POST','body':_0x54cb50});if(!_0x1b2fb6['ok']){const _0x1118d3=await _0x1b2fb6['json']();throw _0x1118d3;}return _0x1b2fb6['json']();}catch(_0xdcfe6a){throw _0xdcfe6a;}}
|
|
9
|
+
|
|
10
|
+
function parseCourseOffering(_0x50c30e){let _0x46c0d3='',_0x5208fa='';const _0x10de99=[],_0x20b1e9=_0x1ec977['parse'](_0x50c30e,{'header':![],'skipEmptyLines':!![],'delimiter':','}),_0x13f832=_0x20b1e9['data'];for(let _0x6e3428=0x0;_0x6e3428<Math['min'](0x5,_0x13f832['length']);_0x6e3428++){const _0x81fac7=_0x13f832[_0x6e3428];if(_0x81fac7&&_0x81fac7['length']>0x0){const _0x324409=_0x81fac7[0x0]?.['toString']()||'',_0x517eb5=_0x324409['match'](/(First|Second)\s+Sem\s+S\/Y\s+(\d{4}-\d{4})/i);if(_0x517eb5){_0x46c0d3=_0x517eb5[0x1]?.['toLowerCase']()==='first'?'1':'2';if(_0x517eb5[0x2]){const _0x1f7103=_0x517eb5[0x2]['match'](/(\d{2})(\d{2})-(\d{2})(\d{2})/);_0x1f7103&&_0x1f7103[0x2]&&_0x1f7103[0x4]&&(_0x5208fa=_0x1f7103[0x2]+_0x1f7103[0x4]);}}}}let _0x18bc5d=-1;for(let _0x25adc3=0x0;_0x25adc3<_0x13f832['length'];_0x25adc3++){const _0x257ffe=_0x13f832[_0x25adc3];if(_0x257ffe&&_0x257ffe['some'](_0x1e6c94=>_0x1e6c94?.['toString']()['toUpperCase']()['includes']('CODE'))){_0x18bc5d=_0x25adc3;break;}}if(_0x18bc5d===-1)throw new Error('Could\x20not\x20find\x20header\x20row\x20in\x20CSV\x20data');for(let _0x4c1451=_0x18bc5d+0x1;_0x4c1451<_0x13f832['length'];_0x4c1451++){const _0x18016b=_0x13f832[_0x4c1451];if(!_0x18016b||_0x18016b['length']<0x8)continue;const _0x281039=_0x18016b[0x0]?.['toString']()['trim']()||'',_0x5d17bf=_0x18016b[0x1]?.['toString']()['trim']()||'',_0x5835dd=_0x18016b[0x2]?.['toString']()['trim']()||'',_0xabdc86=_0x18016b[0x3]?.['toString']()['trim']()||'',_0x2dda65=_0x18016b[0x4]?.['toString']()['trim']()||'',_0x5ae6dd=_0x18016b[0x5]?.['toString']()['trim']()||'',_0x1f4a6a=_0x18016b[0x6]?.['toString']()['trim']()||'',_0xd794b3=_0x18016b[0x7]?.['toString']()['trim']()||'';if(!_0x281039)continue;let _0x39876=0x0;const _0x14133c=_0xabdc86['match'](/(\d+)/);_0x14133c&&_0x14133c[0x1]&&(_0x39876=parseInt(_0x14133c[0x1],0xa));const _0x3e6e38={'sem':_0x46c0d3,'school_year':_0x5208fa,'code':_0x281039,'course_no':_0x5d17bf,'course_desc':_0x5835dd,'unit':_0x39876,'time':_0x2dda65,'days':_0x5ae6dd,'faculty':_0x1f4a6a,'room':_0xd794b3};_0x10de99['push'](_0x3e6e38);}return _0x10de99;}
|
|
11
|
+
|
|
12
|
+
async function uploadCourseOffering(_0x1ff3e9,_0x452cf2){try{const _0x2c5c9f=await convertToCSVFile(_0x452cf2),_0x18f114=await _0x2c5c9f['text'](),_0xe394e=parseCourseOffering(_0x18f114),_0x239e2d=_0x1ec977['unparse'](_0xe394e),_0x3bb5b4=new File([_0x239e2d],_0x2c5c9f['name'],{'type':'text/csv'}),_0x46751a=new FormData();_0x46751a['append']('csvFile',_0x3bb5b4);const _0x466ef8=await fetch(_0x1ff3e9+'/course-offerings/upload',{'method':'POST','body':_0x46751a});if(!_0x466ef8['ok']){const _0x27b298=await _0x466ef8['json']();throw _0x27b298;}return _0x466ef8['json']();}catch(_0x2515e5){throw _0x2515e5;}}
|
|
13
|
+
|
|
14
|
+
function performaceTarget(_0x1ed2fb){if(!_0x1ed2fb)return {'performance_target':null,'passing_score':null};const _0x5cf0e2=_0x1ed2fb['match'](/\d+/g);return {'performance_target':_0x5cf0e2?.[0x0]?parseInt(_0x5cf0e2[0x0],0xa):null,'passing_score':_0x5cf0e2?.[0x1]?parseInt(_0x5cf0e2[0x1],0xa):null};}
|
|
15
|
+
|
|
16
|
+
function parseCOAEP(_0x3d0ad6){const _0xd36abf=_0x1ec977['parse'](_0x3d0ad6,{'skipEmptyLines':![]})['data'],_0x208827={'COAEP':{'faculty':null,'course':null,'sy':null,'semester':null,'co':[]}};_0xd36abf['forEach'](_0x5afa6c=>{_0x5afa6c[0x1]?.['includes']('Name\x20of\x20Faculty:')&&(_0x208827['COAEP']['faculty']=_0x5afa6c[0x2]?.['trim']()||null);if(_0x5afa6c['includes']('School\x20Year')){const _0x2113c1=_0x5afa6c['indexOf']('School\x20Year');_0x208827['COAEP']['sy']=_0x5afa6c[_0x2113c1+0x1]?.['trim']()||null;}if(_0x5afa6c[0x1]?.['includes']('Course:')){const _0x40807c=_0x5afa6c[0x2]?.['trim']()||'';_0x208827['COAEP']['course']=_0x40807c||null;}if(_0x5afa6c['includes']('Semester')){const _0x57807a=_0x5afa6c['indexOf']('Semester'),_0x595633=_0x5afa6c[_0x57807a+0x1]?.['trim']()||'',_0xe05f3d=_0x595633['match'](/\d+/)?.[0x0];_0x208827['COAEP']['semester']=_0xe05f3d?parseInt(_0xe05f3d,0xa):null;}});let _0x3a9bce=null;return _0xd36abf['forEach'](_0x19ddd4=>{const _0x367f26=_0x19ddd4[0x0]?.['trim']()||'',_0xa2789e=_0x19ddd4[0x1]?.['trim']()||'',_0x2f1d79=_0x19ddd4[0x3]?.['trim']()||'';if(_0x367f26&&/^\d+$/['test'](_0x367f26)){_0x3a9bce&&_0x208827['COAEP']['co']['push'](_0x3a9bce);const _0xcca40d=_0xa2789e,_0x374e50=_0xcca40d['trim']()['split'](/\s+/)[0x0]??'';_0x3a9bce={'statement':_0xcca40d,'verb':_0x374e50,'ilo':[]};}if(_0x3a9bce&&_0x2f1d79){const _0x569b62=_0x2f1d79['replace'](/^ILO\d+\s*/,'')['replace'](/\s+/g,'\x20')['trim'](),_0x3eb01e=_0x19ddd4[0x4]?.['replace'](/\s+/g,'\x20')['trim']()||'',_0x416095=_0x19ddd4[0x5]?.['replace'](/\s+/g,'\x20')['trim']()||'',{performance_target:_0x20646b,passing_score:_0x10f6c3}=performaceTarget(_0x416095);_0x3a9bce['ilo']['push']({'statement':_0x569b62,'verb':_0x569b62['split'](/\s+/)[0x0]??'','assessment_tool':_0x3eb01e,'performance_target':_0x20646b,'passing_score':_0x10f6c3});}}),_0x3a9bce&&_0x208827['COAEP']['co']['push'](_0x3a9bce),_0x208827;}
|
|
17
|
+
|
|
18
|
+
async function uploadCOAEP(_0x5cd3f0,_0x1413b9,_0x1b884e){try{const _0x1fb723=await convertToCSVFile(_0x1413b9),_0x1ea0fc=await _0x1fb723['text'](),_0x1b28f6=parseCOAEP(_0x1ea0fc),_0x1b172d=await fetch(_0x5cd3f0+'/coaeps/upload?course_id='+_0x1b884e,{'method':'POST','headers':{'Content-Type':'application/json'},'body':JSON['stringify'](_0x1b28f6)});if(!_0x1b172d['ok']){const _0x27a797=await _0x1b172d['json']();throw _0x27a797;}return _0x1b172d['json']();}catch(_0x581be8){throw _0x581be8;}}
|
|
19
|
+
|
|
20
|
+
async function uploadEnrolledStudent(_0x3b177a,_0x3cc3af){try{const _0xa893ff=await convertToCSVFile(_0x3cc3af),_0x5e1d38=new FormData();_0x5e1d38['append']('csvFile',_0xa893ff);const _0x4d8c62=await fetch(_0x3b177a+'/enrolled-students/upload',{'method':'POST','body':_0x5e1d38});if(!_0x4d8c62['ok']){const _0x557d77=await _0x4d8c62['json']();throw _0x557d77;}return _0x4d8c62['json']();}catch(_0x2eca2e){throw _0x2eca2e;}}
|
|
21
|
+
|
|
22
|
+
function parseClassList(_0x532f23){const _0x2e6446=_0x1ec977['parse'](_0x532f23,{'skipEmptyLines':!![]})['data'];let _0x1eed58='',_0x2e1d64='',_0x48e257='';const _0x4fd6dc=[];return _0x2e6446['forEach'](_0x3e15ab=>{const _0x4da2dd=_0x3e15ab['map'](_0x58e655=>(_0x58e655??'')['toString']()['trim']()),_0x26c150=_0x4da2dd[0x0]??'';if(_0x26c150['startsWith']('Course\x20No:')){const _0x389546=_0x26c150['replace']('Course\x20No:','')['trim'](),_0x326c25=_0x389546['split'](/\s+/);_0x48e257=_0x326c25[0x0]??'';const [_0xd30e0c,_0xaf4d0e]=(_0x326c25[0x1]??'')['split']('-');_0x2e1d64=_0xd30e0c??'';const _0x2db8c2=(_0xaf4d0e??'')['match'](/[a-z]$/);_0x1eed58=_0x2db8c2?_0x2db8c2[0x0]:'';}if(/^\d+$/['test'](_0x26c150)){const _0x6776d6=_0x4da2dd[0x2]??'';_0x4fd6dc['push']({'subj_code':_0x48e257,'student_no':_0x6776d6,'course_id':_0x2e1d64,'section':_0x1eed58});}}),{'enrolledCourses':_0x4fd6dc};}
|
|
23
|
+
|
|
24
|
+
async function uploadClassList(_0x37d786,_0x2a2d1d,_0x2c9814,_0x11255f){try{const _0x34c93f=await convertToCSVFile(_0x2a2d1d),_0x3ddefd=await _0x34c93f['text'](),_0x53eaaa=parseClassList(_0x3ddefd),_0x1b1dbe='subj_code='+_0x2c9814+'&period_id='+_0x11255f,_0x5b218b=await fetch(_0x37d786+'/enrolled-courses/upload?'+_0x1b1dbe,{'method':'POST','headers':{'Content-Type':'application/json'},'body':JSON['stringify'](_0x53eaaa)});if(!_0x5b218b['ok']){const _0x21e8a6=await _0x5b218b['json']();throw _0x21e8a6;}return _0x5b218b['json']();}catch(_0x823b59){throw _0x823b59;}}
|
|
25
|
+
|
|
26
|
+
function parseAssessmentCsv(_0x1f561f){const {data:_0x139037}=_0x1ec977['parse'](_0x1f561f,{'skipEmptyLines':!![]}),_0x1cbed5=_0x139037['filter'](_0x5da998=>_0x5da998['length']>0x0),_0x521524=_0x1cbed5['find'](_0x15608a=>_0x15608a['some'](_0xee86dd=>_0xee86dd?.['includes']('Faculty'))),_0x4afa7f=_0x521524?_0x521524['findIndex'](_0x4c234f=>_0x4c234f?.['includes']('Faculty')):-1,_0x4a00a2=_0x4afa7f!==-1&&_0x521524?_0x521524[_0x4afa7f+0x2]?.['replace'](/"/g,'')['trim']()??'':'',_0x3a36c3=_0x1cbed5['find'](_0x37701f=>_0x37701f['some'](_0x6511f1=>_0x6511f1?.['includes']('Semester'))),_0x2a9d8b=_0x3a36c3?_0x3a36c3['findIndex'](_0x26c52f=>_0x26c52f?.['includes']('Semester')):-1,_0x4bdf4f=_0x2a9d8b!==-1&&_0x3a36c3?_0x3a36c3[_0x2a9d8b+0x2]?.['trim']()??'':'',_0x3eefd7=_0x4bdf4f['includes']('1st')?0x1:_0x4bdf4f['includes']('2nd')?0x2:0x0,_0x427219=_0x1cbed5['find'](_0x21796f=>_0x21796f['some'](_0x49ff80=>_0x49ff80?.['includes']('Course\x20&\x20Sec'))),_0x5b4c5f=_0x427219?_0x427219['findIndex'](_0x3d69c0=>_0x3d69c0?.['includes']('Course\x20&\x20Sec')):-1,_0x1ceca6=_0x5b4c5f!==-1&&_0x427219?_0x427219[_0x5b4c5f+0x2]?.['trim']()??'':'';let _0x5442ef='',_0x212197='';if(_0x1ceca6){const _0x50795e=_0x1ceca6['match'](/^([A-Za-z0-9]+)-?([A-Za-z]+)?/);_0x50795e&&(_0x5442ef=_0x50795e[0x1]??'',_0x50795e[0x2]&&(_0x212197=_0x50795e[0x2]['replace'](/^OC/i,'')));}const _0x31a231=_0x1cbed5['find'](_0x3984a1=>_0x3984a1['some'](_0xd83812=>_0xd83812?.['includes']('School\x20Year'))),_0x5a1d15=_0x31a231?_0x31a231['findIndex'](_0x9f6ee0=>_0x9f6ee0?.['includes']('School\x20Year')):-1,_0x3ec38f=_0x5a1d15!==-1&&_0x31a231?_0x31a231[_0x5a1d15+0x2]?.['trim']()??'':'';let _0x3e8d79=0x0;if(_0x3ec38f){const _0x1ad27d=_0x3ec38f['match'](/(\d{4})-(\d{4})/);if(_0x1ad27d){const _0x5d3e4f=(_0x1ad27d[0x1]??'')['slice'](0x2),_0x3d5b78=(_0x1ad27d[0x2]??'')['slice'](0x2);_0x3e8d79=parseInt(_0x5d3e4f+_0x3d5b78,0xa);}}const _0x441762={'faculty':_0x4a00a2,'course':_0x5442ef,'section':_0x212197,'semester':_0x3eefd7,'sy':_0x3e8d79},_0x5344a9=_0x1cbed5['findIndex'](_0xbf2299=>_0xbf2299['some'](_0xdee8ed=>_0xdee8ed?.['trim']()==='CO\x20#'));if(_0x5344a9===-1)throw new Error('CO\x20header\x20row\x20not\x20found\x20in\x20CSV');const _0x2e2492=_0x1cbed5[_0x5344a9+0x1];if(!_0x2e2492)throw new Error('ILO\x20header\x20row\x20not\x20found\x20in\x20CSV');const _0x49c779={};let _0x5303a7=0x1,_0x47361f=0x1;for(let _0x33ad10=0x3;_0x33ad10<_0x2e2492['length'];_0x33ad10++){const _0x14e2e1=_0x2e2492[_0x33ad10];if(!_0x14e2e1)continue;const _0x32bf22='co'+_0x5303a7;if(!_0x49c779[_0x32bf22])_0x49c779[_0x32bf22]=[];_0x49c779[_0x32bf22]['push']('ilo'+_0x47361f),_0x47361f++,_0x47361f>0x3&&(_0x5303a7++,_0x47361f=0x1);}const _0x416559=_0x1cbed5['findIndex'](_0x5c425e=>_0x5c425e['includes']('Name\x20of\x20Students'));if(_0x416559===-1)throw new Error('Student\x20header\x20row\x20not\x20found\x20in\x20CSV');const _0x566cdc=_0x1cbed5[_0x416559];if(!_0x566cdc)throw new Error('Student\x20header\x20row\x20is\x20missing');const _0x293c5f=_0x566cdc['findIndex'](_0x52ec58=>_0x52ec58?.['includes']('Name\x20of\x20Students'));if(_0x293c5f===-1)throw new Error('Name\x20of\x20Students\x20column\x20not\x20found\x20in\x20CSV');const _0xa24edb=_0x293c5f+0x2,_0x35243a=[];for(let _0x3ff248=_0x416559+0x1;_0x3ff248<_0x1cbed5['length'];_0x3ff248++){const _0x597023=_0x1cbed5[_0x3ff248];if(!_0x597023)continue;if(_0x597023['some'](_0x193295=>_0x193295?.['toUpperCase']()['includes']('TOTAL\x20STUDENTS')||_0x193295?.['toUpperCase']()['includes']('ACHIEVED\x20THE\x20MINIMUM')||_0x193295?.['toUpperCase']()['includes']('INACTIVE')||_0x193295?.['toUpperCase']()['includes']('AVERAGE')))continue;if(!_0x597023[_0x293c5f])continue;const _0x5af3ef=_0x597023[_0x293c5f]['replace'](/"/g,'')['trim'](),_0xd5834b=_0x597023['slice'](_0xa24edb)['map'](_0x1f7be8=>_0x1f7be8===null?null:!isNaN(Number(_0x1f7be8))?parseFloat(_0x1f7be8):0x0);let _0x44ab17=0x0;const _0x350fde={};Object['entries'](_0x49c779)['forEach'](([_0x50daf5,_0x20d3cd])=>{const _0x1545bd={};_0x20d3cd['forEach'](_0x5edc62=>{_0x1545bd[_0x5edc62]=_0xd5834b[_0x44ab17]??0x0,_0x44ab17++;}),_0x350fde[_0x50daf5]={'transmuted_score':_0x1545bd};}),_0x35243a['push']({'student_name':_0x5af3ef,'coaep':_0x350fde});}const _0x4ebd4a=_0x1cbed5['find'](_0x4e79eb=>_0x4e79eb['some'](_0x28715a=>_0x28715a?.['includes']('ACHIEVED\x20THE\x20MINIMUM'))),_0x572ca1=_0x1cbed5['find'](_0xfa41d4=>_0xfa41d4['some'](_0x42580a=>_0x42580a?.['includes']('AVERAGE'))),_0x4e3a74=_0x4ebd4a?_0x4ebd4a['slice'](_0xa24edb)['map'](_0x31dbc8=>_0x31dbc8&&!isNaN(Number(_0x31dbc8))?parseInt(_0x31dbc8):0x0):[],_0x298218=_0x572ca1?_0x572ca1['slice'](_0xa24edb)['map'](_0x254bfd=>_0x254bfd&&_0x254bfd!=='#DIV/0!'&&!isNaN(Number(_0x254bfd))?parseInt(_0x254bfd):0x0):[],_0x40e5f9={};let _0x2e0295=0x0;return Object['entries'](_0x49c779)['forEach'](([_0x412c98,_0xd4ce86])=>{if(!_0x40e5f9[_0x412c98])_0x40e5f9[_0x412c98]={};_0xd4ce86['forEach'](_0x24e736=>{_0x40e5f9[_0x412c98][_0x24e736]={'achievedMinimum':_0x4e3a74[_0x2e0295]??0x0,'average':_0x298218[_0x2e0295]??0x0},_0x2e0295++;});}),{'assessmentData':{'classAssignment':_0x441762,'student':_0x35243a,'total':_0x40e5f9}};}
|
|
27
|
+
|
|
28
|
+
async function uploadAssessmentData(_0x1af8cc,_0x525b96){try{const _0x4f5e28=await convertToCSVFile(_0x525b96),_0x101d3c=await _0x4f5e28['text'](),_0x3f16d6=parseAssessmentCsv(_0x101d3c),_0x4491ca=await fetch(_0x1af8cc+'/assessment-data/upload',{'method':'POST','headers':{'Content-Type':'application/json'},'body':JSON['stringify'](_0x3f16d6)});if(!_0x4491ca['ok']){const _0x398a47=await _0x4491ca['json']();throw _0x398a47;}return _0x4491ca['json']();}catch(_0x48f55a){throw _0x48f55a;}}
|
|
29
|
+
|
|
30
|
+
class Client{['BASE_URL'];constructor(_0x269653){this['BASE_URL']=_0x269653;}['Parser'](){return {'curriculum':async _0x50aeaa=>{const _0x89b877=await uploadCurriculum(this['BASE_URL'],_0x50aeaa);return _0x89b877;},'courseOffering':async _0x88466c=>{const _0x1b707c=await uploadCourseOffering(this['BASE_URL'],_0x88466c);return _0x1b707c;},'coaep':async(_0x2565e2,_0x2e53db)=>{const _0x4bff7d=await uploadCOAEP(this['BASE_URL'],_0x2565e2,_0x2e53db);return _0x4bff7d;},'enrolledStudent':async _0x52d011=>{const _0x133fd9=await uploadEnrolledStudent(this['BASE_URL'],_0x52d011);return _0x133fd9;},'classlist':async(_0x340979,_0x20e7d2,_0x1c4b49)=>{const _0x5d8fc6=await uploadClassList(this['BASE_URL'],_0x340979,_0x20e7d2,_0x1c4b49);return _0x5d8fc6;},'assessmentData':async _0x4db1fb=>{const _0xbbd613=await uploadAssessmentData(this['BASE_URL'],_0x4db1fb);return _0xbbd613;}};}}
|
|
31
|
+
|
|
32
|
+
export { Client as default };
|
package/main.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
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: (xls: File, subj_code: number, period_id: number) => Promise<Record<string, unknown>>;
|
|
20
|
+
assessmentData: (xls: File) => Promise<Record<string, unknown>>;
|
|
21
|
+
};
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obe-loms/coms-parser",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"license": "ISC",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"papaparse": "^5.5.3",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"ts-node": "^10.9.2",
|
|
18
18
|
"typescript": "^5.9.2"
|
|
19
19
|
},
|
|
20
|
-
"main": "./
|
|
20
|
+
"main": "./bundle.js",
|
|
21
|
+
"types": "./main.d.ts",
|
|
21
22
|
"publishConfig": {
|
|
22
23
|
"access": "public"
|
|
23
24
|
}
|
package/parser/xls.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function convertToCSVFile(xls: File): Promise<File>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function uploadAssessmentData(url: string, xls: File): Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function uploadCOAEP(url: string, xls: File, course_id: string): Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function uploadClassList(url: string, xls: File, subj_code: number, period_id: number): Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function uploadCourseOffering(url: string, xls: File): Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function uploadCurriculum(url: string, xls: File): Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function uploadEnrolledStudent(url: string, xls: File): Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type TransmutedScore = Record<string, number | null>;
|
|
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/coaep.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
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/helper/matchTarget.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
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
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/index.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
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/parser/assessmentdata.js
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
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
|
-
}
|
package/parser/classList.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
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
|
-
}
|
package/parser/courseOffering.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
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
|
-
}
|
package/parser/curriculum.js
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
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
|
-
}
|
package/relay/uploadCOAEP.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
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
|
-
}
|
package/relay/uploadClassList.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
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
|
-
}
|
package/types/assessmentdata.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/types/classList.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/types/coaep.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/types/courseOffering.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/types/curriculum.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|