Split/cleanup the API code

This commit is contained in:
wez3 2017-01-21 02:04:32 +01:00
parent d7b34089ea
commit 7aa6c579e9
7 changed files with 302 additions and 267 deletions

View File

@ -1 +1 @@
1.0.1 1.0.2

View File

@ -3,22 +3,53 @@
from flask import request from flask import request
from flaskext.auth import login_required from flaskext.auth import login_required
import git import json, os, sys
import security import security, charts, plugins, webconfig, domoticz
import requests, json, re
import os, sys, imp, shutil
apiDict = {} apiDict = {}
indexes = {} modules = {}
def init(): def init():
global modules global modules
modules = loadPlugins() modules = plugins.loadPlugins()
return 0 return
def addToApi(custom, module, function): def addToApi(custom, module, function):
apiDict[custom] = [module, function] apiDict[custom] = [module, function]
@login_required()
def gateway():
requestedUrl = request.url.split("/api")
custom = request.args.get('custom', '')
if custom == "bar_chart":
result = charts.barChart()
elif custom == "donut_chart":
result = charts.donutChart()
elif custom == "modify_config":
idx = request.args.get('idx', '')
page = request.args.get('page', '')
component = request.args.get('component', '')
description = request.args.get('description', '')
extra = request.args.get('extra', '')
webconfig.writeToConfig(idx, page, component, description, extra)
elif custom == 'indexPlugins':
result = json.dumps(plugins.indexPlugins(request.args))
elif custom == "performUpgrade":
result = json.dumps(webconfig.performUpgrade())
elif custom in apiDict:
module = apiDict.get(custom)[0]
function = apiDict.get(custom)[1]
call = getattr(modules[module], function)
result = call(request.args)
else:
result = domoticz.queryDomoticz(requestedUrl[1])
try:
if not isJson(result):
result = json.dumps(result)
return security.sanitizeJSON(json.loads(result))
except:
return "No results returned"
def setConfig(cfg, orig_cfg): def setConfig(cfg, orig_cfg):
global config global config
global originalCfg global originalCfg
@ -26,267 +57,14 @@ def setConfig(cfg, orig_cfg):
originalCfg = orig_cfg originalCfg = orig_cfg
def getConfig(): def getConfig():
global config
return config return config
def loadPlugins(): def getOriginalConfig():
plugin = {} return originalCfg
plugin_dir = os.getcwd() + '/plugins/'
for i in os.listdir(plugin_dir):
if not i == '__init__.py' and i.endswith('.py'):
name = i.replace('.py', '')
try:
plugin[name] = imp.load_source(name, plugin_dir + i)
plugin[name].init()
except ImportError as msg:
sys.exit("Error occured during loading imports for the plugin {}: {}".format(name, msg))
return plugin
@login_required() def isJson(myjson):
def gateway():
requestedUrl = request.url.split("/api")
custom = request.args.get('custom', '')
if custom == "bar_chart":
idxs = request.args.get('idxs', '')
idxArray = idxs.split(",")
resultArray = []
resultDict = {}
for i in idxArray:
qResults = queryDomoticz("?type=devices&rid=" + i)
jsonObj = json.loads(qResults)
resultDict["y"] = jsonObj["result"][0]["Name"]
resultDict["a"] = jsonObj["result"][0]["Data"]
resultArray.append(resultDict.copy())
result = json.dumps(resultArray)
elif custom == "donut_chart":
idxs = request.args.get('idxs', '')
idxArray = idxs.split(",")
resultArray = []
resultDict = {}
for i in idxArray:
qResults = queryDomoticz("?type=devices&rid=" + i)
jsonObj = json.loads(qResults)
resultDict["label"] = jsonObj["result"][0]["Name"]
resultDict["value"] = re.findall("\d+\.?\d+", jsonObj["result"][0]["Data"])
resultArray.append(resultDict.copy())
result = json.dumps(resultArray)
elif custom == "modify_config":
idx = request.args.get('idx', '')
page = request.args.get('page', '')
component = request.args.get('component', '')
description = request.args.get('description', '')
extra = request.args.get('extra', '')
writeToConfig(idx, page, component, description, extra)
elif custom == 'indexPlugins':
result = json.dumps(indexPlugins(request.args))
elif custom == "performUpgrade":
result = json.dumps(performUpgrade())
elif custom in apiDict:
module = apiDict.get(custom)[0]
function = apiDict.get(custom)[1]
call = getattr(modules[module], function)
result = call(request.args)
else:
result = queryDomoticz(requestedUrl[1])
try:
if not is_json(result):
result = json.dumps(result)
return security.sanitizeJSON(json.loads(result))
except:
return "No results returned"
def is_json(myjson):
try: try:
json_object = json.loads(str(myjson)) json_object = json.loads(str(myjson))
except ValueError, e: except ValueError, e:
return False return False
return True return True
def queryDomoticz(url):
try:
r = requests.get('http://' + config["general_settings"]["server"]["url"] + '/json.htm' + url,
auth=(config["general_settings"]["server"].get("user"), config["general_settings"]["server"].get("password")), timeout=5.00)
except:
return {}
return r.text
def writeToConfig(idx, page, component, description, extra):
section = dict(originalCfg[page][component])
section[description] = idx
originalCfg[page][component] = section
originalCfg.write()
def checkDomoticzStatus(config):
domoticzDevices = []
domoticzScenes = []
try:
result = json.loads(queryDomoticz("?type=devices&filter=all"))
resultScene = json.loads(queryDomoticz("?type=scenes&filter=all"))
except:
sys.exit("Domoticz is not reachable.")
for device in result["result"]:
domoticzDevices.append(device["idx"])
if 'result' in resultScene:
for device in resultScene["result"]:
domoticzScenes.append(device["idx"])
configuredDevicesInDomoticz(config, domoticzDevices, domoticzScenes)
def configuredDevicesInDomoticz(config, domoticzDevices, domoticzScenes):
for k, v in config.iteritems():
if isinstance(v, dict):
configuredDevicesInDomoticz(v, domoticzDevices, domoticzScenes)
else:
if isinstance(v, int):
if v not in domoticzDevices and v not in domoticzScenes:
sys.exit("Device and/or scene with IDX {} is not available in Domoticz".format(v))
elif isinstance(v, list):
if (v[0].isdigit()) and (v[0] not in domoticzDevices and v[0] not in domoticzScenes):
sys.exit("Device and/or scene with IDX {} is not available in Domoticz".format(v[0]))
def getPluginDict():
global indexes
return indexes
def setPluginDict(d):
global indexes
indexes = d
def getPluginVersion(loc):
f = open(loc, 'r').read().split('\n')
v = None
for l in f:
t = l.split('=')
if t[0] == '@version':
_tmp_v = t[1].split('.')
c = 1
_version = _tmp_v[0] + '.'
while(c < len(_tmp_v)):
_version += _tmp_v[c]
c += 1
return float(_version)
def getVersion():
f = open('VERSION.md', 'r')
version = f.read().rstrip()
f.close()
return version
def performUpgrade():
git.cmd.Git('.').pull("https://github.com/wez3/domoboard.git")
return "Upgrade completed."
def getCurrentBranch():
repo = git.Repo('.')
branch = repo.active_branch
return branch.name
def indexPlugins(params={}):
tmpFolder = 'static/tmp'
indexFolderPath = 'static/tmp/pluginsIndex/'
docsFolderPath = 'static/docs/'
installedPlugins = []
staticFolder = ['css/', 'images/', 'fonts/', 'js/']
indexes = getPluginDict()
pluginParts = ['templates/', 'plugins/']
if 'action' in params:
if not params['action'] == 'getPlugins':
try:
if not int(params['folid']) in indexes:
return "No valid plugin id specified."
except:
return "Please specify integers only."
if 'action' in params:
if params['action'] == 'getPlugins':
folders = filter(lambda x: os.path.isdir(os.path.join(indexFolderPath, x)),
os.listdir(indexFolderPath))
for i in folders:
i = security.sanitizePathBasename(i)
if i != '.git':
fol = {}
fol['id'] = len(indexes)
fol['folder'] = i
fol['status'] = 'install'
for filename in os.listdir('templates/'):
installedPlugins.append(filename)
for filename in os.listdir(indexFolderPath + i + '/templates'):
if filename in installedPlugins:
installed_version = getPluginVersion(docsFolderPath + i + '_readme.md')
indexed_version = getPluginVersion(indexFolderPath + i + '/' + docsFolderPath + 'readme.md')
if indexed_version > installed_version:
fol['update'] = 'yes'
else:
fol['update'] = 'no'
fol['status'] = 'remove'
readme = open(indexFolderPath + i + '/' + docsFolderPath + 'readme.md', 'r').read().split('\n')
sumList = {}
for s in readme:
t = s.split('=')
if len(t) > 1:
fol[t[0].replace('@', '')] = t[1]
if not i in (f['folder'] for f in indexes.itervalues()):
indexes[len(indexes)] = fol
else:
for tmp in indexes.itervalues():
if i == tmp['folder']:
for k in fol:
if k != 'id':
indexes[tmp['id']][k] = fol[k]
setPluginDict(indexes)
return indexes
elif params['action'] == 'installPlugin':
if 'folid' in params:
if indexes[int(params['folid'])]['status'] == 'install':
src_path = indexFolderPath + indexes[int(params['folid'])]['folder'] + '/'
for part in pluginParts:
for filename in os.listdir(src_path + part):
shutil.copy(src_path + part + filename, part + filename)
for f in staticFolder:
if os.path.exists(src_path + 'static/' + f):
for filename in os.listdir(src_path + '/static/' + f):
shutil.copy(src_path + 'static/' + f + filename, 'static/' + f + filename)
for filename in os.listdir(src_path + '/' + docsFolderPath):
shutil.copy(src_path + '/' + docsFolderPath + filename, docsFolderPath + indexes[int(params['folid'])]['folder'] + '_' + filename)
indexes[int(params['folid'])]['status'] = 'remove'
global modules
modules = loadPlugins()
return indexes[int(params['folid'])]['folder'] + ' installed.'
else:
return "This plugin is already installed."
elif params['action'] == 'removePlugin':
if 'folid' in params:
if indexes[int(params['folid'])]['status'] == 'remove':
src_path = indexFolderPath + indexes[int(params['folid'])]['folder'] + '/'
for part in pluginParts:
for filename in os.listdir(src_path + part):
os.remove(part + filename)
for f in staticFolder:
if os.path.exists(src_path + 'static/' + f):
for filename in os.listdir(src_path + 'static/' + f):
os.remove('static/' + f + filename)
for filename in os.listdir(src_path + '/' + docsFolderPath):
shutil.copy(src_path + '/' + docsFolderPath + filename, docsFolderPath + indexes[int(params['folid'])]['folder'] + '_' + filename)
indexes[int(params['folid'])]['status'] = 'install'
return indexes[int(params['folid'])]['folder'] + ' removed.'
else:
return "This plugin was already removed."
setPluginDict(indexes)
else:
if not os.path.exists(tmpFolder):
os.makedirs(tmpFolder)
if not os.path.exists(indexFolderPath):
os.makedirs(indexFolderPath)
if not os.path.isfile(indexFolderPath + 'README.md'):
shutil.rmtree(indexFolderPath)
try:
git.Repo.clone_from("https://github.com/wez3/domoboard-plugins.git", indexFolderPath)
except:
print 'indexed'
else:
git.cmd.Git(indexFolderPath).pull("https://github.com/wez3/domoboard-plugins.git")
folders = filter(lambda x: os.path.isdir(os.path.join(indexFolderPath, x)),
os.listdir(indexFolderPath))
return indexPlugins({'action': 'getPlugins'})

