Skip to content

Commit

Permalink
feat: handled s3 uploading from frontend for course module
Browse files Browse the repository at this point in the history
  • Loading branch information
danish-kv committed Nov 9, 2024
1 parent 9f17b5f commit dd321ee
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 44 deletions.
18 changes: 18 additions & 0 deletions course/migrations/0018_alter_module_video.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.1 on 2024-11-09 11:08

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('course', '0017_alter_note_module_alter_note_user'),
]

operations = [
migrations.AlterField(
model_name='module',
name='video',
field=models.URLField(blank=True, max_length=500, null=True),
),
]
18 changes: 18 additions & 0 deletions course/migrations/0019_alter_module_video.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.1 on 2024-11-09 11:11

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('course', '0018_alter_module_video'),
]

operations = [
migrations.AlterField(
model_name='module',
name='video',
field=models.CharField(blank=True, max_length=500, null=True),
),
]
45 changes: 8 additions & 37 deletions course/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,34 +53,8 @@ class ModuleSerializer(ModelSerializer):

class Meta:
model = Module
fields = "__all__"

def validate_video(self, value):
"""
Validates the uploaded video file to ensure it is not
larger than 50 MB and has a valid format.
"""
if value.size > 50 * 1024 * 1024:
raise serializers.ValidationError('Video file size should not exceed 50 MB')

if not value.name.endswith(('mp4', 'mov', 'avi')):
raise serializers.ValidationError('Invalid video type')

return value


def validate_notes(self, value):
"""
Validates the uploaded notes file to ensure it is not
larger than 10 MB and has a valid format.
"""
if value.size > 10 * 1024 * 1024:
raise serializers.ValidationError('Notes file size should not be exceed 10MB')

if not value.name.endswith(('pdf', 'docx')):
raise serializers.ValidationError('Invalid file type for notes')
return value

fields = "__all__"
read_only_fields = ['video', 'notes']
def get_student_notes(self, obj):
"""
Retrieves the notes associated with the student for the module.
Expand Down Expand Up @@ -112,17 +86,14 @@ def get_is_liked(self, obj):

def update(self, instance, validated_data):
"""
Updates the module instance with validated data.
Deletes old video and notes files if new ones are provided.
Handle the update of all fields except for video and notes.
"""
new_video = validated_data.get('video', None)
if new_video and instance.video:
instance.video.delete(save=False)

new_notes = validated_data.get('notes', None)
if new_notes and instance.notes:
instance.notes.delete(save=False)
# Exclude video and notes, handled in the view
print('validate -====',validated_data)
validated_data.pop('video', None)
validated_data.pop('notes', None)

# Update remaining fields
for key, value in validated_data.items():
setattr(instance, key, value)

Expand Down
3 changes: 3 additions & 0 deletions course/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
PaymentSuccess,
ReviewViewSet,
NotesViewSet,
get_presigned_url
)

# Create a router for handling viewsets
Expand All @@ -27,4 +28,6 @@
path('modules/<pk>/mark-watched/', EditModuleView.as_view(), name='mark-watched'),
path('stripe/course-purchase/', CoursePurchaseView.as_view(), name='stripe-payment'),
path('payment_success/', PaymentSuccess.as_view(), name='payment-success'),
path('get-presigned-url/', get_presigned_url, name='get-presigned-url'),

]
91 changes: 85 additions & 6 deletions course/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,48 @@
from django.db.models import Q
from django.core.cache import cache
from rest_framework.exceptions import NotFound
import boto3
from rest_framework.decorators import api_view

# Set the Stripe API key
stripe.api_key = settings.STRIPE_SECRET_KEY





@api_view(['GET'])
def get_presigned_url(request):

s3 = boto3.client('s3',
aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY)

file_type = request.GET.get('file_type')
filename = request.GET.get('filename')


if file_type == 'video':
key = f'module_videos/{filename}'
elif file_type == 'notes':
key = f'module_notes/{filename}'
else:
return Response({'error': 'Invalid file type'}, status=status.HTTP_400_BAD_REQUEST)


presigned_url = s3.generate_presigned_url(
ClientMethod='put_object',
Params={
'Bucket': "react-direct-bucket",
'Key': key,
},
ExpiresIn=3600
)

return Response({'presignedUrl': presigned_url, 'key': key})



class CategoryViewSet(ModelViewSet):
"""
API view for handling Category operations.
Expand Down Expand Up @@ -238,8 +275,8 @@ def post(self, request, *args, **kwargs):
title = data['title']
description = data['description']
duration = data['duration']
video = request.FILES.get(f'video_{i}')
notes = request.FILES.get(f'notes_{i}')
video = data.get('video')
notes = data.get('notes')

Module.objects.create(
course=course,
Expand All @@ -266,12 +303,54 @@ def patch(self, request, *args, **kwargs):
"""
Handle patch requests for toggling likes or marking a module as watched.
"""
if 'toggle-like' in request.path:
return self.toggle_like(request, *args, **kwargs)
if 'mark-watched' in request.path:
return self.mark_watched(request, *args, **kwargs)
try:
if 'toggle-like' in request.path:
return self.toggle_like(request, *args, **kwargs)
if 'mark-watched' in request.path:
return self.mark_watched(request, *args, **kwargs)
except Exception as e:
return Response(str(e), status=status.HTTP_400_BAD_REQUEST)
return super().patch(request, *args, **kwargs)

def perform_update(self, serializer):
"""
Handle the manual update of the 'video' and 'notes' paths.
"""
instance = self.get_object()

# Handle video and notes path updates manually
video_url = self.request.data.get('video', '')
notes_url = self.request.data.get('notes', '')

# Manually update video and notes
if video_url:
instance.video = video_url
if notes_url:
instance.notes = notes_url


# Now let the serializer handle the rest of the fields
validated_data = serializer.validated_data
validated_data.pop('video', None)
validated_data.pop('notes', None)

# Update remaining fields with serializer and save
for key, value in validated_data.items():
setattr(instance, key, value)

# Save the instance
instance.save()

# manually update the video and notes fields
if video_url:
instance.video = video_url
if notes_url:
instance.notes = notes_url

instance.save() # Save again to persist video and notes



def toggle_like(self, request, pk=None):
"""
Toggle the like status of a module for the authenticated user.
Expand Down
2 changes: 1 addition & 1 deletion users/api/user_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def validate(self, attrs):
}, code='authorization')

# Check if verified
if not user.is_verified:
if not user.is_verified and user.role != 'admin':
otp = generate_otp()
user.otp = otp
user.save()
Expand Down

0 comments on commit dd321ee

Please sign in to comment.