#!/usr/bin/env python3 """ Umami Integration Helper Integrates Umami Analytics into website creation workflow. Auto-creates Umami website and adds tracking to Astro layout. """ import os import sys import requests from typing import Dict, Optional, Tuple from datetime import datetime class UmamiIntegration: """Handle Umami website creation and tracking integration""" def __init__(self, umami_url: str, username: str, password: str): """ Initialize Umami integration Args: umami_url: Umami instance URL username: Umami username password: Umami password """ self.umami_url = umami_url.rstrip('/') self.api_url = f"{self.umami_url}/api" self.username = username self.password = password self.token = None self.user_id = None def login(self) -> Tuple[bool, str]: """Login to Umami""" try: url = f"{self.api_url}/auth/login" data = {'username': self.username, 'password': self.password} response = requests.post(url, json=data, timeout=10) response.raise_for_status() result = response.json() if 'token' in result: self.token = result['token'] self.user_id = result.get('user', {}).get('id') return True, "Login successful" else: return False, "No token in response" except requests.exceptions.RequestException as e: return False, f"Login failed: {str(e)}" def create_website(self, website_name: str, website_domain: str) -> Tuple[bool, Dict]: """ Create Umami website Args: website_name: Name for Umami website website_domain: Website domain Returns: (success, result_dict) """ # Login first success, message = self.login() if not success: return False, {'error': message} try: # Create website url = f"{self.api_url}/websites" data = {'name': website_name, 'domain': website_domain} headers = { 'Authorization': f'Bearer {self.token}', 'Content-Type': 'application/json' } response = requests.post(url, json=data, headers=headers, timeout=10) response.raise_for_status() result = response.json() return True, { 'website_id': result.get('id'), 'name': result.get('name'), 'domain': result.get('domain'), 'tracking_script': self._get_tracking_script(result.get('id')) } except requests.exceptions.RequestException as e: return False, {'error': f"Create website failed: {str(e)}"} def _get_tracking_script(self, website_id: str) -> str: """Generate tracking script HTML""" return f'' def add_tracking_to_layout(self, layout_file: str, website_id: str) -> Tuple[bool, str]: """ Add Umami tracking to Astro layout Args: layout_file: Path to Astro layout file website_id: Umami website ID Returns: (success, message) """ try: if not os.path.exists(layout_file): return False, f"Layout file not found: {layout_file}" # Read layout with open(layout_file, 'r', encoding='utf-8') as f: content = f.read() # Add tracking before tracking_script = self._get_tracking_script(website_id) if '' in content: # Insert before indent = ' ' content = content.replace( '', f'{indent}{tracking_script}\n ' ) else: # Add at end content += f'\n{tracking_script}\n' # Write back with open(layout_file, 'w', encoding='utf-8') as f: f.write(content) return True, f"Tracking added to {layout_file}" except Exception as e: return False, f"Failed to add tracking: {str(e)}" def setup_umami_for_website( umami_url: str, username: str, password: str, website_name: str, website_domain: str, website_repo: str ) -> Tuple[bool, Dict]: """ Complete Umami setup for new website Args: umami_url: Umami instance URL username: Umami username password: Umami password website_name: Name for website website_domain: Website domain website_repo: Path to website repository Returns: (success, result_dict) """ print(f"\nšŸ“ˆ Setting up Umami Analytics...") print(f" URL: {umami_url}") print(f" Website: {website_name}") # Initialize integration umami = UmamiIntegration(umami_url, username, password) # Step 1: Create Umami website print(f" Creating Umami website...") success, result = umami.create_website(website_name, website_domain) if not success: print(f" āœ— Failed: {result.get('error', 'Unknown error')}") return False, result website_id = result.get('website_id') print(f" āœ“ Created: {website_id}") # Step 2: Add tracking to Astro layout print(f" Adding tracking to website...") # Find layout file layout_paths = [ os.path.join(website_repo, 'src/layouts/BaseHead.astro'), os.path.join(website_repo, 'src/layouts/Layout.astro'), os.path.join(website_repo, 'src/pages/_document.tsx') ] layout_file = None for path in layout_paths: if os.path.exists(path): layout_file = path break if layout_file: success, message = umami.add_tracking_to_layout(layout_file, website_id) if success: print(f" āœ“ {message}") else: print(f" ⚠ {message}") else: print(f" ⚠ No layout file found - manual tracking setup required") return True, { 'website_id': website_id, 'name': website_name, 'domain': website_domain, 'tracking_script': result.get('tracking_script'), 'layout_updated': layout_file is not None }