diff --git a/administration/templates/administration/includes/sidebar.html b/administration/templates/administration/includes/sidebar.html
index 73e357314f98bcccb5235f59df53fb4a3fdf69ff..76be2e9d24d0e05fd64af810c4cacdeefa3ef04f 100644
--- a/administration/templates/administration/includes/sidebar.html
+++ b/administration/templates/administration/includes/sidebar.html
@@ -50,4 +50,12 @@
     <!-- Divider -->
     <hr class="sidebar-divider my-0">
 
+    <li class="nav-item">
+      <a class="nav-link" href="/administration/news/list">
+        <span>Kelola Berita</span></a>
+    </li>
+
+    <!-- Divider -->
+    <hr class="sidebar-divider my-0">
+
   </ul>
\ No newline at end of file
diff --git a/digipus/settings.py b/digipus/settings.py
index f41bb346df16ab08ec55031f2050d334dba53cc3..4b4ac60a8e97b96169a295af78138d14ff28954a 100644
--- a/digipus/settings.py
+++ b/digipus/settings.py
@@ -46,6 +46,7 @@ INSTALLED_APPS = [
     "register.apps.RegisterConfig",
     "administration.apps.AdministrationConfig",
     'crispy_forms',
+    "news.apps.NewsConfig",
     "traffic_statistics",
 ]
 
