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_menu() # self.init_config()
self.init_plugins() # self.init_menu()
def init_config(self): # self.init_plugins()
""" # def init_config(self):
Initialize & loading configuration from disk # """
""" # Initialize & loading configuration from disk
f = open (self._path) # """
self._config = json.loads(f.read()) # 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 # if self._caller :
self._location = os.sep.join(self._location[:-1]) # self._location = self._original_location.split(os.sep) # needed for plugin loading
self._config['system']['portal'] = self._caller != None # 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 # #
# # # 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'] # self.update_config()
# if 'source' in _system and 'key' in _system['source'] : # # _system = self._config['system']
# _path = _system['source']['key'] # # if 'source' in _system and 'key' in _system['source'] :
# if os.path.exists(_path): # # _path = _system['source']['key']
# f = open(_path) # # if os.path.exists(_path):
# _system['source']['key'] = f.read() # # f = open(_path)
# f.close() # # _system['source']['key'] = f.read()
# self._system = _system # # f.close()
# self._config['system'] = _system # # self._system = _system
def update_config(self): # # self._config['system'] = _system
""" # 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 # #
if 'source' in _system and 'key' in _system['source'] : # # updating security-key that allows the application to update on-demand
_path = _system['source']['key'] # if 'source' in _system and 'key' in _system['source'] :
if os.path.exists(_path): # _path = _system['source']['key']
f = open(_path) # if os.path.exists(_path):
_system['source']['key'] = f.read() # f = open(_path)
f.close() # _system['source']['key'] = f.read()
self._system = _system # f.close()
self._config['system'] = _system # self._system = _system
_layout = self._config['layout'] # 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 # # update root so that the app can be launched from anywhere
_path = os.sep.join(self._path.split(os.sep)[:-1]) # # This would help reduce the footprint of the app/framework
_p = 'source' not in _system # _path = os.sep.join(self._path.split(os.sep)[:-1])
_q = 'source' in _system and _system['source']['id'] != 'cloud' # _p = 'source' not in _system
_r = os.path.exists(_layout['root']) # _q = 'source' in _system and _system['source']['id'] != 'cloud'
if not _r and (_p or _q) : # _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) # #
# # # 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 # _root = os.sep.join([_path,_layout['root']])
self._config['layout']['root_prefix'] = _root # self._config['layout']['root'] = _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, # """
The files are loaded will # 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' : # _config = self._config
_sourceHandler = cloud # if 'source' in _config['system'] and _config['system']['source']['id'] == 'cloud' :
else: # _sourceHandler = cloud
_sourceHandler = disk # else:
_object = _sourceHandler.build(_config) # _sourceHandler = disk
# _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'])
_overwrite = _layout['overwrite'] if 'overwrite' in _layout else {} # _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 # #
# # # @TODO: Find a way to translate rename/replace keys of the _object (menu) here
#-- applying overwrites to the menu items # #
for _name in _object : # #-- applying overwrites to the menu items
_submenu = _object[_name] # for _name in _object :
_index = 0 # _submenu = _object[_name]
for _item in _submenu : # _index = 0
text = _item['text'].strip() # for _item in _submenu :
if text in _overwrite : # text = _item['text'].strip()
if 'uri' in _item and 'url' in 'url' in _overwrite[text] : # if text in _overwrite :
del _item['uri'] # if 'uri' in _item and 'url' in 'url' in _overwrite[text] :
_item = dict(_item,**_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'],'') # if 'uri' in _item and 'type' in _item and _item['type'] != 'open':
# _item['uri'] = _item['uri'].replace(_layout['root'],'')
_submenu[_index] = _item
_index += 1 # _submenu[_index] = _item
self.init_apps(_object) # _index += 1
self._menu = _object # self.init_apps(_object)
self._order() # self._menu = _object
# 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'] # """
_context = _system['context'] # _system = self._config['system']
if 'routes' in _system : # _context = _system['context']
# _items = [] # if 'routes' in _system :
_overwrite = {} if 'overwrite' not in self._config['layout'] else self._config['layout']['overwrite'] # # _items = []
for _text in _system['routes'] : # _overwrite = {} if 'overwrite' not in self._config['layout'] else self._config['layout']['overwrite']
_item = _system['routes'][_text] # for _text in _system['routes'] :
if 'menu' not in _item : # _item = _system['routes'][_text]
continue # if 'menu' not in _item :
uri = f'{_context}/{_text}' # continue
# _items.append ({"text":_text,'uri':uri,'type':'open'}) # uri = f'{_context}/{_text}'
_label = _item['menu'] # # _items.append ({"text":_text,'uri':uri,'type':'open'})
if _label not in _menu : # _label = _item['menu']
_menu [_label] = [] # if _label not in _menu :
_menu[_label].append ({"text":_text,'uri':uri,'type':'open'}) # _menu [_label] = []
# _overwrite[_text] = {'text': _text.replace('-',' ').replace('_',' '),'uri':uri,'type':'open'} # _menu[_label].append ({"text":_text,'uri':uri,'type':'open'})
# _menu['products'] = _items # # _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 # # given that the menu items assumes redirecting to a page ...
# # # This is not the case
# self._config['overwrite'] = _overwrite # #
else: # # self._config['overwrite'] = _overwrite
pass # else:
# pass
pass
def _order (self): # pass
_config = self._config # def _order (self):
if 'order' in _config['layout'] and 'menu' in _config['layout']['order']: # _config = self._config
_sortedmenu = {} # if 'order' in _config['layout'] and 'menu' in _config['layout']['order']:
_menu = self._menu # _sortedmenu = {}
for _name in _config['layout']['order']['menu'] : # _menu = self._menu
if _name in _menu : # for _name in _config['layout']['order']['menu'] :
_sortedmenu[_name] = _menu[_name] # if _name in _menu :
# _sortedmenu[_name] = _menu[_name]
_menu = _sortedmenu if _sortedmenu else _menu
# # _menu = _sortedmenu if _sortedmenu else _menu
# If there are missing items in the sorting # #
_missing = list(set(self._menu.keys()) - set(_sortedmenu)) # # If there are missing items in the sorting
if _missing : # _missing = list(set(self._menu.keys()) - set(_sortedmenu))
for _name in _missing : # if _missing :
_menu[_name] = self._menu[_name] # for _name in _missing :
_config['layout']['menu'] = _menu #cms.components.menu(_config) # _menu[_name] = self._menu[_name]
self._menu = _menu # _config['layout']['menu'] = _menu #cms.components.menu(_config)
self._config = _config # self._menu = _menu
def init_plugins(self) : # 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 # """
""" # 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']) # _config = self._config
if not os.path.exists(PATH) : # 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] ) # # we need to determin if there's an existing
if not os.path.exists(PATH) and self._location and os.path.exists(self._location) : # 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']) # # overriding the location of plugins ...
# PATH = os.sep.join([self._location, _config['layout']['root'],'_plugins'])
_map = {}
# if not os.path.exists(PATH) : # _map = {}
# return _map # # if not os.path.exists(PATH) :
if 'plugins' not in _config : # # return _map
_config['plugins'] = {} # if 'plugins' not in _config :
_conf = _config['plugins'] # _config['plugins'] = {}
# _conf = _config['plugins']
for _key in _conf :
# for _key in _conf :
_path = os.sep.join([PATH,_key+".py"])
if not os.path.exists(_path): # _path = os.sep.join([PATH,_key+".py"])
continue # if not os.path.exists(_path):
for _name in _conf[_key] : # continue
_pointer = self._load_plugin(path=_path,name=_name) # for _name in _conf[_key] :
if _pointer : # _pointer = self._load_plugin(path=_path,name=_name)
_uri = "/".join(["api",_key,_name]) # if _pointer :
_map[_uri] = _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... # # 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() # if 'source' in _config['system'] and _config['system']['source']['id'] == 'cloud' :
else: # _plugins = cloud.plugins()
_plugins = disk.plugins() # else:
# # _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 :
_map = dict(_map,**_plugins) # if _plugins :
else: # _map = dict(_map,**_plugins)
pass # else:
self._plugins = _map # pass
self._config['plugins'] = self._plugins # self._plugins = _map
# 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 # """
:path absolute path of the file (considered plugin) to be loaded # This function will load external module form a given location and return a pointer to a function in a given module
:name name of the function to be applied # :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): # _path = _args['path'] #os.sep.join([_args['root'],'plugin'])
files = os.listdir(_path) # if os.path.isdir(_path):
if files : # files = os.listdir(_path)
files = [name for name in files if name.endswith('.py')] # if files :
if files: # files = [name for name in files if name.endswith('.py')]
_path = os.sep.join([_path,files[0]]) # if files:
else: # _path = os.sep.join([_path,files[0]])
return None # else:
else: # return None
return None # else:
#-- We have a file ... # return None
_name = _args['name'] # #-- We have a file ...
# _name = _args['name']
spec = importlib.util.spec_from_file_location(_name, _path)
module = importlib.util.module_from_spec(spec) # spec = importlib.util.spec_from_file_location(_name, _path)
spec.loader.exec_module(module) # module = importlib.util.module_from_spec(spec)
# 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):
def __init__(self,**_args): # class Getter (Loader):
super().__init__(**_args) # def __init__(self,**_args):
def load(self): # super().__init__(**_args)
super().load() # def load(self):
_system = self.system() # super().load()
_logo = _system['logo'] # _system = self.system()
if 'source' in _system and 'id' in _system['source'] and (_system['source']['id'] == 'cloud'): # _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 # _icon = f'/api/cloud/download?doc=/{_logo}'
# _system['icon'] = _icon
else:
_root = self._config['layout']['root'] # else:
_icon = os.sep.join([_root,_logo]) # _root = self._config['layout']['root']
_system['icon'] = _logo # _icon = os.sep.join([_root,_logo])
# _system['icon'] = _logo
self._config['system'] = _system
if self._caller : # self._config['system'] = _system
_system['caller'] = {'icon': self._caller.system()['icon']} # if self._caller :
def html(self,uri,id,_args={},_system={}) : # _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 # """
# 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': # _system = self._config['system']
_html = cloud.html(uri,dict(_args,**{'system':_system})) # if 'source' in _system and _system['source']['id'] == 'cloud':
# _html = cloud.html(uri,dict(_args,**{'system':_system}))
else:
# else:
_html = disk.html(uri,self.layout())
# _html = (open(uri)).read() # _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>']) # #return ' '.join(['<div id=":id" class=":id">'.replace(':id',id),_html,'</div>'])
appContext = Environment(loader=BaseLoader()).from_string(_html) # _html = ' '.join(['<div id=":id" class=":id">'.replace(':id',id),_html,'</div>'])
_args['system'] = _system # 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) # #
# # # If the rendering of the HTML happens here we should plugin custom functions (at the very least)
# #
return appContext.render(**_args)
# return _html # return appContext.render(**_args)
# # return _html
def data (self,_args):
""" # 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 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) # _store = _args['store']
_queries= copy.deepcopy(_store['query']) # reader = transport.factory.instance(**_store)
_data = reader.read(**_queries) # _queries= copy.deepcopy(_store['query'])
return _data # _data = reader.read(**_queries)
def csv(self,uri) : # return _data
return pd.read(uri).to_html() # def csv(self,uri) :
# return pd.read(uri).to_html()
return _map
def menu(self): # return _map
return self._config['menu'] # def menu(self):
def plugins(self): # return self._config['menu']
return copy.deepcopy(self._plugins) if 'plugins' in self._config else {} # def plugins(self):
def context(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 # """
""" # adding custom variables functions to Jinja2, this function should be called after plugins are loaded
_plugins = self.plugins() # """
# if not location: # _plugins = self.plugins()
# env = Environment(loader=BaseLoader()) # # if not location:
# else: # # env = Environment(loader=BaseLoader())
location = self._config['layout']['root'] # # else:
# env = Environment(loader=FileSystemLoader(location)) # location = self._config['layout']['root']
env = Environment(loader=BaseLoader()) # # env = Environment(loader=FileSystemLoader(location))
# env.globals['routes'] = _config['plugins'] # env = Environment(loader=BaseLoader())
return env # # env.globals['routes'] = _config['plugins']
def config(self): # return env
return copy.deepcopy(self._config) # def config(self):
def system(self,skip=[]): # return copy.deepcopy(self._config)
""" # def system(self,skip=[]):
:skip keys to ignore in the object ... # """
""" # :skip keys to ignore in the object ...
_data = copy.deepcopy(self._config['system']) # """
_system = {} # _data = copy.deepcopy(self._config['system'])
if skip and _system: # _system = {}
for key in _data.keys() : # if skip and _system:
if key not in skip : # for key in _data.keys() :
_system[key] = _data[key] # if key not in skip :
else: # _system[key] = _data[key]
_system= _data # else:
return _system # _system= _data
def layout(self): # return _system
return self._config['layout'] # def layout(self):
def get_app(self): # return self._config['layout']
return self._config['system']['app'] # def get_app(self):
# return self._config['system']['app']
class Router :
def __init__(self,**_args) : # class Router :
# def __init__(self,**_args) :
# _app = Getter (path = path)
_app = Getter (**_args) # # _app = Getter (path = path)
# _app = Getter (**_args)
self._id = 'main'
# _app.load() # self._id = 'main'
self._apps = {} # # _app.load()
_system = _app.system() # self._apps = {}
if 'routes' in _system : # _system = _app.system()
_system = _system['routes'] # if 'routes' in _system :
for _name in _system : # _system = _system['routes']
_path = _system[_name]['path'] # for _name in _system :
self._apps[_name] = Getter(path=_path,caller=_app,location=_path) # _path = _system[_name]['path']
self._apps['main'] = _app # self._apps[_name] = Getter(path=_path,caller=_app,location=_path)
# self._apps['main'] = _app
def set(self,_id):
self._id = _id # def set(self,_id):
def get(self): # 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'] if self._id not in self._apps else self._apps[self._id]
return self._apps['main'] # def get_main(self):
# 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():
""" """
@ -75,26 +74,55 @@ 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')
@_app.route("/") def _getIndex (app_id ,resource=None):
def _index (): _handler = _getHandler(app_id,resource)
_handler = _getHandler() _layout = _handler.layout()
_config = _handler.config() _status_code = 200
global _route global _route
_index_page = 'index.html'
_args = {}
print ([' serving ',session.get('app_id','NA'),_handler.layout()['root']]) try :
_args={'system':_handler.system(skip=['source','app','data']),'layout':_handler.layout()} _uri = os.sep.join([_layout['root'],_layout['index']])
try: _id = _getId(app_id,resource)
uri = os.sep.join([_config['layout']['root'], _config['layout']['index']]) _args = _route.render(_uri,'index',_id)
_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 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>') # @_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}}')
@ -70,7 +70,7 @@ Vanderbilt University Medical Center
<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