Compare commits

..

11 Commits

Author SHA1 Message Date
bdaneels
61cc64742f add updateResultsDatabase functionality and results.json for storing course results 2025-04-15 16:22:43 +02:00
bdaneels
df67c3c2c5 add updateResultsDatabase functionality and results.json for storing course results 2025-04-14 15:43:25 +02:00
bdaneels
8c5dc7db04 adding coursesEnrolled.js as a functionality to check what courses have been taken up. 2025-04-10 16:50:17 +02:00
bdaneels
5cf306a56e adding coursesEnrolled.js as a functionality to check what courses have been taken up. 2025-04-10 16:48:13 +02:00
bdaneels
45023185a1 adding coursesEnrolled.js as a functionality to check what courses have been taken up. 2025-03-24 16:36:07 +01:00
bdaneels
1f5fcbe3c8 Second Beta Version complete
Enhanced VZP checking
2025-02-20 16:58:39 +01:00
bdaneels
47c4afa99e removed files from the remote 2024-12-03 16:43:00 +01:00
bdaneels
0e275a5bc6 First Beta Version complete
Enhance logging with student details in evaluation

Updated `iterateOverDashboardTable.js` to include student name and ID in log output. Added functions in `evaluateStartPakket.js` to fetch student name and ID from specified selectors. Adjusted `.gitignore` to exclude `.idea` directory.
2024-12-03 16:39:11 +01:00
bdaneels
6c7aa018cd Enhance logging with student details in evaluation
Updated `iterateOverDashboardTable.js` to include student name and ID in log output. Added functions in `evaluateStartPakket.js` to fetch student name and ID from specified selectors. Adjusted `.gitignore` to exclude `.idea` directory.
2024-12-03 15:16:45 +01:00
bdaneels
05a1b85801 Enhance logging with student details in evaluation
Updated `iterateOverDashboardTable.js` to include student name and ID in log output. Added functions in `evaluateStartPakket.js` to fetch student name and ID from specified selectors. Adjusted `.gitignore` to exclude `.idea` directory.
2024-12-03 14:16:44 +01:00
bdaneels
3b4ccefa66 Enhance logging with student details in evaluation
Updated `iterateOverDashboardTable.js` to include student name and ID in log output. Added functions in `evaluateStartPakket.js` to fetch student name and ID from specified selectors. Adjusted `.gitignore` to exclude `.idea` directory.
2024-11-27 16:39:20 +01:00
21 changed files with 706 additions and 87 deletions

3
.gitignore vendored
View File

@@ -1,2 +1,5 @@
node_modules
vars.js
.idea
*.xlsx
utils/results.json

5
.idea/.gitignore generated vendored
View File

@@ -1,5 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

1
.idea/.name generated
View File

@@ -1 +0,0 @@
index.js

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/sisa_crawl.iml" filepath="$PROJECT_DIR$/.idea/sisa_crawl.iml" />
</modules>
</component>
</project>

12
.idea/sisa_crawl.iml generated
View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

35
appendResultsToExcel.js Normal file
View File

@@ -0,0 +1,35 @@
const xlsx = require("xlsx");
const fs = require("fs");
function appendToExcel(newResult, filename) {
let workbook;
// Load existing file if it exists
if (fs.existsSync(filename)) {
workbook = xlsx.readFile(filename);
} else {
workbook = xlsx.utils.book_new();
}
const sheetName = "Results";
let worksheet = workbook.Sheets[sheetName];
// If the worksheet doesn't exist, create it
if (!worksheet) {
worksheet = xlsx.utils.json_to_sheet([]);
xlsx.utils.book_append_sheet(workbook, worksheet, sheetName);
}
// Get existing data from the worksheet
const data = xlsx.utils.sheet_to_json(worksheet);
data.push(newResult); // Add new result
// Update worksheet with new data
const updatedWorksheet = xlsx.utils.json_to_sheet(data);
workbook.Sheets[sheetName] = updatedWorksheet;
// Write updated workbook to file
xlsx.writeFile(workbook, filename);
}
module.exports = appendToExcel;

13
config.js Normal file
View File

@@ -0,0 +1,13 @@
module.exports = {
excelFilename: "DashboardResults.xlsx",
//Selectors for the dashboard page
tableBodySelector: "#QQ_RPT_OIS_TEMP\\$scroll\\$0 tbody",
iframeSelector: 'iframe[title="Hoofdinhoud"]',
//Selectors for the AA-page
uitvouwenSelector: 'input[id="DERIVED_SAA_DPR_SSS_EXPAND_ALL"]',
collapsArrowSelector:'a.PSHYPERLINK.PTCOLLAPSE_ARROW',
excludeFromCollapsingSelector: 'a[title="Sectie samenvouwen AFSTUDEERVEREISTEN BACHELOR GESCHIEDENIS"]',
excludedTitle: 'Sectie samenvouwen AFSTUDEERVEREISTEN BACHELOR GESCHIEDENIS',
}

