1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-27 08:49:36 +02:00

feat: enhance transportation card and modal with image handling

- Added CardCarousel component to TransportationCard for image display.
- Implemented privacy indicator with Eye and EyeOff icons.
- Introduced image upload functionality in TransportationModal, allowing users to upload multiple images.
- Added image management features: remove image and set primary image.
- Updated Transportation and Location types to include images as ContentImage array.
- Enhanced UI for image upload and display in modal, including selected images preview and current images management.
This commit is contained in:
Sean Morley 2025-07-14 18:57:39 -04:00
parent ba162175fe
commit 7a61ba2d22
19 changed files with 3181 additions and 1549 deletions

View file

@ -64,47 +64,138 @@ class CollectionShared(permissions.BasePermission):
class IsOwnerOrSharedWithFullAccess(permissions.BasePermission):
"""
Full access for owners and users shared via collections,
read-only for others if public.
Permission class that provides access control based on ownership and sharing.
Access Rules:
- Object owners have full access (read/write)
- Users shared via collections have full access (read/write)
- Collection owners have full access to objects in their collections
- Users with direct sharing have full access
- Anonymous users get read-only access to public objects
- Authenticated users get read-only access to public objects
Supports multiple sharing patterns:
- obj.collections (many-to-many collections)
- obj.collection (single collection foreign key)
- obj.shared_with (direct sharing many-to-many)
- obj.is_public (public access flag)
"""
def has_object_permission(self, request, view, obj):
"""
Check if the user has permission to access the object.
Args:
request: The HTTP request
view: The view being accessed
obj: The object being accessed
Returns:
bool: True if access is granted, False otherwise
"""
user = request.user
is_safe_method = request.method in permissions.SAFE_METHODS
# Anonymous users only get read access to public objects
if not user or not user.is_authenticated:
return request.method in permissions.SAFE_METHODS and obj.is_public
# If safe method (read), allow if:
if request.method in permissions.SAFE_METHODS:
if obj.is_public:
return True
if obj.user == user:
return True
# If user in shared_with of any collection related to obj
if hasattr(obj, 'collections') and obj.collections.filter(shared_with=user).exists():
return True
# **FIX: Check if user OWNS any collection that contains this object**
if hasattr(obj, 'collections') and obj.collections.filter(user=user).exists():
return True
if hasattr(obj, 'collection') and obj.collection and obj.collection.shared_with.filter(id=user.id).exists():
return True
if hasattr(obj, 'collection') and obj.collection and obj.collection.user == user:
return True
if hasattr(obj, 'shared_with') and obj.shared_with.filter(id=user.id).exists():
return True
return False
# For write methods, allow if owner or shared user
if obj.user == user:
return is_safe_method and getattr(obj, 'is_public', False)
# Owner always has full access
if self._is_owner(obj, user):
return True
if hasattr(obj, 'collections') and obj.collections.filter(shared_with=user).exists():
# Check collection-based access (both ownership and sharing)
if self._has_collection_access(obj, user):
return True
# **FIX: Allow write access if user owns any collection containing this object**
if hasattr(obj, 'collections') and obj.collections.filter(user=user).exists():
# Check direct sharing
if self._has_direct_sharing_access(obj, user):
return True
if hasattr(obj, 'collection') and obj.collection and obj.collection.shared_with.filter(id=user.id).exists():
# For safe methods, check if object is public
if is_safe_method and getattr(obj, 'is_public', False):
return True
if hasattr(obj, 'collection') and obj.collection and obj.collection.user == user:
return True
if hasattr(obj, 'shared_with') and obj.shared_with.filter(id=user.id).exists():
return True
return False
return False
def _is_owner(self, obj, user):
"""
Check if the user is the owner of the object.
Args:
obj: The object to check
user: The user to check ownership for
Returns:
bool: True if user owns the object
"""
return hasattr(obj, 'user') and obj.user == user
def _has_collection_access(self, obj, user):
"""
Check if user has access via collections (either as owner or shared user).
Handles both many-to-many collections and single collection foreign keys.
Args:
obj: The object to check
user: The user to check access for
Returns:
bool: True if user has collection-based access
"""
# Check many-to-many collections (obj.collections)
if hasattr(obj, 'collections'):
collections = obj.collections.all()
if collections.exists():
# User is shared with any collection containing this object
if collections.filter(shared_with=user).exists():
return True
# User owns any collection containing this object
if collections.filter(user=user).exists():
return True
# Check single collection foreign key (obj.collection)
if hasattr(obj, 'collection') and obj.collection:
collection = obj.collection
# User is shared with the collection
if hasattr(collection, 'shared_with') and collection.shared_with.filter(id=user.id).exists():
return True
# User owns the collection
if hasattr(collection, 'user') and collection.user == user:
return True
return False
def _has_direct_sharing_access(self, obj, user):
"""
Check if user has direct sharing access to the object.
Args:
obj: The object to check
user: The user to check access for
Returns:
bool: True if user has direct sharing access
"""
return (hasattr(obj, 'shared_with') and
obj.shared_with.filter(id=user.id).exists())
def has_permission(self, request, view):
"""
Check if the user has permission to access the view.
This is called before has_object_permission and provides a way to
deny access at the view level (e.g., for unauthenticated users).
Args:
request: The HTTP request
view: The view being accessed
Returns:
bool: True if access is granted at the view level
"""
# Allow authenticated users and anonymous users for safe methods
# Individual object permissions are handled in has_object_permission
return (request.user and request.user.is_authenticated) or \
request.method in permissions.SAFE_METHODS