- Full PWA support with offline capabilities - Comprehensive search across songs, playlists, and channels - Offline playlist manager with download tracking - Pre-built frontend for zero-build deployment - Docker-based deployment with docker compose - Material-UI dark theme interface - YouTube audio download and management - Multi-user authentication support
4.9 KiB
4.9 KiB
Avatar Upload Feature
Overview
Users can now customize their profile avatar with either preset avatars or custom uploads. Avatars are stored persistently and survive container rebuilds.
Features Implemented
Backend
-
User Model Update (
backend/user/models.py)- Added
avatarfield to Account model - Stores either
preset_X(1-5) or path to custom uploaded file
- Added
-
Avatar Upload Endpoint (
backend/user/views.py)POST /api/user/avatar/upload/- Upload custom avatar- Max size: 20MB
- Allowed types: JPEG, PNG, GIF, WebP
- Automatically removes old custom avatar
- Generates safe filename:
username_timestamp.ext
DELETE /api/user/avatar/upload/- Remove avatar- Security: File validation, path sanitization, user isolation
-
Avatar Preset Endpoint (
backend/user/views.py)POST /api/user/avatar/preset/- Set preset avatar (1-5)- Validates preset number
- Removes old custom avatar file if exists
-
Avatar File Serving (
backend/user/views.py)GET /api/user/avatar/file/<filename>/- Serve custom avatars- Security: Path traversal prevention, symlink protection
- Proper content-type detection
-
User Serializer Update (
backend/user/serializers.py)- Added
avatarandavatar_urlfields avatar_urlreturns full URL for frontend:- Presets:
/avatars/preset_X.svg(served from frontend public folder) - Custom:
/api/user/avatar/file/<filename>/(served from backend)
- Presets:
- Added
Frontend
-
Preset Avatars (
frontend/public/avatars/)- 5 musical-themed SVG avatars:
preset_1.svg- Music note (Indigo)preset_2.svg- Headphones (Pink)preset_3.svg- Microphone (Green)preset_4.svg- Vinyl record (Amber)preset_5.svg- Waveform (Purple)
- 5 musical-themed SVG avatars:
-
AvatarDialog Component (
frontend/src/components/AvatarDialog.tsx)- Grid of 5 preset avatars
- Custom upload with drag-and-drop style UI
- File validation (size, type)
- Remove avatar option
- Success/error notifications
- Visual feedback (checkmark on current avatar)
-
TopBar Update (
frontend/src/components/TopBar.tsx)- Fetches user data on mount
- Displays avatar or username initial
- Click avatar to open selection dialog
- Hover effect on avatar
- Shows username instead of "Music Lover"
Storage
- Location:
/app/data/avatars/ - Persistence: Mounted via
./data:/app/datavolume in docker-compose - Survives: Container rebuilds, restarts, code updates
- Security: Path validation prevents directory traversal
User Experience
- Click avatar in top-left corner
- Dialog opens with:
- 5 preset avatars in a grid
- Upload button for custom image
- Remove button to clear avatar
- Select preset → Instantly updates
- Upload custom → Validates, uploads, updates
- Avatar persists across sessions
Security Features
- File size limit (20MB)
- File type validation (JPEG, PNG, GIF, WebP)
- Filename sanitization (timestamp-based)
- Path traversal prevention
- Symlink protection
- User isolation (can only access own avatars)
- Authentication required for all endpoints
Migration Required
Before running, execute in container:
docker exec -it soundwave python manage.py makemigrations user
docker exec -it soundwave python manage.py migrate user
Or rebuild container:
docker-compose down
docker-compose build
docker-compose up -d
Testing Checklist
- Click avatar opens dialog
- All 5 presets visible and clickable
- Upload JPEG works
- Upload PNG works
- File size validation (try >20MB)
- File type validation (try PDF)
- Remove avatar works
- Avatar persists after container restart
- Avatar shows on mobile
- Username displays instead of "Music Lover"
- Both admin and managed users can set avatars
- Custom avatars survive rebuild
API Endpoints
POST /api/user/avatar/upload/ - Upload custom avatar (multipart/form-data)
DELETE /api/user/avatar/upload/ - Remove avatar
POST /api/user/avatar/preset/ - Set preset avatar (body: {"preset": 1-5})
GET /api/user/avatar/file/<name>/ - Serve custom avatar file
GET /api/user/account/ - Includes avatar and avatar_url
Files Modified
backend/user/models.py- Added avatar fieldbackend/user/views.py- Added avatar endpointsbackend/user/urls.py- Added avatar routesbackend/user/serializers.py- Added avatar_url field
Files Created
frontend/src/components/AvatarDialog.tsx- Avatar selection dialogfrontend/public/avatars/preset_1.svg- Music note avatarfrontend/public/avatars/preset_2.svg- Headphones avatarfrontend/public/avatars/preset_3.svg- Microphone avatarfrontend/public/avatars/preset_4.svg- Vinyl record avatarfrontend/public/avatars/preset_5.svg- Waveform avatardocs/AVATAR_FEATURE.md- This documentation