Fakultas Ilmu Komputer UI

Commit 50c83618 authored by I Gusti Putu Agastya Indrayana's avatar I Gusti Putu Agastya Indrayana
Browse files

Merge branch 'PBI-9-Statistik_Akses_Materi' into 'staging'

Pbi 9 statistik akses materi

See merge request ppl-fasilkom-ui/2020/ppl-c/diskominfo-depok-digipus/marjinal-digipus!51
parents 3d1f443e f0754b70
......@@ -204,4 +204,5 @@ pip-selfcheck.json
__pycache__/
db.sqlite3
.coverage
htmlcov/
\ No newline at end of file
htmlcov/
flowchart/
\ No newline at end of file
# Generated by Django 3.0.3 on 2020-05-17 10:13
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('administration', '0003_verificationreport_user'),
]
operations = [
migrations.AlterField(
model_name='verificationreport',
name='timestamp',
field=models.DateTimeField(default=django.utils.timezone.now),
),
]
from django.contrib.postgres.fields import JSONField
from django.db import models
from django.utils import timezone
from app.models import VERIFICATION_STATUS, Materi
from authentication.models import User
......@@ -15,6 +16,6 @@ class VerificationReport(models.Model):
report = JSONField()
materi = models.ForeignKey(Materi, models.SET_NULL, null=True)
user = models.ForeignKey(User, models.SET_NULL, null=True)
timestamp = models.DateTimeField(auto_now_add=True)
timestamp = models.DateTimeField(default=timezone.now)
status = models.CharField(
max_length=30, choices=VERIFICATION_STATUS, default=VERIFICATION_STATUS[0][0])
......@@ -75,11 +75,9 @@ class DetailVerificationView(TemplateView):
if action == "approve" and feedback != "":
materi.status = "APPROVE"
materi.feedback = feedback
materi.save()
elif action == "disapprove" and feedback != "":
materi.status = "DISAPPROVE"
materi.feedback = feedback
materi.save()
else:
context = self.get_context_data(**kwargs)
......
from datetime import datetime, timedelta
from math import floor, ceil
from random import randint, choice, choices, sample
from typing import List
from django.core.management.base import BaseCommand
from django.core.files.uploadedfile import SimpleUploadedFile
from django.utils import timezone
from app.models import Materi, Category
from app.management.commands.utils import SECONDS_IN_DAY, get_time_before, get_random_datetime, generate_list_of_random_datetime
from administration.models import VerificationReport, VerificationSetting
from authentication.models import User
class Command(BaseCommand):
help = 'Generate dummy data for seeding.'
def add_arguments(self, parser):
parser.add_argument('num_of_materi', type=int,
help="Number of materi to create")
def _generate_category(self, num_of_category: int = 5):
counter = 0
category_name = f"Kategori dummy {counter}"
dummy_category = []
for i in range(num_of_category):
while (Category.objects.filter(name=category_name).exists()):
counter += 1
category_name = f"Kategori dummy {counter}"
category = Category(name=category_name,
description=f"{category_name}.")
category.save()
dummy_category.append(category)
return dummy_category
def _generate_verifivation_criteria(self, num_of_criteria: int = 5):
counter = 0
criterion_name = f"Kriteria dummy {counter}"
dummy_criteria = []
for i in range(num_of_criteria):
while (VerificationSetting.objects.filter(title=criterion_name).exists()):
counter += 1
criterion_name = f"Kriteria dummy {counter}"
criterion = VerificationSetting(title=criterion_name,
description=f"{criterion_name}.")
criterion.save()
dummy_criteria.append(criterion)
return dummy_criteria
def _generate_cover(self):
cover = SimpleUploadedFile(
"cover.jpg",
b"Test file"
)
return cover
def _generate_content(self):
content = SimpleUploadedFile(
"content.txt",
b"Test file"
)
return content
def _generate_admin(self, num_of_user: int = 2):
counter = 0
dummy_user = []
email = f"admin-dummy-{counter}@email.com"
end_date = timezone.now()
for i in range(num_of_user):
while (User.objects.filter(email=email).exists()):
counter += 1
email = f"admin-dummy-{counter}@email.com"
name = f"admin-dummy-{counter}"
user = User(email=email, name=name, is_admin=True)
user.set_password(name)
user.date_joined = get_time_before(
timezone.now(), (365*SECONDS_IN_DAY))
user.save()
dummy_user.append(user)
return dummy_user
def _generate_contributor(self, max_num_of_user: int = 10):
counter = 0
dummy_user = []
email = f"kontributor-dummy-{counter}@email.com"
now = timezone.now() - timedelta(days=30)
last_year = timezone.now() - timedelta(days=365)
dates = generate_list_of_random_datetime(
last_year, now, max_num_of_user)
self.first_created_contributor = dates[0]
for date_joined in dates:
while (User.objects.filter(email=email).exists()):
counter += 1
email = f"kontributor-dummy-{counter}@email.com"
name = f"kontributor-dummy-{counter}"
user = User(email=email, name=name, is_contributor=True)
user.set_password(name)
user.date_joined = date_joined
user.save()
dummy_user.append(user)
return dummy_user
def _generate_materi(self, num_of_materi: int):
counter = 0
materi_name = "Materi Dummy {}"
materi_list = []
now = timezone.now() - timedelta(days=30)
dates = generate_list_of_random_datetime(
self.first_created_contributor, now, num_of_materi)
for date_created in dates:
contributor = choice(
[i for i in self.contributors if i.date_joined < date_created])
while Materi.objects.filter(title=materi_name.format(counter)).exists():
counter += 1
materi = Materi(title=materi_name.format(counter), author=contributor.name, uploader=contributor,
publisher=f"Penerbit {contributor.name}", descriptions=f"Deskripsi {materi_name.format(counter)}.",
status="PENDING", cover=self.cover, content=self.content, date_created=date_created)
materi.save()
category = sample(self.categories, k=2)
materi.categories.add(*category)
materi.save()
materi_list.append(materi)
# Validasi
status = self._get_status()
if status != "PENDING":
timestamp = get_random_datetime(
date_created, date_created+timedelta(days=7))
admin = choice(self.admins)
report_field = {}
if status == "APPROVE":
report_field = self._generate_report(approved=True)
materi.status = "APPROVE"
elif status == "DISAPPROVE":
report_field = self._generate_report(approved=False)
materi.status = "DISAPPROVE"
materi.save()
verif_report = VerificationReport(
report=report_field, materi=materi, user=admin, status=materi.get_status_display(), timestamp=timestamp)
verif_report.save()
else:
pass
return materi
def _verify_count(self, num_of_materi: int, reject_rate: float = 0.15, pending_rate: float = 0.2):
num_of_reject = floor(reject_rate * num_of_materi)
num_of_pending = floor(pending_rate * num_of_materi)
num_of_approve = num_of_materi - (num_of_reject + num_of_pending)
return (num_of_reject, num_of_pending, num_of_approve)
def _get_status(self):
choices = []
if self.num_of_approve > 0:
choices.append("APPROVE")
if self.num_of_reject > 0:
choices.append("DISAPPROVE")
if self.num_of_pending > 0:
choices.append("PENDING")
status = choice(choices)
if status == "APPROVE":
self.num_of_approve -= 1
elif status == "DISAPPROVE":
self.num_of_reject -= 1
else:
self.num_of_pending -= 1
return status
def _generate_report(self, approved):
report = {}
kriteria_list = []
for kriteria in self.criteria:
kriteria_list.append({
"title": kriteria.title,
"status": True
})
if not approved:
n_failed_kriteria = randint(1, len(kriteria_list))
for i in range(n_failed_kriteria):
kriteria_list[i]["status"] = False
feedback = "Materi Dummy tidak diterima karena tidak memenuhi kriteria"
else:
feedback = "Materi Dummy diterima"
report["kriteria"] = kriteria_list
report["feedback"] = feedback
return report
def handle(self, *args, **options):
num_of_materi = options['num_of_materi']
num_of_contributor = min(floor(num_of_materi*0.2), 10)
num_of_admin = ceil(num_of_materi*0.2*0.1)
self.last_contributor_created = get_time_before(
timezone.now(), (365*SECONDS_IN_DAY))
self.cover = self._generate_cover()
self.content = self._generate_content()
self.categories = self._generate_category()
self.criteria = self._generate_verifivation_criteria()
self.num_of_reject, self.num_of_pending, self.num_of_approve = self._verify_count(
num_of_materi)
self.admins = self._generate_admin(num_of_admin)
self.contributors = self._generate_contributor(num_of_contributor)
self._generate_materi(num_of_materi)
self.stdout.write(self.style.SUCCESS(
'Successfully created %s materi' % options['num_of_materi']))
from datetime import datetime, timedelta
from math import floor, ceil
from random import randint, choice, choices, sample, uniform, random
from typing import List
from django.core.management.base import BaseCommand
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, getRandomColor, getLoremWithLength
class Command(BaseCommand):
help = 'Generate dummy data for seeding.'
def add_arguments(self, parser):
parser.add_argument('baseline', type=int, default=100,
help="Baseline number of visit perday")
parser.add_argument('--coef-materi', type=float, default=0.10,
help="Coef number for visit because of materi i.e. more materi = more visit")
parser.add_argument('--coef-time', type=float, default=0.05,
help="Coef number for visit because of time i.e. more time = more visit")
parser.add_argument('--coef-visit-range', type=float, default=0.25,
help="Coef number for visit because of time i.e. more time = more visit")
parser.add_argument('--coef-read', type=float, default=0.20,
help="chance of visiting user to view a materi")
parser.add_argument('--coef-download', type=float, default=0.5,
help="chance of viewing user to download a materi")
parser.add_argument('--coef-like', type=float, default=0.4,
help="chance of viewing user to like a materi")
parser.add_argument('--coef-comment', type=float, default=0.2,
help="chance of viewing user to comment on a materi")
def _view_materi(self, timestamp, materi):
item = ViewStatistics(materi=materi, timestamp=timestamp)
item.save()
DummyViewStatistics(item=item).save()
def _download_materi(self, timestamp, materi):
item = DownloadStatistics(materi=materi, timestamp=timestamp)
item.save()
DummyDownloadStatistics(item=item).save()
def _like_materi(self, timestamp, materi):
item = Like(materi=materi, timestamp=timestamp,
session_id=f"DuMmY{generate_random_string(27)}")
item.save()
DummyLike(item=item).save()
def _comment_materi(self, timestamp, materi):
item = Comment(materi=materi, timestamp=timestamp,
profile=getRandomColor(), comment=getLoremWithLength(240))
item.save()
DummyComment(item=item).save()
def handle(self, *args, **options):
materi = Materi.objects.filter(title__icontains="dummy")
materi = [i for i in materi if i.published_date is not None]
today = timezone.now()
materi_published_date = [i.published_date for i in materi]
materi_published_date.sort()
r_day = 1
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) + \
int(options["coef_materi"] * len(today_materi))
visiting_user = int(visiting_user *
(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:
selected_materi = choice(today_materi)
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']}"))
from datetime import datetime
from math import floor
from random import randint, choice, choices
from typing import List
from django.core.management.base import BaseCommand
from django.core.files.uploadedfile import SimpleUploadedFile
from app.models import Materi, Category, Comment, Like, DownloadStatistics, ViewStatistics
from administration.models import VerificationReport, VerificationSetting
from authentication.models import User
class Command(BaseCommand):
help = 'Remmove dummy data for seeding.'
def _remove_user(self):
for item in User.objects.filter(email__icontains="dummy"):
item.delete()
def _remove_category(self):
for item in Category.objects.filter(name__icontains="dummy"):
item.delete()
def _remove_materi(self):
for item in Materi.objects.filter(title__icontains="dummy"):
item.verificationreport_set.all().delete()
item.delete()
def _remove_verifivation_criteria(self):
for item in VerificationSetting.objects.filter(title__icontains="dummy"):
item.delete()
def _remove_verivication_report(self):
for item in VerificationReport.objects.filter(report__feedback__icontains="dummy"):
item.delete()
def handle(self, *args, **options):
self._remove_user()
self._remove_category()
self._remove_materi()
self._remove_verifivation_criteria()
self.stdout.write(self.style.SUCCESS(
'Successfully remove all dummy object'))
from datetime import datetime, timedelta
from math import floor, ceil
from random import randint, choice, choices, sample, uniform, random
from typing import List
from django.core.management.base import BaseCommand
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, getRandomColor
class Command(BaseCommand):
help = 'Remmove dummy data for seeding.'
def _remove_view(self):
for item in DummyViewStatistics.objects.all():
item.item.delete()
item.delete()
def _remove_download(self):
for item in DummyDownloadStatistics.objects.all():
item.item.delete()
item.delete()
def _remove_like(self):
for item in DummyLike.objects.all():
item.item.delete()
item.delete()
def _remove_comment(self):
for item in DummyComment.objects.all():
item.item.delete()
item.delete()
def handle(self, *args, **options):
self._remove_view()
self._remove_download()
self._remove_like()
self._remove_comment()
self.stdout.write(self.style.SUCCESS(
'Successfully remove all dummy traffic'))
from datetime import datetime, timedelta
from math import floor, ceil
from random import randint, choice, choices, sample, random
from string import ascii_letters
from django.utils import timezone, lorem_ipsum
SECONDS_IN_DAY = 86400
def getRandomColor():
color = "%06x" % randint(0, 0xFFFFFF)
return color
def getLoremWithLength(n):
while True:
s = lorem_ipsum.sentence()
if len(s) < n:
return s
def get_time_before(datetime, delta):
return datetime - timedelta(seconds=delta)
def get_time_after(datetime, delta):
return datetime + timedelta(seconds=delta)
def get_delta_in_seconds(s, e):
return int((e-s).total_seconds())
def get_random_datetime(start_date, end_date, max_delta_seconds=None, min_delta_seconds=None):
delta = get_delta_in_seconds(start_date, end_date)
lower = 0 if min_delta_seconds is None else min_delta_seconds
upper = delta if max_delta_seconds is None else max_delta_seconds
delta = randint(lower, upper)
return start_date + timedelta(seconds=delta)
def generate_list_of_random_datetime(start, end, n):
res = []
for i in range(n):
res.append(get_random_datetime(start, end))
res.sort()
return res
def get_last_year():
datetime = timezone.now() - timedelta(days=365)
datetime = datetime.replace(hour=0, minute=0, second=0, microsecond=0)
return datetime
def generate_random_string(n):
return(''.join(choice(ascii_letters) for i in range(n)))
# Generated by Django 3.0.3 on 2020-05-12 08:34
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('app', '0003_auto_20200509_2108'),
]
operations = [
migrations.CreateModel(
name='Like',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('timestamp', models.DateTimeField(auto_now_add=True)),
('materi', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='app.Materi')),
],
),
]
# Generated by Django 3.0.3 on 2020-05-12 09:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0004_like'),
]
operations = [
migrations.AddField(
model_name='like',
name='session_id',
field=models.CharField(default='', max_length=32),
preserve_default=False,
),
]
# Generated by Django 3.0.3 on 2020-05-13 10:34
from django.db import migrations, models
import django.db.models.deletion