class TestMetsCreation(unittest.TestCase): test_ip = "eark-ip" test_source_directory = os.path.join(ROOT + '/tests/test_resources/') temp_working_dir = os.path.join(ROOT, "tmp/tmp-%s" % randomutils.randomword(10)) tmp_ip_dir = os.path.join(temp_working_dir, test_ip) test_ip_dir = os.path.join(test_source_directory, test_ip) mets_file_path = os.path.join(temp_working_dir, test_ip, 'METS.xml') @classmethod def setUpClass(cls): shutil.copytree(TestMetsCreation.test_ip_dir, TestMetsCreation.tmp_ip_dir) @classmethod def tearDownClass(cls): shutil.rmtree(TestMetsCreation.temp_working_dir) pass @unittest.skip("Currently throws a KeyError:'data' error @{}". \ format("eatb/metadata/mets/metsgenerator.py:446")) def testCreateMets(self): metsgen = MetsGenerator(TestMetsCreation.test_ip_dir) mets_data = {'packageid': '996ed635-3e13-4ee5-8e5b-e9661e1d9a93', 'type': 'AIP', 'schemas': 'schemas', 'parent': None} metsgen.createMets(mets_data, TestMetsCreation.mets_file_path) self.assertTrue(os.path.exists(TestMetsCreation.mets_file_path)) pm = ParsedMets(TestMetsCreation.test_ip_dir) pm.load_mets(TestMetsCreation.mets_file_path) obj_id = pm.get_obj_id() self.assertEqual("996ed635-3e13-4ee5-8e5b-e9661e1d9a93", obj_id)
class EncryptionTest(unittest.TestCase): test_file = 'test.txt' test_dir = os.path.join(root_dir, 'tests/test_resources') test_file_path = os.path.join(test_dir, test_file) tmp_dir = '/tmp/temp-' + randomutils.randomword(10) tmp_file_path = os.path.join(tmp_dir, test_file) def setUp(self): os.makedirs(EncryptionTest.tmp_dir, exist_ok=True) shutil.copyfile(EncryptionTest.test_file_path, EncryptionTest.tmp_file_path) def tearDown(self): shutil.rmtree(EncryptionTest.tmp_dir) def test_gpg_encrypt_file_passphrase(self): """ Test encrypt/decrypt with passphrase """ cmd_encrypt = gpg_encrypt_file_passphrase(EncryptionTest.test_file, "12345") print(cmd_encrypt) self.assertEqual(7, len(cmd_encrypt)) expected_cmd_list = [ 'gpg', '--yes', '--batch', '--passphrase', '12345', '-c', EncryptionTest.test_file ] self.assertTrue(cmd_encrypt == expected_cmd_list) out = subprocess.call(cmd_encrypt, cwd=EncryptionTest.tmp_dir) self.assertEqual(0, out) cli_commands = CliCommands() cli_command = CliCommand( "gpg_passphrase_decrypt_file", cli_commands.get_command_template("gpg_passphrase_decrypt_file")) cmd_decrypt = cli_command.get_command({ 'encrypted_file': "%s.gpg" % EncryptionTest.test_file, 'decrypted_file': "test_decrypted.txt", 'passphrase': "12345" }) out = subprocess.call(cmd_decrypt, cwd=EncryptionTest.tmp_dir) self.assertEqual(0, out) self.assertEqual( "test", read_file_content( os.path.join(EncryptionTest.tmp_dir, "test_decrypted.txt")))
class TestExtract(unittest.TestCase): test_dir = os.path.join(ROOT, 'tests/test_resources/') temp_extract_dir = '/tmp/temp-' + randomutils.randomword(10) @classmethod def setUpClass(cls): if not os.path.exists(TestExtract.temp_extract_dir): os.makedirs(TestExtract.temp_extract_dir) @classmethod def tearDownClass(cls): shutil.rmtree(TestExtract.temp_extract_dir) pass @staticmethod def reset_test_dir(): shutil.rmtree(TestExtract.temp_extract_dir) os.makedirs(TestExtract.temp_extract_dir) def assert_extract(self, package_file): package_file_path = os.path.join(TestExtract.test_dir, package_file) packaged_container = PackagedContainer.factory(package_file_path) packaged_container.extract(TestExtract.temp_extract_dir) # must be 8 extracted files item_counts = [(len(r), len(d), len(files)) for r, d, files in os.walk(TestExtract.temp_extract_dir) ] sum_files = sum(ic[2] for ic in item_counts) self.assertEqual(sum_files, 2, "Number of extracted files not as expected") sum_directories = sum(ic[1] for ic in item_counts) self.assertEqual(sum_directories, 2, "Number of extracted directories not as expected") files_to_check = ( os.path.join(TestExtract.temp_extract_dir, 'package/first_level.txt'), os.path.join(TestExtract.temp_extract_dir, 'package/subfolder/second_level.txt'), ) for file in files_to_check: self.assertTrue(os.path.isfile(file), "File %s not found in extracted directory" + file) TestExtract.reset_test_dir() def test_extract_zip(self): self.assert_extract("package.zip") def test_extract_tar(self): self.assert_extract("package.tar.gz")
class TestManifestCreation(unittest.TestCase): test_asset = os.path.join(root_dir + '/tests/test_resources/test-repo') temp_working_dir = root_dir + '/tmp/temp-aip-dir-' + randomutils.randomword( 10) + "/" manifest_file = os.path.join(temp_working_dir, './manifest.mf') @classmethod def tearDownClass(cls): shutil.rmtree(TestManifestCreation.temp_working_dir) def test_create_manifest(self): manifest_creation = ManifestCreation( TestManifestCreation.temp_working_dir) manifest_creation.create_manifest(self.test_asset, self.manifest_file) self.assertTrue(os.path.isfile(self.manifest_file), "File not found in working directory") with open(TestManifestCreation.manifest_file, 'r') as json_file: json_manifest = json.load(json_file) self.assertEqual(67, len(json_manifest))
class TestExtraction(unittest.TestCase): test_resources_dir = os.path.join(root_dir, 'tests/test_resources') temp_extract_dir = '/tmp/backend-unzip-' + randomword(10) @classmethod def setUpClass(cls): os.makedirs(TestExtraction.temp_extract_dir) zip_container_test_resource_path = os.path.join( TestExtraction.test_resources_dir, "package.zip") shutil.copy(zip_container_test_resource_path, TestExtraction.temp_extract_dir) @classmethod def tearDownClass(cls): shutil.rmtree(TestExtraction.temp_extract_dir) pass def test_extract_sip(self): print("Extracting to %s" % self.temp_extract_dir) zip_container_file_path = os.path.join(TestExtraction.temp_extract_dir, "package.zip") container_folder = "package" zip_container = ZipContainer(zip_container_file_path) success = zip_container.unzip(TestExtraction.temp_extract_dir) self.assertTrue(success) cpt = sum([ len(files) for r, d, files in os.walk(TestExtraction.temp_extract_dir) ]) self.assertEqual(cpt, 3, "Number of extracted files not as expected") files_to_check = ( os.path.join(TestExtraction.temp_extract_dir, container_folder, './first_level.txt'), os.path.join(TestExtraction.temp_extract_dir, container_folder, './subfolder/second_level.txt'), ) for file in files_to_check: self.assertTrue(os.path.isfile(file), "File %s not found in extracted directory" + file)
class TestPairtreeStorage(unittest.TestCase): source_dir = root_dir + '/tests/test_resources/storage-test/' package_file = "bar.tar" repository_storage_dir = '/tmp/temp-' + randomutils.randomword(10) test_repo = root_dir + '/tests/test_resources/test-repo/' @classmethod def setUpClass(cls): if not os.path.exists(TestPairtreeStorage.repository_storage_dir): os.makedirs(TestPairtreeStorage.repository_storage_dir) shutil.copy( os.path.join(TestPairtreeStorage.test_repo, "pairtree_version0_1"), TestPairtreeStorage.repository_storage_dir) @classmethod def tearDownClass(cls): shutil.rmtree(TestPairtreeStorage.repository_storage_dir) def test_identifier_object_exists(self): pts = PairtreeStorage(TestPairtreeStorage.test_repo) existing_identifier = "bar" nonexisting_identifier = "foo" self.assertEqual(pts.identifier_object_exists(existing_identifier), True) self.assertEqual(pts.identifier_object_exists(nonexisting_identifier), False) def test_version_exists(self): pts = PairtreeStorage(TestPairtreeStorage.test_repo) identifier = "bar" self.assertEqual(pts.identifier_version_object_exists(identifier, 3), False) self.assertEqual(pts.identifier_version_object_exists(identifier, 2), True) def test_next_version(self): pts = PairtreeStorage(TestPairtreeStorage.test_repo) identifier = "bar" self.assertEqual("00003", pts._next_version(identifier)) def test_curr_version(self): pts = PairtreeStorage(TestPairtreeStorage.test_repo) identifier = "bar" self.assertEqual("00002", pts.curr_version(identifier)) def test_store(self): pts = PairtreeStorage(TestPairtreeStorage.repository_storage_dir) pts.store("xyz", os.path.join(self.source_dir)) self.assertEqual(1, pts.curr_version_num("xyz")) pts.store("xyz", os.path.join(self.source_dir)) self.assertEqual(2, pts.curr_version_num("xyz")) def test_get_object_path(self): pts = PairtreeStorage(TestPairtreeStorage.test_repo) expected = os.path.join(TestPairtreeStorage.test_repo, "pairtree_root/ba/r/data/00002/bar") actual = pts.get_object_path("bar") self.assertEqual(expected, actual) def test_read_tar_file_entry_as_chunks(self): pts = PairtreeStorage(TestPairtreeStorage.test_repo) identifier = "bar" entry = "739f9c5f-c402-42af-a18b-3d0bdc4e8751/METS.xml" chunked_tar_entry_reader = pts.get_chunked_tar_entry_reader(identifier) try: chunks = chunked_tar_entry_reader.chunks(entry) content = ''.join([chunk.decode('utf-8') for chunk in chunks]) self.assertTrue(content.startswith("<?xml")) except KeyError: raise ObjectNotFoundException( "Entry '%s' not found in package '%s'" % (entry, identifier)) finally: chunked_tar_entry_reader.close()
class TestUtils(unittest.TestCase): temp_extract_dir = '/tmp/backend-utils-' + randomword(10) @classmethod def setUpClass(cls): tests_dir = os.path.join(root_dir, 'tests/test_resources/package') shutil.copytree(tests_dir, TestUtils.temp_extract_dir) @classmethod def tearDownClass(cls): shutil.rmtree(TestUtils.temp_extract_dir) #pass def test_recursive_find_files_in_dir(self): def check_paths(retrieved_file_list, expected_paths): for retrieved_path in retrieved_file_list: self.assertTrue( retrieved_path in expected_paths, "Retrieved path %s not in expected list" % retrieved_path) for expected_path in expected_paths: self.assertTrue( expected_path in retrieved_file_list, "Expected path %s not in retrieved list" % expected_path) def check_excluded(retrieved_file_list, excluded_paths): for excluded_path in excluded_paths: self.assertTrue( excluded_path not in retrieved_file_list, "Excluded path %s appears in retrieved files list" % excluded_path) flist = list( rec_find_files(TestUtils.temp_extract_dir, include_files_rgxs=None, exclude_dirsfiles_rgxs=None)) self.assertEqual(len(flist), 6, "Number of files not as expected") check_paths( flist, expected_paths=( os.path.join(TestUtils.temp_extract_dir, 'first_level.txt'), os.path.join(TestUtils.temp_extract_dir, 'subfolder/second_level.txt'), os.path.join(TestUtils.temp_extract_dir, 'subfolder/screen.png'), os.path.join(TestUtils.temp_extract_dir, 'subfolder/second_level.csv'), os.path.join(TestUtils.temp_extract_dir, 'subfolder/subsubfolder/third_level.txt'), os.path.join( TestUtils.temp_extract_dir, 'subfolder/subsubfolder/subsubsubfolder/fourth_level.txt'), )) with self.assertRaises(AssertionError): list( rec_find_files(TestUtils.temp_extract_dir, include_files_rgxs="*.txt", exclude_dirsfiles_rgxs=None)) flist = list( rec_find_files(TestUtils.temp_extract_dir, include_files_rgxs=[r'.*\.txt$'], exclude_dirsfiles_rgxs=None)) check_paths( flist, expected_paths=( os.path.join(TestUtils.temp_extract_dir, 'first_level.txt'), os.path.join(TestUtils.temp_extract_dir, 'subfolder/second_level.txt'), os.path.join(TestUtils.temp_extract_dir, 'subfolder/subsubfolder/third_level.txt'), os.path.join( TestUtils.temp_extract_dir, 'subfolder/subsubfolder/subsubsubfolder/fourth_level.txt'), )) check_excluded(flist, excluded_paths=(os.path.join(TestUtils.temp_extract_dir, 'subfolder/screen.png'), )) flist = list( rec_find_files(TestUtils.temp_extract_dir, include_files_rgxs=[r'.*\.txt$', r'.*\.csv$'], exclude_dirsfiles_rgxs=None)) check_paths( flist, expected_paths=( os.path.join(TestUtils.temp_extract_dir, 'first_level.txt'), os.path.join(TestUtils.temp_extract_dir, 'subfolder/second_level.txt'), os.path.join(TestUtils.temp_extract_dir, 'subfolder/second_level.csv'), os.path.join(TestUtils.temp_extract_dir, 'subfolder/subsubfolder/third_level.txt'), os.path.join( TestUtils.temp_extract_dir, 'subfolder/subsubfolder/subsubsubfolder/fourth_level.txt'), )) check_excluded(flist, excluded_paths=(os.path.join(TestUtils.temp_extract_dir, 'subfolder/screen.png'), )) flist = list( rec_find_files(TestUtils.temp_extract_dir, include_files_rgxs=[r'.*\.txt$', r'.*\.csv$'], exclude_dirsfiles_rgxs=[r'.*/subfolder.*'])) check_paths(flist, expected_paths=(os.path.join(TestUtils.temp_extract_dir, 'first_level.txt'), )) flist = list( rec_find_files(TestUtils.temp_extract_dir, include_files_rgxs=[r'.*\.txt$'], exclude_dirsfiles_rgxs=[r'.*first_level.txt$'])) check_paths( flist, expected_paths=( os.path.join(TestUtils.temp_extract_dir, 'subfolder/second_level.txt'), os.path.join(TestUtils.temp_extract_dir, 'subfolder/subsubfolder/third_level.txt'), os.path.join( TestUtils.temp_extract_dir, 'subfolder/subsubfolder/subsubsubfolder/fourth_level.txt'), )) flist = list( rec_find_files(TestUtils.temp_extract_dir, include_files_rgxs=[r'.*\.txt$'], exclude_dirsfiles_rgxs=[ r'.*first_level.txt$', r'.*/subsubfolder.*' ])) check_paths( flist, expected_paths=(os.path.join(TestUtils.temp_extract_dir, 'subfolder/second_level.txt'), ))
class TestDirectoryPairtreeStorage(unittest.TestCase): source_dir = os.path.join(root_dir, 'tests/test_resources/storage-test') test_repo_resources = os.path.join(root_dir, 'tests/test_resources/test-repo/') tmp_test_directory = os.path.join(root_dir, 'tmp/temp-' + randomutils.randomword(10)) tmp_test_repo = os.path.join(tmp_test_directory, "test-repo") @classmethod def setUpClass(cls): os.makedirs(TestDirectoryPairtreeStorage.tmp_test_directory) shutil.copytree( TestDirectoryPairtreeStorage.test_repo_resources, os.path.join(TestDirectoryPairtreeStorage.tmp_test_repo)) @classmethod def tearDownClass(cls): #shutil.rmtree(TestDirectoryPairtreeStorage.tmp_test_directory) pass def test_identifier_object_exists(self): pts = DirectoryPairtreeStorage( TestDirectoryPairtreeStorage.tmp_test_repo) existing_identifier = "bar" nonexisting_identifier = "xyz" self.assertEqual(pts.identifier_object_exists(existing_identifier), True) self.assertEqual(pts.identifier_object_exists(nonexisting_identifier), False) def test_version_exists(self): pts = DirectoryPairtreeStorage( TestDirectoryPairtreeStorage.tmp_test_repo) identifier = "bar" version1_exists = pts.identifier_version_object_exists(identifier, 1) self.assertEqual(version1_exists, True) version2_exists = pts.identifier_version_object_exists(identifier, 2) self.assertEqual(version2_exists, True) version3_exists = pts.identifier_version_object_exists(identifier, 3) self.assertEqual(version3_exists, False) def test_next_version(self): pts = DirectoryPairtreeStorage( TestDirectoryPairtreeStorage.tmp_test_repo) identifier = "bar" next_version_dirname = pts._next_version(identifier) self.assertEqual("00003", next_version_dirname) def test_curr_version(self): pts = DirectoryPairtreeStorage( TestDirectoryPairtreeStorage.tmp_test_repo) identifier = "bar" self.assertEqual("00002", pts.curr_version(identifier)) def test_store(self): pts = DirectoryPairtreeStorage( TestDirectoryPairtreeStorage.tmp_test_repo) pts.store("foo", TestDirectoryPairtreeStorage.source_dir) self.assertEqual(1, pts.curr_version_num("foo")) pts.store("foo", TestDirectoryPairtreeStorage.source_dir) self.assertEqual(2, pts.curr_version_num("foo")) def test_get_object_path(self): pts = DirectoryPairtreeStorage( TestDirectoryPairtreeStorage.tmp_test_repo) expected = os.path.join(TestDirectoryPairtreeStorage.tmp_test_repo, "pairtree_root/ba/r/data/00002/bar") actual = pts.get_object_path("bar") self.assertEqual(expected, actual) def test_get_object_item_stream(self): pts = DirectoryPairtreeStorage( TestDirectoryPairtreeStorage.tmp_test_repo) tar_file_path = pts.get_tar_file_path("bar", "default") self.assertTrue(os.path.exists(tar_file_path)) tar_file = tarfile.open(tar_file_path, 'r') content = pts.get_object_item_stream("bar", "default", "default/data/example.txt", tar_file=tar_file) content_chunk = next(content) content_chunk_text = content_chunk.decode('utf-8') self.assertTrue(content_chunk_text.startswith("text file content")) tar_file.close() def test_store_versions_single_package(self): pts = DirectoryPairtreeStorage( TestDirectoryPairtreeStorage.tmp_test_repo) source_dir_opq = os.path.join(root_dir, 'tests/test_resources/storage-test-opq') version = pts.store("opq", source_dir_opq) self.assertEqual("00001", version) tar_file_path = pts.get_tar_file_path("opq") self.assertTrue(os.path.exists(tar_file_path)) version = pts.store("opq", source_dir_opq) self.assertEqual("00002", version) tar_file_path = pts.get_tar_file_path("opq") self.assertTrue(os.path.exists(tar_file_path)) def test_store_versions_packaged_distributions(self): pts = DirectoryPairtreeStorage( TestDirectoryPairtreeStorage.tmp_test_repo) version = pts.store("xyz", TestDirectoryPairtreeStorage.source_dir, single_package=False) self.assertEqual("00001", version) tar_file_path = pts.get_tar_file_path("xyz") self.assertTrue(os.path.exists(tar_file_path)) def test_store_versions_packaged_distribution_versions(self): pts = DirectoryPairtreeStorage( TestDirectoryPairtreeStorage.tmp_test_repo, representations_directory="distributions") # store first version abc1_src_dir = os.path.join( root_dir, 'tests/test_resources/distributionpackages/abc1') version = pts.store("abc", abc1_src_dir, single_package=False) self.assertEqual("00001", version) distr_tar_file_path = pts.get_tar_file_path("abc", "default") self.assertTrue(os.path.exists(distr_tar_file_path)) tar_file = tarfile.open(distr_tar_file_path, 'r') content = pts.get_object_item_stream(identifier="bar", entry="default/data/example.txt", representation_label="default", tar_file=tar_file) # read text file contained in the distribution content_chunk = next(content) content_chunk_text = content_chunk.decode('utf-8') self.assertTrue(content_chunk_text.startswith("text file content")) tar_file.close() # store second version (packaged distribution differs from first one) abc2_src_dir = os.path.join( root_dir, 'tests/test_resources/distributionpackages/abc2') version = pts.store("abc", abc2_src_dir, single_package=False) self.assertEqual("00002", version)
class TestPremisCreation(unittest.TestCase): test_ip = "eark-ip" test_ip_mig = "eark-ip-mig" test_source_directory = os.path.join(root_dir + '/tests/test_resources/') temp_working_dir = os.path.join(root_dir, "tmp/tmp-%s" % randomutils.randomword(10)) tmp_ip_dir = os.path.join(temp_working_dir, test_ip) tmp_ip_dir_mig = os.path.join(temp_working_dir, test_ip_mig) test_ip_dir = os.path.join(test_source_directory, test_ip) test_ip_dir_mig = os.path.join(test_source_directory, test_ip_mig) premis_file_path = os.path.join(temp_working_dir, test_ip, './metadata/preservation/premis.xml') premis_schema_file = os.path.join( root_dir, 'tests/test_resources/schemas/premis-v2-2.xsd') @classmethod def setUpClass(cls): shutil.copytree(TestPremisCreation.test_ip_dir, TestPremisCreation.tmp_ip_dir) shutil.copytree(TestPremisCreation.test_ip_dir_mig, TestPremisCreation.tmp_ip_dir_mig) @classmethod def tearDownClass(cls): shutil.rmtree(TestPremisCreation.temp_working_dir) pass def validate_xml(self, file, premis_schema_file): validation_errors = [] xmlschema = etree.XMLSchema(etree.parse(premis_schema_file)) try: xmlschema.assertValid(etree.parse(file)) print('Validation result: %s' % xmlschema.validate(etree.parse(file))) except etree.XMLSyntaxError as e: validation_errors.append(str(e)) if len(validation_errors) > 0: print(validation_errors) def test_create_premis(self): premisgen = PremisGenerator(TestPremisCreation.tmp_ip_dir) premisgen.createPremis() self.validate_xml(TestPremisCreation.premis_file_path, TestPremisCreation.premis_schema_file) def test_reate_migration_premis(self): premisgen = PremisGenerator(TestPremisCreation.tmp_ip_dir_mig) premis_info = { 'info': '%s/representations/repr1_mig-1/metadata/preservation/premis.xml' % TestPremisCreation.tmp_ip_dir_mig } premisgen.createMigrationPremis(premis_info) premis = '%s/representations/repr1_mig-1/metadata/preservation/premis.xml' % TestPremisCreation.tmp_ip_dir_mig self.validate_xml(premis, TestPremisCreation.premis_schema_file) def test_add_premis_event(self): premisgen = PremisGenerator(TestPremisCreation.tmp_ip_dir_mig) premisinfo = { 'outcome': 'success', 'task_name': 'SIPValidation', 'event_type': 'SIP validation', 'linked_object': 'this-is-a-package-id' } premisgen.addEvent('metadata/preservation/premis.xml', premisinfo) premis = '%s/metadata/preservation/premis.xml' % TestPremisCreation.tmp_ip_dir_mig self.validate_xml(premis, TestPremisCreation.premis_schema_file)
def get_basic_metadata(request, file_path): user_data_path = os.path.join(ip_data_path, request.user.username) vars = environment_variables(request) if not vars['selected_ip']: return {} selected_ip = vars['selected_ip'] print(file_path) archive_file_path = os.path.join(user_data_path, selected_ip.ip_filename) t = tarfile.open(archive_file_path, 'r') file_content = read_textfile_from_tar(t, file_path) tmp_file_path = "/tmp/%s" % randomword(10) res_events = [] try: title = "" date = "" with open(tmp_file_path, 'w') as tmp_file: tmp_file.write(file_content) if fnmatch.fnmatch(file_path, metadata_file_pattern_ead): pead = ParsedEad("/tmp", tmp_file_path) dao_elements = pead.get_dao_elements() actual = pead.ead_tree.getroot().tag unit_titles = [] unit_dates = [] for dao_elm in dao_elements: unit_titles.append( pead._first_md_val_ancpath(dao_elm, "unittitle")) unit_dates.append( pead._first_md_val_ancpath(dao_elm, "unitdate")) title = unit_titles[0] date = unit_dates[0] events = "" elif fnmatch.fnmatch(file_path, metadata_file_pattern_premis): structure = get_ip_structure(request) logical_view = search(structure, "logical_view_data") events = search(logical_view, "events") for event in events: if len(event): res_events.append({ 'type': event[0]['type'], 'datetime': event[0]['datetime'], 'agent': event[0]['linking_agent_id']['value'] }) title = "Root PREMIS" date = "20.09.2017" md_type = ead_md_type if fnmatch.fnmatch(file_path, metadata_file_pattern_ead) \ else premis_md_type if fnmatch.fnmatch(file_path, metadata_file_pattern_premis) else "Other" return JsonResponse( { 'success': True, 'type': md_type, 'title': title, 'date': date, 'events': res_events, 'file_path': file_path }, status=200) except Exception as error: logger.exception(error) return JsonResponse({ 'success': False, 'error': str(error) }, status=500)