This commit is contained in:
Takeus committed 2025-02-03 01:16:13 +01:00
1 parent 0980efcd24
commit f11aa2d6c6
22 files changed
+491

No files matched your search

+108
View File
@@ -0,0 +1,108 @@
from flask import Flask
from flask import abort, request, jsonify, make_response, render_template
from werkzeug.middleware.proxy_fix import ProxyFix
from datetime import datetime
from os import environ
from app._config import *
from app.models import *
from app.extensions import *
from app.routes.r_base import base
from app.routes.r_auth import auth
from app.routes.r_adm import admin
def create_app():
app = Flask(__name__)
app.config.from_object(Configuration)
login_manager.init_app(app)
db.init_app(app)
app.wsgi_app = ProxyFix(
app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1
)
with app.app_context():
db.create_all()
## BLUEPRINTS
app.register_blueprint(base, url_prefix='/')
app.register_blueprint(auth, url_prefix='/auth')
app.register_blueprint(admin, url_prefix='/admin')
## SYSTEM ROUTES
@app.before_request
def before_request():
if app_maintenance:
return abort(503)
@app.route('/app_info')
def route_app_info():
response = make_response(jsonify({'app_name': app_name, 'app_version':app_version,'release_date':app_release_date,'app_maintenance':app_maintenance,'app_debug':app_debug}), 200)
return response
@app.route('/app_check')
def route_app_check():
response = make_response(jsonify({'check': 1}), 200)
return response
## ERROR ROUTES
@app.errorhandler(401)
def not_found(error):
HTTP_ERROR = [
"401",
"Unauthorized",
"The server could not verify that you are authorized to access the URL requested. You are not authenticated, or your browser doesn't understand how to supply the credentials required...",
"https://takeus.ovh/static/img/login.svg"
]
return render_template('srv_error.html',HTTP_ERROR=HTTP_ERROR), 401
@app.errorhandler(403)
def not_found(error):
HTTP_ERROR = [
"403",
"Forbidden",
"You don't have the permission to access the requested resource. It is either read-protected or not readable by the server...",
"https://takeus.ovh/static/img/login.svg"
]
return render_template('srv_error.html',HTTP_ERROR=HTTP_ERROR), 403
@app.errorhandler(404)
def not_found(error):
HTTP_ERROR = [
"404",
"Not Found",
"The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again...",
"https://takeus.ovh/static/img/404.svg"
]
return render_template('srv_error.html',HTTP_ERROR=HTTP_ERROR), 404
@app.errorhandler(500)
def not_found(error):
HTTP_ERROR = [
"500",
"Internal Server Error",
"The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.",
"https://takeus.ovh/static/img/500.svg"
]
return render_template('srv_error.html',HTTP_ERROR=HTTP_ERROR), 500
@app.errorhandler(503)
def not_found(error):
HTTP_ERROR = [
"503",
"Service Unavailable",
"The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.",
"https://takeus.ovh/static/img/503.svg"
]
return render_template('srv_error.html',HTTP_ERROR=HTTP_ERROR), 503
## FLASK LOGIN
@login_manager.user_loader
def load_user(user_id):
return User.query.filter_by(id=int(user_id)).first()
return app
+25
View File
@@ -0,0 +1,25 @@
##########################################################
############# CONFIGURATION FILE | Flask IPAM ############
## Flask Server (For DEV)
app_ip = '127.0.0.1'
app_port = 80
app_debug = True
app_maintenance = False
app_name = 'takeus-ipam'
app_version = 'V1.0'
app_release_date = '02/2025'
app_url = "http://127.0.0.1"
class Configuration:
# openssl rand -hex 32
SECRET_KEY = 'change_me'
# DB CONFIG
SQLALCHEMY_DATABASE_URI = 'sqlite:///database.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ENGINE_OPTIONS = {"pool_pre_ping": True}
# CK CONFIG
SESSION_COOKIE_SECURE = False # SSL REQUIRED
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Lax'
+8
View File
@@ -0,0 +1,8 @@
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy
from flask_turnstile import Turnstile
login_manager = LoginManager()
db = SQLAlchemy()
turnstile = Turnstile()
+7
View File
@@ -0,0 +1,7 @@
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Length
class LoginForm(FlaskForm):
username = StringField(validators=[DataRequired(),Length(max=128)])
password = PasswordField(validators=[DataRequired(),Length(max=128)])
+9
View File
@@ -0,0 +1,9 @@
from app.extensions import db
from flask_login import UserMixin
class User(UserMixin, db.Model):
id = db.Column(db.Integer(),primary_key=True,unique=True)
username = db.Column(db.String(16))
password = db.Column(db.String(32),unique=True)
is_admin = db.Column(db.Boolean(),default=False)
dat_last = db.Column(db.DateTime())
+26
View File
@@ -0,0 +1,26 @@
from datetime import datetime
from flask import Blueprint, request, render_template, flash, url_for, redirect, abort
from flask_login import login_required, current_user
from app._config import app_version
from app.extensions import *
from app.models import *
admin = Blueprint('admin', __name__)
@admin.route('/')
@login_required
def home():
if current_user.is_admin:
return redirect(url_for('admin.dash'))
else:
return abort(403)
@admin.route('/dashboard')
@login_required
def dash():
if current_user.is_admin == False:
return abort(403)
return f"Welcome {current_user.username} to the admin dashboard"
+45
View File
@@ -0,0 +1,45 @@
from datetime import datetime
from flask import Blueprint, request, render_template, flash, abort, redirect, url_for, jsonify
from flask_login import login_required, current_user, login_user, logout_user
from werkzeug.security import generate_password_hash, check_password_hash
from app._config import *
from app.extensions import *
from app.models import *
from app.forms import LoginForm
auth = Blueprint('auth', __name__)
@auth.route("/login",methods=['GET','POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('base.dashboard'))
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user != None:
if user.password != None:
if check_password_hash(user.password,form.password.data):
login_user(user)
user.dat_last = datetime.now()
db.session.commit()
return redirect(url_for("base.dashboard"))
flash("Bad username or password !", 'danger')
return render_template("auth/login.html", title="Login", form=form, bad_password=True)
return render_template('auth/login.html', title="Login", form=form)
@auth.route("/change",methods=['GET','POST'])
@login_required
def change():
pass
@auth.route("/logout")
@login_required
def logout():
logout_user()
return redirect(url_for('auth.login'))
+23
View File
@@ -0,0 +1,23 @@
from datetime import datetime
from flask import Blueprint, request, render_template, flash, redirect, url_for
from flask_login import login_required, current_user
from app._config import app_version
from app.extensions import *
from app.models import *
base = Blueprint('base', __name__)
@base.route('/',methods=['GET','POST'])
def home():
if current_user.is_authenticated:
return redirect(url_for('base.dashboard'))
else:
return redirect(url_for('auth.login'))
@base.route('/dashboard',methods=['GET','POST'])
@login_required
def dashboard():
return render_template('panel/dashboard.html', title="Dashboard", is_dash=True, app_version=app_version)
+12
View File
@@ -0,0 +1,12 @@
@charset "UTF-8";/*!
* Bootswatch v5.3.3 (https://bootswatch.com)
* Theme: cerulean
* Copyright 2012-2024 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/:root,[data-bs-theme=light]{--bs-blue:#033c73;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#e83e8c;--bs-red:#c71c22;--bs-orange:#fd7e14;--bs-yellow:#dd5600;--bs-green:#73a839;--bs-teal:#20c997;--bs-cyan:#2fa4e7;--bs-black:#000;--bs-white:#fff;--bs-gray:#868e96;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#868e96;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#2fa4e7;--bs-secondary:#e9ecef;--bs-success:#73a839;--bs-info:#033c73;--bs-warning:#dd5600;--bs-danger:#c71c22;--bs-light:#f8f9fa;--bs-dark:#343a40;--bs-primary-rgb:47,164,231;--bs-secondary-rgb:233,236,239;--bs-success-rgb:115,168,57;--bs-info-rgb:3,60,115;--bs-warning-rgb:221,86,0;--bs-danger-rgb:199,28,34;--bs-light-rgb:248,249,250;--bs-dark-rgb:52,58,64;--bs-primary-text-emphasis:#13425c;--bs-secondary-text-emphasis:#5d5e60;--bs-success-text-emphasis:#2e4317;--bs-info-text-emphasis:#01182e;--bs-warning-text-emphasis:#582200;--bs-danger-text-emphasis:#500b0e;--bs-light-text-emphasis:#495057;--bs-dark-text-emphasis:#495057;--bs-primary-bg-subtle:#d5edfa;--bs-secondary-bg-subtle:#fbfbfc;--bs-success-bg-subtle:#e3eed7;--bs-info-bg-subtle:#cdd8e3;--bs-warning-bg-subtle:#f8ddcc;--bs-danger-bg-subtle:#f4d2d3;--bs-light-bg-subtle:#fcfcfd;--bs-dark-bg-subtle:#ced4da;--bs-primary-border-subtle:#acdbf5;--bs-secondary-border-subtle:#f6f7f9;--bs-success-border-subtle:#c7dcb0;--bs-info-border-subtle:#9ab1c7;--bs-warning-border-subtle:#f1bb99;--bs-danger-border-subtle:#e9a4a7;--bs-light-border-subtle:#e9ecef;--bs-dark-border-subtle:#adb5bd;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#495057;--bs-body-color-rgb:73,80,87;--bs-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--bs-emphasis-color:#000;--bs-emphasis-color-rgb:0,0,0;--bs-secondary-color:rgba(73, 80, 87, 0.75);--bs-secondary-color-rgb:73,80,87;--bs-secondary-bg:#e9ecef;--bs-secondary-bg-rgb:233,236,239;--bs-tertiary-color:rgba(73, 80, 87, 0.5);--bs-tertiary-color-rgb:73,80,87;--bs-tertiary-bg:#f8f9fa;--bs-tertiary-bg-rgb:248,249,250;--bs-heading-color:#2fa4e7;--bs-link-color:#2fa4e7;--bs-link-color-rgb:47,164,231;--bs-link-decoration:underline;--bs-link-hover-color:#2683b9;--bs-link-hover-color-rgb:38,131,185;--bs-code-color:#e83e8c;--bs-highlight-color:#495057;--bs-highlight-bg:#f8ddcc;--bs-border-width:1px;--bs-border-style:solid;--bs-border-color:#dee2e6;--bs-border-color-translucent:rgba(0, 0, 0, 0.175);--bs-border-radius:0.375rem;--bs-border-radius-sm:0.25rem;--bs-border-radius-lg:0.5rem;--bs-border-radius-xl:1rem;--bs-border-radius-xxl:2rem;--bs-border-radius-2xl:var(--bs-border-radius-xxl);--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width:0.25rem;--bs-focus-ring-opacity:0.25;--bs-focus-ring-color:rgba(47, 164, 231, 0.25);--bs-form-valid-color:#73a839;--bs-form-valid-border-color:#73a839;--bs-form-invalid-color:#c71c22;--bs-form-invalid-border-color:#c71c22}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color:#dee2e6;--bs-body-color-rgb:222,226,230;--bs-body-bg:#212529;--bs-body-bg-rgb:33,37,41;--bs-emphasis-color:#fff;--bs-emphasis-color-rgb:255,255,255;--bs-secondary-color:rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb:222,226,230;--bs-secondary-bg:#343a40;--bs-secondary-bg-rgb:52,58,64;--bs-tertiary-color:rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb:222,226,230;--bs-tertiary-bg:#2b3035;--bs-tertiary-bg-rgb:43,48,53;--bs-primary-text-emphasis:#82c8f1;--bs-secondary-text-emphasis:#f2f4f5;--bs-success-text-emphasis:#abcb88;--bs-info-text-emphasis:#688aab;--bs-warning-text-emphasis:#eb9a66;--bs-danger-text-emphasis:#dd777a;--bs-light-text-emphasis:#f8f9fa;--bs-dark-text-emphasis:#dee2e6;--bs-primary-bg-subtle:#09212e;--bs-secondary-bg-subtle:#2f2f30;--bs-success-bg-subtle:#17220b;--bs-info-bg-subtle:#010c17;--bs-warning-bg-subtle:#2c1100;--bs-danger-bg-subtle:#280607;--bs-light-bg-subtle:#343a40;--bs-dark-bg-subtle:#1a1d20;--bs-primary-border-subtle:#1c628b;--bs-secondary-border-subtle:#8c8e8f;--bs-success-border-subtle:#456522;--bs-info-border-subtle:#022445;--bs-warning-border-subtle:#853400;--bs-danger-border-subtle:#771114;--bs-light-border-subtle:#495057;--bs-dark-border-subtle:#343a40;--bs-heading-color:inheriLine truncated
/*# sourceMappingURL=bootstrap.min.css.map */
View File
Whitespace-only changes.
+7
View File
@@ -0,0 +1,7 @@
/*!
* Bootstrap v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slLine truncated
//# sourceMappingURL=bootstrap.bundle.min.js.map
@@ -0,0 +1 @@
{"version":3,"names":["elementMap","Map","Data","set","element","key","instance","has","instanceMap","get","size","console","error","Array","from","keys","remove","delete","TRANSITION_END","parseSelector","selector","window","CSS","escape","replace","match","id","triggerTransitionEnd","dispatchEvent","Event","isElement","object","jquery","nodeType","getElement","length","document","querySelector","isVisible","getClientRects","elementIsVisible","getComputedStyle","getPropertyValue","closedDetails","closest","summary","parentNode","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","getAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","noop","reflow","offsetHeight","getjQuery","jQuery","body","DOMContentLoadedCallbacks","isRTL","dir","defineJQueryPlugin","plugin","callback","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","readyState","addEventListener","push","execute","possibleCallback","args","defaultValue","executeAfterTransition","transitionElement","waitForTransition","emulatedDuration","transitionDuration","transitionDelay","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","split","getTransitionDurationFromElement","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","listLength","index","indexOf","Math","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","nativeEvents","Set","makeEventUid","uid","getElementEvents","findHandler","events","callable","delegationSelector","Object","values","find","event","normalizeParameters","originalTypeEvent","delegationFunction","isDelegated","typeEvent","getTypeEvent","addHandler","oneOff","wrapFunction","relatedTarget","delegateTarget","call","this","handlers","previousFunction","domElements","querySelectorAll","domElement","hydrateObj","EventHandler","off","type","apply","bootstrapDelegationHandler","bootstrapHandler","removeHandler","Boolean","removeNamespacedHandlers","namespace","storeElementEvent","handlerKey","entries","includes","on","one","inNamespace","isNamespace","startsWith","elementEvent","slice","keyHandlers","trigger","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","evt","cancelable","preventDefault","obj","meta","value","_unused","defineProperty","configurable","normalizeData","toString","JSON","parse","decodeURIComponent","normalizeDataKey","chr","toLowerCase","Manipulator","setDataAttribute","setAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","bsKeys","dataset","filter","pureKey","charAt","getDataAttribute","Config","Default","DefaultType","Error","_getConfig","config","_mergeConfigObj","_configAfterMerge","_typeCheckConfig","jsonConfig","constructor","configTypes","property","expectedTypes","valueType","prototype","RegExp","test","TypeError","toUpperCase","BaseComponent","super","_element","_config","DATA_KEY","dispose","EVENT_KEY","propertyName","getOwnPropertyNames","_queueCallback","isAnimated","getInstance","getOrCreateInstance","VERSION","eventName","getSelector","hrefAttribute","trim","map","sel","join","SelectorEngine","concat","Element","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","el","getSelectorFromElement","getElementFromSelector","getMultipleElementsFromSelector","enableDismissTrigger","component","method","clickEvent","tagName","EVENT_CLOSE","EVENT_CLOSED","Alert","close","_destroyElement","each","data","undefined","SELECTOR_DATA_TOGGLE","Button","toggle","button","EVENT_TOUCHSTART","EVENT_TOUCHMOVE","EVENT_TOUCHEND","EVENT_POINTERDOWN","EVENT_POINTERUP","endCallback","leftCallback","rightCallback","Swipe","isSupported","_deltaX","_supportPointerEvents","PointerEvent","_initEvents","_start","_eventIsPointerPenTouch","clientX","touches","_end","_handleSwipe","_move","absDeltaX","abs","direction","add","pointerType","navigator","maxTouchPoints","DATA_API_KEY","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","EVENT_SLIDE","EVENT_SLID","EVENT_KEYDOWN","EVENT_MOUSEENTER","EVENT_MOUSELEAVE","EVENT_DRAG_START","EVENT_LOAD_DATA_API","EVENT_CLICK_DATA_API","CLASS_NAME_CAROUSEL","CLASS_NAME_ACTIVE","SELECTOR_ACTIVE","SELECTOR_ITEM","SELECTOR_ACTIVE_ITEM","KEY_TO_DIRECTION","ArrowLeft","ArrowRight","interval","keyboard","pause","ride","touch","wrap","Carousel","_interval","_activeElement","_isSliding","touchTimeout","_swipeHelper","_indicatorsElement","_addEventListeners","cycle","_slide","nextWhenVisible","hidden","_clearInterval","_updateInterval","setInterval","_maybeEnableCycle","to","items","_getItems","activeIndex","_getItemIndex","_getActive","order","defaultInterval","_keydown","_addTouLine truncated
+34
View File
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<!-- BASE -->
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IPAM - {% block styles %}{{ title }}{% endblock %}</title>
<meta name="author" content="Takeus">
<meta name="robots" content="noindex, nofollow">
<!-- LINKS -->
<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/bootstrap.min.css') }}"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
</head>
<body class=" d-flex flex-column">
<style>
body {
background: linear-gradient(to right, #87CEEB, #4682B4);
background-size: 100% 300%;
animation: gradientAnimation 5s ease infinite;
}
@keyframes gradientAnimation {
0% {background-position: 0% 50%;}
50% {background-position: 100% 50%;}
100% {background-position: 0% 50%;}
}
</style>
{% block content %}{% endblock %}
<!-- JAVASCRIPT -->
<script src="{{ url_for('static',filename='js/bootstrap.bundle.min.js') }}"></script>
</body>
</html>
+12
View File
@@ -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 -->
+36
View File
@@ -0,0 +1,36 @@
{% extends 'auth/_base.html' %}
{% block content %}
{% include "auth/_flash.html" %}
<div class="container d-flex justify-content-center align-items-center vh-100">
<div class="card p-4 shadow-lg rounded-3">
<h2 class="text-center mb-4">Login Page</h2>
<form method="POST">
{{ form.csrf_token }}
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-person"></i></span>
{% if bad_password %}
{{ form.username(class="form-control is-invalid", placeholder="username") }}
{% else %}
{{ form.username(class="form-control", placeholder="username") }}
{% endif %}
</div>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-lock"></i></span>
{% if bad_password %}
{{ form.password(class="form-control is-invalid", placeholder="password") }}
{% else %}
{{ form.password(class="form-control", placeholder="password") }}
{% endif %}
</div>
</div>
<button type="submit" class="btn btn-primary w-100">Submit</button>
</form>
</div>
</div>
{% endblock %}
+22
View File
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<!-- BASE -->
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IPAM - {% block styles %}{{ title }}{% endblock %}</title>
<meta name="author" content="Takeus">
<meta name="robots" content="noindex, nofollow">
<!-- LINKS -->
<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/bootstrap.min.css') }}"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
</head>
<body>
{% block content %}{% endblock %}
<!-- JAVASCRIPT -->
<script src="{{ url_for('static',filename='js/bootstrap.bundle.min.js') }}"></script>
</body>
</html>
+40
View File
@@ -0,0 +1,40 @@
<nav class="navbar navbar-expand-lg bg-dark bg-body-tertiary" data-bs-theme="dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">Flask IPAM</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link {% if is_dash %}active{% endif %}" href="{{ url_for('base.dashboard') }}">Dashboard</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false">Network</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Subnets</a></li>
<li><a class="dropdown-item" href="#">Attributions</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<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">
<li><a class="dropdown-item" href="#"><i class="bi bi-pc-display"></i> Computers</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>
</li>
{% if current_user.admin %}
<li class="nav-item">
<a class="nav-link active" href="">Admin</a>
</li>
{% endif %}
</ul>
<form class="d-flex" role="search">
<a class="btn btn-outline-warning" type="submit" href="{{ url_for('auth.logout') }}">logout</a>
</form>
</div>
</div>
</nav>
+5
View File
@@ -0,0 +1,5 @@
{% extends 'panel/_base.html' %}
{% block content %}
{% include 'panel/_nav.html' %}
{% endblock %}
+32
View File
@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<!-- BASE -->
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Takeus - {{HTTP_ERROR[0]}} Error</title>
<meta name="author" content="Takeus">
<meta name="copyright" content="Takeus 2024">
<!-- CSS/LINKS -->
<link rel="icon" type="image/png" href="{{ url_for('static',filename='/img/logo.png') }}" />
<link rel="stylesheet" href="https://bootswatch.com/5/zephyr/bootstrap.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" />
</head>
<body>
<div class="px-4 pt-5 my-5 text-center">
<h1 class="display-4 fw-bold">{{HTTP_ERROR[0]}} <u>{{HTTP_ERROR[1]}}</u></h1>
<div class="col-lg-6 mx-auto">
<p class="lead mb-4">{{HTTP_ERROR[2]}}</p>
{% if HTTP_ERROR[0] != "503" %}
<div class="d-grid gap-2 d-sm-flex justify-content-sm-center mb-5">
<a type="button" class="btn btn-primary btn-lg px-4 me-sm-3" href="/">Home</a>
<button type="button" class="btn btn-outline-secondary btn-lg px-4" onclick="location.reload();">Reload</button>
</div>
{% endif %}
</div>
<div class="container px-5">
<img src="{{HTTP_ERROR[3]}}" class="img-fluid" alt="403" loading="lazy" width="300">
</div>
</div>
</body>
</html>