108
coursesEnrolled.js Normal file
View File

@@ -0,0 +1,108 @@
const puppeteer = require('puppeteer');
const IFRAME_SELECTOR = 'iframe[title="Hoofdinhoud"]';
const wait = require("./wait");
const config = require("./config.js");
//Er zijn een aantal helperfuncties die nog verwijderd moeten worden
//zo is de functie van de contentFrame te verwijderen want staat dubbel in evaluatestartpakket.js
//de iframeselector is eveneens van belang om te verwijderen want staat ook dubbel in evaluatestartpakket.js
async function coursesEnrolled(page) {
/*connection to local host
const browser = await puppeteer.connect({
browserURL: "http://localhost:9222", // Connect to the browser's debugging address
});
// Get all open pages (tabs)
const pages = await browser.pages();
console.log(`Found ${pages.length} open pages on the browser.`);
// Interact with the last tab (or any tab of choice)
let page = pages[pages.length - 1]; // Choose the last opened tab
console.log("Current URL:", page.url()); */
let contentFrame= await getContentFrame(page);
const uitvouwenButton = await contentFrame.$(config.uitvouwenSelector);
if (uitvouwenButton) {
await uitvouwenButton.click();
console.log("uitvouwen button clicked");
await wait(2000);
contentFrame= await getContentFrame(page)
}
//logic to collapse all sections except the one with the excluded title
const collapseArrows = await contentFrame.$$(config.collapsArrowSelector);
const excludedArrow = await contentFrame.$(config.excludeFromCollapsingSelector);
const excludedTbody = await excludedArrow.evaluate(el => el.closest('tbody'));
for (const arrow of collapseArrows) {
const isExcluded = await arrow.evaluate((el, excludedTbody) => {
const title = el.getAttribute('title');
const tbody = el.closest('tbody');
return title === 'Sectie samenvouwen AFSTUDEERVEREISTEN BACHELOR GESCHIEDENIS' || tbody === excludedTbody;
}, excludedTbody);
if (!isExcluded) {
const isStillInDOM = await arrow.evaluate(el => document.body.contains(el));
if (isStillInDOM) {
await arrow.click();
await wait(500); // Adjust the wait time as needed
}
}
}
contentFrame= await getContentFrame(page)
const rowData = await contentFrame.$$eval(
'span',
(spans) => {
const uniqueEntries = new Set();
return spans
.filter((span) => span.innerText.trim().includes('Academiejaar'))
.map((span) => {
const tr = span.closest('tr');
if (!tr) return null;
const tds = tr.querySelectorAll('td');
const getInnerHtml = (element) => {
const aElement = element.querySelector('a');
return aElement ? aElement.innerHTML.trim() : element.innerHTML.trim();
};
const studiegidsNummer = tds[0] ? getInnerHtml(tds[0].querySelector('span')) : '';
const opleidingsOnderdeel = tds[1] ? getInnerHtml(tds[1].querySelector('span')) : '';
const studiepunten = tds[2] ? getInnerHtml(tds[2].querySelector('span')) : '';
if (uniqueEntries.has(studiegidsNummer)) return null;
uniqueEntries.add(studiegidsNummer);
return {
studiegidsNummer,
opleidingsOnderdeel,
studiepunten,
};
})
.filter((entry) => entry);
}
);
const totalStudiepunten = sumStudiepunten(rowData);
return {rowData, totalStudiepunten};
}
function sumStudiepunten(rowData) {
return rowData.reduce((total, row) => {
const studiepunten = parseFloat(row.studiepunten) || 0;
return total + studiepunten;
}, 0);
}
async function getContentFrame(page) {
await page.waitForSelector(IFRAME_SELECTOR);
const iframe = await page.$(IFRAME_SELECTOR);
if (!iframe) {
throw new Error("Could not find iframe on the AA-page");
}
console.log("iframe found on AA-page");
return await iframe.contentFrame();
}
module.exports = coursesEnrolled;

View File

@@ -1,6 +1,13 @@
const isPromise = require("./ispromise")
const IFRAME_SELECTOR = 'iframe[title="Hoofdinhoud"]';
const CELL_SELECTOR =
'a[title="Sectie uitvouwen Algemene opleidingsonderdelen"]';
'a[title="Sectie uitvouwen Algemene opleidingsonderdelen"]';
const CELL_SELECTOR_OPEN = "a[title='Sectie samenvouwen Algemene opleidingsonderdelen']";
const STUDENT_NAME_CELL_SELECTOR = 'span[id="DERIVED_SCC_SUM_PERSON_NAME$5$"]';
const STUDENT_ID_CELL_SELECTOR = 'span[id="SCC_PERS_SA_VW_EMPLID"]';
const STPKT_KEUZE_CELL_SELECTOR = 'a[title="Sectie uitvouwen Keuzeopleidingsonderdelen"]';
const STPKT_KEUZE_CELL_SELECTOR_OPEN = 'a[title="Sectie samenvouwen Keuzeopleidingsonderdelen"]'
/**
* Extracted function to get the text content of a node.
@@ -35,22 +42,49 @@ async function getContentFrame(page) {
*/
async function isStartPakketAvailable(page) {
const contentFrame = await getContentFrame(page);
await contentFrame.waitForSelector(CELL_SELECTOR);
const cell = await contentFrame.$(CELL_SELECTOR);
let cell
let isCollapsed_main_before_function = true
try {
await contentFrame.waitForSelector(CELL_SELECTOR, { timeout: 5000 }); // Adjust timeout as needed
cell = await contentFrame.$(CELL_SELECTOR);
} catch (error) {
console.warn("CELL_SELECTOR not found, trying CELL_SELECTOR_OPEN");
await contentFrame.waitForSelector(CELL_SELECTOR_OPEN, { timeout: 5000 }); // Adjust timeout as needed
cell = await contentFrame.$(CELL_SELECTOR_OPEN);
isCollapsed_main_before_function = false
}
if (!cell) {
let cell_keuze = await contentFrame.$(STPKT_KEUZE_CELL_SELECTOR)
if (!cell_keuze) {
cell_keuze = contentFrame.$(STPKT_KEUZE_CELL_SELECTOR_OPEN)
}
if (!cell ) {
throw new Error(
"Cell inside function isStartPakketAvailable is not defined"
);
}
const isCollapsed = await isAriaExpandedFalse(cell);
console.log(`Aria-expanded: ${isCollapsed}`);
//object vars
const isCollapsed_main = isCollapsed_main_before_function ? await isAriaExpandedFalse(cell) : isCollapsed_main_before_function;
const isCollapsed_keuze = await getIsCollapsedKeuze(cell_keuze);
const isCollapsed = isCollapsed_main && isCollapsed_keuze;
const studName = await getStudName(contentFrame);
const studId = await getStudId(contentFrame);
const containsVZP = await hasVZP(cell)
const containsVZP_keuze = await hasVZP(cell_keuze)
return {
isCollapsed: isCollapsed,
// Add more properties here in the future as needed
isCollapsed_main: isCollapsed_main,
isCollapsed_keuze: isCollapsed_keuze,
studName: studName,
studId: studId,
containsVZP: containsVZP,
containsVZP_keuze: containsVZP_keuze,
// more properties here
};
}
@@ -61,7 +95,7 @@ async function isStartPakketAvailable(page) {
* @returns {Promise<boolean>} True if the `aria-expanded` attribute is 'false', false otherwise.
*/
async function isAriaExpandedFalse(node) {
if (!node) {
if (isPromise(node)) {
throw new Error("Node is not defined");
}
return await node.evaluate(
@@ -69,4 +103,48 @@ async function isAriaExpandedFalse(node) {
);
}
async function getIsCollapsedKeuze(cell_keuze) {
if (!isPromise(cell_keuze)) {
return await isAriaExpandedFalse(cell_keuze);
} else {
return false;
}
}
async function getStudName(frame) {
const cell = await frame.$(STUDENT_NAME_CELL_SELECTOR);
if (!cell) {
throw new Error("Cell student name is not defined");
}
return await getNodeTextContent(cell);
}
async function getStudId(frame) {
const cell = await frame.$(STUDENT_ID_CELL_SELECTOR);
if (!cell) {
throw new Error("Cell student id is not defined");
}
return await getNodeTextContent(cell);
}
/**
* Checks if the closest parent of the given node contains the 'VZP' string.
*
* @param {ElementHandle} node - The node to find the closest parent of.
* @returns {Promise<boolean>} True if the closest parent contains 'VZP', false otherwise.
*/
async function hasVZP(node) {
if (isPromise(node) ){
return false;
}
return await node.evaluate((element) => {
let parent = element.closest('table');
if (parent) {
return parent.textContent.includes('VZP')
;
}
return false;
});
}
module.exports = isStartPakketAvailable;

6
ispromise.js Normal file
View File

@@ -0,0 +1,6 @@
function isPromise(obj) {
return obj && typeof obj.then === 'function';
}
module.exports = isPromise;

View File

@@ -2,17 +2,30 @@
open chrome in debug modus
start chrome --remote-debugging-port=9222 --user-data-dir="C:\ChromeDebug"
navigeer naar het dashboard en roep de lijst met startpakket studenten op die relevant zijn voor de test
wees er zeker van dat de tab waarin je moet werken de meest rechtse tab is in de tabbladenbalk
start dan het script
*/
const puppeteer = require("puppeteer");
const isStartPakketAvailable = require("./evaluateStartPakket");
const fs = require("fs");
const saveResultsToExcel = require("./saveResultsToExcel");
const appendToExcel = require("./appendResultsToExcel");
const wait = require("./wait");
const courseEnrolled = require("./coursesEnrolled");
const parseCourseResults = require('./utils/parseCourseResults');
const config = require("./config.js");
const updateResultsDatabase = require("./utils/updateResultsDatabase");
async function iterateOverDashboardTable() {
/*connection to local host */
const browser = await puppeteer.connect({
browserURL: "http://localhost:9222", // Connect to the browser's debugging address
browserURL: "http://localhost:9222"
});
//array to store results for Excel export
let results = [];
const filename = "DashboardResults.xlsx";
// Get all open pages (tabs)
const pages = await browser.pages();
console.log(`Found ${pages.length} open pages on the browser.`);
@@ -23,7 +36,7 @@ async function iterateOverDashboardTable() {
// Select the table body by ID
const iframeElement = await page.waitForSelector(
'iframe[title="Hoofdinhoud"]'
config.iframeSelector
);
const iframe = await iframeElement.contentFrame();
@@ -32,11 +45,8 @@ async function iterateOverDashboardTable() {
return;
}
// Select the table body within the iframe
const tableBodySelector = "#QQ_RPT_OIS_TEMP\\$scroll\\$0 tbody";
// Check if the table exists inside the iframe
const tableExists = await iframe.$(tableBodySelector);
const tableExists = await iframe.$(config.tableBodySelector);
if (!tableExists) {
console.log("Table not found inside iframe!");
return;
@@ -45,21 +55,46 @@ async function iterateOverDashboardTable() {
// Get all rows within the table body
const links = await iframe.$$(
`${tableBodySelector} tr span[title="AA-rapport"] a`
`${config.tableBodySelector} tr span[title="AA-rapport"] a`
);
console.log(`Found ${links.length} AA-links to process.`);
// Initialize Excel file if it doesn't exist
if (!fs.existsSync(filename)) {
saveResultsToExcel([], filename); // Create empty file
console.log(`Initialized new Excel file: ${filename}`);
}
// process links
for (let i = 0; i < links.length; i++) {
console.log(`Processing link ${i + 1}`);
const iframeElement = await page.waitForSelector(
'iframe[title="Hoofdinhoud"]'
config.iframeSelector
);
const iframe = await iframeElement.contentFrame();
const links = await iframe.$$(
`${tableBodySelector} tr span[title="AA-rapport"] a`
`${config.tableBodySelector} tr span[title="AA-rapport"] a`
);
// Get the parent row of the current link
const parentRow = await links[i].evaluateHandle((link) =>
link.closest("tr")
);
const rowContainsBeëindigd = await parentRow.evaluate((row) =>
row.innerText.includes("Beëindigd")
);
if (rowContainsBeëindigd) {
console.log(`Skipping link ${i + 1} as the row contains 'Beëindigd'`);
continue;
}
if ((i + 1) % 10 === 0) {
console.log(
"Simulating break, waiting 10 seconds to stay under the radar :)"
);
await wait(10000);
}
const [newPagePromise] = await Promise.all([
new Promise((resolve) =>
@@ -70,24 +105,55 @@ async function iterateOverDashboardTable() {
),
links[i].click(), // Simulate the click
]);
let result;
const newPage = await newPagePromise;
try {
const evaluationResult = await isStartPakketAvailable(newPage);
const coursesResult = await courseEnrolled(newPage)
if (evaluationResult.isCollapsed) {
console.log(`Evaluation succeeded for link ${i + 1}`);
} else {
console.log(`Evaluation failed for link ${i + 1}`);
}
//Save results for Excel
result = {
LinkNumber: i + 1,
StudentName: evaluationResult.studName || "N/A",
StudentID: evaluationResult.studId || "N/A",
IsCollapsed: evaluationResult.isCollapsed ? "Yes" : "No",
IsCollapsedKeuze: evaluationResult.isCollapsed_keuze ? "Yes" : "No",
IsCollapsedMain: evaluationResult.isCollapsed_main ? "Yes" : "No",
ContainsVZP: evaluationResult.containsVZP ? "Yes" : "No",
ContainsVZPKeuze: evaluationResult.containsVZP_keuze ? "Yes" : "No",
coursesResult: parseCourseResults(coursesResult.rowData),
totalStudiepunten: coursesResult.totalStudiepunten
};
console.log("Courses enrolled: ", coursesResult.rowData);
console.log(`Link ${i + 1} processed successfully.`);
} catch (error) {
console.error(`Error processing link ${i + 1}:`, error.message);
// Save error for Excel
result = {
LinkNumber: i + 1,
StudentName: "Error",
StudentID: "Error",
IsCollapsed: "Error",
IsCollapsedKeuze: "Error",
IsCollapsedMain: "Error",
ContainsVZP: "Error",
ContainsVZPKeuze: "Error",
ErrorStr: error.message,
};
} finally {
await newPage.close();
}
await newPage.close();
results.push(result);
appendToExcel(result, filename);
updateResultsDatabase(result)
}
console.log("All links processed.");
saveResultsToExcel(results, config.excelFilename);
console.log("Results saved successfully to DashboardResults.xlsx");
}
module.exports = iterateOverDashboardTable();

106
package-lock.json generated
View File

@@ -9,7 +9,8 @@
"version": "1.0.0",
"dependencies": {
"inquirer": "^12.1.0",
"puppeteer": "^23.7.0"
"puppeteer": "^23.7.0",
"xlsx": "^0.18.5"
}
},
"node_modules/@babel/code-frame": {
@@ -333,6 +334,15 @@
"@types/node": "*"
}
},
"node_modules/adler-32": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
"integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/agent-base": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
@@ -525,6 +535,19 @@
"node": ">=6"
}
},
"node_modules/cfb": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
"integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
"license": "Apache-2.0",
"dependencies": {
"adler-32": "~1.3.0",
"crc-32": "~1.2.0"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/chardet": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
@@ -568,6 +591,15 @@
"node": ">=12"
}
},
"node_modules/codepage": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz",
"integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -612,6 +644,18 @@
}
}
},
"node_modules/crc-32": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
"license": "Apache-2.0",
"bin": {
"crc32": "bin/crc32.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/data-uri-to-buffer": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
@@ -801,6 +845,15 @@
"pend": "~1.2.0"
}
},
"node_modules/frac": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
"integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/fs-extra": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
@@ -1370,6 +1423,18 @@
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
"license": "BSD-3-Clause"
},
"node_modules/ssf": {
"version": "0.11.2",
"resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
"integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
"license": "Apache-2.0",
"dependencies": {
"frac": "~1.1.2"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/streamx": {
"version": "2.20.1",
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.1.tgz",
@@ -1514,6 +1579,24 @@
"integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==",
"license": "MIT"
},
"node_modules/wmf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
"integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/word": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz",
"integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
@@ -1558,6 +1641,27 @@
}
}
},
"node_modules/xlsx": {
"version": "0.18.5",
"resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz",
"integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
"license": "Apache-2.0",
"dependencies": {
"adler-32": "~1.3.0",
"cfb": "~1.2.1",
"codepage": "~1.15.0",
"crc-32": "~1.2.1",
"ssf": "~0.11.2",
"wmf": "~1.0.1",
"word": "~0.3.0"
},
"bin": {
"xlsx": "bin/xlsx.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",

View File

@@ -9,6 +9,7 @@
"private": true,
"dependencies": {
"inquirer": "^12.1.0",
"puppeteer": "^23.7.0"
"puppeteer": "^23.7.0",
"xlsx": "^0.18.5"
}
}

32
saveResultsToExcel.js Normal file
View File

@@ -0,0 +1,32 @@
const xlsx = require("xlsx");
function saveResultsToExcel(data, filename) {
const workbook = xlsx.utils.book_new(); // Create a new workbook
const worksheetData = [];
data.forEach(item => {
const courses = item.coursesResult.split('. ').filter(course => course.trim() !== '');
courses.forEach(course => {
worksheetData.push({
LinkNumber: item.LinkNumber,
StudentName: item.StudentName,
StudentID: item.StudentID,
IsCollapsed: item.IsCollapsed,
IsCollapsedKeuze: item.IsCollapsedKeuze,
IsCollapsedMain: item.IsCollapsedMain,
ContainsVZP: item.ContainsVZP,
ContainsVZPKeuze: item.ContainsVZPKeuze,
Course: course.trim(),
TotalStudiepunten: item.totalStudiepunten
});
});
});
const worksheet = xlsx.utils.json_to_sheet(worksheetData); // Convert data to worksheet
xlsx.utils.book_append_sheet(workbook, worksheet, "Results"); // Add worksheet to workbook
// Write workbook to file
xlsx.writeFile(workbook, filename);
}
module.exports = saveResultsToExcel;

7
todo.md Normal file
View File

@@ -0,0 +1,7 @@
# TODO
## High Priority
- [ ] adviesrapport geeft geen buizen weer voor het huidige aj. Vakken verschijnen dan ook niet in de functie
coursesenrolled. Hoe oplossen? Rapport deliberatie?
- dit is eig geen probleem voor het begin van het aj wanneer nog geen examenperiode heeft
plaatsgevonden.

View File

@@ -0,0 +1,13 @@
const parseCourseResults = (listOfObj) => {
result = listOfObj.map(obj => {
const studiegidsNummer = obj.studiegidsNummer.slice(-10);
return `${studiegidsNummer} ${obj.opleidingsOnderdeel} - ${obj.studiepunten}SP, `;
});
return result.join("\n");
}
module.exports = parseCourseResults;

169
utils/results.json Normal file
View File

@@ -0,0 +1,169 @@
[
{
"LinkNumber": 1,
"StudentName": "William Van Dessel",
"StudentID": "20001044",
"IsCollapsed": "Yes",
"IsCollapsedKeuze": "Yes",
"IsCollapsedMain": "Yes",
"ContainsVZP": "No",
"ContainsVZPKeuze": "No",
"coursesResult": "1010FLWGES Gesch. van de middeleeuwen - 6.00SP, \n1011FLWGES Gesch. van de nieuwe tijd - 6.00SP, \n1014FLWGES Inleiding wereldgeschiedenis - 6.00SP, \n1053FLWGES Hist oef 1 - 6.00SP, ",
"totalStudiepunten": 24
},
{
"LinkNumber": 2,
"StudentName": "Joren Van Roy",
"StudentID": "20141999",
"IsCollapsed": "No",
"IsCollapsedKeuze": "Yes",
"IsCollapsedMain": "No",
"ContainsVZP": "No",
"ContainsVZPKeuze": "No",
"coursesResult": "1011FLWGES Gesch. van de nieuwe tijd - 6.00SP, \n1014FLWGES Inleiding wereldgeschiedenis - 6.00SP, \n1300PSWSOC Inleiding tot de Sociologie - 6.00SP, \n1087FLWGES Central and Eastern Europe - 3.00SP, \n1013FLWGES Eigentijdse geschiedenis - 6.00SP, \n1200PSWPOL Inleiding tot de Politicologie - 6.00SP, \n1104TEWVSG Inl. tot het recht - 6.00SP, \n1300PSWSFP Samenleving, feiten, problemen - 6.00SP, \n1302TEWVSG Levensbesch., mens en markt - 3.00SP, ",
"totalStudiepunten": 48
},
{
"LinkNumber": 4,
"StudentName": "Zeynep Öcbe",
"StudentID": "20193168",
"IsCollapsed": "No",
"IsCollapsedKeuze": "No",
"IsCollapsedMain": "No",
"ContainsVZP": "No",
"ContainsVZPKeuze": "No",
"coursesResult": "1011FLWGES Gesch. van de nieuwe tijd - 6.00SP, \n1014FLWGES Inleiding wereldgeschiedenis - 6.00SP, \n1053FLWGES Hist oef 1 - 6.00SP, \n1067FLWGES Byzantijnse gesch. - 3.00SP, \n1001IOBGJU Global Justice - 3.00SP, ",
"totalStudiepunten": 24
},
{
"LinkNumber": 5,
"StudentName": "Jens Aelbrecht",
"StudentID": "20213047",
"IsCollapsed": "No",
"IsCollapsedKeuze": "Yes",
"IsCollapsedMain": "No",
"ContainsVZP": "No",
"ContainsVZPKeuze": "No",
"coursesResult": "1002FLWGES Inleiding tot de economie - 6.00SP, \n1005FLWGES Oefeningen paleografie - 3.00SP, \n1011FLWGES Gesch. van de nieuwe tijd - 6.00SP, \n1014FLWGES Inleiding wereldgeschiedenis - 6.00SP, \n1053FLWGES Hist oef 1 - 6.00SP, \n1300PSWSOC Sociologie - 6.00SP, \n1054FLWGES Inleiding wijsbegeerte - 6.00SP, \n1067FLWGES Byzantijnse gesch. - 3.00SP, \n1000PSWPUB Publiekrecht - 3.00SP, \n1013FLWGES Eigentijdse geschiedenis - 6.00SP, \n1200PSWPOL Politicologie - 6.00SP, \n1001CPGVKA Levensbeschouwing &amp; wet - 3.00SP, ",
"totalStudiepunten": 60
},
{
"LinkNumber": 6,
"StudentName": "Hadi Dagher",
"StudentID": "20221279",
"IsCollapsed": "No",
"IsCollapsedKeuze": "No",
"IsCollapsedMain": "No",
"ContainsVZP": "No",
"ContainsVZPKeuze": "No",
"coursesResult": "1002FLWGES Inleiding tot de economie - 6.00SP, \n1005FLWGES Oefeningen paleografie - 3.00SP, \n1053FLWGES Hist oef 1 - 6.00SP, \n1011FLWGES Gesch. van de nieuwe tijd - 6.00SP, \n1014FLWGES Inleiding wereldgeschiedenis - 6.00SP, ",
"totalStudiepunten": 27
},
{
"LinkNumber": 7,
"StudentName": "Casper Janssens",
"StudentID": "20221960",
"IsCollapsed": "No",
"IsCollapsedKeuze": "Yes",
"IsCollapsedMain": "No",
"ContainsVZP": "No",
"ContainsVZPKeuze": "No",
"coursesResult": "1002FLWGES Inleiding tot de economie - 6.00SP, \n1003FLWGES Historische methode - 6.00SP, \n1005FLWGES Oefeningen paleografie - 3.00SP, \n1010FLWGES Gesch. van de middeleeuwen - 6.00SP, \n1011FLWGES Gesch. van de nieuwe tijd - 6.00SP, \n1014FLWGES Inleiding wereldgeschiedenis - 6.00SP, \n1053FLWGES Hist oef 1 - 6.00SP, \n1000RECPOL Politicologie - 3.00SP, \n1300PSWSOC Sociologie - 6.00SP, \n1000RECGPR Geschiedenis privaatrecht - 6.00SP, \n1200RECTEN Taalgebruik Engels - 3.00SP, ",
"totalStudiepunten": 57
},
{
"LinkNumber": 8,
"StudentName": "Hanne De Win",
"StudentID": "20223846",
"IsCollapsed": "No",
"IsCollapsedKeuze": "Yes",
"IsCollapsedMain": "No",
"ContainsVZP": "No",
"ContainsVZPKeuze": "No",
"coursesResult": "1002FLWGES Inleiding tot de economie - 6.00SP, \n1003FLWGES Historische methode - 6.00SP, \n1005FLWGES Oefeningen paleografie - 3.00SP, \n1011FLWGES Gesch. van de nieuwe tijd - 6.00SP, \n1014FLWGES Inleiding wereldgeschiedenis - 6.00SP, \n1053FLWGES Hist oef 1 - 6.00SP, \n1102FLWTLT Geschiedenis van de film 1 - 3.00SP, \n1300PSWSOC Sociologie - 6.00SP, \n1082FLWGES Geschiedenis van België - 3.00SP, ",
"totalStudiepunten": 45
},
{
"LinkNumber": 9,
"StudentName": "Axl Legon",
"StudentID": "20223927",
"IsCollapsed": "Yes",
"IsCollapsedKeuze": "Yes",
"IsCollapsedMain": "Yes",
"ContainsVZP": "No",
"ContainsVZPKeuze": "No",
"coursesResult": "1067FLWGES Byzantijnse gesch. - 3.00SP, \n1083FLWGES Gesch. van de Nederlanden - 3.00SP, \n1002FLWGES Inleiding tot de economie - 6.00SP, \n1300PSWSOC Sociologie - 6.00SP, \n1054FLWGES Inleiding wijsbegeerte - 6.00SP, \n1003FLWGES Historische methode - 6.00SP, \n1005FLWGES Oefeningen paleografie - 3.00SP, \n1072FLWGES Inleiding historiografie - 3.00SP, \n1053FLWGES Hist oef 1 - 6.00SP, \n1010FLWGES Gesch. van de middeleeuwen - 6.00SP, \n1011FLWGES Gesch. van de nieuwe tijd - 6.00SP, \n1014FLWGES Inleiding wereldgeschiedenis - 6.00SP, \n1066FLWGES History islamic world - 6.00SP, \n1082FLWGES Geschiedenis van België - 3.00SP, \n1200PSWPOL Politicologie - 6.00SP, \n1002FLWALG Keuzeruimte - 3.00SP, ",
"totalStudiepunten": 78
},
{
"LinkNumber": 11,
"StudentName": "Error",
"StudentID": "Error",
"IsCollapsed": "Error",
"IsCollapsedKeuze": "Error",
"IsCollapsedMain": "Error",
"ContainsVZP": "Error",
"ContainsVZPKeuze": "Error",
"ErrorStr": "Cannot read properties of null (reading 'evaluate')"
},
{
"LinkNumber": 12,
"StudentName": "Tom Grohmann",
"StudentID": "20230664",
"IsCollapsed": "No",
"IsCollapsedKeuze": "Yes",
"IsCollapsedMain": "No",
"ContainsVZP": "No",
"ContainsVZPKeuze": "No",
"coursesResult": "1002FLWGES Inleiding tot de economie - 6.00SP, \n1005FLWGES Oefeningen paleografie - 3.00SP, \n1011FLWGES Gesch. van de nieuwe tijd - 6.00SP, \n1014FLWGES Inleiding wereldgeschiedenis - 6.00SP, \n1053FLWGES Hist oef 1 - 6.00SP, \n1067FLWGES Byzantijnse gesch. - 3.00SP, ",
"totalStudiepunten": 30
},
{
"LinkNumber": 14,
"StudentName": "Lien Arras",
"StudentID": "20231250",
"IsCollapsed": "No",
"IsCollapsedKeuze": "Yes",
"IsCollapsedMain": "No",
"ContainsVZP": "No",
"ContainsVZPKeuze": "No",
"coursesResult": "1002FLWGES Inleiding tot de economie - 6.00SP, \n1005FLWGES Oefeningen paleografie - 3.00SP, \n1011FLWGES Gesch. van de nieuwe tijd - 6.00SP, \n1014FLWGES Inleiding wereldgeschiedenis - 6.00SP, \n1053FLWGES Hist oef 1 - 6.00SP, \n1038FLWGES Inleiding tot het Latijn - 3.00SP, ",
"totalStudiepunten": 30
},
{
"LinkNumber": 15,
"StudentName": "Oliwier Rogozinski",
"StudentID": "20232813",
"IsCollapsed": "Yes",
"IsCollapsedKeuze": "Yes",
"IsCollapsedMain": "Yes",
"ContainsVZP": "No",
"ContainsVZPKeuze": "No",
"coursesResult": "1002FLWGES Inleiding tot de economie - 6.00SP, \n1003FLWGES Historische methode - 6.00SP, \n1005FLWGES Oefeningen paleografie - 3.00SP, \n1010FLWGES Gesch. van de middeleeuwen - 6.00SP, \n1011FLWGES Gesch. van de nieuwe tijd - 6.00SP, \n1014FLWGES Inleiding wereldgeschiedenis - 6.00SP, \n1053FLWGES Hist oef 1 - 6.00SP, \n1066FLWGES History islamic world - 6.00SP, \n1300PSWSOC Sociologie - 6.00SP, \n1054FLWGES Inleiding wijsbegeerte - 6.00SP, \n1083FLWGES Gesch. van de Nederlanden - 3.00SP, ",
"totalStudiepunten": 60
},
{
"LinkNumber": 16,
"StudentName": "Milan Van De Velde",
"StudentID": "20233391",
"IsCollapsed": "No",
"IsCollapsedKeuze": "No",
"IsCollapsedMain": "No",
"ContainsVZP": "No",
"ContainsVZPKeuze": "No",
"coursesResult": "1002FLWGES Inleiding tot de economie - 6.00SP, \n1005FLWGES Oefeningen paleografie - 3.00SP, \n1011FLWGES Gesch. van de nieuwe tijd - 6.00SP, \n1014FLWGES Inleiding wereldgeschiedenis - 6.00SP, \n1053FLWGES Hist oef 1 - 6.00SP, \n1300PSWSOC Sociologie - 6.00SP, ",
"totalStudiepunten": 33
},
{
"LinkNumber": 17,
"StudentName": "Briek Piessens",
"StudentID": "20233905",
"IsCollapsed": "Yes",
"IsCollapsedKeuze": "Yes",
"IsCollapsedMain": "Yes",
"ContainsVZP": "No",
"ContainsVZPKeuze": "No",
"coursesResult": "1002FLWGES Inleiding tot de economie - 6.00SP, \n1003FLWGES Historische methode - 6.00SP, \n1005FLWGES Oefeningen paleografie - 3.00SP, \n1010FLWGES Gesch. van de middeleeuwen - 6.00SP, \n1011FLWGES Gesch. van de nieuwe tijd - 6.00SP, \n1014FLWGES Inleiding wereldgeschiedenis - 6.00SP, \n1053FLWGES Hist oef 1 - 6.00SP, \n1066FLWGES History islamic world - 6.00SP, \n1300PSWSOC Sociologie - 6.00SP, \n1054FLWGES Inleiding wijsbegeerte - 6.00SP, \n1118FLWTLA Taal tussen natuur en cultuur - 3.00SP, \n1104FLWTLN Cultuurgesch.v/d Lage Landen 2 - 3.00SP, \n1101FLWTLN Nederlandse TB1: basisvaardigh - 6.00SP, ",
"totalStudiepunten": 69
}
]

View File

@@ -0,0 +1,39 @@
const fs = require("fs");
const path = require("path");
const resultsFilePath = path.join(__dirname, "results.json");
// Flag to track if the file has been reset
let isFileReset = false;
function updateResultsDatabase(newResult) {
// Check if the file needs to be reset
if (!isFileReset) {
if (fs.existsSync(resultsFilePath)) {
const fileContent = fs.readFileSync(resultsFilePath, "utf-8");
if (fileContent.trim()) {
// Reset the file to an empty array
fs.writeFileSync(resultsFilePath, JSON.stringify([], null, 2));
console.log("Old data removed from results.json.");
}
}
isFileReset = true; // Mark the file as reset
}
// Read existing results or initialize an empty array
let results = [];
if (fs.existsSync(resultsFilePath)) {
const fileContent = fs.readFileSync(resultsFilePath, "utf-8");
if (fileContent.trim()) {
results = JSON.parse(fileContent);
}
}
// Add the new result to the array
results.push(newResult);
// Write the updated results back to the file
fs.writeFileSync(resultsFilePath, JSON.stringify(results, null, 2));
}
module.exports = updateResultsDatabase;

28
vars.js
View File

@@ -1,28 +0,0 @@
/* Top Level Vars*/
const email = 'bdaneels@ad.ua.ac.be'
const password = 'Heideggershut18891'
const webpage = 'https://sisaweb.uantwerpen.be'
const runId = 'bd'
const dasbhoardInschrijvingenURL = 'https://app.sisaweb.uantwerpen.be/psc/csprd_3/EMPLOYEE/SA/c/QQ_INSCHRIJVINGEN.QQ_OVERZ_ING_STDL.GBL?NavColl=true'
/* Dashboard Form Vars*/
const career = 'BACA'
const program = 'B0011'
const academicYear = '2240'
module.exports = {
email,
password,
webpage,
runId,
dasbhoardInschrijvingenURL,
career,
program,
academicYear
};

5
wait.js Normal file
View File

@@ -0,0 +1,5 @@
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
module.exports = wait;