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()
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})
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
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})
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)
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)