33
modules/charts.py Normal file
View File

@ -0,0 +1,33 @@
#!/usr/bin/python
# Provides all charts functionality
import json, re, domoticz
from flask import request
def barChart():
idxs = request.args.get('idxs', '')
idxArray = idxs.split(",")
resultArray = []
resultDict = {}
for i in idxArray:
qResults = domoticz.queryDomoticz("?type=devices&rid=" + i)
jsonObj = json.loads(qResults)
resultDict["y"] = jsonObj["result"][0]["Name"]
resultDict["a"] = jsonObj["result"][0]["Data"]
resultArray.append(resultDict.copy())
result = json.dumps(resultArray)
return result
def donutChart():
idxs = request.args.get('idxs', '')
idxArray = idxs.split(",")
resultArray = []
resultDict = {}
for i in idxArray:
qResults = domoticz.queryDomoticz("?type=devices&rid=" + i)
jsonObj = json.loads(qResults)
resultDict["label"] = jsonObj["result"][0]["Name"]
resultDict["value"] = re.findall("\d+\.?\d+", jsonObj["result"][0]["Data"])
resultArray.append(resultDict.copy())
result = json.dumps(resultArray)
return result

41
modules/domoticz.py Normal file
View File

@ -0,0 +1,41 @@
#!/usr/bin/python
# This file contains all Domoticz related Python functions
import requests, json, sys
import api
def queryDomoticz(url):
config = api.getConfig()
try:
r = requests.get('http://' + config["general_settings"]["server"]["url"] + '/json.htm' + url,
auth=(config["general_settings"]["server"].get("user"), config["general_settings"]["server"].get("password")), timeout=5.00)
except:
return {}
return r.text
def checkDomoticzStatus(config):
domoticzDevices = []
domoticzScenes = []
try:
result = json.loads(queryDomoticz("?type=devices&filter=all"))
resultScene = json.loads(queryDomoticz("?type=scenes&filter=all"))
except:
sys.exit("Domoticz is not reachable.")
for device in result["result"]:
domoticzDevices.append(device["idx"])
if 'result' in resultScene:
for device in resultScene["result"]:
domoticzScenes.append(device["idx"])
configuredDevicesInDomoticz(config, domoticzDevices, domoticzScenes)
def configuredDevicesInDomoticz(config, domoticzDevices, domoticzScenes):
for k, v in config.iteritems():
if isinstance(v, dict):
configuredDevicesInDomoticz(v, domoticzDevices, domoticzScenes)
else:
if isinstance(v, int):
if v not in domoticzDevices and v not in domoticzScenes:
sys.exit("Device and/or scene with IDX {} is not available in Domoticz".format(v))
elif isinstance(v, list):
if (v[0].isdigit()) and (v[0] not in domoticzDevices and v[0] not in domoticzScenes):
sys.exit("Device and/or scene with IDX {} is not available in Domoticz".format(v[0]))

