""" Invoice Emailing Utility. Provides a web interface for managing invoice emailing configurations. Handles HTTP GET (view) and POST (update) at '/data' for configuration data, and serves the main app page at '/'. Author: Isaak Buslovich Date: 2023-12-21 """ from flask import Flask, request, jsonify, send_from_directory import yaml from pathlib import Path import logging app = Flask(__name__, static_folder='.', static_url_path='') logging.basicConfig(level=logging.INFO) DATA_FILE = 'config.yaml' def read_yaml(): """ Reads data from YAML file specified by DATA_FILE. Returns a tuple containing the data and error message. On success: Returns (data_dict, None), where data_dict contains 'email' and 'email_template'. On file not found: Logs a message and returns ({'email': {}, 'email_template': ''}, None). On error: Logs the specific error and returns (None, error_message), where error_message explains the issue. """ file_path = Path(DATA_FILE) try: if not file_path.is_file(): logging.info("YAML file not found. Returning empty data.") return {'email': {}, 'email_template': ''}, None with file_path.open() as file: data = yaml.safe_load(file) or {} return { 'email': data.get('email', {}), 'email_template': data.get('email_template', '') }, None except yaml.YAMLError as e: logging.error(f"YAML Error: {e}", exc_info=True) return None, f"YAML parsing error: {e}" except IOError as e: logging.error(f"IO Error: {e}", exc_info=True) return None, f"File I/O error: {e}" except Exception as e: logging.error(f"Unexpected Error: {e}", exc_info=True) return None, f"Unexpected error: {e}" def write_yaml(email_data, email_template_data): """ Writes email and template data to the YAML file defined by DATA_FILE. Args: email_data (dict): Email configuration settings. email_template_data (str): Email template content. Returns: tuple: (bool, str) indicating success status and an error message if any. Raises: Exception: Logs and returns error details upon failure. """ file_path = Path(DATA_FILE) try: with file_path.open('w') as file: yaml.dump({ 'email': email_data, 'email_template': email_template_data }, file) return True, None except Exception as e: logging.error(f"Error writing YAML file: {e}", exc_info=True) return False, f"Error writing file: {e}" @app.route('/data', methods=['GET', 'POST']) def handle_data(): """ Flask route handler function for '/data', accepting both GET and POST methods. - GET method: Reads and outputs data from the YAML configuration file. In case of errors, it returns a 500 status code with an error message. - POST method: Gets 'email' and 'email_template' data from the request, writes it to the YAML configuration file. In case of write errors, it returns a 500 status code with an error message. Otherwise, it returns a message stating the file was saved successfully with a 200 status code. """ if request.method == 'GET': data, error = read_yaml() if error: return jsonify({'success': False, 'message': error}), 500 return jsonify(data), 200 elif request.method == 'POST': email_data = request.json.get('email', {}) email_template_data = request.json.get('email_template', '') success, error = write_yaml(email_data, email_template_data) if error: return jsonify({'success': False, 'message': error}), 500 return jsonify({'success': True, 'message': "File saved successfully"}), 200 @app.route('/') def index(): """ Serves the main index HTML page. Returns: HTML content of the main page. """ return send_from_directory('.', 'index.html') if __name__ == '__main__': app.run(debug=True)