Compare commits

..

2 Commits

Author SHA1 Message Date
cd593b8e5c penambahan field content 2025-07-29 23:01:01 +07:00
e91f2bfbdf not required on pu 2025-07-28 10:47:45 +07:00
6 changed files with 145 additions and 14 deletions

View File

@ -10,6 +10,15 @@ class CharacterSerializer(serializers.ModelSerializer):
model = models.Character
fields = ['id', 'name', 'description', 'sex', 'type', 'featured_image', 'featured_icon']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
request_method = self.context.get('request').method if self.context.get('request') else None
if request_method in ['PUT', 'PATCH']:
# Jadikan optional di update
self.fields['featured_image'].required = False
self.fields['featured_icon'].required = False
class CharacterSkinSerializer(serializers.ModelSerializer):
featured_image = ImageField(max_length=255, allow_empty_file=False)
featured_icon = ImageField(max_length=255, allow_empty_file=False)
@ -18,6 +27,15 @@ class CharacterSkinSerializer(serializers.ModelSerializer):
model = models.CharacterSkin
fields = ['id', 'name', 'description', 'featured_image', 'featured_icon', 'character']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
request_method = self.context.get('request').method if self.context.get('request') else None
if request_method in ['PUT', 'PATCH']:
# Jadikan optional di update
self.fields['featured_image'].required = False
self.fields['featured_icon'].required = False
class CharacterSkinDetailSerializer(serializers.ModelSerializer):
character = CharacterSerializer(read_only=True)
featured_image = ImageField(max_length=255, allow_empty_file=False)

View File

@ -21,8 +21,8 @@ def validate_image(image):
raise ValidationError("Invalid image file.")
def validate_file_size(image):
if image.size > 10 * 1024 * 1024:
raise ValidationError("File size exceeds 10MB.")
if image.size > 1 * 1024 * 1024:
raise ValidationError("File size exceeds 1MB.")
class Content(SoftDeleteModel):
@ -52,7 +52,7 @@ class Content(SoftDeleteModel):
('olahraga', 'Olahraga'),
('waktu-tidur', 'Waktu Tidur'),
('kesehatan-mental', 'Kesehatan Mental'),
('pendidikan-seksua', 'Pendidikan Seksual'),
('pendidikan-seksual', 'Pendidikan Seksual'),
('rokok-alkohol-narkoba', 'Bahaya Merokok dan Alkohol serta Pencegahan Narkoba'),
('sistem-imun', 'Sistem Imun')
],
@ -69,7 +69,7 @@ class Content(SoftDeleteModel):
],
'keselamatan': [
('lalu-lintas', 'Keselamatan Berlalu Lintas'),
('pertolongan-pertama', 'Pertolongan Petrtama'),
('pertolongan-pertama', 'Pertolongan Pertama'),
('bencana', 'Kesiapsiagaan Bencana')
]
}
@ -87,10 +87,22 @@ class Content(SoftDeleteModel):
('personality-quiz', 'Permainan Tebak Sifat'),
('game-map', 'Peta Permainan'),
('pilihan-ganda', 'Pilihan Ganda'),
('augmented-reality', 'Augmented Reality'),
]
CONTENT_TYPE_CHOICES = [
('content','Konten'),
('advertorial', 'Advertorial'),
]
CONTENT_STATUS_CHOICES = [
('draft', 'Draf'),
('published', 'Dipublikasikan'),
('archived', 'Diarsipkan'),
]
title = models.CharField(max_length=255, null=False)
slug = models.SlugField(max_length=255)
slug = models.SlugField(max_length=255, unique=True)
featured_image = models.ImageField(
max_length=255,
@ -98,24 +110,30 @@ class Content(SoftDeleteModel):
validators=[validate_image_size, validate_image_ext, validate_image],
null=False, blank=False)
theme = models.CharField(max_length=25, choices=CONTENT_THEME_CHOICES)
topic = models.CharField(max_length=25)
format = models.CharField(max_length=25, choices=CONTENT_FORMAT_CHOICES)
theme = models.CharField(max_length=50, choices=CONTENT_THEME_CHOICES)
topic = models.CharField(max_length=50)
format = models.CharField(max_length=50, choices=CONTENT_FORMAT_CHOICES)
description = models.CharField(max_length=255, null=True, blank=True)
content = models.TextField(null=True)
data = models.JSONField(null=True)
grades = models.JSONField(null=True)
grades = models.JSONField(null=True, blank=True)
point = models.IntegerField()
coin = models.IntegerField()
color = models.CharField(max_length=7, null=True, blank=True)
type = models.CharField(max_length=50, choices=CONTENT_TYPE_CHOICES, default='content')
status = models.CharField(max_length=50, choices=CONTENT_STATUS_CHOICES, default='draft')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
posted_at = models.DateTimeField(null=True, blank=True)
archived_at = models.DateTimeField(null=True, blank=True)
def __str__(self):
return self.title
@ -124,7 +142,7 @@ class Media(SoftDeleteModel):
name = models.CharField(max_length=255, null=False)
media = models.FileField(
max_length=255,
upload_to="uploads/medias/",
upload_to="uploads/media/",
validators=[validate_file_size],
null=False, blank=False)

