mirror of
https://github.com/TakeusV1/flask_ipam.git
synced 2026-10-13 17:15:33 +02:00
V1.0
This commit is contained in:
1 parent
f11aa2d6c6
commit
85969350bc
13 files changed
+146
-29
No files matched your search
@@ -1,8 +1,5 @@
|
|||||||
from flask_login import LoginManager
|
from flask_login import LoginManager
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
from flask_turnstile import Turnstile
|
|
||||||
|
|
||||||
login_manager = LoginManager()
|
login_manager = LoginManager()
|
||||||
|
|
||||||
db = SQLAlchemy()
|
db = SQLAlchemy()
|
||||||
turnstile = Turnstile()
|
|
||||||
+8
-3
@@ -1,7 +1,12 @@
|
|||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import StringField, PasswordField
|
from wtforms import StringField, PasswordField, IntegerField
|
||||||
from wtforms.validators import DataRequired, Length
|
from wtforms.validators import DataRequired, Length, IPAddress, NumberRange
|
||||||
|
|
||||||
class LoginForm(FlaskForm):
|
class LoginForm(FlaskForm):
|
||||||
username = StringField(validators=[DataRequired(),Length(max=128)])
|
username = StringField(validators=[DataRequired(),Length(max=128)])
|
||||||
password = PasswordField(validators=[DataRequired(),Length(max=128)])
|
password = PasswordField(validators=[DataRequired(),Length(max=128)])
|
||||||
|
|
||||||
|
class NewPrefixForm(FlaskForm):
|
||||||
|
subnet = StringField(validators=[DataRequired(),IPAddress(ipv4=True),Length(max=128)])
|
||||||
|
prefix = IntegerField(validators=[DataRequired(),NumberRange(min=0,max=32)])
|
||||||
|
description = StringField(validators=[DataRequired(),Length(max=128)])
|
||||||
+8
-1
@@ -6,4 +6,11 @@ class User(UserMixin, db.Model):
|
|||||||
username = db.Column(db.String(16))
|
username = db.Column(db.String(16))
|
||||||
password = db.Column(db.String(32),unique=True)
|
password = db.Column(db.String(32),unique=True)
|
||||||
is_admin = db.Column(db.Boolean(),default=False)
|
is_admin = db.Column(db.Boolean(),default=False)
|
||||||
dat_last = db.Column(db.DateTime())
|
dat_last = db.Column(db.DateTime())
|
||||||
|
|
||||||
|
class Prefix(db.Model):
|
||||||
|
id = db.Column(db.Integer(),primary_key=True,unique=True)
|
||||||
|
prefix = db.Column(db.Integer())
|
||||||
|
network_address = db.Column(db.String(16),unique=True)
|
||||||
|
hosts = db.Column(db.Integer())
|
||||||
|
description = db.Column(db.String(32),unique=True)
|
||||||
+31
-1
@@ -1,11 +1,13 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from flask import Blueprint, request, render_template, flash, redirect, url_for
|
from flask import Blueprint, request, render_template, flash, redirect, url_for
|
||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user
|
||||||
|
from ipaddress import IPv4Network
|
||||||
|
|
||||||
from app._config import app_version
|
from app._config import app_version
|
||||||
|
|
||||||
from app.extensions import *
|
from app.extensions import *
|
||||||
from app.models import *
|
from app.models import *
|
||||||
|
from app.forms import NewPrefixForm
|
||||||
|
|
||||||
base = Blueprint('base', __name__)
|
base = Blueprint('base', __name__)
|
||||||
|
|
||||||
@@ -20,4 +22,32 @@ def home():
|
|||||||
@login_required
|
@login_required
|
||||||
def dashboard():
|
def dashboard():
|
||||||
|
|
||||||
return render_template('panel/dashboard.html', title="Dashboard", is_dash=True, app_version=app_version)
|
return render_template('panel/dashboard.html', title="Dashboard", is_dash=True, app_version=app_version)
|
||||||
|
|
||||||
|
@base.route('/networks',methods=['GET','POST'])
|
||||||
|
@login_required
|
||||||
|
def networks():
|
||||||
|
prefixes = Prefix.query.all()
|
||||||
|
form = NewPrefixForm()
|
||||||
|
if request.method == 'POST' and form.validate_on_submit():
|
||||||
|
try:
|
||||||
|
network = IPv4Network(f"{str(form.subnet.data)}/{str(form.prefix.data)}")
|
||||||
|
|
||||||
|
add_prefix = Prefix(network_address=str(network.network_address),prefix=network.prefixlen,hosts=network.num_addresses,description=str(form.description.data))
|
||||||
|
db.session.add(add_prefix)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
return f"done {network.num_addresses}"
|
||||||
|
|
||||||
|
except:
|
||||||
|
flash("Invalid Subnet or Prefix", 'danger')
|
||||||
|
return redirect(url_for('base.networks'))
|
||||||
|
elif form.errors:
|
||||||
|
flash(form.errors, 'danger')
|
||||||
|
|
||||||
|
return render_template('panel/networks.html', title="Prefixes", is_networks=True, app_version=app_version, prefixes=prefixes, form=form)
|
||||||
|
|
||||||
|
@base.route('/networks/allocations/<string:network>',methods=['GET','POST'])
|
||||||
|
@login_required
|
||||||
|
def allocations(network):
|
||||||
|
return f"Allocations for {network}"
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
/*!
|
||||||
|
* Bootstrap Icons v1.11.3 (https://icons.getbootstrap.com/)
|
||||||
|
* Copyright 2019-2024 The Bootstrap Authors
|
||||||
|
* Licensed under MIT (https://github.com/twbs/icons/blob/main/LICENSE)
|
||||||
|
*/@font-face{font-display:block;font-family:bootstrap-icons;src:url("/static/fonts/bootstrap-icons.woff2?dd67030699838ea613ee6dbda90effa6") format("woff2"),url("/static/fonts/bootstrap-icons.woff?dd67030699838ea613ee6dbda90effa6") format("woff")}.bi::before,[class*=" bi-"]::before,[class^=bi-]::before{display:inline-block;font-family:bootstrap-icons!important;font-style:normal;font-weight:400!important;font-variant:normal;text-transform:none;line-height:1;vertical-align:-.125em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.bi-123::before{content:"\f67f"}.bi-alarm-fill::before{content:"\f101"}.bi-alarm::before{content:"\f102"}.bi-align-bottom::before{content:"\f103"}.bi-align-center::before{content:"\f104"}.bi-align-end::before{content:"\f105"}.bi-align-middle::before{content:"\f106"}.bi-align-start::before{content:"\f107"}.bi-align-top::before{content:"\f108"}.bi-alt::before{content:"\f109"}.bi-app-indicator::before{content:"\f10a"}.bi-app::before{content:"\f10b"}.bi-archive-fill::before{content:"\f10c"}.bi-archive::before{content:"\f10d"}.bi-arrow-90deg-down::before{content:"\f10e"}.bi-arrow-90deg-left::before{content:"\f10f"}.bi-arrow-90deg-right::before{content:"\f110"}.bi-arrow-90deg-up::before{content:"\f111"}.bi-arrow-bar-down::before{content:"\f112"}.bi-arrow-bar-left::before{content:"\f113"}.bi-arrow-bar-right::before{content:"\f114"}.bi-arrow-bar-up::before{content:"\f115"}.bi-arrow-clockwise::before{content:"\f116"}.bi-arrow-counterclockwise::before{content:"\f117"}.bi-arrow-down-circle-fill::before{content:"\f118"}.bi-arrow-down-circle::before{content:"\f119"}.bi-arrow-down-left-circle-fill::before{content:"\f11a"}.bi-arrow-down-left-circle::before{content:"\f11b"}.bi-arrow-down-left-square-fill::before{content:"\f11c"}.bi-arrow-down-left-square::before{content:"\f11d"}.bi-arrow-down-left::before{content:"\f11e"}.bi-arrow-down-right-circle-fill::before{content:"\f11f"}.bi-arrow-down-right-circle::before{content:"\f120"}.bi-arrow-down-right-square-fill::before{content:"\f121"}.bi-arrow-down-right-square::before{content:"\f122"}.bi-arrow-down-right::before{content:"\f123"}.bi-arrow-down-short::before{content:"\f124"}.bi-arrow-down-square-fill::before{content:"\f125"}.bi-arrow-down-square::before{content:"\f126"}.bi-arrow-down-up::before{content:"\f127"}.bi-arrow-down::before{content:"\f128"}.bi-arrow-left-circle-fill::before{content:"\f129"}.bi-arrow-left-circle::before{content:"\f12a"}.bi-arrow-left-right::before{content:"\f12b"}.bi-arrow-left-short::before{content:"\f12c"}.bi-arrow-left-square-fill::before{content:"\f12d"}.bi-arrow-left-square::before{content:"\f12e"}.bi-arrow-left::before{content:"\f12f"}.bi-arrow-repeat::before{content:"\f130"}.bi-arrow-return-left::before{content:"\f131"}.bi-arrow-return-right::before{content:"\f132"}.bi-arrow-right-circle-fill::before{content:"\f133"}.bi-arrow-right-circle::before{content:"\f134"}.bi-arrow-right-short::before{content:"\f135"}.bi-arrow-right-square-fill::before{content:"\f136"}.bi-arrow-right-square::before{content:"\f137"}.bi-arrow-right::before{content:"\f138"}.bi-arrow-up-circle-fill::before{content:"\f139"}.bi-arrow-up-circle::before{content:"\f13a"}.bi-arrow-up-left-circle-fill::before{content:"\f13b"}.bi-arrow-up-left-circle::before{content:"\f13c"}.bi-arrow-up-left-square-fill::before{content:"\f13d"}.bi-arrow-up-left-square::before{content:"\f13e"}.bi-arrow-up-left::before{content:"\f13f"}.bi-arrow-up-right-circle-fill::before{content:"\f140"}.bi-arrow-up-right-circle::before{content:"\f141"}.bi-arrow-up-right-square-fill::before{content:"\f142"}.bi-arrow-up-right-square::before{content:"\f143"}.bi-arrow-up-right::before{content:"\f144"}.bi-arrow-up-short::before{content:"\f145"}.bi-arrow-up-square-fill::before{content:"\f146"}.bi-arrow-up-square::before{content:"\f147"}.bi-arrow-up::before{content:"\f148"}.bi-arrows-angle-contract::before{content:"\f149"}.bi-arrows-angle-expand::before{content:"\f14a"}.bi-arrows-collapse::before{content:"\f14b"}.bi-arrows-expand::before{content:"\f14c"}.bi-arrows-fullscreen::before{content:"\f14d"}.bi-arrows-move::before{content:"\f14e"}.bi-aspect-ratio-fill::before{content:"\f14f"}.bi-aspect-ratio::before{content:"\f150"}.bi-asterisk::before{content:"\f151"}.bi-at::before{content:"\f152"}.bi-award-fill::before{content:"\f153"}.bi-award::before{content:"\f154"}.bi-back::before{content:"\f155"}.bi-backspace-fill::before{content:"\f156"}.bi-backspace-reverse-fill::before{content:"\f157"}.bi-backspace-reverse::before{content:"\f158"}.bi-backspace::before{content:"\f159"}.bi-badge-3d-fill::before{content:"\f15a"}.bi-badge-3d::before{content:"\f15b"}.bi-badge-4k-fill::before{content:"\f15c"}.bi-badge-4k::before{content:"\f15d"}.bi-badge-8k-fill::before{content:"\f15e"}.bi-badge-8k::before{content:"\f15f"}.bi-badge-ad-fill::before{content:"\f160"}.bi-badge-ad::before{content:"\f161"}.bi-badge-ar-fill::before{content:"\f162"}.bi-badge-ar::before{content:"\f163"}.bi-badge-cc-fill::beLine truncated
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
btn-exsm {
|
||||||
|
padding-top: 1px;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
@@ -12,7 +12,7 @@
|
|||||||
<link rel="icon" type="image/png" href="{{ url_for('static',filename='img/logo.png') }}" />
|
<link rel="icon" type="image/png" href="{{ url_for('static',filename='img/logo.png') }}" />
|
||||||
<link rel="stylesheet" href="{{ url_for('static',filename='css/custom.css') }}"/>
|
<link rel="stylesheet" href="{{ url_for('static',filename='css/custom.css') }}"/>
|
||||||
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap.min.css') }}"/>
|
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap.min.css') }}"/>
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap-icons.min.css') }}"/>
|
||||||
</head>
|
</head>
|
||||||
<body class=" d-flex flex-column">
|
<body class=" d-flex flex-column">
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<link rel="icon" type="image/png" href="{{ url_for('static',filename='img/logo.png') }}" />
|
<link rel="icon" type="image/png" href="{{ url_for('static',filename='img/logo.png') }}" />
|
||||||
<link rel="stylesheet" href="{{ url_for('static',filename='css/custom.css') }}"/>
|
<link rel="stylesheet" href="{{ url_for('static',filename='css/custom.css') }}"/>
|
||||||
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap.min.css') }}"/>
|
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap.min.css') }}"/>
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap-icons.min.css') }}"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<!-- Flash message -->
|
||||||
|
{% with errors = get_flashed_messages(with_categories=true,category_filter=["success","warning","danger","error"]) %}
|
||||||
|
{% if errors %}
|
||||||
|
{% for category, message in errors %}
|
||||||
|
<div class="alert alert-dismissible alert-{{ category }} m-0" style="position:fixed;top:5%;left:38%;z-index:10;min-width:25%;">
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
|
<p class="mb-0"><b>{{ message }}</b></a></p>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
<!-- END|Flash message -->
|
||||||
@@ -7,30 +7,26 @@
|
|||||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {% if is_dash %}active{% endif %}" href="{{ url_for('base.dashboard') }}">Dashboard</a>
|
<a class="nav-link {% if is_dash %}active{% endif %}" href="{{ url_for('base.dashboard') }}"><i class="bi bi-house-door-fill"></i> Dashboard</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% if is_networks %}active{% endif %}" href="{{ url_for('base.networks') }}"><i class="bi bi-globe"></i> Network(s)</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false">Network</a>
|
<a class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><i class="bi bi-archive-fill"></i> Inventory</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a class="dropdown-item" href="#">Subnets</a></li>
|
<li><a class="dropdown-item" href="#"><i class="bi bi-pc-display"></i> Computers</a></li>
|
||||||
<li><a class="dropdown-item" href="#">Attributions</a></li>
|
<li><a class="dropdown-item" href="#"><i class="bi bi-server"></i> Servers</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#"><i class="bi bi-server"></i> Virtual Machines</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#"><i class="bi bi-ethernet"></i> Networks Devices</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#"><i class="bi bi-collection"></i> Others</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item dropdown">
|
{% if current_user.admin %}
|
||||||
<a class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><i class="bi bi-archive-fill"></i> Inventory</a>
|
<li class="nav-item">
|
||||||
<ul class="dropdown-menu">
|
<a class="nav-link active" href="">Admin</a>
|
||||||
<li><a class="dropdown-item" href="#"><i class="bi bi-pc-display"></i> Computers</a></li>
|
</li>
|
||||||
<li><a class="dropdown-item" href="#"><i class="bi bi-server"></i> Servers</a></li>
|
{% endif %}
|
||||||
<li><a class="dropdown-item" href="#"><i class="bi bi-server"></i> Virtual Machines</a></li>
|
|
||||||
<li><a class="dropdown-item" href="#"><i class="bi bi-ethernet"></i> Networks Devices</a></li>
|
|
||||||
<li><a class="dropdown-item" href="#"><i class="bi bi-collection"></i> Others</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
{% if current_user.admin %}
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link active" href="">Admin</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
</ul>
|
||||||
<form class="d-flex" role="search">
|
<form class="d-flex" role="search">
|
||||||
<a class="btn btn-outline-warning" type="submit" href="{{ url_for('auth.logout') }}">logout</a>
|
<a class="btn btn-outline-warning" type="submit" href="{{ url_for('auth.logout') }}">logout</a>
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
{% extends 'panel/_base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
{% include 'panel/_nav.html' %}
|
||||||
|
{% include 'panel/_flash.html' %}
|
||||||
|
<div class="container" style="margin-top:5vh;">
|
||||||
|
<div class="row">
|
||||||
|
<!-- PREFIXES TABLE -->
|
||||||
|
<div class="col-9">
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">#</th>
|
||||||
|
<th scope="col">Subnet</th>
|
||||||
|
<th scope="col">Prefix</th>
|
||||||
|
<th scope="col">Usage</th>
|
||||||
|
<th scope="col">Description</th>
|
||||||
|
<th scope="col">Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for network in prefixes %}
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{{network.id}}</th>
|
||||||
|
<td>{{network.network_address}}</td>
|
||||||
|
<td>{{network.prefix}}</td>
|
||||||
|
<td>X / {{network.hosts}} </td>
|
||||||
|
<td>{{network.description}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-sm btn-outline-info" style="padding-top:1px;padding-bottom:1px">calculate</button>
|
||||||
|
<button class="btn btn-sm btn-outline-danger"style="padding-top:1px;padding-bottom:1px">delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!-- PREFIX FORM -->
|
||||||
|
<div class="col-3">
|
||||||
|
<div class="card p-4 shadow rounded-3">
|
||||||
|
<h2 class="text-center mb-4">Add Network</h2>
|
||||||
|
<form method="POST">
|
||||||
|
{{ form.csrf_token }}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="subnet" class="form-label">Subnet</label>
|
||||||
|
{{ form.subnet(class="form-control", placeholder="192.168.0.0") }}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="prefix" class="form-label">Prefix</label>
|
||||||
|
{{ form.prefix(class="form-control", placeholder="24") }}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="description" class="form-label">Description</label>
|
||||||
|
{{ form.description(class="form-control", placeholder="local area network...") }}
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-secondary w-100">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
Reference in new issue
Block a user