Release 1.2: bulk upload, S3/SFTP/FTP, SMTP, password reset, user groups, git deploy
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import os
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
from app import db
|
||||
from app.models import Photo
|
||||
from app.quota_utils import check_upload_quota
|
||||
from app.settings_service import get_settings
|
||||
from app.storage_service import save_photo_file
|
||||
|
||||
|
||||
def allowed_file(filename, allowed_extensions):
|
||||
return "." in filename and filename.rsplit(".", 1)[1].lower() in allowed_extensions
|
||||
|
||||
|
||||
def collect_upload_files(request_files):
|
||||
files = request_files.getlist("photos")
|
||||
if not files or all(f.filename == "" for f in files):
|
||||
single = request_files.get("photo")
|
||||
if single and single.filename:
|
||||
files = [single]
|
||||
return [f for f in files if f and f.filename]
|
||||
|
||||
|
||||
def process_uploads(request_files, user, folder, allowed_extensions):
|
||||
settings = get_settings()
|
||||
max_bulk = settings.max_bulk_upload or 100
|
||||
files = collect_upload_files(request_files)
|
||||
|
||||
if not files:
|
||||
return {"uploaded": 0, "errors": ["Файлы не выбраны"], "photos": []}
|
||||
|
||||
if len(files) > max_bulk:
|
||||
return {
|
||||
"uploaded": 0,
|
||||
"errors": [f"Максимум {max_bulk} файлов за раз"],
|
||||
"photos": [],
|
||||
}
|
||||
|
||||
total_size = 0
|
||||
valid_files = []
|
||||
errors = []
|
||||
|
||||
for file in files:
|
||||
if not allowed_file(file.filename, allowed_extensions):
|
||||
errors.append(f"{file.filename}: недопустимый формат")
|
||||
continue
|
||||
file.seek(0, os.SEEK_END)
|
||||
size = file.tell()
|
||||
file.seek(0)
|
||||
total_size += size
|
||||
valid_files.append((file, size))
|
||||
|
||||
if not valid_files:
|
||||
return {"uploaded": 0, "errors": errors, "photos": []}
|
||||
|
||||
ok, quota_msg = check_upload_quota(user, total_size)
|
||||
if not ok:
|
||||
return {"uploaded": 0, "errors": [quota_msg], "photos": []}
|
||||
|
||||
uploaded_photos = []
|
||||
for file, _size in valid_files:
|
||||
ext = file.filename.rsplit(".", 1)[1].lower()
|
||||
stored_name = f"{uuid.uuid4().hex}.{ext}"
|
||||
safe_original = secure_filename(file.filename) or f"photo.{ext}"
|
||||
|
||||
try:
|
||||
_path, file_size, storage_backend, sync_errors = save_photo_file(file, stored_name)
|
||||
for sync_err in sync_errors:
|
||||
errors.append(f"{safe_original}: {sync_err}")
|
||||
|
||||
photo = Photo(
|
||||
filename=stored_name,
|
||||
original_name=safe_original,
|
||||
file_size=file_size,
|
||||
mime_type=file.content_type or f"image/{ext}",
|
||||
user_id=user.id,
|
||||
folder_id=folder.id if folder else None,
|
||||
storage_backend=storage_backend,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
)
|
||||
db.session.add(photo)
|
||||
uploaded_photos.append(photo)
|
||||
except Exception as exc:
|
||||
errors.append(f"{safe_original}: {exc}")
|
||||
|
||||
if uploaded_photos:
|
||||
db.session.commit()
|
||||
|
||||
return {
|
||||
"uploaded": len(uploaded_photos),
|
||||
"errors": errors,
|
||||
"photos": uploaded_photos,
|
||||
}
|
||||
Reference in New Issue
Block a user