From 86fb42c6f6b6ec55104a24a2857eddc1664b8fa5 Mon Sep 17 00:00:00 2001 From: mst Date: Tue, 26 Nov 2024 15:16:42 +0300 Subject: [PATCH] add import/export functions --- functions.py | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/functions.py b/functions.py index 53f453b..d4e9187 100644 --- a/functions.py +++ b/functions.py @@ -528,6 +528,156 @@ def generateFavicon(file_name): resized_img_absolute_path = const.faviconDir / filename resized_img.save(resized_img_absolute_path) +def createExport(): + try: + # just to test if connection works + conn = connectToDb() + conn.close() + + timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + timestamp_morereadable = datetime.now().strftime('%b %d, %Y %H:%M') + export_dir = const.exportsDir + temp_dir = const.tempDir + os.makedirs(export_dir, exist_ok=True) + os.makedirs(temp_dir, exist_ok=True) + + config_dest_path = temp_dir / const.configFile + shutil.copy(const.configFile, config_dest_path) + + # Export database to SQL file + dump_file = temp_dir / 'database.sql' + result = subprocess.Popen( + f'mysqldump --quote-names -u {dbUser} -p{dbPass} {dbName} --result-file={dump_file}', + stdin=subprocess.PIPE, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + encoding="utf-8" + ) + # absolutely dumb workaround for an error + time.sleep(1) + + # Create export zip archive + zip_file_path = export_dir / f'export-{timestamp}.zip' + with zipfile.ZipFile(zip_file_path, 'w') as export_zip: + export_zip.write(config_dest_path, arcname=const.configFile) + export_zip.write(dump_file, arcname='database.sql') + + # Add favicon and emojis folders to the zip archive + favicon_dir = Path('static/icons/favicon') + emojis_dir = Path('static/emojis') + + if favicon_dir.exists(): + for root, _, files in os.walk(favicon_dir): + for file in files: + file_path = Path(root) / file + export_zip.write(file_path, arcname=file_path.relative_to(favicon_dir.parent.parent)) + + if emojis_dir.exists(): + for root, _, files in os.walk(emojis_dir): + for file in files: + file_path = Path(root) / file + export_zip.write(file_path, arcname=file_path.relative_to(emojis_dir.parent)) + + # Record export metadata + export_data = { + 'timestamp_esc': timestamp, + 'timestamp': timestamp_morereadable, + 'downloadPath': str(zip_file_path) + } + appendToJSON(export_data, const.exportsFile) + shutil.rmtree(temp_dir) + + return {'message': 'Export created successfully!'} + except mysql.connector.Error as e: + return {'error': str(e)}, 500 + except Exception as e: + return {'error': str(e)}, 500 + + +def importData(export_file): + try: + shutil.unpack_archive(export_file, const.tempDir) + + # Replace config file + os.remove(const.configFile) + shutil.move(const.tempDir / const.configFile, Path.cwd() / const.configFile) + + # Replace favicon and emojis folders + favicon_dest = Path('static/icons/favicon') + emojis_dest = Path('static/emojis') + + shutil.rmtree(favicon_dest) + shutil.copytree(const.tempDir / 'icons' / 'favicon', favicon_dest) + + shutil.rmtree(emojis_dest) + shutil.copytree(const.tempDir / 'emojis', emojis_dest) + + # Restore database from SQL file + conn = connectToDb() + cursor = conn.cursor() + + with open(const.tempDir / 'database.sql', 'r') as schema_file: + try: + # for some reason `cursor.execute(schema, multi=True)` doesn't work, so we use this instead + schema = schema_file.read() + queries = schema.split(';') + for query in queries: + cursor.execute(query) + except mysql.connector.Error as e: + return {'error': str(e)}, 500 + finally: + cursor.close() + conn.close() + shutil.rmtree(const.tempDir) + + return {'message': 'Data imported successfully!'} + except Exception as e: + return {'error': str(e)}, 500 + +# will probably get to it in 1.8.0 because my brain can't do it rn +""" +def retrospringImport(export_file): + shutil.unpack_archive(export_file, const.tempDir) + # probably a hack but whateva + export_dirname = Path(export_file).stem + export_dir = const.tempDir / export_dirname + + conn = connectToDb() + cursor = conn.cursor() + + questions_file = loadJSON(export_dir / 'questions.json') + answers_file = loadJSON(export_dir / 'answers.json') + + # Extract answers list + questions_list = questions_file.get('questions', []) + answers_list = answers_file.get('answers', []) + # ['related']['question']['anonymous'] + + for question in questions_list: + # addQuestion(answer['related']['question']['anonymous'], question['content'], None, noAntispam=True) + for answer in answers_list: + print("anonymous:", answer['related']['question']['anonymous']) + print(question['id'], answer['content'], None) + # addAnswer(question['id'], answer['content'], None) + + # shutil.rmtree(const.tempDir) + + cursor.close() + conn.close() +""" + +def deleteExport(timestamp): + try: + export_file = Path('static') / 'exports' / f'export-{timestamp}.zip' + data = loadJSON(const.exportsFile) + data = [export for export in data if export["timestamp_esc"] != timestamp] + export_file.unlink() + saveJSON(data, const.exportsFile) + return {'message': f'Export {timestamp} deleted successfully.'} + except Exception as e: + return {'error': str(e)}, 500 + # reserved for 1.7.0 or later """ def getUserIp():