MikroWizard Initial commit | MikroMan Welcome to the world :)

This commit is contained in:
sepehr 2024-07-20 15:48:46 +03:30
commit 8c49b9a55d
96 changed files with 12274 additions and 0 deletions

438
py/api/api_account.py Normal file
View file

@ -0,0 +1,438 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# api_account.py: API For managing accounts and permissions
# MikroWizard.com , Mikrotik router management solution
# Author: sepehr.ha@gmail.com
from ctypes import util
from flask import request, session, g, jsonify
from libs.util import ISPRO
from libs.db import db,db_permissions,db_user_group_perm,db_groups,db_sysconfig,db_syslog
import json
from libs import webutil,account
from libs.webutil import app, login_required, get_myself , buildResponse
from libs.mschap3.mschap import nt_password_hash
import logging
log = logging.getLogger("api")
@app.route('/api/login', methods = ['POST'])
def login():
"""Logs the user in with username+password.
On success returns the user object,
on error returns error."""
input = request.json or {}
username = input.get('username')
password = input.get('password')
if not username or not password:
return webutil.warn_reply("Missing input")
u = db.get_user_by_username(username)
if not u or not account.check_password(u.password, password):
# error
try:
db_syslog.add_syslog_event(u.id, "User login","Failed login",webutil.get_ip(),webutil.get_agent(),json.dumps({"username":username}))
except:
pass
return webutil.warn_reply("Invalid login credentials")
else:
# success
account.build_session(u, is_permanent=input.get('remember', True))
tz=db_sysconfig.get_sysconfig('timezone')
# log.info("LOGIN OK agent={}".format(webutil.get_agent()))
res={
"username":u.username,
"name":u.username,
"partner_id":u.id,
"uid":u.id,
"first_name":u.first_name,
"last_name":u.last_name,
"role":u.role,
"tags":u.tags,
"tz":tz,
"perms":json.loads(u.adminperms)
}
db_syslog.add_syslog_event(u.id, "User login","Successful login",webutil.get_ip(),webutil.get_agent(),json.dumps({"username":username}))
return buildResponse(res, 200)
@app.route('/api/user/create', methods = ['POST'])
@login_required(role='admin',perm={'users':'write'})
def create_user():
"""Create new user."""
input = request.json or {}
username = input.get('username')
passwd = input.get('password')
email = input.get('email')
fname = input.get('first_name')
lname = input.get('last_name')
role = input.get('role', 'user')
company = input.get('company')
adminperms = input.get('adminperms',[])
userperms = input.get('userperms',[])
if not username or not passwd or not fname or not lname or not role:
resp={"status":"failed","err":"invalid data"}
return buildResponse(resp, 200)
u = db.get_user_by_username(username)
if u:
msg = "User Name already Taken: {}".format(username)
resp={"status":"failed","err":msg}
return buildResponse(resp, 200)
err = account.check_password_validity(passwd)
if err:
err = "Invalid password : {}".format(err)
resp={"status":"failed","err":err}
return buildResponse(resp, 200)
newpass = account.hash_password(passwd)
nthashhex=''.join(list("{:02x}".format(ord(c)) for c in nt_password_hash(passwd)))
# create new user
u = db.User()
u.username = username
u.company = company
u.first_name = fname
u.last_name = lname
u.password = newpass
u.email= email
u.adminperms= json.dumps(adminperms)
u.hash = nthashhex
u.tags = []
u.role = role # set default to what makes sense to your app
u.save(force_insert=True)
account.new_signup_steps(u)
for perm in userperms:
db_user_group_perm.DevUserGroupPermRel.create_user_group_perm(u.id, int(perm['group_id']), int(perm['perm_id']))
db_syslog.add_syslog_event(webutil.get_myself(), "User Managment","Create", webutil.get_ip(),webutil.get_agent(),json.dumps(input))
return buildResponse(u, 200)
@app.route('/api/user/delete' ,methods=['POST'])
@login_required(role='admin', perm={'users':'full'})
def user_delete():
"""Deletes a user. Only for superusers"""
input = request.json or {}
uid = input.get('uid')
try:
u = db.get_user(uid)
except:
u=False
if not u:
msg = "User not found: {}".format(uid)
resp={"status":"failed","err":msg}
return buildResponse(resp, 200)
u.delete_instance(recursive=True)
db_syslog.add_syslog_event(webutil.get_myself(), "User Managment", "Delete", webutil.get_ip(), webutil.get_agent(), json.dumps(input))
return buildResponse({}, 200)
@app.route('/api/user/change_password' ,methods=['POST'])
@login_required
def user_change_password():
"""Changes user password."""
input = request.json or {}
uid = webutil.get_myself().id
oldpass = input.get('oldpass')
newpass = input.get('newpass')
#check if oldpass is correct
try:
u = db.get_user(uid)
except:
u=False
if not u or not account.check_password(u.password, oldpass):
msg = "Current password is incorrect"
resp={"status":"failed","err":msg}
return buildResponse(resp, 200)
err = account.check_password_validity(newpass)
if not err:
newpass = account.hash_password(newpass)
nthashhex=''.join(list("{:02x}".format(ord(c)) for c in nt_password_hash(newpass)))
else:
err = "Invalid password : {}".format(err)
resp={"status":"failed","err":err}
return buildResponse(resp, 200)
u.password = newpass
u.hash = nthashhex
u.save()
db_syslog.add_syslog_event(webutil.get_myself(), "User Managment", "Change Password", webutil.get_ip(), webutil.get_agent(), json.dumps(input))
resp={"status":"success"}
return buildResponse(resp, 200)
@app.route('/api/logout', methods = ['POST'])
@login_required
def logout():
"""Logs out the user, clears the session."""
db_syslog.add_syslog_event(webutil.get_myself(), "User Logout","User Logged out", webutil.get_ip(),webutil.get_agent(),json.dumps({'logout':True}))
session.clear()
return jsonify({}), 200
@app.route('/api/me', methods=['GET', 'POST'])
def me():
"""Return info about me."""
me = get_myself()
if me:
res={
"username":me.username,
"first_name":me.first_name,
"last_name":me.last_name,
"role":me.role,
"tags":me.tags,
"uid":me.id,
"perms":json.loads(me.adminperms),
"tz":db_sysconfig.get_sysconfig('timezone'),
"ISPRO":ISPRO
}
reply = res
else:
reply = {"username":"public","first_name":"guest","last_name":"guest","role":"admin"}
return buildResponse(reply, 200)
@app.route('/api/user/edit', methods = ['POST'])
@login_required(role='admin',perm={'users':'write'})
def user_edit():
"""Edit user info. Only for admins with write perm"""
err=False
input = request.json or {}
uid = input.get('id')
username = input.get('username')
passwd = input.get('password')
email = input.get('email')
fname = input.get('first_name')
lname = input.get('last_name')
role = input.get('role', 'user')
adminperms = input.get('adminperms',[])
if passwd:
err = account.check_password_validity(passwd)
if not err:
newpass = account.hash_password(passwd)
nthashhex=''.join(list("{:02x}".format(ord(c)) for c in nt_password_hash(passwd)))
else:
err = "Invalid password : {}".format(err)
resp={"status":"failed","err":err}
return buildResponse(resp, 200)
try:
u = db.get_user(uid)
except:
u=False
if not u:
msg = "User not found: {}".format(uid)
resp={"status":"failed","err":msg}
return buildResponse(resp, 200)
ucheck = db.get_user_by_username(username)
if ucheck and str(ucheck.id) != uid:
msg = "User Name already Taken: {}".format(username)
resp={"status":"failed","err":msg}
return buildResponse(resp, 200)
if username:
u.username = username
if fname:
u.first_name = fname
if lname:
u.last_name = lname
if role:
u.role = role
if adminperms and str(u.id) != "37cc36e0-afec-4545-9219-94655805868b":
u.adminperms= json.dumps(adminperms)
if email:
u.email= email
if passwd and passwd!="":
u.password = newpass
u.hash = nthashhex
u.save()
resp={"status":"success"}
if err:
resp={"status":"failed","err":err}
db_syslog.add_syslog_event(webutil.get_myself(), "User Managment","Edit", webutil.get_ip(),webutil.get_agent(),json.dumps(input))
return buildResponse(resp, 200)
@app.route('/api/users/list' ,methods=['POST'])
@login_required(role='admin',perm={'users':'read'})
def users():
"""Search list of users. """
input = request.args or {}
page = input.get('page')
size = input.get('size')
search = input.get('search')
reply = list(db.query_users(page, size, search))
return buildResponse(reply, 200)
@app.route('/api/perms/list' ,methods=['POST'])
@login_required(role='admin',perm={'permissions':'read'})
def perms():
"""Search list of perms. """
input = request.args or {}
page = input.get('page')
size = input.get('size')
search = input.get('search')
reply = db_permissions.query_perms(page, size, search).dicts()
for rep in reply:
rep["perms"]=json.loads(rep["perms"])
return buildResponse(reply, 200)
@app.route('/api/perms/create' ,methods=['POST'])
@login_required(role='admin',perm={'permissions':'write'})
def perms_create():
"""Create permission record"""
input = request.json or {}
name = input.get('name')
perms = input.get('perms')
#check if we dont have permission with same name
perm = db_permissions.get_perm_by_name(name)
if perm or name.lower() in ['full','read','write']:
return buildResponse({"status":"failed","err":"Permission with same name already exists"}, 200)
for perm in perms:
if perm not in ["api","ftp","password","read","romon","sniff","telnet","tikapp","winbox","dude",'rest-api',"local","policy","reboot","sensitive","ssh","test","web","write"]:
return buildResponse({"status":"failed", "err":"Invalid permission"}, 200)
perms=json.dumps(perms)
db_permissions.create_perm(name, perms)
# reply = db_permissions.query_perms(page, size, search)
db_syslog.add_syslog_event(webutil.get_myself(), "Perms Managment","Create", webutil.get_ip(),webutil.get_agent(),json.dumps(input))
return buildResponse({}, 200)
@app.route('/api/perms/edit' ,methods=['POST'])
@login_required(role='admin',perm={'permissions':'write'})
def perms_edit():
"""Edit permission record"""
input = request.json or {}
name = input.get('name')
perms = input.get('perms')
id = input.get('id')
#check if we dont have permission with same name
perm = db_permissions.get_perm(id)
if not perm:
return buildResponse({"status":"failed", "err":"Permission not exists"}, 200)
for per in perms:
if per not in ["api","ftp","password","read","romon","sniff","telnet","tikapp","winbox","dude","rest-api","local","policy","reboot","sensitive","ssh","test","web","write"]:
return buildResponse({"status":"failed", "err":"Invalid permission"}, 200)
perms=json.dumps(perms)
#we are not allowed to change default mikrotik groups name
if name.lower() in ['full','read','write']:
return buildResponse({"status":"failed", "err":"Invalid permission name"}, 200)
if perm.name.lower() in ['full','read','write']:
return buildResponse({"status":"failed", "err":"Invalid permission name"}, 200)
perm.name=name
perm.perms=perms
perm.save()
# reply = db_permissions.query_perms(page, size, search)
db_syslog.add_syslog_event(webutil.get_myself(), "Perms Managment","Edit", webutil.get_ip(),webutil.get_agent(),json.dumps(input))
return buildResponse({'status':'success'}, 200)
@app.route('/api/userperms/list' ,methods=['POST'])
@login_required(role='admin',perm={'users':'read'})
def userperms():
"""Search list of userperms."""
input = request.json or {}
uid = input.get('uid')
#check if user exist
user = db.get_user(uid)
if not user:
return buildResponse({"status":"failed", "err":"User not exists"}, 200)
res=[]
reply = db_user_group_perm.DevUserGroupPermRel.get_user_group_perms(uid)
for data in reply:
res.append({"id":data.id,"user_id":data.user_id.id,"group_id":data.group_id.id,"group_name":data.group_id.name,"perm_id":data.perm_id.id,"perm_name":data.perm_id.name})
return buildResponse(res, 200)
@app.route('/api/userperms/create' ,methods=['POST'])
@login_required(role='admin',perm={'users':'write'})
def userperms_create():
"""Create user permission record"""
input = request.json or {}
uid = input.get('uid')
gid = input.get('gid')
pid = input.get('pid')
#check if user exist
user = db.get_user(uid)
if not user:
return buildResponse({"status":"failed", "err":"User not exists"}, 200)
#check if group exist
group = db_groups.get_group(gid)
if not group:
return buildResponse({"status":"failed", "err":"Group not exists"}, 200)
#check if permission exist
perm = db_permissions.get_perm(pid)
if not perm:
return buildResponse({"status":"failed", "err":"Permission not exists"}, 200)
db_user_group_perm.DevUserGroupPermRel.create_user_group_perm(uid, gid, pid)
# reply = db_permissions.query_perms(page, size, search)
db_syslog.add_syslog_event(webutil.get_myself(), "UserPerms Managment","Create", webutil.get_ip(),webutil.get_agent(),json.dumps(input))
return buildResponse({'status':'success'}, 200)
@app.route('/api/userperms/delete' ,methods=['POST'])
@login_required(role='admin', perm={'users':'write'})
def userperms_delete():
"""Delete user permission record"""
input = request.json or {}
id = input.get('id')
if(id == '1' or id == 1):
return buildResponse({"status":"failed", "err":"Cannot delete admin permission"}, 200)
#check if permission exist
perm = db_user_group_perm.DevUserGroupPermRel.get_user_group_perm(id)
if not perm:
return buildResponse({"status":"failed", "err":"Permission not exists"}, 200)
db_user_group_perm.DevUserGroupPermRel.delete_user_group_perm(id)
db_syslog.add_syslog_event(webutil.get_myself(), "UserPerms Managment", "Delete", webutil.get_ip(), webutil.get_agent(), json.dumps(input))
return buildResponse({'status':'success'}, 200)
@app.route('/api/perms/delete' ,methods=['POST'])
@login_required(role='admin', perm={'permissions':'full'})
def perms_delete():
"""Delete permission record"""
input = request.json or {}
id = input.get('id')
#check if permission exist
perm = db_permissions.get_perm(id)
if perm.name in ['full','read','write']:
return buildResponse({"status":"failed", "err":"Cannot delete default permission"}, 200)
if not perm:
return buildResponse({"status":"failed", "err":"Permission not exists"}, 200)
res=db_permissions.delete_perm(id)
if not res:
return buildResponse({"status":"failed", "err":"Unable to Delete Permission"}, 200)
# reply = db_permissions.query_perms(page, size, search)
db_syslog.add_syslog_event(webutil.get_myself(), "Perms Managment","Delete", webutil.get_ip(),webutil.get_agent(),json.dumps(input))
return buildResponse({'status':'success'}, 200)

