Skip to content

Commit

Permalink
Aktualisiere IP-Listenansicht und Leayout Ändere IP-Listenansicht, um…
Browse files Browse the repository at this point in the history
… eine scrollbare Tabelle mit sticky Header zu ermöglichen. Passe die Höhe der Tabelle an die Bildschirmgröße an. Aktualisiere das Layout, um die Lücken zwischen den Menüpunkten zu entfernen.
  • Loading branch information
LeonKohli committed Feb 8, 2024
1 parent 452c815 commit ac8a291
Show file tree
Hide file tree
Showing 10 changed files with 232 additions and 34 deletions.
Binary file added database/ip_atlas.db
Binary file not shown.
31 changes: 24 additions & 7 deletions ip-atlas/app.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
from flask import Flask
import secrets
from routes import atlas, settings

import os
from database import db

atlasapp = Flask(__name__, static_folder="static", template_folder="templates")
atlasapp.secret_key = secrets.token_hex(16)

# ? Blueprints
atlasapp.register_blueprint(atlas.bp_atlas)
atlasapp.register_blueprint(settings.bp_settings)
# Configure the database URI
database_dir = os.path.join(os.getcwd(), "database")
if not os.path.exists(database_dir):
os.makedirs(database_dir)
atlasapp.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + os.path.join(
database_dir, "ip_atlas.db"
)
atlasapp.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False


# Register the blueprints
from routes.atlas import bp_atlas
from routes.settings import bp_settings

atlasapp.register_blueprint(bp_atlas)
atlasapp.register_blueprint(bp_settings)

# Initialize SQLAlchemy with the Flask app
db.init_app(atlasapp)

if __name__ == "__main__":
with atlasapp.app_context():
from models import *

db.create_all()
atlasapp.run(debug=True, host="0.0.0.0", port=5000)
3 changes: 3 additions & 0 deletions ip-atlas/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
103 changes: 103 additions & 0 deletions ip-atlas/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
from database import db
from sqlalchemy.orm import relationship
from sqlalchemy.orm import validates
import ipaddress
from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey
from datetime import datetime


class Host(db.Model):
__tablename__ = "hosts"
id = Column(Integer, primary_key=True, autoincrement=True)
hostname = Column(String, unique=True, nullable=False, index=True)
ipv4 = Column(String, nullable=False, index=True)
ipv6 = Column(String, index=True)
cidr = Column(Integer)
deleted = Column(Boolean, default=False)
ports = relationship("Port", back_populates="host")
tags = relationship("HostTag", back_populates="host")

@validates("ipv4", "ipv6")
def validate_ip(self, key, address):
if address:
try:
ip_obj = ipaddress.ip_address(address)
if (key == "ipv4" and ip_obj.version != 4) or (
key == "ipv6" and ip_obj.version != 6
):
raise ValueError(f"Invalid {key} address: {address}")
return str(ip_obj)
except ValueError:
raise ValueError(f"Invalid {key} address: {address}")
return address


class Tag(db.Model):
__tablename__ = "tags"
id = Column(Integer, primary_key=True, autoincrement=True)
tag_name = Column(String, unique=True, nullable=False, index=True)
deleted = Column(Boolean, default=False)
hosts = relationship("HostTag", back_populates="tag")


class HostTag(db.Model):
__tablename__ = "host_tags"
host_id = Column(Integer, ForeignKey("hosts.id"), primary_key=True)
tag_id = Column(Integer, ForeignKey("tags.id"), primary_key=True)
host = relationship("Host", back_populates="tags")
tag = relationship("Tag", back_populates="hosts")


class Port(db.Model):
__tablename__ = "ports"
id = Column(Integer, primary_key=True, autoincrement=True)
host_id = Column(Integer, ForeignKey("hosts.id"))
port_number = Column(Integer, nullable=False)
deleted = Column(Boolean, default=False)
host = relationship("Host", back_populates="ports")


class AuditLog(db.Model):
__tablename__ = "audit_logs"
id = Column(Integer, primary_key=True, autoincrement=True)
action_type = Column(String, nullable=False)
table_name = Column(String, nullable=False)
record_id = Column(Integer, nullable=False)
timestamp = Column(DateTime, default=datetime.utcnow)
user = Column(String, nullable=False)


