LifeRPG_v2.0/modern/backend/hooks.py
TLimoges33 7fe4ae5365
🧙‍♂️ Transform LifeRPG into The Wizard's Grimoire - Production-Ready Application
 Major Features Added:
- Complete magical theming and rebranding from LifeRPG to The Wizard's Grimoire
- Production-grade React frontend with Tailwind CSS v4 and magical aesthetics
- Comprehensive analytics dashboard with Recharts integration (ScryingPortal)
- Push notifications system with PWA service worker support
- Drag & drop functionality using @dnd-kit for habit reordering
- Social features with friends system and leaderboards
- Performance optimization tools and monitoring
- Mobile app enhancement with PWA installation support

🏗️ Technical Infrastructure:
- Advanced service worker with offline support and background sync
- Zustand state management for scalable application state
- Production-ready UI component system with enhanced Button, Card, Input
- Progressive Web App (PWA) with manifest and app installation
- FastAPI backend with comprehensive API endpoints
- Docker containerization and CI/CD pipeline setup

📱 Progressive Web App Features:
- Offline functionality with intelligent caching
- Push notification support for habit reminders
- App installation on mobile and desktop platforms
- Background sync for offline data management
- Performance monitoring and optimization tools

🎨 User Experience:
- Magical wizard/grimoire theming throughout application
- Responsive design optimized for all device sizes
- Drag & drop habit management with smooth animations
- Interactive analytics with multiple chart types
- Social connectivity with friends and competitive features
- Comprehensive notification and performance settings

🔧 Developer Experience:
- Modern development stack with Vite and React
- Comprehensive testing setup and CI/CD pipelines
- Code quality tools with pre-commit hooks
- Docker development environment
- Detailed documentation and implementation guides

This represents a complete transformation from prototype to production-ready application with enterprise-grade features and magical user experience.
2025-08-30 17:32:42 +00:00

121 lines
4.6 KiB
Python

from typing import Any, Dict, List
class Hook:
def run(self, *, db, integration_id: int, event: str, context: Dict[str, Any]):
raise NotImplementedError()
class SlackHook(Hook):
def __init__(self, preset_text: str | None = None):
self.preset_text = preset_text
def run(self, *, db, integration_id: int, event: str, context: Dict[str, Any]):
from .notifier import emit_sync_event
# Reuse existing slack notifier; include summary if preset_text provided
payload = {'provider': context.get('provider'), 'summary': {'count': context.get('count')}}
if self.preset_text:
payload['summary'] = {'text': self.preset_text}
try:
emit_sync_event(db, integration_id, event, payload)
except Exception:
pass
class WebhookHook(Hook):
def __init__(self, url: str, template: str | None = None, headers: Dict[str, str] | None = None):
self.url = url
self.template = template
self.headers = headers or {}
def run(self, *, db, integration_id: int, event: str, context: Dict[str, Any]):
from .notifier import send_webhook
body: Dict[str, Any]
if self.template:
try:
text = self.template.format(**context)
body = {'text': text, 'event': event, 'integration_id': integration_id}
except Exception:
body = {'event': event, 'integration_id': integration_id, 'context': context}
else:
body = {'event': event, 'integration_id': integration_id, 'context': context}
try:
send_webhook(self.url, body, headers=self.headers)
except Exception:
pass
class EmailHook(Hook):
def __init__(self, to: str, subject_template: str, body_template: str):
self.to = to
self.subject_template = subject_template
self.body_template = body_template
def run(self, *, db, integration_id: int, event: str, context: Dict[str, Any]):
from .notifier import send_email
try:
subj = self.subject_template.format(**context)
body = self.body_template.format(**context)
except Exception:
subj = f"LifeRPG {event} for integration {integration_id}"
body = str(context)
try:
send_email(self.to, subj, body)
except Exception:
pass
class HookManager:
def __init__(self, hooks_config: Dict[str, Any] | None):
self.cfg = hooks_config or {}
def _build_hooks(self, items: List[Dict[str, Any]]) -> List[Hook]:
hooks: List[Hook] = []
for it in items or []:
typ = (it.get('type') or '').lower()
if typ == 'slack':
hooks.append(SlackHook(preset_text=it.get('text')))
elif typ == 'webhook':
hooks.append(WebhookHook(url=it.get('url', ''), template=it.get('template'), headers=it.get('headers')))
elif typ == 'email':
hooks.append(EmailHook(to=it.get('to', ''), subject_template=it.get('subject', 'LifeRPG {event}'), body_template=it.get('body', '{context}')))
return hooks
def run_pre(self, *, db, integration_id: int, context: Dict[str, Any]):
pre = self._build_hooks(self.cfg.get('pre_sync', []))
for h in pre:
try:
h.run(db=db, integration_id=integration_id, event='pre_sync', context=context)
except Exception:
continue
def run_post(self, *, db, integration_id: int, status: str, context: Dict[str, Any]):
# Filter post hooks by 'on' condition (success, fail, always)
items = self.cfg.get('post_sync', [])
selected: List[Dict[str, Any]] = []
for it in items:
on = (it.get('on') or 'always').lower()
if on == 'always' or (on == 'success' and status == 'success') or (on == 'fail' and status != 'success'):
selected.append(it)
post = self._build_hooks(selected)
ev = 'post_sync_success' if status == 'success' else 'post_sync_fail'
for h in post:
try:
h.run(db=db, integration_id=integration_id, event=ev, context=context)
except Exception:
continue
def hooks_for_integration(db, integration_id: int) -> HookManager:
# Load hooks config from Integration.config.hooks
from . import models
integ = db.query(models.Integration).filter_by(id=integration_id).first()
cfg = {}
if integ and integ.config:
try:
import json as _json
cfg = _json.loads(integ.config) or {}
except Exception:
cfg = {}
return HookManager(cfg.get('hooks'))