83
py/api/api_backups.py Normal file
View file

@ -0,0 +1,83 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# api_bakcups.py: API for managing bakcups
# MikroWizard.com , Mikrotik router management solution
# Author: sepehr.ha@gmail.com
from flask import request, jsonify
from libs.db import db_tasks,db_backups,db_device,db_syslog
from libs import util
from libs.webutil import app, login_required,buildResponse,get_myself,get_ip,get_agent
import bgtasks
import logging
import json
log = logging.getLogger("api.firmware")
@app.route('/api/backup/make', methods = ['POST'])
@login_required(role='admin',perm={'backup':'write'})
def backup_create():
input = request.json
devids=input.get('devids',False)
status=db_tasks.backup_job_status().status
if not status:
db_syslog.add_syslog_event(get_myself(), "Backup Managment","Create", get_ip(),get_agent(),json.dumps(input))
if devids=="0":
all_devices=list(db_device.get_all_device())
bgtasks.backup_devices(devices=all_devices)
else:
devices=db_device.get_devices_by_id(devids)
bgtasks.backup_devices(devices=devices)
return buildResponse([{'status': status}],200)
else:
return buildResponse([{'status': status}],200)
@app.route('/api/backup/list', methods = ['POST'])
@login_required(role='admin',perm={'backup':'read'})
def backup_list():
input = request.json
page = input.get('page')
devid = input.get('devid',False)
size = input.get('size')
search = input.get('search')
backups = db_backups.query_backup_jobs(page, size, search,devid=devid)
reply=[]
for back in backups:
data={}
if back.devid:
dev=back.devid
data['id']=back.id
data['filesize']=util.sizeof_fmt(back.filesize)
data['created']=back.created
data['devname']=dev.name
data['devip']=dev.ip
data['devmac']=dev.mac
else:
data['id']=back.id
data['filesize']=util.sizeof_fmt(back.filesize)
data['created']=back.created
data['devname']='Deleted Device'
data['devip']=''
data['devmac']=''
reply.append(data)
return buildResponse(reply, 200)
@app.route('/api/backup/get', methods = ['POST'])
@login_required(role='admin',perm={'backup':'read'})
def backup_get():
input = request.json
id=input.get('id')
back=db_backups.get_backup(id)
path=back.dir
with open(path, 'r') as file:
file_content = file.read()
return buildResponse({"content":file_content}, 200)
@app.route('/api/backup/status', methods = ['POST'])
@login_required(role='admin',perm={'backup':'read'})
def backup_status():
status=db_tasks.update_check_status().status
return jsonify({'status': status})

