diff --git a/config/__pycache__/__init__.cpython-311.pyc b/config/__pycache__/__init__.cpython-311.pyc index 3d6501c..1be7e50 100644 Binary files a/config/__pycache__/__init__.cpython-311.pyc and b/config/__pycache__/__init__.cpython-311.pyc differ diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index dadfaa7..c0aca8a 100644 Binary files a/config/__pycache__/settings.cpython-311.pyc and b/config/__pycache__/settings.cpython-311.pyc differ diff --git a/config/__pycache__/urls.cpython-311.pyc b/config/__pycache__/urls.cpython-311.pyc index 139db10..81ed005 100644 Binary files a/config/__pycache__/urls.cpython-311.pyc and b/config/__pycache__/urls.cpython-311.pyc differ diff --git a/config/__pycache__/wsgi.cpython-311.pyc b/config/__pycache__/wsgi.cpython-311.pyc index 79ce690..0628b01 100644 Binary files a/config/__pycache__/wsgi.cpython-311.pyc and b/config/__pycache__/wsgi.cpython-311.pyc differ diff --git a/core/__pycache__/__init__.cpython-311.pyc b/core/__pycache__/__init__.cpython-311.pyc index 3b7774e..9fe0af5 100644 Binary files a/core/__pycache__/__init__.cpython-311.pyc and b/core/__pycache__/__init__.cpython-311.pyc differ diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index 5e41572..65fbd5a 100644 Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ diff --git a/core/__pycache__/apps.cpython-311.pyc b/core/__pycache__/apps.cpython-311.pyc index 6435d92..1b60d9a 100644 Binary files a/core/__pycache__/apps.cpython-311.pyc and b/core/__pycache__/apps.cpython-311.pyc differ diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc index f6e5c4e..7e82c9a 100644 Binary files a/core/__pycache__/forms.cpython-311.pyc and b/core/__pycache__/forms.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 5b41fe1..9fa1d46 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 4e4f113..732b20f 100644 Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 9d0ddd8..aa5727c 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/admin.py b/core/admin.py index 639ff3a..6fe1e89 100644 --- a/core/admin.py +++ b/core/admin.py @@ -1,8 +1,13 @@ from django.contrib import admin -from .models import Ticket +from .models import Application, Vulnerability -@admin.register(Ticket) -class TicketAdmin(admin.ModelAdmin): - list_display = ('subject', 'status', 'priority', 'requester_email', 'created_at') - list_filter = ('status', 'priority') - search_fields = ('subject', 'requester_email', 'description') +@admin.register(Application) +class ApplicationAdmin(admin.ModelAdmin): + list_display = ('name', 'version', 'vendor') + search_fields = ('name', 'vendor') + +@admin.register(Vulnerability) +class VulnerabilityAdmin(admin.ModelAdmin): + list_display = ('cve_id', 'application', 'severity', 'status', 'discovered_at') + list_filter = ('severity', 'status', 'application__name') + search_fields = ('cve_id', 'description') \ No newline at end of file diff --git a/core/forms.py b/core/forms.py index 7a6b83b..21e602d 100644 --- a/core/forms.py +++ b/core/forms.py @@ -1,7 +1,4 @@ from django import forms -from .models import Ticket -class TicketForm(forms.ModelForm): - class Meta: - model = Ticket - fields = ['subject', 'requester_email', 'priority', 'description'] +class UploadFileForm(forms.Form): + file = forms.FileField() \ No newline at end of file diff --git a/core/migrations/0002_application_vulnerability_delete_ticket.py b/core/migrations/0002_application_vulnerability_delete_ticket.py new file mode 100644 index 0000000..fce2355 --- /dev/null +++ b/core/migrations/0002_application_vulnerability_delete_ticket.py @@ -0,0 +1,39 @@ +# Generated by Django 5.2.7 on 2025-10-27 12:23 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Application', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('version', models.CharField(max_length=100)), + ('vendor', models.CharField(max_length=255)), + ], + ), + migrations.CreateModel( + name='Vulnerability', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('cve_id', models.CharField(max_length=50, unique=True)), + ('description', models.TextField()), + ('severity', models.CharField(choices=[('Critical', 'Critical'), ('High', 'High'), ('Medium', 'Medium'), ('Low', 'Low')], max_length=10)), + ('status', models.CharField(choices=[('New', 'New'), ('Acknowledged', 'Acknowledged'), ('In-Progress', 'In-Progress'), ('Resolved', 'Resolved')], default='New', max_length=20)), + ('discovered_at', models.DateTimeField(auto_now_add=True)), + ('last_updated', models.DateTimeField(auto_now=True)), + ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='vulnerabilities', to='core.application')), + ], + ), + migrations.DeleteModel( + name='Ticket', + ), + ] diff --git a/core/migrations/__pycache__/0001_initial.cpython-311.pyc b/core/migrations/__pycache__/0001_initial.cpython-311.pyc index 64d8a55..487e6cd 100644 Binary files a/core/migrations/__pycache__/0001_initial.cpython-311.pyc and b/core/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/core/migrations/__pycache__/0002_application_vulnerability_delete_ticket.cpython-311.pyc b/core/migrations/__pycache__/0002_application_vulnerability_delete_ticket.cpython-311.pyc new file mode 100644 index 0000000..bf22a95 Binary files /dev/null and b/core/migrations/__pycache__/0002_application_vulnerability_delete_ticket.cpython-311.pyc differ diff --git a/core/migrations/__pycache__/__init__.cpython-311.pyc b/core/migrations/__pycache__/__init__.cpython-311.pyc index 58b1c14..1b47153 100644 Binary files a/core/migrations/__pycache__/__init__.cpython-311.pyc and b/core/migrations/__pycache__/__init__.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 78b60d1..e1ff649 100644 --- a/core/models.py +++ b/core/models.py @@ -1,25 +1,34 @@ from django.db import models -class Ticket(models.Model): - STATUS_CHOICES = [ - ('open', 'Open'), - ('in_progress', 'In Progress'), - ('closed', 'Closed'), - ] - - PRIORITY_CHOICES = [ - ('low', 'Low'), - ('medium', 'Medium'), - ('high', 'High'), - ] - - subject = models.CharField(max_length=255) - status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='open') - priority = models.CharField(max_length=20, choices=PRIORITY_CHOICES, default='medium') - requester_email = models.EmailField() - description = models.TextField() - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) +class Application(models.Model): + name = models.CharField(max_length=255) + version = models.CharField(max_length=100) + vendor = models.CharField(max_length=255) def __str__(self): - return self.subject \ No newline at end of file + return f"{self.name} {self.version}" + +class Vulnerability(models.Model): + SEVERITY_CHOICES = [ + ('Critical', 'Critical'), + ('High', 'High'), + ('Medium', 'Medium'), + ('Low', 'Low'), + ] + STATUS_CHOICES = [ + ('New', 'New'), + ('Acknowledged', 'Acknowledged'), + ('In-Progress', 'In-Progress'), + ('Resolved', 'Resolved'), + ] + + cve_id = models.CharField(max_length=50, unique=True) + description = models.TextField() + severity = models.CharField(max_length=10, choices=SEVERITY_CHOICES) + application = models.ForeignKey(Application, on_delete=models.CASCADE, related_name='vulnerabilities') + status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='New') + discovered_at = models.DateTimeField(auto_now_add=True) + last_updated = models.DateTimeField(auto_now=True) + + def __str__(self): + return self.cve_id diff --git a/core/templates/base.html b/core/templates/base.html new file mode 100644 index 0000000..d486179 --- /dev/null +++ b/core/templates/base.html @@ -0,0 +1,69 @@ + + + + + + {% block title %}{{ project_name|default:"Vulnerability Scanner" }}{% endblock %} + + + {% load static %} + + + + +
+ + + + + +
+ + +
+ {% block content %}{% endblock %} +
+
+ +
+ + + + + + \ No newline at end of file diff --git a/core/templates/core/article_detail.html b/core/templates/core/article_detail.html new file mode 100644 index 0000000..8820990 --- /dev/null +++ b/core/templates/core/article_detail.html @@ -0,0 +1,14 @@ +{% extends 'base.html' %} + +{% block title %}{{ article.title }}{% endblock %} + +{% block content %} +
+

