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

@ -20,7 +20,7 @@ class Initializer :
""" """
def __init__(self,**_args): 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)
_system = _handler.system()
_logo =_system['icon'] #if 'icon' in _system else 'static/img/logo.svg'
_stream = requests.get(''.join([request.host_url,_logo]))
return "_stream",200,{"Content-Type":"image/png"} #_handler.get(_logo),200,{"content-type":"image/png"}
def _getHandler (app_id,resource=None) :
global _route
_id = _getId(app_id,resource)
# _logo =_system['icon'] if 'icon' in _system else 'static/img/logo.svg'
# return _handler.get(_logo)
# # # _root = _route.get().config()['layout']['root']
# # # print ([_system])
# # # if 'source' in _system and 'id' in _system['source'] and (_system['source']['id'] == 'cloud'):
# # # uri = f'/api/cloud/downloads?doc=/{_logo}'
# # # print (['****' , uri])
# # # return redirect(uri,200) #,{'content-type':'application/image'}
# # # else:
# # # return send_from_directory(_root, #_app.root_path, 'static/img'),
# # _logo, mimetype='image/vnd.microsoft.icon')
def _getHandler () :
_id = session.get('app_id','main')
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']])
_args={'system':_handler.system(skip=['source','app','data']),'layout':_handler.layout()}
try : try :
uri = os.sep.join([_config['layout']['root'], _config['layout']['index']]) _uri = os.sep.join([_layout['root'],_layout['index']])
_index_page = "index.html" _id = _getId(app_id,resource)
print ([_route]) _args = _route.render(_uri,'index',_id)
_args = _route.render(uri,'index',session.get('app_id','main'))
except Exception as e: except Exception as e:
# print () _status_code = 404
_index_page = '404.html'
print(e) print(e)
_index_page = "404.html" return render_template(_index_page,**_args),_status_code
@_app.route("/")
return render_template(_index_page,**_args),200 if _index_page != "404.html" else 200 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()

@ -17,38 +17,21 @@ bootup.CMSObserver = function(_sysId,_domId,_fileURI){
}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