getCourseTable method
- required String username,
- required SemesterDto semester,
Fetches the course schedule table for a specific student and semester.
Returns a list of course offerings enrolled by the student, including:
- Course details (name, credits, hours)
- Schedule information (days, periods, classroom)
- Teacher and class information
- Enrollment status and remarks
The username should be a student ID, and semester should be obtained
from getCourseSemesterList.
Throws an Exception if no courses are found for the given semester.
Implementation
Future<List<ScheduleDto>> getCourseTable({
required String username,
required SemesterDto semester,
}) async {
final response = await _courseDio.get(
'Select.jsp',
queryParameters: {
'format': '-2',
'code': username,
'year': semester.year,
'sem': semester.term,
},
);
final document = parse(response.data);
// There are two tables in the document; the first one is a timetable grid
// The second table is a list with one course per row, we'll extract that
final courseSelectionTable = document.querySelectorAll('table')[1];
// Find all rows except the first two header rows and the last summary row
final tableRows = courseSelectionTable.querySelectorAll('tr');
final trimmedTableRows = tableRows.sublist(2, tableRows.length - 1);
if (trimmedTableRows.isEmpty) {
throw Exception('No courses found in the selection table.');
}
return trimmedTableRows.map((row) {
final cells = row.children;
// Extract basic course information
final number = _parseCellText(cells[0]);
final course = _parseCellRef(cells[1]);
final phase = int.tryParse(cells[2].text.trim());
final credits = double.tryParse(cells[3].text.trim());
final hours = int.tryParse(cells[4].text.trim());
final type = _parseCellText(cells[5]);
final teacher = _parseCellRef(cells[6]);
final classes = _parseCellRefs(cells[7]);
// Parse schedule from day columns (indices 8-14)
final schedule = <(DayOfWeek, Period)>[];
final days = DayOfWeek.values;
for (var i = 0; i < days.length; i++) {
final dayText = _parseCellText(cells[8 + i]);
if (dayText == null) continue;
// Parse period codes (e.g., "7 8" or "8 9 A") and skip invalid ones
final periods = dayText
.split(' ')
.map(
(e) => Period.values.firstWhereOrNull((p) => p.code == e.trim()),
)
.whereType<Period>()
.toList();
final scheduleOfDay = periods.map((p) => (days[i], p));
schedule.addAll(scheduleOfDay);
}
final classroom = _parseCellRef(cells[15]);
final status = _parseCellText(cells[16]);
final language = _parseCellText(cells[17]);
final syllabusId = _parseCellRef(cells[18]).id;
final remarks = _parseCellText(cells[19]);
return (
number: number,
course: course,
phase: phase,
credits: credits,
hours: hours,
type: type,
teacher: teacher,
classes: classes,
schedule: schedule.isEmpty ? null : schedule,
classroom: classroom,
status: status,
language: language,
syllabusId: syllabusId,
remarks: remarks,
);
}).toList();
}