diff --git a/digipus/urls.py b/digipus/urls.py
index 6f5ec5477ac62cc199a3c424d5a3970ca36507cc..8e694b93f0365307258f1730fa1b2faa5202f188 100644
--- a/digipus/urls.py
+++ b/digipus/urls.py
@@ -24,5 +24,6 @@ urlpatterns = [
     path("", include("authentication.urls"), name="auth"),
     path("", include("app.urls"), name="app"),
     path("administration/", include("administration.urls")),
+    path("", include("news.urls"), name="news"),
     path("statistics/", include("traffic_statistics.urls")),
 ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
diff --git a/news/__init__.py b/news/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/news/admin.py b/news/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..8c38f3f3dad51e4585f3984282c2a4bec5349c1e
--- /dev/null
+++ b/news/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/news/apps.py b/news/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..5a7b92d0f844e1bd89c73e7bba369b07298ae70a
--- /dev/null
+++ b/news/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class NewsConfig(AppConfig):
+    name = 'news'
diff --git a/news/forms.py b/news/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..4269106791db1147ee48589fb5e9e23c3769a894
--- /dev/null
+++ b/news/forms.py
@@ -0,0 +1,24 @@
+from django import forms
+from .models import News
+
+class NewsForm(forms.ModelForm):
+    class Meta:
+        attribute_text_input = {
+            'class' : 'form-control col-6'
+        }
+        attribute_text_area = {
+            'class' : 'form-control col-8',
+            'rows'  : "5"
+        }
+        model = News
+        fields = [
+            "title", "cover", "content"
+        ]
+        widgets = {
+            "title" : forms.TextInput(
+                attrs=attribute_text_input
+            ),
+            "content" : forms.Textarea(
+                attrs=attribute_text_area
+            )
+        }
\ No newline at end of file
diff --git a/news/migrations/0001_initial.py b/news/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..7c584641a29f5191a19848e13e52ed48722d8ff4
--- /dev/null
+++ b/news/migrations/0001_initial.py
@@ -0,0 +1,24 @@
+# Generated by Django 3.1 on 2020-10-03 07:47
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='News',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('title', models.CharField(max_length=100)),
+                ('content', models.TextField()),
+                ('timestamp', models.DateTimeField(auto_now=True)),
+                ('cover', models.ImageField(upload_to='news')),
+            ],
+        ),
+    ]
diff --git a/news/migrations/__init__.py b/news/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/news/models.py b/news/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..76bdd59a66217a31173fa59916c09060c997092c
--- /dev/null
+++ b/news/models.py
@@ -0,0 +1,8 @@
+from django.db import models
+
+class News(models.Model):
+    title = models.CharField(max_length = 100)
+    content = models.TextField()
+    timestamp = models.DateTimeField(auto_now = True)
+    cover = models.ImageField(upload_to = 'news')
+    
\ No newline at end of file
diff --git a/news/templates/news_form.html b/news/templates/news_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..8170ffa0db230be968eab5655860bab64e69f97d
--- /dev/null
+++ b/news/templates/news_form.html
@@ -0,0 +1,70 @@
+{% extends 'administration/base_administrasi2.html' %}
+
+{% load static %}
+
+{% block title %}
+    <title>Form Pembuatan Berita</title>
+{% endblock %}
+
+{% block stylesheets %}
+    <script src="https://code.jquery.com/jquery-3.4.1.min.js" crossorigin="anonymous"></script>
+    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
+            integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
+            crossorigin="anonymous"></script>
+
+    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
+          integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
+    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
+            integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
+            crossorigin="anonymous"></script>
+
+    <link href="https://cdn.jsdelivr.net/npm/summernote@0.8.16/dist/summernote-bs4.min.css" rel="stylesheet">
+    <script src="https://cdn.jsdelivr.net/npm/summernote@0.8.16/dist/summernote-bs4.min.js"></script>
+{% endblock stylesheets %}
+
+{% block content %}
+    <div class="row-12">
+        {% if type == 'update' %}
+            <form method="POST" action="{% url 'update_news_form' form.instance.pk%}" enctype="multipart/form-data">
+                {% csrf_token %}
+                <h1 class="h3 mb-2 text-gray-800">
+                    Formulir Sunting Berita
+                </h1>
+                <br>
+                {{form.as_p}}
+                <br>
+                <button type="submit" class="btn btn-primary">Update News</button>
+            </form>
+        {% else %}
+            <form method="POST" action="{% url 'post_news_form' %}" enctype="multipart/form-data">
+                {% csrf_token %}
+                <h1 class="h3 mb-2 text-gray-800">
+                    Formulir Tambah Berita
+                </h1>
+                <br>
+                {{form.as_p}}
+                <br>
+                <button type="submit" class="btn btn-primary">Post News</button>
+            </form>
+        {% endif %}
+    </div>
+
+    <script>
+    $('#id_content').summernote({
+        placeholder: 'Write here ...',
+        tabsize: 2,
+        height: 300,
+        codeviewFilter: false,
+        codeviewIframeFilter: true,
+        toolbar: [
+            ['style', ['style']],
+            ['font', ['bold', 'italic', 'underline', 'clear']],
+            ['fontname', ['fontname']],
+            ['color', ['color']],
+            ['para', ['ul', 'ol', 'paragraph']],
+            ['insert', ['link', 'picture', 'video']],
+            ['view', ['fullscreen']],
+        ]
+    });
+    </script>
+{% endblock %}
diff --git a/news/templates/news_list.html b/news/templates/news_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..d3c99fdd55fd2a870191ea401dad68c6fb62a870
--- /dev/null
+++ b/news/templates/news_list.html
@@ -0,0 +1,73 @@
+{% extends 'administration/base_administrasi2.html' %}
+{% load static %}
+
+{% block title %}
+<title>Kelola Berita | Digipus</title>
+{% endblock %}
+
+{% block content %}
+<!-- Page Heading -->
+<h1 class="h3 mb-2 text-gray-800">Kelola Berita</h1>
+<br>
+<!-- DataTales Example -->
+<div class="card shadow mb-4">
+  <div class="card-header py-3">
+    <div class="d-flex">
+      <div class="mr-auto p-2">
+        <h6 class="m-0 font-weight-bold text-primary">Tabel Daftar Berita</h6>
+      </div>
+      <div class="p-2">
+        <a href="/administration/news/form" class="accept-button button-decoration button-header">Buat Berita Baru</a>
+      </div>
+    </div>
+  </div>
+  <div class="card-body">
+    <div class="table-responsive">
+      <table class="table table-bordered" id="dataTable">
+        <caption class="table_caption">Daftar Berita</caption>
+        <thead>
+          <tr>
+            <th id="table_title">Judul</th>
+            <th id="table_timestamp">Waktu Diperbarui Terakhir</th>
+            <th id="table_buttons">Pilihan</th>
+          </tr>
+        </thead>
+        <tbody>
+          {% for current in news_list %}
+          <tr>
+            <td>{{ current.title }}</td>
+            <td>{{ current.timestamp }}</td>
+            <td class="verif-buttons">
+              <span>
+                <a href="/administration/news/form/edit/{{ current.id }}" class="accept-button button-decoration">Update</a>
+                <button type="button" class="reject-button button-decoration" data-toggle="modal" data-target="#confirmModal{{ current.id }}">Hapus</button>
+                <div class="modal fade" id="confirmModal{{ current.id }}" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
+                  <div class="modal-dialog" role="document">
+                    <div class="modal-content">
+                      <div class="modal-header">
+                        <h5 class="modal-title" id="exampleModalLabel">Konfirmasi Penghapusan Berita "{{current.title}}"</h5>
+                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                          <span aria-hidden="true">&times;</span>
+                        </button>
+                      </div>
+                      <div class="modal-body">
+                        <p>Silahkan konfirmasi penghapusan berita dengan tekan tombol hapus di bawah</p>
+                      </div>
+                      <div class="modal-footer">
+                        <button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
+                        <a href="/administration/news/delete/{{current.id}}" type="button" class="btn btn-danger">Hapus</a>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </span>
+            </td>
+          </tr>
+          {% endfor %}
+        </tbody>
+      </table>
+    </div>
+  </div>
+</div>
+
+{% endblock %}
\ No newline at end of file
diff --git a/news/tests.py b/news/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..595532f63a1943dbf19cdf2dd6d626c5fe94f8f1
--- /dev/null
+++ b/news/tests.py
@@ -0,0 +1,284 @@
+import shutil
+import tempfile
+import uuid
+
+from django.contrib.auth import get_user_model
+from django.test import TestCase, override_settings, Client
+from django.core.files.uploadedfile import SimpleUploadedFile
+from io import BytesIO
+from PIL import Image
+from django.core.files.base import File
+
+from .models import News
+from administration import models
+
+MOCK_MEDIA_ROOT = tempfile.mkdtemp()
+
+@override_settings(MEDIA_ROOT = MOCK_MEDIA_ROOT)
+class NewsModelTest(TestCase):
+    def setUp(self):
+        self.test_file_jpg1 = SimpleUploadedFile("foto1.jpg", b"file_content")
+        self.test_file_jpg2 = SimpleUploadedFile("foto2.jpg", b"file_content")
+        self.news1 = News.objects.create(
+            title = 'title1',
+            content = 'content news1',
+            cover = self.test_file_jpg1
+        )
+        self.news2 = News.objects.create(
+            title = 'title2',
+            content = 'content news2',
+            cover = self.test_file_jpg2
+        )
+        
+        self.news1.save()
+        self.news2.save()
+
+    @classmethod
+    def tearDownClass(cls):
+        shutil.rmtree(MOCK_MEDIA_ROOT, ignore_errors=True)
+        super().tearDownClass()
+
+    def test_object_news_is_created(self):
+        self.assertTrue(type(self.news1), News)
+        self.assertTrue(type(self.news2), News)
+
+    def test_id_news_is_generated(self):
+        self.assertIsNotNone(self.news1.id)
+        self.assertIsNotNone(self.news2.id)
+
+    def test_news1_title_is_title1(self):
+        self.assertEqual(self.news1.title, "title1")
+    
+    def test_news1_adn_news2_title_is_not_equal(self):
+        self.assertNotEqual(self.news1.title, self.news2.title)
+
+    def test_news1_content_is_content_news1(self):
+        self.assertEqual(self.news1.content, "content news1")
+    
+    def test_news1_and_news2_content_is_not_equal(self):
+        self.assertNotEqual(self.news1.content, self.news2.content)
+
+    def test_news1_timestamp_is_not_none(self):
+        self.assertIsNotNone(self.news1.timestamp)
+
+    def test_news1_cover_is_not_none(self):
+        self.assertIsNotNone(self.news1.cover)
+
+    def test_news1_and_news2_cover_is_not_equal(self):
+        self.assertNotEqual(self.news1.cover, self.news2.cover)
+
+@override_settings(MEDIA_ROOT = MOCK_MEDIA_ROOT)
+class NewsFormTest(TestCase):
+    def setUp(self):
+        self.client = Client()
+        self.root_url = "/"
+        self.base_url = '/administration/news/'
+        self.form_url = self.base_url+"form/"
+        self.post_form_url = self.form_url+"post"
+        self.delete_news_url = self.base_url+"delete/"
+        self.update_form_url = self.form_url+"edit/"
+        self.list_news_url = self.base_url+"list"
+        self.admin_jpg_name = "news_admin.jpg"
+        self.admin_credential = {
+            "email": "admin@gov.id",
+            "password": str(uuid.uuid4())
+        }
+        self.contributor_credential = {
+            "email": "kontributor@gov.id",
+            "password": str(uuid.uuid4())
+        }
+        self.admin = get_user_model().objects.create_user(
+            **self.admin_credential, name="Admin", is_admin=True)
+        self.contributor = get_user_model().objects.create_user(
+            **self.contributor_credential, name="Kontributor", is_contributor=True
+        )
+        self.test_file_jpg3 = SimpleUploadedFile("foto3.jpg", b"file_content")
+        self.test_file_jpg4 = SimpleUploadedFile("foto4.jpg", b"file_content")
+        self.news3 = News.objects.create(
+            title = 'title3',
+            content = 'content news3',
+            cover = self.test_file_jpg3
+        )
+        self.news4 = News.objects.create(
+            title = 'title4',
+            content = 'content news4',
+            cover = self.test_file_jpg4
+        )
+        self.news3.save()
+        self.news4.save()
+
+    @classmethod
+    def tearDownClass(cls):
+        shutil.rmtree(MOCK_MEDIA_ROOT, ignore_errors=True)
+        super().tearDownClass()
+
+    @staticmethod
+    def get_image_file(name, ext='png', size=(50, 50), color=(256, 0, 0)):
+        file_obj = BytesIO()
+        image = Image.new("RGBA", size=size, color=color)
+        image.save(file_obj, ext)
+        file_obj.seek(0)
+        return File(file_obj, name=name)
+
+    def test_post_form_news_open_raw_url(self):
+        self.client.login(**self.admin_credential)
+        response = self.client.get(self.post_form_url)
+        self.assertRedirects(response, self.root_url)
+        self.client.logout()
+
+    def test_post_form_news_by_admin_and_form_is_valid_data_exist(self):
+        self.client.login(**self.admin_credential)
+        news_data = {
+            "title" : "news_admin",
+            "content" : "content_admin",
+            "cover" : self.get_image_file(self.admin_jpg_name)
+        }
+        response = self.client.post(self.post_form_url, news_data, format='multipart')
+        self.assertTrue(News.objects.filter(title="news_admin").exists())
+        self.assertRedirects(response, self.list_news_url)
+        self.client.logout()
+    
+    def test_post_form_news_by_admin_and_form_is_not_valid_and_data_not_exist(self):
+        self.client.login(**self.admin_credential)
+        news_data = {
+            "title" : "not_news_admin",
+        }
+        response = self.client.post(self.post_form_url, news_data, format='multipart')
+        self.assertFalse(News.objects.filter(title="not_news_admin").exists())
+        self.assertRedirects(response, self.root_url)
+        self.client.logout()
+
+    def test_post_form_news_by_kontributi_and_form_is_valid_data_not_exist(self):
+        self.client.login(**self.contributor_credential)
+        news_data = {
+            "title" : "news_contrib",
+            "content" : "content_admin",
+            "cover" : self.get_image_file(self.admin_jpg_name)
+        }
+        response = self.client.post(self.post_form_url, news_data, format='multipart')
+        self.assertFalse(News.objects.filter(title="news_admin").exists())
+        self.assertRedirects(response, self.root_url)
+        self.client.logout()
+
+    def test_delete_news_by_admin_and_data_is_exist_and_data_deleted(self):
+        self.client.login(**self.admin_credential)
+        id_news4 = self.news4.id
+        response = self.client.post(self.delete_news_url+str(id_news4), {})
+        self.assertFalse(News.objects.filter(pk=id_news4).exists())
+        self.assertRedirects(response, self.list_news_url)
+        self.client.logout()
+    
+    def test_delete_news_by_contributor_and_data_is_exist_and_data_not_deleted(self):
+        self.client.login(**self.contributor_credential)
+        id_news4 = self.news4.id
+        response = self.client.post(self.delete_news_url+str(id_news4), {})
+        self.assertTrue(News.objects.filter(pk=id_news4).exists())
+        self.assertRedirects(response, self.root_url)
+        self.client.logout()
+
+    def test_delete_news_by_anonymous_and_data_is_exist_and_data_not_deleted(self):
+        id_news4 = self.news4.id
+        response = self.client.post(self.delete_news_url+str(id_news4), {})
+        self.assertTrue(News.objects.filter(pk=id_news4).exists())
+        self.assertEqual(response.status_code, 302)
+
+    def test_delete_news_by_admin_and_data_is_not_exist(self):
+        self.client.login(**self.admin_credential)
+        response = self.client.post(self.delete_news_url+"4124123", {})
+        self.assertRedirects(response, self.list_news_url)
+        self.client.logout()
+    
+    def test_form_news_url_is_exist_for_admin(self):
+        self.client.login(**self.admin_credential)
+        response = self.client.get(self.form_url)
+        self.assertEqual(response.status_code, 200)
+        self.client.logout()
+    
+    def test_form_news_url_is_not_exist_for_contributor(self):
+        self.client.login(**self.contributor_credential)
+        response = self.client.get(self.form_url)
+        self.assertRedirects(response, self.root_url)
+        self.client.logout()
+
+    def test_form_news_url_is_not_exist_for_anonymous(self):
+        response = self.client.get(self.form_url)
+        self.assertEqual(response.status_code, 302)
+    
+    def test_form_news_using_news_form_html(self):
+        self.client.login(**self.admin_credential)
+        response = self.client.get(self.form_url)
+        self.assertTemplateUsed(response, 'news_form.html')
+        self.client.logout()
+
+    def test_update_form_news_using_news_form_html(self):
+        self.client.login(**self.admin_credential)
+        id_news4 = str(self.news4.id)
+        response = self.client.get(self.update_form_url+id_news4)
+        self.assertTemplateUsed(response, 'news_form.html')
+        self.client.logout()
+
+    def test_update_form_news_but_news_not_exist(self):
+        self.client.login(**self.admin_credential)
+        response = self.client.get(self.update_form_url+"283912")
+        self.assertEqual(response.status_code, 302)
+        self.client.logout()
+
+    def test_update_news_form_for_non_admin(self):
+        self.client.login(**self.contributor_credential)
+        id_news3 = str(self.news3.id)
+        response = self.client.get(self.update_form_url+id_news3)
+        self.assertRedirects(response, self.root_url)
+        self.client.logout()
+
+    def test_update_form_news_by_admin_and_form_is_valid_change_data(self):
+        self.client.login(**self.admin_credential)
+        id_news3 = self.news3.id
+        news_data = {
+            "id" : id_news3,
+            "title" : "title3_new",
+            "content" : "content_admin",
+            "cover" : self.get_image_file(self.admin_jpg_name)
+        }
+        response = self.client.post(self.update_form_url+str(id_news3), news_data, format='multipart')
+        self.assertTrue(News.objects.filter(title="title3_new").exists())
+        self.assertFalse(News.objects.filter(title="title3").exists())
+        self.assertEqual(response.status_code, 302)
+        self.client.logout()
+
+    def test_update_form_news_by_contributor_and_form_is_valid_not_change_data(self):
+        self.client.login(**self.contributor_credential)
+        id_news3 = self.news3.id
+        news_data = {
+            "id" : id_news3,
+            "title" : "title3_new",
+            "content" : "content_admin",
+            "cover" : self.get_image_file(self.admin_jpg_name)
+        }
+        response = self.client.post(self.update_form_url+str(id_news3), news_data, format='multipart')
+        self.assertFalse(News.objects.filter(title="title3_new").exists())
+        self.assertTrue(News.objects.filter(title="title3").exists())
+        self.assertEqual(response.status_code, 302)
+        self.client.logout()
+
+    def test_list_news_url_is_exist_for_admin(self):
+        self.client.login(**self.admin_credential)
+        response = self.client.get(self.list_news_url)
+        self.assertEqual(response.status_code, 200)
+        self.client.logout()
+    
+    def test_list_news_url_is_not_exist_for_contributor(self):
+        self.client.login(**self.contributor_credential)
+        response = self.client.get(self.list_news_url)
+        self.assertRedirects(response, self.root_url)
+        self.client.logout()
+
+    def test_list_news_url_is_not_exist_for_anonymous(self):
+        response = self.client.get(self.list_news_url)
+        self.assertEqual(response.status_code, 302)
+    
+    def test_list_news_using_news_form_html(self):
+        self.client.login(**self.admin_credential)
+        response = self.client.get(self.list_news_url)
+        self.assertTemplateUsed(response, 'news_list.html')
+        self.client.logout()
+    
\ No newline at end of file
diff --git a/news/urls.py b/news/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..568d2060336a7583d0fa8ad63ae48e5256d5e4ca
--- /dev/null
+++ b/news/urls.py
@@ -0,0 +1,31 @@
+from django.urls import path
+
+from . import views
+
+urlpatterns = [
+    path(
+        'administration/news/form/post',
+        views.post_news_form,
+        name = "post_news_form"
+    ),
+    path(
+        'administration/news/delete/<int:id_news>',
+        views.delete_news_by_id,
+        name = "delete_news_by_id"
+    ),
+    path(
+        'administration/news/form/',
+        views.show_news_form,
+        name = "show_news_form"
+    ),
+    path(
+        'administration/news/form/edit/<int:id_news>',
+        views.update_news_form,
+        name = "update_news_form"
+    ),
+    path(
+        'administration/news/list',
+        views.show_news_list,
+        name = "show_news_list"
+    ),
+]
\ No newline at end of file
diff --git a/news/views.py b/news/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..296f774b906429eb9cd3b2902d50d6143ce3537d
--- /dev/null
+++ b/news/views.py
@@ -0,0 +1,90 @@
+from django.http import HttpResponse
+from django.shortcuts import render, redirect
+from django.contrib.auth.decorators import login_required
+from django.views.decorators.csrf import csrf_exempt
+
+from .forms import NewsForm
+
+from .models import News
+
+html_news_form = "news_form.html"
+html_news_list = "news_list.html"
+login_url = "/login/"
+root_url = "/"
+news_list_url = "/administration/news/list"
+
+@login_required(login_url=login_url)
+def post_news_form(request):
+    if request.user.is_admin is False:
+        return redirect(root_url)
+    
+    form = NewsForm(request.POST or None, request.FILES or None)
+    if form.is_valid():
+        news_data = News.objects.create(
+            title=request.POST["title"],
+            content=request.POST["content"],
+            cover=request.FILES.get("cover", False)
+        )
+        news_data.save()
+        return redirect(news_list_url)
+    return redirect("/")
+
+@csrf_exempt
+@login_required(login_url=login_url)
+def delete_news_by_id(request, id_news):
+    if request.user.is_admin is False:
+        return redirect(root_url)
+
+    try:
+        news_data = News.objects.get(pk=id_news)
+    except News.DoesNotExist:
+        return redirect(news_list_url)
+    news_data.cover.delete()
+    news_data.delete()
+    return redirect(news_list_url)
+
+@login_required(login_url=login_url)
+def show_news_form(request):
+    if request.user.is_admin is False:
+        return redirect(root_url)
+
+    response = {
+        "form" : NewsForm()
+    }
+    return render(request, html_news_form, response)
+
+@login_required(login_url=login_url)
+def update_news_form(request, id_news):
+    if request.user.is_admin is False:
+        return redirect(root_url)
+    
+    try:
+        news_data = News.objects.get(pk=id_news)
+    except News.DoesNotExist:
+        return redirect(news_list_url)
+    
+    form = NewsForm(instance=news_data)
+    if request.method == "POST":
+        form = NewsForm(request.POST or None,
+                        request.FILES or None,
+                        instance=news_data)
+        if form.is_valid():
+            form.save()
+            return redirect(news_list_url)
+
+    response = {
+        'form': form,
+        'type': 'update',
+        'pk':id_news
+    }
+    return render(request, html_news_form, response)
+
+@login_required(login_url=login_url)
+def show_news_list(request):
+    if request.user.is_admin is False:
+        return redirect(root_url)
+
+    response = {
+        "news_list" : News.objects.all()
+    }
+    return render(request, html_news_list, response)
\ No newline at end of file