Skip to content

Commit

Permalink
Merge branch 'dev' into yeonwoo/payments
Browse files Browse the repository at this point in the history
  • Loading branch information
AlbertImKr authored Oct 13, 2024
2 parents 817285c + 9b0894e commit 0659915
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 115 deletions.
55 changes: 42 additions & 13 deletions materials/models.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
import uuid

from accounts.models import CustomUser
from courses.models import Course, Topic
from django.db import models


def upload_to(instance, filename):
"""
ImageField를 통해 파일이 업로드될 때 해당 파일의 저장 경로를 동적으로 생성합니다.
- 모델 인스턴스가 save() 호출될 때, 파일이 저장되기 전 upload_to에 정의된 경로를 생성하기 위해 호출됩니다.
- ImageField의 upload_to 인자로 전달됩니다.
- 생성된 경로를 반환하며, 이 경로는 Django가 해당 파일을 저장할 때 사용됩니다.
- (장점) 사용자 접근성을 높이면서 중복 파일 이름 문제를 해결합니다.
"""
ext = filename.split(".")[-1]
return f"images/{uuid.uuid4()}.{ext}"


class Image(models.Model):
"""
이미지 객체를 위해 작성된 모델입니다.
"""

course = models.OneToOneField(
Course,
on_delete=models.CASCADE,
Expand All @@ -18,30 +36,34 @@ class Image(models.Model):
null=True,
blank=True,
)
title = models.CharField(max_length=255, verbose_name="이미지 제목")
file = models.ImageField(upload_to="images/", verbose_name="이미지 파일")
image_url = models.URLField(
upload_to="images/", blank=True, null=True, verbose_name="이미지 파일"
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

def __str__(self):
return f"{self.topic.title} - {self.title}"

# 실제 이미지 파일
image = models.ImageField(upload_to="images/", blank=True, null=True)
if self.user:
return f"{self.user}'s Image"
elif self.course:
return f"Course Image for {self.course}"
return "Image"

def save(self, *args, **kwargs):

if self.user and not self.file:
self.file = "images/default_user_image.jpg"
if self.course and not self.file:
self.file = "images/default_course_image.jpg"
if self.user and not self.image_url:
self.image_url = "images/default_user_image.jpg"
if self.course and not self.image_url:
self.image_url = "images/default_course_image.jpg"
super().save(*args, **kwargs)


class Video(models.Model):
topic = models.OneToOneField(Topic, on_delete=models.CASCADE, related_name="video")
title = models.CharField(max_length=255, verbose_name="비디오 제목")
file = models.FileField(upload_to="videos/", verbose_name="비디오 파일")
course = models.OneToOneField(
Course, on_delete=models.CASCADE, related_name="video"
)
video_url = models.FileField(upload_to="videos/", verbose_name="비디오 파일")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

Expand All @@ -56,11 +78,18 @@ class VideoEventData(models.Model):
("leave", "Left Page"),
]

user = models.ForeignKey(
CustomUser,
on_delete=models.CASCADE,
related_name="video_event_datas",
verbose_name="시청 기록의 해당 사용자",
)

video = models.ForeignKey(
Video,
on_delete=models.CASCADE,
related_name="video_event_datas",
verbose_name="해당 비디오",
verbose_name="시청 기록의 해당 비디오",
)

event_type = models.CharField(
Expand Down
46 changes: 25 additions & 21 deletions materials/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,35 @@


class ImageSerializer(serializers.ModelSerializer):
"""
이미지 생성(업로드)을 위한 시리얼라이저입니다.
- 형식, 손상 여부에 대해 유효성 검사를 합니다.
"""

class Meta:
model = Image
fields = [
"id",
"title",
"file",
"image_url",
"created_at",
"updated_at",
]
read_only_fields = ["id", "created_at", "updated_at"]

def validate_file(self, value):
# 이미지 형식과 크기 유효성 검사
def validate_image_url(self, value):
allowed_image_extensions = (".png", ".jpg", ".jpeg")
max_image_size = 5 * 1024 * 1024 # 5MB

if not value.name.endswith(allowed_image_extensions):
raise serializers.ValidationError(
"지원하지 않는 파일 형식입니다. PNG, JPG, JPEG만 가능합니다."
)

if value.size > max_image_size:
raise serializers.ValidationError("파일 크기는 5MB를 초과할 수 없습니다.")

# 이미지 손상 여부 검사
try:
img = PILImage.open(value)
img.verify()
except Exception:
raise serializers.ValidationError("유효한 이미지 파일이 아닙니다.")

# 중복 파일명 검사
user = self.context["request"].user
if Image.objects.filter(user=user, file__exact=value.name).exists():
raise serializers.ValidationError("이미 존재하는 파일명입니다.")

return value


Expand All @@ -57,8 +49,7 @@ class Meta:
"topic",
"topic_title",
"course_title",
"title",
"file",
"video_url",
"created_at",
"updated_at",
]
Expand All @@ -73,7 +64,7 @@ def validate_topic(self, value):
)
return value

def validate_file(self, value):
def validate_image_url(self, value):
# 영상 형식과 크기 유효성 검사
allowed_extensions = ["mp4", "avi", "mov", "wmv"]
max_size = 100 * 1024 * 1024 # 100MB
Expand Down Expand Up @@ -169,10 +160,23 @@ def create(self, validated_data):
return video_event_data


class ViewEventListSerializer(serializers.ModelSerializer):
pass
class UserViewEventListSerializer(serializers.ModelSerializer):
duration_in_minutes = serializers.SerializerMethodField()
current_time_in_minutes = serializers.SerializerMethodField()

class Meta:
model = VideoEventData
fields = [
"event_type",
"duration",
"current_time",
"timestamp",
"duration_in_minutes", # 분과 초로 변환된 전체 재생시간
"current_time_in_minutes", # 분과 초로 변환된 현재 시간
]

class WatchHistorySerializer(serializers.Serializer):
def get_duration_in_minutes(self, obj):
return obj.get_duration_in_minutes()

pass
def get_current_time_in_minutes(self, obj):
return obj.get_current_time_in_minutes()
9 changes: 2 additions & 7 deletions materials/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,9 @@
views.VideoEventCreateView.as_view(),
name="video-event-data",
),
path(
"video/<int:video_id>/events",
views.VideoEventListView.as_view(),
name="video-event-list",
),
path(
"users/<int:user_id>/videos/<int:video_id>/watch-history/",
views.WatchHistoryRetrieveUpdateView.as_view(),
name="watch-history",
views.UserVideoEventListView.as_view(),
name="video-event-list",
),
]
Loading

0 comments on commit 0659915

Please sign in to comment.