559
py/api/api_dev.py Normal file
View file

@ -0,0 +1,559 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# api_bakcups.py: API for managing bakcups
# MikroWizard.com , Mikrotik router management solution
# Author: sepehr.ha@gmail.com
from flask import request,redirect ,session
import datetime
import html
import config
import re
from libs.red import RedisDB
from libs.webutil import app,buildResponse,login_required,get_myself,get_ip,get_agent
from libs import util
from libs.db import db_device,db_groups,db_user_group_perm,db_user_tasks,db_sysconfig,db_syslog
import logging
import json
from playhouse.shortcuts import model_to_dict
log = logging.getLogger("api")
try:
from libs import utilpro
ISPRO=True
except ImportError:
ISPRO=False
pass
@app.route('/', methods = ['GET'])
def index():
"""Just a redirect to api list."""
if config.IS_PRODUCTION:
return "not available", 400
return redirect('/api/list')
@app.route('/api/dev/list', methods = ['POST'])
@login_required(role='admin',perm={'device':'read'})
def list_devs():
"""Return devs list of assigned to user , all for admin"""
input = request.json
# Get devices that are in the group
group_id = int(input.get('group_id', False))
page = input.get('page')
size = input.get('size')
search = input.get('search',False)
page = int(page or 0)
limit = int(size or 1000)
res = []
try:
# Get devices that current user have access
uid = session.get("userid") or False
if not uid:
return buildResponse({'result':'failed','err':"No User"}, 200)
# Get devices that current user have access
devs=db_user_group_perm.DevUserGroupPermRel.get_user_devices(uid,group_id).paginate(page, limit).dicts()
for dev in devs:
temp=dev
del temp['user_name']
del temp['password']
if ' ' not in temp['uptime']:
temp['uptime'] = temp['uptime'].replace('w',' week ').replace('d',' day ').replace('h',' hour ').replace('m',' min ')
res.append(temp)
except Exception as e:
return buildResponse({'result':'failed','err':str(e)},200)
return buildResponse(res,200)
@app.route('/api/dev/get_editform', methods = ['POST'])
@login_required(role='admin',perm={'device':'full'})
def get_editform():
"""return device editable data"""
input = request.json
# get devices that are in the group
devid = int(input.get('devid', False))
res = {}
try:
dev=db_device.get_device(devid)
if not dev:
return buildResponse({'status': 'failed'}, 200, error="Wrong Data")
res['user_name']=util.decrypt_data(dev['user_name'])
res['password']=util.decrypt_data(dev['password'])
res['ip']=dev['ip']
res['peer_ip']=dev['peer_ip']
res['name']=dev['name']
res['id']=dev['id']
try:
res['ips']=json.loads(db_sysconfig.get_sysconfig('all_ip'))
except Exception as e:
res['ips']=[]
except Exception as e:
log.error(e)
return buildResponse({'status': 'failed'}, 200, error="Wrong Data")
return buildResponse(res,200)
@app.route('/api/dev/save_editform', methods = ['POST'])
@login_required(role='admin', perm={'device':'full'})
def save_editform():
"""save device configuration"""
input = request.json
devid = int(input.get('id', False))
user_name = input.get('user_name', False)
password = input.get('password', False)
ip = input.get('ip', False)
peer_ip = input.get('peer_ip', False)
name = input.get('name', False)
try:
if db_device.update_device(devid, util.crypt_data(user_name), util.crypt_data(password), ip, peer_ip, name):
db_syslog.add_syslog_event(get_myself(), "Device", "Edit", get_ip(),get_agent(),json.dumps(input))
return buildResponse({"result":"success"}, 200)
else:
return buildResponse({"result":"failed","err":"Unable to update device"}, 200)
except Exception as e:
log.error(e)
return buildResponse({"result":"failed","err":str(e)}, 200)
@app.route('/api/devgroup/list', methods = ['POST'])
@login_required(role='admin',perm={'device_group':'read'})
def list_devgroups():
"""return dev groups"""
# build HTML of the method list
devs = []
try:
devs=list(db_groups.query_groups_api())
except Exception as e:
return buildResponse({'result':'failed','err':str(e)},200)
return buildResponse(devs,200)
@app.route('/api/devgroup/delete', methods = ['POST'])
@login_required(role='admin',perm={'device_group':'full'})
def delete_group():
"""delete dev group"""
input = request.json
gid = input.get('gid', False)
try:
if db_user_group_perm.DevUserGroupPermRel.delete_group(gid):
db_syslog.add_syslog_event(get_myself(), "Device Group","Delete", get_ip(),get_agent(),json.dumps(input))
return buildResponse({"result":"success"}, 200)
else:
return buildResponse({"result":"failed",'err':'Unable to delete'}, 200)
except Exception as e:
return buildResponse({"result":"failed",'err':'Unable to delete'}, 200)
@app.route('/api/devgroup/members', methods = ['POST'])
@login_required(role='admin',perm={'device_group':'read','device':'read'})
def list_devgroups_members():
"""return list of dev groups"""
input = request.json
gid=input.get('gid',False)
# get devices that are in the group
devs = []
try:
devs=list(db_groups.devs(gid))
except Exception as e:
return buildResponse({'result':'failed','err':str(e)},200)
return buildResponse(devs,200)
@app.route('/api/devgroup/update_save_group', methods = ['POST'])
@login_required(role='admin',perm={'device_group':'write','device':'read'})
def update_save_group():
"""save device group config"""
input = request.json
devids= input.get('array_agg', False)
name = input.get('name', False)
id = input.get('id', False)
# First check if we are editiong or creating new group
# if id is 0 then we are creating new group
if id==0:
# create new group and add devices to it
try:
group=db_groups.create_group(name)
if group:
db_syslog.add_syslog_event(get_myself(), "Device Group","Create", get_ip(),get_agent(),json.dumps(input))
gid=group.id
db_groups.add_devices_to_group(gid,devids)
else:
return buildResponse({'result':'failed','err':"Group not created"}, 200)
return buildResponse({"result":"success"}, 200)
except Exception as e:
return buildResponse({'result':'failed','err':str(e)}, 200)
else:
# update group and add devices to it
try:
group=db_groups.update_group(id, name)
db_groups.add_devices_to_group(group.id, devids)
#get all dev ids from group and compare to devids,remove devs not availble in devids
devs=db_groups.devs2(id)
ids=[]
for dev in devs:
ids.append(dev.id)
dev_to_remove=list(set(ids)-set(devids))
db_groups.delete_from_group(dev_to_remove)
db_syslog.add_syslog_event(get_myself(), "Device Group","Update", get_ip(),get_agent(),json.dumps(input))
return buildResponse({"result":"success"}, 200)
except Exception as e:
return buildResponse({'result':'failed','err':str(e)}, 200)
@app.route('/api/search/groups', methods = ['POST'])
@login_required(role='admin',perm={'device_group':'read','device':'read'})
def search_groups():
"""search in devices"""
input = request.json
searchstr=input.get('searchstr',False)
dev_groups = []
group=db_groups.DevGroups
try:
if searchstr and searchstr!="":
# find device groups that contains searchstr in the name
dev_groups = (group
.select()
.where(group.name.contains(searchstr))
.dicts())
else:
# return first 10 ordered alphabeticaly
dev_groups = (group
.select()
.order_by(group.name)
.limit(10)
.dicts())
except Exception as e:
return buildResponse({'result':'failed','err':str(e)},200)
return buildResponse(dev_groups,200)
@app.route('/api/search/devices', methods = ['POST'])
@login_required(role='admin',perm={'device':'read'})
def search_devices():
"""search in groups"""
input = request.json
searchstr=input.get('searchstr',False)
# build HTML of the method list
device=db_device.Devices
searchstr=input.get('searchstr',False)
devs = []
try:
if searchstr and searchstr!="":
# find devices that contains searchstr in the name
devs = (device
.select()
.where(device.name.contains(searchstr))
.dicts())
else:
# return first 10 ordered alphabeticaly
devs = (device
.select()
.order_by(device.name)
.limit(10)
.dicts())
except Exception as e:
return buildResponse({'result':'failed','err':str(e)},200)
return buildResponse(devs,200)
@app.route('/api/taskmember/details', methods = ['POST'])
@login_required(role='admin',perm={'device_group':'read','device':'read'})
def get_taskmember_details():
"""search in groups"""
# build HTML of the method list
input = request.json
tid=input.get('taskid',False)
if not tid:
return buildResponse({"success":'failed',"err":"Wrong task"},200)
res=[]
utask=db_user_tasks.UserTasks.get_utask_by_id(tid)
members=db_user_tasks.get_task_devices(utask,False)
if utask.selection_type=="groups":
for group in members:
tmp = model_to_dict(group)
res.append({"id":tmp['id'], "name":tmp['name']})
else:
for dev in members:
tmp = model_to_dict(dev)
res.append({"id":tmp['id'],"name":tmp['name'],"mac":tmp['mac']})
return buildResponse(res,200)
@app.route('/api/dev/info', methods = ['POST'])
@login_required(role='admin',perm={'device':'read'})
def dev_info():
"""return dev info"""
input = request.json
devid=input.get('devid',False)
if not devid or not isinstance(devid, int):
return buildResponse({'status': 'failed'},200,error="Wrong Data")
res=db_device.get_device(devid)
options=util.build_api_options(db_device.get_devices_by_id([res['id'],])[0])
network_info=[]
try:
if util.check_port(options['host'],options['port']):
router=util.RouterOSCheckResource(options)
network_info=util.get_network_data(router)
del network_info['total']
except:
pass
interfaces=[]
for iface in network_info:
interfaces.append(network_info[iface])
#fix and change some data
res['interfaces']=interfaces
res.pop('user_name')
res.pop('password')
res.pop('wifi_config')
res['created']=res['created'].strftime("%Y-%m-%d %H:%M:%S")
res['modified']=res['modified'].strftime("%Y-%m-%d %H:%M:%S")
#get data from redis
if ISPRO:
res['is_radio']=utilpro.check_is_radio(res['id'])
try:
del res['sensors']
except Exception as e:
log.error(e)
return buildResponse({'status': 'failed'}, 200, error="Wrong Data")
pass
return buildResponse(res,200)
@app.route('/api/dev/sensors', methods = ['POST'])
@login_required(role='admin',perm={'device':'read'})
def dev_sensors():
"""return dev sensors chart data"""
input = request.json
devid=input.get('devid',False)
total=input.get('total','bps')
delta=input.get('delta',"5m")
if delta not in ["5m","1h","daily","live"]:
return buildResponse({'status': 'failed'},200,error="Wrong Data")
if not devid or not isinstance(devid, int):
return buildResponse({'status': 'failed'},200,error="Wrong Data")
dev=db_device.get_device(devid)
if delta=="5m":
start_time=datetime.datetime.now()-datetime.timedelta(minutes=5*24)
elif delta=="1h":
start_time=datetime.datetime.now()-datetime.timedelta(hours=24)
elif delta=="daily":
start_time=datetime.datetime.now()-datetime.timedelta(days=30)
else:
start_time=datetime.datetime.now()-datetime.timedelta(days=30)
end_time=datetime.datetime.now()
try:
res={}
res['sensors']=json.loads(dev['sensors'])
redopts={
"dev_id":dev['id'],
"keys":res['sensors'],
"start_time":start_time,
"end_time":end_time,
"delta":delta,
}
colors={
'backgroundColor': 'rgba(77,189,116,.2)',
'borderColor': '#4dbd74',
'pointHoverBackgroundColor': '#fff'
}
reddb=RedisDB(redopts)
data=reddb.get_dev_data_keys()
tz=db_sysconfig.get_sysconfig('timezone')
res["radio-sensors"]=[]
for key in res['sensors'][:]:
if "rx" in key or "tx" in key or "rxp" in key or "txp" in key or "radio" in key:
if "radio" in key:
res["radio-sensors"].append(key)
if not 'total' in key:
res['sensors'].remove(key)
continue
if "total" in key:
if total=='bps' and 'rx/tx-total' in res['sensors'] and 'rx/tx-total' in res['sensors']:
continue
if total!='bps' and 'rxp/txp-total' in res['sensors'] and 'rxp/txp-total' in res['sensors']:
continue
temp=[]
ids=['yA','yB']
colors=['#17522f','#171951']
datasets=[]
lables=[]
data_keys=['tx-total','rx-total']
if total!='bps':
data_keys=['txp-total','rxp-total']
for idx, val in enumerate(data_keys) :
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"))
temp.append(round(d[1],1))
datasets.append({'borderColor': colors[idx],'type': 'line','yAxisID': ids[idx],'data':temp,'unit':val.split("-")[0],'backgroundColor': colors[idx],'pointHoverBackgroundColor': '#fff'})
temp=[]
if total=='bps':
res["rx/tx-total"]={'labels':lables,'datasets':datasets}
res['sensors'].append("rx/tx-total")
else:
res["rxp/txp-total"]={'labels':lables,'datasets':datasets}
res['sensors'].append("rxp/txp-total")
else:
temp={"labels":[],"data":[]}
for d in data[key]:
edatetime=datetime.datetime.fromtimestamp(d[0]/1000)
temp["labels"].append(util.utc2local(edatetime,tz=tz).strftime("%m/%d/%Y, %H:%M:%S %Z"))
temp["data"].append(round(d[1],1))
res[key]={'labels':temp["labels"],'datasets':[{'data':temp['data'],'backgroundColor': 'rgba(77,189,116,.2)','borderColor': '#fff','pointHoverBackgroundColor': '#fff'}]}
if 'rxp-total' in res['sensors']:
res['sensors'].remove('txp-total')
res['sensors'].remove('rxp-total')
elif 'rx-total' in res['sensors']:
res['sensors'].remove('tx-total')
res['sensors'].remove('rx-total')
except Exception as e:
log.error(e)
return buildResponse({'status': 'failed'}, 200, error="Error in generating data")
pass
return buildResponse(res,200)
@app.route('/api/dev/ifstat', methods = ['POST'])
@login_required(role='admin',perm={'device':'read'})
def dev_ifstat():
"""return device interfaces info"""
input = request.json
devid=input.get('devid',False)
chart_type=input.get('type','bps')
delta=input.get('delta',"5m")
interface=input.get('interface',False)
if delta not in ["5m","1h","daily","live"]:
return buildResponse({'status': 'failed'},200,error="Wrong Data")
if not devid or not isinstance(devid, int):
return buildResponse({'status': 'failed'},200,error="Wrong Data")
res=db_device.get_device(devid)
if delta=="5m":
start_time=datetime.datetime.now()-datetime.timedelta(minutes=5*24)
elif delta=="1h":
start_time=datetime.datetime.now()-datetime.timedelta(hours=24)
elif delta=="daily":
start_time=datetime.datetime.now()-datetime.timedelta(days=30)
else:
start_time=datetime.datetime.now()-datetime.timedelta(days=30)
end_time=datetime.datetime.now()
#Fix and change some data
#Get data from redis
res['name']="Device : " + db_device.get_device(devid)['name'] + " - Interface : " + interface
try:
res['sensors']=json.loads(res['sensors'])
for sensor in res['sensors'][:]:
regex=r'.*{}$'.format(interface)
if not bool(re.match(regex,sensor)):
res['sensors'].remove(sensor)
redopts={
"dev_id":res['id'],
"keys":res['sensors'],
"start_time":start_time,
"end_time":end_time,
"delta":delta,
}
colors={
'backgroundColor': 'rgba(77,189,116,.2)',
'borderColor': '#4dbd74',
'pointHoverBackgroundColor': '#fff'
}
reddb=RedisDB(redopts)
data=reddb.get_dev_data_keys()
temp=[]
ids=['yA','yB']
colors=['#17522f','#171951']
datasets=[]
lables=[]
tz=db_sysconfig.get_sysconfig('timezone')
data_keys=['tx-{}'.format(interface),'rx-{}'.format(interface)]
if chart_type=='bps':
data_keys=['tx-{}'.format(interface),'rx-{}'.format(interface)]
elif chart_type=='pps':
data_keys=['txp-{}'.format(interface),'rxp-{}'.format(interface)]
for idx, val in enumerate(data_keys):
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"))
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'})
temp=[]
res["data"]={'labels':lables,'datasets':datasets}
except Exception as e:
log.error(e)
return buildResponse({'status': 'failed'}, 200, error="Error in generating data")
pass
return buildResponse(res,200)
@app.route('/api/dev/delete', methods = ['POST'])
@login_required(role='admin',perm={'device':'full'})
def dev_delete():
"""return dev info"""
input = request.json
devids=input.get('devids', False)
res={}
# ToDo: we need to delete redis keys also
try:
for dev in devids:
if db_groups.delete_device(dev):
db_syslog.add_syslog_event(get_myself(), "Device","Delete", get_ip(),get_agent(),json.dumps(input))
res['status']='success'
else:
res['status'] = 'failed'
res['err'] = 'Unable to Delete Device'
except Exception as e:
log.error(e)
return buildResponse({'status': 'failed'}, 200, error=str(e))
return buildResponse(res, 200)
#Development tool , We dont want this in production
@app.route('/api/list', methods = ['GET'])
def list_api():
"""List the available REST APIs in this service as HTML. Queries
methods directly from Flask, no need to maintain separate API doc.
(Maybe this could be used as a start to generate Swagger API spec too.)"""
# decide whether available in production
if config.IS_PRODUCTION:
return "not available in production", 400
# build HTML of the method list
apilist = []
rules = sorted(app.url_map.iter_rules(), key=lambda x: str(x))
for rule in rules:
f = app.view_functions[rule.endpoint]
docs = f.__doc__ or ''
module = f.__module__ + ".py"
# remove noisy OPTIONS
methods = sorted([x for x in rule.methods if x != "OPTIONS"])
url = html.escape(str(rule))
if not "/api/" in url and not "/auth/" in url:
continue
apilist.append("<div><a href='{}'><b>{}</b></a> {}<br/>{} <i>{}</i></div>".format(
url, url, methods, docs, module))
header = """<body>
<title>MikroWizard Generated API LIST</title>
<style>
body { width: 80%; margin: 20px auto;
font-family: Courier; }
section { background: #eee; padding: 40px 20px;
border: 1px dashed #aaa; }
i { color: #888; }
</style>"""
title = """
<section>
<h2>REST API ({} end-points)</h2>
<h3>IS_PRODUCTION={} IS_LOCAL_DEV={} Started ago={}</h3>
""".format(len(apilist), config.IS_PRODUCTION, config.IS_LOCAL_DEV,
config.started_ago(True))
footer = "</section></body>"
return header + title + "<br/>".join(apilist) + footer

