Files
links/core/urls.py
T
OpenClaw Sub-agent f2f8192fba refactor: make Ask a regular ACTION link instead of fixed route
Remove hardcoded /ask/ routes (core/urls.py), /api/ask/ (api_urls.py),
ask_views.py, and ask.html input page. Ask is now a normal Link record
(alias='ask', link_type=ACTION) created by data migration 0053, so it
behaves exactly like other action links: go/ask/问题 → catch-all →
execute_action → 302 to Discord, editable/deletable in the Links UI.

Tests updated: ask covered as ACTION link (redirect/dedup/empty-query).
2026-08-01 20:43:29 +10:00

81 lines
3.3 KiB
Python

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from django.views.static import serve
from django.views.generic import TemplateView
from django.http import FileResponse, Http404
from links.views import LinkDetailView, LinkUpdateView, CustomLinkView
from links.file_views import PublicFileView, import_image_view
from django.urls import path, include, re_path
from django.conf.urls.i18n import i18n_patterns
import os
def _serve_static_file(filename, content_type):
"""Serve a file directly from the committed static/ directory."""
def view(request):
path = os.path.join(settings.BASE_DIR, 'static', filename)
try:
return FileResponse(open(path, 'rb'), content_type=content_type)
except FileNotFoundError:
raise Http404
return view
urlpatterns = [
# LLM-friendly discovery endpoints — must be FIRST before any catch-all routes
path('llms.txt', _serve_static_file('llms.txt', 'text/plain; charset=utf-8'), name='llms-txt'),
path('.well-known/ai-plugin.json', _serve_static_file('.well-known/ai-plugin.json', 'application/json'), name='ai-plugin-json'),
path('admin/', admin.site.urls),
# Add API URLs before locale URLs
path('api/', include('links.api_urls')), # New line for API routes
path('api/invest/', include('invest.api_urls')),
path('api/jbot/', include('jbot.api_urls')), # JBOT API endpoints
# Media files
path('media/<path:path>', serve, {
'document_root': settings.MEDIA_ROOT,
}),
# Music files
path('music/<path:path>', serve, {
'document_root': settings.MUSIC_ROOT,
}),
path('i18n/', include('django.conf.urls.i18n')),
path('search/', include('links.search_urls')),
path('link/<int:pk>/', LinkDetailView.as_view(), name='link_detail'),
path('link/<int:pk>/edit/', LinkUpdateView.as_view(), name='link_update'),
path('custom/<slug:alias>/', CustomLinkView.as_view(), name='custom_link'),
path('custom/<slug:alias>/edit/', LinkUpdateView.as_view(), name='custom_link_update'),
path('invest/', include('invest.urls')),
# Include netscan and files BEFORE links.urls to prevent the alias catch-all from intercepting them
path('ui/netscan/', include('netscan.urls')),
path('ui/nginxmon/', include('nginxmon.urls')),
path('ui/routermon/', include('routermon.urls')),
path('ui/pricemon/', include('pricemon.urls')),
path('ui/files/', include('links.file_urls')),
# JBOT AI Robot Face SPA
path('jbot/', include('jbot.urls')),
# Import external image by URL — /import/images/<path:image_url> (also plural alias)
path('import/images/<path:image_url>', import_image_view, name='import-image'),
path('imports/images/<path:image_url>', import_image_view, name='imports-image'),
# Public file access — /public/files/{uuid}-{filename}
re_path(
r'^public/files/(?P<pk>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})-(?P<filename>.+)$',
PublicFileView.as_view(),
name='public-file',
),
# Include main app URLs with locale
path('', include('links.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)