Files
Task_Reporter/app/modules/file_storage/models.py
egg 1d5d4d447d feat: Add mobile responsive layout, open room access, and admin room management
Mobile Responsive Layout:
- Add useMediaQuery, useIsMobile, useIsTablet, useIsDesktop hooks for device detection
- Create MobileHeader component with hamburger menu and action drawer
- Create BottomToolbar for mobile navigation (Files, Members)
- Create SlidePanel component for full-screen mobile sidebars
- Update RoomDetail.tsx with mobile/desktop conditional rendering
- Update RoomList.tsx with single-column grid and touch-friendly buttons
- Add CSS custom properties for safe areas and touch targets (min 44px)
- Add mobile viewport meta tags for notched devices

Open Room Access:
- All authenticated users can view all rooms (not just their own)
- Users can join active rooms they're not members of
- Add is_member field to room responses
- Update room list API to return all rooms by default

Admin Room Management:
- Add permanent delete functionality for system admins
- Add delete confirmation dialog with room title verification
- Broadcast room deletion via WebSocket to connected users
- Add users search API for adding members

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 09:12:10 +08:00

45 lines
1.5 KiB
Python

"""Database models for file storage"""
from sqlalchemy import Column, String, BigInteger, DateTime, Index, ForeignKey
from sqlalchemy.orm import relationship
from datetime import datetime
from app.core.database import Base
class RoomFile(Base):
"""File uploaded to an incident room"""
__tablename__ = "room_files"
# Primary key
file_id = Column(String(36), primary_key=True)
# Foreign key to incident room (CASCADE delete when room is permanently deleted)
room_id = Column(String(36), ForeignKey("incident_rooms.room_id", ondelete="CASCADE"), nullable=False)
# File metadata
uploader_id = Column(String(255), nullable=False)
filename = Column(String(255), nullable=False)
file_type = Column(String(20), nullable=False) # 'image', 'document', 'log'
mime_type = Column(String(100), nullable=False)
file_size = Column(BigInteger, nullable=False) # bytes
# MinIO storage information
minio_bucket = Column(String(100), nullable=False)
minio_object_path = Column(String(500), nullable=False)
# Timestamps
uploaded_at = Column(DateTime, default=datetime.utcnow, nullable=False)
deleted_at = Column(DateTime, nullable=True) # soft delete
# Relationships
room = relationship("IncidentRoom", back_populates="files")
# Indexes
__table_args__ = (
Index("ix_room_files", "room_id", "uploaded_at"),
Index("ix_file_uploader", "uploader_id"),
)
def __repr__(self):
return f"<RoomFile(file_id={self.file_id}, filename={self.filename}, room_id={self.room_id})>"