FileProvider.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. from os import path, mkdir, getcwd
  2. from time import time
  3. from uuid import uuid1
  4. from flask import Flask, make_response, send_from_directory, request
  5. from werkzeug import formparser
  6. from pycs.ApplicationStatus import ApplicationStatus
  7. from pycs.util.GenericWrapper import GenericWrapper
  8. from pycs.util.ProgressFileWriter import ProgressFileWriter
  9. class FileProvider(Flask):
  10. def __init__(self, app_status: ApplicationStatus, cors=False):
  11. super().__init__(__name__)
  12. # add download handler
  13. @self.route('/media/<identifier>', methods=['GET'])
  14. def media(identifier):
  15. # get current project
  16. opened_projects = list(filter(lambda x: x['status'] == 'open', app_status['projects']))
  17. if len(opened_projects) == 0:
  18. return make_response('no open project available', 500)
  19. current_project = opened_projects[0]
  20. file_directory = path.join(getcwd(), 'projects', current_project['id'], 'data')
  21. # get object
  22. data_objects = list(filter(lambda x: x['id'] == identifier, current_project['data']))
  23. if len(data_objects) == 0:
  24. return make_response('data object not avilable', 500)
  25. target_object = data_objects[0]
  26. # return data
  27. file_name = target_object['id'] + target_object['extension']
  28. return send_from_directory(file_directory, file_name)
  29. # add upload handler
  30. @self.route('/upload', methods=['POST'])
  31. def upload():
  32. file_uuid = str(uuid1())
  33. # get current project path
  34. opened_projects = list(filter(lambda x: x['status'] == 'open', app_status['projects']))
  35. if len(opened_projects) == 0:
  36. return make_response('no open project available', 500)
  37. current_project = opened_projects[0]
  38. upload_path = path.join('projects', current_project['id'], 'data')
  39. job = GenericWrapper()
  40. file_name = GenericWrapper()
  41. file_extension = GenericWrapper()
  42. file_size = GenericWrapper(0)
  43. # save upload to file
  44. def custom_stream_factory(total_content_length, filename, content_type, content_length=None):
  45. file_name.value, file_extension.value = path.splitext(filename)
  46. file_path = path.join(upload_path, f'{file_uuid}{file_extension.value}')
  47. # add job to app status
  48. job.value = app_status['jobs'].append({
  49. 'id': file_uuid,
  50. 'type': 'upload',
  51. 'progress': 0,
  52. 'filename': filename,
  53. 'created': int(time()),
  54. 'finished': None
  55. })
  56. # create upload path if not exists
  57. if not path.exists(upload_path):
  58. mkdir(upload_path)
  59. # define progress callback
  60. length = content_length if content_length is not None and content_length != 0 else total_content_length
  61. def callback(progress):
  62. file_size.value += progress
  63. relative = progress / length
  64. if relative - job.value['progress'] > 0.02:
  65. job.value['progress'] = relative
  66. # open file handler
  67. return ProgressFileWriter(file_path, 'wb', callback)
  68. stream, form, files = formparser.parse_form_data(request.environ, stream_factory=custom_stream_factory)
  69. if 'file' not in files.keys():
  70. return make_response('no file uploaded', 500)
  71. # set progress to 1 after upload is done
  72. job = job.value
  73. job['progress'] = 1
  74. job['finished'] = int(time())
  75. # add to project files
  76. if 'data' not in current_project:
  77. current_project['data'] = []
  78. current_project['data'].append({
  79. 'id': file_uuid,
  80. 'name': file_name.value,
  81. 'extension': file_extension.value,
  82. 'size': file_size.value,
  83. 'created': job['created']
  84. })
  85. # create response and allow cors if needed
  86. response = make_response()
  87. if cors:
  88. response.headers['Access-Control-Allow-Origin'] = '*'
  89. return response