Fakultas Ilmu Komputer UI
Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
PMPL
Class Project
DIGIPUS
Commits
571c5e68
Commit
571c5e68
authored
Oct 31, 2020
by
Yaumi
Browse files
refactor code conflict
parents
e9a0c90b
c320f26c
Changes
43
Hide whitespace changes
Inline
Side-by-side
.gitlab-ci.yml
View file @
571c5e68
...
...
@@ -100,8 +100,11 @@ Dev Docker Image:
-
.docker-image
-
.development
allow_failure
:
true
when
:
manual
Prod Docker Image
:
extends
:
-
.docker-image
-
.production
\ No newline at end of file
-
.production
when
:
manual
allow_failure
:
true
\ No newline at end of file
administration/choices.py
View file @
571c5e68
...
...
@@ -18,7 +18,7 @@ BASE_PERIODE = [
]
def
gener
e
ate
P
eriode
C
hoices
():
def
generate
_p
eriode
_c
hoices
():
periode
=
BASE_PERIODE
now
=
timezone
.
now
()
# Month
...
...
administration/forms.py
View file @
571c5e68
...
...
@@ -3,7 +3,7 @@ from crispy_forms.layout import Layout, Submit, Row, Column, Reset, ButtonHolder
from
crispy_forms.bootstrap
import
InlineCheckboxes
from
django
import
forms
from
administration.choices
import
gener
e
ate
P
eriode
C
hoices
from
administration.choices
import
generate
_p
eriode
_c
hoices
from
administration.models
import
VerificationSetting
from
app.models
import
Category
from
authentication.models
import
User
...
...
@@ -88,7 +88,7 @@ class RegistrasiAdminForm(forms.ModelForm):
class
PeriodForm
(
forms
.
Form
):
period
=
forms
.
ChoiceField
(
choices
=
gener
e
ate
P
eriode
C
hoices
(),
label
=
"Periode"
,
required
=
False
)
choices
=
generate
_p
eriode
_c
hoices
(),
label
=
"Periode"
,
required
=
False
)
start_date
=
forms
.
DateField
(
widget
=
DateInput
,
label
=
"Waktu mulai"
,
required
=
False
)
end_date
=
forms
.
DateField
(
...
...
@@ -102,14 +102,16 @@ class PeriodForm(forms.Form):
for
field_name
,
field
in
self
.
fields
.
items
():
field
.
widget
.
attrs
[
'class'
]
=
'form-control'
period_css_class
=
'form-group col-md-4 mb-0'
self
.
helper
=
FormHelper
()
self
.
helper
.
attrs
[
"name"
]
=
"filter-form"
self
.
helper
.
form_method
=
'get'
self
.
helper
.
layout
=
Layout
(
Row
(
Column
(
'period'
,
css_class
=
'form-group col-md-4 mb-0'
),
Column
(
'start_date'
,
css_class
=
'form-group col-md-4 mb-0'
),
Column
(
'end_date'
,
css_class
=
'form-group col-md-4 mb-0'
),
Column
(
'period'
,
css_class
=
period_css_class
),
Column
(
'start_date'
,
css_class
=
period_css_class
),
Column
(
'end_date'
,
css_class
=
period_css_class
),
css_class
=
'form-row'
),
InlineCheckboxes
(
'categories'
),
...
...
@@ -130,10 +132,9 @@ class PeriodForm(forms.Form):
if
start_date
is
None
and
end_date
is
not
None
:
self
.
add_error
(
"start_date"
,
"masukan waktu mulai"
)
if
start_date
is
not
None
and
end_date
is
not
None
:
if
start_date
>
end_date
:
self
.
add_error
(
"end_date"
,
"waktu selesai sebelum waktu mulai"
)
if
start_date
is
not
None
and
end_date
is
not
None
and
start_date
>
end_date
:
self
.
add_error
(
"end_date"
,
"waktu selesai sebelum waktu mulai"
)
class
EditAdminStatusForm
(
forms
.
ModelForm
):
...
...
administration/templates/administration/data_statistik.html
View file @
571c5e68
...
...
@@ -97,20 +97,6 @@
<!-- Card Header - Dropdown -->
<div
class=
"card-header py-3 d-flex flex-row align-items-center justify-content-between"
>
<h6
class=
"m-0 font-weight-bold text-primary"
>
Statistik
</h6>
<!-- <div class="dropdown no-arrow">
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<em class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></em>
</a>
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in"
aria-labelledby="dropdownMenuLink">
<div class="dropdown-header">Dropdown Header:</div>
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div> -->
</div>
<!-- Card Body -->
<div
class=
"card-body"
style=
"overflow:auto!important; display:inline-block!important; height: 750px;"
>
...
...
@@ -128,7 +114,7 @@
</div>
<div
class=
"card-body"
>
<div
class=
"table-responsive"
>
<table
class=
"table table-bordered"
id=
"dataTableRiwayat"
width=
"100%"
cellspacing=
"0"
<table
class=
"table table-bordered"
id=
"dataTableRiwayat"
aria-describedby=
"titleTabelRiwayat"
>
<thead>
<tr>
...
...
administration/templates/kelola_kontributor.html
View file @
571c5e68
...
...
@@ -17,7 +17,7 @@
</div>
<div
class=
"card-body"
>
<div
class=
"table-responsive"
>
<table
aria-describedby=
"table-description"
class=
"table table-bordered"
id=
"dataTable"
width=
"100%"
cellspacing=
"0"
>
<table
aria-describedby=
"table-description"
class=
"table table-bordered"
id=
"dataTable"
>
<thead>
<tr>
<th
scope=
"col"
>
Nama
</th>
...
...
administration/templates/laporan_materi.html
View file @
571c5e68
...
...
@@ -21,7 +21,7 @@
</div>
<div
class=
"card-body"
>
<div
class=
"table-responsive"
>
<table
class=
"table table-bordered"
id=
"dataTable"
width=
"100%"
cellspacing=
"0"
>
<table
class=
"table table-bordered"
id=
"dataTable"
>
<thead>
<tr>
<th
scope=
"col"
>
Judul
</th>
...
...
administration/templates/setting_verifikasi.html
View file @
571c5e68
...
...
@@ -186,7 +186,7 @@
</div>
<div
class=
"card-body"
>
<div
class=
"table-responsive"
>
<table
aria-describedby=
"table-description"
class=
"table table-bordered"
id=
"dataTable"
width=
"100%"
cellspacing=
"0"
>
<table
aria-describedby=
"table-description"
class=
"table table-bordered"
id=
"dataTable"
>
<thead>
<tr>
<th
scope=
"col"
>
Judul Verifikasi
</th>
...
...
@@ -235,29 +235,6 @@
<em
class=
"fas fa-angle-up"
></em>
</a>
<!-- <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.5.0.min.js"
integrity="sha256-xNzN2a4ltkB44Mc/Jz3pT4iU1cmeR0FkXs4pru/JxaQ=" crossorigin="anonymous"></script>
<script src="{% static 'js/sb-admin-2.min.js' %}"></script>
<script src="{% static 'vendor/datatables/jquery.dataTables.min.js' %}"></script>
<script src="{% static 'vendor/datatables/dataTables.bootstrap4.min.js' %}"></script>
<script src="{% static 'js/demo/datatables-demo.js' %}"></script> -->
</body>
</html>
\ No newline at end of file
administration/templates/verif.html
View file @
571c5e68
...
...
@@ -61,7 +61,7 @@
</div>
<div
class=
"card-body"
>
<div
class=
"table-responsive"
>
<table
class=
"table table-bordered"
id=
"dataTableRiwayat"
width=
"100%"
cellspacing=
"0"
aria-describedby=
"titleTabelRiwayat"
>
<table
class=
"table table-bordered"
id=
"dataTableRiwayat"
aria-describedby=
"titleTabelRiwayat"
>
<thead>
<tr>
<th
scope=
"col"
>
Judul Materi
</th>
...
...
administration/tests.py
View file @
571c5e68
...
...
@@ -10,7 +10,9 @@ from app.models import Category, Materi, LaporanMateri
from
authentication.models
import
User
from
bs4
import
BeautifulSoup
from
datetime
import
datetime
from
datetime
import
datetime
,
timedelta
from
.forms
import
PeriodForm
EDIT_ENDPOINT
=
"/edit"
ERROR_403_MESSAGE
=
'Kamu harus login untuk mengakses halaman ini'
...
...
@@ -1659,3 +1661,50 @@ class EditKontributorStatusTests(TestCase):
self
.
assertEqual
(
response
.
status_code
,
403
)
class
PeriodFormTests
(
TestCase
):
def
test_validation_error_when_start_date_is_none
(
self
):
data
=
{
'start_date'
:
None
,
'end_date'
:
datetime
.
now
(),
}
form
=
PeriodForm
(
data
)
self
.
assertFalse
(
form
.
is_valid
())
self
.
assertEqual
(
form
[
"start_date"
].
errors
,
[
'masukan waktu mulai'
]
)
def
test_validation_error_when_end_date_is_none
(
self
):
data
=
{
'start_date'
:
datetime
.
now
(),
'end_date'
:
None
,
}
form
=
PeriodForm
(
data
)
self
.
assertFalse
(
form
.
is_valid
())
self
.
assertEqual
(
form
[
"end_date"
].
errors
,
[
'masukan waktu selesai'
]
)
def
test_validation_error_when_start_date_greater_than_end_date
(
self
):
current_time
=
datetime
.
now
()
data
=
{
'start_date'
:
current_time
+
timedelta
(
days
=
1
),
'end_date'
:
current_time
,
}
form
=
PeriodForm
(
data
)
self
.
assertFalse
(
form
.
is_valid
())
self
.
assertEqual
(
form
[
"end_date"
].
errors
,
[
'waktu selesai sebelum waktu mulai'
]
)
def
test_form_valid_when_data_valid
(
self
):
current_time
=
datetime
.
now
()
data
=
{
'start_date'
:
current_time
-
timedelta
(
days
=
1
),
'end_date'
:
current_time
,
}
form
=
PeriodForm
(
data
)
self
.
assertTrue
(
form
.
is_valid
())
administration/views.py
View file @
571c5e68
...
...
@@ -19,6 +19,8 @@ from django.core import management
ADMINISTRATION_MANAGEMENT
=
"/administration/kelola-admin/"
ADMINISTRATION_REPORT
=
"/administration/laporan-materi/"
ADMINISTRATION_VERIFICATION_SETTING
=
"/administration/setting/verification/"
ADMINISTRATION_CATEGORY_SETTING
=
"/administration/setting/category/"
class
VerificationView
(
TemplateView
):
...
...
@@ -115,7 +117,7 @@ class VerificationSettingView(TemplateView):
form
=
VerificationSettingForm
(
request
.
POST
)
if
form
.
is_valid
():
form
.
save
()
return
HttpResponseRedirect
(
"/administration/setting/verification/"
)
return
HttpResponseRedirect
(
ADMINISTRATION_VERIFICATION_SETTING
)
else
:
context
=
self
.
get_context_data
(
**
kwargs
)
context
[
"form"
]
=
form
...
...
@@ -146,7 +148,7 @@ class CategorySettingView(TemplateView):
form
=
CategoryForm
(
request
.
POST
)
if
form
.
is_valid
():
form
.
save
()
return
HttpResponseRedirect
(
"/administration/setting/category/"
)
return
HttpResponseRedirect
(
ADMINISTRATION_CATEGORY_SETTING
)
else
:
context
=
self
.
get_context_data
(
**
kwargs
)
context
[
"form"
]
=
form
...
...
@@ -351,7 +353,7 @@ class EditVerificationView(TemplateView):
request
.
POST
,
instance
=
verification_object
)
if
form
.
is_valid
():
form
.
save
()
return
HttpResponseRedirect
(
"/administration/setting/verification/"
)
return
HttpResponseRedirect
(
ADMINISTRATION_VERIFICATION_SETTING
)
else
:
context
=
self
.
get_context_data
(
**
kwargs
)
context
[
"form"
]
=
form
...
...
@@ -383,7 +385,7 @@ class EditCategoryView(TemplateView):
request
.
POST
,
instance
=
category_object
)
if
form
.
is_valid
():
form
.
save
()
return
HttpResponseRedirect
(
"/administration/setting/category/"
)
return
HttpResponseRedirect
(
ADMINISTRATION_CATEGORY_SETTING
)
else
:
context
=
self
.
get_context_data
(
**
kwargs
)
context
[
"form"
]
=
form
...
...
@@ -483,15 +485,15 @@ def delete_contributor(request, *args, **kwargs):
def
delete_verification
(
request
,
*
args
,
**
kwargs
):
if
not
request
.
user
.
is_authenticated
or
not
request
.
user
.
is_admin
:
raise
PermissionDenied
(
request
)
query
O
bject
=
get_object_or_404
(
VerificationSetting
,
query
_o
bject
=
get_object_or_404
(
VerificationSetting
,
pk
=
kwargs
[
"pk_verification"
])
query
O
bject
.
archived
=
True
query
O
bject
.
description
=
"Telah dihapus pada "
+
\
query
_o
bject
.
archived
=
True
query
_o
bject
.
description
=
"Telah dihapus pada "
+
\
str
(
timezone
.
now
().
strftime
(
"%m/%d/%Y, %H:%M:%S"
))
+
" WIB"
query
O
bject
.
archived_by
=
request
.
user
query
O
bject
.
save
()
query
_o
bject
.
archived_by
=
request
.
user
query
_o
bject
.
save
()
messages
.
success
(
request
,
"Point verifikasi berhasil dihapus"
)
return
HttpResponseRedirect
(
"/administration/setting/verification/"
)
return
HttpResponseRedirect
(
ADMINISTRATION_VERIFICATION_SETTING
)
def
delete_category
(
request
,
*
args
,
**
kwargs
):
...
...
@@ -499,16 +501,16 @@ def delete_category(request, *args, **kwargs):
raise
PermissionDenied
(
request
)
category_name
=
get_object_or_404
(
Category
,
pk
=
kwargs
[
"pk_category"
]).
name
query
O
bject
=
get_object_or_404
(
Category
,
query
_o
bject
=
get_object_or_404
(
Category
,
pk
=
kwargs
[
"pk_category"
])
query
O
bject
.
archived
=
True
query
O
bject
.
description
=
"Telah dihapus pada "
+
\
query
_o
bject
.
archived
=
True
query
_o
bject
.
description
=
"Telah dihapus pada "
+
\
str
(
timezone
.
now
().
strftime
(
"%m/%d/%Y, %H:%M:%S"
))
+
" WIB"
query
O
bject
.
archived_by
=
request
.
user
query
O
bject
.
save
()
query
_o
bject
.
archived_by
=
request
.
user
query
_o
bject
.
save
()
messages
.
success
(
request
,
"Kategori "
+
category_name
+
" berhasil dihapus"
)
return
HttpResponseRedirect
(
"/administration/setting/category/"
)
return
HttpResponseRedirect
(
ADMINISTRATION_CATEGORY_SETTING
)
def
generatedummy
(
request
):
if
request
.
user
.
is_authenticated
is
False
or
request
.
user
.
is_admin
is
False
:
...
...
app/forms.py
View file @
571c5e68
...
...
@@ -10,7 +10,6 @@ def year_choices():
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>
\
...
...
app/management/commands/generatedummy.py
View file @
571c5e68
...
...
@@ -24,7 +24,7 @@ class Command(BaseCommand):
counter
=
0
category_name
=
f
"Kategori dummy
{
counter
}
"
dummy_category
=
[]
for
i
in
range
(
num_of_category
):
for
_
in
range
(
num_of_category
):
while
(
Category
.
objects
.
filter
(
name
=
category_name
).
exists
()):
counter
+=
1
category_name
=
f
"Kategori dummy
{
counter
}
"
...
...
@@ -38,7 +38,7 @@ class Command(BaseCommand):
counter
=
0
criterion_name
=
f
"Kriteria dummy
{
counter
}
"
dummy_criteria
=
[]
for
i
in
range
(
num_of_criteria
):
for
_
in
range
(
num_of_criteria
):
while
(
VerificationSetting
.
objects
.
filter
(
title
=
criterion_name
).
exists
()):
counter
+=
1
criterion_name
=
f
"Kriteria dummy
{
counter
}
"
...
...
@@ -67,8 +67,7 @@ class Command(BaseCommand):
counter
=
0
dummy_user
=
[]
email
=
f
"admin-dummy-
{
counter
}
@email.com"
end_date
=
timezone
.
now
()
for
i
in
range
(
num_of_user
):
for
_
in
range
(
num_of_user
):
while
(
User
.
objects
.
filter
(
email
=
email
).
exists
()):
counter
+=
1
email
=
f
"admin-dummy-
{
counter
}
@email.com"
...
...
@@ -140,8 +139,6 @@ class Command(BaseCommand):
verif_report
=
VerificationReport
(
report
=
report_field
,
materi
=
materi
,
user
=
admin
,
status
=
materi
.
get_status_display
(),
timestamp
=
timestamp
)
verif_report
.
save
()
else
:
pass
return
materi
...
...
app/management/commands/generatetraffic.py
View file @
571c5e68
...
...
@@ -8,7 +8,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile
from
django.utils
import
timezone
from
app.models
import
Materi
,
Comment
,
Like
,
DownloadStatistics
,
ViewStatistics
,
DummyLike
,
DummyViewStatistics
,
DummyDownloadStatistics
,
DummyComment
from
app.management.commands.utils
import
SECONDS_IN_DAY
,
get_time_before
,
get_random_datetime
,
generate_list_of_random_datetime
,
generate_random_string
,
get
R
andom
C
olor
,
get
L
orem
W
ith
L
ength
from
app.management.commands.utils
import
SECONDS_IN_DAY
,
get_time_before
,
get_random_datetime
,
generate_list_of_random_datetime
,
generate_random_string
,
get
_r
andom
_c
olor
,
get
_l
orem
_w
ith
_l
ength
class
Command
(
BaseCommand
):
...
...
@@ -50,7 +50,7 @@ class Command(BaseCommand):
def
_comment_materi
(
self
,
timestamp
,
materi
):
item
=
Comment
(
materi
=
materi
,
timestamp
=
timestamp
,
profile
=
get
R
andom
C
olor
(),
comment
=
get
L
orem
W
ith
L
ength
(
240
))
profile
=
get
_r
andom
_c
olor
(),
comment
=
get
_l
orem
_w
ith
_l
ength
(
240
))
item
.
save
()
DummyComment
(
item
=
item
).
save
()
...
...
@@ -64,16 +64,7 @@ class Command(BaseCommand):
s_date
=
materi_published_date
[
0
]
s_date
=
s_date
.
replace
(
day
=
s_date
.
day
+
1
,
hour
=
0
,
minute
=
0
,
second
=
0
,
microsecond
=
0
)
# reports = []
while
(
s_date
<
today
):
# report = {
# "s_date": s_date,
# "visit": 0,
# "view": 0,
# "download": 0,
# "like": 0,
# "comment": 0,
# }
today_materi
=
[
i
for
i
in
materi
if
i
.
published_date
<
s_date
]
visiting_user
=
options
[
"baseline"
]
visiting_user
+=
int
(
options
[
"coef_time"
]
*
r_day
)
+
\
...
...
@@ -82,8 +73,6 @@ class Command(BaseCommand):
(
1
+
uniform
(
-
options
[
"coef_visit_range"
],
options
[
"coef_visit_range"
])))
active_user
=
int
(
visiting_user
*
options
[
"coef_read"
])
# report["visit"] = visiting_user
# report["view"] = active_user
times
=
generate_list_of_random_datetime
(
s_date
,
s_date
+
timedelta
(
days
=
1
),
active_user
)
for
timestamp
in
times
:
...
...
@@ -91,23 +80,9 @@ class Command(BaseCommand):
self
.
_view_materi
(
timestamp
,
selected_materi
)
if
random
()
<
options
[
"coef_download"
]:
self
.
_download_materi
(
timestamp
,
selected_materi
)
# report["download"] += 1
if
random
()
<
options
[
"coef_like"
]:
self
.
_like_materi
(
timestamp
,
selected_materi
)
# report["like"] += 1
if
random
()
<
options
[
"coef_comment"
]:
self
.
_comment_materi
(
timestamp
,
selected_materi
)
# report["comment"] += 1
s_date
=
s_date
+
timedelta
(
days
=
1
)
r_day
+=
1
# reports.append(report)
# for i in range
# for i in reports:
# self.stdout.write(self.style.SUCCESS(f"Today is {i['s_date']}"))
# self.stdout.write(self.style.SUCCESS(f"User visit {i['visit']}"))
# self.stdout.write(self.style.SUCCESS(f"User view {i['view']}"))
# self.stdout.write(self.style.SUCCESS(
# f"User download {i['download']}"))
# self.stdout.write(self.style.SUCCESS(f"User like {i['like']}"))
# self.stdout.write(self.style.SUCCESS(
# f"User comment {i['comment']}"))
app/management/commands/removetraffic.py
View file @
571c5e68
...
...
@@ -8,7 +8,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile
from
django.utils
import
timezone
,
lorem_ipsum
from
app.models
import
DummyLike
,
DummyViewStatistics
,
DummyDownloadStatistics
,
DummyComment
from
app.management.commands.utils
import
SECONDS_IN_DAY
,
get_time_before
,
get_random_datetime
,
generate_list_of_random_datetime
,
generate_random_string
,
get
R
andom
C
olor
from
app.management.commands.utils
import
SECONDS_IN_DAY
,
get_time_before
,
get_random_datetime
,
generate_list_of_random_datetime
,
generate_random_string
,
get
_r
andom
_c
olor
class
Command
(
BaseCommand
):
...
...
app/management/commands/utils.py
View file @
571c5e68
...
...
@@ -9,12 +9,12 @@ from django.utils import timezone, lorem_ipsum
SECONDS_IN_DAY
=
86400
def
get
R
andom
C
olor
():
def
get
_r
andom
_c
olor
():
color
=
"%06x"
%
randint
(
0
,
0xFFFFFF
)
return
color
def
get
L
orem
W
ith
L
ength
(
n
):
def
get
_l
orem
_w
ith
_l
ength
(
n
):
while
True
:
s
=
lorem_ipsum
.
sentence
()
if
len
(
s
)
<
n
:
...
...
@@ -43,7 +43,7 @@ def get_random_datetime(start_date, end_date, max_delta_seconds=None, min_delta_
def
generate_list_of_random_datetime
(
start
,
end
,
n
):
res
=
[]
for
i
in
range
(
n
):
for
_
in
range
(
n
):
res
.
append
(
get_random_datetime
(
start
,
end
))
res
.
sort
()
return
res
...
...
@@ -56,4 +56,4 @@ def get_last_year():
def
generate_random_string
(
n
):
return
(
''
.
join
(
choice
(
ascii_letters
)
for
i
in
range
(
n
)))
return
(
''
.
join
(
choice
(
ascii_letters
)
for
_
in
range
(
n
)))
app/migrations/0003_auto_20200509_2108.py
View file @
571c5e68
...
...
@@ -14,6 +14,6 @@ class Migration(migrations.Migration):
migrations
.
AlterField
(
model_name
=
'comment'
,
name
=
'profile'
,
field
=
models
.
CharField
(
default
=
app
.
models
.
get
R
andom
C
olor
,
max_length
=
100
),
field
=
models
.
CharField
(
default
=
app
.
models
.
get
_r
andom
_c
olor
,
max_length
=
100
),
),
]
app/migrations/0025_review.py
View file @
571c5e68
...
...
@@ -20,7 +20,7 @@ class Migration(migrations.Migration):
fields
=
[
(
'id'
,
models
.
AutoField
(
auto_created
=
True
,
primary_key
=
True
,
serialize
=
False
,
verbose_name
=
'ID'
)),
(
'username'
,
models
.
CharField
(
max_length
=
100
)),
(
'profile'
,
models
.
CharField
(
default
=
app
.
models
.
get
R
andom
C
olor
,
max_length
=
100
)),
(
'profile'
,
models
.
CharField
(
default
=
app
.
models
.
get
_r
andom
_c
olor
,
max_length
=
100
)),
(
'review'
,
models
.
TextField
(
default
=
'review'
)),
(
'timestamp'
,
models
.
DateTimeField
(
default
=
django
.
utils
.
timezone
.
now
)),
(
'materi'
,
models
.
ForeignKey
(
null
=
True
,
on_delete
=
django
.
db
.
models
.
deletion
.
SET_NULL
,
to
=
'app.materi'
)),
...
...
app/migrations/0027_readlater.py
0 → 100644
View file @
571c5e68
# Generated by Django 3.1 on 2020-10-30 13:26
from
django.conf
import
settings
from
django.db
import
migrations
,
models
import
django.db.models.deletion
import
django.utils.timezone
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
migrations
.
swappable_dependency
(
settings
.
AUTH_USER_MODEL
),
(
'app'
,
'0027_auto_20201030_1648'
),
]
operations
=
[
migrations
.
CreateModel
(
name
=
'ReadLater'
,
fields
=
[
(
'id'
,
models
.
AutoField
(
auto_created
=
True
,
primary_key
=
True
,
serialize
=
False
,
verbose_name
=
'ID'
)),
(
'timestamp'
,
models
.
DateTimeField
(
default
=
django
.
utils
.
timezone
.
now
)),
(
'materi'
,
models
.
ForeignKey
(
on_delete
=
django
.
db
.
models
.
deletion
.
CASCADE
,
to
=
'app.materi'
)),
(
'user'
,
models
.
ForeignKey
(
on_delete
=
django
.
db
.
models
.
deletion
.
CASCADE
,
to
=
settings
.
AUTH_USER_MODEL
)),
],
options
=
{
'unique_together'
:
{(
'materi'
,
'user'
)},
},
),
]
app/models.py
View file @
571c5e68
...
...
@@ -21,7 +21,7 @@ VERIFICATION_STATUS = [
# Create your models here.
def
get
R
andom
C
olor
():
def
get
_r
andom
_c
olor
():
color
=
"%06x"
%
random
.
randint
(
0
,
0xFFFFFF
)
return
color
...
...
@@ -140,11 +140,12 @@ class Materi(SoftDeleteModel):
like
=
False
if
Like
.
objects
.
filter
(
materi
=
self
).
exists
():
like
=
True
return
like
class
Comment
(
models
.
Model
):
username
=
models
.
CharField
(
max_length
=
100
)
profile
=
models
.
CharField
(
max_length
=
100
,
default
=
get
R
andom
C
olor
)
profile
=
models
.
CharField
(
max_length
=
100
,
default
=
get
_r
andom
_c
olor
)
comment
=
models
.
CharField
(
max_length
=
240
,
default
=
"comments"
)
materi
=
models
.
ForeignKey
(
Materi
,
models
.
SET_NULL
,
null
=
True
)
user
=
models
.
ForeignKey
(
User
,
on_delete
=
models
.
SET_NULL
,
blank
=
True
,
null
=
True
)
...
...
@@ -165,7 +166,7 @@ class Comment(models.Model):
class
Review
(
models
.
Model
):
username
=
models
.
CharField
(
max_length
=
100
)
profile
=
models
.
CharField
(
max_length
=
100
,
default
=
get
R
andom
C
olor
)
profile
=
models
.
CharField
(
max_length
=
100
,
default
=
get
_r
andom
_c
olor
)
review
=
models
.
TextField
(
default
=
"review"
)
materi
=
models
.
ForeignKey
(
Materi
,
models
.
SET_NULL
,
null
=
True
)
user
=
models
.
ForeignKey
(
User
,
on_delete
=
models
.
SET_NULL
,
blank
=
True
,
null
=
True
)
...
...
@@ -272,3 +273,11 @@ class LaporanMateri(models.Model):
laporan
=
models
.
TextField
(
validators
=
[
MinValueValidator
(
30
),
MaxValueValidator
(
120
)],
default
=
""
)
timestamp
=
models
.
DateTimeField
(
default
=
timezone
.
now
)
is_rejected
=
models
.
BooleanField
(
default
=
False
)
class
ReadLater
(
models
.
Model
):
materi
=
models
.
ForeignKey
(
Materi
,
on_delete
=
models
.
CASCADE
)
user
=
models
.
ForeignKey
(
User
,
on_delete
=
models
.
CASCADE
)
timestamp
=
models
.
DateTimeField
(
default
=
timezone
.
now
)
class
Meta
:
unique_together
=
[
"materi"
,
"user"
]
\ No newline at end of file
app/services.py
View file @
571c5e68
...
...
@@ -15,7 +15,7 @@ from pydrive.drive import GoogleDrive
from
administration.models
import
VerificationReport
from
app.forms
import
SuntingProfilForm
from
app.models
import
Category
,
Like
,
LikeComment
,
DislikeComment
,
Materi
,
Comment
,
Rating
,
DownloadStatistics
,
\
ViewStatistics
ViewStatistics
,
ReadLater
from
app.utils.fileManagementUtil
import
get_random_filename
,
remove_image_exifdata
from
digipus
import
settings
import
requests
...
...
@@ -343,7 +343,6 @@ class UploadMateriService:
@
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"
)
...
...
@@ -470,3 +469,18 @@ class GoogleDriveUploadService:
file1
[
"title"
]
=
title
print
(
"title: %s, mimeType: %s"
%
(
file1
[
"title"
],
file1
[
"mimeType"
]))
file1
.
Upload
()
class
ReadLaterService
:
@
staticmethod
def
toggle_read_later
(
materi_id
,
current_user
):
materi
=
get_object_or_404
(
Materi
,
pk
=
materi_id
)
read_later_item_exist
=
ReadLater
.
objects
.
filter
(
materi
=
materi
,
user
=
current_user
).
exists
()
if
read_later_item_exist
: