Fakultas Ilmu Komputer UI
Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
PMPL
Class Project
DIGIPUS
Commits
56c108ac
Commit
56c108ac
authored
Oct 26, 2020
by
Edward Partogi Gembira Abyatar
Browse files
[
#63
] Added video descriptions for Materi Models
parent
512cbda6
Changes
9
Hide whitespace changes
Inline
Side-by-side
app/forms.py
View file @
56c108ac
...
...
@@ -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
)
...
...
app/migrations/0019_materi_yt_video_id.py
0 → 100644
View file @
56c108ac
# 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
),
),
]
app/migrations/0023_merge_20201016_1713.py
0 → 100644
View file @
56c108ac
# 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
=
[
]
app/migrations/0024_merge_20201026_0812.py
0 → 100644
View file @
56c108ac
# 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
=
[
]
app/models.py
View file @
56c108ac
...
...
@@ -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
)
...
...
app/services.py
View file @
56c108ac
...
...
@@ -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
()
...
...
app/templates/app/detail_materi.html
View file @
56c108ac
...
...
@@ -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" %}
...
...
app/tests.py
View file @
56c108ac
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
()
...
...
app/views.py
View file @
56c108ac
...
...
@@ -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
=
{}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment