Bugs:
Fixed Firmware download from the Mikrotik website when there are multiple npk available Fixed Mikrowizard system permission error when it is set to None Fixed user device group permissions Some minor UI improvements Fix IP scan for one IP scan / Fix not scanning the last IP in the range Fix manual snippet execution not working when device groups are selected Some minor bug fixes and improvements New: Show background tasks and be able to stop them while running in the background (like an IP scanner) Add support for manual MikroWizard update dashboard/settings page update to version 1.0.5 Enhancement: Show permission error in some pages when the user doesn't have permission for that page/action show better charts/graphs in the dashboard and device interface details show more info on the dashboard about update and version information and license
This commit is contained in:
parent
a26bd6ae55
commit
70dc0ddc55
15 changed files with 296 additions and 63 deletions
|
|
@ -120,11 +120,15 @@ def save_editform():
|
|||
@login_required(role='admin',perm={'device_group':'read'})
|
||||
def list_devgroups():
|
||||
"""return dev groups"""
|
||||
|
||||
# build HTML of the method list
|
||||
devs = []
|
||||
uid=session.get("userid") or False
|
||||
try:
|
||||
devs=list(db_groups.query_groups_api())
|
||||
perms=list(db_user_group_perm.DevUserGroupPermRel.get_user_group_perms(uid))
|
||||
group_ids = [perm.group_id for perm in perms]
|
||||
if str(uid) == "37cc36e0-afec-4545-9219-94655805868b":
|
||||
group_ids=False
|
||||
devs=list(db_groups.query_groups_api(group_ids))
|
||||
except Exception as e:
|
||||
return buildResponse({'result':'failed','err':str(e)},200)
|
||||
return buildResponse(devs,200)
|
||||
|
|
@ -468,8 +472,8 @@ def dev_ifstat():
|
|||
|
||||
temp=[]
|
||||
ids=['yA','yB']
|
||||
colors=['#17522f','#171951']
|
||||
|
||||
colors=['#4caf50','#ff9800']
|
||||
bgcolor=['rgba(76, 175, 80, 0.2)','rgba(255, 152, 0, 0.2)']
|
||||
datasets=[]
|
||||
lables=[]
|
||||
tz=db_sysconfig.get_sysconfig('timezone')
|
||||
|
|
@ -482,9 +486,9 @@ def dev_ifstat():
|
|||
for d in data[val]:
|
||||
if len(lables) <= len(data[val]):
|
||||
edatetime=datetime.datetime.fromtimestamp(d[0]/1000)
|
||||
lables.append(util.utc2local(edatetime,tz=tz).strftime("%m/%d/%Y, %H:%M:%S %Z"))
|
||||
lables.append(util.utc2local(edatetime,tz=tz).strftime("%Y-%m-%d %H:%M:%S"))
|
||||
temp.append(round(d[1],1))
|
||||
datasets.append({'label':val,'borderColor': colors[idx],'type': 'line','yAxisID': ids[idx],'data':temp,'unit':val.split("-")[0],'backgroundColor': colors[idx],'pointHoverBackgroundColor': '#fff'})
|
||||
datasets.append({'label':val,'borderColor': colors[idx],'type': 'line','yAxisID': ids[idx],'data':temp,'unit':val.split("-")[0],'backgroundColor': bgcolor[idx],'pointHoverBackgroundColor': '#fff','fill': True})
|
||||
temp=[]
|
||||
res["data"]={'labels':lables,'datasets':datasets}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
from flask import request
|
||||
import datetime
|
||||
|
||||
from libs.db import db,db_syslog,db_device,db_AA,db_events,db_sysconfig
|
||||
from libs.db import db,db_syslog,db_device,db_AA,db_events,db_sysconfig,db_tasks
|
||||
from libs.webutil import app,buildResponse,login_required
|
||||
import logging
|
||||
import operator
|
||||
|
|
@ -306,6 +306,7 @@ def dashboard_stats():
|
|||
"""return dashboard data"""
|
||||
input = request.json
|
||||
versioncheck = input.get('versioncheck',False)
|
||||
front_version = input.get('front_version',False)
|
||||
VERSIONFILE="_version.py"
|
||||
from _version import __version__
|
||||
res={}
|
||||
|
|
@ -342,13 +343,15 @@ def dashboard_stats():
|
|||
res['Devices']=devs.select().count()
|
||||
res['Auth']=auth.select().count()
|
||||
res['Acc']=acc.select().count()
|
||||
res['Registred']=False
|
||||
res['license']=False
|
||||
username=False
|
||||
internet_connection=True
|
||||
# check for internet connection before getting data from website
|
||||
feedurl="https://mikrowizard.com/tag/Blog/feed/?orderby=latest"
|
||||
test_url="https://google.com"
|
||||
update_mode=db_sysconfig.get_sysconfig('update_mode')
|
||||
update_mode=json.loads(update_mode)
|
||||
res['update_mode']=update_mode['mode']
|
||||
try:
|
||||
req = requests.get(test_url, timeout=(0.5,1))
|
||||
req.raise_for_status()
|
||||
|
|
@ -371,11 +374,32 @@ def dashboard_stats():
|
|||
if internet_connection:
|
||||
response = requests.post(url, json=params)
|
||||
response=response.json()
|
||||
# log.error(response)
|
||||
res['license']=response.get('license',False)
|
||||
res['update_available']=response.get('available',False)
|
||||
res['latest_version']=response.get('latest_version',False)
|
||||
res['update_inprogress']=update_mode['update_back']
|
||||
else:
|
||||
res['license']='connection_error'
|
||||
res['update_available']=False
|
||||
res['latest_version']=False
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
if front_version and internet_connection:
|
||||
params['version']=front_version
|
||||
params['front']=True
|
||||
response = requests.post(url, json=params)
|
||||
response=response.json()
|
||||
res['front_update_available']=response.get('available',False)
|
||||
res['front_latest_version']=response.get('latest_version',False)
|
||||
res['front_update_inprogress']=update_mode['update_front']
|
||||
except:
|
||||
pass
|
||||
except:
|
||||
pass
|
||||
res['front_update_available']=True
|
||||
res['update_available']=True
|
||||
if username:
|
||||
res['username']=username
|
||||
res['blog']=[]
|
||||
|
|
@ -410,11 +434,12 @@ def dashboard_stats():
|
|||
def get_version():
|
||||
"""return version info and serial in crypted format for front updater service"""
|
||||
VERSIONFILE="_version.py"
|
||||
log.error("front_update_request")
|
||||
from _version import __version__
|
||||
res={}
|
||||
res['version']=__version__
|
||||
try:
|
||||
res['username']=username = db_sysconfig.get_sysconfig('username')
|
||||
res['username']=db_sysconfig.get_sysconfig('username')
|
||||
except:
|
||||
res['username']=False
|
||||
interfaces = util.get_ethernet_wifi_interfaces()
|
||||
|
|
@ -424,10 +449,21 @@ def get_version():
|
|||
install_date=db_sysconfig.get_sysconfig('install_date')
|
||||
except:
|
||||
pass
|
||||
update_mode=db_sysconfig.get_sysconfig('update_mode')
|
||||
update_mode=json.loads(update_mode)
|
||||
if install_date:
|
||||
res['serial']=hwid + "-" + datetime.datetime.strptime(install_date, "%Y-%m-%d %H:%M:%S").strftime("%Y%m%d")
|
||||
if update_mode['mode']=='manual':
|
||||
if not update_mode['update_front']:
|
||||
hwid=hwid+"MANUAL"
|
||||
else:
|
||||
update_mode['update_front']=False
|
||||
db_sysconfig.set_sysconfig('update_mode',json.dumps(update_mode))
|
||||
res['serial'] = hwid + "-" + datetime.datetime.strptime(install_date, "%Y-%m-%d %H:%M:%S").strftime("%Y%m%d")
|
||||
if update_mode=='update_now':
|
||||
db_sysconfig.update_sysconfig('update_mode','manual')
|
||||
else:
|
||||
res['serial']=False
|
||||
log.error(res)
|
||||
res=util.crypt_data(json.dumps(res))
|
||||
return buildResponse(res, 200)
|
||||
|
||||
|
|
@ -477,8 +513,8 @@ def dashboard_traffic():
|
|||
|
||||
temp=[]
|
||||
ids=['yA','yB']
|
||||
colors=['#17522f','#171951']
|
||||
|
||||
colors=['#4caf50','#ff9800']
|
||||
bgcolor=['rgba(76, 175, 80, 0.2)','rgba(255, 152, 0, 0.2)']
|
||||
datasets=[]
|
||||
lables=[]
|
||||
data_keys=['tx-{}'.format(interface),'rx-{}'.format(interface)]
|
||||
|
|
@ -491,7 +527,7 @@ def dashboard_traffic():
|
|||
if len(lables) <= len(data[val]):
|
||||
lables.append(datetime.datetime.fromtimestamp(d[0]/1000))
|
||||
temp.append(round(d[1],1))
|
||||
datasets.append({'label':val,'borderColor': colors[idx],'type': 'line','yAxisID': ids[idx],'data':temp,'unit':val.split("-")[0],'backgroundColor': colors[idx],'pointHoverBackgroundColor': '#fff'})
|
||||
datasets.append({'label':val,'borderColor': colors[idx],'type': 'line','yAxisID': ids[idx],'data':temp,'unit':val.split("-")[0],'backgroundColor': bgcolor[idx],'pointHoverBackgroundColor': '#fff','fill': True})
|
||||
temp=[]
|
||||
res["data"]={'labels':lables,'datasets':datasets}
|
||||
|
||||
|
|
@ -499,4 +535,17 @@ def dashboard_traffic():
|
|||
log.error(e)
|
||||
return buildResponse({'status': 'failed'}, 200, error=e)
|
||||
pass
|
||||
return buildResponse(res,200)
|
||||
return buildResponse(res,200)
|
||||
|
||||
@app.route('/api/dashboard/tasks/running', methods = ['POST'])
|
||||
@login_required(role='admin', perm={'settings':'read'})
|
||||
def dashboard_tasks_running():
|
||||
"""return all running tasks"""
|
||||
input = request.json
|
||||
tasks=db_tasks.Tasks
|
||||
try:
|
||||
res=tasks.select().where(tasks.status=='running').dicts()
|
||||
except Exception as e:
|
||||
log.error(e)
|
||||
return buildResponse({'status': 'failed'}, 200, error=e)
|
||||
return buildResponse(res,200)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from flask import request,session
|
|||
|
||||
from libs.db import db_user_tasks,db_syslog,db_tasks,db_sysconfig
|
||||
from libs.webutil import app, login_required,buildResponse,get_myself,get_ip,get_agent
|
||||
from libs.db.db_groups import devs, get_devs_of_groups
|
||||
from functools import reduce
|
||||
import bgtasks
|
||||
import operator
|
||||
|
|
@ -117,8 +118,17 @@ def exec_snippet():
|
|||
return buildResponse({'status': 'failed'},200,error="Wrong name/desc")
|
||||
#check if cron is valid and correct
|
||||
taskdata={}
|
||||
taskdata['memebrs']=members
|
||||
taskdata['owner']=members
|
||||
if selection_type=="devices":
|
||||
taskdata['memebrs']=members
|
||||
elif selection_type=="groups":
|
||||
devs=get_devs_of_groups(members)
|
||||
devids=[dev.id for dev in devs]
|
||||
taskdata['memebrs']=devids
|
||||
uid = session.get("userid") or False
|
||||
if not uid:
|
||||
return buildResponse({'result':'failed','err':"No User"}, 200)
|
||||
taskdata['owner']=str(uid)
|
||||
default_ip=db_sysconfig.get_sysconfig('default_ip')
|
||||
snipet=db_user_tasks.get_snippet(snippetid)
|
||||
if snipet:
|
||||
taskdata['snippet']={'id':snipet.id,'code':snipet.content,'description':snipet.description,'name':snipet.name}
|
||||
|
|
@ -144,12 +154,8 @@ def exec_snippet():
|
|||
}
|
||||
task=utasks.create(**data)
|
||||
status=db_tasks.exec_snipet_status().status
|
||||
uid = session.get("userid") or False
|
||||
default_ip=db_sysconfig.get_sysconfig('default_ip')
|
||||
if not uid:
|
||||
return buildResponse({'result':'failed','err':"No User"}, 200)
|
||||
if not status:
|
||||
bgtasks.exec_snipet(task=task,default_ip=default_ip,devices=members,uid=uid)
|
||||
bgtasks.exec_snipet(task=task,default_ip=default_ip,devices=taskdata['memebrs'],uid=uid)
|
||||
res={'status': True}
|
||||
else:
|
||||
res={'status': status}
|
||||
|
|
@ -158,8 +164,7 @@ def exec_snippet():
|
|||
return buildResponse([{'status': 'success'}],200)
|
||||
except Exception as e:
|
||||
log.error(e)
|
||||
return buildResponse({'status': 'failed','massage':str(e)},200)
|
||||
|
||||
return buildResponse({'status': 'failed','massage':str(e)},200)
|
||||
|
||||
@app.route('/api/snippet/executed', methods = ['POST'])
|
||||
@login_required(role='admin',perm={'task':'write'})
|
||||
|
|
|
|||
|
|
@ -6,13 +6,16 @@
|
|||
# Author: sepehr.ha@gmail.com
|
||||
|
||||
from flask import request
|
||||
|
||||
from libs.db import db_sysconfig,db_syslog
|
||||
import uwsgi
|
||||
import signal
|
||||
import os
|
||||
from libs.db import db_sysconfig,db_syslog, db_tasks
|
||||
from libs import util
|
||||
from libs.webutil import app, login_required,buildResponse,get_myself,get_ip,get_agent
|
||||
import time
|
||||
import logging
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
log = logging.getLogger("api.sysconfig")
|
||||
|
||||
|
|
@ -44,8 +47,91 @@ def sysconfig_save_all():
|
|||
continue
|
||||
elif k=="default_password" or k=="default_user":
|
||||
v['value']=util.crypt_data(v['value'])
|
||||
elif k=="update_mode":
|
||||
v['value']=json.dumps(v['value'])
|
||||
data.append({"key":k,"value":v['value'],"modified":"NOW"})
|
||||
db_syslog.add_syslog_event(get_myself(), "Sys Config","Update", get_ip(),get_agent(),json.dumps(input))
|
||||
db_sysconfig.save_all(data)
|
||||
|
||||
return buildResponse({"status":"success"})
|
||||
|
||||
@app.route('/api/tasks/list', methods = ['POST'])
|
||||
@login_required(role='admin',perm={'settings':'read'})
|
||||
def tasks_list():
|
||||
"""get all tasks"""
|
||||
input = request.json
|
||||
res=[]
|
||||
res=db_tasks.get_all().dicts()
|
||||
for t in res:
|
||||
t['name']=t['name'].replace("-"," ").replace("_"," ")
|
||||
return buildResponse({"tasks":res})
|
||||
|
||||
@app.route('/api/tasks/stop', methods = ['POST'])
|
||||
@login_required(role='admin',perm={'settings':'write'})
|
||||
def stop_task():
|
||||
"""get all tasks"""
|
||||
input = request.json
|
||||
task_signal = int(input['signal'])
|
||||
task=db_tasks.get_task_by_signal(task_signal)
|
||||
res=[]
|
||||
#remove spooler file to stop task
|
||||
#list files under directory
|
||||
if not task:
|
||||
return buildResponse({'result':'failed','err':"No task"}, 200)
|
||||
spooldir=uwsgi.opt['spooler'].decode()+'/'+str(task_signal)
|
||||
#list all files and remove them in spooldir
|
||||
files = []
|
||||
try:
|
||||
if os.path.exists(spooldir):
|
||||
for file in os.listdir(spooldir):
|
||||
file_path = os.path.join(spooldir, file)
|
||||
if os.path.isfile(file_path):
|
||||
os.remove(file_path)
|
||||
files.append(file)
|
||||
except Exception as e:
|
||||
log.error(f"Error removing spool files: {str(e)}")
|
||||
return buildResponse({'result':'failed','err':str(e)}, 200)
|
||||
pid=uwsgi.spooler_pid()
|
||||
#kill pid to stop task
|
||||
if task_signal not in [130,140]:
|
||||
try:
|
||||
os.kill(pid, signal.SIGTERM) # Attempt graceful shutdown
|
||||
except ProcessLookupError:
|
||||
return buildResponse({'result':'failed','err':'Spooler not running'}, 200)
|
||||
except PermissionError:
|
||||
return buildResponse({'result':'failed','err':'Permission denied to reload spooler process'}, 200)
|
||||
except Exception as e:
|
||||
return buildResponse({'result':'failed','err':str(e)}, 200)
|
||||
else:
|
||||
task.action="cancel"
|
||||
task.status=False
|
||||
task.save()
|
||||
return buildResponse({"status":"success"})
|
||||
task.status=False
|
||||
task.action="None"
|
||||
task.save()
|
||||
return buildResponse({"status":"success"})
|
||||
|
||||
|
||||
|
||||
@app.route('/api/sysconfig/apply_update', methods = ['POST'])
|
||||
@login_required(role='admin',perm={'settings':'write'})
|
||||
def apply_update():
|
||||
"""apply update"""
|
||||
input = request.json
|
||||
action = input['action']
|
||||
update_mode=db_sysconfig.get_sysconfig('update_mode')
|
||||
update_mode=json.loads(update_mode)
|
||||
|
||||
if update_mode['mode']=='manual':
|
||||
if action=='update_mikroman':
|
||||
update_mode['update_back']=True
|
||||
db_sysconfig.set_sysconfig('update_mode',json.dumps(update_mode))
|
||||
Path('/app/reload').touch()
|
||||
return buildResponse({"status":"success"})
|
||||
if action=='update_mikrofront':
|
||||
update_mode['update_front']=True
|
||||
db_sysconfig.set_sysconfig('update_mode',json.dumps(update_mode))
|
||||
return buildResponse({"status":"success"})
|
||||
return buildResponse({"status":"success"})
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue