Files
PiCopy/routes/upload_routes.py

124 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""PiCopy Blueprint: /api/upload/*."""
import subprocess
import uuid as _uuid_mod
from flask import Blueprint, jsonify, request
from picopy.config import load_cfg, save_cfg
from picopy.upload import (
upload_state, upload_lock,
configure_smb_remote, delete_remote, test_remote,
_rclone_obscure, RCLONE_CONF as _RCLONE_CONF,
)
upload_bp = Blueprint('upload', __name__)
@upload_bp.route('/api/upload/targets', methods=['GET'])
def r_upload_list():
return jsonify(load_cfg().get('upload_targets', []))
@upload_bp.route('/api/upload/targets', methods=['POST'])
def r_upload_add():
data = request.get_json(force=True)
cfg = load_cfg()
tid = data.get('id') or _uuid_mod.uuid4().hex[:8]
ctype = data.get('type', 'smb')
if ctype != 'smb':
return jsonify(error='Nur SMB/NAS wird unterstützt'), 400
ok, err = configure_smb_remote(
tid, data.get('host', ''), data.get('share', ''),
data.get('user', ''), data.get('pass', ''))
if not ok:
return jsonify(error=f'rclone: {err}'), 500
# Credentials direkt im Entry speichern (für Connection-String bei Upload)
obscured_pw = _rclone_obscure(data.get('pass', '')) if data.get('pass') else ''
entry = {
'id': tid, 'type': ctype,
'name': data.get('name', ctype),
'dest_path': data.get('dest_path', 'PiCopy'),
'enabled': True,
'smb_host': data.get('host', ''),
'smb_share': data.get('share', ''),
'smb_user': data.get('user', ''),
'smb_pass': obscured_pw,
}
targets = [t for t in cfg.get('upload_targets', []) if t['id'] != tid]
targets.append(entry)
cfg['upload_targets'] = targets
save_cfg(cfg)
return jsonify(ok=True, id=tid)
@upload_bp.route('/api/upload/targets/<tid>', methods=['DELETE'])
def r_upload_del(tid):
cfg = load_cfg()
cfg['upload_targets'] = [t for t in cfg.get('upload_targets', []) if t['id'] != tid]
save_cfg(cfg)
delete_remote(tid)
return jsonify(ok=True)
@upload_bp.route('/api/upload/browse', methods=['POST'])
def r_upload_browse():
"""Listet SMB-Freigaben eines Servers ohne gespeicherte Config (rclone connection string)."""
data = request.get_json(force=True)
host = data.get('host', '').strip()
user = data.get('user', '').strip()
pw = data.get('pass', '')
if not host:
return jsonify(error='Server-Adresse fehlt'), 400
conn = f':smb,host={host}'
if user:
conn += f',user={user}'
if pw:
try:
obscured = _rclone_obscure(pw)
conn += f',pass={obscured}'
except Exception:
pass
conn += ':'
r = subprocess.run(
['rclone', '--config', str(_RCLONE_CONF), 'lsd', conn],
capture_output=True, text=True, timeout=15
)
if r.returncode != 0:
lines = r.stderr.strip().splitlines()
err = lines[-1] if lines else 'Verbindung fehlgeschlagen'
return jsonify(error=err), 400
shares = [line.strip().split()[-1] for line in r.stdout.splitlines() if line.strip()]
return jsonify(shares=shares)
@upload_bp.route('/api/upload/targets/<tid>/toggle', methods=['POST'])
def r_upload_toggle(tid):
cfg = load_cfg()
for t in cfg.get('upload_targets', []):
if t['id'] == tid:
t['enabled'] = not t.get('enabled', True)
break
save_cfg(cfg)
return jsonify(ok=True)
@upload_bp.route('/api/upload/targets/<tid>/test', methods=['POST'])
def r_upload_test(tid):
from picopy.config import log
try:
ok, err = test_remote(tid)
except Exception as e:
log.exception('upload test failed')
ok, err = False, str(e)
return jsonify(ok=ok, error=err)
@upload_bp.route('/api/upload/status')
def r_upload_status():
with upload_lock:
return jsonify(dict(upload_state))