First version with web gui

This commit is contained in:
2020-02-21 08:42:29 +01:00
parent fb54505a40
commit 609d821501
27 changed files with 1298 additions and 36 deletions
+275
View File
@@ -0,0 +1,275 @@
#!/usr/bin/python3
from flask import Flask, url_for, render_template, request, Response,redirect,make_response
import os
import jinja2
import requests
import hashlib #SHA256
import json
import base64
import configparser
from datetime import datetime
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
BUILD=1
APIC_VER=2
# Load config to comunicate with API or use default
try:
config = configparser.ConfigParser()
config.read(os.path.relpath('..\\client\\configpcm.ini'))
c_server = config['General']['server']
except:
c_server = "https://127.0.0.1:3333" #Default server api address
app = Flask(__name__,static_url_path="/assets", static_folder='assets', template_folder="templates")
def returnvalueapi(suburl,field="Name"):
global c_server
passha256=request.cookies.get('admin_logued')
if 'Password=' in suburl:
twopart = ""
elif '?' in suburl:
twopart = '&Password='+str(passha256)
else:
twopart = '?Password='+str(passha256)
r=(requests.post(c_server+suburl+twopart, verify=False).text).replace("\'", "\"").replace('\\"',"'").replace(': None',': "None"')
try:
#print(suburl+twopart+"->"+r)
jsonobj = json.loads(r)
return jsonobj[field]
except:
print('Error: '+str(r))
return str({'TEXT':r,'RESULT':'ERROR'})
def returnTable(suburl,field=["Name"]):
global c_server
passha256=request.cookies.get('admin_logued')
if isinstance(field,str):
if field != 'ASIS': # Do not touch if it says that we have to return table AS IS
field=[field] # Convert to list
if 'Password=' in suburl:
twopart = ""
elif '?' in suburl:
twopart = '&Password='+str(passha256)
else:
twopart= '?Password='+str(passha256)
try:
r=(requests.post(c_server+suburl+twopart, verify=False).text).replace("\'", "\"").replace('\\"',"'").replace(': None',': "None"')
jsonobj = json.loads(r)
if field == 'ASIS':
return jsonobj
else:
listitems = []
for ite in jsonobj: # Run in array from json
to = []
for i in field:
to.append(str(ite[i]))
listitems.append(to)
return listitems
except:
return None
@app.route("/admin",methods=['GET'])
@app.route("/admin/",methods=['GET'])
def pAdminIndex(): #Admin Index page
if returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE') != '0':
return render_template('/login.tmpl', title="Login")
table = returnTable("/get/computers",['ID_C','Name','RAM','CPUName','SOVersion','SOCaption','HDD','LastConnection','RAMFree'])
for lista in table:
lista.append(returnTable("/get/groups?ComputerID="+lista[0],["Name"])) #lista[9]¿
if lista[6] is not None:
try:
lista[6]=json.loads(base64.b64decode(lista[6]).decode('UTF-8'))
except:
lista[6]=json.loads(str("{}"))
else:
lista[6]=json.loads(str("{}"))
#print (lista[6])
try:
lista[7] = datetime.fromtimestamp(int(lista[7])).strftime('%Y-%m-%d %H:%M:%S') # LastConnection
except:
lista[7] = "Never"
return render_template('/adminindex.tmpl', title="Admin Dashboard",tablecomputers=table)
@app.route("/admin/addcomputer",methods=['GET'])
def pAdminAddcomputer():
computeradd=request.args.get('computeradd')
if computeradd is not None:
r = returnvalueapi("/add/computer?ComputerName="+computeradd,field="RESULT")
if r == "OK":
return redirect('/admin')
else:
return "ERROR"
else:
return redirect('/admin')
@app.route("/admin/delcomputer",methods=['GET'])
def pAdminDelcomputer():
computerdel=request.args.get('computerdel')
r = returnvalueapi("/del/computer?ComputerID="+computerdel,field="RESULT")
if r == "OK":
return redirect('/admin')
else:
return "ERROR"
@app.route("/admin/computer",methods=['GET'])
def pAdminComputer(): #Admin see one group
if returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE') != '0':
return render_template('/login.tmpl', title="Login")
computerid=request.args.get('ID_C')
if computerid is not None and computerid.isnumeric():
computername = returnvalueapi('/get/computers?ComputerID='+str(computerid),"Name")
groups = returnTable("/get/groups?ComputerName="+str(computername),['ID_G','Name'])
#####IT DOESNT HAVE TEMPLATE CREATED
return render_template('/admincomputer.tmpl', title="Computer "+computername,computerid=computerid,computername=computername,groups=groups)
return redirect('/admin')
@app.route("/admin/groups",methods=['GET'])
def pAdminGroups(): #Admin Index groups
if returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE') != '0':
return render_template('/login.tmpl', title="Login")
table = returnTable("/get/groups",['ID_G','Name'])
for lista in table:
lista.append(returnTable("/get/computersgrp?GroupID="+lista[0],['ID_C','Name'])) #lista[3]¿
lista.append(returnTable("/get/cookgrp?GroupID="+lista[0],['CookName'])) #lista[4]¿
return render_template('/admingroups.tmpl', title="Groups",tablegroups=table)
@app.route("/admin/group",methods=['GET'])
def pAdminGroup(): #Admin see one group
if returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE') != '0':
return render_template('/login.tmpl', title="Login")
groupid=request.args.get('ID_G')
if groupid is not None and groupid.isnumeric():
groupname=returnvalueapi('/get/groups?GroupID='+str(groupid),"Name")
computers = returnTable("/get/computers",['ID_C','Name'])
datagroup = (returnTable("/get/computersgrp?GroupID="+groupid,['ID_C','Name'])) #lista[0]¿
tem = (returnTable("/get/cookgrp?GroupID="+groupid,['CookName'])) #lista[1]¿
cooksdata = []
for cook in tem:
to = []
to.append(cook[0])
to.append(returnvalueapi('/get/lastrevisioncook?CookName='+cook[0],"Revision"))
to.append(returnTable("/get/statuscook?CookName="+cook[0],'ASIS'))
cooksdata.append(to)
tem = (returnTable("/get/cookall",'ASIS')) #Lista de todas las recetas
allcooks = []
for cook in tem['CookName']:
to = []
to.append(cook)
to.append(returnvalueapi('/get/lastrevisioncook?CookName='+cook,"Revision"))
allcooks.append(to)
return render_template('/admingroup.tmpl', title="Group "+groupname,groupname=groupname,groupid=groupid,datagroup=datagroup,cooksdata=cooksdata,computers=computers,allcooks=allcooks)
return redirect('/admin/groups')
@app.route("/admin/group/addcook",methods=['GET'])
def pAdminGroupAddcook(): #Add cook form enter
cooktoadd=request.args.get('cooknameadd')
groupid=request.args.get('groupid')
if cooktoadd != None and groupid != None:
r = returnvalueapi("/add/cookgrp?CookName="+cooktoadd+"&GroupID="+groupid,field="RESULT")
if r == "OK":
return redirect('/admin/group?ID_G='+groupid)
@app.route("/admin/group/addcomputer",methods=['GET'])
def pAdminGroupAddcomputer(): #Add computer form enter
computertoadd=request.args.get('computeridadd')
groupid=request.args.get('groupid')
if computertoadd != None and groupid != None:
r = returnvalueapi("/add/grpcomputer?ComputerID="+computertoadd+"&GroupID="+groupid,field="RESULT")
if r == "OK":
return redirect('/admin/group?ID_G='+groupid)
@app.route("/admin/group/delcomputer",methods=['GET'])
def pAdminGroupDelcomputer(): #Add computer form enter
computertodel=request.args.get('computernamedel')
groupid=request.args.get('groupid')
if computertodel != None and groupid != None:
r = returnvalueapi("/del/grpcomputer?ComputerName="+computertodel+"&GroupID="+groupid,field="RESULT")
if r == "OK":
return redirect('/admin/group?ID_G='+groupid)
else:
return redirect('/admin/group?ID_G='+groupid)
@app.route("/admin/cook",methods=['GET'])
def pAdminCook(): #Admin Index groups
if returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE') != '0':
return render_template('/login.tmpl', title="Login")
cookname=request.args.get('CookName')
if cookname != None:
groupscook=returnTable('/get/grpcook?CookName='+str(cookname),['Name'])
allgroups=returnTable('/get/groups',['ID_G','Name'])
return render_template('/admincook.tmpl', title="Cook "+cookname,cookname=cookname,allgroups=allgroups,groupscook=groupscook)
@app.route("/admin/cook/addgroup",methods=['GET'])
def pAdminCookAddgroup(): # Add cook to group
if returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE') != '0':
return render_template('/login.tmpl', title="Login")
cookname=request.args.get('cooknameadd')
groupid=request.args.get('groupidadd')
if cookname != None and groupid != None:
returnvalueapi('/add/cookgrp?CookName='+cookname+'&GroupID='+groupid,'RESULT')
return redirect('/admin/cook?CookName='+cookname)
else:
return "Error of arguments"
@app.route("/admin/cook/delgroup",methods=['GET'])
def pAdminCookDelgroup(): # Add cook to group
if returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE') != '0':
return render_template('/login.tmpl', title="Login")
cookname=request.args.get('cooknamedel')
groupname=request.args.get('groupnamedel')
if cookname != None and groupname != None:
ret = returnvalueapi('/del/cookgrp?CookName='+cookname+'&GroupName='+groupname,'RESULT')
if ret != '0':
return "Error "+str(ret)
return redirect('/admin/cook?CookName='+cookname)
else:
return "Error of arguments"
@app.route("/",methods=['GET'])
def pIndex(): #Index page
howispasswd=returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE')
if howispasswd == '0': # Logued
return redirect(url_for('pAdminIndex'))
if howispasswd == '1' or howispasswd == '2': # Has to login
return render_template('/login.tmpl')
if howispasswd == '3': # No password yet
return 'Yet to do it..'
@app.route("/login",methods=['GET','POST'])
def pLogin(): #Login
if request.values.get('password'):
trpass = hashlib.sha256(request.values.get('password').encode()).hexdigest()
#print(returnvalueapi('/check/password?Password='+trpass,'EXITCODE'))
if returnvalueapi('/check/password?Password='+trpass,'EXITCODE') == '0':
res = make_response(redirect(url_for('pAdminIndex')))
res.set_cookie("admin_logued",value=trpass)
return res
else:
return render_template('/login.tmpl')
else:
return render_template('/login.tmpl')
print("Build: "+str(BUILD))
print("API Client Compatible Version: "+str(APIC_VER))
app.run(debug=True,port=3434,ssl_context='adhoc',host='0.0.0.0',threaded=True) #Default is port 3434
File diff suppressed because one or more lines are too long
+93
View File
@@ -0,0 +1,93 @@
body {
font-size: .875rem;
}
.feather {
width: 16px;
height: 16px;
vertical-align: text-bottom;
}
/*
* Sidebar
*/
.sidebar {
position: fixed;
top: 0;
bottom: 0;
left: 0;
z-index: 100; /* Behind the navbar */
padding: 0;
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
}
.sidebar-sticky {
position: -webkit-sticky;
position: sticky;
top: 48px; /* Height of navbar */
height: calc(100vh - 48px);
padding-top: .5rem;
overflow-x: hidden;
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
}
.sidebar .nav-link {
font-weight: 500;
color: #333;
}
.sidebar .nav-link .feather {
margin-right: 4px;
color: #999;
}
.sidebar .nav-link.active {
color: #007bff;
}
.sidebar .nav-link:hover .feather,
.sidebar .nav-link.active .feather {
color: inherit;
}
.sidebar-heading {
font-size: .75rem;
text-transform: uppercase;
}
/*
* Navbar
*/
.navbar-brand {
padding-top: .75rem;
padding-bottom: .75rem;
font-size: 1rem;
background-color: rgba(0, 0, 0, .25);
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25);
}
.navbar .form-control {
padding: .75rem 1rem;
border-width: 0;
border-radius: 0;
}
.form-control-dark {
color: #fff;
background-color: rgba(255, 255, 255, .1);
border-color: rgba(255, 255, 255, .1);
}
.form-control-dark:focus {
border-color: transparent;
box-shadow: 0 0 0 3px rgba(255, 255, 255, .25);
}
/*
* Utilities
*/
.border-top { border-top: 1px solid #e5e5e5; }
.border-bottom { border-bottom: 1px solid #e5e5e5; }
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

+10
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+5
View File
File diff suppressed because one or more lines are too long
+32
View File
@@ -0,0 +1,32 @@
{# -*- coding: utf-8 -*- #} {# NOT DID ALREADY!!! #}
{% extends 'baseadmin.tmpl' %}
{% block content %}
<h2>Computer {{computername}}</h2>
<br>
<h2>Groups of {{computername}}</h2>
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>#</th>
<th>Group Name</th>
<th>Cooks</th>
<th></th>
</tr>
</thead>
<tbody>
{% for item in tablegroups %} {#['ID_G','Name','Cooks[CookName]']#}
<tr>
<td><a href="/admin/group?ID_G={{item.0}}">{{item.1}}</a></td>
<td style='width:50%;'>
{% for x in item.2 %}
{{x.0}},
{% endfor %}
</td>
<td><a class="btn btn-outline-danger btn-sm" data-wgroup="{{item.1}}" data-toggle="modal" data-target="#delGroup">Delete {{computername}} from group {{item.1}}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
<br>
{% endblock %}
+92
View File
@@ -0,0 +1,92 @@
{# -*- coding: utf-8 -*- #}
{% extends 'baseadmin.tmpl' %}
{% block content %}
<!-- Modal Delete Group From Cook -->
<div class="modal fade" id="modalDelete" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<form method="get" action="/admin/cook/delgroup">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Delete group from cook {{cookname}}</h5>
</div>
<div class="modal-body">
<div class="form-group">
<input type="text" readonly="readonly" class="form-control" hidden="hidden" name="cooknamedel" id="cooknamedel" value="{{cookname}}"/>
<p>Are you sure?<br>
<label for="groupnamedel" class="col-form-label">Group:</label>
</div>
<input type="text" readonly="readonly" class="form-control" name="groupnamedel" id="groupnamedel">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-danger">Remove</button>
</div>
</div>
</form>
</div>
</div>
<!-- Modal Add Group To Cook -->
<div class="modal fade" id="modalAdd" tabindex="-1" role="dialog" aria-labelledby="modalAddLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<form method="get" action="/admin/cook/addgroup">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalAddLabel">Add cook to Group {{groupname}}</h5>
</div>
<div class="modal-body">
<div class="form-group">
<p>Add group to cook {{cookname}}<br>
<input type="text" readonly="readonly" class="form-control" hidden="hidden" name="cooknameadd" id="cooknameadd" value="{{cookname}}"/>
<label for="groupidadd" class="col-form-label">Group:</label>
<select class="form-control" name="groupidadd" id="groupidadd">
{% for item in allgroups %}
<option value="{{item.0}}">{{item.1}}</option>
{% endfor %}
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Add</button>
</div>
</div>
</form>
</div>
</div>
<h2>Groups of cook {{cookname}}</h2>
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>#</th>
<th>Group Name</th>
<th style="align:right">Delete Group from this Cook</th>
</tr>
</thead>
<tbody>
{% for item in groupscook %} {#['Name']#}
<tr>
<td style='width:64px'>{{item.0}}</td>
<td><a href="/admin/group?ID_G={{item.0}}">{{item.0}}</a></td>
<td><a class="btn btn-outline-danger btn-sm" data-wgroup="{{item.0}}" data-toggle="modal" data-target="#modalDelete">Remove group {{item.0}} from cook {{cookname}}</a></td>
</tr>
{% endfor %}
<tr>
<td>#</td>
<td colspan="2"><a class="btn btn-outline-primary btn-sm" data-toggle="modal" data-target="#modalAdd">Add group to {{cookname}}</a></td>
</tbody>
</table>
</div>
<script>
$('#modalDelete').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget) // Button that triggered the modal
var recipient = button.data('wgroup') // Extract info from data-* attributes
var modal = $(this)
modal.find('#groupnamedel').val(recipient)
})
</script>
{% endblock %}
+150
View File
@@ -0,0 +1,150 @@
{# -*- coding: utf-8 -*- #}
{% extends 'baseadmin.tmpl' %}
{% block content %}
<!-- Modal Delete Computer From Group -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<form method="get" action="/admin/group/delcomputer">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Delete computer from Group {{groupname}}</h5>
</div>
<div class="modal-body">
<div class="form-group">
<input type="text" readonly="readonly" class="form-control" hidden="hidden" name="groupid" id="groupid" value="{{groupid}}"/>
<p>Are you sure?<br>
<label for="computername" class="col-form-label">Computer:</label>
</div>
<input type="text" readonly="readonly" class="form-control" name="computernamedel" id="computernamedel">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-danger">Delete</button>
</div>
</div>
</form>
</div>
</div>
<!-- Modal Add Computer To Group -->
<div class="modal fade" id="modalAdd" tabindex="-1" role="dialog" aria-labelledby="modalAddLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<form method="get" action="/admin/group/addcomputer">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalAddLabel">Add computer to Group {{groupname}}</h5>
</div>
<div class="modal-body">
<div class="form-group">
<p>Add computer to group {{groupname}}<br>
<input type="text" readonly="readonly" class="form-control" hidden="hidden" name="groupid" value="{{groupid}}"/>
<label for="computername2" class="col-form-label">Computer:</label>
<select class="form-control" name="computeridadd" id="computeridadd">
{% for item in computers %}
<option value="{{item.0}}">{{item.1}}</option>
{% endfor %}
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Add</button>
</div>
</div>
</form>
</div>
</div>
<!-- Modal Add Cook To Group -->
<div class="modal fade" id="modalAddCook" tabindex="-1" role="dialog" aria-labelledby="modalAddCookLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<form method="get" action="/admin/group/addcook">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalAddCookLabel">Add Cook to Group {{groupname}}</h5>
</div>
<div class="modal-body">
<div class="form-group">
<p>Add cook to group {{groupname}}<br>
<input type="text" readonly="readonly" class="form-control" hidden="hidden" name="groupid" value="{{groupid}}"/>
<label for="cookname" class="col-form-label">Cook name:</label>
<select class="form-control" name="cooknameadd" id="cooknameadd">
{% for item in allcooks %}
<option value="{{item.0}}">{{item.0}}</option>
{% endfor %}
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Add</button>
</div>
</div>
</form>
</div>
</div>
<h2>Computers of group {{groupname}}</h2>
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>#</th>
<th>Computer Name</th>
<th style="align:right">Delete computer from Group</th>
</tr>
</thead>
<tbody>
{% for item in datagroup %} {#['ID_C','Name']#}
<tr>
<td style='width:64px'>{{item.0}}</td>
<td><a href="/admin/computer?ID_C={{item.0}}">{{item.1}}</a></td>
<td><a class="btn btn-outline-danger btn-sm" {#href="/admin/groupcomputerdel?ID_C={{item.0}}&ID_G={{groupid}}"#} data-wcomputer="{{item.1}}" data-toggle="modal" data-target="#exampleModal">Delete {{item.1}} from group {{groupname}}</a></td>
</tr>
{% endfor %}
<tr>
<td>#</td>
<td colspan="2"><a class="btn btn-outline-primary btn-sm" data-toggle="modal" data-target="#modalAdd">Add computer to {{groupname}}</a></td>
</tbody>
</table>
</div>
<h2>Cooks of group {{groupname}}</h2>
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>Cook Name</th>
<th style="width:64px">Cook Last Revision</th>
<th>Applied to</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="3"><a class="btn btn-outline-primary btn-sm" data-toggle="modal" data-target="#modalAddCook">Add new cook to group {{groupname}}</a></td>
</tr>
{% for item in cooksdata %} {#['CookName','LastRevision','AppliedTo']#}
<tr>
<td><a href="/admin/cook?CookName={{item.0}}">{{item.0}}</a></td>
<td>{{item.1}}</td>
<td>
{% for subitem in item.2|sort(attribute='Revision')|sort(attribute='Name') %} {# item.2 = AppliedTo #}
{{subitem.Name}}{% if subitem.Revision|int < item.1|int %}<span style="color:red">({{subitem.Revision}})</span>{% elif subitem.Error != 0 %}<span style="color:orange;font-weigth:bold;font-style:italic" title="{{subitem.ErrorDesc}}">(Error r.{{subitem.Revision}})</span>{% endif %},
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
<script>
$('#exampleModal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget) // Button that triggered the modal
var recipient = button.data('wcomputer') // Extract info from data-* attributes
var modal = $(this)
//modal.find('.modal-title').text('New message to ' + recipient)
modal.find('#computernamedel').val(recipient)
})
</script>
{% endblock %}
+35
View File
@@ -0,0 +1,35 @@
{# -*- coding: utf-8 -*- #}
{% extends 'baseadmin.tmpl' %}
{% block content %}
<h2>Groups</h2>
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>#</th>
<th>Group Name</th>
<th>Cooks</th>
<th>Computers</th>
</tr>
</thead>
<tbody>
{% for item in tablegroups %} {#['ID_G','Name','Computers[ID_C,Name]','Cooks[CookName]']#}
<tr>
<td>{{item.0}}</td>
<td><a href="/admin/group?ID_G={{item.0}}">{{item.1}}</a></td>
<td style='width:50%;'>
{% for x in item.3 %}
{{x.0}},
{% endfor %}
</td>
<td>
{% for x in item.2 %}
{{x.1}},
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
+102
View File
@@ -0,0 +1,102 @@
{# -*- coding: utf-8 -*- #}
{% extends 'baseadmin.tmpl' %}
{% block content %}
<!-- Modal Add Computer To Database -->
<div class="modal fade" id="modalAdd" tabindex="-1" role="dialog" aria-labelledby="modalAddLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<form method="get" action="/admin/addcomputer">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalAddLabel">Add computer to Database</h5>
</div>
<div class="modal-body">
<div class="form-group">
<p>Add computer to database<br>
<label for="computeradd" class="col-form-label">Computer:</label>
<input name="computeradd" id="computeradd" type="text"/>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Add</button>
</div>
</div>
</form>
</div>
</div>
<!-- Modal Delete Computer To Database -->
<div class="modal fade" id="modalDel" tabindex="-1" role="dialog" aria-labelledby="modalDelLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<form method="get" action="/admin/delcomputer">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalDelLabel">Delete computer to Database. NOT REVERSIBLE</h5>
</div>
<div class="modal-body">
<div class="form-group">
<p>Delete computer from database. NOT REVERSIBLE<br>
<label for="computerdel" class="col-form-label">Computer:</label>
<select class="form-control" name="computerdel" id="computerdel">
{% for item in tablecomputers %} {#['ID_C','Name',.....]#}
<option value="{{item.0}}">{{item.1}}</option>
{% endfor %}
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-danger">DELETE</button>
</div>
</div>
</form>
</div>
</div>
<h2>Computers</h2>
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>#</th>
<th>Computer</th>
<th>Operating System</th>
<th>Groups</th>
<th>CPU</th>
<th>RAM (RAMUsed/RAM) Mb</th>
<th>HDD</th>
<th>Last ping</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="8"><a class="btn btn-outline-success btn-sm" data-toggle="modal" data-target="#modalAdd">Add computer to database</a></td>
</tr>
{% for item in tablecomputers %} {#['ID_C','Name','RAM','CPUName','SOVersion','SOCaption','HDD','LastConnection','RamFree','GroupsNames']#}
<tr>
<td>{{item.0}}</td>
<td>{{item.1}}</td>
<td>{{item.5}} {{item.4}}</td>
<td width='200px'>
{% for x in item.9 %}
{{x.0}},
{% endfor %}
</td>
<td>{{item.3}}</td>
<td>{{item.2|int - item.8|int}}/{{item.2}}</td>
<td>
{% for x in item.6 %}
{{x.Volume}}({{x.FreeSpace}}/{{x.Capacity}} GB)<br>
{% endfor %}
</td>
<td>{{item.7}}</td>
</tr>
{% endfor %}
<tr>
<td colspan="8"><a class="btn btn-outline-danger btn-sm" data-toggle="modal" data-target="#modalDel">Delete computer to database</a></td>
</tr>
</tbody>
</table>
</div>
{% endblock %}
+84
View File
@@ -0,0 +1,84 @@
{# -*- coding: utf-8 -*- #}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<!--<link rel="icon" href="/docs/4.0/assets/img/favicons/favicon.ico">-->
<title>{{title}} - Powerful Computer Manager</title>
<link rel="canonical" href="index.html">
<!-- Bootstrap core CSS -->
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="{{ url_for('static', filename='css/dashboard.css') }}" rel="stylesheet">
<!-- Jquery JS -->
<script src="{{ url_for('static', filename='js/jquery-3.2.1.slim.min.js') }}"></script>
</head>
<body>
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0">
<a class="navbar-brand col-sm-3 col-md-2 mr-0" href="#">Company name</a>
<input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
<ul class="navbar-nav px-3">
<li class="nav-item text-nowrap">
<a class="nav-link" href="#">Sign out</a>
</li>
</ul>
</nav>
<div class="container-fluid">
<div class="row">
<nav class="col-md-2 d-none d-md-block bg-light sidebar">
<div class="sidebar-sticky pt-4">
<ul class="nav flex-column pt-4">
<li class="nav-item">
<a class="nav-link {% if request.path == "/admin/" or request.path == "/admin" %}active{% endif %}" href="/admin">
<span data-feather="home"></span>
Dashboard
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.path == "/admin/groups" or request.path == "/admin/group" %}active{% endif %}" href="/admin/groups">
<span data-feather="file"></span>
Groups
</a>
</li>
</ul>
</div>
</nav>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom">
<h1 class="h2">{{title}}</h1>
<div class="btn-toolbar mb-2 mb-md-0">
</div>
</div>
{% block content %}{% endblock %}
</main>
</div>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="{{ url_for('static', filename='js/popper.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script>
<!-- Icons -->
<script src="{{ url_for('static', filename='js/feather-4.24.1.min.js') }}"></script>
<script>
feather.replace()
</script>
<!-- Graphs -->
{% block scripts %}{% endblock %}
</body>
</html>
+17
View File
@@ -0,0 +1,17 @@
{# -*- coding: utf-8 -*- #}
{% extends 'baseadmin.tmpl' %}
{% block content %}
<h2>Login</h2>
<form action="/login" method="POST">
<div class="table-responsive">
<table class="table table-striped table-sm">
<tr>
<td>Password<input type="password" name="password" id="password" /></td>
</tr>
<tr>
<td><button type="submit">Login</button></td>
</tr>
</table>
</div>
</form>
{% endblock %}
+304
View File
@@ -0,0 +1,304 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="/docs/4.0/assets/img/favicons/favicon.ico">
<title>Dashboard Template for Bootstrap</title>
<link rel="canonical" href="index.html">
<!-- Bootstrap core CSS -->
<link href="../../admin/assets/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="../../admin/assets/css/dashboard.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0">
<a class="navbar-brand col-sm-3 col-md-2 mr-0" href="#">Company name</a>
<input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
<ul class="navbar-nav px-3">
<li class="nav-item text-nowrap">
<a class="nav-link" href="#">Sign out</a>
</li>
</ul>
</nav>
<div class="container-fluid">
<div class="row">
<nav class="col-md-2 d-none d-md-block bg-light sidebar">
<div class="sidebar-sticky">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" href="#">
<span data-feather="home"></span>
Dashboard <span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<span data-feather="file"></span>
Orders
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<span data-feather="shopping-cart"></span>
Products
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<span data-feather="users"></span>
Customers
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<span data-feather="bar-chart-2"></span>
Reports
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<span data-feather="layers"></span>
Integrations
</a>
</li>
</ul>
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
<span>Saved reports</span>
<a class="d-flex align-items-center text-muted" href="#">
<span data-feather="plus-circle"></span>
</a>
</h6>
<ul class="nav flex-column mb-2">
<li class="nav-item">
<a class="nav-link" href="#">
<span data-feather="file-text"></span>
Current month
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<span data-feather="file-text"></span>
Last quarter
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<span data-feather="file-text"></span>
Social engagement
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<span data-feather="file-text"></span>
Year-end sale
</a>
</li>
</ul>
</div>
</nav>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom">
<h1 class="h2">Dashboard</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<div class="btn-group mr-2">
<button class="btn btn-sm btn-outline-secondary">Share</button>
<button class="btn btn-sm btn-outline-secondary">Export</button>
</div>
<button class="btn btn-sm btn-outline-secondary dropdown-toggle">
<span data-feather="calendar"></span>
This week
</button>
</div>
</div>
<canvas class="my-4" id="myChart" width="900" height="380"></canvas>
<h2>Section title</h2>
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>#</th>
<th>Header</th>
<th>Header</th>
<th>Header</th>
<th>Header</th>
</tr>
</thead>
<tbody>
<tr>
<td>1,001</td>
<td>Lorem</td>
<td>ipsum</td>
<td>dolor</td>
<td>sit</td>
</tr>
<tr>
<td>1,002</td>
<td>amet</td>
<td>consectetur</td>
<td>adipiscing</td>
<td>elit</td>
</tr>
<tr>
<td>1,003</td>
<td>Integer</td>
<td>nec</td>
<td>odio</td>
<td>Praesent</td>
</tr>
<tr>
<td>1,003</td>
<td>libero</td>
<td>Sed</td>
<td>cursus</td>
<td>ante</td>
</tr>
<tr>
<td>1,004</td>
<td>dapibus</td>
<td>diam</td>
<td>Sed</td>
<td>nisi</td>
</tr>
<tr>
<td>1,005</td>
<td>Nulla</td>
<td>quis</td>
<td>sem</td>
<td>at</td>
</tr>
<tr>
<td>1,006</td>
<td>nibh</td>
<td>elementum</td>
<td>imperdiet</td>
<td>Duis</td>
</tr>
<tr>
<td>1,007</td>
<td>sagittis</td>
<td>ipsum</td>
<td>Praesent</td>
<td>mauris</td>
</tr>
<tr>
<td>1,008</td>
<td>Fusce</td>
<td>nec</td>
<td>tellus</td>
<td>sed</td>
</tr>
<tr>
<td>1,009</td>
<td>augue</td>
<td>semper</td>
<td>porta</td>
<td>Mauris</td>
</tr>
<tr>
<td>1,010</td>
<td>massa</td>
<td>Vestibulum</td>
<td>lacinia</td>
<td>arcu</td>
</tr>
<tr>
<td>1,011</td>
<td>eget</td>
<td>nulla</td>
<td>Class</td>
<td>aptent</td>
</tr>
<tr>
<td>1,012</td>
<td>taciti</td>
<td>sociosqu</td>
<td>ad</td>
<td>litora</td>
</tr>
<tr>
<td>1,013</td>
<td>torquent</td>
<td>per</td>
<td>conubia</td>
<td>nostra</td>
</tr>
<tr>
<td>1,014</td>
<td>per</td>
<td>inceptos</td>
<td>himenaeos</td>
<td>Curabitur</td>
</tr>
<tr>
<td>1,015</td>
<td>sodales</td>
<td>ligula</td>
<td>in</td>
<td>libero</td>
</tr>
</tbody>
</table>
</div>
</main>
</div>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="../../admin/assets/js/jquery-3.2.1.slim.min.js"></script>
<script src="../../admin/assets/js/popper.min.js"></script>
<script src="../../admin/assets/js/bootstrap.min.js"></script>
<!-- Icons -->
<script src="../../admin/assets/js/feather-4.24.1.min.js"></script>
<script>
feather.replace()
</script>
<!-- Graphs -->
<script src="../../admin/assets/js/Chart.min.js"></script>
<script>
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
datasets: [{
data: [15339, 21345, 18483, 24003, 23489, 24092, 12034],
lineTension: 0,
backgroundColor: 'transparent',
borderColor: '#007bff',
borderWidth: 4,
pointBackgroundColor: '#007bff'
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: false
}
}]
},
legend: {
display: false,
}
}
});
</script>
</body>
</html>