151
py/api/api_firmware.py Normal file
View file

@ -0,0 +1,151 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# api_firmware.py: API for managing firmware
# MikroWizard.com , Mikrotik router management solution
# Author: sepehr.ha@gmail.com
from flask import request, jsonify,session,send_file
from playhouse.shortcuts import model_to_dict
import datetime
from libs.db import db_tasks,db_sysconfig,db_device,db_firmware,db_syslog
from libs import util
from libs.webutil import app, login_required, get_myself,buildResponse,get_myself,get_ip,get_agent
import bgtasks
import re
import logging
log = logging.getLogger("api.firmware")
import json
@app.route('/api/firmware/check_firmware_update', methods = ['POST'])
@login_required(role='admin',perm={'device':'write'})
def check_firmware_update():
"""Chck fimware update status"""
input = request.json
devids=input.get('devids',"0")
status=db_tasks.update_check_status().status
uid = session.get("userid") or False
if not uid:
return buildResponse({'result':'failed','err':"No User"}, 200)
#if devices is [0] then check firmware for all devices of user
if not status:
bgtasks.check_devices_for_update(devices=devids,uid=uid)
db_syslog.add_syslog_event(get_myself(), "Firmware","Check", get_ip(),get_agent(),json.dumps(input))
res={'status': True}
else:
res={'status': status}
return buildResponse(res,200)
@app.route('/api/firmware/check_task_status', methods = ['GET'])
@login_required(role='admin',perm={'device':'read'})
def check_task_status():
"""Return firmware update check service status"""
status=db_tasks.update_check_status().status
return jsonify({'status': status})
@app.route('/api/firmware/update_firmware', methods = ['POST'])
@login_required(role='admin',perm={'device':'full'})
def update_device():
"""Update devices"""
status=db_tasks.update_job_status().status
input=request.json
devids=input.get('devids',"0")
uid = session.get("userid") or False
if not uid:
return buildResponse({'result':'failed','err':"No User"}, 200)
if not status:
db_syslog.add_syslog_event(get_myself(), "Firmware","update", get_ip(),get_agent(),json.dumps(input))
bgtasks.update_device(devices=devids,uid=uid)
res={'status': True}
else:
res={'status': status}
return buildResponse(res,200)
@app.route('/api/firmware/get_firms', methods = ['POST'])
@login_required(role='admin',perm={'settings':'full'})
def get_firms():
"""get list of of downloaded firmwares in local repo"""
input = request.json or {}
page = input.get('page')
size = input.get('size')
search = input.get('search')
reply = db_firmware.query_firms(page, size, search).dicts()
data={
"firms":reply,
"updateBehavior":db_sysconfig.get_sysconfig("old_firmware_action"),
"firmwaretoinstall":db_sysconfig.get_sysconfig("latest_version"),
"firmwaretoinstallv6":db_sysconfig.get_sysconfig("old_version"),
}
return buildResponse(data, 200)
@app.route('/api/firmware/get_downloadable_firms', methods = ['POST'])
@login_required(role='admin',perm={'settings':'full'})
def get_downloadable_firms():
"""get list of availble Firmwares from Mikrotik Official webstire"""
input = request.json or {}
versions=util.get_mikrotik_versions()
versions = sorted(versions, key=lambda x: [int(y) if y.isdigit() else int(re.sub(r'\D', '', y)) for y in x.split('.')])
return buildResponse({"versions":versions}, 200)
@app.route('/api/firmware/download_firmware_to_repository', methods = ['POST'])
@login_required(role='admin',perm={'settings':'full'})
def download_firmware_to_repository():
"""Download Firmware from Mikrotik Official website"""
input = request.json or {}
version=input.get('version')
status=db_tasks.downloader_job_status().status
if not status:
db_syslog.add_syslog_event(get_myself(), "Firmware","Download", get_ip(),get_agent(),json.dumps(input))
bgtasks.download_firmware(version=version)
return buildResponse({'status': True}, 200)
else:
return buildResponse({'status': status}, 200)
@app.route('/api/firmware/update_firmware_settings', methods = ['POST'])
@login_required(role='admin',perm={'settings':'write'})
def update_firmware_settings():
"""Change system settings for firmware update"""
input = request.json or {}
updateBehavior=input.get('updatebehavior')
firmwaretoinstall=input.get('firmwaretoinstall')
firmwaretoinstallv6=input.get('firmwaretoinstallv6')
db_sysconfig.update_sysconfig("old_firmware_action", updateBehavior)
db_sysconfig.update_sysconfig("latest_version", firmwaretoinstall)
db_sysconfig.update_sysconfig("old_version", firmwaretoinstallv6)
db_syslog.add_syslog_event(get_myself(), "Firmware","settings", get_ip(),get_agent(),json.dumps(input))
return buildResponse({'status': True}, 200)
def serialize_datetime(obj):
if isinstance(obj, datetime.datetime):
return obj.isoformat()
@app.route('/api/firmware/get_firmware/<firmid>', methods = ['POST','GET'])
def get_firmware(firmid):
"""Download firmware of given id from repo"""
firm=db_firmware.get_firm(firmid)
dev_ip=request.remote_addr
# log.error(dev_ip)
# if dev_ip:
# dev=db_device.query_device_by_ip(dev_ip)
# if not dev:
# return buildResponse({'result':'failed', 'err':"Device not found"}, 200)
if firm:
log.error(dev_ip)
data={
"devip":dev_ip,
# "devid":dev.id,
"firm":model_to_dict(firm),
}
db_syslog.add_syslog_event(get_myself(), "Firmware","download", get_ip(),get_agent(),json.dumps(data,default=serialize_datetime))
# if dev.arch != firm.architecture:
# return buildResponse({'result':'failed','err':"Wrong architecture"}, 200)
path=firm.location
return send_file(path, as_attachment=True)
# log.error(dev)
return buildResponse({'result':'failed','err':"somthing went wrong"}, 200)

