Add secret management guide, client-side performance monitoring, and search accessibility enhancements

- Introduced a comprehensive Secret Management Guide detailing best practices, secret classification, development setup, production management, rotation procedures, and emergency protocols.
- Implemented a client-side performance monitoring script to track various metrics including page load performance, paint metrics, layout shifts, and memory usage.
- Enhanced search accessibility with keyboard navigation support for search results, ensuring compliance with WCAG standards and improving user experience.
This commit is contained in:
pacnpal
2025-12-23 16:41:42 -05:00
parent ae31e889d7
commit edcd8f2076
155 changed files with 22046 additions and 4645 deletions

View File

@@ -1,28 +1,202 @@
"""
Django admin configuration for the Media (shared) application.
This module provides admin interfaces for photo management with
bulk operations and content type linking.
Performance targets:
- List views: < 10 queries
- Page load time: < 500ms for 100 records
"""
from django.contrib import admin
from django.utils.html import format_html
from .models import Photo
@admin.register(Photo)
class PhotoAdmin(admin.ModelAdmin):
"""
Admin interface for Photo management.
Provides photo administration with:
- Thumbnail previews in list view
- Content type linking
- Bulk primary photo management
- Alt text validation warnings
Query optimizations:
- select_related: content_type
"""
list_display = (
"thumbnail_preview",
"content_type",
"content_object",
"caption",
"is_primary",
"content_type_display",
"content_object_link",
"caption_preview",
"is_primary_badge",
"has_alt_text",
"created_at",
)
list_filter = ("content_type", "is_primary", "created_at")
search_fields = ("caption", "alt_text")
readonly_fields = ("thumbnail_preview",)
list_select_related = ["content_type"]
search_fields = ("caption", "alt_text", "object_id")
readonly_fields = ("thumbnail_preview", "created_at", "updated_at")
list_per_page = 50
show_full_result_count = False
ordering = ("-created_at",)
fieldsets = (
(
"Image",
{
"fields": ("image", "thumbnail_preview"),
"description": "Upload and preview the photo.",
},
),
(
"Related Object",
{
"fields": ("content_type", "object_id"),
"description": "The object this photo belongs to (park, ride, etc.).",
},
),
(
"Photo Details",
{
"fields": ("caption", "alt_text", "is_primary"),
"description": "Caption and accessibility information.",
},
),
(
"Metadata",
{
"fields": ("created_at", "updated_at"),
"classes": ("collapse",),
},
),
)
@admin.display(description="Preview")
def thumbnail_preview(self, obj):
"""Display thumbnail preview of the photo."""
if obj.image:
return format_html(
'<img src="{}" style="max-height: 50px; max-width: 100px;" />',
'<img src="{}" style="max-height: 60px; max-width: 100px; '
'border-radius: 4px; object-fit: cover;" loading="lazy" />',
obj.image.url,
)
return "No image"
return format_html('<span style="color: gray;">No image</span>')
thumbnail_preview.short_description = "Thumbnail"
@admin.display(description="Type")
def content_type_display(self, obj):
"""Display content type in a readable format."""
if obj.content_type:
return f"{obj.content_type.app_label}.{obj.content_type.model}"
return "-"
@admin.display(description="Object")
def content_object_link(self, obj):
"""Create a link to the related object's admin page."""
try:
content_obj = obj.content_object
if content_obj:
from django.urls import reverse
app_label = obj.content_type.app_label
model_name = obj.content_type.model
try:
url = reverse(
f"admin:{app_label}_{model_name}_change",
args=[content_obj.pk],
)
return format_html(
'<a href="{}">{}</a>',
url,
str(content_obj)[:30],
)
except Exception:
return str(content_obj)[:30]
return "-"
except Exception:
return format_html('<span style="color: red;">Not found</span>')
@admin.display(description="Caption")
def caption_preview(self, obj):
"""Display truncated caption."""
if obj.caption:
return obj.caption[:40] + "..." if len(obj.caption) > 40 else obj.caption
return "-"
@admin.display(description="Primary")
def is_primary_badge(self, obj):
"""Display primary status with badge."""
if obj.is_primary:
return format_html(
'<span style="background-color: green; color: white; padding: 2px 8px; '
'border-radius: 4px; font-size: 11px;">Primary</span>'
)
return format_html(
'<span style="background-color: gray; color: white; padding: 2px 8px; '
'border-radius: 4px; font-size: 11px;">-</span>'
)
@admin.display(description="Alt", boolean=True)
def has_alt_text(self, obj):
"""Indicate if photo has alt text for accessibility."""
return bool(obj.alt_text)
@admin.action(description="Set as primary photo")
def set_primary(self, request, queryset):
"""Set selected photos as primary for their objects."""
for photo in queryset:
# Unset other primary photos for the same object
Photo.objects.filter(
content_type=photo.content_type,
object_id=photo.object_id,
is_primary=True,
).exclude(pk=photo.pk).update(is_primary=False)
photo.is_primary = True
photo.save(update_fields=["is_primary"])
self.message_user(request, f"Set {queryset.count()} photos as primary.")
@admin.action(description="Remove primary status")
def remove_primary(self, request, queryset):
"""Remove primary status from selected photos."""
updated = queryset.update(is_primary=False)
self.message_user(request, f"Removed primary status from {updated} photos.")
@admin.action(description="Flag missing alt text")
def flag_missing_alt(self, request, queryset):
"""List photos missing alt text for accessibility."""
missing = queryset.filter(alt_text__isnull=True) | queryset.filter(alt_text="")
count = missing.count()
if count:
self.message_user(
request,
f"Found {count} photos missing alt text. Please add alt text for accessibility.",
level="WARNING",
)
else:
self.message_user(request, "All selected photos have alt text.")
def get_actions(self, request):
"""Add custom actions to the admin."""
actions = super().get_actions(request)
actions["set_primary"] = (
self.set_primary,
"set_primary",
"Set as primary photo",
)
actions["remove_primary"] = (
self.remove_primary,
"remove_primary",
"Remove primary status",
)
actions["flag_missing_alt"] = (
self.flag_missing_alt,
"flag_missing_alt",
"Flag missing alt text",
)
return actions

