Initial commit - SoundWave v1.0

- 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
This commit is contained in:
Iulian 2025-12-16 23:43:07 +00:00
commit 51679d1943
254 changed files with 37281 additions and 0 deletions

View file

@ -0,0 +1,181 @@
"""Serializers for admin user management"""
from rest_framework import serializers
from user.models import Account, UserYouTubeAccount
from channel.models import Channel
from playlist.models import Playlist
class UserStatsSerializer(serializers.Serializer):
"""User statistics"""
total_channels = serializers.IntegerField()
total_playlists = serializers.IntegerField()
total_audio_files = serializers.IntegerField()
storage_used_gb = serializers.FloatField()
storage_quota_gb = serializers.IntegerField()
storage_percent = serializers.FloatField()
class UserDetailSerializer(serializers.ModelSerializer):
"""Detailed user information for admin"""
storage_percent_used = serializers.FloatField(read_only=True)
can_add_channel = serializers.BooleanField(read_only=True)
can_add_playlist = serializers.BooleanField(read_only=True)
stats = serializers.SerializerMethodField()
created_by_username = serializers.CharField(source='created_by.username', read_only=True)
class Meta:
model = Account
fields = [
'id',
'username',
'email',
'is_admin',
'is_active',
'is_staff',
'is_superuser',
'two_factor_enabled',
'storage_quota_gb',
'storage_used_gb',
'storage_percent_used',
'max_channels',
'max_playlists',
'can_add_channel',
'can_add_playlist',
'user_notes',
'created_by',
'created_by_username',
'date_joined',
'last_login',
'stats',
]
read_only_fields = [
'id',
'date_joined',
'last_login',
'storage_used_gb',
'two_factor_enabled',
]
def get_stats(self, obj):
"""Get user statistics"""
from audio.models import Audio
channels_count = Channel.objects.filter(owner=obj).count()
playlists_count = Playlist.objects.filter(owner=obj).count()
audio_count = Audio.objects.filter(owner=obj).count()
return {
'total_channels': channels_count,
'total_playlists': playlists_count,
'total_audio_files': audio_count,
'storage_used_gb': obj.storage_used_gb,
'storage_quota_gb': obj.storage_quota_gb,
'storage_percent': obj.storage_percent_used,
}
class UserCreateSerializer(serializers.ModelSerializer):
"""Create new user (admin only)"""
password = serializers.CharField(write_only=True, required=True, style={'input_type': 'password'})
password_confirm = serializers.CharField(write_only=True, required=True, style={'input_type': 'password'})
class Meta:
model = Account
fields = [
'username',
'email',
'password',
'password_confirm',
'is_admin',
'is_active',
'storage_quota_gb',
'max_channels',
'max_playlists',
'user_notes',
]
def validate(self, data):
"""Validate password match"""
if data['password'] != data['password_confirm']:
raise serializers.ValidationError({"password": "Passwords do not match"})
return data
def create(self, validated_data):
"""Create user with hashed password"""
validated_data.pop('password_confirm')
password = validated_data.pop('password')
user = Account.objects.create_user(
username=validated_data['username'],
email=validated_data['email'],
password=password,
)
# Update additional fields
for key, value in validated_data.items():
setattr(user, key, value)
# Set created_by from request context
request = self.context.get('request')
if request and request.user.is_authenticated:
user.created_by = request.user
user.save()
return user
class UserUpdateSerializer(serializers.ModelSerializer):
"""Update user (admin only)"""
class Meta:
model = Account
fields = [
'is_admin',
'is_active',
'is_staff',
'storage_quota_gb',
'max_channels',
'max_playlists',
'user_notes',
]
class UserYouTubeAccountSerializer(serializers.ModelSerializer):
"""YouTube account serializer"""
class Meta:
model = UserYouTubeAccount
fields = [
'id',
'account_name',
'youtube_channel_id',
'youtube_channel_name',
'is_active',
'auto_download',
'download_quality',
'created_date',
'last_verified',
]
read_only_fields = ['id', 'created_date', 'last_verified']
class UserYouTubeAccountCreateSerializer(serializers.ModelSerializer):
"""Create YouTube account"""
class Meta:
model = UserYouTubeAccount
fields = [
'account_name',
'youtube_channel_id',
'youtube_channel_name',
'cookies_file',
'auto_download',
'download_quality',
]
def create(self, validated_data):
"""Set user from request context"""
request = self.context.get('request')
if request and request.user.is_authenticated:
validated_data['user'] = request.user
return super().create(validated_data)