import os import re import logging from packaging import version from flask import current_app logger = logging.getLogger(__name__) class ContentManager: def __init__(self, app=None): self.app = app if app: self.init_app(app) def init_app(self, app): self.app = app # Controleer of het pad bestaat if not os.path.exists(app.config['CONTENT_DIR']): logger.warning(f"Content directory not found at: {app.config['CONTENT_DIR']}") else: logger.info(f"Content directory configured at: {app.config['CONTENT_DIR']}") def get_content_path(self, content_type, major_minor=None, patch=None): """ Geef het volledige pad naar een contentbestand Args: content_type (str): Type content (bv. 'changelog', 'terms') major_minor (str, optional): Major.Minor versie (bv. '1.0') patch (str, optional): Patchnummer (bv. '5') Returns: str: Volledige pad naar de content map of bestand """ content_path = os.path.join(self.app.config['CONTENT_DIR'], content_type) if major_minor: content_path = os.path.join(content_path, major_minor) if patch: content_path = os.path.join(content_path, f"{major_minor}.{patch}.md") return content_path def _parse_version(self, filename): """Parse een versienummer uit een bestandsnaam""" match = re.match(r'(\d+\.\d+)\.(\d+)\.md', filename) if match: return match.group(1), match.group(2) return None, None def get_latest_version(self, content_type, major_minor=None): """ Verkrijg de laatste versie van een bepaald contenttype Args: content_type (str): Type content (bv. 'changelog', 'terms') major_minor (str, optional): Specifieke major.minor versie, anders de hoogste Returns: tuple: (major_minor, patch, full_version) of None als niet gevonden """ try: # Basispad voor dit contenttype content_path = os.path.join(self.app.config['CONTENT_DIR'], content_type) if not os.path.exists(content_path): logger.error(f"Content path does not exist: {content_path}") return None # Als geen major_minor opgegeven, vind de hoogste if not major_minor: available_versions = os.listdir(content_path) if not available_versions: return None # Sorteer op versienummer (major.minor) available_versions.sort(key=lambda v: version.parse(v)) major_minor = available_versions[-1] # Nu we major_minor hebben, zoek de hoogste patch major_minor_path = os.path.join(content_path, major_minor) if not os.path.exists(major_minor_path): logger.error(f"Version path does not exist: {major_minor_path}") return None files = os.listdir(major_minor_path) version_files = [] for file in files: mm, p = self._parse_version(file) if mm == major_minor and p: version_files.append((mm, p, f"{mm}.{p}")) if not version_files: return None # Sorteer op patch nummer version_files.sort(key=lambda v: int(v[1])) return version_files[-1] except Exception as e: logger.error(f"Error finding latest version for {content_type}: {str(e)}") return None def read_content(self, content_type, major_minor=None, patch=None): """ Lees content met versieondersteuning Als major_minor en patch niet zijn opgegeven, wordt de laatste versie gebruikt. Als alleen major_minor is opgegeven, wordt de laatste patch van die versie gebruikt. Args: content_type (str): Type content (bv. 'changelog', 'terms') major_minor (str, optional): Major.Minor versie (bv. '1.0') patch (str, optional): Patchnummer (bv. '5') Returns: dict: { 'content': str, 'version': str, 'content_type': str } of None bij fout """ try: # Als geen versie opgegeven, vind de laatste if not major_minor: version_info = self.get_latest_version(content_type) if not version_info: logger.error(f"No versions found for {content_type}") return None major_minor, patch, full_version = version_info # Als geen patch opgegeven, vind de laatste patch voor deze major_minor elif not patch: version_info = self.get_latest_version(content_type, major_minor) if not version_info: logger.error(f"No versions found for {content_type} {major_minor}") return None major_minor, patch, full_version = version_info else: full_version = f"{major_minor}.{patch}" # Nu hebben we major_minor en patch, lees het bestand file_path = self.get_content_path(content_type, major_minor, patch) if not os.path.exists(file_path): logger.error(f"Content file does not exist: {file_path}") return None with open(file_path, 'r', encoding='utf-8') as file: content = file.read() return { 'content': content, 'version': full_version, 'content_type': content_type } except Exception as e: logger.error(f"Error reading content {content_type} {major_minor}.{patch}: {str(e)}") return None def list_content_types(self): """Lijst alle beschikbare contenttypes op""" try: return [d for d in os.listdir(self.app.config['CONTENT_DIR']) if os.path.isdir(os.path.join(self.app.config['CONTENT_DIR'], d))] except Exception as e: logger.error(f"Error listing content types: {str(e)}") return [] def list_versions(self, content_type): """ Lijst alle beschikbare versies voor een contenttype Returns: list: Lijst van dicts met versie-informatie [{'version': '1.0.0', 'path': '/path/to/file', 'date_modified': datetime}] """ versions = [] try: content_path = os.path.join(self.app.config['CONTENT_DIR'], content_type) if not os.path.exists(content_path): return [] for major_minor in os.listdir(content_path): major_minor_path = os.path.join(content_path, major_minor) if not os.path.isdir(major_minor_path): continue for file in os.listdir(major_minor_path): mm, p = self._parse_version(file) if mm and p: file_path = os.path.join(major_minor_path, file) mod_time = os.path.getmtime(file_path) versions.append({ 'version': f"{mm}.{p}", 'path': file_path, 'date_modified': mod_time }) # Sorteer op versienummer versions.sort(key=lambda v: version.parse(v['version'])) return versions except Exception as e: logger.error(f"Error listing versions for {content_type}: {str(e)}") return []