calendar_handler.dart 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import 'dart:convert';
  2. import 'package:icalserver/icalendar.dart';
  3. import 'package:jiffy/jiffy.dart';
  4. import 'package:supabase/supabase.dart';
  5. import 'package:shelf/shelf.dart';
  6. class CalendarHandler {
  7. SupabaseClient getSupabaseClient(Request request) {
  8. // final supabaseUrl = request.headers['supabase-url'];
  9. // final authHeader = request.headers['authorization'];
  10. // final token = authHeader!.substring(7); // Remove 'Bearer ' prefix
  11. final supabaseUrl = 'http://baas.fares.cyou:8000';
  12. final token =
  13. "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q";
  14. return SupabaseClient(
  15. supabaseUrl,
  16. token,
  17. );
  18. }
  19. // Handler for the /link route
  20. Future<Response> getCalendar(Request request) async {
  21. final credentials = _getBasicAuthCredentials(request);
  22. if (credentials == null) {
  23. return Response.unauthorized('Invalid credentials');
  24. }
  25. final (username, password) = credentials;
  26. if (username != password) {
  27. return Response.unauthorized('Invalid credentials');
  28. }
  29. final supabase = getSupabaseClient(request);
  30. //print(licencesCsv);
  31. // Execute the query
  32. final rosterlist =
  33. await supabase.rpc('get_roster_ical', params: {'__tlc': username});
  34. // Handle the response
  35. final requester =
  36. (await supabase.from('licences').select().eq('tlc', username));
  37. print(
  38. 'TLC: $username ... EVENTS: ${rosterlist.length} ... Name: ${requester[0]['lname']}, ${requester[0]['fname']}');
  39. // Create an iCalendar object
  40. final ical = ICalendar();
  41. if (rosterlist is List) {
  42. for (var i = 0; i < rosterlist.length; i++) {
  43. final event = rosterlist[i];
  44. switch (event["_dutytype"]) {
  45. case "flight":
  46. ical.addEvent(
  47. summary: "${event["dep"]}-${event["des"]}",
  48. description: """
  49. Flight ${event["al"]}${event["fnum"]} from ${event["dep"]} to ${event["des"]}
  50. A/C: ${event["_reg"] ?? "---"}/${event["actype"]}
  51. ${event["_version"] != null ? "Ver: ${event["_version"]}" : ""} ${(event["_paxy"] != null || event["_paxc"] != null) ? "/ PAX: ${event["_paxc"] != null ? "C${event["_paxc"]}" : ""} Y${event["_paxy"] ?? "0"}" : ""}
  52. Dep/Arr time: ${Jiffy.parse(event["_hdep"], isUtc: true).Hm} - ${Jiffy.parse(event["_hdes"], isUtc: true).Hm}
  53. ${event["_hdep_sched"] != null ? "Sched Dep time: ${Jiffy.parse(event["_hdep_sched"], isUtc: true).format(pattern: "dd MMM yyyy HH:mm")}" : ""}
  54. ${event["_delay"] != null ? "Delay codes: ${(event["_delay"] as List<dynamic>).map((e) {
  55. final f = (e ?? "")
  56. .split('|')
  57. .map((j) => j == "" ? null : j)
  58. .toList();
  59. return "${(f[1]) ?? (f[0]) ?? '--'}:${((f[2]) ?? '0000').padLeft(4, '0')}";
  60. })}" : ""}
  61. Crew:
  62. ${(event["crew"] as List<dynamic>).map((e) {
  63. final f = (e ?? "").split('|').toList();
  64. return " ${f[0]}: ${f[2]}, ${f[3]} (${f[1]})";
  65. }).join("\n")}
  66. """
  67. .replaceAll("\n", "\\n"),
  68. startTime: Jiffy.parse(event["_hdep"], isUtc: true).dateTime,
  69. endTime: Jiffy.parse(event["_hdes"]).dateTime,
  70. attendees: [],
  71. );
  72. break;
  73. case "dhflight" || "dhlimo":
  74. ical.addEvent(
  75. summary: "DH ${event["dep"]}-${event["des"]}",
  76. description: """
  77. DH ${event["_dutytype"] == "dhflight" ? "Flight" : "Limo"} ${event["al"]}${event["fnum"]} from ${event["dep"]} to ${event["des"]}
  78. ${event["_dutytype"] == "dhflight" ? "A/C: ${event["_reg"] ?? "---"}/${event["actype"]}" : ""}
  79. ${event["_version"] != null ? "Ver: ${event["_version"]}" : ""} ${(event["_paxy"] != null || event["_paxc"] != null) ? "/ PAX: ${event["_paxc"] != null ? "C${event["_paxc"]}" : ""} Y${event["_paxy"] ?? "0"}" : ""}
  80. Dep/Arr time: ${Jiffy.parse(event["_hdep"], isUtc: true).Hm} - ${Jiffy.parse(event["_hdes"], isUtc: true).Hm}
  81. ${event["_hdep_sched"] != null ? "Sched Dep time: ${Jiffy.parse(event["_hdep_sched"], isUtc: true).format(pattern: "dd MMM yyyy HH:mm")}" : ""}
  82. ${event["_delay"] != null ? "Delay codes: ${(event["_delay"] as List<dynamic>).map((e) {
  83. final f = (e ?? "")
  84. .split('|')
  85. .map((j) => j == "" ? null : j)
  86. .toList();
  87. return "${(f[1]) ?? (f[0]) ?? '--'}:${((f[2]) ?? '0000').padLeft(4, '0')}";
  88. })}" : ""}
  89. Crew:
  90. ${(event["crew"] as List<dynamic>).map((e) {
  91. final f = (e ?? "").split('|').toList();
  92. return " ${f[0]}: ${f[2]}, ${f[3]} (${f[1]})";
  93. }).join("\n")}
  94. """
  95. .replaceAll("\n", "\\n"),
  96. startTime: Jiffy.parse(event["_hdep"], isUtc: true).dateTime,
  97. endTime: Jiffy.parse(event["_hdes"]).dateTime,
  98. attendees: [],
  99. );
  100. break;
  101. case "standby" || "ground":
  102. ical.addEvent(
  103. summary:
  104. "${event["_dutytype"] == "standby" ? "STDBY" : ""} ${event["label"]}",
  105. description: """
  106. ${event["_dutytype"] == "standby" ? "STDBY" : ""} ${event["label"]} @ ${event["dep"]}
  107. Start/End time: ${Jiffy.parse(event["_hdep"], isUtc: true).Hm} - ${Jiffy.parse(event["_hdes"], isUtc: true).Hm}
  108. Attendee:
  109. ${(event["crew"] as List<dynamic>).map((e) {
  110. final f = (e ?? "").split('|').toList();
  111. return " ${f[0]}: ${f[2]}, ${f[3]} (${f[1]})";
  112. }).join("\n")}
  113. """
  114. .replaceAll("\n", "\\n"),
  115. startTime: Jiffy.parse(event["_hdep"], isUtc: true).dateTime,
  116. endTime: Jiffy.parse(event["_hdes"]).dateTime,
  117. attendees: [],
  118. );
  119. break;
  120. case "day":
  121. ical.addEvent(
  122. summary: "${event["label"]}",
  123. description: """
  124. ${event["label"]} @ ${event["dep"] ?? ""}
  125. """
  126. .replaceAll("\n", "\\n"),
  127. startTime: Jiffy.parse(event["_hdep"]).dateTime,
  128. endTime: Jiffy.parse(event["_hdep"]).dateTime,
  129. attendees: [],
  130. allday: true,
  131. );
  132. break;
  133. default:
  134. }
  135. }
  136. }
  137. // Return the response with the iCalendar content
  138. await supabase.dispose();
  139. return Response.ok(
  140. ical.serialize(),
  141. headers: {'Content-Type': 'text/calendar; charset=utf-8'},
  142. );
  143. }
  144. (String, String)? _getBasicAuthCredentials(Request request) {
  145. // Get Authorization header
  146. if (!request.headers.containsKey('authorization')) {
  147. return null;
  148. }
  149. String authHeader = request.headers['authorization'] ?? "";
  150. if (!authHeader.startsWith('Basic ')) {
  151. return null;
  152. }
  153. // Extract and decode credentials
  154. try {
  155. String base64Credentials = authHeader.substring('Basic '.length);
  156. String credentials = utf8.decode(base64.decode(base64Credentials));
  157. List<String> userPass = credentials.split(':');
  158. if (userPass.length != 2) return null;
  159. return (userPass[0], userPass[1]);
  160. } catch (e) {
  161. return null;
  162. }
  163. }
  164. }