fix: Add authenticated image proxy for part images
Fixes 'Unauthorized' errors when loading part images in web app. Problem: - InvenTree media files require authentication - Direct image URLs return 401 Unauthorized - Browser can't send API token with image requests Solution: - Added /api/proxy/image endpoint in Flask app - Proxy fetches images with API token authentication - Returns image with correct Content-Type header - Frontend uses proxy URL instead of direct InvenTree URL Usage: - Images now load via: /api/proxy/image?url=/media/part_images/... - Proxy adds Authorization header automatically - Works for both image and thumbnail URLs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -399,6 +399,31 @@ def get_pending():
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/proxy/image')
|
||||||
|
def proxy_image():
|
||||||
|
"""Proxy image requests with authentication."""
|
||||||
|
image_url = request.args.get('url')
|
||||||
|
|
||||||
|
if not image_url:
|
||||||
|
return jsonify({'error': 'url parameter required'}), 400
|
||||||
|
|
||||||
|
# If it's a relative URL, make it absolute
|
||||||
|
if image_url.startswith('/'):
|
||||||
|
image_url = config['host'] + image_url
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Fetch image with authentication
|
||||||
|
response = requests.get(image_url, headers={'Authorization': f"Token {config['token']}"})
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
# Return image with correct content type
|
||||||
|
content_type = response.headers.get('Content-Type', 'image/jpeg')
|
||||||
|
return response.content, 200, {'Content-Type': content_type}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({'error': str(e)}), 500
|
||||||
|
|
||||||
|
|
||||||
# WebSocket events
|
# WebSocket events
|
||||||
@socketio.on('connect')
|
@socketio.on('connect')
|
||||||
def handle_connect():
|
def handle_connect():
|
||||||
|
|||||||
@@ -346,12 +346,12 @@ function stockApp() {
|
|||||||
this.currentPart = data.part_info;
|
this.currentPart = data.part_info;
|
||||||
this.currentParameters = data.parameters;
|
this.currentParameters = data.parameters;
|
||||||
|
|
||||||
// Fix image URLs - convert relative paths to full InvenTree URLs
|
// Fix image URLs - use proxy for authenticated access
|
||||||
if (this.currentPart.image && this.currentPart.image.startsWith('/')) {
|
if (this.currentPart.image) {
|
||||||
this.currentPart.image = this.config.host + this.currentPart.image;
|
this.currentPart.image = `/api/proxy/image?url=${encodeURIComponent(this.currentPart.image)}`;
|
||||||
}
|
}
|
||||||
if (this.currentPart.thumbnail && this.currentPart.thumbnail.startsWith('/')) {
|
if (this.currentPart.thumbnail) {
|
||||||
this.currentPart.thumbnail = this.config.host + this.currentPart.thumbnail;
|
this.currentPart.thumbnail = `/api/proxy/image?url=${encodeURIComponent(this.currentPart.thumbnail)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.log('success', `✅ Found part: ${partCode}`);
|
this.log('success', `✅ Found part: ${partCode}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user