Auto-sync from website-creator
This commit is contained in:
213
skills/website-creator/scripts/umami_integration.py
Normal file
213
skills/website-creator/scripts/umami_integration.py
Normal file
@@ -0,0 +1,213 @@
|
||||
#!/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'<script defer src="{self.umami_url}/script.js" data-website-id="{website_id}"></script>'
|
||||
|
||||
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 </head>
|
||||
tracking_script = self._get_tracking_script(website_id)
|
||||
|
||||
if '</head>' in content:
|
||||
# Insert before </head>
|
||||
indent = ' '
|
||||
content = content.replace(
|
||||
'</head>',
|
||||
f'{indent}{tracking_script}\n </head>'
|
||||
)
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user