upload_controller.dart 2.5 KB
Newer Older
1
2
import 'dart:io';

Daniel Ravi Negi's avatar
Daniel Ravi Negi committed
3
import 'package:aqueduct/aqueduct.dart';
4
5
import 'package:mime/mime.dart';

Daniel Ravi Negi's avatar
Daniel Ravi Negi committed
6
7
import '../coupons_backend.dart';

8
9
10
11
12
const Map<List<int>, String> supportedTypes = <List<int>, String>{
  [0xFF, 0xD8]: 'image/jpeg',
  [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]: 'image/png',
  [0x47, 0x49, 0x46, 0x38]: 'image/gif',
  [0x42, 0x4D]: 'image/bmp',
13
  [0x52, 0x49, 0x46, 0x46]: 'image/webp',
14
15
};

Daniel Ravi Negi's avatar
Daniel Ravi Negi committed
16
class UploadController extends ResourceController {
17
18
  MimeTypeResolver mimeChecker;

Daniel Ravi Negi's avatar
Daniel Ravi Negi committed
19
  UploadController() {
20
21
22
23
24
    mimeChecker = MimeTypeResolver();
    supportedTypes.forEach(mimeChecker.addMagicNumber);
    acceptedContentTypes = supportedTypes.values
        .map((String e) => ContentType(e.split('/').first, e.split('/').last))
        .toList();
Daniel Ravi Negi's avatar
Daniel Ravi Negi committed
25
26
  }

27
  @Scope(['user'])
Daniel Ravi Negi's avatar
Daniel Ravi Negi committed
28
29
30
  @Operation.get()
  Future<Response> getFiles() async {
    final assetsDir = Directory('assets');
31
    final files = <String>[];
Leon Tappe's avatar
Leon Tappe committed
32
    await assetsDir.list(recursive: true, followLinks: false).listen((FileSystemEntity entity) {
33
      files.add(entity.path.split(Platform.pathSeparator).last);
34
    }).asFuture<Null>();
Daniel Ravi Negi's avatar
Daniel Ravi Negi committed
35

36
37
    files.sort();

Leon Tappe's avatar
Leon Tappe committed
38
    return Response.ok(files);
Daniel Ravi Negi's avatar
Daniel Ravi Negi committed
39
40
  }

41
  @Scope(['admin'])
Daniel Ravi Negi's avatar
Daniel Ravi Negi committed
42
  @Operation.post()
43
44
45
46
47
  Future<Response> postFile() async {
    var filename = '${DateTime.now().millisecondsSinceEpoch}';
    final newFilePath = '$assetsFolderPath${Platform.pathSeparator}$filename';

    // read response and write to file
Daniel Ravi Negi's avatar
Daniel Ravi Negi committed
48
    final bodyBytes = await request.body.decode<List<int>>();
49
50
51
    final contentType = request.raw.headers['Content-Type'].single;
    var file = await File(newFilePath).writeAsBytes(bodyBytes);

Leon Tappe's avatar
Leon Tappe committed
52
    final mimeType = mimeChecker.lookup(file.path, headerBytes: bodyBytes.take(8).toList());
53
54
55

    // check mimetype and append suffix to filename
    if (contentType == null || mimeType != contentType) {
56
      await file.delete();
Leon Tappe's avatar
Leon Tappe committed
57
      return Response.badRequest(body: 'content-type not given or inconsistent with file');
58
59
60
61
62
63
64
65
    }

    try {
      filename += '.${acceptedContentTypes.singleWhere((ContentType type) {
            print('${type.mimeType} == $contentType');
            return type.mimeType == contentType;
          }).mimeType.split('/').last}';
    } catch (e) {
66
      await file.delete();
67
68
69
      return Response.badRequest(body: e.toString());
    }

Leon Tappe's avatar
Leon Tappe committed
70
    file = await file.rename('$assetsFolderPath${Platform.pathSeparator}$filename');
71
72

    // return name if file was successfully renamed
Daniel Ravi Negi's avatar
Daniel Ravi Negi committed
73
74
75
    if (file.existsSync()) {
      return Response.ok(filename);
    } else {
76
      await file.delete();
Daniel Ravi Negi's avatar
Daniel Ravi Negi committed
77
78
      return Response.noContent();
    }
Daniel Ravi Negi's avatar
Daniel Ravi Negi committed
79
80
  }
}