class Statistics(db.Model):
__tablename__ = "statistics"
id = Column(Integer, primary_key=True, autoincrement=True)
stat_key = Column(String, nullable=False, index=True)
stat_value = Column(Integer, nullable=False)
last_updated = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)


class DiscoveredDevice(db.Model):
__tablename__ = "discovered_devices"
id = Column(Integer, primary_key=True, autoincrement=True)
mac_address = Column(String, nullable=False, index=True)
ipv4 = Column(String, nullable=False, index=True)
ipv6 = Column(String, index=True)
hostname = Column(String, index=True)
first_seen = Column(DateTime, default=datetime.utcnow)
last_seen = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
deleted = Column(Boolean, default=False)
vendor = Column(String)
ignore = Column(Boolean, default=False)

@validates("ipv4", "ipv6")
def validate_ip(self, key, address):
if address:
try:
ip_obj = ipaddress.ip_address(address)
if (key == "ipv4" and ip_obj.version != 4) or (
key == "ipv6" and ip_obj.version != 6
):
raise ValueError(f"Invalid {key} address: {address}")
return str(ip_obj)
except ValueError:
raise ValueError(f"Invalid {key} address: {address}")
return address
14 changes: 12 additions & 2 deletions ip-atlas/routes/atlas.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from jinja2 import TemplateNotFound
from helper import *
from filter import *
from models import Host, Port, Tag

bp_atlas = Blueprint("atlas", __name__)

Expand All @@ -15,8 +16,17 @@ def index():

@bp_atlas.route("/ip/list")
def list():
createJson()
data = loadJson()
hosts = Host.query.all()
data = {"hosts": []}
for host in hosts:
host_data = {
"id": host.id,
"name": host.hostname,
"ip": host.ipv4, # Assuming ipv4 is the primary IP to display
"ports": [port.port_number for port in host.ports],
"tags": [host_tag.tag.tag_name for host_tag in host.tags], # Adjusted line
}
data["hosts"].append(host_data)
return render_template("ip/list.html", data=data)


Expand Down
64 changes: 45 additions & 19 deletions ip-atlas/templates/ip/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -103,41 +103,55 @@ <h1 class="text-lg font-semibold md:text-2xl">IP Adressen</h1>
}
});
});
</script>

<div class="flex gap-2">
</div>
</script>
</div>
{% if data and data.hosts %}
<style>
.scrollable-table-container {
max-height: 90vh;
overflow: auto;
}

.sticky-table-header th {
position: sticky;
top: 0;
background-color: #1f2937;
z-index: 1;
}

.scrollable-table-container::-webkit-scrollbar {
display: none;
}
</style>

<div class="border rounded-lg shadow-sm">
<div class="relative w-full overflow-auto">
<table class="w-full text-sm caption-bottom">
<thead>
<div class="relative w-full scrollable-table-container">
<table class="w-full text-sm table-fixed caption-bottom">
<thead class="sticky-table-header">
<tr class="border-b">
<th class="hidden h-12 px-4 font-medium text-left align-middle md:table-cell">
Name
</th>
<th class="h-12 px-4 font-medium text-left align-middle ">
<th class="h-12 px-4 font-medium text-left align-middle">
IP Adresse
</th>
<th class="h-12 px-4 font-medium text-left align-middle ">
<th class="h-12 px-4 font-medium text-left align-middle">
Ports in der FBox
</th>
<th class="h-12 px-4 font-medium text-left align-middle ">
<th class="h-12 px-4 font-medium text-left align-middle">
Tags
</th>
<th class="h-12 px-4 text-left align-middle font-medium max-w-[150px]">
<th class="h-12 px-4 text-left align-middle font-medium max-w-[150px]">
Status
</th>
<th class="h-12 px-4 font-medium text-center align-middle ">
<th class="h-12 px-4 font-medium text-center align-middle">
Aktionen
</th>
</tr>
</thead>
<tbody>
{% for host in data.hosts %}
<tr data-id="{{ host.id }}"
class="transition duration-150 ease-in-out border-b hover:bg-gray-700 hover:bg-opacity-25">
<tr data-id="{{ host.id }}" class="transition duration-150 ease-in-out border-b hover:bg-gray-700 hover:bg-opacity-25">
<td class="hidden p-4 align-middle edit-field md:table-cell">{{ host.name }}</td>
<td class="p-4 font-medium align-middle edit-field">{{ host.ip }}</td>
<td class="p-4 align-middle edit-field">{{ host.ports|join(", ") }}</td>
Expand All @@ -150,11 +164,6 @@ <h1 class="text-lg font-semibold md:text-2xl">IP Adressen</h1>
</td>
<td class="p-4 align-middle ip-ping-status" data-ip="{{ host.ip }}">
<i class="text-green-500 material-symbols-outlined" style="font-size:24px;">check_circle</i>
<!-- {% if host.pingable %}
<i class="text-green-500 material-symbols-outlined" style="font-size:24px;">check_circle</i>
{% else %}
<i class="text-red-500 material-symbols-outlined" style="font-size:24px;">cancel</i>
{% endif %} -->
</td>
<td class="p-4 text-center align-middle">
<button
Expand All @@ -175,6 +184,23 @@ <h1 class="text-lg font-semibold md:text-2xl">IP Adressen</h1>
</div>
</div>

