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):
categories = forms.ModelMultipleChoiceField(queryset=Category.objects.all(),widget=forms.CheckboxSelectMultiple(attrs={'style' : 'column-count:2'}),required=True)
#categories.widget.attrs["style"] = "column-count:2"
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:
model = Materi
fields = ["title", "author", "publisher", "release_year",
"categories", "descriptions", "cover", "content"]
"categories", "descriptions", "cover", "content", "yt_video_id"]
def __init__(self, *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):
categories = models.ManyToManyField(Category)
date_created = models.DateTimeField(default=timezone.now)
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)
......
......@@ -16,6 +16,7 @@ from app.models import Category, Like, LikeComment, DislikeComment, Materi, Comm
ViewStatistics
from app.utils.fileManagementUtil import get_random_filename, remove_image_exifdata
from digipus import settings
import requests
class DafterKatalogService:
......@@ -306,15 +307,23 @@ class UploadMateriService:
raise ValidationError("Unsupported file extension.")
@staticmethod
def validate_file_extension(konten, request):
def validate_file_extension(konten, request, yt_video_id):
is_file_extension_valid = True
try:
UploadMateriService.validate_extension(konten)
except ValidationError:
messages.error(request, "Materi gagal diunggah, format file tidak sesuai")
UploadMateriService.validate_yt_video_url(yt_video_id)
except ValidationError as e:
messages.error(request, "Materi gagal diunggah, format file tidak sesuai"+str(e))
is_file_extension_valid = False
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
def upload_materi(form, materi):
materi.save()
......
......@@ -264,6 +264,16 @@
<h1>Deskripsi</h1>
<div class="col col-8 description">
<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>
{% if materi_data.status == "APPROVE" %}
......
import json, tempfile, os, mock
import json, tempfile, os, mock, base64
import pandas as pd
from io import StringIO
import time
from django.test import override_settings
from bs4 import BeautifulSoup
from datetime import datetime
......@@ -69,6 +70,7 @@ from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from webdriver_manager.chrome import ChromeDriverManager
from selenium.common.exceptions import NoSuchElementException
import requests
from statistics import mean
......@@ -2453,6 +2455,122 @@ class YearChoicesTest(TestCase):
choices = year_choices()
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):
def setUp(self):
self.client = Client()
......
......@@ -284,7 +284,8 @@ class UploadMateriView(TemplateView):
materi = form.save(commit=False)
materi.uploader = request.user
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/")
UploadMateriService.upload_materi(form, materi)
messages.success(request, "Materi berhasil diunggah, periksa riwayat unggah anda")
......@@ -306,8 +307,6 @@ class UploadMateriView(TemplateView):
return self.render_to_response(context)
class UploadMateriHTML(TemplateView):
template_name = "unggah.html"
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