diff --git a/app/migrations/0015_downloadstatistics_downloader.py b/app/migrations/0015_downloadstatistics_downloader.py
new file mode 100644
index 0000000000000000000000000000000000000000..16780d0c070064f852acf2e180dfcb1ba5179afc
--- /dev/null
+++ b/app/migrations/0015_downloadstatistics_downloader.py
@@ -0,0 +1,21 @@
+# Generated by Django 3.0.4 on 2020-09-30 04:50
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('app', '0014_rating'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='downloadstatistics',
+            name='downloader',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='riwayat_unduh', to=settings.AUTH_USER_MODEL),
+        ),
+    ]
diff --git a/app/migrations/0018_merge_20201009_0700.py b/app/migrations/0018_merge_20201009_0700.py
new file mode 100644
index 0000000000000000000000000000000000000000..2e5d56480fa1f304956819f4012e5e52c2100d5e
--- /dev/null
+++ b/app/migrations/0018_merge_20201009_0700.py
@@ -0,0 +1,14 @@
+# Generated by Django 3.1 on 2020-10-09 00:00
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('app', '0017_auto_20201005_2145'),
+        ('app', '0015_downloadstatistics_downloader'),
+    ]
+
+    operations = [
+    ]
diff --git a/app/models.py b/app/models.py
index 54e05f404d9b68827b86d9ce247a2f7873caa26c..4164b8443638d80ea89f091d476ef96ff0ce954d 100644
--- a/app/models.py
+++ b/app/models.py
@@ -98,6 +98,8 @@ class ViewStatistics(models.Model):
 class DownloadStatistics(models.Model):
     materi = models.ForeignKey(
         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)
 
 
diff --git a/app/static/app/css/katalog_materi.css b/app/static/app/css/katalog_materi.css
index fa4103f99ac5280444c273fa45d38b3b9c8da919..67a035f6e97ee499d66aaf892692709b38e2ea1e 100644
--- a/app/static/app/css/katalog_materi.css
+++ b/app/static/app/css/katalog_materi.css
@@ -62,6 +62,21 @@ body{
     background-color: #615CFD;
 }
 
+.btn-history {
+    width: auto;
+    padding: 8px 8px;
+    border-radius: 2px;
+    background-color: #ffffff;
+    color: #615CFD;
+    border: none;
+    box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
+}
+
+.btn-history:hover{
+    color: #ffffff;
+    background-color: #615CFD;
+}
+
 .content {
     display: flex;
     margin: 5px;
diff --git a/app/templates/app/katalog_materi.html b/app/templates/app/katalog_materi.html
index c4013e21b6549391bcea6a7281e3540f782a98d0..0d02d0b102957774ca1586703592ac85b5d393da 100644
--- a/app/templates/app/katalog_materi.html
+++ b/app/templates/app/katalog_materi.html
@@ -49,7 +49,6 @@
 <body style="background-color: #f8f8f8;">
     <!-- Page Content -->
     <div class="container">
-
         <header class="jumbotron my-4">
             <div class="container">
                 <div class="row header">
@@ -61,15 +60,17 @@
                                 <input type="text" name='search' class="form-control" placeholder="Tulis di sini"
                                     value='{{request.GET.search}}'>
                             </div>
-                            <button type="submit" class="btn btn-cari">Cari</button>
+							<button type="submit" class="btn btn-cari">Cari</button>
                         </form>
                         <p class="pageTitle">Tidak menemukan materi yang kamu cari ? ajukan permintaan materi kami <a
                                 href="/req-materi">disini</a></p>
                     </div>
                 </div>
-            </div>
+            </div>    
         </header>
-
+		
+		<a href="/download-history/" class="btn-history">Riwayat Unduh</a><br><br>
+		
         <div class="container">
             <div class="row content">
                 <div class="col-3 sidebar">
@@ -154,7 +155,6 @@
                 <div class="center">
                     <div class="pagination">
                         <span class="step-links">
-
                             <span class="current">
                                 Page {{ materi_list.number }} of {{ materi_list.paginator.num_pages }}
                             </span>
diff --git a/app/templates/download_history.html b/app/templates/download_history.html
new file mode 100644
index 0000000000000000000000000000000000000000..cbb47b957137bd20fa472b0f7aed5559cc30b330
--- /dev/null
+++ b/app/templates/download_history.html
@@ -0,0 +1,61 @@
+{% extends 'base.html' %}
+{% load static %}
+
+{% block title %}
+<title>Riwayat Unduh | Digipus</title>
+{% endblock %} 
+
+{% block header %}
+<link rel="icon" type="image/png" href="{% static 'images/icons/logo.ico' %}" />
+<link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
+
+<link href="{% static 'css/sb-admin-2.min.css' %}" rel="stylesheet">
+<link rel="stylesheet" href="{% static 'css/button.css' %}">
+
+<link href="{% static 'vendor/datatables/dataTables.bootstrap4.min.css' %}" rel="stylesheet">
+{% endblock %} 
+
+{% block content %}
+<br><br>
+<h1 id="riwayat_unduh" class="h3 mb-2 text-gray-800">Riwayat Unduh | {{ user_name }}</h1>
+{% if riwayat_list %}
+<p class="mb-4">Tekan tombol detail untuk informasi lebih lanjut tentang materi</p>
+
+<div class="card shadow mb-4">
+  <div class="card-body">
+    <div class="table-responsive">
+      <table aria-describedby="riwayat_unduh" class="table table-bordered" id="dataTable">
+        <thead>
+          <tr>
+            <th id="judul_materi">Judul Materi</th>
+            <th id="author">Pembuat Materi</th>
+			<th id="download_time">Waktu Download</th>
+            <th id="detail_buttons">Detail</th>
+          </tr>
+        </thead>
+        <tbody>
+          {% for riwayat in riwayat_list %}
+          <tr>
+            <td>{{riwayat.materi.title}}</td>
+            <td>{{riwayat.materi.author}}</td>
+			<td>{{riwayat.timestamp|date:"d F Y H:i:s"}}</td>
+            <td class="verif-buttons">
+              <span>
+                <a href="/materi/{{riwayat.materi.id}}/" class="accept-button button-decoration"
+                style="background-color:#4e73df">Detail</a>
+              </span>
+            </td>
+          </tr>
+          {% endfor %}
+        </tbody>
+      </table>
+    </div>
+  </div>
+{% else %}
+<p class="mb-4">Anda belum mengunduh materi. Silahkan unduh materi yang anda butuhkan</p>
+{% endif %}
+<span>
+	<a href="/" class="btn btn-primary main-content" style="background-color:#4e73df; right: 0px;">Back to Katalog</a>
+</span>
+<br>
+{% endblock %}
\ No newline at end of file
diff --git a/app/tests.py b/app/tests.py
index cff2740ab0736020aa14278053b5180e6ff2b562..2b65c523038a63a196033069604832b23b10bd92 100644
--- a/app/tests.py
+++ b/app/tests.py
@@ -1,31 +1,39 @@
 import json, tempfile, os
+import pandas as pd
 from io import StringIO
 
+from bs4 import BeautifulSoup
+from datetime import datetime
 from django.conf import settings
+from django.contrib import messages as dj_messages
 from django.contrib.auth import get_user_model
+from django.core import serializers
+from django.core.files import File
 from django.core.exceptions import PermissionDenied, ValidationError
 from django.core.files.uploadedfile import SimpleUploadedFile
 from django.core.management import call_command
-from django.test import Client, TestCase, TransactionTestCase
-from django.urls import resolve
-from django.contrib import messages as dj_messages
 from django.db.utils import IntegrityError
+from django.urls import resolve
+from django.test import Client, RequestFactory, TestCase, TransactionTestCase
+from pytz import timezone
+from time import sleep
 
 from administration.models import VerificationSetting, VerificationReport
 from administration.utils import id_generator
-from app.views import UploadMateriView, add_rating_materi
+from app.views import UploadMateriHTML, add_rating_materi
 from authentication.models import User
-from .models import Category, Comment, Materi, Like, Rating, ReqMaterial, RatingContributor
+from digipus.settings import TIME_ZONE
+from .models import (Category, Comment, DownloadStatistics, Materi, Like, 
+                    Rating, ReqMaterial, RatingContributor, ViewStatistics)
+
 from .views import (DaftarKatalog, DashboardKontributorView, DetailMateri,
                     ProfilKontributorView, SuksesLoginAdminView,
                     SuksesLoginKontributorView, SuntingProfilView,
                     ProfilAdminView, PostsView, SuntingProfilAdminView, 
                     RevisiMateriView, ReqMateriView, KatalogPerKontributorView,
-                    UploadMateriExcelView)
+                    UploadMateriView, UploadMateriExcelView)
 from app.forms import SuntingProfilForm
 from app.utils.fileManagementUtil import get_random_filename, remove_image_exifdata
-import pandas as pd
-
 
 class DaftarKatalogTest(TestCase):
     def test_daftar_katalog_url_exist(self):
@@ -1658,3 +1666,318 @@ class RatingContributorTest(TransactionTestCase):
         self.assertEqual(0, RatingContributor.objects.filter(user=self.contributor.id).count())
         self.client.post(url, data={"user": self.contributor.id, "score": 0})
         self.assertEqual(0, RatingContributor.objects.filter(user=self.contributor.id).count())
+
+class UserDownloadHistoryTest(TestCase):
+    def setUp(self):
+        self.user1_credential = {
+            "email": "anonim1@gov.id",
+            "password": id_generator()
+        }
+        self.user1_anonim = get_user_model().objects.create_user(
+            **self.user1_credential, name="Anonim1")
+        self.user2_credential = {
+            "email": "anonim2@gov.id",
+            "password": id_generator()
+        }
+        self.user2_anonim = get_user_model().objects.create_user(
+            **self.user2_credential, name="Anonim2")
+        self.contributor_credential = {
+            "email": "kontributor@gov.id",
+            "password": id_generator()
+        }
+        self.contributor = get_user_model().objects.create_user(
+            **self.contributor_credential, name="Kontributor", is_contributor=True
+        )
+        self.client = Client()
+        content = b"Test file"
+        self.cover = SimpleUploadedFile(
+            "cover.jpg",
+            content
+        )
+        self.content = SimpleUploadedFile(
+            "content.txt",
+            content
+        )
+        Materi(title="Materi 1", author="Agas", uploader=self.contributor,
+               publisher="Kelas SC", descriptions="Deskripsi Materi 1",
+               status="PENDING", cover=self.cover, content=self.content).save()
+        self.materi1 = Materi.objects.first()
+        self.download_url = f"/materi/{self.materi1.id}/unduh"
+        self.history_url = "/download-history/"
+	
+    def test_multiple_insert_download_statistic_with_user(self):
+        DownloadStatistics(materi=self.materi1, downloader=self.user1_anonim).save()
+        num_of_downloads = self.user1_anonim.riwayat_unduh.all().count()
+        self.assertEqual(num_of_downloads, 1)
+		
+        DownloadStatistics(materi=self.materi1, downloader=self.user1_anonim).save()
+        num_of_downloads = self.user1_anonim.riwayat_unduh.all().count()
+        self.assertEqual(num_of_downloads, 2)
+		
+    def test_download_statistics_bound_to_specific_user(self):
+        DownloadStatistics(materi=self.materi1, downloader=self.user1_anonim).save()
+        num_of_downloads = self.user1_anonim.riwayat_unduh.all().count()
+        self.assertEqual(num_of_downloads, 1)
+		
+        DownloadStatistics(materi=self.materi1).save()
+        num_of_downloads = self.user1_anonim.riwayat_unduh.all().count()
+        self.assertEqual(num_of_downloads, 1)
+		
+        DownloadStatistics(materi=self.materi1, downloader=self.user2_anonim).save()
+        user1_num_of_downloads = self.user1_anonim.riwayat_unduh.all().count()
+        user2_num_of_downloads = self.user2_anonim.riwayat_unduh.all().count()
+        self.assertEqual(user1_num_of_downloads, 1)
+        self.assertEqual(user2_num_of_downloads, 1)
+
+    def test_registered_user_download(self):
+        # Login
+        self.client.login(**self.user1_credential)
+		
+        self.client.get(self.download_url)
+        num_of_downloads = self.user1_anonim.riwayat_unduh.all().count()
+        self.assertEqual(num_of_downloads, 1)
+		
+        # Logout
+        self.client.logout()
+		
+    def test_unregistered_user_download(self):
+        self.client.get(self.download_url)
+        downloaded_materi = self.client.session['downloaded_materi']
+        num_of_downloads = DownloadStatistics.objects.filter(
+                            pk__in=downloaded_materi).count()
+        self.assertEqual(num_of_downloads, 1)
+
+    def test_registered_user_multiple_download(self):
+        # Login
+        self.client.login(**self.user1_credential)
+        self.client.get(self.download_url)
+        num_of_downloads = self.user1_anonim.riwayat_unduh.all().count()
+        self.assertEqual(num_of_downloads, 1)
+
+        self.client.get(self.download_url)
+        num_of_downloads = self.user1_anonim.riwayat_unduh.all().count()
+        self.assertEqual(num_of_downloads, 2)
+		
+        # Logout
+        self.client.logout()
+		
+    def test_unregistered_user_multiple_download(self):
+        self.client.get(self.download_url)
+        downloaded_materi = self.client.session['downloaded_materi']
+        num_of_downloads = DownloadStatistics.objects.filter(
+                            pk__in=downloaded_materi).count()
+        self.assertEqual(num_of_downloads, 1)
+
+        self.client.get(self.download_url)
+        downloaded_materi = self.client.session['downloaded_materi']
+        num_of_downloads = DownloadStatistics.objects.filter(
+                            pk__in=downloaded_materi).count()
+        self.assertEqual(num_of_downloads, 2)
+		
+    def test_registered_user_doesnt_use_session_when_download(self):
+        # Login
+        self.client.login(**self.user1_credential)
+		
+        self.client.get(self.download_url)
+        self.assertFalse('downloaded_materi' in self.client.session)
+		
+        # Logout
+        self.client.logout()
+	
+    def test_download_history_bound_to_specific_user(self):
+        # Login Anonym 1
+        self.client.login(**self.user1_credential)
+        self.client.get(self.download_url)
+        num_of_downloads = self.user1_anonim.riwayat_unduh.all().count()
+        self.assertEqual(num_of_downloads, 1)
+		
+        # Logout Anonym 1
+        self.client.logout()
+		
+		# Unregistered User download
+        self.client.get(self.download_url)
+        user1_num_of_downloads = self.user1_anonim.riwayat_unduh.all().count()
+        downloaded_materi = self.client.session['downloaded_materi']
+        guest_num_of_downloads = DownloadStatistics.objects.filter(
+                            pk__in=downloaded_materi).count()
+        self.assertEqual(user1_num_of_downloads, 1)
+        self.assertEqual(guest_num_of_downloads, 1)
+		
+		# Login Anonym 2
+        self.client.login(**self.user2_credential)
+        self.client.get(self.download_url)
+        user1_num_of_downloads = self.user1_anonim.riwayat_unduh.all().count()
+        user2_num_of_downloads = self.user2_anonim.riwayat_unduh.all().count()
+        self.assertEqual(user1_num_of_downloads, 1)
+        self.assertEqual(guest_num_of_downloads, 1)
+        self.assertEqual(user2_num_of_downloads, 1)
+		
+        # Logout Anonym 2
+        self.client.logout()
+
+class DownloadHistoryViewTest(TestCase):
+    def setUp(self):
+        self.user_credential = {
+            "email": "anonim1@gov.id",
+            "password": id_generator()
+        }
+        self.user_anonim = get_user_model().objects.create_user(
+            **self.user_credential, name="Anonim")
+        self.contributor_credential = {
+            "email": "kontributor@gov.id",
+            "password": id_generator()
+        }
+        self.contributor = get_user_model().objects.create_user(
+            **self.contributor_credential, name="Kontributor", is_contributor=True
+        )
+        self.client = Client()
+		
+        content1 = b"Test file"
+        content2 = b"File Test"
+		
+        self.cover1 = SimpleUploadedFile("cover1.jpg",content1)
+        self.content1 = SimpleUploadedFile("content1.txt",content1)
+		
+        self.cover2 = SimpleUploadedFile("cover2.jpg",content2)
+        self.content2 = SimpleUploadedFile("content2.txt",content2)
+		
+        self.materi1 = Materi.objects.create(title="Materi 1", author="Agas", uploader=self.contributor,
+               publisher="Kelas SC", descriptions="Deskripsi Materi 1",
+               status="PENDING", cover=self.cover1, content=self.content1)
+        self.materi2 = Materi.objects.create(title="Materi 2", author="Danin", uploader=self.contributor,
+               publisher="Kelas DDP", descriptions="Deskripsi Materi 2",
+               status="PENDING", cover=self.cover2, content=self.content2)
+			   
+        self.download_url1 = f"/materi/{self.materi1.id}/unduh"
+        self.download_url2 = f"/materi/{self.materi2.id}/unduh"
+        self.history_url = "/download-history/"
+		
+        # Login
+        self.client.login(**self.user_credential)
+
+    def tearDown(self):
+        # Logout
+        self.client.logout()
+		
+    def test_allow_registered_user(self):
+        response = self.client.get(self.history_url)
+        self.assertEqual(response.status_code, 200)
+	
+    def test_allow_unregistered_user(self):
+	    # Forced Logout
+        self.client.logout()
+		
+        response = self.client.get(self.history_url)
+        self.assertEqual(response.status_code, 200)
+
+    def test_download_history_using_correct_template(self):
+        response = self.client.get(self.history_url)
+        self.assertTemplateUsed(response, "download_history.html")
+
+    def test_download_history_has_user_name(self):
+        response = self.client.get(self.history_url)
+        resp_html = response.content.decode('utf8')
+        self.assertIn(self.user_anonim.name, resp_html)
+		
+    def test_registered_user_download_history_correctly_displayed(self):
+        self.client.get(self.download_url1)
+        self.client.get(self.download_url2)
+        self.client.get(self.download_url1)
+		
+        jkt_timezone = timezone(TIME_ZONE)
+		
+        download_history = self.user_anonim.riwayat_unduh.all()
+        response = self.client.get(self.history_url)
+        resp_html = response.content.decode('utf8')
+        for riwayat in download_history:
+            downloaded_materi = riwayat.materi
+            self.assertIn(downloaded_materi.title, resp_html)
+            self.assertIn(downloaded_materi.author, resp_html)
+			
+            jkt_timestamp = riwayat.timestamp.astimezone(jkt_timezone)
+            self.assertIn(jkt_timestamp.strftime("%d %B %Y %H:%M:%S"), resp_html)
+			
+    def test_unregistered_user_download_history_correctly_displayed(self):
+        self.client.logout()
+
+        self.client.get(self.download_url1)
+        self.client.get(self.download_url2)
+        self.client.get(self.download_url1)
+		
+        jkt_timezone = timezone(TIME_ZONE)
+		
+        response = self.client.get(self.history_url)
+        resp_html = response.content.decode('utf8')
+        for riwayat_id in self.client.session['downloaded_materi']:
+            riwayat = DownloadStatistics.objects.get(pk=riwayat_id)
+            downloaded_materi = riwayat.materi
+            self.assertIn(downloaded_materi.title, resp_html)
+            self.assertIn(downloaded_materi.author, resp_html)
+			
+            jkt_timestamp = riwayat.timestamp.astimezone(jkt_timezone)
+            self.assertIn(jkt_timestamp.strftime("%d %B %Y %H:%M:%S"), resp_html)
+			
+    def test_download_history_not_display_if_user_changed(self):
+        self.client.get(self.download_url1)
+        self.client.get(self.download_url2)
+        self.client.get(self.download_url1)
+
+        self.client.logout()
+		
+        jkt_timezone = timezone(TIME_ZONE)
+		
+        download_history = self.user_anonim.riwayat_unduh.all()
+        response = self.client.get(self.history_url)
+        resp_html = response.content.decode('utf8')
+        for riwayat in download_history:
+            downloaded_materi = riwayat.materi
+            self.assertNotIn(downloaded_materi.title, resp_html)
+            self.assertNotIn(downloaded_materi.author, resp_html)
+			
+            jkt_timestamp = riwayat.timestamp.astimezone(jkt_timezone)
+            self.assertNotIn(jkt_timestamp.strftime("%d %B %Y %H:%M:%S"), resp_html)
+			
+    def test_unregistered_user_download_history_wont_be_saved_if_user_changes(self):
+        self.client.logout()
+
+        self.client.get(self.download_url1)
+        self.client.get(self.download_url2)
+        self.client.get(self.download_url1)
+		
+        self.client.get(self.history_url)
+
+        self.client.login(**self.user_credential)
+        self.client.logout()
+        self.assertFalse('downloaded_materi' in self.client.session)
+			
+    def test_download_history_sorted_by_download_time(self):
+		# download with 1 second interval to differ download time
+        self.client.get(self.download_url1)
+        sleep(1)
+        self.client.get(self.download_url2)
+        sleep(1)
+        self.client.get(self.download_url1)
+        sleep(1)
+        self.client.get(self.download_url2)
+		
+        response = self.client.get(self.history_url)
+        resp_html = response.content.decode('utf8')
+		
+        table_html = ("<table" + resp_html.split("<table")[1]).split("</table>")[0] + "</table>"
+        soup = BeautifulSoup(table_html, 'html.parser')
+        histories_html = soup.find('tbody').find_all('tr')
+        prev_timestamp = None
+		
+        for riwayat_html in histories_html:
+            materi_data = riwayat_html.find_all("td")
+            date_format = "%d %B %Y %H:%M:%S"
+            materi_timestamp = datetime.strptime(materi_data[2].get_text(), date_format)
+            if prev_timestamp:
+                self.assertTrue(prev_timestamp > materi_timestamp)
+            prev_timestamp = materi_timestamp
+			
+    def test_no_history_display_message(self):
+        no_history_msg = "Anda belum mengunduh materi. Silahkan unduh materi yang anda butuhkan"
+        response = self.client.get(self.history_url)
+        resp_html = response.content.decode('utf8')
+        self.assertIn(no_history_msg, resp_html)
\ No newline at end of file
diff --git a/app/urls.py b/app/urls.py
index e401f2ecc8735b95178609f659d757635d2f8881..a0230cfb6efe40b0c558c4e9588559f609c3b3f6 100644
--- a/app/urls.py
+++ b/app/urls.py
@@ -2,7 +2,7 @@ from django.urls import path, re_path
 
 from app import views
 from app.views import (DashboardKontributorView, ProfilKontributorView,
-                       SuksesLoginAdminView, SuksesLoginKontributorView,
+                       SuksesLoginAdminView, SuksesLoginKontributorView, DownloadHistoryView,
                        SuntingProfilView, UploadMateriHTML, UploadMateriView, UploadMateriExcelView,
                        ProfilAdminView, PostsView, SuntingProfilAdminView,
                        ReqMateriView, KatalogPerKontributorView)
