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) : def html(_uri,_config) :
# _html = (open(uri)).read() # _html = (open(uri)).read()
_path = _realpath(_uri,_config) _path = _realpath(_uri,_config)
_context = _config['system']['context'] _context = str(_config['system']['context'])
# if '/' in _context :
# _context = _context.split('/')[-1]
_html = ( open(_path)).read() _html = ( open(_path)).read()
_layout = _config['layout'] _layout = _config['layout']
if 'location' in _layout : if 'location' in _layout :

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

@ -20,7 +20,7 @@ class Initializer :
""" """
def __init__(self,**_args): def __init__(self,**_args):
self._config = {'system':{},'layout':{},'plugins':{}} 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._location= _args['location'] if 'location' in _args else None
self._menu = {} self._menu = {}
# _source = self._config ['system']['source'] if 'source' in self._config['system'] else {} # _source = self._config ['system']['source'] if 'source' in self._config['system'] else {}
@ -29,8 +29,13 @@ class Initializer :
self._ISCLOUD = False self._ISCLOUD = False
self._caller = None if 'caller' not in _args else _args['caller'] self._caller = None if 'caller' not in _args else _args['caller']
self._args = _args self._args = _args
# if 'context' in _args :
# self._config
self.reload() #-- this is an initial load of various components 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): def reload(self):
@ -39,7 +44,7 @@ class Initializer :
self._isource() self._isource()
self._imenu() self._imenu()
self._iplugins() self._iplugins()
self._iroutes ()
# self._ISCLOUD = 'source' in self._config['system'] and self._config['system']['source']['id'] == 'cloud' # self._ISCLOUD = 'source' in self._config['system'] and self._config['system']['source']['id'] == 'cloud'
@ -52,7 +57,15 @@ class Initializer :
return cloud return cloud
else: else:
return disk 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) : def _imenu(self,**_args) :
pass pass
def _iplugins(self,**_args) : def _iplugins(self,**_args) :
@ -252,8 +265,9 @@ class Initializer :
_callerContext = self._caller.system()['context'] _callerContext = self._caller.system()['context']
if not self._config['system']['context'] : if not self._config['system']['context'] :
self._config['system']['context'] = _callerContext self._config['system']['context'] = _callerContext
self._config['system']['caller'] = {'icon': 'caller/main/'+self._caller.system()['icon'].replace(_callerContext,'')} self._config['system']['caller'] = {'icon': '/main'+self._caller.system()['icon'].replace(_callerContext,'')}
_context = _callerContext _context = '/'.join([_callerContext,_context]) if _callerContext != '' else _context
if os.path.exists(_newpath) and not self._ISCLOUD: if os.path.exists(_newpath) and not self._ISCLOUD:
@ -278,14 +292,15 @@ class Initializer :
else: else:
_icon = f'{_context}/api/disk/read?uri={_logo}' _icon = f'{_context}/api/disk/read?uri={_logo}'
if disk.exists(uri=_logo,config=self._config): if disk.exists(uri=_logo,config=self._config):
_icon = _logo _icon = _logo
if self._location : if self._location :
self._config['layout']['location'] = _path self._config['layout']['location'] = _path
self._config['system']['icon'] = _icon self._config['system']['icon'] = _icon
self._config['system']['logo'] = _logo self._config['system']['logo'] = _logo
# self.set('layout.root',os.sep.join([_path,_oroot])) # self.set('layout.root',os.sep.join([_path,_oroot]))
pass pass
class Module (Initializer): class Module (Initializer):
@ -312,6 +327,15 @@ class Module (Initializer):
elif type(_stream) == io.StringIO : elif type(_stream) == io.StringIO :
self._config = json.loads( _stream.read()) 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' 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'] # 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): class MicroService (Module):
""" """
This is a CMS MicroService class that is capable of initializing a site and exposing Module functions This is a CMS MicroService class that is capable of initializing a site and exposing Module functions
""" """
def __init__(self,**_args): def __init__(self,**_args):
super().__init__(**_args) super().__init__(**_args)
@ -402,7 +427,6 @@ class CMS:
_system = _system['routes'] _system = _system['routes']
for _name in _system : for _name in _system :
_path = _system[_name]['path'] _path = _system[_name]['path']
self._apps[_name] = MicroService(context=_name,path=_path,caller=_app,location=_path) self._apps[_name] = MicroService(context=_name,path=_path,caller=_app,location=_path)
self._apps['main'] = _app self._apps['main'] = _app

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