{{ article.title }}

+

Published on {{ article.created_at|date:"F d, Y" }}

+
+
+ {{ article.content|safe }} +
+
+{% endblock %} diff --git a/core/templates/core/index.html b/core/templates/core/index.html index f4e4991..6a0a55d 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,157 +1,107 @@ - - +{% extends 'base.html' %} +{% load static %} - - - - {{ project_name }} - {% if project_description %} - - - - {% endif %} - {% if project_image_url %} - - - {% endif %} - - - - - - - -
-
-

Analyzing your requirements and generating your website…

-
- Loading… +
+
+
+
+
+
+
{{ total_applications }}
+
Total Applications
+
+ +
+
-

Appwizzy AI is collecting your requirements and applying the first changes.

-

This page will refresh automatically as the plan is implemented.

-

- Runtime: Django {{ django_version }} · Python {{ python_version }} — - UTC {{ current_time|date:"Y-m-d H:i:s" }} -

- -
- +
+
+
+
+
+
{{ total_vulnerabilities }}
+
Total Vulnerabilities
+
+ +
+
+
+
+
+
+
+
+
+
{{ critical_vulnerabilities }}
+
Critical Vulnerabilities
+
+ +
+
+
+
+
+
+
+
+
+
{{ new_vulnerabilities }}
+
New Vulnerabilities
+
+ +
+
+
+
+ - \ No newline at end of file +
+
+
+ + Application Inventory +
+ Upload Inventory +
+
+
+ + + + + + + + + + + {% for app in applications %} + + + + + + + {% empty %} + + + + {% endfor %} + +
NameVersionVendorActions
{{ app.name }}{{ app.version }}{{ app.vendor }} + +
No applications found.
+
+
+
+ + +{% endblock %} diff --git a/core/templates/core/upload_inventory.html b/core/templates/core/upload_inventory.html new file mode 100644 index 0000000..3a0d6c1 --- /dev/null +++ b/core/templates/core/upload_inventory.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block content %} +
+

