🚀 Major improvements: Fix short URLs, separate public/admin views, and enhance UX

 Fixed Critical Issues:
- Fixed dynamic QR code short URL redirect functionality
- Resolved data consistency issues with multiple LinkPageManager instances
- Fixed worker concurrency problems in Gunicorn configuration

🎨 UI/UX Enhancements:
- Separated public page from admin statistics view
- Created clean public_page.html for QR code users (no admin info)
- Added comprehensive statistics_page.html for admin analytics
- Enhanced dashboard with separate 'Manage' and 'Stats' buttons
- Improved navigation flow throughout the application

🔧 Technical Improvements:
- Added URLShortener instance reloading for data consistency
- Reduced Gunicorn workers to 1 to prevent file conflicts
- Increased timeout to 60s for better performance
- Enhanced debug logging for troubleshooting
- Added proper error handling and 404 responses

📁 New Files:
- app/templates/public_page.html - Clean public interface
- app/templates/statistics_page.html - Admin analytics dashboard

�� Modified Files:
- app/routes/main.py - Added /stats route, improved short URL handling
- app/templates/edit_links.html - Added Statistics button
- app/templates/index.html - Added Stats button for QR codes
- app/utils/link_manager.py - Enhanced data reloading
- app/utils/url_shortener.py - Added debug logging
- gunicorn.conf.py - Optimized worker configuration

This update provides a professional separation between public content and admin functionality while ensuring reliable short URL operation.
This commit is contained in:
2025-07-18 09:21:36 -04:00
parent 1ae080df37
commit 53f5c513d4
11 changed files with 920 additions and 8 deletions

View File

@@ -69,7 +69,16 @@ class LinkPageManager:
def add_link(self, page_id, title, url, description="", enable_shortener=False, custom_short_code=None):
"""Add a link to a page with optional URL shortening"""
print(f"DEBUG: LinkManager.add_link called for page {page_id}")
print(f"DEBUG: Current pages in memory: {list(self.link_pages_db.keys())}")
if page_id not in self.link_pages_db:
print(f"DEBUG: Page {page_id} not found in memory, reloading from file")
self.link_pages_db = self._load_link_pages()
print(f"DEBUG: After reload, pages: {list(self.link_pages_db.keys())}")
if page_id not in self.link_pages_db:
print(f"DEBUG: Page {page_id} still not found after reload")
return False
# Ensure URL has protocol
@@ -90,21 +99,27 @@ class LinkPageManager:
# Generate short URL if enabled
if enable_shortener:
print(f"DEBUG: Creating short URL for {url}")
try:
short_result = self.url_shortener.create_short_url(
url,
custom_code=custom_short_code,
title=title
)
print(f"DEBUG: Short URL created: {short_result}")
link_data['short_url'] = short_result['short_url']
link_data['short_code'] = short_result['short_code']
except Exception as e:
# If shortening fails, continue without it
print(f"URL shortening failed: {e}")
print(f"DEBUG: URL shortening failed: {e}")
print(f"DEBUG: Adding link to page data: {link_data}")
self.link_pages_db[page_id]['links'].append(link_data)
self.link_pages_db[page_id]['updated_at'] = datetime.now().isoformat()
print(f"DEBUG: Saving link pages to file")
self._save_link_pages() # Persist to file
print(f"DEBUG: Link added successfully")
return True
def update_link(self, page_id, link_id, title=None, url=None, description=None, enable_shortener=None, custom_short_code=None):
@@ -196,4 +211,6 @@ class LinkPageManager:
def resolve_short_url(self, short_code):
"""Resolve a short URL to its original URL"""
# Reload URLShortener data to ensure we have the latest URLs
self.url_shortener = URLShortener()
return self.url_shortener.get_original_url(short_code)

View File

@@ -57,11 +57,15 @@ class URLShortener:
def create_short_url(self, original_url, custom_code=None, title=""):
"""Create a shortened URL"""
print(f"DEBUG: URLShortener.create_short_url called with url='{original_url}', custom_code='{custom_code}', title='{title}'")
# Generate or use custom short code
if custom_code and custom_code not in self.short_urls_db:
short_code = custom_code
print(f"DEBUG: Using custom short code: {short_code}")
else:
short_code = self.generate_short_code()
print(f"DEBUG: Generated short code: {short_code}")
# Ensure original URL has protocol
if not original_url.startswith(('http://', 'https://')):
@@ -78,11 +82,16 @@ class URLShortener:
'last_accessed': None
}
print(f"DEBUG: Adding to short_urls_db: {short_code} -> {url_data}")
self.short_urls_db[short_code] = url_data
print(f"DEBUG: Saving short URLs to file")
self._save_short_urls() # Persist to file
print(f"DEBUG: Short URLs saved successfully")
# Return the complete short URL
short_url = f"{self.base_domain}/s/{short_code}"
print(f"DEBUG: Returning short URL: {short_url}")
return {
'short_url': short_url,
'short_code': short_code,