Beispiel #1
0
    def test_audio_upload_with_non_mp3_file(self):
        self.login(self.EDITOR_EMAIL)
        response = self.get_html_response('/create/0')
        csrf_token = self.get_csrf_token_from_response(response)

        file_system_class = fs_services.get_exploration_file_system_class()
        fs = fs_domain.AbstractFileSystem(
            file_system_class(fs_domain.ENTITY_TYPE_EXPLORATION, '0'))

        with open(os.path.join(feconf.TESTS_DATA_DIR,
                               self.TEST_AUDIO_FILE_FLAC),
                  mode='rb') as f:
            raw_audio = f.read()

        self.assertFalse(fs.isfile('audio/%s' % self.TEST_AUDIO_FILE_FLAC))

        with self.accepted_audio_extensions_swap:
            self.post_json('%s/0' % self.AUDIO_UPLOAD_URL_PREFIX,
                           {'filename': self.TEST_AUDIO_FILE_FLAC},
                           csrf_token=csrf_token,
                           upload_files=[('raw_audio_file', 'unused_filename',
                                          raw_audio)])

        self.assertTrue(fs.isfile('audio/%s' % self.TEST_AUDIO_FILE_FLAC))

        self.logout()
Beispiel #2
0
    def post(self, exploration_id):
        """Saves an image uploaded by a content creator."""

        raw = self.request.get('image')
        filename = self.payload.get('filename')
        if not raw:
            raise self.InvalidInputException('No image supplied')

        allowed_formats = ', '.join(
            feconf.ACCEPTED_IMAGE_FORMATS_AND_EXTENSIONS.keys())

        # Verify that the data is recognized as an image.
        file_format = imghdr.what(None, h=raw)
        if file_format not in feconf.ACCEPTED_IMAGE_FORMATS_AND_EXTENSIONS:
            raise self.InvalidInputException('Image not recognized')

        # Verify that the file type matches the supplied extension.
        if not filename:
            raise self.InvalidInputException('No filename supplied')
        if filename.rfind('.') == 0:
            raise self.InvalidInputException('Invalid filename')
        if '/' in filename or '..' in filename:
            raise self.InvalidInputException(
                'Filenames should not include slashes (/) or consecutive dot '
                'characters.')
        if '.' not in filename:
            raise self.InvalidInputException(
                'Image filename with no extension: it should have '
                'one of the following extensions: %s.' % allowed_formats)

        dot_index = filename.rfind('.')
        extension = filename[dot_index + 1:].lower()
        if (extension not in
                feconf.ACCEPTED_IMAGE_FORMATS_AND_EXTENSIONS[file_format]):
            raise self.InvalidInputException(
                'Expected a filename ending in .%s, received %s' %
                (file_format, filename))

        file_system_class = fs_services.get_exploration_file_system_class()
        fs = fs_domain.AbstractFileSystem(
            file_system_class(fs_domain.ENTITY_TYPE_EXPLORATION,
                              exploration_id))
        filepath = '%s/%s' % (self._FILENAME_PREFIX, filename)

        if fs.isfile(filepath):
            raise self.InvalidInputException(
                'A file with the name %s already exists. Please choose a '
                'different name.' % filename)

        exp_services.save_original_and_compressed_versions_of_image(
            self.user_id, filename, exploration_id, raw)

        self.render_json({'filename': filename})
Beispiel #3
0
def get_filename_with_dimensions(old_filename, exp_id):
    """Gets the filename with dimensions of the image file in it.

    Args:
        old_filename: str. Name of the file whose dimensions need to be
            calculated.
        exp_id: str. Exploration id.

    Returns:
        str. The new filename of the image file.
    """
    file_system_class = fs_services.get_exploration_file_system_class()
    fs = fs_domain.AbstractFileSystem(
        file_system_class('exploration/%s' % exp_id))
    filepath = 'image/%s' % old_filename
    try:
        content = fs.get(filepath.encode('utf-8'))
        height, width = gae_image_services.get_image_dimensions(content)
    except IOError:
        height = 120
        width = 120
    new_filename = regenerate_image_filename_using_dimensions(
        old_filename, height, width)
    return new_filename
