final app for testing and deployment
This commit is contained in:
@@ -7,7 +7,7 @@ import io
|
||||
import base64
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from flask import Blueprint, request, jsonify, send_file
|
||||
from flask import Blueprint, request, jsonify, send_file, redirect, Response, current_app
|
||||
from app.utils.auth import login_required
|
||||
from app.utils.qr_generator import QRCodeGenerator
|
||||
from app.utils.link_manager import LinkPageManager
|
||||
@@ -20,9 +20,11 @@ qr_generator = QRCodeGenerator()
|
||||
link_manager = LinkPageManager()
|
||||
data_manager = QRDataManager()
|
||||
|
||||
# Configuration for file uploads
|
||||
UPLOAD_FOLDER = 'app/static/qr_codes'
|
||||
LOGOS_FOLDER = 'app/static/logos'
|
||||
# Configuration for file uploads - use paths relative to app root
|
||||
UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), '..', 'static', 'qr_codes')
|
||||
LOGOS_FOLDER = os.path.join(os.path.dirname(__file__), '..', 'static', 'logos')
|
||||
UPLOAD_FOLDER = os.path.abspath(UPLOAD_FOLDER)
|
||||
LOGOS_FOLDER = os.path.abspath(LOGOS_FOLDER)
|
||||
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
||||
os.makedirs(LOGOS_FOLDER, exist_ok=True)
|
||||
|
||||
@@ -107,7 +109,7 @@ END:VCARD"""
|
||||
@bp.route('/download/<qr_id>')
|
||||
@login_required
|
||||
def download_qr(qr_id):
|
||||
"""Download QR code"""
|
||||
"""Download QR code in PNG format"""
|
||||
try:
|
||||
img_path = os.path.join(UPLOAD_FOLDER, f'{qr_id}.png')
|
||||
if os.path.exists(img_path):
|
||||
@@ -117,6 +119,32 @@ def download_qr(qr_id):
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@bp.route('/download/<qr_id>/svg')
|
||||
@login_required
|
||||
def download_qr_svg(qr_id):
|
||||
"""Download QR code in SVG format"""
|
||||
try:
|
||||
# Get QR code data from database
|
||||
qr_data = data_manager.get_qr_code(qr_id)
|
||||
if not qr_data:
|
||||
return jsonify({'error': 'QR code not found'}), 404
|
||||
|
||||
# Regenerate QR code as SVG
|
||||
settings = qr_data.get('settings', {})
|
||||
content = qr_data.get('content', '')
|
||||
|
||||
# Generate SVG QR code
|
||||
svg_string = qr_generator.generate_qr_code_svg_string(content, settings)
|
||||
|
||||
# Create a response with SVG content
|
||||
response = Response(svg_string, mimetype='image/svg+xml')
|
||||
response.headers['Content-Disposition'] = f'attachment; filename=qr_code_{qr_id}.svg'
|
||||
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@bp.route('/qr_codes')
|
||||
@login_required
|
||||
def list_qr_codes():
|
||||
@@ -195,8 +223,19 @@ def create_link_page():
|
||||
# Create the link page
|
||||
page_id = link_manager.create_link_page(title, description)
|
||||
|
||||
# Create QR code pointing to the link page
|
||||
page_url = f"{request.url_root}links/{page_id}"
|
||||
# Create the original page URL
|
||||
original_page_url = f"{request.url_root}links/{page_id}"
|
||||
|
||||
# Automatically create a short URL for the link page
|
||||
short_result = link_manager.create_standalone_short_url(
|
||||
original_page_url,
|
||||
title=f"Link Page: {title}",
|
||||
custom_code=None
|
||||
)
|
||||
short_page_url = short_result['short_url']
|
||||
|
||||
# Store the short URL info with the page
|
||||
link_manager.set_page_short_url(page_id, short_page_url, short_result['short_code'])
|
||||
|
||||
settings = {
|
||||
'size': data.get('size', 10),
|
||||
@@ -206,8 +245,8 @@ def create_link_page():
|
||||
'style': data.get('style', 'square')
|
||||
}
|
||||
|
||||
# Generate QR code
|
||||
qr_img = qr_generator.generate_qr_code(page_url, settings)
|
||||
# Generate QR code pointing to the SHORT URL (not the original long URL)
|
||||
qr_img = qr_generator.generate_qr_code(short_page_url, settings)
|
||||
|
||||
# Convert to base64
|
||||
img_buffer = io.BytesIO()
|
||||
@@ -215,8 +254,8 @@ def create_link_page():
|
||||
img_buffer.seek(0)
|
||||
img_base64 = base64.b64encode(img_buffer.getvalue()).decode()
|
||||
|
||||
# Save QR code record
|
||||
qr_id = data_manager.save_qr_record('link_page', page_url, settings, img_base64, page_id)
|
||||
# Save QR code record with the short URL
|
||||
qr_id = data_manager.save_qr_record('link_page', short_page_url, settings, img_base64, page_id)
|
||||
|
||||
# Save image file
|
||||
img_path = os.path.join(UPLOAD_FOLDER, f'{qr_id}.png')
|
||||
@@ -226,7 +265,9 @@ def create_link_page():
|
||||
'success': True,
|
||||
'qr_id': qr_id,
|
||||
'page_id': page_id,
|
||||
'page_url': page_url,
|
||||
'page_url': short_page_url, # Return the short URL as the main page URL
|
||||
'original_url': original_page_url, # Keep original for reference
|
||||
'short_code': short_result['short_code'],
|
||||
'edit_url': f"{request.url_root}edit/{page_id}",
|
||||
'image_data': f'data:image/png;base64,{img_base64}',
|
||||
'download_url': f'/api/download/{qr_id}'
|
||||
@@ -244,11 +285,17 @@ def add_link_to_page(page_id):
|
||||
title = data.get('title', '')
|
||||
url = data.get('url', '')
|
||||
description = data.get('description', '')
|
||||
enable_shortener = data.get('enable_shortener', False)
|
||||
custom_short_code = data.get('custom_short_code', None)
|
||||
|
||||
if not title or not url:
|
||||
return jsonify({'error': 'Title and URL are required'}), 400
|
||||
|
||||
success = link_manager.add_link(page_id, title, url, description)
|
||||
success = link_manager.add_link(
|
||||
page_id, title, url, description,
|
||||
enable_shortener=enable_shortener,
|
||||
custom_short_code=custom_short_code
|
||||
)
|
||||
|
||||
if success:
|
||||
return jsonify({'success': True})
|
||||
@@ -267,8 +314,14 @@ def update_link_in_page(page_id, link_id):
|
||||
title = data.get('title')
|
||||
url = data.get('url')
|
||||
description = data.get('description')
|
||||
enable_shortener = data.get('enable_shortener')
|
||||
custom_short_code = data.get('custom_short_code')
|
||||
|
||||
success = link_manager.update_link(page_id, link_id, title, url, description)
|
||||
success = link_manager.update_link(
|
||||
page_id, link_id, title, url, description,
|
||||
enable_shortener=enable_shortener,
|
||||
custom_short_code=custom_short_code
|
||||
)
|
||||
|
||||
if success:
|
||||
return jsonify({'success': True})
|
||||
@@ -302,3 +355,108 @@ def get_link_page(page_id):
|
||||
return jsonify(page_data)
|
||||
else:
|
||||
return jsonify({'error': 'Page not found'}), 404
|
||||
|
||||
# URL Shortener API Routes
|
||||
|
||||
@bp.route('/shorten', methods=['POST'])
|
||||
@login_required
|
||||
def create_short_url():
|
||||
"""Create a shortened URL"""
|
||||
try:
|
||||
data = request.json
|
||||
url = data.get('url', '')
|
||||
title = data.get('title', '')
|
||||
custom_code = data.get('custom_code', None)
|
||||
|
||||
if not url:
|
||||
return jsonify({'error': 'URL is required'}), 400
|
||||
|
||||
result = link_manager.create_standalone_short_url(url, title, custom_code)
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'short_url': result['short_url'],
|
||||
'short_code': result['short_code'],
|
||||
'original_url': result['original_url']
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@bp.route('/short_urls')
|
||||
@login_required
|
||||
def list_short_urls():
|
||||
"""List all shortened URLs"""
|
||||
try:
|
||||
urls = link_manager.list_all_short_urls()
|
||||
return jsonify({'success': True, 'urls': urls})
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@bp.route('/short_urls/<short_code>/stats')
|
||||
@login_required
|
||||
def get_short_url_stats(short_code):
|
||||
"""Get statistics for a short URL"""
|
||||
try:
|
||||
stats = link_manager.get_short_url_stats(short_code)
|
||||
if stats:
|
||||
return jsonify({'success': True, 'stats': stats})
|
||||
else:
|
||||
return jsonify({'error': 'Short URL not found'}), 404
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@bp.route('/generate_shortened_qr', methods=['POST'])
|
||||
@login_required
|
||||
def generate_shortened_qr():
|
||||
"""Generate QR code for a shortened URL"""
|
||||
try:
|
||||
data = request.json
|
||||
shortener_data = data.get('shortener', {})
|
||||
url = shortener_data.get('url', '')
|
||||
title = shortener_data.get('title', '')
|
||||
custom_code = shortener_data.get('custom_code', '').strip() or None
|
||||
|
||||
if not url:
|
||||
return jsonify({'error': 'URL is required'}), 400
|
||||
|
||||
# Create shortened URL
|
||||
result = link_manager.create_standalone_short_url(url, title, custom_code)
|
||||
short_url = result['short_url']
|
||||
|
||||
# Generate QR code for the short URL
|
||||
settings = {
|
||||
'size': data.get('size', 10),
|
||||
'border': data.get('border', 4),
|
||||
'foreground_color': data.get('foreground_color', '#000000'),
|
||||
'background_color': data.get('background_color', '#FFFFFF'),
|
||||
'style': data.get('style', 'square')
|
||||
}
|
||||
|
||||
qr_img = qr_generator.generate_qr_code(short_url, settings)
|
||||
|
||||
# Convert to base64
|
||||
img_buffer = io.BytesIO()
|
||||
qr_img.save(img_buffer, format='PNG')
|
||||
img_buffer.seek(0)
|
||||
img_base64 = base64.b64encode(img_buffer.getvalue()).decode()
|
||||
|
||||
# Save QR code record
|
||||
qr_id = data_manager.save_qr_record('url_shortener', short_url, settings, img_base64)
|
||||
|
||||
# Save image file
|
||||
img_path = os.path.join(UPLOAD_FOLDER, f'{qr_id}.png')
|
||||
qr_img.save(img_path)
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'qr_id': qr_id,
|
||||
'short_url': short_url,
|
||||
'short_code': result['short_code'],
|
||||
'original_url': result['original_url'],
|
||||
'image_data': f'data:image/png;base64,{img_base64}',
|
||||
'download_url': f'/api/download/{qr_id}'
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
Reference in New Issue
Block a user