Browse Source

static and media structure has uploaded.

master
Mohsen Taba 5 months ago
parent
commit
aa2af2cec2
  1. 6
      config/settings/base.py
  2. 10
      docker-compose.prod.yml
  3. 266
      utils/__init__.py

6
config/settings/base.py

@ -263,8 +263,10 @@ STATIC_URL = '/static/'
MEDIA_URL = '/media/' MEDIA_URL = '/media/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')] STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
STATIC_ROOT = os.path.join(BASE_DIR, 'static', 'static')
MEDIA_ROOT = os.path.join(BASE_DIR, 'static', 'media')
# *********************************************************
STATIC_ROOT = BASE_DIR/'staticfiles'
MEDIA_ROOT = BASE_DIR/'media'
# os.path.join(BASE_DIR, 'static', 'media')
# FILER_ADMIN_ICON_SIZES = ('32', '48') # FILER_ADMIN_ICON_SIZES = ('32', '48')

10
docker-compose.prod.yml

@ -9,7 +9,10 @@ services:
dockerfile: Dockerfile.prod dockerfile: Dockerfile.prod
command: gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers=4 --timeout 560 command: gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers=4 --timeout 560
volumes: volumes:
- static_volume:/usr/src/app/static
- static_volume:/usr/src/app/staticfiles
# /usr/src/app/static
- media_volume:/usr/src/app/media
- logs_volume:/usr/src/app/logs
ports: ports:
- "8010:8000" - "8010:8000"
env_file: env_file:
@ -77,7 +80,10 @@ services:
volumes: volumes:
postgres_data: postgres_data:
static_volume:
staticfiles_volume:
media_volume:
# static_volume:
logs_volume:
redis_data: redis_data:
networks: networks:

266
utils/__init__.py

