From 3a564d5db7bdedea748f61d9a5a0d5a9eedc3fe7 Mon Sep 17 00:00:00 2001 From: Jan-Tarek Butt <tarek@ring0.de> Date: Sat, 9 Dec 2023 22:48:55 +0100 Subject: [PATCH] Init add netmon2 django project Signed-off-by: Jan-Tarek Butt <tarek@ring0.de> --- .gitignore | 49 ++++++ README.md | 7 + crawler/__init__.py | 0 crawler/admin.py | 6 + crawler/apps.py | 6 + crawler/migrations/0001_initial.py | 36 ++++ crawler/migrations/0002_node_entry_date.py | 20 +++ crawler/migrations/0003_ownsettings.py | 20 +++ crawler/migrations/0004_delete_ownsettings.py | 16 ++ crawler/migrations/0005_node_is_online.py | 18 ++ .../migrations/0006_alter_monitor_notify.py | 18 ++ crawler/migrations/__init__.py | 0 crawler/models.py | 24 +++ crawler/tasks.py | 62 +++++++ crawler/tests.py | 3 + crawler/views.py | 3 + manage.py | 22 +++ netmon2/__init__.py | 0 netmon2/asgi.py | 16 ++ netmon2/celery.py | 16 ++ netmon2/settings.py | 154 ++++++++++++++++++ netmon2/urls.py | 24 +++ netmon2/wsgi.py | 16 ++ netmon_core/__init__.py | 0 netmon_core/admin.py | 3 + netmon_core/apps.py | 6 + netmon_core/forms.py | 10 ++ netmon_core/migrations/__init__.py | 0 netmon_core/models.py | 3 + netmon_core/templates/index.html | 7 + .../protected/unmonitored_nodes.html | 17 ++ .../protected/user_monitored_nodes.html | 23 +++ .../templates/registration/register.html | 7 + netmon_core/tests.py | 3 + netmon_core/urls.py | 16 ++ netmon_core/views.py | 89 ++++++++++ 36 files changed, 720 insertions(+) create mode 100644 .gitignore create mode 100644 crawler/__init__.py create mode 100644 crawler/admin.py create mode 100644 crawler/apps.py create mode 100644 crawler/migrations/0001_initial.py create mode 100644 crawler/migrations/0002_node_entry_date.py create mode 100644 crawler/migrations/0003_ownsettings.py create mode 100644 crawler/migrations/0004_delete_ownsettings.py create mode 100644 crawler/migrations/0005_node_is_online.py create mode 100644 crawler/migrations/0006_alter_monitor_notify.py create mode 100644 crawler/migrations/__init__.py create mode 100644 crawler/models.py create mode 100644 crawler/tasks.py create mode 100644 crawler/tests.py create mode 100644 crawler/views.py create mode 100755 manage.py create mode 100644 netmon2/__init__.py create mode 100644 netmon2/asgi.py create mode 100644 netmon2/celery.py create mode 100644 netmon2/settings.py create mode 100644 netmon2/urls.py create mode 100644 netmon2/wsgi.py create mode 100644 netmon_core/__init__.py create mode 100644 netmon_core/admin.py create mode 100644 netmon_core/apps.py create mode 100644 netmon_core/forms.py create mode 100644 netmon_core/migrations/__init__.py create mode 100644 netmon_core/models.py create mode 100644 netmon_core/templates/index.html create mode 100644 netmon_core/templates/protected/unmonitored_nodes.html create mode 100644 netmon_core/templates/protected/user_monitored_nodes.html create mode 100644 netmon_core/templates/registration/register.html create mode 100644 netmon_core/tests.py create mode 100644 netmon_core/urls.py create mode 100644 netmon_core/views.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b2bdbac --- /dev/null +++ b/.gitignore @@ -0,0 +1,49 @@ +# .gitignore for a Django project + +# Ignore Celery-related files +celerybeat-schedule +celerybeat.pid +celeryd.pid +celery_*.pickle + +# Ignore Celery worker state file +worker_state + +# Ignore Celery task result files +celery-results/ + +# Ignore Python bytecode files +__pycache__/ +*.pyc + +# Ignore database files +*.sqlite3 + +# Ignore system-specific files +*.pyo +*.pyd +*.db + +# Ignore environment configuration files +.env + +# Ignore virtual environment folders +venv/ +env/ +*.env/ + +# Ignore local development settings +local_settings.py + +# Ignore logs and data +log/ +*.log +*.sql + +# Ignore backup files +*.bak +*.swp +*~ + +# Ignore local development files +local/ diff --git a/README.md b/README.md index 392c90e..0805048 100644 --- a/README.md +++ b/README.md @@ -91,3 +91,10 @@ For open source projects, say how it is licensed. ## Project status If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. + +## Setup instructions + +celery -A netmon2.celery beat -l info +celery -A netmon2.celery worker -l info + +python manage.py runserver diff --git a/crawler/__init__.py b/crawler/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/crawler/admin.py b/crawler/admin.py new file mode 100644 index 0000000..86f8c99 --- /dev/null +++ b/crawler/admin.py @@ -0,0 +1,6 @@ +from django.contrib import admin + +from .models import Monitor, Node + +admin.site.register(Monitor) +admin.site.register(Node) diff --git a/crawler/apps.py b/crawler/apps.py new file mode 100644 index 0000000..88478dd --- /dev/null +++ b/crawler/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CrawlerConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'crawler' diff --git a/crawler/migrations/0001_initial.py b/crawler/migrations/0001_initial.py new file mode 100644 index 0000000..8127f13 --- /dev/null +++ b/crawler/migrations/0001_initial.py @@ -0,0 +1,36 @@ +# Generated by Django 4.2.7 on 2023-12-07 14:36 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Node', + fields=[ + ('node_id', models.CharField(max_length=12, primary_key=True, serialize=False)), + ('node_name', models.CharField(max_length=64)), + ], + ), + migrations.CreateModel( + name='Monitor', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('notify', models.BooleanField(default=True)), + ('node_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='crawler.node')), + ('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'unique_together': {('user_id', 'node_id')}, + }, + ), + ] diff --git a/crawler/migrations/0002_node_entry_date.py b/crawler/migrations/0002_node_entry_date.py new file mode 100644 index 0000000..cd052f6 --- /dev/null +++ b/crawler/migrations/0002_node_entry_date.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.7 on 2023-12-08 06:15 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('crawler', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='node', + name='entry_date', + field=models.DateField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + ] diff --git a/crawler/migrations/0003_ownsettings.py b/crawler/migrations/0003_ownsettings.py new file mode 100644 index 0000000..7351ada --- /dev/null +++ b/crawler/migrations/0003_ownsettings.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.7 on 2023-12-08 08:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('crawler', '0002_node_entry_date'), + ] + + operations = [ + migrations.CreateModel( + name='OwnSettings', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('TBL_NODE_DELETE_AFTER_AMOUNT_OF_DAYS', models.PositiveIntegerField(default=0)), + ], + ), + ] diff --git a/crawler/migrations/0004_delete_ownsettings.py b/crawler/migrations/0004_delete_ownsettings.py new file mode 100644 index 0000000..1d4f329 --- /dev/null +++ b/crawler/migrations/0004_delete_ownsettings.py @@ -0,0 +1,16 @@ +# Generated by Django 4.2.7 on 2023-12-08 13:07 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('crawler', '0003_ownsettings'), + ] + + operations = [ + migrations.DeleteModel( + name='OwnSettings', + ), + ] diff --git a/crawler/migrations/0005_node_is_online.py b/crawler/migrations/0005_node_is_online.py new file mode 100644 index 0000000..f175764 --- /dev/null +++ b/crawler/migrations/0005_node_is_online.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2023-12-09 19:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('crawler', '0004_delete_ownsettings'), + ] + + operations = [ + migrations.AddField( + model_name='node', + name='is_online', + field=models.BooleanField(default=True), + ), + ] diff --git a/crawler/migrations/0006_alter_monitor_notify.py b/crawler/migrations/0006_alter_monitor_notify.py new file mode 100644 index 0000000..47dac1f --- /dev/null +++ b/crawler/migrations/0006_alter_monitor_notify.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2023-12-09 19:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('crawler', '0005_node_is_online'), + ] + + operations = [ + migrations.AlterField( + model_name='monitor', + name='notify', + field=models.BooleanField(), + ), + ] diff --git a/crawler/migrations/__init__.py b/crawler/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/crawler/models.py b/crawler/models.py new file mode 100644 index 0000000..35b1823 --- /dev/null +++ b/crawler/models.py @@ -0,0 +1,24 @@ +from django.db import models +from django.contrib.auth.models import User + +class Node(models.Model): + # id is a 12 char long mac addr + node_id = models.CharField(max_length=12, primary_key=True) + # hostname of the node + node_name = models.CharField(max_length=64) + entry_date = models.DateField(auto_now_add=True) + is_online = models.BooleanField(default=True) + + def __str__(self): + return f"{self.node_id} - {self.node_name} - {self.entry_date} - {self.is_online}" + +class Monitor(models.Model): + user_id = models.ForeignKey(User, on_delete=models.CASCADE) + node_id = models.ForeignKey(Node, on_delete=models.CASCADE) + notify = models.BooleanField() + + def __str__(self): + return f"{self.user_id.username} - {self.node_id.node_id} - {self.notify}" + + class Meta: + unique_together = ['user_id', 'node_id'] diff --git a/crawler/tasks.py b/crawler/tasks.py new file mode 100644 index 0000000..b3a0345 --- /dev/null +++ b/crawler/tasks.py @@ -0,0 +1,62 @@ +# tasks.py +from celery import shared_task +from django.conf import settings +from crawler.models import Node, Monitor +from datetime import timedelta +from django.utils import timezone +import requests +import logging + +logger = logging.getLogger(__name__) + +# This task is responsible for cleaning up expired entries in the Node model based on the entry_date. +@shared_task +def cleanup_expired_entries(): + expired_days = settings.EXPIRED_DAYS_FOR_CLEANUP + current_date = timezone.now().date() + cutoff_date = current_date + timedelta(days=-expired_days) + + # Filter entries with entry_date older than the cutoff_date + nodes_to_delete = Node.objects.filter(entry_date__lt=cutoff_date) + + # Exclude nodes that are referenced in the Monitor table + nodes_to_delete = nodes_to_delete.exclude(node_id__in=Monitor.objects.values('node_id')) + + try: + # Delete the filtered entries + nodes_to_delete.delete() + except Exception as e: + logger.error(f'Error cleaning up expired entries: {e}') + + + +#This task fetches JSON data from a given URL and updates the Node model accordingly. +@shared_task +def update_node_table_task(): + json_url = settings.JSON_DATA_URL + + try: + response = requests.get(json_url) + response.raise_for_status() + + json_data = response.json() + + for entry in json_data.get("nodes"): + node_id = entry.get('node_id') + node_name = entry.get('hostname') + is_online = entry.get('is_online') + + # Update or create the node + node, created = Node.objects.update_or_create( + node_id=node_id, + defaults={ + 'node_name': node_name, + 'entry_date': timezone.now().date().strftime('%Y-%m-%d'), + 'is_online': is_online + } + ) + + logger.info('Successfully updated the Node table') + + except requests.RequestException as e: + logger.error(f'Error fetching JSON data: {e}') diff --git a/crawler/tests.py b/crawler/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/crawler/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/crawler/views.py b/crawler/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/crawler/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..0a66c52 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'netmon2.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/netmon2/__init__.py b/netmon2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/netmon2/asgi.py b/netmon2/asgi.py new file mode 100644 index 0000000..188f1ab --- /dev/null +++ b/netmon2/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for netmon2 project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'netmon2.settings') + +application = get_asgi_application() diff --git a/netmon2/celery.py b/netmon2/celery.py new file mode 100644 index 0000000..13a1e8d --- /dev/null +++ b/netmon2/celery.py @@ -0,0 +1,16 @@ +# celery.py +from __future__ import absolute_import, unicode_literals +import os +from celery import Celery + +# set the default Django settings module for the 'celery' program. +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'netmon2.settings') + +# create a Celery instance and configure it using the settings from Django +app = Celery('netmon2') + +# Load task modules from all registered Django app configs. +app.config_from_object('django.conf:settings', namespace='CELERY') + +# Auto-discover tasks in all installed apps +app.autodiscover_tasks() diff --git a/netmon2/settings.py b/netmon2/settings.py new file mode 100644 index 0000000..47930d9 --- /dev/null +++ b/netmon2/settings.py @@ -0,0 +1,154 @@ +""" +Django settings for netmon2 project. + +Generated by 'django-admin startproject' using Django 4.2.7. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.2/ref/settings/ +""" +import os +from pathlib import Path +from celery.schedules import crontab + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '<YOUR_SECRED_KEY>' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = False + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + "crawler.apps.CrawlerConfig", + "django_celery_results", + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'netmon2.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'netmon_core', 'templates')], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'netmon2.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'de' + +TIME_ZONE = 'Europe/Berlin' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +CELERY_BROKER_URL = 'redis://localhost:6379/0' # Use your broker URL +CELERY_RESULT_BACKEND = 'redis://localhost:6379/0' # Use your result backend URL +CELERY_ACCEPT_CONTENT = ['json'] +CELERY_TASK_SERIALIZER = 'json' +CELERY_RESULT_SERIALIZER = 'json' +CELERY_TIMEZONE = 'Europe/Berlin' + +CELERY_BEAT_SCHEDULE = { + 'update-node-table': { + 'task': 'crawler.tasks.update_node_table_task', + 'schedule': crontab(minute="*/5"), + }, + 'cleanup_expired_entries': { + 'task': 'crawler.tasks.cleanup_expired_entries', + 'schedule': crontab(hour="*/24"), + } +} + +EXPIRED_DAYS_FOR_CLEANUP = 5 # Adjust this based on your needs +JSON_DATA_URL = "<YOUR_JSON_URL>" + +AUTHENTICATION_BACKENDS = [ + 'django.contrib.auth.backends.ModelBackend', +] + +LOGIN_REDIRECT_URL = 'unmonitored_nodes' +LOGIN_URL = 'login' # Adjust to match your login URL pattern name diff --git a/netmon2/urls.py b/netmon2/urls.py new file mode 100644 index 0000000..26bf1b3 --- /dev/null +++ b/netmon2/urls.py @@ -0,0 +1,24 @@ +""" +URL configuration for netmon2 project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/4.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import include, path + +urlpatterns = [ + path('admin/', admin.site.urls), + path('', include('netmon_core.urls')), + # Add other URL patterns as needed +] diff --git a/netmon2/wsgi.py b/netmon2/wsgi.py new file mode 100644 index 0000000..62b9def --- /dev/null +++ b/netmon2/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for netmon2 project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'netmon2.settings') + +application = get_wsgi_application() diff --git a/netmon_core/__init__.py b/netmon_core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/netmon_core/admin.py b/netmon_core/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/netmon_core/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/netmon_core/apps.py b/netmon_core/apps.py new file mode 100644 index 0000000..143e765 --- /dev/null +++ b/netmon_core/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class NetmonCoreConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'netmon_core' diff --git a/netmon_core/forms.py b/netmon_core/forms.py new file mode 100644 index 0000000..60efcf0 --- /dev/null +++ b/netmon_core/forms.py @@ -0,0 +1,10 @@ +# forms.py +from django import forms +from django.contrib.auth.forms import UserCreationForm +from django.contrib.auth.models import User + +class CustomUserCreationForm(UserCreationForm): + # Add any additional fields if needed + class Meta: + model = User + fields = ('username', 'email', 'password1', 'password2') diff --git a/netmon_core/migrations/__init__.py b/netmon_core/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/netmon_core/models.py b/netmon_core/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/netmon_core/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/netmon_core/templates/index.html b/netmon_core/templates/index.html new file mode 100644 index 0000000..94f9813 --- /dev/null +++ b/netmon_core/templates/index.html @@ -0,0 +1,7 @@ +<!-- registration/login.html --> +<form method="post" action="{% url 'login' %}"> + {% csrf_token %} + {{ form.as_p }} + <button type="submit">Login</button> +</form> +<a href="{% url 'register' %}">Register</a> diff --git a/netmon_core/templates/protected/unmonitored_nodes.html b/netmon_core/templates/protected/unmonitored_nodes.html new file mode 100644 index 0000000..0842841 --- /dev/null +++ b/netmon_core/templates/protected/unmonitored_nodes.html @@ -0,0 +1,17 @@ +<!-- unmonitored_nodes.html --> + +<h2>Unmonitored Nodes</h2> +<a href="{% url 'user_monitored_nodes' %}">Monitored</a> +<a href="{% url 'user_logout' %}">Logout</a> + +<ul> + {% for node in nodes %} + <li> + {{ node.node_id }} - {{ node.node_name }} - {{ node.entry_date }} + <form method="post" action="{% url 'add_to_monitored' node.node_id %}"> + {% csrf_token %} + <button type="submit">Add to Monitored</button> + </form> + </li> + {% endfor %} +</ul> diff --git a/netmon_core/templates/protected/user_monitored_nodes.html b/netmon_core/templates/protected/user_monitored_nodes.html new file mode 100644 index 0000000..cd6271e --- /dev/null +++ b/netmon_core/templates/protected/user_monitored_nodes.html @@ -0,0 +1,23 @@ +<!-- user_monitored_nodes.html --> + +<h2>Nodes Monitored by {{ request.user.username }}</h2> + +<a href="{% url 'unmonitored_nodes' %}">Unmonitored</a> +<a href="{% url 'user_logout' %}">Logout</a> +<ul> + {% for node in monitored_nodes %} + <li> + {{ node.node_id.node_id }} - {{ node.node_id.node_name }} - {{ node.node_id.entry_date }} - {{ node.node_id.is_online }} + + <form method="post" action="{% url 'toggle_notify' node.id %}" class="notify-form"> + {% csrf_token %} + <input type="checkbox" name="notify" {% if node.notify %}checked{% endif %} onclick="this.form.submit()"> + </form> + + <form method="post" action="{% url 'delete_monitored_node' node.id %}" class="delete-form"> + {% csrf_token %} + <button type="submit">Delete</button> + </form> + </li> + {% endfor %} +</ul> diff --git a/netmon_core/templates/registration/register.html b/netmon_core/templates/registration/register.html new file mode 100644 index 0000000..f18cfb5 --- /dev/null +++ b/netmon_core/templates/registration/register.html @@ -0,0 +1,7 @@ +<!-- registration/register.html --> +<form method="post" action="{% url 'register' %}"> + {% csrf_token %} + {{ form.as_p }} + <button type="submit">Register</button> +</form> + diff --git a/netmon_core/tests.py b/netmon_core/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/netmon_core/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/netmon_core/urls.py b/netmon_core/urls.py new file mode 100644 index 0000000..9e7977f --- /dev/null +++ b/netmon_core/urls.py @@ -0,0 +1,16 @@ +# urls.py +from django.urls import path +from .views import register, CustomLoginView, unmonitored_nodes, user_monitored_nodes, delete_monitored_node, add_to_monitored, toggle_notify, user_logout + +urlpatterns = [ + path('register/', register, name='register'), + path('', CustomLoginView.as_view(), name='login'), + path('logout/', user_logout, name='user_logout'), + path('protected/unmonitored/', unmonitored_nodes, name='unmonitored_nodes'), + path('protected/monitored/', user_monitored_nodes, name='user_monitored_nodes'), + path('protected/delete_monitored_node/<int:monitor_id>/', delete_monitored_node, name='delete_monitored_node'), + path('protected/add_to_monitored/<str:node_id>/', add_to_monitored, name='add_to_monitored'), + path('protected/toggle_notify/<int:monitor_id>/', toggle_notify, name='toggle_notify'), + # Add other URL patterns as needed +] + diff --git a/netmon_core/views.py b/netmon_core/views.py new file mode 100644 index 0000000..f78a421 --- /dev/null +++ b/netmon_core/views.py @@ -0,0 +1,89 @@ +from django.shortcuts import render, redirect, get_object_or_404 +from django.contrib.auth import login, logout +from django.contrib.auth.views import LoginView +from django.contrib.auth.decorators import login_required +from crawler.models import Node, Monitor +from .forms import CustomUserCreationForm + + +def register(request): + if request.method == 'POST': + form = CustomUserCreationForm(request.POST) + if form.is_valid(): + user = form.save() + login(request, user) # Log the user in after registration + return redirect('login') # Redirect to the home page or any other page + else: + form = CustomUserCreationForm() + + return render(request, 'registration/register.html', {'form': form}) + +class CustomLoginView(LoginView): + template_name = 'index.html' # Specify the login template + +def user_logout(request): + # Logout the user + logout(request) + # Redirect to the home page or any other page after logout + return redirect('login') # Replace 'home' with the actual name or URL of your home page + + +@login_required +def unmonitored_nodes(request): + # Query all Node entries that do not have corresponding entries in Monitor + nodes = Node.objects.exclude(monitor__isnull=False) + + # Pass the queried data to the template + context = {'nodes': nodes} + + # Render the template with the context + return render(request, 'protected/unmonitored_nodes.html', context) + +@login_required +def user_monitored_nodes(request): + # Query all Node entries monitored by the current user + monitored_nodes = Monitor.objects.filter(user_id=request.user) + + # Pass the queried data to the template + context = {'monitored_nodes': monitored_nodes} + + # Render the template with the context + return render(request, 'protected/user_monitored_nodes.html', context) + +@login_required +def delete_monitored_node(request, monitor_id): + # Get the monitoring entry + monitor_entry = get_object_or_404(Monitor, id=monitor_id) + + # Ensure that the user making the request is the owner of the monitoring entry + if request.user == monitor_entry.user_id: + # Delete the monitoring entry + monitor_entry.delete() + + # Redirect back to the user_monitored_nodes view + return redirect('user_monitored_nodes') + +@login_required +def add_to_monitored(request, node_id): + # Get the Node entry + node = get_object_or_404(Node, node_id=node_id) + + # Check if the monitoring entry already exists + if not Monitor.objects.filter(user_id=request.user, node_id=node).exists(): + # Create a new monitoring entry + Monitor.objects.create(user_id=request.user, node_id=node) + + # Redirect back to the unmonitored_nodes view + return redirect('unmonitored_nodes') + +@login_required +def toggle_notify(request, monitor_id): + # Get the monitoring entry + monitor_entry = get_object_or_404(Monitor, id=monitor_id) + + # Toggle the notify field + monitor_entry.notify = not monitor_entry.notify + monitor_entry.save() + + # Redirect back to the user_monitored_nodes view + return redirect('user_monitored_nodes') -- GitLab