<script>
function adjustTableHeight() {
const tableContainer = document.querySelector('.scrollable-table-container');
if (!tableContainer) return;

const viewportHeight = window.innerHeight;
const offsetTop = tableContainer.getBoundingClientRect().top;
const margin = 20; // Adjust this margin as needed

const desiredHeight = viewportHeight - offsetTop - margin;
tableContainer.style.maxHeight = `${desiredHeight}px`;
}

window.addEventListener('resize', adjustTableHeight);
window.addEventListener('DOMContentLoaded', adjustTableHeight);
</script>

<style>
.edit-field {
max-width: 120px !important;
Expand Down
4 changes: 2 additions & 2 deletions ip-atlas/templates/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
</button>
</div>
<div class="flex-1 py-2 overflow-auto">
<nav class="grid items-start px-4 text-sm font-medium">
<nav class="grid items-start px-4 text-sm font-medium gap-y-2">
{% set current_page = request.path %}
<a class="flex items-center gap-2 px-3 py-2 transition-all rounded-lg hover:text-gray-100 {% if current_page == url_for('atlas.index') %}bg-gray-700{% endif %}"
href="{{ url_for('atlas.index') }}">
Expand All @@ -81,7 +81,7 @@
</a>
</nav>
</div>
<div class="py-2 px-3">
<div class="mt-auto">
<a class="flex items-center gap-2 px-3 py-2 transition-all rounded-lg hover:text-gray-100 {% if current_page == url_for('settings.config') %}bg-gray-700{% endif %}"
href="{{ url_for('settings.config') }}">
<span class="text-base leading-none material-symbols-outlined">settings</span>
Expand Down
41 changes: 37 additions & 4 deletions ip-atlas/testdatenfiller.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,50 @@
from helper import writeJson
from faker import Faker
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import db, Host, Tag, Port, HostTag
import random
from app import atlasapp

# Assuming your database URI is stored in a variable or directly provided
DATABASE_URI = atlasapp.config["SQLALCHEMY_DATABASE_URI"]
engine = create_engine(DATABASE_URI)
Session = sessionmaker(bind=engine)

fake = Faker()


def generate_test_data(num_hosts=50):
session = Session()
for i in range(1, num_hosts + 1):
hostname = f"Host{i}"
ipv4 = fake.ipv4_private(network=False, address_class=None)
tags = [fake.word(), fake.word(), "test"]
ipv6 = fake.ipv6(network=False)
ports = [fake.random_int(min=1, max=65535) for _ in range(2)]
writeJson(hostname, ipv4, tags, ipv6, ports)
ports_numbers = [fake.random_int(min=1, max=65535) for _ in range(2)]

# Create Host instance
host = Host(hostname=hostname, ipv4=ipv4, ipv6=ipv6)
session.add(host)
session.commit() # Commit to assign an ID to the host

# Create Port instances
for port_number in ports_numbers:
port = Port(host_id=host.id, port_number=port_number)
session.add(port)

# Create and associate Tags
tags = [fake.word(), fake.word(), "test"]
for tag_name in tags:
tag = session.query(Tag).filter_by(tag_name=tag_name).first()
if not tag:
tag = Tag(tag_name=tag_name)
session.add(tag)
session.commit() # Commit to assign an ID to the tag

# Create association between host and tag
host_tag = HostTag(host_id=host.id, tag_id=tag.id)
session.add(host_tag)

session.commit()


generate_test_data()
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified requirements.txt
Binary file not shown.

0 comments on commit ac8a291

Please sign in to comment.