mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-01-28 05:20:57 +01:00
- **Backend Refactor:** - Merged route and operation files for regex and format. - Updated directory structure and consolidated utility functions. - Removed unnecessary app.py, using `__init__.py` for app creation. - **Git Integration:** - Enhanced git cloning and merging methods, ensuring accurate local file updates. - Implemented comprehensive git status fetching with improved file status display and error handling. - Added branch management features, including branch creation, checkout, deletion, and associated UI improvements. - Integrated loading indicators and fun messages for better user feedback during git operations. - **Settings Manager Enhancements:** - Expanded Git status display, including connected repository link, branch information, and detailed change listings. - Added revert functionality for individual files and all changes, with conditional UI updates based on file statuses. - Integrated `react-toastify` for alert notifications with improved styling. - Improved file name parsing, handling of file paths, and consistent API request structure. - Added UI components for a smooth tab transition and enhanced settings layout. - **General Improvements:** - Revised sanitization logic for less aggressive handling, particularly for regex101 links. - Refactored backend logic to improve performance, specifically optimizing git status checks. - Implemented dynamic retrieval of default branches and enhanced handling of IDs in files. **fixes, refactors, and additional features included**: - Bug fixes for branch handling, git status accuracy, and file name adjustments. - Improved error handling, logging, and user feedback across various components.
130 lines
4.3 KiB
Python
130 lines
4.3 KiB
Python
from flask import Blueprint, request, jsonify
|
|
from collections import OrderedDict
|
|
import os
|
|
import yaml
|
|
import logging
|
|
from .utils import get_next_id, generate_filename, get_current_timestamp, sanitize_input
|
|
|
|
bp = Blueprint('format', __name__, url_prefix='/format')
|
|
FORMAT_DIR = os.path.join('data', 'db', 'custom_formats')
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
@bp.route('', methods=['GET', 'POST'])
|
|
def handle_formats():
|
|
if request.method == 'POST':
|
|
data = request.json
|
|
saved_data = save_format(data)
|
|
return jsonify(saved_data), 201
|
|
else:
|
|
formats = load_all_formats()
|
|
return jsonify(formats)
|
|
|
|
@bp.route('/<int:id>', methods=['GET', 'PUT', 'DELETE'])
|
|
def handle_format(id):
|
|
if request.method == 'GET':
|
|
format = load_format(id)
|
|
if format:
|
|
return jsonify(format)
|
|
return jsonify({"error": "Format not found"}), 404
|
|
elif request.method == 'PUT':
|
|
data = request.json
|
|
data['id'] = id
|
|
saved_data = save_format(data)
|
|
return jsonify(saved_data)
|
|
elif request.method == 'DELETE':
|
|
if delete_format(id):
|
|
return jsonify({"message": f"Format with ID {id} deleted."}), 200
|
|
return jsonify({"error": f"Format with ID {id} not found."}), 404
|
|
|
|
def save_format(data):
|
|
logger.info("Received data for saving format: %s", data)
|
|
|
|
# Sanitize and extract necessary fields
|
|
name = sanitize_input(data.get('name', ''))
|
|
description = sanitize_input(data.get('description', ''))
|
|
format_id = data.get('id', None)
|
|
|
|
# Determine if this is a new format or an existing one
|
|
if format_id == 0 or not format_id:
|
|
format_id = get_next_id(FORMAT_DIR)
|
|
logger.info("Assigned new format ID: %d", format_id)
|
|
date_created = get_current_timestamp()
|
|
else:
|
|
existing_filename = os.path.join(FORMAT_DIR, f"{format_id}.yml")
|
|
if os.path.exists(existing_filename):
|
|
existing_data = load_format(format_id)
|
|
date_created = existing_data.get('date_created', get_current_timestamp())
|
|
else:
|
|
raise FileNotFoundError(f"No existing file found for ID: {format_id}")
|
|
|
|
date_modified = get_current_timestamp()
|
|
|
|
# Process conditions
|
|
conditions = []
|
|
for condition in data.get('conditions', []):
|
|
logger.info("Processing condition: %s", condition)
|
|
cond_dict = OrderedDict([
|
|
('type', condition['type']),
|
|
('name', sanitize_input(condition['name'])),
|
|
('negate', condition.get('negate', False)),
|
|
('required', condition.get('required', False))
|
|
])
|
|
if condition['type'] == 'regex':
|
|
cond_dict['regex_id'] = condition['regex_id']
|
|
elif condition['type'] == 'size':
|
|
cond_dict['min'] = condition['min']
|
|
cond_dict['max'] = condition['max']
|
|
elif condition['type'] == 'flag':
|
|
cond_dict['flag'] = sanitize_input(condition['flag'])
|
|
conditions.append(cond_dict)
|
|
|
|
# Process tags
|
|
tags = [sanitize_input(tag) for tag in data.get('tags', [])]
|
|
|
|
# Construct the ordered data
|
|
ordered_data = OrderedDict([
|
|
('id', format_id),
|
|
('name', name),
|
|
('description', description),
|
|
('date_created', str(date_created)),
|
|
('date_modified', str(date_modified)),
|
|
('conditions', conditions),
|
|
('tags', tags)
|
|
])
|
|
|
|
# Generate the filename using only the ID
|
|
filename = os.path.join(FORMAT_DIR, f"{format_id}.yml")
|
|
|
|
# Write to the file
|
|
with open(filename, 'w') as file:
|
|
yaml.dump(ordered_data, file, default_flow_style=False, Dumper=yaml.SafeDumper)
|
|
|
|
return ordered_data
|
|
|
|
def load_format(id):
|
|
filename = os.path.join(FORMAT_DIR, f"{id}.yml")
|
|
if os.path.exists(filename):
|
|
with open(filename, 'r') as file:
|
|
data = yaml.safe_load(file)
|
|
return data
|
|
return None
|
|
|
|
|
|
def load_all_formats():
|
|
formats = []
|
|
for filename in os.listdir(FORMAT_DIR):
|
|
if filename.endswith('.yml'):
|
|
with open(os.path.join(FORMAT_DIR, filename), 'r') as file:
|
|
data = yaml.safe_load(file)
|
|
formats.append(data)
|
|
return formats
|
|
|
|
def delete_format(id):
|
|
filename = os.path.join(FORMAT_DIR, f"{id}.yml")
|
|
if os.path.exists(filename):
|
|
os.remove(filename)
|
|
return True
|
|
return False
|