- 🌐 Enhanced web interface for invoice emailing config management with GET/POST at '/data'. - 📝 Refactored Flask app to specialize as an invoice emailing utility. - 🔍 Improved read_yaml() to return data and error messages. - 📤 Enhanced write_yaml() for better YAML file handling. - 🛠️ Updated handle_data() to efficiently handle '/data' route with GET/POST methods. Note: Excluded changes to imports and requires.
113 lines
4.0 KiB
Python
113 lines
4.0 KiB
Python
"""
|
|
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)
|