@ -5,6 +5,11 @@ import mimetypes
import re import re
from urllib.parse import urlparse from urllib.parse import urlparse
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from pathlib import Path
from django.utils.text import get_valid_filename
from django.conf import settings from django.conf import settings
from django.core.files import File from django.core.files import File
from django.http import HttpRequest from django.http import HttpRequest
@ -198,6 +203,26 @@ def sizeof_fmt(num, suffix="B"):
num /= 1024.0 num /= 1024.0
return f"{num:.1f} Yi{suffix}" return f"{num:.1f} Yi{suffix}"
def file_location_media(path: str):
"""
Resolve a media URL/relative path to absolute filesystem path under MEDIA_ROOT.
"""
from django.conf import settings
media_url = (getattr(settings, "MEDIA_URL", "/media/") or "/media/").rstrip("/")
media_root = settings.MEDIA_ROOT
if path.startswith("http"):
path = exclude_host_from_url(path)
if path.startswith(media_url + "/"):
path = path[len(media_url):]
if path.startswith("/"):
path = path[1:]
return os.path.join(media_root, path)
def file_location(path): def file_location(path):
from django.conf import settings from django.conf import settings
@ -253,14 +278,16 @@ class FileFieldSerializer(serializers.CharField):
# value not changed and here we simply return old file path # value not changed and here we simply return old file path
return self.get_rpath(data) return self.get_rpath(data)
if data.startswith('http'):
data = self.get_rpath(data)
# if data.startswith('http'):
# data = self.get_rpath(data)
fpath = file_location(data)
fpath = file_location_media(data)
if not os.path.exists(fpath): if not os.path.exists(fpath):
raise serializers.ValidationError(f"File: '{fpath}' Does not exist") raise serializers.ValidationError(f"File: '{fpath}' Does not exist")
return File(open(fpath, 'rb'), os.path.basename(data))
rel = os.path.basename(data)
return File(open(fpath, "rb"), rel)
# return File(open(fpath, 'rb'), os.path.basename(data))
class UploadChatMediaSerializer(serializers.Serializer): class UploadChatMediaSerializer(serializers.Serializer):
@ -277,62 +304,137 @@ class UploadChatMediaSerializer(serializers.Serializer):
data['file'] = instance['file'] data['file'] = instance['file']
return data return data
# def store_file(self, file):
# from django.conf import settings
# from utils.image_utils import (
# create_thumbnail,
# is_image_file,
# is_video_file,
# extract_video_thumbnail
# )
# media_path = settings.MEDIA_ROOT
# os.makedirs(f'{media_path}/chat/uploads', exist_ok=True)
# fpath = f"/chat/uploads/{secrets.token_urlsafe(4)}-{file.name}"
# full_path = media_path + fpath
# if hasattr(file, 'read'):
# default_storage.save(str(full_path), ContentFile(file.read()))
# else:
# default_storage.save(str(full_path), file)
# os.chmod(full_path, 0o644)
# result = {
# 'file': fpath,
# 'url': absolute_url(self.context['request'], f"/media{fpath}"),
# 'name': file.name,
# 'size': sizeof_fmt(file.size),
# 'mime_type': guess_file_type(fpath)
# }
# # Generate thumbnail if file is an image (low quality for preview)
# if is_image_file(full_path):
# try:
# thumbnail_path = create_thumbnail(full_path, size=(200, 200), quality=60)
# thumbnail_relative = thumbnail_path.replace(media_path, '')
# result['thumbnail_url'] = absolute_url(
# self.context['request'],
# f"/media{thumbnail_relative}"
# )
# except Exception as e:
# print(f"Failed to generate image thumbnail: {e}")
# result['thumbnail_url'] = None
# # Generate thumbnail if file is a video (low quality for preview)
# elif is_video_file(full_path):
# try:
# thumbnail_path = extract_video_thumbnail(
# full_path,
# time_offset='00:00:01',
# size=(200, 200),
# quality=60
# )
# thumbnail_relative = thumbnail_path.replace(media_path, '')
# result['thumbnail_url'] = absolute_url(
# self.context['request'],
# f"/media{thumbnail_relative}"
# )
# except Exception as e:
# print(f"Failed to generate video thumbnail: {e}")
# result['thumbnail_url'] = None
# else:
# result['thumbnail_url'] = None
# return result
def store_file(self, file): def store_file(self, file):
from django.conf import settings from django.conf import settings
from utils.image_utils import ( from utils.image_utils import (
create_thumbnail,
is_image_file,
is_video_file,
extract_video_thumbnail
create_thumbnail,
is_image_file,
is_video_file,
extract_video_thumbnail,
) )
media_path = settings.MEDIA_ROOT
os.makedirs(f'{media_path}/chat/uploads', exist_ok=True)
fpath = f"/chat/uploads/{secrets.token_urlsafe(4)}-{file.name}"
full_path = media_path + fpath
shutil.move(file.temporary_file_path(), full_path)
os.chmod(full_path, 0o644)
media_root = Path(settings.MEDIA_ROOT) # Path object
chat_dir = media_root / "chat" / "uploads"
chat_dir.mkdir(parents=True, exist_ok=True)
safe_name = get_valid_filename(os.path.basename(file.name))
rel_path = Path("chat") / "uploads" / f"{secrets.token_urlsafe(4)}-{safe_name}"
full_path = media_root / rel_path # Path object
# Save via default_storage (path must be relative to MEDIA_ROOT)
if hasattr(file, "read"):
default_storage.save(str(rel_path), ContentFile(file.read()))
else:
default_storage.save(str(rel_path), file)
# Optional: chmod only if local filesystem and OS supports it
try:
os.chmod(full_path, 0o644)
except PermissionError:
pass
result = { result = {
'file': fpath,
'url': absolute_url(self.context['request'], f"/media{fpath}"),
'name': file.name,
'size': sizeof_fmt(file.size),
'mime_type': guess_file_type(fpath)
"file": f"/{rel_path.as_posix()}",
"url": absolute_url(
self.context["request"],
f"{settings.MEDIA_URL.rstrip('/')}/{rel_path.as_posix()}",
),
"name": safe_name,
"size": sizeof_fmt(file.size),
"mime_type": guess_file_type(rel_path.name),
} }
# Generate thumbnail if file is an image (low quality for preview)
if is_image_file(full_path):
# For images
if is_image_file(str(full_path)):
try: try:
thumbnail_path = create_thumbnail(full_path, size=(200, 200), quality=60)
thumbnail_relative = thumbnail_path.replace(media_path, '')
result['thumbnail_url'] = absolute_url(
self.context['request'],
f"/media{thumbnail_relative}"
thumbnail_path = create_thumbnail(str(full_path), size=(200, 200), quality=60)
thumb_rel = str(thumbnail_path).replace(str(media_root), "").lstrip("\\/")
result["thumbnail_url"] = absolute_url(
self.context["request"],
f"{settings.MEDIA_URL.rstrip('/')}/{thumb_rel.replace(os.sep, '/')}",
) )
except Exception as e: except Exception as e:
print(f"Failed to generate image thumbnail: {e}") print(f"Failed to generate image thumbnail: {e}")
result['thumbnail_url'] = None
# Generate thumbnail if file is a video (low quality for preview)
elif is_video_file(full_path):
result["thumbnail_url"] = None
# For videos
elif is_video_file(str(full_path)):
try: try:
thumbnail_path = extract_video_thumbnail( thumbnail_path = extract_video_thumbnail(
full_path,
time_offset='00:00:01',
size=(200, 200),
quality=60
str(full_path),
time_offset="00:00:01",
size=(200, 200),
quality=60,
) )
thumbnail_relative = thumbnail_path.replace(media_path, '')
result['thumbnail_url'] = absolute_url(
self.context['request'],
f"/media{thumbnail_relative}"
thumb_rel = str(thumbnail_path).replace(str(media_root), "").lstrip("\\/")
result["thumbnail_url"] = absolute_url(
self.context["request"],
f"{settings.MEDIA_URL.rstrip('/')}/{thumb_rel.replace(os.sep, '/')}",
) )
except Exception as e: except Exception as e:
print(f"Failed to generate video thumbnail: {e}") print(f"Failed to generate video thumbnail: {e}")
result['thumbnail_url'] = None
result["thumbnail_url"] = None
else: else:
result['thumbnail_url'] = None
result["thumbnail_url"] = None
return result return result
def validate(self, attrs): def validate(self, attrs):
@ -356,58 +458,70 @@ class UploadTmpSerializer(serializers.Serializer):
def store_file(self, file): def store_file(self, file):
from django.conf import settings from django.conf import settings
from utils.image_utils import ( from utils.image_utils import (
create_thumbnail,
is_image_file,
is_video_file,
extract_video_thumbnail
create_thumbnail,
is_image_file,
is_video_file,
extract_video_thumbnail,
) )
static_path = settings.STATIC_ROOT
os.makedirs(f'{static_path}/tmp', exist_ok=True)
fpath = f"/tmp/{secrets.token_urlsafe(4)}-{file.name}"
full_path = static_path + fpath
shutil.move(file.temporary_file_path(), full_path)
os.chmod(full_path, 0o644)
media_root = Path(settings.MEDIA_ROOT)
tmp_dir = media_root / "tmp"
tmp_dir.mkdir(parents=True, exist_ok=True)
safe_name = get_valid_filename(os.path.basename(file.name))
rel_path = Path("tmp") / f"{secrets.token_urlsafe(4)}-{safe_name}"
# Save the file using Django storage (safe on Windows)
# If the file is an InMemoryFile or TemporaryUploadedFile, read its content
if hasattr(file, 'read'):
default_storage.save(str(rel_path), ContentFile(file.read()))
else:
default_storage.save(str(rel_path), file)
full_path = str(media_root / rel_path)
result = { result = {
'file': fpath,
'url': absolute_url(self.context['request'], f"/static{fpath}"),
'name': file.name,
'size': sizeof_fmt(file.size),
'mime_type': guess_file_type(fpath)
"file": f"/{rel_path.as_posix()}",
"url": absolute_url(
self.context["request"],
f"{settings.MEDIA_URL.rstrip('/')}/{rel_path.as_posix()}",
),
"name": safe_name,
"size": sizeof_fmt(file.size),
"mime_type": guess_file_type(rel_path.name),
} }
# Generate thumbnail if file is an image (low quality for preview)
# Generate thumbnail if image
if is_image_file(full_path): if is_image_file(full_path):
try: try:
thumbnail_path = create_thumbnail(full_path, size=(200, 200), quality=60)
thumbnail_relative = thumbnail_path.replace(static_path, '')
result['thumbnail_url'] = absolute_url(
self.context['request'],
f"/static{thumbnail_relative}"
thumb_path = create_thumbnail(full_path, size=(200, 200), quality=60)
thumb_rel = thumb_path.replace(str(media_root), "").lstrip("\\/")
result["thumbnail_url"] = absolute_url(
self.context["request"],
f"{settings.MEDIA_URL.rstrip('/')}/{thumb_rel.replace(os.sep, '/')}",
) )
except Exception as e: except Exception as e:
print(f"Failed to generate image thumbnail: {e}")
result['thumbnail_url'] = None
# Generate thumbnail if file is a video (low quality for preview)
print("Failed to generate image thumbnail:", e)
result["thumbnail_url"] = None
# Generate thumbnail if video
elif is_video_file(full_path): elif is_video_file(full_path):
try: try:
thumbnail_path = extract_video_thumbnail(
full_path,
time_offset='00:00:01',
size=(200, 200),
quality=60
thumb_path = extract_video_thumbnail(
full_path,
time_offset="00:00:01",
size=(200, 200),
quality=60,
) )
thumbnail_relative = thumbnail_path.replace(static_path, '')
result['thumbnail_url'] = absolute_url(
self.context['request'],
f"/static{thumbnail_relative}"
thumb_rel = thumb_path.replace(str(media_root), "").lstrip("\\/")
result["thumbnail_url"] = absolute_url(
self.context["request"],
f"{settings.MEDIA_URL.rstrip('/')}/{thumb_rel.replace(os.sep, '/')}",
) )
except Exception as e: except Exception as e:
print(f"Failed to generate video thumbnail: {e}")
result['thumbnail_url'] = None
print("Failed to generate video thumbnail:", e)
result["thumbnail_url"] = None
else: else:
result['thumbnail_url'] = None
result["thumbnail_url"] = None
return result return result

Loading…
Cancel
Save