153
modules/plugins.py Normal file
View File

@ -0,0 +1,153 @@
#!/usr/bin/python
# This file contains the functions regarding the plugin manager.
import git, shutil, os, imp
import security
indexes = {}
def loadPlugins():
plugin = {}
plugin_dir = os.getcwd() + '/plugins/'
for i in os.listdir(plugin_dir):
if not i == '__init__.py' and i.endswith('.py'):
name = i.replace('.py', '')
try:
plugin[name] = imp.load_source(name, plugin_dir + i)
plugin[name].init()
except ImportError as msg:
sys.exit("Error occured during loading imports for the plugin {}: {}".format(name, msg))
return plugin
def getPluginDict():
global indexes
return indexes
def setPluginDict(d):
global indexes
indexes = d
def getPluginVersion(loc):
f = open(loc, 'r').read().split('\n')
v = None
for l in f:
t = l.split('=')
if t[0] == '@version':
_tmp_v = t[1].split('.')
c = 1
_version = _tmp_v[0] + '.'
while(c < len(_tmp_v)):
_version += _tmp_v[c]
c += 1
return float(_version)
def indexPlugins(params={}):
tmpFolder = 'static/tmp'
indexFolderPath = 'static/tmp/pluginsIndex/'
docsFolderPath = 'static/docs/'
installedPlugins = []
staticFolder = ['css/', 'images/', 'fonts/', 'js/']
indexes = getPluginDict()
pluginParts = ['templates/', 'plugins/']
if 'action' in params:
if not params['action'] == 'getPlugins':
try:
if not int(params['folid']) in indexes:
return "No valid plugin id specified."
except:
return "Please specify integers only."
if 'action' in params:
if params['action'] == 'getPlugins':
folders = filter(lambda x: os.path.isdir(os.path.join(indexFolderPath, x)),
os.listdir(indexFolderPath))
for i in folders:
i = security.sanitizePathBasename(i)
if i != '.git':
fol = {}
fol['id'] = len(indexes)
fol['folder'] = i
fol['status'] = 'install'
for filename in os.listdir('templates/'):
installedPlugins.append(filename)
for filename in os.listdir(indexFolderPath + i + '/templates'):
if filename in installedPlugins:
installed_version = getPluginVersion(docsFolderPath + i + '_readme.md')
indexed_version = getPluginVersion(indexFolderPath + i + '/' + docsFolderPath + 'readme.md')
if indexed_version > installed_version:
fol['update'] = 'yes'
else:
fol['update'] = 'no'
fol['status'] = 'remove'
readme = open(indexFolderPath + i + '/' + docsFolderPath + 'readme.md', 'r').read().split('\n')
sumList = {}
for s in readme:
t = s.split('=')
if len(t) > 1:
fol[t[0].replace('@', '')] = t[1]
if not i in (f['folder'] for f in indexes.itervalues()):
indexes[len(indexes)] = fol
else:
for tmp in indexes.itervalues():
if i == tmp['folder']:
for k in fol:
if k != 'id':
indexes[tmp['id']][k] = fol[k]
setPluginDict(indexes)
return indexes
elif params['action'] == 'installPlugin':
if 'folid' in params:
if indexes[int(params['folid'])]['status'] == 'install':
src_path = indexFolderPath + indexes[int(params['folid'])]['folder'] + '/'
for part in pluginParts:
for filename in os.listdir(src_path + part):
shutil.copy(src_path + part + filename, part + filename)
for f in staticFolder:
if os.path.exists(src_path + 'static/' + f):
for filename in os.listdir(src_path + '/static/' + f):
shutil.copy(src_path + 'static/' + f + filename, 'static/' + f + filename)
for filename in os.listdir(src_path + '/' + docsFolderPath):
shutil.copy(src_path + '/' + docsFolderPath + filename, docsFolderPath + indexes[int(params['folid'])]['folder'] + '_' + filename)
indexes[int(params['folid'])]['status'] = 'remove'
global modules
modules = loadPlugins()
return indexes[int(params['folid'])]['folder'] + ' installed.'
else:
return "This plugin is already installed."
elif params['action'] == 'removePlugin':
if 'folid' in params:
if indexes[int(params['folid'])]['status'] == 'remove':
src_path = indexFolderPath + indexes[int(params['folid'])]['folder'] + '/'
for part in pluginParts:
for filename in os.listdir(src_path + part):
os.remove(part + filename)
for f in staticFolder:
if os.path.exists(src_path + 'static/' + f):
for filename in os.listdir(src_path + 'static/' + f):
os.remove('static/' + f + filename)
for filename in os.listdir(src_path + '/' + docsFolderPath):
shutil.copy(src_path + '/' + docsFolderPath + filename, docsFolderPath + indexes[int(params['folid'])]['folder'] + '_' + filename)
indexes[int(params['folid'])]['status'] = 'install'
return indexes[int(params['folid'])]['folder'] + ' removed.'
else:
return "This plugin was already removed."
setPluginDict(indexes)
else:
if not os.path.exists(tmpFolder):
os.makedirs(tmpFolder)
if not os.path.exists(indexFolderPath):
os.makedirs(indexFolderPath)
if not os.path.isfile(indexFolderPath + 'README.md'):
shutil.rmtree(indexFolderPath)
try:
git.Repo.clone_from("https://github.com/wez3/domoboard-plugins.git", indexFolderPath)
except:
print 'indexed'
else:
git.cmd.Git(indexFolderPath).pull("https://github.com/wez3/domoboard-plugins.git")
folders = filter(lambda x: os.path.isdir(os.path.join(indexFolderPath, x)),
os.listdir(indexFolderPath))
return indexPlugins({'action': 'getPlugins'})