@ -12,43 +12,26 @@ bootup.CMSObserver = function(_sysId,_domId,_fileURI){
var http = HttpClient.instance() var http = HttpClient.instance()
http.setHeader('uri',_fileURI) http.setHeader('uri',_fileURI)
if (sessionStorage[_sysId] != null){ if (sessionStorage[_sysId] != null ){
var uri = sessionStorage[_sysId]+'/page' var uri = sessionStorage[_sysId]+'/page'
}else{ }else{
var uri = '/page' var uri = '/page'
} }
if (window.location.pathname != '/'){
uri = ([window.location.pathname,'page']).join('/')
}
try{ try{
// var _domElement = jx.dom.get.instance('div') // var _domElement = jx.dom.get.instance('div')
// _domElement.className = 'busy-loading' // _domElement.className = 'busy-loading'
// jx.dom.append(_domId, _domElement) // jx.dom.append(_domId, _domElement)
http.post(uri,function(x){ 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){ if (x.status == 200){
// jx.dom.set.value(_domId,x.responseText)
// var _domElement = jx.dom.get.instance('div')
// _domElement.innerHTML = x.responseText
setTimeout(function(){ setTimeout(function(){
// _domElement.innerHTML = x.responseText
// _domElement.className = null
// $(_domElement).html(x.responseText)
$('#'+_domId).append(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) },1500)

@ -1,5 +1,4 @@
<div class="icon"> <div class="icon">
<img src="{{system.icon}}"> <img src="{{system.icon}}">
</div> </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/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/icons.css" rel="stylesheet" type="text/css"> <link href="{{system.parentContext}}/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.parentContext}}/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.parentContext}}/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/dialog.css" rel="stylesheet" type="text/css">
<!-- applying themes as can --> <!-- 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"> <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}}/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"> <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.parentContext}}/static/js/jx/dom.js"></script>
<script src="{{system.context}}/static/js/jx/utils.js"></script> <script src="{{system.parentContext}}/static/js/jx/utils.js"></script>
<script src="{{system.context}}/static/js/jx/rpc.js"></script> <script src="{{system.parentContext}}/static/js/jx/rpc.js"></script>
<script src="{{system.context}}/static/js/jx/ext/modal.js"></script> <script src="{{system.parentContext}}/static/js/jx/ext/modal.js"></script>
<script src="{{system.context}}/static/js/jx/ext/math.js"></script> <script src="{{system.parentContext}}/static/js/jx/ext/math.js"></script>
<script src="{{system.context}}/static/js/jquery/jquery.js"></script> <script src="{{system.parentContext}}/static/js/jquery/jquery.js"></script>
<script src="{{system.context}}/static/js/menu.js"></script> <script src="{{system.parentContext}}/static/js/menu.js"></script>
<script src="{{system.context}}/static/js/search.js"></script> <script src="{{system.parentContext}}/static/js/search.js"></script>
<script src="{{system.context}}/static/js/bootup.js"></script> <script src="{{system.parentContext}}/static/js/bootup.js"></script>
<script src="{{system.context}}/static/js/fontawesome/js/all.js"></script> <script src="{{system.parentContext}}/static/js/fontawesome/js/all.js"></script>
</head> </head>
<script> <script>
sessionStorage.setItem('{{system.id}}','{{system.context|safe}}') sessionStorage.setItem('{{system.id}}','{{system.context|safe}}')
@ -68,9 +68,9 @@ Vanderbilt University Medical Center
}) })
</script> </script>
<body> <body>
<div class="main {{system.theme}}"> <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" %} {%include "header.html" %}
</div> </div>

@ -1,7 +1,7 @@
{%if system.portal %} {%if system.portal %}
<div class="icon active"> <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> <i class="fa-solid fa-chevron-left" style="color:darkgray; display:block"></i>
<img src="{{system.caller.icon}}" style="height:100%"/> <img src="{{system.caller.icon}}" style="height:100%"/>
</div> </div>

Loading…
Cancel
Save