class UploadVideoHandler(BaseHandler):
    """
    @api {post} /uploadVideo/ Upload Video
    @apiName UploadVideo
    @apiVersion 0.2.0
    @apiGroup Upload
    @apiDescription This route will create a new project and upload a video to it.

    @apiParam {File} video The video file to analyze. This can have any file extension.
    
    @apiSuccess {String} identifier The project identifier. This will be used to reference the project in all other requests.

    @apiError error_message The error message to display.
    """
    def prepare(self):
        if self.request.method.lower() == "post":
            # Set this request's max_body_size to 20 GB
            self.request.connection.set_max_body_size(20 * self.GB)
        try:
            total = int(self.request.headers.get("Content-Length", "0"))
        except KeyError:
            total = 0
        self.ps = MultiPartStreamer(total)
        print 'Upload Video Prepared'

    def data_received(self, chunk):
        self.ps.data_received(chunk)

    def post(self):
        try:
            self.ps.data_complete()
            # If multiple files called "video" are sent, we pick the first one
            video_part = self.ps.get_parts_by_name("video")[0]
            self.identifier = str(uuid4())

            if video_part:
                create_project(self.identifier, video_part)
            else:
                print "video_part was None"
                self.error_message = "Error decoding video upload"
                raise tornado.web.HTTPError(status_code=500)

        except Exception as e:
            print "could not complete streaming of data parts"
            self.error_message = "Error uploading video: " + str(e)
            raise tornado.web.HTTPError(status_code=500)

        finally:
            self.ps.release_parts()
            self.write({'identifier': self.identifier})
            self.finish()
class UploadHandler(tornado.web.RequestHandler):
    """ Upload log file Tornado request handler: handles page requests and POST
    data """
    def initialize(self):
        self.multipart_streamer = None

    def prepare(self):
        if self.request.method.upper() == 'POST':
            if 'expected_size' in self.request.arguments:
                self.request.connection.set_max_body_size(
                    int(self.get_argument('expected_size')))
            try:
                total = int(self.request.headers.get("Content-Length", "0"))
            except KeyError:
                total = 0
            self.multipart_streamer = MultiPartStreamer(total)

    def data_received(self, data):
        if self.multipart_streamer:
            self.multipart_streamer.data_received(data)

    def get(self):
        template = _ENV.get_template(UPLOAD_TEMPLATE)
        self.write(template.render())

    def post(self):
        if self.multipart_streamer:
            try:
                self.multipart_streamer.data_complete()
                form_data = self.multipart_streamer.get_values([
                    'description', 'email', 'allowForAnalysis', 'obfuscated',
                    'source', 'type', 'feedback', 'windSpeed', 'rating',
                    'videoUrl', 'public', 'vehicleName'
                ])
                description = cgi.escape(
                    form_data['description'].decode("utf-8"))
                email = form_data['email'].decode("utf-8")
                upload_type = 'personal'
                if 'type' in form_data:
                    upload_type = form_data['type'].decode("utf-8")
                source = 'webui'
                title = ''  # may be used in future...
                if 'source' in form_data:
                    source = form_data['source'].decode("utf-8")
                obfuscated = 0
                if 'obfuscated' in form_data:
                    if form_data['obfuscated'].decode("utf-8") == 'true':
                        obfuscated = 1
                allow_for_analysis = 0
                if 'allowForAnalysis' in form_data:
                    if form_data['allowForAnalysis'].decode("utf-8") == 'true':
                        allow_for_analysis = 1
                feedback = ''
                if 'feedback' in form_data:
                    feedback = cgi.escape(
                        form_data['feedback'].decode("utf-8"))
                wind_speed = -1
                rating = ''
                stored_email = ''
                video_url = ''
                is_public = 0
                vehicle_name = ''

                if upload_type == 'flightreport':
                    try:
                        wind_speed = int(
                            cgi.escape(form_data['windSpeed'].decode("utf-8")))
                    except ValueError:
                        wind_speed = -1
                    rating = cgi.escape(form_data['rating'].decode("utf-8"))
                    if rating == 'notset': rating = ''
                    stored_email = email
                    # get video url & check if valid
                    video_url = cgi.escape(
                        form_data['videoUrl'].decode("utf-8"), quote=True)
                    if not validate_url(video_url):
                        video_url = ''
                    if 'vehicleName' in form_data:
                        vehicle_name = cgi.escape(
                            form_data['vehicleName'].decode("utf-8"))

                    # always allow for statistical analysis
                    allow_for_analysis = 1
                    if 'public' in form_data:
                        if form_data['public'].decode("utf-8") == 'true':
                            is_public = 1

                file_obj = self.multipart_streamer.get_parts_by_name(
                    'filearg')[0]
                upload_file_name = file_obj.get_filename()

                while True:
                    log_id = str(uuid.uuid4())
                    new_file_name = get_log_filename(log_id)
                    if not os.path.exists(new_file_name):
                        break

                # read file header & check if really an ULog file
                header_len = len(ULog.HEADER_BYTES)
                if (file_obj.get_payload_partial(header_len) !=
                        ULog.HEADER_BYTES):
                    if upload_file_name[-7:].lower() == '.px4log':
                        raise CustomHTTPError(
                            400,
                            'Invalid File. This seems to be a px4log file. '
                            'Upload it to <a href="http://logs.uaventure.com" '
                            'target="_blank">logs.uaventure.com</a>.')
                    raise CustomHTTPError(400, 'Invalid File')

                print('Moving uploaded file to', new_file_name)
                file_obj.move(new_file_name)

                if obfuscated == 1:
                    # TODO: randomize gps data, ...
                    pass

                # generate a token: secure random string (url-safe)
                token = str(binascii.hexlify(os.urandom(16)), 'ascii')

                # Load the ulog file but only if not uploaded via CI.
                # Then we open the DB connection.
                ulog = None
                if source != 'CI':
                    ulog_file_name = get_log_filename(log_id)
                    ulog = load_ulog_file(ulog_file_name)

                # put additional data into a DB
                con = sqlite3.connect(get_db_filename())
                cur = con.cursor()
                cur.execute(
                    'insert into Logs (Id, Title, Description, '
                    'OriginalFilename, Date, AllowForAnalysis, Obfuscated, '
                    'Source, Email, WindSpeed, Rating, Feedback, Type, '
                    'videoUrl, Public, Token) values '
                    '(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [
                        log_id, title, description, upload_file_name,
                        datetime.datetime.now(), allow_for_analysis,
                        obfuscated, source, stored_email, wind_speed, rating,
                        feedback, upload_type, video_url, is_public, token
                    ])

                if ulog is not None:
                    update_vehicle_db_entry(cur, ulog, log_id, vehicle_name)

                con.commit()

                url = '/plot_app?log=' + log_id
                full_plot_url = 'http://' + get_domain_name() + url

                delete_url = 'http://'+get_domain_name()+ \
                    '/edit_entry?action=delete&log='+log_id+'&token='+token

                if upload_type == 'flightreport' and is_public:
                    send_flightreport_email(
                        email_notifications_config['public_flightreport'],
                        full_plot_url, description, feedback,
                        DBData.rating_str_static(rating),
                        DBData.wind_speed_str_static(wind_speed), delete_url,
                        stored_email)

                    # also generate the additional DB entry
                    # (we may have the log already loaded in 'ulog', however the
                    # lru cache will make it very quick to load it again)
                    generate_db_data_from_log_file(log_id, con)

                con.commit()
                cur.close()
                con.close()

                # TODO: now that we have loaded the ulog already, add more
                # information to the notification email (airframe, ...)

                # send notification emails
                send_notification_email(email, full_plot_url, description,
                                        delete_url)

                # do not redirect for QGC
                if source != 'QGroundControl':
                    self.redirect(url)

            except CustomHTTPError:
                raise

            except:
                print('Error when handling POST data',
                      sys.exc_info()[0],
                      sys.exc_info()[1])
                raise CustomHTTPError(500)

            finally:
                self.multipart_streamer.release_parts()

    def write_error(self, status_code, **kwargs):
        html_template = """
<html><title>Error {status_code}</title>
<body>HTTP Error {status_code}{error_message}</body>
</html>
"""
        error_message = ''
        if 'exc_info' in kwargs:
            e = kwargs["exc_info"][1]
            if isinstance(e, CustomHTTPError) and e.error_message:
                error_message = ': ' + e.error_message
        self.write(
            html_template.format(status_code=status_code,
                                 error_message=error_message))