Beispiel #4
0
    def post(self, exploration_id):
        """Saves an audio file uploaded by a content creator."""

        raw_audio_file = self.request.get('raw_audio_file')
        filename = self.payload.get('filename')
        allowed_formats = feconf.ACCEPTED_AUDIO_EXTENSIONS.keys()

        if not raw_audio_file:
            raise self.InvalidInputException('No audio supplied')
        dot_index = filename.rfind('.')
        extension = filename[dot_index + 1:].lower()

        if dot_index == -1 or dot_index == 0:
            raise self.InvalidInputException(
                'No filename extension: it should have '
                'one of the following extensions: %s' % allowed_formats)
        if extension not in feconf.ACCEPTED_AUDIO_EXTENSIONS:
            raise self.InvalidInputException(
                'Invalid filename extension: it should have '
                'one of the following extensions: %s' % allowed_formats)

        tempbuffer = StringIO.StringIO()
        tempbuffer.write(raw_audio_file)
        tempbuffer.seek(0)
        try:
            # For every accepted extension, use the mutagen-specific
            # constructor for that type. This will catch mismatched audio
            # types e.g. uploading a flac file with an MP3 extension.
            if extension == 'mp3':
                audio = mp3.MP3(tempbuffer)
            else:
                audio = mutagen.File(tempbuffer)
        except mutagen.MutagenError:
            # The calls to mp3.MP3() versus mutagen.File() seem to behave
            # differently upon not being able to interpret the audio.
            # mp3.MP3() raises a MutagenError whereas mutagen.File()
            # seems to return None. It's not clear if this is always
            # the case. Occasionally, mutagen.File() also seems to
            # raise a MutagenError.
            raise self.InvalidInputException('Audio not recognized '
                                             'as a %s file' % extension)
        tempbuffer.close()

        if audio is None:
            raise self.InvalidInputException('Audio not recognized '
                                             'as a %s file' % extension)
        if audio.info.length > feconf.MAX_AUDIO_FILE_LENGTH_SEC:
            raise self.InvalidInputException(
                'Audio files must be under %s seconds in length. The uploaded '
                'file is %.2f seconds long.' %
                (feconf.MAX_AUDIO_FILE_LENGTH_SEC, audio.info.length))
        if len(
                set(audio.mime).intersection(
                    set(feconf.ACCEPTED_AUDIO_EXTENSIONS[extension]))) == 0:
            raise self.InvalidInputException(
                'Although the filename extension indicates the file '
                'is a %s file, it was not recognized as one. '
                'Found mime types: %s' % (extension, audio.mime))

        mimetype = audio.mime[0]

        # For a strange, unknown reason, the audio variable must be
        # deleted before opening cloud storage. If not, cloud storage
        # throws a very mysterious error that entails a mutagen
        # object being recursively passed around in app engine.
        del audio

        # Audio files are stored to the datastore in the dev env, and to GCS
        # in production.
        file_system_class = fs_services.get_exploration_file_system_class()
        fs = fs_domain.AbstractFileSystem(
            file_system_class('exploration/%s' % exploration_id))
        fs.commit(self.user_id,
                  '%s/%s' % (self._FILENAME_PREFIX, filename),
                  raw_audio_file,
                  mimetype=mimetype)

        self.render_json({'filename': filename})
Beispiel #5
0
 def test_get_exploration_file_system_with_dev_mode_disabled(self):
     with self.swap(constants, 'DEV_MODE', False):
         file_system = fs_services.get_exploration_file_system_class()
         self.assertIsInstance(
             file_system(fs_domain.ENTITY_TYPE_EXPLORATION, 'entity_id'),
             fs_domain.GcsFileSystem)
Beispiel #6
0
 def test_get_exploration_file_system_with_dev_mode_enabled(self):
     with self.swap(constants, 'DEV_MODE', True):
         file_system = fs_services.get_exploration_file_system_class()
         self.assertIsInstance(file_system('exploration_id'),
                               fs_domain.ExplorationFileSystem)