|
@@ -1,15 +1,16 @@
|
|
|
import 'dart:io';
|
|
import 'dart:io';
|
|
|
|
|
+import 'package:file_upload_processor/handlers/base_api.dart';
|
|
|
import 'package:intl/intl.dart';
|
|
import 'package:intl/intl.dart';
|
|
|
import 'package:mime/mime.dart';
|
|
import 'package:mime/mime.dart';
|
|
|
import 'package:shelf/shelf.dart' as shelf;
|
|
import 'package:shelf/shelf.dart' as shelf;
|
|
|
-//import 'package:shelf/shelf_io.dart' as shelf_io;
|
|
|
|
|
-import 'package:shelf_router/shelf_router.dart';
|
|
|
|
|
import 'package:path/path.dart' as path;
|
|
import 'package:path/path.dart' as path;
|
|
|
import 'package:http_parser/http_parser.dart';
|
|
import 'package:http_parser/http_parser.dart';
|
|
|
import 'package:archive/archive.dart';
|
|
import 'package:archive/archive.dart';
|
|
|
import 'package:supabase/supabase.dart';
|
|
import 'package:supabase/supabase.dart';
|
|
|
|
|
|
|
|
-class FileUploadApi {
|
|
|
|
|
|
|
+class FileUploadApi extends BaseApi {
|
|
|
|
|
+ FileUploadApi(shelf.Request request) : super(request);
|
|
|
|
|
+
|
|
|
SupabaseClient getSupabaseClient(shelf.Request request) {
|
|
SupabaseClient getSupabaseClient(shelf.Request request) {
|
|
|
final supabaseUrl = request.headers['supabase-url'];
|
|
final supabaseUrl = request.headers['supabase-url'];
|
|
|
if (supabaseUrl == null) {
|
|
if (supabaseUrl == null) {
|
|
@@ -96,77 +97,68 @@ class FileUploadApi {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Router get router {
|
|
|
|
|
- final router = Router();
|
|
|
|
|
-
|
|
|
|
|
- router.get('/', (shelf.Request request) {
|
|
|
|
|
- return shelf.Response.ok('Hello World');
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ @override
|
|
|
|
|
+ response() async {
|
|
|
|
|
+ final supabaseClient = getSupabaseClient(request);
|
|
|
|
|
+ await initializeDirectories();
|
|
|
|
|
|
|
|
- router.post('/upload', (shelf.Request request) async {
|
|
|
|
|
- final supabaseClient = getSupabaseClient(request);
|
|
|
|
|
- await initializeDirectories();
|
|
|
|
|
|
|
+ final contentType = request.headers['content-type'];
|
|
|
|
|
+ if (contentType == null ||
|
|
|
|
|
+ !contentType.toLowerCase().startsWith('multipart/form-data')) {
|
|
|
|
|
+ return shelf.Response.badRequest(
|
|
|
|
|
+ body: 'Content-Type must be multipart/form-data');
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- final contentType = request.headers['content-type'];
|
|
|
|
|
- if (contentType == null ||
|
|
|
|
|
- !contentType.toLowerCase().startsWith('multipart/form-data')) {
|
|
|
|
|
- return shelf.Response.badRequest(
|
|
|
|
|
- body: 'Content-Type must be multipart/form-data');
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ final mediaType = MediaType.parse(contentType);
|
|
|
|
|
+ final boundary = mediaType.parameters['boundary'];
|
|
|
|
|
+ if (boundary == null) {
|
|
|
|
|
+ return shelf.Response.badRequest(body: 'Boundary not found');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- try {
|
|
|
|
|
- final mediaType = MediaType.parse(contentType);
|
|
|
|
|
- final boundary = mediaType.parameters['boundary'];
|
|
|
|
|
- if (boundary == null) {
|
|
|
|
|
- return shelf.Response.badRequest(body: 'Boundary not found');
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ final transformer = MimeMultipartTransformer(boundary);
|
|
|
|
|
+ final bodyBytes = await request.read().expand((e) => e).toList();
|
|
|
|
|
+ final stream = Stream.fromIterable([bodyBytes]);
|
|
|
|
|
+ final parts = await transformer.bind(stream).toList();
|
|
|
|
|
|
|
|
- final transformer = MimeMultipartTransformer(boundary);
|
|
|
|
|
- final bodyBytes = await request.read().expand((e) => e).toList();
|
|
|
|
|
- final stream = Stream.fromIterable([bodyBytes]);
|
|
|
|
|
- final parts = await transformer.bind(stream).toList();
|
|
|
|
|
|
|
+ for (var part in parts) {
|
|
|
|
|
+ final contentDisposition = part.headers['content-disposition'];
|
|
|
|
|
+ if (contentDisposition == null) continue;
|
|
|
|
|
|
|
|
- for (var part in parts) {
|
|
|
|
|
- final contentDisposition = part.headers['content-disposition'];
|
|
|
|
|
- if (contentDisposition == null) continue;
|
|
|
|
|
|
|
+ final filenameMatch =
|
|
|
|
|
+ RegExp(r'filename="([^"]*)"').firstMatch(contentDisposition);
|
|
|
|
|
+ if (filenameMatch == null) continue;
|
|
|
|
|
|
|
|
- final filenameMatch =
|
|
|
|
|
- RegExp(r'filename="([^"]*)"').firstMatch(contentDisposition);
|
|
|
|
|
- if (filenameMatch == null) continue;
|
|
|
|
|
|
|
+ final filename = filenameMatch.group(1);
|
|
|
|
|
+ if (filename == null) continue;
|
|
|
|
|
|
|
|
- final filename = filenameMatch.group(1);
|
|
|
|
|
- if (filename == null) continue;
|
|
|
|
|
|
|
+ final bytes = await part.fold<List<int>>(
|
|
|
|
|
+ [],
|
|
|
|
|
+ (prev, element) => [...prev, ...element],
|
|
|
|
|
+ );
|
|
|
|
|
|
|
|
- final bytes = await part.fold<List<int>>(
|
|
|
|
|
- [],
|
|
|
|
|
- (prev, element) => [...prev, ...element],
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ final rawFilePath = path.join('./uploaded/raw', filename);
|
|
|
|
|
+ await File(rawFilePath).writeAsBytes(bytes);
|
|
|
|
|
|
|
|
- final rawFilePath = path.join('./uploaded/raw', filename);
|
|
|
|
|
- await File(rawFilePath).writeAsBytes(bytes);
|
|
|
|
|
-
|
|
|
|
|
- if (isZipFile(bytes)) {
|
|
|
|
|
- await processZipFile(rawFilePath);
|
|
|
|
|
- } else {
|
|
|
|
|
- final dataFilePath = path.join('./uploaded/data', filename);
|
|
|
|
|
- await File(rawFilePath).copy(dataFilePath);
|
|
|
|
|
- }
|
|
|
|
|
- await uploadToSupabase(rawFilePath, filename, supabaseClient,
|
|
|
|
|
- bucket: 'csvhich_archive', timestamped: true, upsert: false);
|
|
|
|
|
|
|
+ if (isZipFile(bytes)) {
|
|
|
|
|
+ await processZipFile(rawFilePath);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ final dataFilePath = path.join('./uploaded/data', filename);
|
|
|
|
|
+ await File(rawFilePath).copy(dataFilePath);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- return shelf.Response.ok('File processed and uploaded successfully');
|
|
|
|
|
- } catch (e, stackTrace) {
|
|
|
|
|
- print('Error: $e\n$stackTrace');
|
|
|
|
|
- return shelf.Response.internalServerError(
|
|
|
|
|
- body: 'Error processing upload: $e');
|
|
|
|
|
- } finally {
|
|
|
|
|
- supabaseClient.dispose();
|
|
|
|
|
- await File('./uploaded/raw').delete(recursive: true);
|
|
|
|
|
- await File('./uploaded/data').delete(recursive: true);
|
|
|
|
|
|
|
+ await uploadToSupabase(rawFilePath, filename, supabaseClient,
|
|
|
|
|
+ bucket: 'csvhich_archive', timestamped: true, upsert: false);
|
|
|
}
|
|
}
|
|
|
- });
|
|
|
|
|
|
|
|
|
|
- return router;
|
|
|
|
|
|
|
+ return shelf.Response.ok('File processed and uploaded successfully');
|
|
|
|
|
+ } catch (e, stackTrace) {
|
|
|
|
|
+ print('Error: $e\n$stackTrace');
|
|
|
|
|
+ return shelf.Response.internalServerError(
|
|
|
|
|
+ body: 'Error processing upload: $e');
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ supabaseClient.dispose();
|
|
|
|
|
+ await File('./uploaded/raw').delete(recursive: true);
|
|
|
|
|
+ await File('./uploaded/data').delete(recursive: true);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|