feat: Upload in freigegebene Ordner + Benachrichtigung
Share-Links fuer Ordner erlauben jetzt auch Uploads: Backend: - POST /share/<token>/upload - Datei in freigegebenen Ordner hochladen - Passwort-Schutz wird bei Upload ebenfalls geprueft - share_info gibt jetzt upload_allowed zurueck (true bei Ordner-Shares) - Email-Benachrichtigung an den Ersteller wenn jemand eine Datei hochlaedt (Dateiname, Groesse, IP-Adresse) Frontend (ShareView): - Ordner-Shares zeigen jetzt eine Upload-Zone (Drag & Drop + Button) - Fortschrittsbalken beim Upload mit Datei-Zaehler - Erfolgs-/Fehlermeldung nach Upload - Passwortgeschuetzte Ordner-Shares: erst entsperren, dann uploaden Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -490,6 +490,7 @@ def share_info(token):
|
||||
'size': f.size,
|
||||
'mime_type': f.mime_type,
|
||||
'has_password': bool(link.password_hash),
|
||||
'upload_allowed': f.is_folder,
|
||||
}), 200
|
||||
|
||||
|
||||
@@ -557,6 +558,67 @@ def share_download(token):
|
||||
download_name=f.name)
|
||||
|
||||
|
||||
@api_bp.route('/share/<token>/upload', methods=['POST'])
|
||||
def share_upload(token):
|
||||
"""Upload a file via a share link (only if the shared item is a folder)."""
|
||||
link = ShareLink.query.filter_by(token=token).first()
|
||||
if not link:
|
||||
return jsonify({'error': 'Link nicht gefunden'}), 404
|
||||
|
||||
if link.is_expired():
|
||||
return jsonify({'error': 'Link abgelaufen'}), 410
|
||||
|
||||
# Check password if set
|
||||
if link.password_hash:
|
||||
password = request.form.get('password', '') or request.headers.get('X-Share-Password', '')
|
||||
if not bcrypt.check_password_hash(link.password_hash, password):
|
||||
return jsonify({'error': 'Passwort erforderlich'}), 401
|
||||
|
||||
f = db.session.get(File, link.file_id)
|
||||
if not f.is_folder:
|
||||
return jsonify({'error': 'Upload nur in freigegebene Ordner moeglich'}), 400
|
||||
|
||||
if 'file' not in request.files:
|
||||
return jsonify({'error': 'Keine Datei gesendet'}), 400
|
||||
|
||||
uploaded = request.files['file']
|
||||
if not uploaded.filename:
|
||||
return jsonify({'error': 'Leerer Dateiname'}), 400
|
||||
|
||||
filename = uploaded.filename
|
||||
mime = uploaded.content_type or mimetypes.guess_type(filename)[0] or 'application/octet-stream'
|
||||
|
||||
storage_name = str(uuid.uuid4())
|
||||
user_dir = _user_upload_dir(f.owner_id)
|
||||
storage_path = user_dir / storage_name
|
||||
uploaded.save(str(storage_path))
|
||||
|
||||
size = os.path.getsize(str(storage_path))
|
||||
checksum = _compute_checksum(str(storage_path))
|
||||
|
||||
file_obj = File(
|
||||
owner_id=f.owner_id,
|
||||
parent_id=f.id,
|
||||
name=filename,
|
||||
is_folder=False,
|
||||
mime_type=mime,
|
||||
size=size,
|
||||
storage_path=storage_name,
|
||||
checksum=checksum,
|
||||
)
|
||||
db.session.add(file_obj)
|
||||
db.session.commit()
|
||||
|
||||
# Notify share link creator about the upload
|
||||
try:
|
||||
from app.services.system_mail import notify_share_link_upload
|
||||
notify_share_link_upload(link, f.name, filename, size, request.remote_addr)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return jsonify(file_obj.to_dict()), 201
|
||||
|
||||
|
||||
@api_bp.route('/share/<token>', methods=['DELETE'])
|
||||
@token_required
|
||||
def delete_share_link(token):
|
||||
|
||||
Reference in New Issue
Block a user