Exemple #3
0
class UploadHandler(tornado.web.RequestHandler):
    def initialize(self):
        self.ps = None

    def prepare(self):
        if self.request.method.upper() == 'POST':
            if 'expected_size' in self.request.arguments:
                self.request.connection.set_max_body_size(
                    int(self.get_argument('expected_size')))
            try:
                total = int(self.request.headers.get("Content-Length", "0"))
            except KeyError:
                total = 0
            self.ps = MultiPartStreamer(total)

    def data_received(self, data):
        if self.ps:
            self.ps.data_received(data)

    def get(self):
        template = env.get_template(UPLOAD_TEMPLATE)
        self.write(template.render())

    def post(self):
        if self.ps:
            try:
                self.ps.data_complete()
                form_data = self.ps.get_values([
                    'description', 'email', 'allowForAnalysis', 'obfuscated',
                    'source'
                ])
                description = cgi.escape(
                    form_data['description'].decode("utf-8"))
                email = form_data['email'].decode("utf-8")
                source = 'webui'
                title = ''  # may be used in future...
                if 'source' in form_data:
                    source = form_data['source'].decode("utf-8")
                obfuscated = 0
                if 'obfuscated' in form_data:
                    if form_data['obfuscated'].decode("utf-8") == 'true':
                        obfuscated = 1
                allow_for_analysis = 0
                if 'allowForAnalysis' in form_data:
                    if form_data['allowForAnalysis'].decode("utf-8") == 'true':
                        allow_for_analysis = 1
                file_obj = self.ps.get_parts_by_name('filearg')[0]
                upload_file_name = file_obj.get_filename()

                while True:
                    log_id = str(uuid.uuid4())
                    new_file_name = get_log_filename(log_id)
                    if not os.path.exists(new_file_name):
                        break

                # read file header & check if really an ULog file
                header_len = len(ULog.HEADER_BYTES)
                if (file_obj.get_payload_partial(header_len) !=
                        ULog.HEADER_BYTES):
                    if upload_file_name[-7:].lower() == '.px4log':
                        raise CustomHTTPError(
                            400,
                            'Invalid File. This seems to be a px4log file. '
                            'Upload it to <a href="http://logs.uaventure.com" '
                            'target="_blank">logs.uaventure.com</a>.')
                    raise CustomHTTPError(400, 'Invalid File')

                print('Moving uploaded file to', new_file_name)
                file_obj.move(new_file_name)

                if obfuscated == 1:
                    # TODO: randomize gps data, ...
                    pass

                # put additional data into a DB
                con = sqlite3.connect(get_db_filename())
                cur = con.cursor()
                cur.execute(
                    'insert into Logs (Id, Title, Description, '
                    'OriginalFilename, Date, AllowForAnalysis, Obfuscated, '
                    'Source) values (?, ?, ?, ?, ?, ?, ?, ?)', [
                        log_id, title, description, upload_file_name,
                        datetime.datetime.now(), allow_for_analysis,
                        obfuscated, source
                    ])
                con.commit()
                cur.close()
                con.close()

                url = '/plot_app?log=' + log_id

                send_notification_email(email,
                                        'http://' + get_domain_name() + url,
                                        description)

                # do not redirect for QGC
                if not source == 'QGroundControl':
                    self.redirect(url)

            except CustomHTTPError:
                raise

            except:
                print('Error when handling POST data',
                      sys.exc_info()[0],
                      sys.exc_info()[1])
                raise CustomHTTPError(500)

            finally:
                self.ps.release_parts()

    def write_error(self, status_code, **kwargs):
        html_template = """
<html><title>Error {status_code}</title>
<body>HTTP Error {status_code}{error_message}</body>
</html>
"""
        error_message = ''
        if 'exc_info' in kwargs:
            e = kwargs["exc_info"][1]
            if isinstance(e, CustomHTTPError) and e.error_message:
                error_message = ': ' + e.error_message
        self.write(
            html_template.format(status_code=status_code,
                                 error_message=error_message))