UploadFile.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. from os import path
  2. from uuid import uuid1
  3. from eventlet import tpool
  4. from flask import make_response, request, abort
  5. from flask.views import View
  6. from werkzeug import formparser
  7. from pycs.database.Database import Database
  8. from pycs.frontend.notifications.NotificationManager import NotificationManager
  9. from pycs.util.FileParser import file_info
  10. class UploadFile(View):
  11. """
  12. save file uploads
  13. """
  14. # pylint: disable=arguments-differ
  15. methods = ['POST']
  16. def __init__(self, db: Database, nm: NotificationManager):
  17. # pylint: disable=invalid-name
  18. self.db = db
  19. self.nm = nm
  20. self.data_folder = None
  21. self.file_id = None
  22. self.file_name = None
  23. self.file_extension = None
  24. self.file_size = None
  25. def dispatch_request(self, identifier):
  26. # find project
  27. project = self.db.project(identifier)
  28. if project is None:
  29. return abort(404, "Project not found")
  30. # abort if external storage is used
  31. if project.external_data:
  32. return abort(400, "Project uses external data, but a file was uploaded")
  33. # get upload path and id
  34. self.data_folder = project.data_folder
  35. self.file_id = str(uuid1())
  36. # parse upload data
  37. _, _, files = tpool.execute(formparser.parse_form_data,
  38. request.environ, stream_factory=self.custom_stream_factory)
  39. # abort if there is no file entry in uploaded data
  40. if 'file' not in files.keys():
  41. return abort(400, "No file entry was found in uploaded data")
  42. # detect file type
  43. try:
  44. ftype, frames, fps = tpool.execute(file_info,
  45. self.data_folder, self.file_id, self.file_extension)
  46. except ValueError as e:
  47. return abort(400, str(e))
  48. # add to project files
  49. with self.db:
  50. file, _ = project.add_file(self.file_id, ftype, self.file_name, self.file_extension,
  51. self.file_size, self.file_id, frames, fps)
  52. # send update
  53. self.nm.create_file(file)
  54. # return default success response
  55. return make_response()
  56. def custom_stream_factory(self, total_content_length, filename, content_type,
  57. content_length=None):
  58. """
  59. save some useful information and open a file handler to save the uploaded file to
  60. :param total_content_length:
  61. :param filename:
  62. :param content_type:
  63. :param content_length:
  64. :return:
  65. """
  66. # pylint: disable=unused-argument
  67. # set relevant properties
  68. self.file_name, self.file_extension = path.splitext(filename)
  69. if content_length is not None and content_length > 0:
  70. self.file_size = content_length
  71. else:
  72. self.file_size = total_content_length
  73. # open file handler
  74. file_path = path.join(self.data_folder, f'{self.file_id}{self.file_extension}')
  75. return open(file_path, 'wb')