28
modules/webconfig.py Normal file
View File

@ -0,0 +1,28 @@
#!/usr/bin/python
# This file contains the functions used for web based configuration of domoboard
import git
import api
from flask import request
def writeToConfig(idx, page, component, description, extra):
originalCfg = api.getOriginalConfig()
section = dict(originalCfg[page][component])
section[description] = idx
originalCfg[page][component] = section
originalCfg.write()
def getVersion():
f = open('VERSION.md', 'r')
version = f.read().rstrip()
f.close()
return version
def performUpgrade():
git.cmd.Git('.').pull("https://github.com/wez3/domoboard.git")
return "Upgrade completed."
def getCurrentBranch():
repo = git.Repo('.')
branch = repo.active_branch
return branch.name

View File

@ -6,7 +6,9 @@ from collections import OrderedDict
import argparse, socket, re import argparse, socket, re
import hashlib, configobj, json, sys, os import hashlib, configobj, json, sys, os
import modules.api as api import modules.api as api
import modules.domoticz as domoticz
import modules.security as security import modules.security as security
import modules.webconfig as webconfig
app = Flask(__name__) app = Flask(__name__)
@ -46,8 +48,8 @@ def generatePage():
configValues = configValues, configValues = configValues,
blockArray = blockArray, blockArray = blockArray,
_csrf_token = session['_csrf_token'], _csrf_token = session['_csrf_token'],
version = api.getVersion(), version = webconfig.getVersion(),
branch = api.getCurrentBranch(), branch = webconfig.getCurrentBranch(),
debug = app.debug) debug = app.debug)
else: else:
abort(404) abort(404)
@ -154,7 +156,7 @@ if __name__ == '__main__':
api.setConfig(config, unsanitizedConfig) api.setConfig(config, unsanitizedConfig)
api.init() api.init()
validateConfigFormat(config) validateConfigFormat(config)
api.checkDomoticzStatus(config) domoticz.checkDomoticzStatus(config)
server_location = config["general_settings"]["server"]["url"] server_location = config["general_settings"]["server"]["url"]
flask_server_location = config["general_settings"]["server"]["flask_url"] flask_server_location = config["general_settings"]["server"]["flask_url"]
auth = Auth(app, login_url_name='login_form') auth = Auth(app, login_url_name='login_form')