View File

@@ -1 +0,0 @@
[GITHUB-TOKEN-REMOVED]

View File

@@ -1,203 +0,0 @@
# ThrillWiki Automation Service Environment Configuration
# Copy this file to thrillwiki-automation***REMOVED*** and customize for your environment
#
# Security Note: This file should have restricted permissions (600) as it may contain
# sensitive information like GitHub Personal Access Tokens
# [AWS-SECRET-REMOVED]====================================
# PROJECT CONFIGURATION
# [AWS-SECRET-REMOVED]====================================
# Base project directory (usually auto-detected)
# PROJECT_DIR=/home/ubuntu/thrillwiki
# Service name for systemd integration
# SERVICE_NAME=thrillwiki
# [AWS-SECRET-REMOVED]====================================
# GITHUB REPOSITORY CONFIGURATION
# [AWS-SECRET-REMOVED]====================================
# GitHub repository remote name
# GITHUB_REPO=origin
# Branch to pull from
# GITHUB_BRANCH=main
# GitHub Personal Access Token (PAT) - Required for private repositories
# Generate at: https://github.com/settings/tokens
# Required permissions: repo (Full control of private repositories)
# GITHUB_TOKEN=ghp_your_personal_access_token_here
# GitHub token file location (alternative to GITHUB_TOKEN)
# GITHUB_TOKEN_FILE=/home/ubuntu/thrillwiki/.github-pat
# [AWS-SECRET-REMOVED]====================================
# AUTOMATION TIMING CONFIGURATION
# [AWS-SECRET-REMOVED]====================================
# Repository pull interval in seconds (default: 300 = 5 minutes)
# PULL_INTERVAL=300
# Health check interval in seconds (default: 60 = 1 minute)
# HEALTH_CHECK_INTERVAL=60
# Server startup timeout in seconds (default: 120 = 2 minutes)
# STARTUP_TIMEOUT=120
# Restart delay after failure in seconds (default: 10)
# RESTART_DELAY=10
# [AWS-SECRET-REMOVED]====================================
# LOGGING CONFIGURATION
# [AWS-SECRET-REMOVED]====================================
# Log directory (default: project_dir/logs)
# LOG_DIR=/home/ubuntu/thrillwiki/logs
# Log file path
# LOG_[AWS-SECRET-REMOVED]proof-automation.log
# Maximum log file size in bytes (default: 10485760 = 10MB)
# MAX_LOG_SIZE=10485760
# Lock file location to prevent multiple instances
# LOCK_FILE=/tmp/thrillwiki-bulletproof.lock
# [AWS-SECRET-REMOVED]====================================
# DEVELOPMENT SERVER CONFIGURATION
# [AWS-SECRET-REMOVED]====================================
# Server host address (default: 0.0.0.0 for all interfaces)
# SERVER_HOST=0.0.0.0
# Server port (default: 8000)
# SERVER_PORT=8000
# [AWS-SECRET-REMOVED]====================================
# DJANGO CONFIGURATION
# [AWS-SECRET-REMOVED]====================================
# Django settings module
# DJANGO_SETTINGS_MODULE=thrillwiki.settings
# Python path
# PYTHONPATH=/home/ubuntu/thrillwiki
# [AWS-SECRET-REMOVED]====================================
# ADVANCED CONFIGURATION
# [AWS-SECRET-REMOVED]====================================
# GitHub authentication script location
# GITHUB_AUTH_[AWS-SECRET-REMOVED]ithub-auth.py
# Enable verbose logging (true/false)
# VERBOSE_LOGGING=false
# Enable debug mode for troubleshooting (true/false)
# DEBUG_MODE=false
# Custom git remote URL (overrides GITHUB_REPO if set)
# CUSTOM_GIT_REMOTE=https://github.com/username/repository.git
# Email notifications for critical failures (requires email configuration)
# NOTIFICATION_EMAIL=admin@example.com
# Maximum consecutive failures before alerting (default: 5)
# MAX_CONSECUTIVE_FAILURES=5
# Enable automatic dependency updates (true/false, default: true)
# AUTO_UPDATE_DEPENDENCIES=true
# Enable automatic migrations on code changes (true/false, default: true)
# AUTO_MIGRATE=true
# Enable automatic static file collection (true/false, default: true)
# AUTO_COLLECTSTATIC=true
# [AWS-SECRET-REMOVED]====================================
# SECURITY CONFIGURATION
# [AWS-SECRET-REMOVED]====================================
# GitHub authentication method (token|ssh|https)
# Default: token (uses GITHUB_TOKEN or GITHUB_TOKEN_FILE)
# GITHUB_AUTH_METHOD=token
# SSH key path for git operations (when using ssh auth method)
# SSH_KEY_PATH=/home/ubuntu/.ssh/***REMOVED***
# Git user configuration for commits
# GIT_USER_NAME="ThrillWiki Automation"
# GIT_USER_EMAIL="automation@thrillwiki.local"
# [AWS-SECRET-REMOVED]====================================
# MONITORING AND HEALTH CHECKS
# [AWS-SECRET-REMOVED]====================================
# Health check URL to verify server is running
# HEALTH_CHECK_URL=http://localhost:8000/health/
# Health check timeout in seconds
# HEALTH_CHECK_TIMEOUT=30
# Enable system resource monitoring (true/false)
# MONITOR_RESOURCES=true
# Memory usage threshold for warnings (in MB)
# MEMORY_WARNING_THRESHOLD=1024
# CPU usage threshold for warnings (percentage)
# CPU_WARNING_THRESHOLD=80
# Disk usage threshold for warnings (percentage)
# DISK_WARNING_THRESHOLD=90
# [AWS-SECRET-REMOVED]====================================
# INTEGRATION SETTINGS
# [AWS-SECRET-REMOVED]====================================
# Webhook integration (if using thrillwiki-webhook service)
# WEBHOOK_INTEGRATION=true
# Slack webhook URL for notifications (optional)
# SLACK_WEBHOOK_URL=https://hooks.slack.com/services/your/webhook/url
# Discord webhook URL for notifications (optional)
# DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/your/webhook/url
# [AWS-SECRET-REMOVED]====================================
# USAGE EXAMPLES
# [AWS-SECRET-REMOVED]====================================
# Example 1: Basic setup with GitHub PAT
# GITHUB_TOKEN=ghp_your_token_here
# PULL_INTERVAL=300
# AUTO_MIGRATE=true
# Example 2: Enhanced monitoring setup
# HEALTH_CHECK_INTERVAL=30
# MONITOR_RESOURCES=true
# NOTIFICATION_EMAIL=admin@thrillwiki.com
# SLACK_WEBHOOK_URL=https://hooks.slack.com/services/your/webhook
# Example 3: Development environment with frequent pulls
# PULL_INTERVAL=60
# DEBUG_MODE=true
# VERBOSE_LOGGING=true
# AUTO_UPDATE_DEPENDENCIES=true
# [AWS-SECRET-REMOVED]====================================
# INSTALLATION NOTES
# [AWS-SECRET-REMOVED]====================================
# 1. Copy this file: cp thrillwiki-automation***REMOVED***.example thrillwiki-automation***REMOVED***
# 2. Set secure permissions: chmod 600 thrillwiki-automation***REMOVED***
# 3. Customize the settings above for your environment
# 4. Enable the service: sudo systemctl enable thrillwiki-automation
# 5. Start the service: sudo systemctl start thrillwiki-automation
# 6. Check status: sudo systemctl status thrillwiki-automation
# 7. View logs: sudo journalctl -u thrillwiki-automation -f
# For security, ensure only the ubuntu user can read this file:
# sudo chown ubuntu:ubuntu thrillwiki-automation***REMOVED***
# sudo chmod 600 thrillwiki-automation***REMOVED***