Time Table Fixed
This commit is contained in:
@@ -81,6 +81,7 @@ public class StudentMenuHandler {
|
||||
weeklyBtn.put("id", "student_weekly_timetable");
|
||||
weeklyBtn.put("title", "Weekly Timetable");
|
||||
buttons.add(weeklyBtn);
|
||||
System.out.println("FINAL TODAY TIMETABLE MESSAGE:\n" + todaySchedule);
|
||||
|
||||
Map<String, Object> buttonMessage = WhatsAppMessageBuilder.buildButtonMessage(todaySchedule, buttons);
|
||||
messageService.sendInteractiveMessage(phoneNumber, buttonMessage);
|
||||
|
||||
@@ -95,74 +95,136 @@ public class MessageFormatter {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String formatTimetable(String rawJson) {
|
||||
private static class TimetableEntry {
|
||||
String subjectName;
|
||||
String subjectCode;
|
||||
String staffName;
|
||||
String staffCode;
|
||||
|
||||
public TimetableEntry(String subjectName, String subjectCode, String staffName, String staffCode) {
|
||||
this.subjectName = subjectName != null ? subjectName.trim() : "";
|
||||
this.subjectCode = subjectCode != null ? subjectCode.trim() : "";
|
||||
this.staffName = staffName != null ? staffName.trim() : "";
|
||||
this.staffCode = staffCode != null ? staffCode.trim() : "";
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return !subjectName.isEmpty() && !subjectCode.isEmpty();
|
||||
}
|
||||
|
||||
public String getUniqueKey() {
|
||||
return subjectName + "||" + subjectCode;
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatTodayTimetable(String rawJson) {
|
||||
String day = java.time.LocalDate.now()
|
||||
.getDayOfWeek()
|
||||
.getDisplayName(java.time.format.TextStyle.FULL, java.util.Locale.ENGLISH)
|
||||
.toLowerCase(java.util.Locale.ROOT);
|
||||
return formatTodayTimetableForDay(rawJson, day);
|
||||
}
|
||||
|
||||
public static String formatTodayTimetableForDay(String rawJson, String day) {
|
||||
if (rawJson == null) return "❌ Failed to retrieve timetable data.";
|
||||
|
||||
try {
|
||||
JsonNode root = mapper.readTree(rawJson);
|
||||
if (!root.has("data") || !root.get("data").isObject() || !root.get("data").has("schedule")) {
|
||||
return "❌ Timetable details not available in this format.";
|
||||
}
|
||||
|
||||
JsonNode schedule = root.get("data").get("schedule");
|
||||
|
||||
System.out.println("TIMETABLE DEBUG");
|
||||
System.out.println("Current day: " + day.toUpperCase());
|
||||
System.out.println("Normalized day: " + day);
|
||||
boolean hasSchedule = schedule.has(day);
|
||||
System.out.println("Schedule found: " + hasSchedule);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\ud83d\uddd3\ufe0f *Today's Classes*\n\n");
|
||||
sb.append("📅 *Today's Classes*\n");
|
||||
sb.append("━━━━━━━━━━━━━━\n\n");
|
||||
|
||||
boolean validFormat = false;
|
||||
boolean hasClassesToday = false;
|
||||
|
||||
if (root.has("data") && root.get("data").isObject() && root.get("data").has("schedule")) {
|
||||
validFormat = true;
|
||||
JsonNode schedule = root.get("data").get("schedule");
|
||||
if (hasSchedule) {
|
||||
JsonNode daySchedule = schedule.get(day);
|
||||
|
||||
String today = java.time.LocalDate.now().getDayOfWeek().toString().toLowerCase();
|
||||
int maxPeriod = 7;
|
||||
java.util.Iterator<String> fieldNames = daySchedule.fieldNames();
|
||||
java.util.List<String> foundPeriods = new java.util.ArrayList<>();
|
||||
while (fieldNames.hasNext()) {
|
||||
String fName = fieldNames.next();
|
||||
foundPeriods.add(fName);
|
||||
try {
|
||||
int p = Integer.parseInt(fName);
|
||||
if (p > maxPeriod) {
|
||||
maxPeriod = p;
|
||||
}
|
||||
} catch (NumberFormatException e) {}
|
||||
}
|
||||
System.out.println("Periods found: [" + String.join(", ", foundPeriods) + "]");
|
||||
|
||||
if (schedule.has(today)) {
|
||||
JsonNode todaySchedule = schedule.get(today);
|
||||
for (int period = 1; period <= maxPeriod; period++) {
|
||||
String periodKey = String.valueOf(period);
|
||||
sb.append(getNumberEmoji(period)).append(" ");
|
||||
|
||||
if (todaySchedule.isObject() && todaySchedule.size() > 0) {
|
||||
java.util.Iterator<java.util.Map.Entry<String, JsonNode>> fields = todaySchedule.fields();
|
||||
while (fields.hasNext()) {
|
||||
java.util.Map.Entry<String, JsonNode> field = fields.next();
|
||||
String timeOrPeriod = field.getKey();
|
||||
JsonNode details = field.getValue();
|
||||
|
||||
if (details.isObject()) {
|
||||
String course = details.has("course_name") ? details.get("course_name").asText() :
|
||||
(details.has("name") ? details.get("name").asText() : "Unknown");
|
||||
String room = details.has("room") ? details.get("room").asText() : "";
|
||||
|
||||
sb.append("*").append(timeOrPeriod).append(":* ").append(course);
|
||||
if (!room.isEmpty()) sb.append(" (Room ").append(room).append(")");
|
||||
sb.append("\n");
|
||||
} else {
|
||||
sb.append("*").append(timeOrPeriod).append(":* ").append(details.asText()).append("\n");
|
||||
if (daySchedule.has(periodKey)) {
|
||||
JsonNode periodNode = daySchedule.get(periodKey);
|
||||
java.util.List<TimetableEntry> entries = new java.util.ArrayList<>();
|
||||
|
||||
if (periodNode.isArray()) {
|
||||
for (JsonNode node : periodNode) {
|
||||
String sName = node.has("subjectName") ? node.get("subjectName").asText() : "";
|
||||
String sCode = node.has("subjectCode") ? node.get("subjectCode").asText() : "";
|
||||
String stName = node.has("staffName") ? node.get("staffName").asText() : "";
|
||||
String stCode = node.has("staffCode") ? node.get("staffCode").asText() : "";
|
||||
entries.add(new TimetableEntry(sName, sCode, stName, stCode));
|
||||
}
|
||||
hasClassesToday = true;
|
||||
}
|
||||
} else if (todaySchedule.isArray() && todaySchedule.size() > 0) {
|
||||
for (JsonNode details : todaySchedule) {
|
||||
String time = details.has("time") ? details.get("time").asText() : "TBA";
|
||||
String course = details.has("course_name") ? details.get("course_name").asText() : "Unknown";
|
||||
String room = details.has("room") ? details.get("room").asText() : "";
|
||||
|
||||
sb.append("*").append(time).append(":* ").append(course);
|
||||
if (!room.isEmpty()) sb.append(" (Room ").append(room).append(")");
|
||||
sb.append("\n");
|
||||
hasClassesToday = true;
|
||||
|
||||
System.out.println("Period " + period + " entries: " + entries.size());
|
||||
if (!entries.isEmpty()) {
|
||||
TimetableEntry first = entries.get(0);
|
||||
System.out.println("Period " + period + " first subjectName: " + first.subjectName);
|
||||
System.out.println("Period " + period + " first subjectCode: " + first.subjectCode);
|
||||
}
|
||||
|
||||
java.util.Map<String, TimetableEntry> uniqueMap = new java.util.LinkedHashMap<>();
|
||||
for (TimetableEntry entry : entries) {
|
||||
if (entry.isValid()) {
|
||||
uniqueMap.putIfAbsent(entry.getUniqueKey(), entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (!uniqueMap.isEmpty()) {
|
||||
java.util.List<String> formattedSubjects = new java.util.ArrayList<>();
|
||||
for (TimetableEntry entry : uniqueMap.values()) {
|
||||
formattedSubjects.add("*" + entry.subjectName + "*\n `" + entry.subjectCode + "`");
|
||||
}
|
||||
sb.append(String.join(" / ", formattedSubjects)).append("\n\n");
|
||||
} else {
|
||||
sb.append("*Free Period*\n\n");
|
||||
}
|
||||
} else {
|
||||
sb.append("*Free Period*\n\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sb.append("No classes scheduled for today.\n\n");
|
||||
}
|
||||
|
||||
if (validFormat && !hasClassesToday) {
|
||||
sb.append("No classes scheduled for today.\n");
|
||||
} else if (!validFormat) {
|
||||
sb.append("Details not available in this format.\n");
|
||||
sb.append("\n\n*DEBUG RAW JSON:*\n").append(rawJson);
|
||||
}
|
||||
|
||||
sb.append("━━━━━━━━━━━━━━");
|
||||
return sb.toString();
|
||||
} catch (Exception e) {
|
||||
return "⚠️ Error formatting timetable data.\nRAW JSON: " + rawJson;
|
||||
System.err.println("Error formatting today's timetable: " + e.getMessage());
|
||||
return "⚠️ Error formatting timetable data.";
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatTimetable(String rawJson) {
|
||||
return formatTodayTimetable(rawJson);
|
||||
}
|
||||
|
||||
public static String formatResults(String rawJson, int semester) {
|
||||
if (rawJson == null) return "❌ Failed to retrieve semester results.";
|
||||
|
||||
@@ -444,76 +506,105 @@ public class MessageFormatter {
|
||||
return rows;
|
||||
}
|
||||
|
||||
private static String getNumberEmoji(int num) {
|
||||
switch (num) {
|
||||
case 1: return "1️⃣";
|
||||
case 2: return "2️⃣";
|
||||
case 3: return "3️⃣";
|
||||
case 4: return "4️⃣";
|
||||
case 5: return "5️⃣";
|
||||
case 6: return "6️⃣";
|
||||
case 7: return "7️⃣";
|
||||
case 8: return "8️⃣";
|
||||
case 9: return "9️⃣";
|
||||
default: return num + "️⃣";
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatWeeklyTimetable(String rawJson) {
|
||||
if (rawJson == null) return "❌ Failed to retrieve weekly timetable data.";
|
||||
|
||||
try {
|
||||
JsonNode root = mapper.readTree(rawJson);
|
||||
|
||||
if (!root.has("data") || !root.get("data").isObject() || !root.get("data").has("schedule")) {
|
||||
return "❌ Weekly timetable details not available in the response.";
|
||||
}
|
||||
|
||||
JsonNode schedule = root.get("data").get("schedule");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("📅 *Weekly Class Timetable*\n\n");
|
||||
sb.append("```\n");
|
||||
sb.append(String.format("%-3s | %-11s | %s\n", "Day", "Time/Period", "Subject (Room)"));
|
||||
sb.append("----+-------------+------------------------\n");
|
||||
sb.append("📚 WEEKLY TIMETABLE\n\n");
|
||||
|
||||
String[] days = {"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"};
|
||||
String[] dayAbbrevs = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
|
||||
String[] days = {"monday", "tuesday", "wednesday", "thursday", "friday", "saturday"};
|
||||
String[] dayLabels = {"MON", "TUE", "WED", "THU", "FRI", "SAT"};
|
||||
boolean hasAnyClasses = false;
|
||||
|
||||
for (int i = 0; i < days.length; i++) {
|
||||
String day = days[i];
|
||||
String abbrev = dayAbbrevs[i];
|
||||
String label = dayLabels[i];
|
||||
|
||||
if (schedule.has(day)) {
|
||||
JsonNode daySchedule = schedule.get(day);
|
||||
|
||||
if (daySchedule.isObject() && daySchedule.size() > 0) {
|
||||
java.util.Iterator<java.util.Map.Entry<String, JsonNode>> fields = daySchedule.fields();
|
||||
while (fields.hasNext()) {
|
||||
java.util.Map.Entry<String, JsonNode> field = fields.next();
|
||||
String timeOrPeriod = field.getKey();
|
||||
JsonNode details = field.getValue();
|
||||
sb.append(label).append("\n");
|
||||
|
||||
int maxPeriod = 7;
|
||||
java.util.Iterator<String> fieldNames = daySchedule.fieldNames();
|
||||
while (fieldNames.hasNext()) {
|
||||
try {
|
||||
int p = Integer.parseInt(fieldNames.next());
|
||||
if (p > maxPeriod) {
|
||||
maxPeriod = p;
|
||||
}
|
||||
} catch (NumberFormatException e) {}
|
||||
}
|
||||
|
||||
for (int period = 1; period <= maxPeriod; period++) {
|
||||
String periodKey = String.valueOf(period);
|
||||
sb.append(getNumberEmoji(period)).append(" ");
|
||||
|
||||
if (daySchedule.has(periodKey)) {
|
||||
JsonNode details = daySchedule.get(periodKey);
|
||||
java.util.Set<String> subjects = new java.util.LinkedHashSet<>();
|
||||
|
||||
String course = "";
|
||||
String room = "";
|
||||
if (details.isObject()) {
|
||||
course = details.has("course_name") ? details.get("course_name").asText() :
|
||||
(details.has("name") ? details.get("name").asText() : "Unknown");
|
||||
room = details.has("room") ? details.get("room").asText() : "";
|
||||
} else {
|
||||
course = details.asText();
|
||||
if (details.isArray()) {
|
||||
for (JsonNode entry : details) {
|
||||
String name = entry.has("subjectName") ? entry.get("subjectName").asText() : "";
|
||||
String code = entry.has("subjectCode") ? entry.get("subjectCode").asText() : "";
|
||||
if (!name.trim().isEmpty()) {
|
||||
subjects.add(name.trim() + " — " + code.trim());
|
||||
}
|
||||
}
|
||||
} else if (details.isObject()) {
|
||||
String name = details.has("course_name") ? details.get("course_name").asText() :
|
||||
(details.has("name") ? details.get("name").asText() :
|
||||
(details.has("subjectName") ? details.get("subjectName").asText() : ""));
|
||||
String code = details.has("course_code") ? details.get("course_code").asText() :
|
||||
(details.has("code") ? details.get("code").asText() :
|
||||
(details.has("subjectCode") ? details.get("subjectCode").asText() : ""));
|
||||
if (!name.trim().isEmpty()) {
|
||||
subjects.add(name.trim() + " — " + code.trim());
|
||||
}
|
||||
}
|
||||
|
||||
String subjectRoom = room.isEmpty() ? course : course + " (" + room + ")";
|
||||
sb.append(String.format("%-3s | %-11s | %s\n", abbrev, truncate(timeOrPeriod, 11), subjectRoom));
|
||||
hasAnyClasses = true;
|
||||
}
|
||||
} else if (daySchedule.isArray() && daySchedule.size() > 0) {
|
||||
for (JsonNode details : daySchedule) {
|
||||
String time = details.has("time") ? details.get("time").asText() : "TBA";
|
||||
String course = details.has("course_name") ? details.get("course_name").asText() : "Unknown";
|
||||
String room = details.has("room") ? details.get("room").asText() : "";
|
||||
|
||||
String subjectRoom = room.isEmpty() ? course : course + " (" + room + ")";
|
||||
sb.append(String.format("%-3s | %-11s | %s\n", abbrev, truncate(time, 11), subjectRoom));
|
||||
hasAnyClasses = true;
|
||||
if (!subjects.isEmpty()) {
|
||||
sb.append(String.join(" / ", subjects)).append("\n");
|
||||
hasAnyClasses = true;
|
||||
} else {
|
||||
sb.append("—\n");
|
||||
}
|
||||
} else {
|
||||
sb.append("—\n");
|
||||
}
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("```");
|
||||
|
||||
if (!hasAnyClasses) {
|
||||
return "📅 *Weekly Class Timetable*\n\nNo classes scheduled for this week.";
|
||||
return "📚 WEEKLY TIMETABLE\n\nNo classes scheduled for this week.";
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
return sb.toString().trim();
|
||||
} catch (Exception e) {
|
||||
return "⚠️ Error formatting weekly timetable data.";
|
||||
}
|
||||
|
||||
@@ -19,4 +19,4 @@ spring.h2.console.enabled=true
|
||||
|
||||
# Encryption Secret for Passcodes (Must be 16, 24, or 32 bytes)
|
||||
bot.encryption.secret=12345678901234567890123456789012
|
||||
whatsapp.api-token=EAAc3Wjql00oBSdoBhXozC8gKyWN9Il6cqpjvE531hZAnuFqOfHCuCBGt8hYZCICzm2dnXsH2RR3HIi3dpZAZBbNFE9Xj8Hvs3TS94nHrmxevicgThlqSQDjZCDm6SS1qFvt7NwRjiy1TWtZCuLLvcTxyjjNPUtjt91OZBr5DtddHzESLezP6R3oJEzIhSjLqlRAvNwfhW8wDYiCkkx0Qw69iO2UeodHw5E8Q86kZCPEvocldDZCyb7qZCMZAELPbYJYkWVLk8MjVyZAXjmnoGFnS5n4ZAsXBE
|
||||
whatsapp.api-token=EAAc3Wjql00oBSUjYhQ1TZBiNJNmwNlpktCtJpqSLXycDVjWjPiP5dBWHvvFX2Deq1tGXQO2jgVOGChnJk9jsMxLVdxvUs4z7g7xlfcQtAPYiHwvQbPVSbGTTCBvjv2IvHf7Ql2iNBKL72GZCrxAJrQpmjHUG5sbQkVWmMpNfwgI52iDBw0BifU1QhQHFEOnQfiPu19KUp3hJOg6XkUbbXyfBKvbSkZB57xj0XHMv6wgpqDrQwAACOjSlSPrNEC3eZB9DbZAqWYnPkJCsX99Pz3GhA
|
||||
|
||||
@@ -10,4 +10,46 @@ class WhatsappBotApplicationTests {
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFormatTodayTimetableThursday() {
|
||||
String thursdayJson = "{\n" +
|
||||
" \"success\": true,\n" +
|
||||
" \"data\": {\n" +
|
||||
" \"schedule\": {\n" +
|
||||
" \"thursday\": {\n" +
|
||||
" \"1\": [{\"subjectName\":\"Business Analytics\",\"subjectCode\":\"CB23531\",\"staffName\":\"FOUZIA SULTHANA K.\",\"staffCode\":\"CS84\"}],\n" +
|
||||
" \"2\": [{\"subjectName\":\"Computer Networks\",\"subjectCode\":\"CS23511\",\"staffName\":\"SELVAKUMARAN S.\",\"staffCode\":\"CS91\"}],\n" +
|
||||
" \"3\": [\n" +
|
||||
" {\"subjectName\":\"Deep Learning\",\"subjectCode\":\"AD23511\",\"staffName\":\"DIVYA S\",\"staffCode\":\"CS193\"},\n" +
|
||||
" {\"subjectName\":\"Deep Learning\",\"subjectCode\":\"AD23511\",\"staffName\":\"SARANYA S.\",\"staffCode\":\"CS85\"},\n" +
|
||||
" {\"subjectName\":\"Deep Learning\",\"subjectCode\":\"AD23511\",\"staffName\":\"DR.VIDHYA M\",\"staffCode\":\"CS256\"},\n" +
|
||||
" {\"subjectName\":\"Deep Learning\",\"subjectCode\":\"AD23511\",\"staffName\":\"SANDHIYARAJESHWARI K\",\"staffCode\":\"CS153\"},\n" +
|
||||
" {\"subjectName\":\"Deep Learning\",\"subjectCode\":\"AD23511\",\"staffName\":\"MONIKAA R\",\"staffCode\":\"CS178\"},\n" +
|
||||
" {\"subjectName\":\"Deep Learning\",\"subjectCode\":\"AD23511\",\"staffName\":\"ARTHI A.\",\"staffCode\":\"CS87\"}\n" +
|
||||
" ],\n" +
|
||||
" \"4\": [{\"subjectName\":\"Image and Video Analytics\",\"subjectCode\":\"AD23V15\",\"staffName\":\"JOEL J\",\"staffCode\":\"CS226\"}],\n" +
|
||||
" \"5\": [{\"subjectName\":\"Big Data Analytics\",\"subjectCode\":\"AD23V12\",\"staffName\":\"KAVITHA V\",\"staffCode\":\"CS253\"}],\n" +
|
||||
" \"6\": [\n" +
|
||||
" {\"subjectName\":\"Data Exploration and Visualization\",\"subjectCode\":\"AD23532\",\"staffName\":\"DR.VIDHYA M\",\"staffCode\":\"CS256\"},\n" +
|
||||
" {\"subjectName\":\"Data Exploration and Visualization\",\"subjectCode\":\"AD23532\",\"staffName\":\"DR.VIDHYA M\",\"staffCode\":\"CS256\"}\n" +
|
||||
" ],\n" +
|
||||
" \"7\": [{\"subjectName\":\"\",\"subjectCode\":\"\",\"staffName\":\"FOUZIA SULTHANA K.\",\"staffCode\":\"CS84\"}]\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
String formatted = com.rit.whatsapp.util.MessageFormatter.formatTodayTimetableForDay(thursdayJson, "thursday");
|
||||
System.out.println("Formatted output:\n" + formatted);
|
||||
|
||||
org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("📅 *Today's Classes*"));
|
||||
org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("1️⃣ *Business Analytics*\n `CB23531`"));
|
||||
org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("2️⃣ *Computer Networks*\n `CS23511`"));
|
||||
org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("3️⃣ *Deep Learning*\n `AD23511`"));
|
||||
org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("4️⃣ *Image and Video Analytics*\n `AD23V15`"));
|
||||
org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("5️⃣ *Big Data Analytics*\n `AD23V12`"));
|
||||
org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("6️⃣ *Data Exploration and Visualization*\n `AD23532`"));
|
||||
org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("7️⃣ *Free Period*"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user