Upload Application Inventory

+

Upload a CSV file with the following columns: Name, Version, Vendor.

+
+ {% csrf_token %} + {{ form.as_p }} + +
+
+{% endblock %} diff --git a/core/urls.py b/core/urls.py index 6299e3d..048e0b9 100644 --- a/core/urls.py +++ b/core/urls.py @@ -1,7 +1,8 @@ from django.urls import path -from .views import home +from .views import dashboard, upload_inventory urlpatterns = [ - path("", home, name="home"), -] + path("", dashboard, name="dashboard"), + path("upload/", upload_inventory, name="upload_inventory"), +] \ No newline at end of file diff --git a/core/views.py b/core/views.py index c1a6d45..4525723 100644 --- a/core/views.py +++ b/core/views.py @@ -1,37 +1,48 @@ -import os -import platform +from django.shortcuts import render, redirect +from .models import Application, Vulnerability +from .forms import UploadFileForm +import csv +import io -from django import get_version as django_version -from django.shortcuts import render -from django.urls import reverse_lazy -from django.utils import timezone -from django.views.generic.edit import CreateView - -from .forms import TicketForm -from .models import Ticket - - -def home(request): - """Render the landing screen with loader and environment details.""" - host_name = request.get_host().lower() - agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic" - now = timezone.now() +def dashboard(request): + # Placeholder data + total_apps = Application.objects.count() + total_vulns = Vulnerability.objects.count() + critical_vulns = Vulnerability.objects.filter(severity='Critical').count() + new_vulns = Vulnerability.objects.filter(status='New').count() + applications = Application.objects.all() context = { - "project_name": "New Style", - "agent_brand": agent_brand, - "django_version": django_version(), - "python_version": platform.python_version(), - "current_time": now, - "host_name": host_name, - "project_description": os.getenv("PROJECT_DESCRIPTION", ""), - "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""), + 'total_applications': total_apps, + 'total_vulnerabilities': total_vulns, + 'critical_vulnerabilities': critical_vulns, + 'new_vulnerabilities': new_vulns, + 'applications': applications, + "project_name": "Vulnerability Scanner", } return render(request, "core/index.html", context) - -class TicketCreateView(CreateView): - model = Ticket - form_class = TicketForm - template_name = "core/ticket_create.html" - success_url = reverse_lazy("home") +def upload_inventory(request): + if request.method == 'POST': + form = UploadFileForm(request.POST, request.FILES) + if form.is_valid(): + try: + csv_file = request.FILES['file'] + decoded_file = io.TextIOWrapper(csv_file.file, encoding='utf-8', newline='', errors='ignore') + reader = csv.reader(decoded_file) + # Skip header row + next(reader) + for row in reader: + print(f"Processing row: {row}") + Application.objects.create( + name=row[0], + version=row[1], + vendor=row[2], + ) + return redirect('dashboard') + except Exception as e: + print(f"An error occurred: {e}") + form.add_error(None, f"An error occurred: {e}") + else: + form = UploadFileForm() + return render(request, 'core/upload_inventory.html', {'form': form}) diff --git a/static/css/custom.css b/static/css/custom.css new file mode 100644 index 0000000..b4e4285 --- /dev/null +++ b/static/css/custom.css @@ -0,0 +1,46 @@ +body { + overflow-x: hidden; +} + +#sidebar-wrapper { + min-height: 100vh; + margin-left: -15rem; + transition: margin .25s ease-out; +} + +#sidebar-wrapper .sidebar-heading { + padding: 0.875rem 1.25rem; + font-size: 1.2rem; + font-weight: bold; +} + +#sidebar-wrapper .list-group { + width: 15rem; +} + +#page-content-wrapper { + min-width: 100vw; +} + +#wrapper.toggled #sidebar-wrapper { + margin-left: 0; +} + +@media (min-width: 768px) { + #sidebar-wrapper { + margin-left: 0; + } + + #page-content-wrapper { + min-width: 0; + width: 100%; + } + + #wrapper.toggled #sidebar-wrapper { + margin-left: -15rem; + } +} + +.card-body .fs-1 { + opacity: 0.7; +}