@@ -16,6 +16,7 @@ urlpatterns = [
     path("materi/<int:pk>/unduh", views.download_materi, name="download-materi"),
     path("materi/<int:pk>/view", views.view_materi, name="view-materi"),
     path("dashboard/", DashboardKontributorView.as_view(), name="dashboard"),
+    path("download-history/", DownloadHistoryView.as_view(), name="download-history"),
     path("revisi/materi/<int:pk>/", views.RevisiMateriView.as_view(), name="revisi"),
     path("unggah/", UploadMateriView.as_view(), name="unggah"),
     path("unggah_excel/", UploadMateriExcelView.as_view(), name="unggah_excel"),
diff --git a/app/views.py b/app/views.py
index 8a6887565562d847ff8fa1c52c40b3c240811419..d204493a86f270c11059acfb7a7b9a35c2908081 100644
--- a/app/views.py
+++ b/app/views.py
@@ -248,7 +248,14 @@ def download_materi(request, pk):
                 response = HttpResponse(fh.read(), content_type=mimetype[0])
                 response["Content-Disposition"] = "attachment; filename=" + \
                     os.path.basename(file_path)
-                DownloadStatistics(materi=materi).save()
+                if request.user.is_authenticated:
+                    DownloadStatistics(materi=materi, downloader=request.user).save()
+                else:
+                    downloaded_materi = DownloadStatistics.objects.create(materi=materi)
+                    if 'downloaded_materi' not in request.session:
+                        request.session['downloaded_materi'] = []
+                    request.session['downloaded_materi'].append(downloaded_materi.pk)
+                    request.session.modified = True
                 return response
         except Exception as e:
             raise Http404("File tidak dapat ditemukan.")
@@ -750,3 +757,27 @@ def pages(request):
 
         template = loader.get_template("error-404.html")
         return HttpResponse(template.render(context, request))
+		
+class DownloadHistoryView(TemplateView):
+    template_name = "download_history.html"
+
+    def get_context_data(self, **kwargs):
+        context = super(DownloadHistoryView,
+                        self).get_context_data(**kwargs)
+        return context
+
+    def get(self, request, *args, **kwargs):
+        context = self.get_context_data(**kwargs)
+        if request.user.is_authenticated:
+            current_user = self.request.user
+            riwayat_list = current_user.riwayat_unduh.all().order_by('-timestamp')
+            context["riwayat_list"] = riwayat_list
+            context["user_name"] = current_user.name
+        else:
+            has_downloaded_materi = 'downloaded_materi' in request.session
+            downloaded_materi = request.session['downloaded_materi'] if has_downloaded_materi else []
+            riwayat_list = DownloadStatistics.objects.filter(
+            pk__in=downloaded_materi).order_by('-timestamp')
+            context["riwayat_list"] = riwayat_list
+            context["user_name"] = 'Guest'
+        return self.render_to_response(context)