mirror of
https://github.com/calibrain/shelfmark.git
synced 2026-09-24 13:40:21 +01:00
Remove deprecated /request route prefix support (#318)
This commit removes all references to the deprecated /request route prefix that was previously used for dual routing. The following changes were made: - Removed register_dual_routes() function that registered routes with /request prefix - Removed url_for_with_request() helper function for generating /request URLs - Removed call to register_dual_routes(app) at application startup - Removed /request/ prefixed favicon routes - Updated StatusEndpointFilter to remove /request/api/status log filtering - Removed unused flask_url_for import All routes now only use the standard paths without the /request prefix.
This commit is contained in:
+1
-1
@@ -110,7 +110,7 @@ EXPOSE ${FLASK_PORT}
|
||||
# Add healthcheck for container status
|
||||
# This will run as root initially, but check localhost which should work if the app binds correctly.
|
||||
HEALTHCHECK --interval=60s --timeout=60s --start-period=60s --retries=3 \
|
||||
CMD curl -s http://localhost:${FLASK_PORT}/request/api/status > /dev/null || exit 1
|
||||
CMD curl -s http://localhost:${FLASK_PORT}/api/status > /dev/null || exit 1
|
||||
|
||||
# Use dumb-init as the entrypoint to handle signals properly
|
||||
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
|
||||
|
||||
@@ -12,7 +12,6 @@ from flask_socketio import SocketIO, emit
|
||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||
from werkzeug.security import check_password_hash
|
||||
from werkzeug.wrappers import Response
|
||||
from flask import url_for as flask_url_for
|
||||
import typing
|
||||
|
||||
from logger import setup_logger
|
||||
@@ -132,10 +131,10 @@ if DEBUG:
|
||||
class StatusEndpointFilter(logging.Filter):
|
||||
"""Filter out routine status endpoint requests to reduce log noise."""
|
||||
def filter(self, record):
|
||||
# Exclude GET /api/status and GET /request/api/status requests
|
||||
# Exclude GET /api/status requests
|
||||
if hasattr(record, 'getMessage'):
|
||||
message = record.getMessage()
|
||||
if 'GET /api/status' in message or 'GET /request/api/status' in message:
|
||||
if 'GET /api/status' in message:
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -194,44 +193,6 @@ def login_required(f):
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
|
||||
def register_dual_routes(app : Flask) -> None:
|
||||
"""
|
||||
Register each route both with and without the /request prefix.
|
||||
This function should be called after all routes are defined.
|
||||
"""
|
||||
# Store original url_map rules
|
||||
rules = list(app.url_map.iter_rules())
|
||||
|
||||
# Add /request prefix to each rule
|
||||
for rule in rules:
|
||||
if rule.rule != '/request/' and rule.rule != '/request': # Skip if it's already a request route
|
||||
# Create new routes with /request prefix, both with and without trailing slash
|
||||
base_rule = rule.rule[:-1] if rule.rule.endswith('/') else rule.rule
|
||||
if base_rule == '': # Special case for root path
|
||||
app.add_url_rule('/request', f"root_request",
|
||||
view_func=app.view_functions[rule.endpoint],
|
||||
methods=rule.methods)
|
||||
app.add_url_rule('/request/', f"root_request_slash",
|
||||
view_func=app.view_functions[rule.endpoint],
|
||||
methods=rule.methods)
|
||||
else:
|
||||
app.add_url_rule(f"/request{base_rule}",
|
||||
f"{rule.endpoint}_request",
|
||||
view_func=app.view_functions[rule.endpoint],
|
||||
methods=rule.methods)
|
||||
app.add_url_rule(f"/request{base_rule}/",
|
||||
f"{rule.endpoint}_request_slash",
|
||||
view_func=app.view_functions[rule.endpoint],
|
||||
methods=rule.methods)
|
||||
app.jinja_env.globals['url_for'] = url_for_with_request
|
||||
|
||||
def url_for_with_request(endpoint : str, **values : typing.Any) -> str:
|
||||
"""Generate URLs with /request prefix by default."""
|
||||
if endpoint == 'static' or endpoint == 'serve_frontend_assets':
|
||||
# For static files, add /request prefix
|
||||
url = flask_url_for(endpoint, **values)
|
||||
return f"/request{url}"
|
||||
return flask_url_for(endpoint, **values)
|
||||
|
||||
# Serve frontend static files
|
||||
@app.route('/assets/<path:filename>')
|
||||
@@ -259,8 +220,6 @@ def logo() -> Response:
|
||||
|
||||
@app.route('/favicon.ico')
|
||||
@app.route('/favico<path:_>')
|
||||
@app.route('/request/favico<path:_>')
|
||||
@app.route('/request/static/favico<path:_>')
|
||||
def favicon(_ : typing.Any = None) -> Response:
|
||||
"""
|
||||
Serve favicon from built frontend assets.
|
||||
@@ -823,9 +782,6 @@ def catch_all(path: str) -> Response:
|
||||
# Otherwise serve the React app
|
||||
return send_from_directory(os.path.join(app.root_path, 'frontend-dist'), 'index.html')
|
||||
|
||||
# Register all routes with /request prefix
|
||||
register_dual_routes(app)
|
||||
|
||||
# WebSocket event handlers
|
||||
@socketio.on('connect')
|
||||
def handle_connect():
|
||||
|
||||
@@ -275,7 +275,7 @@ Checks run every 30 seconds with a 30-second timeout and 3 retries.
|
||||
You can enable by adding this to your compose :
|
||||
```
|
||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
|
||||
CMD pyrequests http://localhost:8084/request/api/status || exit 1
|
||||
CMD curl -s http://localhost:8084/api/status || exit 1
|
||||
```
|
||||
|
||||
## 📝 Logging
|
||||
|
||||
+2
-2
@@ -69,8 +69,8 @@ The development server supports HMR for instant feedback during development.
|
||||
|
||||
### API Integration
|
||||
The frontend communicates with the Flask backend via:
|
||||
- REST API endpoints (`/request/api/*`)
|
||||
- WebSocket connection (`ws://localhost:8084/request/ws`)
|
||||
- REST API endpoints (`/api/*`)
|
||||
- WebSocket connection (`ws://localhost:8084/ws`)
|
||||
|
||||
### Building for Production
|
||||
The production build is optimized and minified:
|
||||
|
||||
@@ -192,7 +192,7 @@ export const DownloadsSidebar = ({
|
||||
<h3 className="font-semibold text-sm truncate" title={book.title}>
|
||||
{isCompleted && book.download_path ? (
|
||||
<a
|
||||
href={`/request/api/localdownload?id=${encodeURIComponent(book.id)}`}
|
||||
href={`/api/localdownload?id=${encodeURIComponent(book.id)}`}
|
||||
className="text-sky-600 hover:underline"
|
||||
>
|
||||
{book.title || 'Unknown Title'}
|
||||
|
||||
@@ -277,7 +277,7 @@ export const Header = ({
|
||||
{/* Debug Buttons */}
|
||||
{debug && (
|
||||
<>
|
||||
<form action="/request/debug" method="get" className="w-full">
|
||||
<form action="/debug" method="get" className="w-full">
|
||||
<button
|
||||
className="w-full text-left px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors flex items-center gap-3 text-orange-600 dark:text-orange-400"
|
||||
type="submit"
|
||||
@@ -288,7 +288,7 @@ export const Header = ({
|
||||
<span>Debug</span>
|
||||
</button>
|
||||
</form>
|
||||
<form action="/request/api/restart" method="get" className="w-full">
|
||||
<form action="/api/restart" method="get" className="w-full">
|
||||
<button
|
||||
className="w-full text-left px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors flex items-center gap-3 text-orange-600 dark:text-orange-400"
|
||||
type="submit"
|
||||
|
||||
@@ -114,7 +114,7 @@ export const StatusSection = ({
|
||||
{Object.values(items).map((book: any) => {
|
||||
const maybeLinkedTitle = book.download_path ? (
|
||||
<a
|
||||
href={`/request/api/localdownload?id=${encodeURIComponent(book.id)}`}
|
||||
href={`/api/localdownload?id=${encodeURIComponent(book.id)}`}
|
||||
className="text-blue-600 hover:underline"
|
||||
>
|
||||
{book.title || '-'}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Book, StatusData, AppConfig, LoginCredentials, AuthResponse } from '../types';
|
||||
|
||||
const API_BASE = '/request/api';
|
||||
const API_BASE = '/api';
|
||||
|
||||
// API endpoints
|
||||
const API = {
|
||||
|
||||
@@ -16,12 +16,6 @@ export default defineConfig({
|
||||
cors: true,
|
||||
proxy: {
|
||||
// Proxy API requests to the Docker backend
|
||||
'/request/api': {
|
||||
target: 'http://localhost:8084',
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
},
|
||||
// Also proxy direct API calls (without /request prefix)
|
||||
'/api': {
|
||||
target: 'http://localhost:8084',
|
||||
changeOrigin: true,
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ print(f"Verified file exists: {expected_filepath}")
|
||||
|
||||
# Step 6 : Download the book
|
||||
print(f"Step 6: Downloading book {book_id}...")
|
||||
download_response = requests.get(f"{server_url}/request/api/localdownload?id={book_id}")
|
||||
download_response = requests.get(f"{server_url}/api/localdownload?id={book_id}")
|
||||
download_response.raise_for_status()
|
||||
# Write book to temp file :
|
||||
temp_file_path = os.path.join("/tmp", f"{book_id}.epub")
|
||||
|
||||
Reference in New Issue
Block a user