Fakultas Ilmu Komputer UI

Commit 8e7e67a9 authored by Selvy Fitriani's avatar Selvy Fitriani
Browse files

Merge branch '1706039446/110' into 'master'

[#110] Guest Book For Non Registered User

See merge request !112
parents defcd506 60a1898e
Pipeline #60185 passed with stages
in 26 minutes and 38 seconds
from django import forms from django import forms
from app.models import Materi, Category, RatingContributor from app.models import Materi, Category, RatingContributor, GuestBook
from authentication.models import User from authentication.models import User
import datetime import datetime
def year_choices(): def year_choices():
return[(r,r) for r in range(2000, datetime.date.today().year+1)] return[(r, r) for r in range(2000, datetime.date.today().year+1)]
class UploadMateriForm(forms.ModelForm): 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(
release_year = forms.TypedChoiceField(coerce=int, choices=year_choices, initial=datetime.date.today().year) ), widget=forms.CheckboxSelectMultiple(attrs={'style': 'column-count:2'}), required=True)
yt_video_id = forms.CharField(label="Youtube Video Id", \ release_year = forms.TypedChoiceField(
help_text="This is not required.<br>\ 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>\ 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) Example : https://www.youtube.com/watch?v=DkJ-50GLi2I <br> has video id DkJ-50GLi2I", required=False)
...@@ -29,14 +33,13 @@ class UploadMateriForm(forms.ModelForm): ...@@ -29,14 +33,13 @@ class UploadMateriForm(forms.ModelForm):
field.widget.attrs["class"] = "form-control" field.widget.attrs["class"] = "form-control"
field.widget.attrs["placeholder"] = field.initial field.widget.attrs["placeholder"] = field.initial
field.initial = "" field.initial = ""
self.fields['categories'].widget.attrs.update({'class' : "native"}) self.fields['categories'].widget.attrs.update({'class': "native"})
class SuntingProfilForm(forms.ModelForm): class SuntingProfilForm(forms.ModelForm):
class Meta: class Meta:
model = User model = User
fields = ["email","name","instansi", "nik", "alamat", "nomor_telpon", fields = ["email", "name", "instansi", "nik", "alamat", "nomor_telpon",
"profile_picture", "linkedin", "profile_picture", "linkedin",
"facebook", "twitter", "instagram", "biography", "facebook", "twitter", "instagram", "biography",
"is_subscribing_to_material_comments"] "is_subscribing_to_material_comments"]
...@@ -50,7 +53,6 @@ class SuntingProfilForm(forms.ModelForm): ...@@ -50,7 +53,6 @@ class SuntingProfilForm(forms.ModelForm):
if any(self.errors): if any(self.errors):
key = list(self.errors)[0] key = list(self.errors)[0]
self.fields[key].widget.attrs["autofocus"] = "" self.fields[key].widget.attrs["autofocus"] = ""
self.fields["email"].widget.attrs["readonly"] = True self.fields["email"].widget.attrs["readonly"] = True
...@@ -61,14 +63,43 @@ class RatingContributorForm(forms.ModelForm): ...@@ -61,14 +63,43 @@ class RatingContributorForm(forms.ModelForm):
fields = ['score', 'user', 'contributor'] fields = ['score', 'user', 'contributor']
SCORE_CHOICE = ( SCORE_CHOICE = (
('', 'Select score'), ('', 'Select score'),
('1', '1'), # First one is the value of select option and second is the displayed value in option # First one is the value of select option and second is the displayed value in option
('1', '1'),
('2', '2'), ('2', '2'),
('3', '3'), ('3', '3'),
('4', '4'), ('4', '4'),
('5', '5'), ('5', '5'),
) )
widgets = { widgets = {
'score': forms.Select(choices=SCORE_CHOICE, attrs={'class': 'form-control', 'id':'form-rating'},), 'score': forms.Select(choices=SCORE_CHOICE, attrs={'class': 'form-control', 'id': 'form-rating'},),
'user': forms.HiddenInput(), 'user': forms.HiddenInput(),
'contributor': forms.HiddenInput() 'contributor': forms.HiddenInput()
} }
class GuestBookForm(forms.models.ModelForm):
class Meta:
model = GuestBook
fields = ['name', 'job', 'gender']
gender_choices = (
('Male', 'Male'),
('Female', 'Female')
)
widgets = {
'name': forms.fields.TextInput(attrs={
'placeholder': 'Input your name',
'class': 'form-control input-lg'
}),
'job': forms.fields.TextInput(attrs={
'placeholder': 'Input your job',
'class': 'form-control input-lg'
}),
'gender': forms.fields.Select(choices=gender_choices, attrs={
'class': 'form-control input-lg'
})
}
error_messages = {
'name': {'required': 'Name is required'},
'job': {'required': 'Job is required'},
'gender': {'required': 'Gender is required'}
}
# Generated by Django 3.1 on 2020-10-31 18:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0028_adminnotification'),
]
operations = [
migrations.CreateModel(
name='GuestBook',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.TextField(default='')),
('job', models.TextField(default='')),
('gender', models.CharField(default='Male', max_length=6)),
],
),
]
# Generated by Django 3.1 on 2020-10-31 19:17 # Generated by Django 3.1 on 2020-10-31 23:21
from django.db import migrations from django.db import migrations
...@@ -6,8 +6,8 @@ from django.db import migrations ...@@ -6,8 +6,8 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('app', '0029_guestbook'),
('app', '0028_notifikasikontributor'), ('app', '0028_notifikasikontributor'),
('app', '0028_adminnotification'),
] ]
operations = [ operations = [
......
...@@ -26,9 +26,11 @@ def get_random_color(): ...@@ -26,9 +26,11 @@ def get_random_color():
color = "%06x" % random.randint(0, 0xFFFFFF) color = "%06x" % random.randint(0, 0xFFFFFF)
return color return color
def current_year(): def current_year():
return datetime.date.today().year return datetime.date.today().year
class Category(models.Model): class Category(models.Model):
name = models.CharField(max_length=20) name = models.CharField(max_length=20)
description = models.TextField(blank=False, default="") description = models.TextField(blank=False, default="")
...@@ -48,7 +50,7 @@ class MateriManager(models.Manager): ...@@ -48,7 +50,7 @@ class MateriManager(models.Manager):
if self.alive_only: if self.alive_only:
return SoftDeletionQuerySet(self.model).filter(deleted_at=None) return SoftDeletionQuerySet(self.model).filter(deleted_at=None)
return SoftDeletionQuerySet(self.model) return SoftDeletionQuerySet(self.model)
def search(self, search_text): def search(self, search_text):
search_vector = None search_vector = None
for field, weight in Materi.SEARCH_INDEX: for field, weight in Materi.SEARCH_INDEX:
...@@ -75,18 +77,20 @@ class SoftDeletionQuerySet(models.query.QuerySet): ...@@ -75,18 +77,20 @@ class SoftDeletionQuerySet(models.query.QuerySet):
def delete(self): def delete(self):
return super(SoftDeletionQuerySet, self).update(deleted_at=timezone.now()) return super(SoftDeletionQuerySet, self).update(deleted_at=timezone.now())
class SoftDeleteModel(models.Model): class SoftDeleteModel(models.Model):
deleted_at = models.DateTimeField(blank=True, null=True) deleted_at = models.DateTimeField(blank=True, null=True)
all_objects = MateriManager(alive_only=False) all_objects = MateriManager(alive_only=False)
class Meta: class Meta:
abstract = True abstract = True
def soft_delete(self): def soft_delete(self):
self.deleted_at = timezone.now() self.deleted_at = timezone.now()
self.save() self.save()
class Materi(SoftDeleteModel): class Materi(SoftDeleteModel):
cover = models.ImageField() cover = models.ImageField()
content = models.FileField() content = models.FileField()
...@@ -96,8 +100,9 @@ class Materi(SoftDeleteModel): ...@@ -96,8 +100,9 @@ class Materi(SoftDeleteModel):
publisher = models.CharField(max_length=30, default="Penerbit") publisher = models.CharField(max_length=30, default="Penerbit")
release_year = models.IntegerField(default=current_year) release_year = models.IntegerField(default=current_year)
pages = models.IntegerField(default=0) pages = models.IntegerField(default=0)
descriptions = models.TextField(default="Deskripsi") descriptions = models.TextField(default="Deskripsi")
status = models.CharField(max_length=30, choices=VERIFICATION_STATUS, default=VERIFICATION_STATUS[0][0]) status = models.CharField(
max_length=30, choices=VERIFICATION_STATUS, default=VERIFICATION_STATUS[0][0])
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)
...@@ -117,7 +122,8 @@ class Materi(SoftDeleteModel): ...@@ -117,7 +122,8 @@ class Materi(SoftDeleteModel):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
super().save(*args, **kwargs) super().save(*args, **kwargs)
search_index = {field: weight for (field, weight) in Materi.SEARCH_INDEX} search_index = {field: weight for (
field, weight) in Materi.SEARCH_INDEX}
if "update_fields" in kwargs: if "update_fields" in kwargs:
is_search_index_updated = bool( is_search_index_updated = bool(
set(search_index.keys()) & set(kwargs["update_fields"]) set(search_index.keys()) & set(kwargs["update_fields"])
...@@ -127,9 +133,11 @@ class Materi(SoftDeleteModel): ...@@ -127,9 +133,11 @@ class Materi(SoftDeleteModel):
self._search_vector = None self._search_vector = None
for field, weight in search_index.items(): for field, weight in search_index.items():
if self._search_vector is None: if self._search_vector is None:
self._search_vector = search.SearchVector(field, weight=weight) self._search_vector = search.SearchVector(
field, weight=weight)
else: else:
self._search_vector += search.SearchVector(field, weight=weight) self._search_vector += search.SearchVector(
field, weight=weight)
self.save(update_fields=["_search_vector"]) self.save(update_fields=["_search_vector"])
...@@ -154,7 +162,7 @@ class Materi(SoftDeleteModel): ...@@ -154,7 +162,7 @@ class Materi(SoftDeleteModel):
def like_count(self): def like_count(self):
count = Like.objects.filter(materi=self).count() count = Like.objects.filter(materi=self).count()
return count return count
@property @property
def comment_count(self): def comment_count(self):
count = Comment.objects.filter(materi=self).count() count = Comment.objects.filter(materi=self).count()
...@@ -181,7 +189,7 @@ class Materi(SoftDeleteModel): ...@@ -181,7 +189,7 @@ class Materi(SoftDeleteModel):
@property @property
def hot_score(self): def hot_score(self):
view_score = math.log(max(self.view_count, 1), 10) view_score = math.log(max(self.view_count, 1), 10)
time_score = self.seconds_since_earliest_materi / 604800 # 1 week time_score = self.seconds_since_earliest_materi / 604800 # 1 week
return round(view_score + time_score, 7) return round(view_score + time_score, 7)
@property @property
...@@ -197,7 +205,8 @@ class Comment(models.Model): ...@@ -197,7 +205,8 @@ class Comment(models.Model):
profile = models.CharField(max_length=100, default=get_random_color) profile = models.CharField(max_length=100, default=get_random_color)
comment = models.CharField(max_length=240, default="comments") comment = models.CharField(max_length=240, default="comments")
materi = models.ForeignKey(Materi, models.SET_NULL, null=True) materi = models.ForeignKey(Materi, models.SET_NULL, null=True)
user = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True) user = models.ForeignKey(
User, on_delete=models.SET_NULL, blank=True, null=True)
timestamp = models.DateTimeField(default=timezone.now) timestamp = models.DateTimeField(default=timezone.now)
def __str__(self): def __str__(self):
...@@ -207,18 +216,20 @@ class Comment(models.Model): ...@@ -207,18 +216,20 @@ class Comment(models.Model):
def like_count(self): def like_count(self):
count = LikeComment.objects.filter(comment=self).count() count = LikeComment.objects.filter(comment=self).count()
return count return count
@property @property
def dislike_count(self): def dislike_count(self):
count = DislikeComment.objects.filter(comment=self).count() count = DislikeComment.objects.filter(comment=self).count()
return count return count
class Review(models.Model): class Review(models.Model):
username = models.CharField(max_length=100) username = models.CharField(max_length=100)
profile = models.CharField(max_length=100, default=get_random_color) profile = models.CharField(max_length=100, default=get_random_color)
review = models.TextField(default="review") review = models.TextField(default="review")
materi = models.ForeignKey(Materi, models.SET_NULL, null=True) materi = models.ForeignKey(Materi, models.SET_NULL, null=True)
user = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True) user = models.ForeignKey(
User, on_delete=models.SET_NULL, blank=True, null=True)
timestamp = models.DateTimeField(default=timezone.now) timestamp = models.DateTimeField(default=timezone.now)
def __str__(self): def __str__(self):
...@@ -247,6 +258,7 @@ class ReqMaterial(models.Model): ...@@ -247,6 +258,7 @@ class ReqMaterial(models.Model):
title = models.CharField(max_length=100) title = models.CharField(max_length=100)
timestamp = models.DateTimeField(default=timezone.now) timestamp = models.DateTimeField(default=timezone.now)
class SubmitVisitor(models.Model): class SubmitVisitor(models.Model):
user_id = models.CharField(max_length=50) user_id = models.CharField(max_length=50)
email = models.CharField(max_length=50) email = models.CharField(max_length=50)
...@@ -255,13 +267,16 @@ class SubmitVisitor(models.Model): ...@@ -255,13 +267,16 @@ class SubmitVisitor(models.Model):
class ViewStatistics(models.Model): class ViewStatistics(models.Model):
materi = models.ForeignKey(Materi, models.SET_NULL, null=True, related_name="baca") materi = models.ForeignKey(
Materi, models.SET_NULL, null=True, related_name="baca")
timestamp = models.DateTimeField(default=timezone.now) timestamp = models.DateTimeField(default=timezone.now)
class DownloadStatistics(models.Model): class DownloadStatistics(models.Model):
materi = models.ForeignKey(Materi, models.SET_NULL, null=True, related_name="unduh") materi = models.ForeignKey(
downloader = models.ForeignKey(User, models.SET_NULL, blank=True, null=True, related_name="riwayat_unduh") Materi, models.SET_NULL, null=True, related_name="unduh")
downloader = models.ForeignKey(
User, models.SET_NULL, blank=True, null=True, related_name="riwayat_unduh")
timestamp = models.DateTimeField(default=timezone.now) timestamp = models.DateTimeField(default=timezone.now)
...@@ -302,27 +317,39 @@ class Rating(models.Model): ...@@ -302,27 +317,39 @@ class Rating(models.Model):
class RatingContributor(models.Model): class RatingContributor(models.Model):
timestamp = models.DateTimeField(auto_now=True) timestamp = models.DateTimeField(auto_now=True)
score = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)]) score = models.PositiveIntegerField(
contributor = models.ForeignKey(User, on_delete=models.CASCADE, related_name='contributor') validators=[MinValueValidator(1), MaxValueValidator(5)])
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user') contributor = models.ForeignKey(
User, on_delete=models.CASCADE, related_name='contributor')
user = models.ForeignKey(
User, on_delete=models.CASCADE, related_name='user')
def save(self, force_insert=False, force_update=False, using=None, update_fields=None): def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
if 1 <= self.score <= 5: if 1 <= self.score <= 5:
super().save(force_insert, force_update, using, update_fields) super().save(force_insert, force_update, using, update_fields)
else: else:
raise ValidationError("Rating score must be integer between 1-5") raise ValidationError("Rating score must be integer between 1-5")
class Meta: class Meta:
unique_together = ["contributor", "user"] unique_together = ["contributor", "user"]
class LaporanMateri(models.Model): class LaporanMateri(models.Model):
materi = models.ForeignKey(Materi, on_delete=models.CASCADE, max_length=120) materi = models.ForeignKey(
Materi, on_delete=models.CASCADE, max_length=120)
user = models.ForeignKey(User, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE)
laporan = models.TextField(validators=[MinValueValidator(30), MaxValueValidator(120)], default="") laporan = models.TextField(
validators=[MinValueValidator(30), MaxValueValidator(120)], default="")
timestamp = models.DateTimeField(default=timezone.now) timestamp = models.DateTimeField(default=timezone.now)
is_rejected = models.BooleanField(default=False) is_rejected = models.BooleanField(default=False)
class GuestBook(models.Model):
name = models.TextField(default='')
job = models.TextField(default='')
gender = models.CharField(max_length=6, default="Male")
class ReadLater(models.Model): class ReadLater(models.Model):
materi = models.ForeignKey(Materi, on_delete=models.CASCADE) materi = models.ForeignKey(Materi, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE)
...@@ -331,13 +358,16 @@ class ReadLater(models.Model): ...@@ -331,13 +358,16 @@ class ReadLater(models.Model):
class Meta: class Meta:
unique_together = ["materi", "user"] unique_together = ["materi", "user"]
class NotifikasiKontributor(models.Model): class NotifikasiKontributor(models.Model):
materi = models.ForeignKey(Materi, on_delete=models.CASCADE, max_length=120) materi = models.ForeignKey(
Materi, on_delete=models.CASCADE, max_length=120)
user = models.ForeignKey(User, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE)
feedback = models.CharField(max_length=20, default="") feedback = models.CharField(max_length=20, default="")
def __str__(self): def __str__(self):
return "Status: {}".format(self.feedback) return "Status: {}".format(self.feedback)
class AdminNotification(models.Model): class AdminNotification(models.Model):
materi = models.ForeignKey(Materi, on_delete=models.CASCADE) materi = models.ForeignKey(Materi, on_delete=models.CASCADE)
.form-style-6{
font: 95% Arial, Helvetica, sans-serif;
max-width: 500px;
margin: 25px auto;
padding: 16px;
background: #F7F7F7;
align-content: center;
justify-content: center;
}
.form-style-6 h1{
background: #43D1AF;
padding: 20px 0;
font-size: 140%;
font-weight: 300;
text-align: center;
color: #fff;
margin: -16px -16px 16px -16px;
}
.form-style-6 input[type="text"],
.form-style-6 select
{
-webkit-transition: all 0.30s ease-in-out;
-moz-transition: all 0.30s ease-in-out;
-ms-transition: all 0.30s ease-in-out;
-o-transition: all 0.30s ease-in-out;
outline: none;
box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
width: 100%;
background: #fff;
margin-bottom: 4%;
border: 1px solid #ccc;
color: #555;
font: 95% Arial, Helvetica, sans-serif;
}
.form-style-6 input[type="text"]:focus,
.form-style-6 textarea:focus,
.form-style-6 select:focus
{
box-shadow: 0 0 5px #43D1AF;
padding: 3%;
border: 1px solid #43D1AF;
}
.form-style-6 button[type="submit"]{
box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
width: 100%;
padding: 3%;
background: #1da1f2;
border-bottom: 2px solid #1da1f2;
border-top-style: none;
border-right-style: none;
border-left-style: none;
color: #fff;
}
.form-style-6 input[type="submit"]:hover,
.form-style-6 input[type="button"]:hover{
background: #2EBC99;
}
\ No newline at end of file
{% extends 'base.html' %}
{% load static %}
{% block title %}Digipus Home{% endblock %}
{% block header %}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Digipus Home</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, inital-scale=1">
<link rel="stylesheet" type="text/css" href="{% static 'app/css/guest_book.css' %}">
{% endblock header %}
</head>
<!-- Page Content -->
{% block content %}
<div class="form-group form-style-6" id="myForm">
<form method="POST">
<h3 style="text-align: center;">Buku Tamu Non Anggota</h3>
{% csrf_token %}
{{form}}
<button type="submit" class="btn btn-success">Submit</button>
</form>
</div>
{% endblock %}
</html>
\ No newline at end of file
This diff is collapsed.
...@@ -5,8 +5,7 @@ from app import views ...@@ -5,8 +5,7 @@ from app import views
from app.views import (DashboardKontributorView, ProfilView, StatisticsView, from app.views import (DashboardKontributorView, ProfilView, StatisticsView,
SuksesLoginAdminView, SuksesLoginKontributorView, DownloadHistoryView,