Files
simple-nanoshare/my_modules/textview/own_links.py
T
daniel156161 3db374b1ab
Build and Push Docker Container / build-and-push (push) Successful in 2m37s
feat(files): cache served files and add HTML text viewer
File cache:
- Add my_modules/filecache with metadata, blob, validator and store layers
- Cache convex.get_file via AsyncCache, TTL clamped to the file expiry
- Skip caching for missing, incomplete or already expired records
- Add a process-local, size-bounded LRU for immutable storage blobs
- Build the cache stack from FILE_CACHE_* env vars in build_file_cache
- Attach the cache to the app in my_modules/app/setup.py
- Expose app-bound helpers in filecache/access.py for routes

Serving:
- Send strong ETag, Last-Modified and Cache-Control on served files
- Answer If-None-Match and If-Modified-Since with 304 from metadata only
- Avoid pulling the blob from Convex on a revalidation hit
- Add a short Cloudflare-CDN-Cache-Control edge window for deleted files
- Record cache_status in the wide event on a 304
- Invalidate cached metadata after file update and delete in both routes

Text viewer:
- Add my_modules/textview to render text/plain and text/markdown as HTML
- Linkify http(s) URLs and trim trailing sentence punctuation
- Resolve links pointing at this instance to the referenced file
- Inline image previews, mark missing and expired targets
- Cap resolution at MAX_LOOKUPS backend lookups per document
- Serve the viewer only for real browser navigations, never for curl or CLI
- Keep raw bytes for ?raw=1, downloads and Accept headers without text/html
- Add templates/side/views/webpage/files/text_view.htm with a raw link

Other:
- Add tests for cache layers, serving, text rendering and the route
- Bump multidict to 7.2.1 in uv.lock
- Update the my_helpers submodule pointer
2026-10-25 18:54:46 +01:00

36 lines
912 B
Python

from __future__ import annotations
from urllib.parse import urlsplit
_ALLOWED_SCHEMES = {'http', 'https'}
def _normalize_host(host: str) -> str:
return (host or '').split(',')[0].strip().lower().rstrip('.')
def parse_share_link(url: str, host: str, root_path: str = '') -> str | None:
"""Return the file_id when url points at this instance's /-<file_id> route."""
try:
parts = urlsplit(url)
except ValueError:
return None
if parts.scheme.lower() not in _ALLOWED_SCHEMES:
return None
if not parts.netloc or _normalize_host(parts.netloc) != _normalize_host(host):
return None
prefix = (root_path or '').rstrip('/')
path = parts.path
if prefix:
if not path.startswith(prefix + '/'):
return None
path = path[len(prefix):]
if not path.startswith('/-'):
return None
file_id = path[2:]
if not file_id or '/' in file_id:
return None
return file_id