routes withe depths

pull/10/head
Steve Nyemba 3 months ago
parent b283d26717
commit 4e2430fc21

@ -113,7 +113,9 @@ def exists(**_args):
def html(_uri,_config) :
# _html = (open(uri)).read()
_path = _realpath(_uri,_config)
_context = _config['system']['context']
_context = str(_config['system']['context'])
# if '/' in _context :
# _context = _context.split('/')[-1]
_html = ( open(_path)).read()
_layout = _config['layout']
if 'location' in _layout :

@ -1,384 +1,385 @@
import json
from genericpath import isdir
import os
import pandas as pd
import transport
import copy
from jinja2 import Environment, BaseLoader, FileSystemLoader
import importlib
import importlib.util
# import json
# from genericpath import isdir
# import os
# import pandas as pd
# import transport
# import copy
# from jinja2 import Environment, BaseLoader, FileSystemLoader
# import importlib
# import importlib.util
from cms import disk, cloud
from . import basic
class Loader :
"""
This class is designed to exclusively load configuration from disk into an object
:path path to the configuraiton file
:location original location (caller)
"""
def __init__(self,**_args):
self._path = _args['path']
self._original_location = None if 'location' not in _args else _args['location']
self._location = None
self._caller = None if 'caller' not in _args else _args['caller']
self._menu = {}
self._plugins={}
self.load()
def load(self):
"""
This function will load menu (overwrite) and plugins
"""
self.init_config()
self.init_menu()
self.init_plugins()
def init_config(self):
"""
Initialize & loading configuration from disk
"""
f = open (self._path)
self._config = json.loads(f.read())
if self._caller :
self._location = self._original_location.split(os.sep) # needed for plugin loading
self._location = os.sep.join(self._location[:-1])
self._config['system']['portal'] = self._caller != None
#
# let's see if we have a location for a key (i.e security key) in the configuration
#
self.update_config()
# _system = self._config['system']
# if 'source' in _system and 'key' in _system['source'] :
# _path = _system['source']['key']
# if os.path.exists(_path):
# f = open(_path)
# _system['source']['key'] = f.read()
# f.close()
# self._system = _system
# self._config['system'] = _system
def update_config(self):
"""
We are going to update the configuration (source.key, layout.root)
"""
_system = self._config['system']
#
# updating security-key that allows the application to update on-demand
if 'source' in _system and 'key' in _system['source'] :
_path = _system['source']['key']
if os.path.exists(_path):
f = open(_path)
_system['source']['key'] = f.read()
f.close()
self._system = _system
self._config['system'] = _system
_layout = self._config['layout']
#
# update root so that the app can be launched from anywhere
# This would help reduce the footprint of the app/framework
_path = os.sep.join(self._path.split(os.sep)[:-1])
_p = 'source' not in _system
_q = 'source' in _system and _system['source']['id'] != 'cloud'
_r = os.path.exists(_layout['root'])
if not _r and (_p or _q) :
#
# If we did running this app from installed framework (this should not apply to dependent apps)
#
_root = os.sep.join([_path,_layout['root']])
self._config['layout']['root'] = _root
self._config['layout']['root_prefix'] = _root
def init_menu(self):
"""
This function will read menu and sub-menu items from disk structure,
The files are loaded will
"""
_config = self._config
if 'source' in _config['system'] and _config['system']['source']['id'] == 'cloud' :
_sourceHandler = cloud
else:
_sourceHandler = disk
_object = _sourceHandler.build(_config)
#
# After building the site's menu, let us add the one from 3rd party apps
#
_layout = copy.deepcopy(_config['layout'])
_overwrite = _layout['overwrite'] if 'overwrite' in _layout else {}
#
# @TODO: Find a way to translate rename/replace keys of the _object (menu) here
#
#-- applying overwrites to the menu items
for _name in _object :
_submenu = _object[_name]
_index = 0
for _item in _submenu :
text = _item['text'].strip()
if text in _overwrite :
if 'uri' in _item and 'url' in 'url' in _overwrite[text] :
del _item['uri']
_item = dict(_item,**_overwrite[text])
if 'uri' in _item and 'type' in _item and _item['type'] != 'open':
_item['uri'] = _item['uri'].replace(_layout['root'],'')
_submenu[_index] = _item
_index += 1
self.init_apps(_object)
self._menu = _object
self._order()
def init_apps (self,_menu):
"""
Insuring that the apps are loaded into the menu with an approriate label
"""
_system = self._config['system']
_context = _system['context']
if 'routes' in _system :
# _items = []
_overwrite = {} if 'overwrite' not in self._config['layout'] else self._config['layout']['overwrite']
for _text in _system['routes'] :
_item = _system['routes'][_text]
if 'menu' not in _item :
continue
uri = f'{_context}/{_text}'
# _items.append ({"text":_text,'uri':uri,'type':'open'})
_label = _item['menu']
if _label not in _menu :
_menu [_label] = []
_menu[_label].append ({"text":_text,'uri':uri,'type':'open'})
# _overwrite[_text] = {'text': _text.replace('-',' ').replace('_',' '),'uri':uri,'type':'open'}
# _menu['products'] = _items
#
# given that the menu items assumes redirecting to a page ...
# This is not the case
#
# self._config['overwrite'] = _overwrite
else:
pass
pass
def _order (self):
_config = self._config
if 'order' in _config['layout'] and 'menu' in _config['layout']['order']:
_sortedmenu = {}
_menu = self._menu
for _name in _config['layout']['order']['menu'] :
if _name in _menu :
_sortedmenu[_name] = _menu[_name]
_menu = _sortedmenu if _sortedmenu else _menu
#
# If there are missing items in the sorting
_missing = list(set(self._menu.keys()) - set(_sortedmenu))
if _missing :
for _name in _missing :
_menu[_name] = self._menu[_name]
_config['layout']['menu'] = _menu #cms.components.menu(_config)
self._menu = _menu
self._config = _config
def init_plugins(self) :
"""
This function looks for plugins in the folder on disk (no cloud support) and attempts to load them
"""
_config = self._config
PATH= os.sep.join([_config['layout']['root'],'_plugins'])
if not os.path.exists(PATH) :
#
# we need to determin if there's an existing
PATH = os.sep.join(self._path.split(os.sep)[:-1]+ [PATH] )
if not os.path.exists(PATH) and self._location and os.path.exists(self._location) :
#
# overriding the location of plugins ...
PATH = os.sep.join([self._location, _config['layout']['root'],'_plugins'])
_map = {}
# if not os.path.exists(PATH) :
# return _map
if 'plugins' not in _config :
_config['plugins'] = {}
_conf = _config['plugins']
for _key in _conf :
_path = os.sep.join([PATH,_key+".py"])
if not os.path.exists(_path):
continue
for _name in _conf[_key] :
_pointer = self._load_plugin(path=_path,name=_name)
if _pointer :
_uri = "/".join(["api",_key,_name])
_map[_uri] = _pointer
#
# We are adding some source specific plugins to the user-defined plugins
# This is intended to have out-of the box plugins...
#
if 'source' in _config['system'] and _config['system']['source']['id'] == 'cloud' :
_plugins = cloud.plugins()
else:
_plugins = disk.plugins()
#
# If there are any plugins found, we should load them and use them
if _plugins :
_map = dict(_map,**_plugins)
else:
pass
self._plugins = _map
self._config['plugins'] = self._plugins
def _load_plugin(self,**_args):
"""
This function will load external module form a given location and return a pointer to a function in a given module
:path absolute path of the file (considered plugin) to be loaded
:name name of the function to be applied
"""
_path = _args['path'] #os.sep.join([_args['root'],'plugin'])
if os.path.isdir(_path):
files = os.listdir(_path)
if files :
files = [name for name in files if name.endswith('.py')]
if files:
_path = os.sep.join([_path,files[0]])
else:
return None
else:
return None
#-- We have a file ...
_name = _args['name']
spec = importlib.util.spec_from_file_location(_name, _path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return getattr(module,_name) if hasattr(module,_name) else None
class Getter (Loader):
def __init__(self,**_args):
super().__init__(**_args)
def load(self):
super().load()
_system = self.system()
_logo = _system['logo']
if 'source' in _system and 'id' in _system['source'] and (_system['source']['id'] == 'cloud'):
_icon = f'/api/cloud/download?doc=/{_logo}'
_system['icon'] = _icon
else:
_root = self._config['layout']['root']
_icon = os.sep.join([_root,_logo])
_system['icon'] = _logo
self._config['system'] = _system
if self._caller :
_system['caller'] = {'icon': self._caller.system()['icon']}
def html(self,uri,id,_args={},_system={}) :
"""
This function reads a given uri and returns the appropriate html document, and applies environment context
"""
_system = self._config['system']
if 'source' in _system and _system['source']['id'] == 'cloud':
_html = cloud.html(uri,dict(_args,**{'system':_system}))
else:
_html = disk.html(uri,self.layout())
# _html = (open(uri)).read()
#return ' '.join(['<div id=":id" class=":id">'.replace(':id',id),_html,'</div>'])
_html = ' '.join(['<div id=":id" class=":id">'.replace(':id',id),_html,'</div>'])
appContext = Environment(loader=BaseLoader()).from_string(_html)
_args['system'] = _system
#
# If the rendering of the HTML happens here we should plugin custom functions (at the very least)
#
return appContext.render(**_args)
# return _html
def data (self,_args):
"""
:store data-store parameters (data-transport, github.com/lnyemba/data-transport)
:query query to be applied against the store (expected data-frame)
"""
_store = _args['store']
reader = transport.factory.instance(**_store)
_queries= copy.deepcopy(_store['query'])
_data = reader.read(**_queries)
return _data
def csv(self,uri) :
return pd.read(uri).to_html()
return _map
def menu(self):
return self._config['menu']
def plugins(self):
return copy.deepcopy(self._plugins) if 'plugins' in self._config else {}
def context(self):
"""
adding custom variables functions to Jinja2, this function should be called after plugins are loaded
"""
_plugins = self.plugins()
# if not location:
# env = Environment(loader=BaseLoader())
# else:
location = self._config['layout']['root']
# env = Environment(loader=FileSystemLoader(location))
env = Environment(loader=BaseLoader())
# env.globals['routes'] = _config['plugins']
return env
def config(self):
return copy.deepcopy(self._config)
def system(self,skip=[]):
"""
:skip keys to ignore in the object ...
"""
_data = copy.deepcopy(self._config['system'])
_system = {}
if skip and _system:
for key in _data.keys() :
if key not in skip :
_system[key] = _data[key]
else:
_system= _data
return _system
def layout(self):
return self._config['layout']
def get_app(self):
return self._config['system']['app']
class Router :
def __init__(self,**_args) :
# _app = Getter (path = path)
_app = Getter (**_args)
self._id = 'main'
# _app.load()
self._apps = {}
_system = _app.system()
if 'routes' in _system :
_system = _system['routes']
for _name in _system :
_path = _system[_name]['path']
self._apps[_name] = Getter(path=_path,caller=_app,location=_path)
self._apps['main'] = _app
def set(self,_id):
self._id = _id
def get(self):
return self._apps['main'] if self._id not in self._apps else self._apps[self._id]
def get_main(self):
return self._apps['main']
# class Loader :
# """
# This class is designed to exclusively load configuration from disk into an object
# :path path to the configuraiton file
# :location original location (caller)
# """
# def __init__(self,**_args):
# self._path = _args['path']
# self._original_location = None if 'location' not in _args else _args['location']
# self._location = None
# self._caller = None if 'caller' not in _args else _args['caller']
# print ([' *** ', self._caller])
# self._menu = {}
# self._plugins={}
# self.load()
# def load(self):
# """
# This function will load menu (overwrite) and plugins
# """
# self.init_config()
# self.init_menu()
# self.init_plugins()
# def init_config(self):
# """
# Initialize & loading configuration from disk
# """
# f = open (self._path)
# self._config = json.loads(f.read())
# if self._caller :
# self._location = self._original_location.split(os.sep) # needed for plugin loading
# self._location = os.sep.join(self._location[:-1])
# self._config['system']['portal'] = self._caller != None
# #
# # let's see if we have a location for a key (i.e security key) in the configuration
# #
# self.update_config()
# # _system = self._config['system']
# # if 'source' in _system and 'key' in _system['source'] :
# # _path = _system['source']['key']
# # if os.path.exists(_path):
# # f = open(_path)
# # _system['source']['key'] = f.read()
# # f.close()
# # self._system = _system
# # self._config['system'] = _system
# def update_config(self):
# """
# We are going to update the configuration (source.key, layout.root)
# """
# _system = self._config['system']
# #
# # updating security-key that allows the application to update on-demand
# if 'source' in _system and 'key' in _system['source'] :
# _path = _system['source']['key']
# if os.path.exists(_path):
# f = open(_path)
# _system['source']['key'] = f.read()
# f.close()
# self._system = _system
# self._config['system'] = _system
# _layout = self._config['layout']
# #
# # update root so that the app can be launched from anywhere
# # This would help reduce the footprint of the app/framework
# _path = os.sep.join(self._path.split(os.sep)[:-1])
# _p = 'source' not in _system
# _q = 'source' in _system and _system['source']['id'] != 'cloud'
# _r = os.path.exists(_layout['root'])
# if not _r and (_p or _q) :
# #
# # If we did running this app from installed framework (this should not apply to dependent apps)
# #
# _root = os.sep.join([_path,_layout['root']])
# self._config['layout']['root'] = _root
# self._config['layout']['root_prefix'] = _root
# def init_menu(self):
# """
# This function will read menu and sub-menu items from disk structure,
# The files are loaded will
# """
# _config = self._config
# if 'source' in _config['system'] and _config['system']['source']['id'] == 'cloud' :
# _sourceHandler = cloud
# else:
# _sourceHandler = disk
# _object = _sourceHandler.build(_config)
# #
# # After building the site's menu, let us add the one from 3rd party apps
# #
# _layout = copy.deepcopy(_config['layout'])
# _overwrite = _layout['overwrite'] if 'overwrite' in _layout else {}
# #
# # @TODO: Find a way to translate rename/replace keys of the _object (menu) here
# #
# #-- applying overwrites to the menu items
# for _name in _object :
# _submenu = _object[_name]
# _index = 0
# for _item in _submenu :
# text = _item['text'].strip()
# if text in _overwrite :
# if 'uri' in _item and 'url' in 'url' in _overwrite[text] :
# del _item['uri']
# _item = dict(_item,**_overwrite[text])
# if 'uri' in _item and 'type' in _item and _item['type'] != 'open':
# _item['uri'] = _item['uri'].replace(_layout['root'],'')
# _submenu[_index] = _item
# _index += 1
# self.init_apps(_object)
# self._menu = _object
# self._order()
# def init_apps (self,_menu):
# """
# Insuring that the apps are loaded into the menu with an approriate label
# """
# _system = self._config['system']
# _context = _system['context']
# if 'routes' in _system :
# # _items = []
# _overwrite = {} if 'overwrite' not in self._config['layout'] else self._config['layout']['overwrite']
# for _text in _system['routes'] :
# _item = _system['routes'][_text]
# if 'menu' not in _item :
# continue
# uri = f'{_context}/{_text}'
# # _items.append ({"text":_text,'uri':uri,'type':'open'})
# _label = _item['menu']
# if _label not in _menu :
# _menu [_label] = []
# _menu[_label].append ({"text":_text,'uri':uri,'type':'open'})
# # _overwrite[_text] = {'text': _text.replace('-',' ').replace('_',' '),'uri':uri,'type':'open'}
# # _menu['products'] = _items
# #
# # given that the menu items assumes redirecting to a page ...
# # This is not the case
# #
# # self._config['overwrite'] = _overwrite
# else:
# pass
# pass
# def _order (self):
# _config = self._config
# if 'order' in _config['layout'] and 'menu' in _config['layout']['order']:
# _sortedmenu = {}
# _menu = self._menu
# for _name in _config['layout']['order']['menu'] :
# if _name in _menu :
# _sortedmenu[_name] = _menu[_name]
# _menu = _sortedmenu if _sortedmenu else _menu
# #
# # If there are missing items in the sorting
# _missing = list(set(self._menu.keys()) - set(_sortedmenu))
# if _missing :
# for _name in _missing :
# _menu[_name] = self._menu[_name]
# _config['layout']['menu'] = _menu #cms.components.menu(_config)
# self._menu = _menu
# self._config = _config
# def init_plugins(self) :
# """
# This function looks for plugins in the folder on disk (no cloud support) and attempts to load them
# """
# _config = self._config
# PATH= os.sep.join([_config['layout']['root'],'_plugins'])
# if not os.path.exists(PATH) :
# #
# # we need to determin if there's an existing
# PATH = os.sep.join(self._path.split(os.sep)[:-1]+ [PATH] )
# if not os.path.exists(PATH) and self._location and os.path.exists(self._location) :
# #
# # overriding the location of plugins ...
# PATH = os.sep.join([self._location, _config['layout']['root'],'_plugins'])
# _map = {}
# # if not os.path.exists(PATH) :
# # return _map
# if 'plugins' not in _config :
# _config['plugins'] = {}
# _conf = _config['plugins']
# for _key in _conf :
# _path = os.sep.join([PATH,_key+".py"])
# if not os.path.exists(_path):
# continue
# for _name in _conf[_key] :
# _pointer = self._load_plugin(path=_path,name=_name)
# if _pointer :
# _uri = "/".join(["api",_key,_name])
# _map[_uri] = _pointer
# #
# # We are adding some source specific plugins to the user-defined plugins
# # This is intended to have out-of the box plugins...
# #
# if 'source' in _config['system'] and _config['system']['source']['id'] == 'cloud' :
# _plugins = cloud.plugins()
# else:
# _plugins = disk.plugins()
# #
# # If there are any plugins found, we should load them and use them
# if _plugins :
# _map = dict(_map,**_plugins)
# else:
# pass
# self._plugins = _map
# self._config['plugins'] = self._plugins
# def _load_plugin(self,**_args):
# """
# This function will load external module form a given location and return a pointer to a function in a given module
# :path absolute path of the file (considered plugin) to be loaded
# :name name of the function to be applied
# """
# _path = _args['path'] #os.sep.join([_args['root'],'plugin'])
# if os.path.isdir(_path):
# files = os.listdir(_path)
# if files :
# files = [name for name in files if name.endswith('.py')]
# if files:
# _path = os.sep.join([_path,files[0]])
# else:
# return None
# else:
# return None
# #-- We have a file ...
# _name = _args['name']
# spec = importlib.util.spec_from_file_location(_name, _path)
# module = importlib.util.module_from_spec(spec)
# spec.loader.exec_module(module)
# return getattr(module,_name) if hasattr(module,_name) else None
# class Getter (Loader):
# def __init__(self,**_args):
# super().__init__(**_args)
# def load(self):
# super().load()
# _system = self.system()
# _logo = _system['logo']
# if 'source' in _system and 'id' in _system['source'] and (_system['source']['id'] == 'cloud'):
# _icon = f'/api/cloud/download?doc=/{_logo}'
# _system['icon'] = _icon
# else:
# _root = self._config['layout']['root']
# _icon = os.sep.join([_root,_logo])
# _system['icon'] = _logo
# self._config['system'] = _system
# if self._caller :
# _system['caller'] = {'icon': self._caller.system()['icon']}
# def html(self,uri,id,_args={},_system={}) :
# """
# This function reads a given uri and returns the appropriate html document, and applies environment context
# """
# _system = self._config['system']
# if 'source' in _system and _system['source']['id'] == 'cloud':
# _html = cloud.html(uri,dict(_args,**{'system':_system}))
# else:
# _html = disk.html(uri,self.layout())
# # _html = (open(uri)).read()
# #return ' '.join(['<div id=":id" class=":id">'.replace(':id',id),_html,'</div>'])
# _html = ' '.join(['<div id=":id" class=":id">'.replace(':id',id),_html,'</div>'])
# appContext = Environment(loader=BaseLoader()).from_string(_html)
# _args['system'] = _system
# #
# # If the rendering of the HTML happens here we should plugin custom functions (at the very least)
# #
# return appContext.render(**_args)
# # return _html
# def data (self,_args):
# """
# :store data-store parameters (data-transport, github.com/lnyemba/data-transport)
# :query query to be applied against the store (expected data-frame)
# """
# _store = _args['store']
# reader = transport.factory.instance(**_store)
# _queries= copy.deepcopy(_store['query'])
# _data = reader.read(**_queries)
# return _data
# def csv(self,uri) :
# return pd.read(uri).to_html()
# return _map
# def menu(self):
# return self._config['menu']
# def plugins(self):
# return copy.deepcopy(self._plugins) if 'plugins' in self._config else {}
# def context(self):
# """
# adding custom variables functions to Jinja2, this function should be called after plugins are loaded
# """
# _plugins = self.plugins()
# # if not location:
# # env = Environment(loader=BaseLoader())
# # else:
# location = self._config['layout']['root']
# # env = Environment(loader=FileSystemLoader(location))
# env = Environment(loader=BaseLoader())
# # env.globals['routes'] = _config['plugins']
# return env
# def config(self):
# return copy.deepcopy(self._config)
# def system(self,skip=[]):
# """
# :skip keys to ignore in the object ...
# """
# _data = copy.deepcopy(self._config['system'])
# _system = {}
# if skip and _system:
# for key in _data.keys() :
# if key not in skip :
# _system[key] = _data[key]
# else:
# _system= _data
# return _system
# def layout(self):
# return self._config['layout']
# def get_app(self):
# return self._config['system']['app']
# class Router :
# def __init__(self,**_args) :
# # _app = Getter (path = path)
# _app = Getter (**_args)
# self._id = 'main'
# # _app.load()
# self._apps = {}
# _system = _app.system()
# if 'routes' in _system :
# _system = _system['routes']
# for _name in _system :
# _path = _system[_name]['path']
# self._apps[_name] = Getter(path=_path,caller=_app,location=_path)
# self._apps['main'] = _app
# def set(self,_id):
# self._id = _id
# def get(self):
# return self._apps['main'] if self._id not in self._apps else self._apps[self._id]
# def get_main(self):
# return self._apps['main']

@ -20,7 +20,7 @@ class Initializer :
"""
def __init__(self,**_args):
self._config = {'system':{},'layout':{},'plugins':{}}
self._shared = False if not 'shared' in _args else _args['shared']
# self._shared = False if not 'shared' in _args else _args['shared']
self._location= _args['location'] if 'location' in _args else None
self._menu = {}
# _source = self._config ['system']['source'] if 'source' in self._config['system'] else {}
@ -29,8 +29,13 @@ class Initializer :
self._ISCLOUD = False
self._caller = None if 'caller' not in _args else _args['caller']
self._args = _args
# if 'context' in _args :
# self._config
self.reload() #-- this is an initial load of various components
#
# @TODO:
# Each module should submit it's routers to the parent, and adjust the references given the callers
#
def reload(self):
@ -39,7 +44,7 @@ class Initializer :
self._isource()
self._imenu()
self._iplugins()
self._iroutes ()
# self._ISCLOUD = 'source' in self._config['system'] and self._config['system']['source']['id'] == 'cloud'
@ -52,7 +57,15 @@ class Initializer :
return cloud
else:
return disk
def _iroutes (self):
"""
Initializing routes to be submitted to the CMS Handler
The routes must be able to :
1. submit an object (dependency to the cms)
2. submit with the object a route associated
The CMS handler will resolve dependencies/redundancies
"""
pass
def _imenu(self,**_args) :
pass
def _iplugins(self,**_args) :
@ -252,8 +265,9 @@ class Initializer :
_callerContext = self._caller.system()['context']
if not self._config['system']['context'] :
self._config['system']['context'] = _callerContext
self._config['system']['caller'] = {'icon': 'caller/main/'+self._caller.system()['icon'].replace(_callerContext,'')}
_context = _callerContext
self._config['system']['caller'] = {'icon': '/main'+self._caller.system()['icon'].replace(_callerContext,'')}
_context = '/'.join([_callerContext,_context]) if _callerContext != '' else _context
if os.path.exists(_newpath) and not self._ISCLOUD:
@ -278,14 +292,15 @@ class Initializer :
else:
_icon = f'{_context}/api/disk/read?uri={_logo}'
if disk.exists(uri=_logo,config=self._config):
_icon = _logo
if self._location :
self._config['layout']['location'] = _path
self._config['system']['icon'] = _icon
self._config['system']['logo'] = _logo
# self.set('layout.root',os.sep.join([_path,_oroot]))
pass
class Module (Initializer):
@ -312,6 +327,15 @@ class Module (Initializer):
elif type(_stream) == io.StringIO :
self._config = json.loads( _stream.read())
self._ISCLOUD = 'source' in self._config['system'] and self._config['system']['source'] and self._config['system']['source']['id'] == 'cloud'
if self._caller :
self._config['system']['parentContext'] = self._caller.system()['context']
else:
self._config['system']['parentContext'] = self._config['system']['context']
if 'context' in _args :
self._config['system']['context'] = _args['context']
if '/' in self._config['system']['context'] :
self._config['system']['context'] = self._config['system']['context'].split('/')[-1]
#
#
# self._name = self._config['system']['name'] if 'name' in self._config['system'] else _args['name']
@ -361,6 +385,7 @@ class Module (Initializer):
class MicroService (Module):
"""
This is a CMS MicroService class that is capable of initializing a site and exposing Module functions
"""
def __init__(self,**_args):
super().__init__(**_args)
@ -402,7 +427,6 @@ class CMS:
_system = _system['routes']
for _name in _system :
_path = _system[_name]['path']
self._apps[_name] = MicroService(context=_name,path=_path,caller=_app,location=_path)
self._apps['main'] = _app

@ -22,35 +22,34 @@ from typing import Optional
import pandas as pd
import uuid
import datetime
import requests
from cms import disk, cloud, engine
_app = Flask(__name__)
cli = typer.Typer()
# @_app.route('/favicon.ico')
# def favicon():
# global _route
# _system = _route.get ().system()
# _handler = _route.get()
# _logo =_system['icon'] if 'icon' in _system else 'static/img/logo.svg'
# return _handler.get(_logo)
# # # _root = _route.get().config()['layout']['root']
# # # print ([_system])
# # # if 'source' in _system and 'id' in _system['source'] and (_system['source']['id'] == 'cloud'):
# # # uri = f'/api/cloud/downloads?doc=/{_logo}'
# # # print (['****' , uri])
# # # return redirect(uri,200) #,{'content-type':'application/image'}
# # # else:
# # # return send_from_directory(_root, #_app.root_path, 'static/img'),
# # _logo, mimetype='image/vnd.microsoft.icon')
def _getHandler () :
_id = session.get('app_id','main')
@_app.route('/<id>/favicon.ico')
def favicon(id):
global _route
# _system = _route.get ().system()
# _handler = _route.get()
_handler = _getHandler(id)
_system = _handler.system()
_logo =_system['icon'] #if 'icon' in _system else 'static/img/logo.svg'
_stream = requests.get(''.join([request.host_url,_logo]))
return "_stream",200,{"Content-Type":"image/png"} #_handler.get(_logo),200,{"content-type":"image/png"}
def _getHandler (app_id,resource=None) :
global _route
_id = _getId(app_id,resource)
return _route._apps[_id]
def _setHandler (id) :
session['app_id'] = id
def _getId(app_id,resource):
return '/'.join([app_id,resource]) if resource else app_id
def _setHandler (app_id,resource) :
session['app_id'] = _getId(app_id,resource)
@_app.route("/robots.txt")
def robots_txt():
"""
@ -75,26 +74,55 @@ def robots_txt():
# return '\n'.join(_info),200,{'Content-Type':'plain/text'}
return Response('\n'.join(_info), mimetype='text/plain')
@_app.route("/")
def _index ():
_handler = _getHandler()
_config = _handler.config()
def _getIndex (app_id ,resource=None):
_handler = _getHandler(app_id,resource)
_layout = _handler.layout()
_status_code = 200
global _route
_index_page = 'index.html'
_args = {}
print ([' serving ',session.get('app_id','NA'),_handler.layout()['root']])
_args={'system':_handler.system(skip=['source','app','data']),'layout':_handler.layout()}
try:
uri = os.sep.join([_config['layout']['root'], _config['layout']['index']])
_index_page = "index.html"
print ([_route])
_args = _route.render(uri,'index',session.get('app_id','main'))
except Exception as e:
# print ()
print (e)
_index_page = "404.html"
try :
_uri = os.sep.join([_layout['root'],_layout['index']])
_id = _getId(app_id,resource)
_args = _route.render(_uri,'index',_id)
return render_template(_index_page,**_args),200 if _index_page != "404.html" else 200
except Exception as e:
_status_code = 404
_index_page = '404.html'
print(e)
return render_template(_index_page,**_args),_status_code
@_app.route("/")
def _index ():
return _getIndex('main')
# def _xindex ():
# _handler = _getHandler()
# _config = _handler.config()
# global _route
# # print ([' serving ',session.get('app_id','NA'),_handler.layout()['root']])
# _args={'system':_handler.system(skip=['source','app','data']),'layout':_handler.layout()}
# try:
# uri = os.sep.join([_config['layout']['root'], _config['layout']['index']])
# _index_page = "index.html"
# _args = _route.render(uri,'index',session.get('app_id','main'))
# # _setHandler('main')
# except Exception as e:
# # print ()
# print (e)
# _index_page = "404.html"
# return render_template(_index_page,**_args),200 if _index_page != "404.html" else 200
@_app.route("/<app>/<resource>")
@_app.route("/<app>",defaults={'resource':None})
def _aindex (app,resource=None):
_handler = _getHandler(app,resource)
_setHandler(app,resource)
_html,_code = _getIndex(app,resource)
return _html,_code
# @_app.route('/id/<uid>')
# def people(uid):
# """
@ -115,23 +143,28 @@ def _dialog ():
_args = _route.render(_uri,'html',session.get('app_id','main'))
_args['title'] = _id
return render_template('dialog.html',**_args) #title=_id,html=_html)
@_app.route("/caller/<app>/api/<module>/<name>")
def _delegate_call(app,module,name):
global _route
_handler = _route._apps[app]
@_app.route("/api/<module>/<name>",defaults={'app':'main','key':None})
@_app.route("/<app>/api/<module>/<name>",defaults={'key':None})
@_app.route("/<app>/<key>/<module>/<name>",defaults={'key':None})
def _delegate_call(app,key,module,name):
_handler = _getHandler(app,key)
return _delegate(_handler,module,name)
@_app.route('/api/<module>/<name>')
def _api(module,name) :
# @_app.route('/api/<module>/<name>')
@_app.route("/<app_id>/<key>/api/<module>/<name>", methods=['GET'])
@_app.route("/api/<module>/<name>",defaults={'app_id':'main','key':None})
@_app.route("/<app_id>/api/<module>/<name>",defaults={'key':None})
def _api(app_id,key,module,name) :
"""
This endpoint will load a module and make a function call
:_module entry specified in plugins of the configuration
:_name name of the function to execute
"""
# global _config
# global _route
# _handler = _route.get()
_handler = _getHandler()
_handler = _getHandler( app_id,key)
return _delegate(_handler,module,name)
def _delegate(_handler,module,name):
@ -143,7 +176,7 @@ def _delegate(_handler,module,name):
_context = _handler.system()['context']
if _context :
uri = f'{_context}/{uri}'
_mimeType = 'application/octet-stream'
if uri not in _plugins :
_data = {}
_code = 404
@ -163,12 +196,21 @@ def _delegate(_handler,module,name):
_data = json.dumps(_data)
_code = 200 if _data else 500
return _data,_code,{'Content-Type':_mimeType}
@_app.route("/api/<module>/<name>" , methods=['POST'])
def _post (module,name):
# @_app.route("/api/<module>/<name>" , methods=['POST'],defaults={'app_id':'main','key':None})
# @_app.route('/<app_id>/api/<module>/<name>',methods=['POST'],defaults={'key':None})
# @_app.route('/<app_id>/<key>/api/<module>/<name>',methods=['POST'],defaults={'app_id':'main','key':None})
@_app.route("/<app_id>/<key>/api/<module>/<name>", methods=['POST'])
@_app.route("/api/<module>/<name>",defaults={'app_id':'main','key':None},methods=['POST'])
@_app.route("/<app_id>/api/<module>/<name>",defaults={'key':None},methods=['POST'])
def _post (app_id,key,module,name):
# global _config
# global _route
# _handler = _route.get()
_handler = _getHandler()
# app_id = '/'.join([app_id,key]) if key else app_id
_handler = _getHandler(app_id,key)
return _delegate(_handler,module,name)
@_app.route('/version')
@ -212,8 +254,11 @@ def reload():
# return "",200
# pass
# return "",403
@_app.route('/page',methods=['POST'])
def cms_page():
@_app.route('/page',methods=['POST'],defaults={'app_id':'main','key':None})
@_app.route('/<app_id>/page',methods=['POST'],defaults={'key':None})
@_app.route('/<app_id>/<key>/page',methods=['POST'])
def _POST_CMSPage(app_id,key):
"""
return the content of a folder formatted for a menu
"""
@ -221,7 +266,9 @@ def cms_page():
global _route
# _handler = _route.get()
# _config = _handler.config()
_handler = _getHandler()
_handler = _getHandler(app_id,key)
_setHandler(app_id,key)
_config = _handler.config()
# _uri = os.sep.join([_config['layout']['root'],request.headers['uri']])
_uri = request.headers['uri']
@ -244,11 +291,13 @@ def cms_page():
if 'read?uri=' in _uri or 'download?doc=' in _uri :
_uri = _uri.split('=')[1]
_args = _route.render(_uri,_id,session.get('app_id','main'))
_args = _route.render(_uri,_id,_getId(app_id,key)) #session.get(app_id,'main'))
return _args[_id],200
# return _html,200
@_app.route('/page')
def _cms_page ():
@_app.route('/page',defaults={'app_id':'main','resource':None})
@_app.route('/<app_id>/page',defaults={'resource':None},methods=['GET'])
@_app.route('/<app_id>/<resource>/page',methods=['GET'])
def _cms_page (app_id,resource):
# global _config
global _route
# _handler = _route.get()
@ -257,33 +306,33 @@ def _cms_page ():
# _uri = os.sep.join([_config['layout']['root'],_uri])
_title = request.args['title'] if 'title' in request.args else ''
_args = _route.render(_uri,_title,session.get('app_id','main'))
_args = _route.render(_uri,_title,session.get(app_id,'main'))
return _args[_title],200
@_app.route('/set/<id>')
def set(id):
global _route
_setHandler(id)
# _route.set(id)
# _handler = _route.get()
_handler = _getHandler()
_context = _handler.system()['context']
_uri = f'/{_context}'.replace('//','/')
return redirect(_uri)
@_app.route('/<id>')
def _open(id):
global _route
# _handler = _route.get()
# @_app.route('/set/<id>')
# def set(id):
# global _route
# _setHandler(id)
# # _route.set(id)
# # _handler = _route.get()
# _handler = _getHandler()
# _context = _handler.system()['context']
# _uri = f'/{_context}'.replace('//','/')
# return redirect(_uri)
# @_app.route('/<id>')
# def _open(id):
# global _route
# # _handler = _route.get()
_handler = _getHandler()
if id not in _route._apps :
# _handler = _getHandler()
# if id not in _route._apps :
_args = {'config':_handler.config(), 'layout':_handler.layout(),'system':_handler.system(skip=['source','app'])}
return render_template("404.html",**_args)
else:
_setHandler(id)
# _route.set(id)
return _index()
# _args = {'config':_handler.config(), 'layout':_handler.layout(),'system':_handler.system(skip=['source','app'])}
# return render_template("404.html",**_args)
# else:
# _setHandler(id)
# # _route.set(id)
# return _index()
@cli.command()
@ -310,6 +359,7 @@ def start (
# _route = cms.engine.Router(**_args) #path=path,shared=shared)
_route = cms.engine.basic.CMS(**_args)
# dir(_route)
# _args = _route.get().get_app()
_args = _route.get().app()

@ -12,43 +12,26 @@ bootup.CMSObserver = function(_sysId,_domId,_fileURI){
var http = HttpClient.instance()
http.setHeader('uri',_fileURI)
if (sessionStorage[_sysId] != null){
if (sessionStorage[_sysId] != null ){
var uri = sessionStorage[_sysId]+'/page'
}else{
var uri = '/page'
}
if (window.location.pathname != '/'){
uri = ([window.location.pathname,'page']).join('/')
}
try{
// var _domElement = jx.dom.get.instance('div')
// _domElement.className = 'busy-loading'
// jx.dom.append(_domId, _domElement)
http.post(uri,function(x){
// console.log(jx.dom.exists(_domId))
// var _domElement = jx.dom.get.instance('div')
// _domElement.className = 'busy-and-loading'
// jx.dom.append(_domId, _domElement)
if (x.status == 200){
// jx.dom.set.value(_domId,x.responseText)
// var _domElement = jx.dom.get.instance('div')
// _domElement.innerHTML = x.responseText
setTimeout(function(){
// _domElement.innerHTML = x.responseText
// _domElement.className = null
// $(_domElement).html(x.responseText)
$('#'+_domId).append(x.responseText)
// $(_domElement).attr('class',_domId)
//
// If there is a script associated it must be extracted and executed
// menu.runScript(_domId)
// console.log([_domId, ' **** ',$(_domId + ' script')])
},1500)

@ -1,5 +1,4 @@
<div class="icon">
<img src="{{system.icon}}">
</div>

@ -31,10 +31,10 @@ Vanderbilt University Medical Center
<!-- <link href="{{system.context}}/static/css/themes/{{system.theme}}" rel="stylesheet" type="text/css"> -->
<!-- <link href="{{system.context}}/static/css/icons.css" rel="stylesheet" type="text/css"> -->
<link href="{{system.context}}/static/css/icons.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/static/css/source-code.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/static/css/search.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/static/css/dialog.css" rel="stylesheet" type="text/css">
<link href="{{system.parentContext}}/static/css/icons.css" rel="stylesheet" type="text/css">
<link href="{{system.parentContext}}/static/css/source-code.css" rel="stylesheet" type="text/css">
<link href="{{system.parentContext}}/static/css/search.css" rel="stylesheet" type="text/css">
<link href="{{system.parentContext}}/static/css/dialog.css" rel="stylesheet" type="text/css">
<!-- applying themes as can -->
<link href="{{system.context}}/api/disk/read?uri={{layout.root}}/_assets/themes/{{system.theme}}/layout.css" rel="stylesheet" type="text/css">
@ -44,16 +44,16 @@ Vanderbilt University Medical Center
<link href="{{system.context}}/api/disk/read?uri={{layout.root}}/_assets/themes/{{system.theme}}/footer.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/api/disk/read?uri={{layout.root}}/_assets/themes/{{system.theme}}/pane.css" rel="stylesheet" type="text/css">
<script src="{{system.context}}/static/js/jx/dom.js"></script>
<script src="{{system.context}}/static/js/jx/utils.js"></script>
<script src="{{system.context}}/static/js/jx/rpc.js"></script>
<script src="{{system.context}}/static/js/jx/ext/modal.js"></script>
<script src="{{system.context}}/static/js/jx/ext/math.js"></script>
<script src="{{system.context}}/static/js/jquery/jquery.js"></script>
<script src="{{system.context}}/static/js/menu.js"></script>
<script src="{{system.context}}/static/js/search.js"></script>
<script src="{{system.context}}/static/js/bootup.js"></script>
<script src="{{system.context}}/static/js/fontawesome/js/all.js"></script>
<script src="{{system.parentContext}}/static/js/jx/dom.js"></script>
<script src="{{system.parentContext}}/static/js/jx/utils.js"></script>
<script src="{{system.parentContext}}/static/js/jx/rpc.js"></script>
<script src="{{system.parentContext}}/static/js/jx/ext/modal.js"></script>
<script src="{{system.parentContext}}/static/js/jx/ext/math.js"></script>
<script src="{{system.parentContext}}/static/js/jquery/jquery.js"></script>
<script src="{{system.parentContext}}/static/js/menu.js"></script>
<script src="{{system.parentContext}}/static/js/search.js"></script>
<script src="{{system.parentContext}}/static/js/bootup.js"></script>
<script src="{{system.parentContext}}/static/js/fontawesome/js/all.js"></script>
</head>
<script>
sessionStorage.setItem('{{system.id}}','{{system.context|safe}}')
@ -70,7 +70,7 @@ Vanderbilt University Medical Center
<body>
<div class="main {{system.theme}}">
<div id="header" class="header" onclick="window.location.href='{{system.context}}/'" style="cursor:pointer">
<div id="header" class="header" onclick="window.location.href='{{system.parentContext}}'" style="cursor:pointer">
{%include "header.html" %}
</div>

@ -1,7 +1,7 @@
{%if system.portal %}
<div class="icon active">
<div align="center" class="button" onclick="window.open('{{system.context}}/set/main','_self')" style="display:grid; grid-template-columns:auto auto; gap:4px; align-items:center ">
<div align="center" class="button" onclick="window.open('{{system.parentContext}}/','_self')" style="display:grid; grid-template-columns:auto auto; gap:4px; align-items:center ">
<i class="fa-solid fa-chevron-left" style="color:darkgray; display:block"></i>
<img src="{{system.caller.icon}}" style="height:100%"/>
</div>

Loading…
Cancel
Save