updated to correct frature
This commit is contained in:
263
app.py
263
app.py
@@ -8,7 +8,6 @@ from PIL import Image, ImageDraw
|
||||
import qrcode
|
||||
from qrcode.image.styledpil import StyledPilImage
|
||||
from qrcode.image.styles.moduledrawers import RoundedModuleDrawer, CircleModuleDrawer, SquareModuleDrawer
|
||||
from qrcode.image.styles.colorfills import SolidFillColorMask
|
||||
from flask import Flask, request, jsonify, send_file, render_template
|
||||
from flask_cors import CORS
|
||||
|
||||
@@ -24,6 +23,9 @@ os.makedirs(LOGOS_FOLDER, exist_ok=True)
|
||||
# In-memory storage for QR codes (in production, use a database)
|
||||
qr_codes_db = {}
|
||||
|
||||
# In-memory storage for dynamic link pages
|
||||
link_pages_db = {}
|
||||
|
||||
class QRCodeGenerator:
|
||||
def __init__(self):
|
||||
self.default_settings = {
|
||||
@@ -55,27 +57,28 @@ class QRCodeGenerator:
|
||||
qr.add_data(data)
|
||||
qr.make(fit=True)
|
||||
|
||||
# Choose module drawer based on style
|
||||
module_drawer = None
|
||||
if settings['style'] == 'rounded':
|
||||
module_drawer = RoundedModuleDrawer()
|
||||
elif settings['style'] == 'circle':
|
||||
module_drawer = CircleModuleDrawer()
|
||||
# For styled QR codes with custom module drawer
|
||||
if settings['style'] != 'square':
|
||||
# Choose module drawer based on style
|
||||
module_drawer = None
|
||||
if settings['style'] == 'rounded':
|
||||
module_drawer = RoundedModuleDrawer()
|
||||
elif settings['style'] == 'circle':
|
||||
module_drawer = CircleModuleDrawer()
|
||||
|
||||
# Generate the styled image
|
||||
img = qr.make_image(
|
||||
image_factory=StyledPilImage,
|
||||
module_drawer=module_drawer,
|
||||
fill_color=settings['foreground_color'],
|
||||
back_color=settings['background_color']
|
||||
)
|
||||
else:
|
||||
module_drawer = SquareModuleDrawer()
|
||||
|
||||
# Create color mask
|
||||
color_mask = SolidFillColorMask(
|
||||
back_color=settings['background_color'],
|
||||
front_color=settings['foreground_color']
|
||||
)
|
||||
|
||||
# Generate the image
|
||||
img = qr.make_image(
|
||||
image_factory=StyledPilImage,
|
||||
module_drawer=module_drawer,
|
||||
color_mask=color_mask
|
||||
)
|
||||
# Generate standard image with custom colors
|
||||
img = qr.make_image(
|
||||
fill_color=settings['foreground_color'],
|
||||
back_color=settings['background_color']
|
||||
)
|
||||
|
||||
return img
|
||||
|
||||
@@ -109,8 +112,78 @@ class QRCodeGenerator:
|
||||
print(f"Error adding logo: {e}")
|
||||
return qr_img
|
||||
|
||||
# Initialize QR code generator
|
||||
class LinkPageManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def create_link_page(self, title="My Links", description="Collection of useful links"):
|
||||
"""Create a new dynamic link page"""
|
||||
page_id = str(uuid.uuid4())
|
||||
page_data = {
|
||||
'id': page_id,
|
||||
'title': title,
|
||||
'description': description,
|
||||
'links': [],
|
||||
'created_at': datetime.now().isoformat(),
|
||||
'updated_at': datetime.now().isoformat(),
|
||||
'view_count': 0
|
||||
}
|
||||
link_pages_db[page_id] = page_data
|
||||
return page_id
|
||||
|
||||
def add_link(self, page_id, title, url, description=""):
|
||||
"""Add a link to a page"""
|
||||
if page_id not in link_pages_db:
|
||||
return False
|
||||
|
||||
link_data = {
|
||||
'id': str(uuid.uuid4()),
|
||||
'title': title,
|
||||
'url': url if url.startswith(('http://', 'https://')) else f'https://{url}',
|
||||
'description': description,
|
||||
'created_at': datetime.now().isoformat()
|
||||
}
|
||||
|
||||
link_pages_db[page_id]['links'].append(link_data)
|
||||
link_pages_db[page_id]['updated_at'] = datetime.now().isoformat()
|
||||
return True
|
||||
|
||||
def update_link(self, page_id, link_id, title=None, url=None, description=None):
|
||||
"""Update a specific link"""
|
||||
if page_id not in link_pages_db:
|
||||
return False
|
||||
|
||||
for link in link_pages_db[page_id]['links']:
|
||||
if link['id'] == link_id:
|
||||
if title is not None:
|
||||
link['title'] = title
|
||||
if url is not None:
|
||||
link['url'] = url if url.startswith(('http://', 'https://')) else f'https://{url}'
|
||||
if description is not None:
|
||||
link['description'] = description
|
||||
|
||||
link_pages_db[page_id]['updated_at'] = datetime.now().isoformat()
|
||||
return True
|
||||
return False
|
||||
|
||||
def delete_link(self, page_id, link_id):
|
||||
"""Delete a specific link"""
|
||||
if page_id not in link_pages_db:
|
||||
return False
|
||||
|
||||
links = link_pages_db[page_id]['links']
|
||||
link_pages_db[page_id]['links'] = [link for link in links if link['id'] != link_id]
|
||||
link_pages_db[page_id]['updated_at'] = datetime.now().isoformat()
|
||||
return True
|
||||
|
||||
def increment_view_count(self, page_id):
|
||||
"""Increment view count for a page"""
|
||||
if page_id in link_pages_db:
|
||||
link_pages_db[page_id]['view_count'] += 1
|
||||
|
||||
# Initialize managers
|
||||
qr_generator = QRCodeGenerator()
|
||||
link_manager = LinkPageManager()
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
@@ -282,5 +355,151 @@ def upload_logo():
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
# Dynamic Link Pages API Routes
|
||||
|
||||
@app.route('/api/create_link_page', methods=['POST'])
|
||||
def create_link_page():
|
||||
"""Create a new dynamic link page and QR code"""
|
||||
try:
|
||||
data = request.json
|
||||
title = data.get('title', 'My Links')
|
||||
description = data.get('description', 'Collection of useful links')
|
||||
|
||||
# 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}"
|
||||
|
||||
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')
|
||||
}
|
||||
|
||||
# Generate QR code
|
||||
qr_img = qr_generator.generate_qr_code(page_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 = str(uuid.uuid4())
|
||||
qr_record = {
|
||||
'id': qr_id,
|
||||
'type': 'link_page',
|
||||
'content': page_url,
|
||||
'page_id': page_id,
|
||||
'settings': settings,
|
||||
'created_at': datetime.now().isoformat(),
|
||||
'image_data': img_base64
|
||||
}
|
||||
qr_codes_db[qr_id] = qr_record
|
||||
|
||||
# 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,
|
||||
'page_id': page_id,
|
||||
'page_url': page_url,
|
||||
'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}'
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/link_pages/<page_id>/links', methods=['POST'])
|
||||
def add_link_to_page(page_id):
|
||||
"""Add a link to a page"""
|
||||
try:
|
||||
data = request.json
|
||||
title = data.get('title', '')
|
||||
url = data.get('url', '')
|
||||
description = data.get('description', '')
|
||||
|
||||
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)
|
||||
|
||||
if success:
|
||||
return jsonify({'success': True})
|
||||
else:
|
||||
return jsonify({'error': 'Page not found'}), 404
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/link_pages/<page_id>/links/<link_id>', methods=['PUT'])
|
||||
def update_link_in_page(page_id, link_id):
|
||||
"""Update a link in a page"""
|
||||
try:
|
||||
data = request.json
|
||||
title = data.get('title')
|
||||
url = data.get('url')
|
||||
description = data.get('description')
|
||||
|
||||
success = link_manager.update_link(page_id, link_id, title, url, description)
|
||||
|
||||
if success:
|
||||
return jsonify({'success': True})
|
||||
else:
|
||||
return jsonify({'error': 'Page or link not found'}), 404
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/link_pages/<page_id>/links/<link_id>', methods=['DELETE'])
|
||||
def delete_link_from_page(page_id, link_id):
|
||||
"""Delete a link from a page"""
|
||||
try:
|
||||
success = link_manager.delete_link(page_id, link_id)
|
||||
|
||||
if success:
|
||||
return jsonify({'success': True})
|
||||
else:
|
||||
return jsonify({'error': 'Page or link not found'}), 404
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/link_pages/<page_id>')
|
||||
def get_link_page(page_id):
|
||||
"""Get link page data"""
|
||||
if page_id in link_pages_db:
|
||||
return jsonify(link_pages_db[page_id])
|
||||
else:
|
||||
return jsonify({'error': 'Page not found'}), 404
|
||||
|
||||
@app.route('/links/<page_id>')
|
||||
def view_link_page(page_id):
|
||||
"""Display the public link page"""
|
||||
if page_id not in link_pages_db:
|
||||
return "Page not found", 404
|
||||
|
||||
link_manager.increment_view_count(page_id)
|
||||
page_data = link_pages_db[page_id]
|
||||
|
||||
return render_template('link_page.html', page=page_data)
|
||||
|
||||
@app.route('/edit/<page_id>')
|
||||
def edit_link_page(page_id):
|
||||
"""Display the edit interface for the link page"""
|
||||
if page_id not in link_pages_db:
|
||||
return "Page not found", 404
|
||||
|
||||
page_data = link_pages_db[page_id]
|
||||
return render_template('edit_links.html', page=page_data)
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True, host='0.0.0.0', port=5000)
|
||||
|
||||
Reference in New Issue
Block a user