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
admin/admin.py Normal file
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

7
admin/assets/css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

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
admin/assets/js/Chart.min.js vendored Normal file

File diff suppressed because one or more lines are too long

7
admin/assets/js/bootstrap.min.js vendored Normal file

File diff suppressed because one or more lines are too long

13
admin/assets/js/feather-4.24.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

5
admin/assets/js/popper.min.js vendored Normal file

File diff suppressed because one or more lines are too long

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 %}

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 %}

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 %}

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 %}

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 %}

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>

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
admin/templates/test.html Normal file
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>