upload_handler.dart 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'package:myshelf/models/data.dart';
  4. import 'package:shelf/shelf.dart';
  5. import 'package:shelf_multipart/shelf_multipart.dart';
  6. import 'package:supabase/supabase.dart';
  7. import 'package:archive/archive.dart';
  8. Future<Response> handleFileUpload(Request request) async {
  9. // Check authorization
  10. final authHeader = request.headers['authorization'];
  11. if (authHeader == null || !authHeader.startsWith('Bearer ')) {
  12. return Response.forbidden('Authorization header missing or invalid');
  13. }
  14. final token = authHeader.substring(7); // Remove 'Bearer ' prefix
  15. // Initialize Supabase client with the bearer token
  16. final supabase = SupabaseClient(
  17. 'http://baas.fares.cyou:8000',
  18. token,
  19. );
  20. final contentType = request.headers['content-type'];
  21. if (contentType == null || !contentType.contains('multipart/form-data')) {
  22. return Response(400, body: 'Unsupported content-type');
  23. }
  24. if (request.multipart() case var multipart?) {
  25. List<Map<String, dynamic>> uploadedFiles = [];
  26. await for (final part in multipart.parts) {
  27. final contentDisposition = part.headers['content-disposition'];
  28. if (contentDisposition != null &&
  29. contentDisposition.contains('filename=')) {
  30. final name =
  31. RegExp(r'name="([^"]*)"').firstMatch(contentDisposition)?.group(1);
  32. final filename = RegExp(r'filename="([^"]*)"')
  33. .firstMatch(contentDisposition)
  34. ?.group(1);
  35. if (name != null && filename != null) {
  36. try {
  37. // Create temporary file
  38. final tempFile = File('uploads/$filename');
  39. await tempFile.create(recursive: true);
  40. await part.pipe(tempFile.openWrite());
  41. // Upload to Supabase
  42. final bytes = await tempFile.readAsBytes();
  43. await supabase.storage.from('csvhich').uploadBinary(
  44. filename,
  45. bytes,
  46. fileOptions: FileOptions(
  47. upsert: true,
  48. contentType: part.headers['content-type'],
  49. ),
  50. );
  51. //insertline in csvhichupdates
  52. await supabase.from('csvhichupdates').insert({
  53. 'filename': filename,
  54. 'updated_at': DateTime.now().toUtc().toIso8601String(),
  55. });
  56. //copy file to csvhich archive
  57. final nowdt = DateTime.now().toUtc();
  58. final now = nowdt.toIso8601String();
  59. // final timestamp ='${nowdt.year}${nowdt.month.toString().padLeft(2, '0')}${nowdt.day.toString().padLeft(2, '0')}_${nowdt.hour.toString().padLeft(2, '0')}${nowdt.minute.toString().padLeft(2, '0')}';
  60. final timestamp = nowdt.millisecondsSinceEpoch.toString();
  61. //upload file to storage archive bucket
  62. try {
  63. final archiveFilename = 'upload/${timestamp}_$filename';
  64. await supabase.storage.from('csvhich_archive').uploadBinary(
  65. archiveFilename,
  66. bytes,
  67. fileOptions: FileOptions(
  68. upsert: true,
  69. contentType: part.headers['content-type'],
  70. ),
  71. );
  72. } catch (e) {
  73. print('Error uploading to archive: $e');
  74. // Continue execution even if archive upload fails
  75. }
  76. await processCsvFile(tempFile);
  77. // No need to subscribe to channel
  78. final channel = supabase.channel('csvhichstorage');
  79. final res = await channel.sendBroadcastMessage(
  80. event: "upload",
  81. payload: {
  82. "filename": filename,
  83. "updated_at": now,
  84. },
  85. );
  86. print("fileupload: realtime res: $res");
  87. //add filename ta list
  88. uploadedFiles.add({
  89. 'filename': filename,
  90. 'updated_at': now,
  91. });
  92. // Clean up temporary file
  93. await tempFile.delete();
  94. } catch (e) {
  95. print('Error processing file: $e');
  96. return Response.internalServerError(
  97. body: 'Error processing file: ${e.toString()}');
  98. }
  99. }
  100. }
  101. }
  102. if (uploadedFiles.isNotEmpty) {
  103. return Response.ok(
  104. '{"status": "success", "files": ${uploadedFiles.toString()}}',
  105. headers: {'Content-Type': 'application/json'},
  106. );
  107. }
  108. return Response(400, body: 'No files were uploaded');
  109. } else {
  110. return Response(401, body: 'Not a multipart request');
  111. }
  112. }
  113. class FilesAsData {
  114. String? filename;
  115. String? updatedAt;
  116. String data;
  117. FilesAsData({
  118. this.filename,
  119. this.updatedAt,
  120. required this.data,
  121. });
  122. }
  123. processCsvFile(File tempfile) async {
  124. List<FilesAsData> csvData = [];
  125. final filename = tempfile.path.split('/').last;
  126. final bytes = await tempfile.readAsBytes();
  127. // Check if file is a zip archive
  128. String? csvcontent;
  129. if (filename.toLowerCase().endsWith('.zip')) {
  130. final archive = ZipDecoder().decodeBytes(bytes);
  131. for (final file in archive) {
  132. if (!file.isFile) continue;
  133. csvcontent = utf8.decode(file.content as List<int>);
  134. csvData.add(FilesAsData(filename: file.name, data: csvcontent));
  135. }
  136. } else {
  137. // For non-zip files, store in extracted folder
  138. csvcontent = utf8.decode(bytes);
  139. csvData.add(FilesAsData(filename: filename, data: csvcontent));
  140. }
  141. // No need to subscribe to channel
  142. print((csv2list(csvData!.first!.data!))
  143. .map((e) => Pnleg.fromList(e))
  144. .toList()
  145. .first
  146. .toMap()
  147. .keys);
  148. // print(
  149. // (csv2list(csvData!.first!.data!)).map((e) => Acleg.fromList(e)).toList());
  150. //insert csv content to database
  151. // List<List<dynamic>> csvData = [];
  152. // if (csvcontent != null) {
  153. // List<String> lines = csvcontent.split('\n');
  154. // for (String line in lines) {
  155. // List<String> values = line.split(',');
  156. // csvData.add(values.map((value) {
  157. // String trimmedValue = value
  158. // .trim()
  159. // .replaceAll(RegExp(r'^"|"$'), '')
  160. // .replaceAll(RegExp(r'^ | $'), '')
  161. // .trim();
  162. // return trimmedValue.isEmpty ? null : trimmedValue;
  163. // }).toList());
  164. // }
  165. // print(csvData);
  166. // }
  167. }