View File

@ -8,14 +8,69 @@ class ContentSerializer(serializers.ModelSerializer):
class Meta:
model = models.Content
fields = ['id', 'title', 'slug', 'featured_image', 'theme', 'topic', 'format', 'description','content', 'point', 'coin', 'data', 'grades', 'color']
fields = [
'id',
'title',
'slug',
'featured_image',
'theme',
'topic',
'format',
'description',
'content',
'point',
'coin',
'data',
'grades',
'color',
'type',
'status',
'posted_at',
'archived_at',
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
request_method = self.context.get('request').method if self.context.get('request') else None
if request_method in ['PUT', 'PATCH']:
self.fields['featured_image'].required = False
class ContentDetailSerializer(serializers.ModelSerializer):
featured_image = ImageField(max_length=255, allow_empty_file=False)
theme_display = serializers.SerializerMethodField()
topic_display = serializers.SerializerMethodField()
format_display = serializers.SerializerMethodField()
type_display = serializers.SerializerMethodField()
status_display = serializers.SerializerMethodField()
class Meta:
model = models.Content
fields = ['id', 'title', 'slug', 'featured_image', 'theme', 'topic', 'format', 'description','content', 'point', 'coin', 'data', 'grades', 'color']
fields = [
'id',
'title',
'slug',
'featured_image',
'theme',
'topic',
'format',
'description',
'content',
'point',
'coin',
'data',
'grades',
'color',
'type',
'status',
'posted_at',
'archived_at',
'theme_display',
'topic_display',
'format_display',
'type_display',
'status_display',
]
def validate(self, data):
theme = data.get('theme')
@ -29,6 +84,25 @@ class ContentDetailSerializer(serializers.ModelSerializer):
return data
def get_theme_display(self, obj):
return dict(models.Content.CONTENT_THEME_CHOICES).get(obj.theme)
def get_topic_display(self, obj):
# Ambil label topic dari dict berdasarkan theme
topic_choices = dict(models.Content.CONTENT_TOPIC_CHOICES).get(obj.theme, [])
topic_dict = dict(topic_choices)
return topic_dict.get(obj.topic)
def get_format_display(self, obj):
return dict(models.Content.CONTENT_FORMAT_CHOICES).get(obj.format, obj.format)
def get_type_display(self, obj):
return dict(models.Content.CONTENT_TYPE_CHOICES).get(obj.type, obj.type)
def get_status_display(self, obj):
return dict(models.Content.CONTENT_STATUS_CHOICES).get(obj.status, obj.status)
class ContentMediaSerializer(serializers.ModelSerializer):
media = FileField(max_length=255, allow_empty_file=False)

View File

@ -8,6 +8,8 @@ urlpatterns = [
path('themes/', views.ContentThemeChoices.as_view()),
path('topics/<str:theme_key>/', views.ContentTopicChoices.as_view()),
path('formats/', views.ContentFormatChoices.as_view()),
path('types/', views.ContentTypeChoices.as_view()),
path('statuses/', views.ContentStatusChoices.as_view()),
path('media/', views.ContentMediaList.as_view()),
path('media/<int:pk>/', views.ContentMediaDetail.as_view()),

View File

@ -95,4 +95,24 @@ class ContentMediaDetail(generics.RetrieveUpdateDestroyAPIView):
serializer_class = serializers.ContentMediaSerializer
filter_backends = [filters.SearchFilter, filters.OrderingFilter]
search_fields = ['name']
ordering_fields = '__all__'
ordering_fields = '__all__'
class ContentTypeChoices(views.APIView):
def get(self, request, *args, **kwargs):
return Response({
"count": len(models.Content.CONTENT_TYPE_CHOICES),
"results": [
{"value": choice[0], "label": choice[1]}
for choice in models.Content.CONTENT_TYPE_CHOICES
]
})
class ContentStatusChoices(views.APIView):
def get(self, request, *args, **kwargs):
return Response({
"count": len(models.Content.CONTENT_STATUS_CHOICES),
"results": [
{"value": choice[0], "label": choice[1]}
for choice in models.Content.CONTENT_STATUS_CHOICES
]
})

View File

@ -22,7 +22,6 @@ from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# path('admin/', admin.site.urls),
path('admin/', admin.site.urls),
path('oauth/', include(oauth2_urls)),
path('auth/', include('djoser.urls')),