496
py/api/api_logs.py Normal file

File diff suppressed because one or more lines are too long

39
py/api/api_scanner.py Normal file
View file

@ -0,0 +1,39 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# api_scanner.py: API for device scanner in network
# MikroWizard.com , Mikrotik router management solution
# Author: sepehr.ha@gmail.com
from flask import request
from libs.db import db_tasks,db_syslog
from libs.webutil import app, login_required,buildResponse,get_myself,get_ip,get_agent
import bgtasks
import json
import logging
log = logging.getLogger("api.scanner")
@app.route('/api/scanner/scan', methods = ['POST'])
@login_required(role='admin',perm={'device':'full'})
def scan_network():
"""Do scan requested network for given ip range to find mikrotik devices"""
input = request.json
start=input.get('start',False)
end=input.get('end',False)
port=input.get('port',8728)
if not port:
port=8728
password=input.get('password',False)
username=input.get('user',False)
status=db_tasks.scanner_job_status().status
if not status:
if start and end and port:
db_syslog.add_syslog_event(get_myself(), "Scanner","start", get_ip(),get_agent(),json.dumps(input))
bgtasks.scan_with_ip(start=start,end=end,port=port,password=password,username=username)
return buildResponse({'status': True},200)
else:
return buildResponse({'status': status},200)
else:
return buildResponse({'status': status},200)

