feat(cli): sync folders with remote paths
Build and Push Docker Container / build-and-push (push) Successful in 1m36s
Build and Push Docker Container / build-and-push (push) Successful in 1m36s
- Store synced folder locations in file_path instead of embedding them in file names. - Add ignore rules from .nanoshareignore and repeatable sync --ignore flags. - Adopt existing remote files only after SHA-256 verification. - Move adopted remotes with metadata updates instead of uploading duplicates. - Bump NanoShare to 1.23.0 and the standalone CLI to 0.2.0.
This commit is contained in:
+16
-3
@@ -12,6 +12,8 @@ from __future__ import annotations
|
||||
import base64
|
||||
import os
|
||||
|
||||
from pathlib import PurePosixPath
|
||||
|
||||
from quart import current_app
|
||||
|
||||
from my_modules.app.setup import LIMITER
|
||||
@@ -24,6 +26,14 @@ RPC_SCOPES = ('files', 'mesh')
|
||||
|
||||
router = Router('picoshare')
|
||||
|
||||
def _safe_file_path(value: str) -> str:
|
||||
raw = (value or '').replace('\\', '/')
|
||||
parts = [
|
||||
part for part in PurePosixPath(raw).parts
|
||||
if part not in ('', '.', '..', '/')
|
||||
]
|
||||
return '/'.join(parts)
|
||||
|
||||
def _user_id(ctx):
|
||||
if ctx.principal is None:
|
||||
raise Unauthorized('authentication required')
|
||||
@@ -47,10 +57,12 @@ async def files_upload(params, ctx):
|
||||
else:
|
||||
raise InvalidParams('provide text or content_b64')
|
||||
|
||||
file_name = params.get('file_name') or iso_stamp_filename('mesh', default_ext)
|
||||
file_name = PurePosixPath(str(params.get('file_name') or iso_stamp_filename('mesh', default_ext)).replace('\\', '/')).name
|
||||
file_path = _safe_file_path(str(params.get('file_path') or ''))
|
||||
storage_id = await current_app.convex.send_to_storage(data=data, content_type=content_type)
|
||||
file_record = await current_app.convex.add_file(
|
||||
file_name=file_name,
|
||||
file_path=file_path,
|
||||
file_size=format_size(len(data)),
|
||||
note=params.get('note', ''),
|
||||
content_type=content_type,
|
||||
@@ -59,7 +71,7 @@ async def files_upload(params, ctx):
|
||||
user_id=user_id,
|
||||
)
|
||||
file_id = file_record.get('file_id') if isinstance(file_record, dict) else None
|
||||
return {'file_id': file_id, 'file_name': file_name, 'size': len(data), 'content_type': content_type}
|
||||
return {'file_id': file_id, 'file_name': file_name, 'file_path': file_path, 'size': len(data), 'content_type': content_type}
|
||||
|
||||
@router.method('files.list')
|
||||
async def files_list(params, ctx):
|
||||
@@ -85,12 +97,13 @@ async def files_info(params, ctx):
|
||||
@router.method('files.update')
|
||||
async def files_update(params, ctx):
|
||||
file_id = params.get('file_id')
|
||||
file_name = params.get('file_name')
|
||||
file_name = PurePosixPath(str(params.get('file_name') or '').replace('\\', '/')).name
|
||||
if not file_id or not file_name:
|
||||
raise InvalidParams('file_id and file_name are required')
|
||||
await current_app.convex.update_file(
|
||||
file_id=file_id,
|
||||
file_name=file_name,
|
||||
file_path=_safe_file_path(str(params.get('file_path') or '')),
|
||||
note=params.get('note', ''),
|
||||
expires_at=ensure_utc(parse_expires(params.get('expires', ''))),
|
||||
user_id=_user_id(ctx),
|
||||
|
||||
Reference in New Issue
Block a user