mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2026-07-30 23:38:02 -04:00
* Add new default light and dark themes to match AdventureLog styles * Allow different theme for site and maps Fixes #1130 * Update settings page to use translation keys for currency and map style descriptions * Add global flag to CollectionItineraryItemSerializer and implement map view persistence in frontend * Update appVersion to v0.12.0-main-052126 * Enhance permissions for shared collections and restrict publicity changes to owners only * Update appVersion to v0.12.1-beta-052126 * Add new localization strings and descriptions for various languages - Updated Spanish (es.json) with new map style and preferred currency descriptions. - Enhanced French (fr.json) with additional details for Strava activities and currency descriptions. - Added new strings in Hungarian (hu.json) for map style and preferred currency. - Included additional details in Italian (it.json) for Strava activities and currency descriptions. - Updated Japanese (ja.json) with new strings for map style and preferred currency. - Enhanced Korean (ko.json) with additional details for Strava activities and currency descriptions. - Added new strings in Dutch (nl.json) for map style and preferred currency. - Updated Norwegian (no.json) with new strings for map style and preferred currency. - Enhanced Polish (pl.json) with additional details for Strava activities and currency descriptions. - Updated Brazilian Portuguese (pt-br.json) with new map style and preferred currency descriptions. - Added new strings in Romanian (ro.json) for additional details and currency descriptions. - Enhanced Russian (ru.json) with new strings for map style and preferred currency. - Updated Slovak (sk.json) with additional details for map style and preferred currency. - Enhanced Swedish (sv.json) with new strings for map style and preferred currency. - Added new strings in Turkish (tr.json) for map style and preferred currency. - Updated Ukrainian (uk.json) with new strings for map style and preferred currency. - Enhanced Chinese (zh.json) with additional details for map style and preferred currency. * feat: Implement cloud billing system with subscription management - Added billing app with models, serializers, views, and admin configuration for Subscription. - Integrated Stripe for payment processing and subscription management. - Created middleware for cloud access control based on user subscriptions. - Developed frontend components for subscription status and billing management. - Updated settings to include cloud mode and Stripe configuration. - Added routes for billing and subscription management in the API. - Implemented user subscription creation and management on user registration and checkout. * feat: Implement media storage limit and usage tracking - Added media storage limit configuration in settings. - Introduced utility functions for managing media storage limits and usage. - Updated models to delete media files using storage backend. - Enhanced serializers to build media URLs dynamically. - Implemented media usage tracking in user views and added endpoint for fetching media usage. - Updated frontend to display media storage usage and limits. - Added translations for media storage related strings in multiple languages. * feat: Implement conditional throttling for various external services and update settings for rate limits
89 lines
2.5 KiB
Python
89 lines
2.5 KiB
Python
from django.conf import settings
|
|
from django.core.files.storage import default_storage
|
|
from adventures.models import ContentAttachment, ContentImage
|
|
|
|
|
|
def get_media_storage_limit_bytes():
|
|
limit = getattr(settings, 'MEDIA_STORAGE_LIMIT_BYTES', 0) or 0
|
|
return limit if limit > 0 else None
|
|
|
|
|
|
def get_uploaded_file_size(file_obj):
|
|
if not file_obj:
|
|
return 0
|
|
size = getattr(file_obj, 'size', None)
|
|
if size is None:
|
|
try:
|
|
size = len(file_obj)
|
|
except TypeError:
|
|
size = 0
|
|
return size or 0
|
|
|
|
|
|
def _sum_storage_sizes(names):
|
|
total = 0
|
|
for name in names:
|
|
if not name:
|
|
continue
|
|
try:
|
|
total += default_storage.size(name)
|
|
except (OSError, ValueError, FileNotFoundError):
|
|
continue
|
|
return total
|
|
|
|
|
|
def get_user_media_usage(user, exclude_names=None):
|
|
exclude_names = set(filter(None, exclude_names or []))
|
|
|
|
image_names = set(
|
|
ContentImage.objects.filter(user=user)
|
|
.exclude(image__isnull=True)
|
|
.exclude(image='')
|
|
.values_list('image', flat=True)
|
|
)
|
|
attachment_names = set(
|
|
ContentAttachment.objects.filter(user=user)
|
|
.exclude(file__isnull=True)
|
|
.exclude(file='')
|
|
.values_list('file', flat=True)
|
|
)
|
|
profile_names = set()
|
|
if user.profile_pic and user.profile_pic.name:
|
|
profile_names.add(user.profile_pic.name)
|
|
|
|
image_names -= exclude_names
|
|
attachment_names -= exclude_names
|
|
profile_names -= exclude_names
|
|
|
|
images_bytes = _sum_storage_sizes(image_names)
|
|
attachments_bytes = _sum_storage_sizes(attachment_names)
|
|
profile_pics_bytes = _sum_storage_sizes(profile_names)
|
|
|
|
return {
|
|
"total_bytes": images_bytes + attachments_bytes + profile_pics_bytes,
|
|
"images_bytes": images_bytes,
|
|
"attachments_bytes": attachments_bytes,
|
|
"profile_pics_bytes": profile_pics_bytes,
|
|
"images_files": len(image_names),
|
|
"attachments_files": len(attachment_names),
|
|
"profile_pics_files": len(profile_names),
|
|
}
|
|
|
|
|
|
def enforce_media_storage_limit(user, incoming_bytes, exclude_names=None):
|
|
limit = get_media_storage_limit_bytes()
|
|
if not limit:
|
|
return True, None
|
|
|
|
usage = get_user_media_usage(user, exclude_names=exclude_names)
|
|
projected = usage["total_bytes"] + max(incoming_bytes, 0)
|
|
|
|
if projected > limit:
|
|
return False, {
|
|
"limit_bytes": limit,
|
|
"current_bytes": usage["total_bytes"],
|
|
"incoming_bytes": incoming_bytes,
|
|
}
|
|
|
|
return True, None
|