98
py/api/api_snippet.py Normal file
View file

@ -0,0 +1,98 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# api_snippet.py: API for code snippets
# MikroWizard.com , Mikrotik router management solution
# Author: sepehr.ha@gmail.com
from flask import request
from libs.db import db_user_tasks,db_syslog
from libs.webutil import app, login_required,buildResponse,get_myself,get_ip,get_agent
from functools import reduce
import operator
import logging
import json
log = logging.getLogger("api.snippet")
@app.route('/api/snippet/list', methods = ['POST'])
@login_required(role='admin',perm={'snippet':'read'})
def user_snippet_list():
"""return snippets list """
input = request.json
name=input.get('name',False)
description=input.get('description',False)
content=input.get('content',False)
snips=db_user_tasks.Snippets
page=input.get('page',0)
size=input.get('size',10000)
# build where query
clauses = []
if name and name!="":
clauses.append(snips.name.contains(name))
if description and description!="":
clauses.append(snips.description.contains(description))
if content and content!="":
clauses.append(snips.content == content)
expr=""
logs = []
selector=[snips.id,snips.name,snips.description,snips.content,snips.created]
try:
if len(clauses):
expr = reduce(operator.and_, clauses)
query=snips.select(*selector).where(expr)
else:
query=snips.select(*selector)
query=query.order_by(snips.id.desc())
query=query.paginate(page,size)
logs=list(query.dicts())
except Exception as e:
return buildResponse({"status":"failed", "err":str(e)},400)
return buildResponse(logs,200)
@app.route('/api/snippet/save', methods = ['POST'])
@login_required(role='admin',perm={'snippet':'write'})
def user_snippet_save():
"""save or create snippets"""
input = request.json
id=input.get('id', 0)
name=input.get('name', False)
description=input.get('description', False)
content=input.get('content', False)
# if id is 0 then we are creating new snippet
# else edit the snippet with provided id
if id==0:
snippet=db_user_tasks.get_snippet_by_name(name)
if snippet:
return buildResponse({"result":"failed","err":"Snippet already exists"}, 200)
snippet=db_user_tasks.create_snippet(name,description,content)
if snippet:
db_syslog.add_syslog_event(get_myself(), "Snippet","Create", get_ip(),get_agent(),json.dumps(input))
return buildResponse({"result":"success"}, 200)
else:
return buildResponse({"result":"failed","err":"Snippet create failed"}, 200)
else:
snippet=db_user_tasks.get_snippet(id)
if snippet:
db_syslog.add_syslog_event(get_myself(), "Snippet","Update", get_ip(),get_agent(),json.dumps(input))
snippet=db_user_tasks.update_snippet(id, name, description, content)
return buildResponse({"result":"success"}, 200)
else:
return buildResponse({"result":"failed","err":"Snippet not found"}, 200)
@app.route('/api/snippet/delete', methods = ['POST'])
@login_required(role='admin',perm={'snippet':'full'})
def user_snippet_delete():
input = request.json
id=input.get('id', 0)
snippet=db_user_tasks.get_snippet(id)
if snippet:
db_syslog.add_syslog_event(get_myself(), "Snippet","Delete", get_ip(),get_agent(),json.dumps(input))
snippet=db_user_tasks.delete_snippet(id)
return buildResponse({"result":"success"}, 200)
else:
return buildResponse({"result":"failed","err":"Failed to delete snippet"}, 200)

51
py/api/api_sysconfig.py Normal file
View file

@ -0,0 +1,51 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# api_sysconfig.py: API for MikroWizard system config
# MikroWizard.com , Mikrotik router management solution
# Author: sepehr.ha@gmail.com
from flask import request
from libs.db import db_sysconfig,db_syslog
from libs import util
from libs.webutil import app, login_required,buildResponse,get_myself,get_ip,get_agent
import time
import logging
import json
log = logging.getLogger("api.sysconfig")
@app.route('/api/sysconfig/get_all', methods = ['POST'])
@login_required(role='admin',perm={'settings':'read'})
def sysconfig_get_all():
"""get all system configs"""
input = request.json
sysconfig=db_sysconfig.get_all()
res={}
for s in sysconfig:
res[s.key]={"value":s.value,"modified":s.modified}
return buildResponse({"sysconfigs":res})
@app.route('/api/sysconfig/save_all', methods = ['POST'])
@login_required(role='admin',perm={'settings':'write'})
def sysconfig_save_all():
"""save system configs"""
input = request.json
data=[]
now=time.time()
for k,v in input.items():
if k=="default_password" and v['value']=="":
continue
elif k=="default_user" and v['value']=="":
continue
elif k=="default_password" or k=="default_user":
v['value']=util.crypt_data(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"})

239
py/api/api_user_tasks.py Normal file
View file

@ -0,0 +1,239 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# api_user_tasks.py: API for create modify schedule tasks
# MikroWizard.com , Mikrotik router management solution
# Author: sepehr.ha@gmail.com
from flask import request
from libs.db import db_syslog,db_user_tasks
from libs.webutil import app, login_required,buildResponse,get_myself,get_ip,get_agent
from functools import reduce
import operator
from crontab import CronTab,CronSlices
import logging
from cron_descriptor import get_description
import json
from pathlib import Path
try:
from libs import utilpro
ISPRO=True
except ImportError:
ISPRO=False
pass
log = logging.getLogger("api.usertasks")
@app.route('/api/user_tasks/list', methods = ['POST'])
@login_required(role='admin',perm={'task':'read'})
def user_tasks_list():
"""return user task list"""
input = request.json
name=input.get('name',False)
description=input.get('description',False)
action=input.get('action',False)
task_type=input.get('task_type',False)
utaks=db_user_tasks.UserTasks
# build where query
clauses = []
if name:
clauses.append(utaks.name.contains(name))
if description:
clauses.append(utaks.description.contains(description))
if action:
clauses.append(utaks.action == action)
if task_type:
clauses.append(utaks.task_type == task_type)
if not ISPRO:
clauses.append(utaks.task_type != 'firmware')
expr=""
logs = []
selector=[utaks.id,utaks.name,utaks.description,utaks.desc_cron,utaks.action,utaks.task_type,utaks.dev_ids,utaks.snippetid,utaks.data,utaks.cron,utaks.selection_type,utaks.created]
try:
if len(clauses):
expr = reduce(operator.and_, clauses)
query=utaks.select(*selector).where(expr)
else:
query=utaks.select(*selector)
query=query.order_by(utaks.id.desc())
logs=list(query.dicts())
except Exception as e:
return buildResponse({"status":"failed", "err":str(e)},200)
return buildResponse(logs,200)
@app.route('/api/user_tasks/create', methods = ['POST'])
@login_required(role='admin',perm={'task':'write'})
def user_tasks_create():
"""crate user task"""
input = request.json
name=input.get('name',False)
description=input.get('description',False)
snippetid=input.get('snippetid',False)
members=input.get('members', False)
cron=input.get('cron',False)
action=input.get('action',False)
task_type=input.get('task_type',"backup")
selection_type=input.get('selection_type',False)
taskdata=input.get('data',False)
utasks=db_user_tasks.UserTasks
# todo
# add owner check devids and dev groups with owner
if not name or not description:
return buildResponse({'status': 'failed'},200,error="Wrong name/desc")
#check if cron is valid and correct
if cron and not CronSlices.is_valid(cron):
return buildResponse({'status': 'failed'},200,error="Wrong Cron")
data={
'name':name,
'description':description,
'snippetid':int(snippetid) if snippetid else 0,
'cron':cron,
'desc_cron': get_description(cron),
'action': action,
'task_type':task_type,
'selection_type':selection_type,
'data':json.dumps(taskdata) if taskdata else None
}
if selection_type not in ["devices","groups"]:
return buildResponse({'status': 'failed'}, 200, error="Wrong member type")
if task_type not in ["backup","snippet","firmware"]:
return buildResponse({'status': 'failed'}, 200, error="Wrong task type")
try:
task=utasks.create(**data)
#add members to task
if len(members):
db_user_tasks.add_member_to_task(task.id, members, selection_type)
taskid=task.id
if task_type=="backup":
crontab = CronTab(user=True)
directory=Path(app.root_path).parent.absolute()
command = "python3 {}/task_run.py {}".format(directory,taskid)
comment = "MikroWizard task #" + "taskid:{};".format(taskid)
jobs = crontab.find_comment(comment)
if len(list(jobs)) > 0:
jobs = crontab.find_comment(comment)
crontab.remove(jobs)
crontab.write()
job = crontab.new(command=command,comment=comment)
job.setall(cron)
crontab.write()
db_syslog.add_syslog_event(get_myself(), "Task","Create", get_ip(),get_agent(),json.dumps(input))
return buildResponse([{'status': 'success',"taskid":taskid}],200)
except Exception as e:
log.error(e)
return buildResponse({'status': 'failed','massage':str(e)},200)
@app.route('/api/user_tasks/edit', methods = ['POST'])
@login_required(role='admin',perm={'task':'write'})
def user_tasks_edit():
"""create edit user task"""
input = request.json
name=input.get('name',False)
task_id=input.get('id', False)
description=input.get('description',False)
snippetid=input.get('snippetid',False)
members=input.get('members', False)
cron=input.get('cron',False)
action=input.get('action',False)
task_type=input.get('task_type',"backup")
selection_type=input.get('selection_type',False)
taskdata=input.get('data', False)
# todo
# add owner check devids and dev groups with owner
if not name or not description:
return buildResponse({'status': 'failed'},200,error="Wrong name/desc")
# Check if cron is valid and correct
if cron and not CronSlices.is_valid(cron):
return buildResponse({'status': 'failed'},200,error="Wrong Cron")
if selection_type not in ["devices","groups"]:
return buildResponse({'status': 'failed'}, 200, error="Wrong member type")
if task_type not in ["backup","snippet","firmware"]:
return buildResponse({'status': 'failed'}, 200, error="Wrong task type")
# check task exist and valid
utask=db_user_tasks.get_object_or_none(db_user_tasks.UserTasks, id=task_id)
data={
'name':name,
'description':description,
'snippetid':int(snippetid) if snippetid else 0,
'cron':cron,
'desc_cron': get_description(cron),
'action': action,
'task_type':task_type,
'selection_type':selection_type,
'data':json.dumps(taskdata) if taskdata else None
}
# Update utask
utasks=db_user_tasks.UserTasks
utasks.update(**data).where(utasks.id == utask.id).execute()
# Delete old members
db_user_tasks.delete_members(utask.id)
# Add new members
if len(members):
db_user_tasks.add_member_to_task(task_id, members, selection_type)
try:
taskid=utask.id
crontab = CronTab(user=True)
directory=Path(app.root_path).parent.absolute()
command = "/usr/local/bin/python3 {}/task_run.py {} >> /var/log/cron.log 2>&1".format(directory,taskid)
comment = "MikroWizard task #" + "taskid:{};".format(taskid)
jobs = crontab.find_comment(comment)
if len(list(jobs)) > 0:
jobs = crontab.find_comment(comment)
crontab.remove(jobs)
crontab.write()
job = crontab.new(command=command,comment=comment)
job.setall(cron)
crontab.write()
db_syslog.add_syslog_event(get_myself(), "Task","Edit", get_ip(),get_agent(),json.dumps(input))
return buildResponse([{'status': 'success',"taskid":taskid}],200)
except Exception as e:
log.error(e)
return buildResponse({'status': 'failed','massage':str(e)},200)
@app.route('/api/user_tasks/delete', methods = ['POST'])
@login_required(role='admin',perm={'task':'full'})
def user_tasks_delete():
"""delete user task"""
input = request.json
taskid=input.get('taskid',False)
utaks=db_user_tasks.UserTasks
crontab = CronTab(user=True)
utask=db_user_tasks.get_object_or_none(db_user_tasks.UserTasks, id=taskid)
comment = "MikroWizard task #" + "taskid:{};".format(taskid)
if not taskid:
return buildResponse({'status': 'failed'},200,error="Wrong name/desc")
try:
jobs = crontab.find_comment(comment)
if len(list(jobs)) > 0:
jobs = crontab.find_comment(comment)
crontab.remove(jobs)
crontab.write()
# Delete old members
db_user_tasks.delete_members(utask.id)
# delete task
res=utaks.delete().where(utaks.id == utask.id).execute()
if res:
db_syslog.add_syslog_event(get_myself(), "Task","Delete", get_ip(),get_agent(),json.dumps(input))
return buildResponse([{'status': 'success',"taskid":res}],200)
else:
return buildResponse([{'status': 'failed',"massage":"record not exist"}],200)
except Exception as e:
log.error(e)
return buildResponse({'status': 'failed','massage':str(e)},200)