Convert all Chinese comments, docstrings, logger/print output, HTTPException detail messages, and API response messages to English across the entire codebase. Functional zh/ja localized strings (e.g. prompt templates, timezone display names, date formats) are preserved as-is. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
96 lines
3.2 KiB
Python
96 lines
3.2 KiB
Python
"""
|
|
WebDAV file management routes.
|
|
Uses the open-source WsgiDAV library to provide full WebDAV protocol support.
|
|
Provides WebDAV access for the projects/{resource_type}/ directories.
|
|
Supported resource types: robot, docs
|
|
"""
|
|
|
|
from pathlib import Path
|
|
from urllib.parse import urlparse, urlunparse
|
|
|
|
from wsgidav.wsgidav_app import WsgiDAVApp
|
|
from wsgidav.fs_dav_provider import FilesystemProvider
|
|
|
|
from utils.settings import WEBDAV_USERNAME, WEBDAV_PASSWORD
|
|
|
|
PROJECTS_BASE_DIR = Path("projects")
|
|
ALLOWED_RESOURCE_TYPES = {"robot", "docs"}
|
|
|
|
# Ensure the base directories exist
|
|
for resource_type in ALLOWED_RESOURCE_TYPES:
|
|
(PROJECTS_BASE_DIR / resource_type).mkdir(parents=True, exist_ok=True)
|
|
|
|
# Build provider_mapping: map each resource type to its corresponding directory
|
|
provider_mapping = {}
|
|
for resource_type in ALLOWED_RESOURCE_TYPES:
|
|
abs_path = str((PROJECTS_BASE_DIR / resource_type).resolve())
|
|
provider_mapping[f"/{resource_type}"] = FilesystemProvider(abs_path)
|
|
|
|
config = {
|
|
"mount_path": "/webdav",
|
|
"provider_mapping": provider_mapping,
|
|
"http_authenticator": {
|
|
"domain_controller": "wsgidav.dc.simple_dc.SimpleDomainController",
|
|
"accept_basic": True,
|
|
"accept_digest": False,
|
|
"default_to_digest": False,
|
|
},
|
|
"simple_dc": {
|
|
"user_mapping": {
|
|
"*": {
|
|
WEBDAV_USERNAME: {
|
|
"password": WEBDAV_PASSWORD,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"verbose": 1,
|
|
"lock_storage": True,
|
|
"property_manager": True,
|
|
"dir_browser": {
|
|
"enable": True,
|
|
"icon": True,
|
|
"response_trailer": "",
|
|
},
|
|
"hotfixes": {
|
|
"re_encode_path_info": True,
|
|
},
|
|
}
|
|
|
|
_wsgidav_app = WsgiDAVApp(config)
|
|
|
|
|
|
def wsgidav_app(environ, start_response):
|
|
"""WSGI middleware that fixes Destination header scheme/host mismatches behind a reverse proxy.
|
|
|
|
When the service runs behind an HTTPS reverse proxy, the client sends a Destination
|
|
header with the external URL (for example https://example.com/webdav/docs/new-name),
|
|
while WsgiDAV internally sees an HTTP request. This middleware rewrites the
|
|
Destination header so its scheme and host match the internal request.
|
|
"""
|
|
# Read external request information from X-Forwarded headers and keep
|
|
# wsgi.url_scheme aligned with the forwarded protocol.
|
|
forwarded_proto = environ.get("HTTP_X_FORWARDED_PROTO")
|
|
if forwarded_proto:
|
|
environ["wsgi.url_scheme"] = forwarded_proto
|
|
|
|
# Rewrite the Destination header by replacing the external scheme/host
|
|
# with the internal values observed by the application.
|
|
destination = environ.get("HTTP_DESTINATION")
|
|
if destination:
|
|
parsed = urlparse(destination)
|
|
# Replace with the actual internal scheme and host.
|
|
internal_scheme = environ.get("wsgi.url_scheme", "http")
|
|
internal_host = environ.get("HTTP_HOST", environ.get("SERVER_NAME", "localhost"))
|
|
rewritten = urlunparse((
|
|
internal_scheme,
|
|
internal_host,
|
|
parsed.path,
|
|
parsed.params,
|
|
parsed.query,
|
|
parsed.fragment,
|
|
))
|
|
environ["HTTP_DESTINATION"] = rewritten
|
|
|
|
return _wsgidav_app(environ, start_response)
|