wip
This commit is contained in:
parent
3b2f1db4ce
commit
5c16964b76
47 changed files with 2080 additions and 1053 deletions
|
@ -4,383 +4,384 @@ import markdown
|
|||
from app.core.models import Server, App, Subnet, Port
|
||||
from app.core.extensions import db, limiter
|
||||
from datetime import datetime
|
||||
from app.utils.app_utils import validate_app_data
|
||||
|
||||
bp = Blueprint('dashboard', __name__, url_prefix='/dashboard')
|
||||
bp = Blueprint("dashboard", __name__, url_prefix="/dashboard")
|
||||
|
||||
@bp.route('/')
|
||||
|
||||
@bp.route("/")
|
||||
@login_required
|
||||
def dashboard_home():
|
||||
"""Main dashboard view showing server statistics"""
|
||||
server_count = Server.query.count()
|
||||
app_count = App.query.count()
|
||||
subnet_count = Subnet.query.count()
|
||||
|
||||
|
||||
# Get latest added servers
|
||||
latest_servers = Server.query.order_by(Server.created_at.desc()).limit(5).all()
|
||||
|
||||
|
||||
# Get subnets with usage stats
|
||||
subnets = Subnet.query.all()
|
||||
for subnet in subnets:
|
||||
subnet.usage_percent = subnet.used_ips / 254 * 100 if subnet.cidr.endswith('/24') else 0
|
||||
|
||||
subnet.usage_percent = (
|
||||
subnet.used_ips / 254 * 100 if subnet.cidr.endswith("/24") else 0
|
||||
)
|
||||
|
||||
return render_template(
|
||||
'dashboard/index.html',
|
||||
title='Dashboard',
|
||||
"dashboard/index.html",
|
||||
title="Dashboard",
|
||||
server_count=server_count,
|
||||
app_count=app_count,
|
||||
subnet_count=subnet_count,
|
||||
latest_servers=latest_servers,
|
||||
subnets=subnets,
|
||||
now=datetime.now()
|
||||
now=datetime.now(),
|
||||
)
|
||||
|
||||
@bp.route('/servers')
|
||||
|
||||
@bp.route("/servers")
|
||||
@login_required
|
||||
def server_list():
|
||||
"""List all servers"""
|
||||
servers = Server.query.order_by(Server.hostname).all()
|
||||
|
||||
|
||||
return render_template(
|
||||
'dashboard/server_list.html',
|
||||
title='Servers',
|
||||
"dashboard/server_list.html",
|
||||
title="Servers",
|
||||
servers=servers,
|
||||
now=datetime.now()
|
||||
now=datetime.now(),
|
||||
)
|
||||
|
||||
@bp.route('/server/<int:server_id>')
|
||||
|
||||
@bp.route("/server/<int:server_id>")
|
||||
@login_required
|
||||
def server_view(server_id):
|
||||
"""View server details"""
|
||||
server = Server.query.get_or_404(server_id)
|
||||
apps = App.query.filter_by(server_id=server_id).all()
|
||||
|
||||
|
||||
return render_template(
|
||||
'dashboard/server_view.html',
|
||||
title=f'Server - {server.hostname}',
|
||||
"dashboard/server_view.html",
|
||||
title=f"Server - {server.hostname}",
|
||||
server=server,
|
||||
apps=apps,
|
||||
now=datetime.now()
|
||||
now=datetime.now(),
|
||||
)
|
||||
|
||||
@bp.route('/server/new', methods=['GET', 'POST'])
|
||||
|
||||
@bp.route("/server/new", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def server_new():
|
||||
"""Create a new server"""
|
||||
subnets = Subnet.query.all()
|
||||
|
||||
if request.method == 'POST':
|
||||
hostname = request.form.get('hostname')
|
||||
ip_address = request.form.get('ip_address')
|
||||
subnet_id = request.form.get('subnet_id')
|
||||
documentation = request.form.get('documentation', '')
|
||||
|
||||
|
||||
if request.method == "POST":
|
||||
hostname = request.form.get("hostname")
|
||||
ip_address = request.form.get("ip_address")
|
||||
subnet_id = request.form.get("subnet_id")
|
||||
documentation = request.form.get("documentation", "")
|
||||
|
||||
# Basic validation
|
||||
if not hostname or not ip_address or not subnet_id:
|
||||
flash('Please fill in all required fields', 'danger')
|
||||
flash("Please fill in all required fields", "danger")
|
||||
return render_template(
|
||||
'dashboard/server_form.html',
|
||||
title='New Server',
|
||||
"dashboard/server_form.html",
|
||||
title="New Server",
|
||||
subnets=subnets,
|
||||
now=datetime.now()
|
||||
now=datetime.now(),
|
||||
)
|
||||
|
||||
|
||||
# Check if hostname or IP already exists
|
||||
if Server.query.filter_by(hostname=hostname).first():
|
||||
flash('Hostname already exists', 'danger')
|
||||
flash("Hostname already exists", "danger")
|
||||
return render_template(
|
||||
'dashboard/server_form.html',
|
||||
title='New Server',
|
||||
"dashboard/server_form.html",
|
||||
title="New Server",
|
||||
subnets=subnets,
|
||||
now=datetime.now()
|
||||
now=datetime.now(),
|
||||
)
|
||||
|
||||
|
||||
if Server.query.filter_by(ip_address=ip_address).first():
|
||||
flash('IP address already exists', 'danger')
|
||||
flash("IP address already exists", "danger")
|
||||
return render_template(
|
||||
'dashboard/server_form.html',
|
||||
title='New Server',
|
||||
"dashboard/server_form.html",
|
||||
title="New Server",
|
||||
subnets=subnets,
|
||||
now=datetime.now()
|
||||
now=datetime.now(),
|
||||
)
|
||||
|
||||
|
||||
# Create new server
|
||||
server = Server(
|
||||
hostname=hostname,
|
||||
ip_address=ip_address,
|
||||
subnet_id=subnet_id,
|
||||
documentation=documentation
|
||||
documentation=documentation,
|
||||
)
|
||||
|
||||
|
||||
db.session.add(server)
|
||||
db.session.commit()
|
||||
|
||||
flash('Server created successfully', 'success')
|
||||
return redirect(url_for('dashboard.server_view', server_id=server.id))
|
||||
|
||||
|
||||
flash("Server created successfully", "success")
|
||||
return redirect(url_for("dashboard.server_view", server_id=server.id))
|
||||
|
||||
return render_template(
|
||||
'dashboard/server_form.html',
|
||||
title='New Server',
|
||||
"dashboard/server_form.html",
|
||||
title="New Server",
|
||||
subnets=subnets,
|
||||
now=datetime.now()
|
||||
now=datetime.now(),
|
||||
)
|
||||
|
||||
@bp.route('/server/<int:server_id>/edit', methods=['GET', 'POST'])
|
||||
|
||||
@bp.route("/server/<int:server_id>/edit", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def server_edit(server_id):
|
||||
"""Edit an existing server"""
|
||||
server = Server.query.get_or_404(server_id)
|
||||
subnets = Subnet.query.all()
|
||||
|
||||
if request.method == 'POST':
|
||||
hostname = request.form.get('hostname')
|
||||
ip_address = request.form.get('ip_address')
|
||||
subnet_id = request.form.get('subnet_id')
|
||||
documentation = request.form.get('documentation', '')
|
||||
|
||||
|
||||
if request.method == "POST":
|
||||
hostname = request.form.get("hostname")
|
||||
ip_address = request.form.get("ip_address")
|
||||
subnet_id = request.form.get("subnet_id")
|
||||
documentation = request.form.get("documentation", "")
|
||||
|
||||
if not hostname or not ip_address or not subnet_id:
|
||||
flash('All fields are required', 'danger')
|
||||
flash("All fields are required", "danger")
|
||||
return render_template(
|
||||
'dashboard/server_form.html',
|
||||
title='Edit Server',
|
||||
"dashboard/server_form.html",
|
||||
title="Edit Server",
|
||||
server=server,
|
||||
subnets=subnets
|
||||
subnets=subnets,
|
||||
)
|
||||
|
||||
|
||||
# Check if hostname changed and already exists
|
||||
if hostname != server.hostname and Server.query.filter_by(hostname=hostname).first():
|
||||
flash('Hostname already exists', 'danger')
|
||||
if (
|
||||
hostname != server.hostname
|
||||
and Server.query.filter_by(hostname=hostname).first()
|
||||
):
|
||||
flash("Hostname already exists", "danger")
|
||||
return render_template(
|
||||
'dashboard/server_form.html',
|
||||
title='Edit Server',
|
||||
"dashboard/server_form.html",
|
||||
title="Edit Server",
|
||||
server=server,
|
||||
subnets=subnets
|
||||
subnets=subnets,
|
||||
)
|
||||
|
||||
|
||||
# Check if IP changed and already exists
|
||||
if ip_address != server.ip_address and Server.query.filter_by(ip_address=ip_address).first():
|
||||
flash('IP address already exists', 'danger')
|
||||
if (
|
||||
ip_address != server.ip_address
|
||||
and Server.query.filter_by(ip_address=ip_address).first()
|
||||
):
|
||||
flash("IP address already exists", "danger")
|
||||
return render_template(
|
||||
'dashboard/server_form.html',
|
||||
title='Edit Server',
|
||||
"dashboard/server_form.html",
|
||||
title="Edit Server",
|
||||
server=server,
|
||||
subnets=subnets
|
||||
subnets=subnets,
|
||||
)
|
||||
|
||||
|
||||
# Update server
|
||||
server.hostname = hostname
|
||||
server.ip_address = ip_address
|
||||
server.subnet_id = subnet_id
|
||||
server.documentation = documentation
|
||||
|
||||
|
||||
db.session.commit()
|
||||
|
||||
flash('Server updated successfully', 'success')
|
||||
return redirect(url_for('dashboard.server_view', server_id=server.id))
|
||||
|
||||
|
||||
flash("Server updated successfully", "success")
|
||||
return redirect(url_for("dashboard.server_view", server_id=server.id))
|
||||
|
||||
# GET request - show form with current values
|
||||
return render_template(
|
||||
'dashboard/server_form.html',
|
||||
title=f'Edit Server - {server.hostname}',
|
||||
"dashboard/server_form.html",
|
||||
title=f"Edit Server - {server.hostname}",
|
||||
server=server,
|
||||
subnets=subnets
|
||||
subnets=subnets,
|
||||
)
|
||||
|
||||
@bp.route('/server/<int:server_id>/delete', methods=['POST'])
|
||||
|
||||
@bp.route("/server/<int:server_id>/delete", methods=["POST"])
|
||||
@login_required
|
||||
def server_delete(server_id):
|
||||
"""Delete a server"""
|
||||
server = Server.query.get_or_404(server_id)
|
||||
|
||||
|
||||
# Delete all apps associated with this server
|
||||
App.query.filter_by(server_id=server_id).delete()
|
||||
|
||||
|
||||
# Delete the server
|
||||
db.session.delete(server)
|
||||
db.session.commit()
|
||||
|
||||
flash('Server deleted successfully', 'success')
|
||||
return redirect(url_for('dashboard.dashboard_home'))
|
||||
|
||||
@bp.route('/app/new', methods=['GET', 'POST'])
|
||||
flash("Server deleted successfully", "success")
|
||||
return redirect(url_for("dashboard.dashboard_home"))
|
||||
|
||||
|
||||
@bp.route("/app/new", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def app_new():
|
||||
"""Create a new application"""
|
||||
"""Create a new application with comprehensive error handling"""
|
||||
# Get all servers for dropdown
|
||||
servers = Server.query.all()
|
||||
|
||||
if request.method == 'POST':
|
||||
name = request.form.get('name')
|
||||
server_id = request.form.get('server_id')
|
||||
documentation = request.form.get('documentation', '')
|
||||
|
||||
# Get port data from form
|
||||
port_numbers = request.form.getlist('port_numbers[]')
|
||||
protocols = request.form.getlist('protocols[]')
|
||||
port_descriptions = request.form.getlist('port_descriptions[]')
|
||||
|
||||
# Basic validation
|
||||
if not name or not server_id:
|
||||
flash('Please fill in all required fields', 'danger')
|
||||
return render_template(
|
||||
'dashboard/app_form.html',
|
||||
title='New Application',
|
||||
servers=servers
|
||||
)
|
||||
|
||||
# Create new app
|
||||
app = App(
|
||||
name=name,
|
||||
server_id=server_id,
|
||||
documentation=documentation
|
||||
)
|
||||
|
||||
db.session.add(app)
|
||||
db.session.flush() # Get the app ID without committing
|
||||
|
||||
# Add ports if provided
|
||||
|
||||
if not servers:
|
||||
flash("You need to create a server before adding applications", "warning")
|
||||
return redirect(url_for("dashboard.server_new"))
|
||||
|
||||
if request.method == "POST":
|
||||
# Get form data
|
||||
name = request.form.get("name", "").strip()
|
||||
server_id = request.form.get("server_id")
|
||||
documentation = request.form.get("documentation", "")
|
||||
|
||||
# Process port data from form
|
||||
port_data = []
|
||||
port_numbers = request.form.getlist("port_numbers[]")
|
||||
protocols = request.form.getlist("protocols[]")
|
||||
descriptions = request.form.getlist("port_descriptions[]")
|
||||
|
||||
for i in range(len(port_numbers)):
|
||||
if port_numbers[i] and port_numbers[i].strip():
|
||||
try:
|
||||
port_num = int(port_numbers[i])
|
||||
|
||||
# Get protocol and description, handling index errors
|
||||
protocol = protocols[i] if i < len(protocols) else 'TCP'
|
||||
description = port_descriptions[i] if i < len(port_descriptions) else ''
|
||||
|
||||
new_port = Port(
|
||||
app_id=app.id,
|
||||
port_number=port_num,
|
||||
protocol=protocol,
|
||||
description=description
|
||||
)
|
||||
db.session.add(new_port)
|
||||
except (ValueError, IndexError):
|
||||
continue
|
||||
|
||||
db.session.commit()
|
||||
|
||||
flash('Application created successfully', 'success')
|
||||
return redirect(url_for('dashboard.server_view', server_id=server_id))
|
||||
|
||||
protocol = protocols[i] if i < len(protocols) else "TCP"
|
||||
description = descriptions[i] if i < len(descriptions) else ""
|
||||
port_data.append((port_numbers[i], protocol, description))
|
||||
|
||||
# Save application
|
||||
from app.utils.app_utils import save_app
|
||||
|
||||
success, app, error = save_app(name, server_id, documentation, port_data)
|
||||
|
||||
if success:
|
||||
flash("Application created successfully", "success")
|
||||
return redirect(url_for("dashboard.app_view", app_id=app.id))
|
||||
else:
|
||||
flash(error, "danger")
|
||||
|
||||
# For GET requests or failed POSTs
|
||||
return render_template(
|
||||
'dashboard/app_form.html',
|
||||
title='New Application',
|
||||
servers=servers
|
||||
"dashboard/app_form.html",
|
||||
title="Create New Application",
|
||||
edit_mode=False,
|
||||
dashboard_link=url_for("dashboard.dashboard_home"),
|
||||
servers=servers,
|
||||
)
|
||||
|
||||
@bp.route('/app/<int:app_id>', methods=['GET'])
|
||||
|
||||
@bp.route("/app/<int:app_id>", methods=["GET"])
|
||||
@login_required
|
||||
def app_view(app_id):
|
||||
"""View a specific application"""
|
||||
app = App.query.get_or_404(app_id)
|
||||
server = Server.query.get(app.server_id)
|
||||
|
||||
|
||||
return render_template(
|
||||
'dashboard/app_view.html',
|
||||
title=f'Application - {app.name}',
|
||||
"dashboard/app_view.html",
|
||||
title=f"Application - {app.name}",
|
||||
app=app,
|
||||
server=server,
|
||||
now=datetime.now()
|
||||
now=datetime.now(),
|
||||
)
|
||||
|
||||
@bp.route('/app/<int:app_id>/edit', methods=['GET', 'POST'])
|
||||
|
||||
@bp.route("/app/<int:app_id>/edit", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def app_edit(app_id):
|
||||
"""Edit an existing application"""
|
||||
"""Edit an existing application with comprehensive error handling"""
|
||||
# Get the application and all servers
|
||||
app = App.query.get_or_404(app_id)
|
||||
servers = Server.query.all()
|
||||
|
||||
if request.method == 'POST':
|
||||
name = request.form.get('name')
|
||||
server_id = request.form.get('server_id')
|
||||
documentation = request.form.get('documentation', '')
|
||||
|
||||
if not name or not server_id:
|
||||
flash('All required fields must be filled', 'danger')
|
||||
return render_template(
|
||||
'dashboard/app_form.html',
|
||||
title='Edit Application',
|
||||
app=app,
|
||||
servers=servers
|
||||
|
||||
if request.method == "POST":
|
||||
# Get form data
|
||||
name = request.form.get("name", "").strip()
|
||||
server_id = request.form.get("server_id")
|
||||
documentation = request.form.get("documentation", "")
|
||||
|
||||
# Process port data from form
|
||||
port_data = []
|
||||
port_numbers = request.form.getlist("port_numbers[]")
|
||||
protocols = request.form.getlist("protocols[]")
|
||||
descriptions = request.form.getlist("port_descriptions[]")
|
||||
|
||||
for i in range(len(port_numbers)):
|
||||
if port_numbers[i] and port_numbers[i].strip():
|
||||
protocol = protocols[i] if i < len(protocols) else "TCP"
|
||||
description = descriptions[i] if i < len(descriptions) else ""
|
||||
port_data.append((port_numbers[i], protocol, description))
|
||||
|
||||
# Replace local validation with shared function
|
||||
valid, error = validate_app_data(name, server_id, existing_app_id=app_id)
|
||||
|
||||
if valid:
|
||||
# Update application
|
||||
from app.utils.app_utils import save_app
|
||||
|
||||
success, updated_app, error = save_app(
|
||||
name, server_id, documentation, port_data, app_id
|
||||
)
|
||||
|
||||
# Check if name changed and already exists on the same server
|
||||
existing_app = App.query.filter(App.name == name,
|
||||
App.server_id == server_id,
|
||||
App.id != app.id).first()
|
||||
if existing_app:
|
||||
flash('Application with this name already exists on the selected server', 'danger')
|
||||
return render_template(
|
||||
'dashboard/app_form.html',
|
||||
title='Edit Application',
|
||||
app=app,
|
||||
servers=servers
|
||||
)
|
||||
|
||||
# Update application
|
||||
app.name = name
|
||||
app.server_id = server_id
|
||||
app.documentation = documentation
|
||||
|
||||
try:
|
||||
db.session.commit()
|
||||
flash('Application updated successfully', 'success')
|
||||
return redirect(url_for('dashboard.app_view', app_id=app.id))
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
flash(f'Error updating application: {str(e)}', 'danger')
|
||||
|
||||
|
||||
if success:
|
||||
flash("Application updated successfully", "success")
|
||||
return redirect(url_for("dashboard.app_view", app_id=app_id))
|
||||
else:
|
||||
flash(error, "danger")
|
||||
else:
|
||||
flash(error, "danger")
|
||||
|
||||
# For GET requests or failed POSTs
|
||||
return render_template(
|
||||
'dashboard/app_form.html',
|
||||
title=f'Edit Application - {app.name}',
|
||||
"dashboard/app_form.html",
|
||||
title=f"Edit Application: {app.name}",
|
||||
edit_mode=True,
|
||||
app=app,
|
||||
servers=servers
|
||||
dashboard_link=url_for("dashboard.dashboard_home"),
|
||||
servers=servers,
|
||||
)
|
||||
|
||||
@bp.route('/app/<int:app_id>/delete', methods=['POST'])
|
||||
|
||||
@bp.route("/app/<int:app_id>/delete", methods=["POST"])
|
||||
@login_required
|
||||
def app_delete(app_id):
|
||||
"""Delete an application"""
|
||||
app = App.query.get_or_404(app_id)
|
||||
server_id = app.server_id
|
||||
|
||||
|
||||
db.session.delete(app)
|
||||
db.session.commit()
|
||||
|
||||
flash('Application deleted successfully', 'success')
|
||||
return redirect(url_for('dashboard.server_view', server_id=server_id))
|
||||
|
||||
@bp.route('/settings', methods=['GET', 'POST'])
|
||||
flash("Application deleted successfully", "success")
|
||||
return redirect(url_for("dashboard.server_view", server_id=server_id))
|
||||
|
||||
|
||||
@bp.route("/settings", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def settings():
|
||||
"""User settings page"""
|
||||
if request.method == 'POST':
|
||||
if request.method == "POST":
|
||||
# Handle user settings update
|
||||
current_password = request.form.get('current_password')
|
||||
new_password = request.form.get('new_password')
|
||||
confirm_password = request.form.get('confirm_password')
|
||||
|
||||
current_password = request.form.get("current_password")
|
||||
new_password = request.form.get("new_password")
|
||||
confirm_password = request.form.get("confirm_password")
|
||||
|
||||
# Validate inputs
|
||||
if not current_password:
|
||||
flash('Current password is required', 'danger')
|
||||
return redirect(url_for('dashboard.settings'))
|
||||
|
||||
flash("Current password is required", "danger")
|
||||
return redirect(url_for("dashboard.settings"))
|
||||
|
||||
if new_password != confirm_password:
|
||||
flash('New passwords do not match', 'danger')
|
||||
return redirect(url_for('dashboard.settings'))
|
||||
|
||||
flash("New passwords do not match", "danger")
|
||||
return redirect(url_for("dashboard.settings"))
|
||||
|
||||
# Verify current password
|
||||
if not current_user.check_password(current_password):
|
||||
flash('Current password is incorrect', 'danger')
|
||||
return redirect(url_for('dashboard.settings'))
|
||||
|
||||
flash("Current password is incorrect", "danger")
|
||||
return redirect(url_for("dashboard.settings"))
|
||||
|
||||
# Update password
|
||||
current_user.set_password(new_password)
|
||||
db.session.commit()
|
||||
|
||||
flash('Password updated successfully', 'success')
|
||||
return redirect(url_for('dashboard.settings'))
|
||||
|
||||
return render_template(
|
||||
'dashboard/settings.html',
|
||||
title='User Settings'
|
||||
)
|
||||
|
||||
flash("Password updated successfully", "success")
|
||||
return redirect(url_for("dashboard.settings"))
|
||||
|
||||
return render_template("dashboard/settings.html", title="User Settings")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue