Fakultas Ilmu Komputer UI

Commit 56c108ac authored by Edward Partogi Gembira Abyatar's avatar Edward Partogi Gembira Abyatar
Browse files

[#63] Added video descriptions for Materi Models

parent 512cbda6
...@@ -12,11 +12,15 @@ class UploadMateriForm(forms.ModelForm): ...@@ -12,11 +12,15 @@ class UploadMateriForm(forms.ModelForm):
categories = forms.ModelMultipleChoiceField(queryset=Category.objects.all(),widget=forms.CheckboxSelectMultiple(attrs={'style' : 'column-count:2'}),required=True) categories = forms.ModelMultipleChoiceField(queryset=Category.objects.all(),widget=forms.CheckboxSelectMultiple(attrs={'style' : 'column-count:2'}),required=True)
#categories.widget.attrs["style"] = "column-count:2" #categories.widget.attrs["style"] = "column-count:2"
release_year = forms.TypedChoiceField(coerce=int, choices=year_choices, initial=datetime.date.today().year) release_year = forms.TypedChoiceField(coerce=int, choices=year_choices, initial=datetime.date.today().year)
yt_video_id = forms.CharField(label="Youtube Video Id", \
help_text="This is not required.<br>\
Please insert only Youtube link videos! Take a note for the video id!<br>\
Example : https://www.youtube.com/watch?v=DkJ-50GLi2I <br> has video id DkJ-50GLi2I", required=False)
class Meta: class Meta:
model = Materi model = Materi
fields = ["title", "author", "publisher", "release_year", fields = ["title", "author", "publisher", "release_year",
"categories", "descriptions", "cover", "content"] "categories", "descriptions", "cover", "content", "yt_video_id"]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(UploadMateriForm, self).__init__(*args, **kwargs) super(UploadMateriForm, self).__init__(*args, **kwargs)
......
# Generated by Django 3.1 on 2020-10-09 13:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0018_merge_20201009_0700'),
]
operations = [
migrations.AddField(
model_name='materi',
name='yt_video_id',
field=models.CharField(blank=True, max_length=100, null=True),
),
]
# Generated by Django 3.1 on 2020-10-16 10:13
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('app', '0022_merge_20201011_1122'),
('app', '0019_materi_yt_video_id'),
]
operations = [
]
# Generated by Django 3.1 on 2020-10-26 01:12
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('app', '0023_merge_20201016_1713'),
('app', '0023_materi_deleted_at'),
]
operations = [
]
...@@ -90,6 +90,7 @@ class Materi(SoftDeleteModel): ...@@ -90,6 +90,7 @@ class Materi(SoftDeleteModel):
categories = models.ManyToManyField(Category) categories = models.ManyToManyField(Category)
date_created = models.DateTimeField(default=timezone.now) date_created = models.DateTimeField(default=timezone.now)
date_modified = models.DateTimeField(auto_now=True) date_modified = models.DateTimeField(auto_now=True)
yt_video_id = models.CharField(max_length=100, blank=True, null=True)
_search_vector = search.SearchVectorField(null=True, editable=False) _search_vector = search.SearchVectorField(null=True, editable=False)
......
...@@ -16,6 +16,7 @@ from app.models import Category, Like, LikeComment, DislikeComment, Materi, Comm ...@@ -16,6 +16,7 @@ from app.models import Category, Like, LikeComment, DislikeComment, Materi, Comm
ViewStatistics ViewStatistics
from app.utils.fileManagementUtil import get_random_filename, remove_image_exifdata from app.utils.fileManagementUtil import get_random_filename, remove_image_exifdata
from digipus import settings from digipus import settings
import requests
class DafterKatalogService: class DafterKatalogService:
...@@ -306,15 +307,23 @@ class UploadMateriService: ...@@ -306,15 +307,23 @@ class UploadMateriService:
raise ValidationError("Unsupported file extension.") raise ValidationError("Unsupported file extension.")
@staticmethod @staticmethod
def validate_file_extension(konten, request): def validate_file_extension(konten, request, yt_video_id):
is_file_extension_valid = True is_file_extension_valid = True
try: try:
UploadMateriService.validate_extension(konten) UploadMateriService.validate_extension(konten)
except ValidationError: UploadMateriService.validate_yt_video_url(yt_video_id)
messages.error(request, "Materi gagal diunggah, format file tidak sesuai") except ValidationError as e:
messages.error(request, "Materi gagal diunggah, format file tidak sesuai"+str(e))
is_file_extension_valid = False is_file_extension_valid = False
return is_file_extension_valid return is_file_extension_valid
@staticmethod
def validate_yt_video_url(value):
is_yt_id_valid = True
r = requests.get('http://www.youtube.com/watch?v='+value)
if "\"playabilityStatus\":{\"status\":\"ERROR\"" in r.text:
raise ValidationError("Invalid Youtube video ID")
@staticmethod @staticmethod
def upload_materi(form, materi): def upload_materi(form, materi):
materi.save() materi.save()
......
...@@ -264,6 +264,16 @@ ...@@ -264,6 +264,16 @@
<h1>Deskripsi</h1> <h1>Deskripsi</h1>
<div class="col col-8 description"> <div class="col col-8 description">
<p>{{materi_data.descriptions}}</p> <p>{{materi_data.descriptions}}</p>
{% if materi_data.yt_video_id %}
<div style="border-top:1px solid #d4d4d4;text-align:center">
<h3>Video</h3>
<iframe src="https://www.youtube.com/embed/{{ materi_data.yt_video_id }}"
allowfullscreen="allowfullscreen"
width="564" height="300">
invalid video url
</iframe>
</div>
{% endif %}
</div> </div>
</div> </div>
{% if materi_data.status == "APPROVE" %} {% if materi_data.status == "APPROVE" %}
......
import json, tempfile, os, mock import json, tempfile, os, mock, base64
import pandas as pd import pandas as pd
from io import StringIO from io import StringIO
import time import time
from django.test import override_settings
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from datetime import datetime from datetime import datetime
...@@ -69,6 +70,7 @@ from selenium.webdriver.chrome.options import Options ...@@ -69,6 +70,7 @@ from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.keys import Keys
from webdriver_manager.chrome import ChromeDriverManager from webdriver_manager.chrome import ChromeDriverManager
from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import NoSuchElementException
import requests
from statistics import mean from statistics import mean
...@@ -2453,6 +2455,122 @@ class YearChoicesTest(TestCase): ...@@ -2453,6 +2455,122 @@ class YearChoicesTest(TestCase):
choices = year_choices() choices = year_choices()
self.assertEqual((2000, 2000), choices[0]) self.assertEqual((2000, 2000), choices[0])
TEST_IMAGE = '''
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
'''.strip()
class YTUrlVideoTest(TestCase):
def setUp(self):
self.client = Client()
self.contributor_credential = {"email": "kontributor@gov.id", "password": "passwordtest"}
self.contributor = get_user_model().objects.create_user(
**self.contributor_credential, name="Kontributor", is_contributor=True
)
self.setUpImage()
self.content = SimpleUploadedFile("ExampleFile221.pdf", b"Test file")
self.category = Category.objects.create(id="1", name="medis", description="kategori medis")
@override_settings(MEDIA_ROOT=tempfile.gettempdir())
def setUpImage(self):
from django.core.files.uploadedfile import InMemoryUploadedFile
from io import BytesIO
self.cover = InMemoryUploadedFile(
BytesIO(base64.b64decode(TEST_IMAGE)),
field_name='tempfile',
name='tempfile.png',
content_type='image/png',
size=len(TEST_IMAGE),
charset='utf-8',
)
def test_yt_video_id_exists_in_Materi(self):
materiTemp = Materi.objects.create()
self.assertEqual(hasattr(materiTemp, 'yt_video_id'), True)
def test_yt_video_id_exists_in_UploadMateri_page(self):
self.client.login(**self.contributor_credential)
response = self.client.get("/unggah/")
html = response.content.decode("utf-8")
self.assertIn('Youtube Video Id', html)
def test_upload_materi_with_valid_yt_video_id(self):
self.client.login(**self.contributor_credential)
response = self.client.post(
"/unggah/", data={"title":"Materi 1", "author":"Agas", "publisher":"Kelas SC", "release_year":"2000",
"descriptions":"Deskripsi Materi 1", 'categories':"1",
"cover":self.cover, "content":self.content,
"yt_video_id":"jNwz4L9MGVY"}
)
self.assertTrue(Materi.objects.get(title="Materi 1"))
def test_upload_materi_with_invalid_yt_video_id(self):
self.client.login(**self.contributor_credential)
response = self.client.post(
"/unggah/", data={"title":"Materi 2", "author":"Agas", "publisher":"Kelas SC", "release_year":"2000",
"descriptions":"Deskripsi Materi 1", 'categories':"1",
"cover":self.cover, "content":self.content,
"yt_video_id":"randomId"}
)
self.assertEqual(Materi.objects.filter(title="Materi 2").count(), 0)
def test_detail_materi_has_video_if_yt_video_id_not_empty(self):
self.test_upload_materi_with_valid_yt_video_id()
pk = Materi.objects.get(title="Materi 1").pk
response = self.client.get("/materi/"+str(pk)+"/")
html = response.content.decode("utf-8")
self.assertIn("Video", html)
def test_detail_materi_has_no_video_if_yt_video_id_empty(self):
self.client.login(**self.contributor_credential)
response = self.client.post(
"/unggah/", data={"title":"Materi 2", "author":"Agas", "publisher":"Kelas SC", "release_year":"2000",
"descriptions":"Deskripsi Materi 1", 'categories':"1",
"cover":self.cover, "content":self.content,}
)
pk = Materi.objects.get(title="Materi 2").pk
response = self.client.get("/materi/"+str(pk)+"/")
html = response.content.decode("utf-8")
self.assertNotIn("Video", html)
class ChangePasswordTest(TestCase): class ChangePasswordTest(TestCase):
def setUp(self): def setUp(self):
self.client = Client() self.client = Client()
......
...@@ -284,7 +284,8 @@ class UploadMateriView(TemplateView): ...@@ -284,7 +284,8 @@ class UploadMateriView(TemplateView):
materi = form.save(commit=False) materi = form.save(commit=False)
materi.uploader = request.user materi.uploader = request.user
konten = form.cleaned_data["content"] konten = form.cleaned_data["content"]
if not UploadMateriService.validate_file_extension(konten, request): yt_url_id = form.cleaned_data['yt_video_id']
if not UploadMateriService.validate_file_extension(konten, request, yt_url_id):
return HttpResponseRedirect("/unggah/") return HttpResponseRedirect("/unggah/")
UploadMateriService.upload_materi(form, materi) UploadMateriService.upload_materi(form, materi)
messages.success(request, "Materi berhasil diunggah, periksa riwayat unggah anda") messages.success(request, "Materi berhasil diunggah, periksa riwayat unggah anda")
...@@ -306,8 +307,6 @@ class UploadMateriView(TemplateView): ...@@ -306,8 +307,6 @@ class UploadMateriView(TemplateView):
return self.render_to_response(context) return self.render_to_response(context)
class UploadMateriHTML(TemplateView): class UploadMateriHTML(TemplateView):
template_name = "unggah.html" template_name = "unggah.html"
context = {} context = {}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment