From 4e2430fc2185d24b17482cd01cebf7e5f3c751d1 Mon Sep 17 00:00:00 2001 From: Steve Nyemba Date: Mon, 26 Aug 2024 10:12:37 -0500 Subject: [PATCH] routes withe depths --- cms/disk.py | 4 +- cms/engine/__init__.py | 679 +++++++++++++++++++------------------- cms/engine/basic.py | 40 ++- cms/index.py | 216 +++++++----- cms/static/js/bootup.js | 29 +- cms/templates/header.html | 1 - cms/templates/index.html | 32 +- cms/templates/menu.html | 2 +- 8 files changed, 531 insertions(+), 472 deletions(-) diff --git a/cms/disk.py b/cms/disk.py index 3d31f76..da2be29 100644 --- a/cms/disk.py +++ b/cms/disk.py @@ -113,7 +113,9 @@ def exists(**_args): def html(_uri,_config) : # _html = (open(uri)).read() _path = _realpath(_uri,_config) - _context = _config['system']['context'] + _context = str(_config['system']['context']) + # if '/' in _context : + # _context = _context.split('/')[-1] _html = ( open(_path)).read() _layout = _config['layout'] if 'location' in _layout : diff --git a/cms/engine/__init__.py b/cms/engine/__init__.py index f6200cc..9d03eac 100644 --- a/cms/engine/__init__.py +++ b/cms/engine/__init__.py @@ -1,384 +1,385 @@ -import json +# import json -from genericpath import isdir -import os -import pandas as pd -import transport -import copy -from jinja2 import Environment, BaseLoader, FileSystemLoader -import importlib -import importlib.util +# from genericpath import isdir +# import os +# import pandas as pd +# import transport +# import copy +# from jinja2 import Environment, BaseLoader, FileSystemLoader +# import importlib +# import importlib.util from cms import disk, cloud from . import basic -class Loader : - """ - This class is designed to exclusively load configuration from disk into an object - :path path to the configuraiton file - :location original location (caller) - """ - def __init__(self,**_args): - self._path = _args['path'] - self._original_location = None if 'location' not in _args else _args['location'] - self._location = None - self._caller = None if 'caller' not in _args else _args['caller'] - self._menu = {} - self._plugins={} - self.load() +# class Loader : +# """ +# This class is designed to exclusively load configuration from disk into an object +# :path path to the configuraiton file +# :location original location (caller) +# """ +# def __init__(self,**_args): +# self._path = _args['path'] +# self._original_location = None if 'location' not in _args else _args['location'] +# self._location = None +# self._caller = None if 'caller' not in _args else _args['caller'] +# print ([' *** ', self._caller]) +# self._menu = {} +# self._plugins={} +# self.load() - def load(self): - """ - This function will load menu (overwrite) and plugins - """ - self.init_config() - self.init_menu() - self.init_plugins() - def init_config(self): - """ - Initialize & loading configuration from disk - """ - f = open (self._path) - self._config = json.loads(f.read()) +# def load(self): +# """ +# This function will load menu (overwrite) and plugins +# """ +# self.init_config() +# self.init_menu() +# self.init_plugins() +# def init_config(self): +# """ +# Initialize & loading configuration from disk +# """ +# f = open (self._path) +# self._config = json.loads(f.read()) - if self._caller : - self._location = self._original_location.split(os.sep) # needed for plugin loading - self._location = os.sep.join(self._location[:-1]) - self._config['system']['portal'] = self._caller != None +# if self._caller : +# self._location = self._original_location.split(os.sep) # needed for plugin loading +# self._location = os.sep.join(self._location[:-1]) +# self._config['system']['portal'] = self._caller != None - # - # let's see if we have a location for a key (i.e security key) in the configuration - # - self.update_config() - # _system = self._config['system'] - # if 'source' in _system and 'key' in _system['source'] : - # _path = _system['source']['key'] - # if os.path.exists(_path): - # f = open(_path) - # _system['source']['key'] = f.read() - # f.close() - # self._system = _system - # self._config['system'] = _system - def update_config(self): - """ - We are going to update the configuration (source.key, layout.root) - """ - _system = self._config['system'] - # - # updating security-key that allows the application to update on-demand - if 'source' in _system and 'key' in _system['source'] : - _path = _system['source']['key'] - if os.path.exists(_path): - f = open(_path) - _system['source']['key'] = f.read() - f.close() - self._system = _system - self._config['system'] = _system - _layout = self._config['layout'] - # - # update root so that the app can be launched from anywhere - # This would help reduce the footprint of the app/framework - _path = os.sep.join(self._path.split(os.sep)[:-1]) - _p = 'source' not in _system - _q = 'source' in _system and _system['source']['id'] != 'cloud' - _r = os.path.exists(_layout['root']) - if not _r and (_p or _q) : - # - # If we did running this app from installed framework (this should not apply to dependent apps) - # - _root = os.sep.join([_path,_layout['root']]) - self._config['layout']['root'] = _root - self._config['layout']['root_prefix'] = _root +# # +# # let's see if we have a location for a key (i.e security key) in the configuration +# # +# self.update_config() +# # _system = self._config['system'] +# # if 'source' in _system and 'key' in _system['source'] : +# # _path = _system['source']['key'] +# # if os.path.exists(_path): +# # f = open(_path) +# # _system['source']['key'] = f.read() +# # f.close() +# # self._system = _system +# # self._config['system'] = _system +# def update_config(self): +# """ +# We are going to update the configuration (source.key, layout.root) +# """ +# _system = self._config['system'] +# # +# # updating security-key that allows the application to update on-demand +# if 'source' in _system and 'key' in _system['source'] : +# _path = _system['source']['key'] +# if os.path.exists(_path): +# f = open(_path) +# _system['source']['key'] = f.read() +# f.close() +# self._system = _system +# self._config['system'] = _system +# _layout = self._config['layout'] +# # +# # update root so that the app can be launched from anywhere +# # This would help reduce the footprint of the app/framework +# _path = os.sep.join(self._path.split(os.sep)[:-1]) +# _p = 'source' not in _system +# _q = 'source' in _system and _system['source']['id'] != 'cloud' +# _r = os.path.exists(_layout['root']) +# if not _r and (_p or _q) : +# # +# # If we did running this app from installed framework (this should not apply to dependent apps) +# # +# _root = os.sep.join([_path,_layout['root']]) +# self._config['layout']['root'] = _root +# self._config['layout']['root_prefix'] = _root - def init_menu(self): - """ - This function will read menu and sub-menu items from disk structure, - The files are loaded will - """ +# def init_menu(self): +# """ +# This function will read menu and sub-menu items from disk structure, +# The files are loaded will +# """ - _config = self._config - if 'source' in _config['system'] and _config['system']['source']['id'] == 'cloud' : - _sourceHandler = cloud - else: - _sourceHandler = disk - _object = _sourceHandler.build(_config) +# _config = self._config +# if 'source' in _config['system'] and _config['system']['source']['id'] == 'cloud' : +# _sourceHandler = cloud +# else: +# _sourceHandler = disk +# _object = _sourceHandler.build(_config) - # - # After building the site's menu, let us add the one from 3rd party apps - # +# # +# # 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 - # - #-- applying overwrites to the menu items - for _name in _object : - _submenu = _object[_name] - _index = 0 - for _item in _submenu : - text = _item['text'].strip() - if text in _overwrite : - if 'uri' in _item and 'url' in 'url' in _overwrite[text] : - del _item['uri'] - _item = dict(_item,**_overwrite[text]) +# # +# # @TODO: Find a way to translate rename/replace keys of the _object (menu) here +# # +# #-- applying overwrites to the menu items +# for _name in _object : +# _submenu = _object[_name] +# _index = 0 +# for _item in _submenu : +# text = _item['text'].strip() +# if text in _overwrite : +# if 'uri' in _item and 'url' in 'url' in _overwrite[text] : +# del _item['uri'] +# _item = dict(_item,**_overwrite[text]) - if 'uri' in _item and 'type' in _item and _item['type'] != 'open': - _item['uri'] = _item['uri'].replace(_layout['root'],'') +# if 'uri' in _item and 'type' in _item and _item['type'] != 'open': +# _item['uri'] = _item['uri'].replace(_layout['root'],'') - _submenu[_index] = _item - _index += 1 - self.init_apps(_object) - self._menu = _object - self._order() +# _submenu[_index] = _item +# _index += 1 +# self.init_apps(_object) +# self._menu = _object +# self._order() - def init_apps (self,_menu): - """ - Insuring that the apps are loaded into the menu with an approriate label - """ - _system = self._config['system'] - _context = _system['context'] - if 'routes' in _system : - # _items = [] - _overwrite = {} if 'overwrite' not in self._config['layout'] else self._config['layout']['overwrite'] - for _text in _system['routes'] : - _item = _system['routes'][_text] - if 'menu' not in _item : - continue - uri = f'{_context}/{_text}' - # _items.append ({"text":_text,'uri':uri,'type':'open'}) - _label = _item['menu'] - if _label not in _menu : - _menu [_label] = [] - _menu[_label].append ({"text":_text,'uri':uri,'type':'open'}) - # _overwrite[_text] = {'text': _text.replace('-',' ').replace('_',' '),'uri':uri,'type':'open'} - # _menu['products'] = _items - # - # given that the menu items assumes redirecting to a page ... - # This is not the case - # - # self._config['overwrite'] = _overwrite - else: - pass +# def init_apps (self,_menu): +# """ +# Insuring that the apps are loaded into the menu with an approriate label +# """ +# _system = self._config['system'] +# _context = _system['context'] +# if 'routes' in _system : +# # _items = [] +# _overwrite = {} if 'overwrite' not in self._config['layout'] else self._config['layout']['overwrite'] +# for _text in _system['routes'] : +# _item = _system['routes'][_text] +# if 'menu' not in _item : +# continue +# uri = f'{_context}/{_text}' +# # _items.append ({"text":_text,'uri':uri,'type':'open'}) +# _label = _item['menu'] +# if _label not in _menu : +# _menu [_label] = [] +# _menu[_label].append ({"text":_text,'uri':uri,'type':'open'}) +# # _overwrite[_text] = {'text': _text.replace('-',' ').replace('_',' '),'uri':uri,'type':'open'} +# # _menu['products'] = _items +# # +# # given that the menu items assumes redirecting to a page ... +# # This is not the case +# # +# # self._config['overwrite'] = _overwrite +# else: +# pass - pass - def _order (self): - _config = self._config - if 'order' in _config['layout'] and 'menu' in _config['layout']['order']: - _sortedmenu = {} - _menu = self._menu - for _name in _config['layout']['order']['menu'] : - if _name in _menu : - _sortedmenu[_name] = _menu[_name] +# pass +# def _order (self): +# _config = self._config +# if 'order' in _config['layout'] and 'menu' in _config['layout']['order']: +# _sortedmenu = {} +# _menu = self._menu +# for _name in _config['layout']['order']['menu'] : +# if _name in _menu : +# _sortedmenu[_name] = _menu[_name] - _menu = _sortedmenu if _sortedmenu else _menu - # - # If there are missing items in the sorting - _missing = list(set(self._menu.keys()) - set(_sortedmenu)) - if _missing : - for _name in _missing : - _menu[_name] = self._menu[_name] - _config['layout']['menu'] = _menu #cms.components.menu(_config) - self._menu = _menu - self._config = _config - def init_plugins(self) : - """ - This function looks for plugins in the folder on disk (no cloud support) and attempts to load them - """ - _config = self._config - PATH= os.sep.join([_config['layout']['root'],'_plugins']) - if not os.path.exists(PATH) : - # - # we need to determin if there's an existing - PATH = os.sep.join(self._path.split(os.sep)[:-1]+ [PATH] ) - if not os.path.exists(PATH) and self._location and os.path.exists(self._location) : - # - # overriding the location of plugins ... - PATH = os.sep.join([self._location, _config['layout']['root'],'_plugins']) +# _menu = _sortedmenu if _sortedmenu else _menu +# # +# # If there are missing items in the sorting +# _missing = list(set(self._menu.keys()) - set(_sortedmenu)) +# if _missing : +# for _name in _missing : +# _menu[_name] = self._menu[_name] +# _config['layout']['menu'] = _menu #cms.components.menu(_config) +# self._menu = _menu +# self._config = _config +# def init_plugins(self) : +# """ +# This function looks for plugins in the folder on disk (no cloud support) and attempts to load them +# """ +# _config = self._config +# PATH= os.sep.join([_config['layout']['root'],'_plugins']) +# if not os.path.exists(PATH) : +# # +# # we need to determin if there's an existing +# PATH = os.sep.join(self._path.split(os.sep)[:-1]+ [PATH] ) +# if not os.path.exists(PATH) and self._location and os.path.exists(self._location) : +# # +# # overriding the location of plugins ... +# PATH = os.sep.join([self._location, _config['layout']['root'],'_plugins']) - _map = {} - # if not os.path.exists(PATH) : - # return _map - if 'plugins' not in _config : - _config['plugins'] = {} - _conf = _config['plugins'] +# _map = {} +# # if not os.path.exists(PATH) : +# # return _map +# if 'plugins' not in _config : +# _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): - 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 +# _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 +# 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'] +# 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) +# 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 +# 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'): +# 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 +# _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 +# 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 +# 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})) +# """ +# _system = self._config['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(['
'.replace(':id',id),_html,'
']) - _html = ' '.join(['
'.replace(':id',id),_html,'
']) - 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 ' '.join(['
'.replace(':id',id),_html,'
']) +# _html = ' '.join(['
'.replace(':id',id),_html,'
']) +# 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 +# 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() +# def data (self,_args): +# """ +# :store data-store parameters (data-transport, github.com/lnyemba/data-transport) +# :query query to be applied against the store (expected data-frame) +# """ +# _store = _args['store'] +# reader = transport.factory.instance(**_store) +# _queries= copy.deepcopy(_store['query']) +# _data = reader.read(**_queries) +# return _data +# def csv(self,uri) : +# return pd.read(uri).to_html() - return _map - def menu(self): - return self._config['menu'] - def plugins(self): - return copy.deepcopy(self._plugins) if 'plugins' in self._config else {} - def context(self): - """ - adding custom variables functions to Jinja2, this function should be called after plugins are loaded - """ - _plugins = self.plugins() - # if not location: - # env = Environment(loader=BaseLoader()) - # else: - location = self._config['layout']['root'] - # env = Environment(loader=FileSystemLoader(location)) - env = Environment(loader=BaseLoader()) - # env.globals['routes'] = _config['plugins'] - return env - def config(self): - return copy.deepcopy(self._config) - def system(self,skip=[]): - """ - :skip keys to ignore in the object ... - """ - _data = copy.deepcopy(self._config['system']) - _system = {} - if skip and _system: - for key in _data.keys() : - if key not in skip : - _system[key] = _data[key] - else: - _system= _data - return _system - def layout(self): - return self._config['layout'] - def get_app(self): - return self._config['system']['app'] +# return _map +# def menu(self): +# return self._config['menu'] +# def plugins(self): +# return copy.deepcopy(self._plugins) if 'plugins' in self._config else {} +# def context(self): +# """ +# adding custom variables functions to Jinja2, this function should be called after plugins are loaded +# """ +# _plugins = self.plugins() +# # if not location: +# # env = Environment(loader=BaseLoader()) +# # else: +# location = self._config['layout']['root'] +# # env = Environment(loader=FileSystemLoader(location)) +# env = Environment(loader=BaseLoader()) +# # env.globals['routes'] = _config['plugins'] +# return env +# def config(self): +# return copy.deepcopy(self._config) +# def system(self,skip=[]): +# """ +# :skip keys to ignore in the object ... +# """ +# _data = copy.deepcopy(self._config['system']) +# _system = {} +# if skip and _system: +# for key in _data.keys() : +# if key not in skip : +# _system[key] = _data[key] +# else: +# _system= _data +# return _system +# def layout(self): +# return self._config['layout'] +# def get_app(self): +# return self._config['system']['app'] -class Router : - def __init__(self,**_args) : +# 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._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 +# 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): +# 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'] +# return self._apps['main'] if self._id not in self._apps else self._apps[self._id] +# def get_main(self): +# return self._apps['main'] diff --git a/cms/engine/basic.py b/cms/engine/basic.py index 3ec6fe9..8dd5b2f 100644 --- a/cms/engine/basic.py +++ b/cms/engine/basic.py @@ -20,7 +20,7 @@ class Initializer : """ def __init__(self,**_args): self._config = {'system':{},'layout':{},'plugins':{}} - self._shared = False if not 'shared' in _args else _args['shared'] + # self._shared = False if not 'shared' in _args else _args['shared'] self._location= _args['location'] if 'location' in _args else None self._menu = {} # _source = self._config ['system']['source'] if 'source' in self._config['system'] else {} @@ -29,8 +29,13 @@ class Initializer : self._ISCLOUD = False self._caller = None if 'caller' not in _args else _args['caller'] self._args = _args - + # if 'context' in _args : + # self._config self.reload() #-- this is an initial load of various components + # + # @TODO: + # Each module should submit it's routers to the parent, and adjust the references given the callers + # def reload(self): @@ -39,7 +44,7 @@ class Initializer : self._isource() self._imenu() self._iplugins() - + self._iroutes () # self._ISCLOUD = 'source' in self._config['system'] and self._config['system']['source']['id'] == 'cloud' @@ -52,7 +57,15 @@ class Initializer : return cloud else: return disk - + def _iroutes (self): + """ + Initializing routes to be submitted to the CMS Handler + The routes must be able to : + 1. submit an object (dependency to the cms) + 2. submit with the object a route associated + The CMS handler will resolve dependencies/redundancies + """ + pass def _imenu(self,**_args) : pass def _iplugins(self,**_args) : @@ -252,8 +265,9 @@ class Initializer : _callerContext = self._caller.system()['context'] if not self._config['system']['context'] : self._config['system']['context'] = _callerContext - self._config['system']['caller'] = {'icon': 'caller/main/'+self._caller.system()['icon'].replace(_callerContext,'')} - _context = _callerContext + self._config['system']['caller'] = {'icon': '/main'+self._caller.system()['icon'].replace(_callerContext,'')} + _context = '/'.join([_callerContext,_context]) if _callerContext != '' else _context + if os.path.exists(_newpath) and not self._ISCLOUD: @@ -278,14 +292,15 @@ class Initializer : else: _icon = f'{_context}/api/disk/read?uri={_logo}' + if disk.exists(uri=_logo,config=self._config): _icon = _logo if self._location : self._config['layout']['location'] = _path - self._config['system']['icon'] = _icon self._config['system']['logo'] = _logo + # self.set('layout.root',os.sep.join([_path,_oroot])) pass class Module (Initializer): @@ -312,6 +327,15 @@ class Module (Initializer): elif type(_stream) == io.StringIO : self._config = json.loads( _stream.read()) self._ISCLOUD = 'source' in self._config['system'] and self._config['system']['source'] and self._config['system']['source']['id'] == 'cloud' + if self._caller : + self._config['system']['parentContext'] = self._caller.system()['context'] + else: + self._config['system']['parentContext'] = self._config['system']['context'] + if 'context' in _args : + self._config['system']['context'] = _args['context'] + + if '/' in self._config['system']['context'] : + self._config['system']['context'] = self._config['system']['context'].split('/')[-1] # # # self._name = self._config['system']['name'] if 'name' in self._config['system'] else _args['name'] @@ -361,6 +385,7 @@ class Module (Initializer): class MicroService (Module): """ This is a CMS MicroService class that is capable of initializing a site and exposing Module functions + """ def __init__(self,**_args): super().__init__(**_args) @@ -402,7 +427,6 @@ class CMS: _system = _system['routes'] for _name in _system : _path = _system[_name]['path'] - self._apps[_name] = MicroService(context=_name,path=_path,caller=_app,location=_path) self._apps['main'] = _app diff --git a/cms/index.py b/cms/index.py index 5fbe446..b6be9e3 100644 --- a/cms/index.py +++ b/cms/index.py @@ -22,35 +22,34 @@ from typing import Optional import pandas as pd import uuid import datetime - +import requests from cms import disk, cloud, engine _app = Flask(__name__) cli = typer.Typer() -# @_app.route('/favicon.ico') -# def favicon(): -# global _route -# _system = _route.get ().system() -# _handler = _route.get() - -# _logo =_system['icon'] if 'icon' in _system else 'static/img/logo.svg' -# return _handler.get(_logo) -# # # _root = _route.get().config()['layout']['root'] -# # # print ([_system]) -# # # if 'source' in _system and 'id' in _system['source'] and (_system['source']['id'] == 'cloud'): -# # # uri = f'/api/cloud/downloads?doc=/{_logo}' -# # # print (['****' , uri]) -# # # return redirect(uri,200) #,{'content-type':'application/image'} -# # # else: - -# # # return send_from_directory(_root, #_app.root_path, 'static/img'), -# # _logo, mimetype='image/vnd.microsoft.icon') -def _getHandler () : - _id = session.get('app_id','main') +@_app.route('//favicon.ico') +def favicon(id): + global _route + # _system = _route.get ().system() + # _handler = _route.get() + _handler = _getHandler(id) + _system = _handler.system() + _logo =_system['icon'] #if 'icon' in _system else 'static/img/logo.svg' + _stream = requests.get(''.join([request.host_url,_logo])) + + return "_stream",200,{"Content-Type":"image/png"} #_handler.get(_logo),200,{"content-type":"image/png"} + +def _getHandler (app_id,resource=None) : + global _route + _id = _getId(app_id,resource) + return _route._apps[_id] -def _setHandler (id) : - session['app_id'] = id +def _getId(app_id,resource): + return '/'.join([app_id,resource]) if resource else app_id +def _setHandler (app_id,resource) : + session['app_id'] = _getId(app_id,resource) + @_app.route("/robots.txt") def robots_txt(): """ @@ -74,27 +73,56 @@ def robots_txt(): ''') # return '\n'.join(_info),200,{'Content-Type':'plain/text'} - return Response('\n'.join(_info), mimetype='text/plain') + return Response('\n'.join(_info), mimetype='text/plain') +def _getIndex (app_id ,resource=None): + _handler = _getHandler(app_id,resource) + _layout = _handler.layout() + _status_code = 200 + global _route + _index_page = 'index.html' + _args = {} + + try : + _uri = os.sep.join([_layout['root'],_layout['index']]) + _id = _getId(app_id,resource) + _args = _route.render(_uri,'index',_id) + + except Exception as e: + _status_code = 404 + _index_page = '404.html' + print(e) + return render_template(_index_page,**_args),_status_code @_app.route("/") def _index (): - _handler = _getHandler() - _config = _handler.config() - global _route + 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" - print ([_route]) - _args = _route.render(uri,'index',session.get('app_id','main')) - except Exception as e: - # print () - print (e) - _index_page = "404.html" +# # print ([' serving ',session.get('app_id','NA'),_handler.layout()['root']]) +# _args={'system':_handler.system(skip=['source','app','data']),'layout':_handler.layout()} - return render_template(_index_page,**_args),200 if _index_page != "404.html" else 200 - +# try: +# uri = os.sep.join([_config['layout']['root'], _config['layout']['index']]) +# _index_page = "index.html" + +# _args = _route.render(uri,'index',session.get('app_id','main')) +# # _setHandler('main') +# except Exception as e: +# # print () +# print (e) +# _index_page = "404.html" + +# return render_template(_index_page,**_args),200 if _index_page != "404.html" else 200 +@_app.route("//") +@_app.route("/",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/') # def people(uid): # """ @@ -115,23 +143,28 @@ def _dialog (): _args = _route.render(_uri,'html',session.get('app_id','main')) _args['title'] = _id return render_template('dialog.html',**_args) #title=_id,html=_html) -@_app.route("/caller//api//") -def _delegate_call(app,module,name): - global _route - _handler = _route._apps[app] + +@_app.route("/api//",defaults={'app':'main','key':None}) +@_app.route("//api//",defaults={'key':None}) +@_app.route("////",defaults={'key':None}) + +def _delegate_call(app,key,module,name): + _handler = _getHandler(app,key) return _delegate(_handler,module,name) -@_app.route('/api//') -def _api(module,name) : +# @_app.route('/api//') +@_app.route("///api//", methods=['GET']) +@_app.route("/api//",defaults={'app_id':'main','key':None}) +@_app.route("//api//",defaults={'key':None}) + +def _api(app_id,key,module,name) : """ This endpoint will load a module and make a function call :_module entry specified in plugins of the configuration :_name name of the function to execute """ - # global _config - # global _route - # _handler = _route.get() - _handler = _getHandler() + + _handler = _getHandler( app_id,key) return _delegate(_handler,module,name) def _delegate(_handler,module,name): @@ -143,7 +176,7 @@ def _delegate(_handler,module,name): _context = _handler.system()['context'] if _context : uri = f'{_context}/{uri}' - + _mimeType = 'application/octet-stream' if uri not in _plugins : _data = {} _code = 404 @@ -163,12 +196,21 @@ def _delegate(_handler,module,name): _data = json.dumps(_data) _code = 200 if _data else 500 return _data,_code,{'Content-Type':_mimeType} -@_app.route("/api//" , methods=['POST']) -def _post (module,name): + +# @_app.route("/api//" , methods=['POST'],defaults={'app_id':'main','key':None}) +# @_app.route('//api//',methods=['POST'],defaults={'key':None}) +# @_app.route('///api//',methods=['POST'],defaults={'app_id':'main','key':None}) + +@_app.route("///api//", methods=['POST']) +@_app.route("/api//",defaults={'app_id':'main','key':None},methods=['POST']) +@_app.route("//api//",defaults={'key':None},methods=['POST']) + +def _post (app_id,key,module,name): # global _config # global _route # _handler = _route.get() - _handler = _getHandler() + # app_id = '/'.join([app_id,key]) if key else app_id + _handler = _getHandler(app_id,key) return _delegate(_handler,module,name) @_app.route('/version') @@ -212,8 +254,11 @@ def reload(): # return "",200 # pass # return "",403 -@_app.route('/page',methods=['POST']) -def cms_page(): + +@_app.route('/page',methods=['POST'],defaults={'app_id':'main','key':None}) +@_app.route('//page',methods=['POST'],defaults={'key':None}) +@_app.route('///page',methods=['POST']) +def _POST_CMSPage(app_id,key): """ return the content of a folder formatted for a menu """ @@ -221,7 +266,9 @@ def cms_page(): global _route # _handler = _route.get() # _config = _handler.config() - _handler = _getHandler() + _handler = _getHandler(app_id,key) + _setHandler(app_id,key) + _config = _handler.config() # _uri = os.sep.join([_config['layout']['root'],request.headers['uri']]) _uri = request.headers['uri'] @@ -244,11 +291,13 @@ def cms_page(): if 'read?uri=' in _uri or 'download?doc=' in _uri : _uri = _uri.split('=')[1] - _args = _route.render(_uri,_id,session.get('app_id','main')) + _args = _route.render(_uri,_id,_getId(app_id,key)) #session.get(app_id,'main')) return _args[_id],200 # return _html,200 -@_app.route('/page') -def _cms_page (): +@_app.route('/page',defaults={'app_id':'main','resource':None}) +@_app.route('//page',defaults={'resource':None},methods=['GET']) +@_app.route('///page',methods=['GET']) +def _cms_page (app_id,resource): # global _config global _route # _handler = _route.get() @@ -257,33 +306,33 @@ def _cms_page (): # _uri = os.sep.join([_config['layout']['root'],_uri]) _title = request.args['title'] if 'title' in request.args else '' - _args = _route.render(_uri,_title,session.get('app_id','main')) + _args = _route.render(_uri,_title,session.get(app_id,'main')) return _args[_title],200 -@_app.route('/set/') -def set(id): - global _route - _setHandler(id) - # _route.set(id) - # _handler = _route.get() - _handler = _getHandler() - _context = _handler.system()['context'] - _uri = f'/{_context}'.replace('//','/') - return redirect(_uri) -@_app.route('/') -def _open(id): - global _route - # _handler = _route.get() +# @_app.route('/set/') +# def set(id): +# global _route +# _setHandler(id) +# # _route.set(id) +# # _handler = _route.get() +# _handler = _getHandler() +# _context = _handler.system()['context'] +# _uri = f'/{_context}'.replace('//','/') +# return redirect(_uri) +# @_app.route('/') +# def _open(id): +# global _route +# # _handler = _route.get() - _handler = _getHandler() - if id not in _route._apps : +# _handler = _getHandler() +# if id not in _route._apps : - _args = {'config':_handler.config(), 'layout':_handler.layout(),'system':_handler.system(skip=['source','app'])} - return render_template("404.html",**_args) - else: - _setHandler(id) - # _route.set(id) - return _index() +# _args = {'config':_handler.config(), 'layout':_handler.layout(),'system':_handler.system(skip=['source','app'])} +# return render_template("404.html",**_args) +# else: +# _setHandler(id) +# # _route.set(id) +# return _index() @cli.command() @@ -310,6 +359,7 @@ def start ( # _route = cms.engine.Router(**_args) #path=path,shared=shared) _route = cms.engine.basic.CMS(**_args) + # dir(_route) # _args = _route.get().get_app() _args = _route.get().app() diff --git a/cms/static/js/bootup.js b/cms/static/js/bootup.js index d9b3101..015380c 100644 --- a/cms/static/js/bootup.js +++ b/cms/static/js/bootup.js @@ -12,43 +12,26 @@ bootup.CMSObserver = function(_sysId,_domId,_fileURI){ var http = HttpClient.instance() http.setHeader('uri',_fileURI) - if (sessionStorage[_sysId] != null){ + if (sessionStorage[_sysId] != null ){ var uri = sessionStorage[_sysId]+'/page' }else{ var uri = '/page' } + + if (window.location.pathname != '/'){ + uri = ([window.location.pathname,'page']).join('/') + } + try{ // var _domElement = jx.dom.get.instance('div') // _domElement.className = 'busy-loading' // jx.dom.append(_domId, _domElement) http.post(uri,function(x){ - // console.log(jx.dom.exists(_domId)) - // var _domElement = jx.dom.get.instance('div') - // _domElement.className = 'busy-and-loading' - // jx.dom.append(_domId, _domElement) if (x.status == 200){ - // jx.dom.set.value(_domId,x.responseText) - // var _domElement = jx.dom.get.instance('div') - // _domElement.innerHTML = x.responseText - setTimeout(function(){ - // _domElement.innerHTML = x.responseText - // _domElement.className = null - // $(_domElement).html(x.responseText) - - $('#'+_domId).append(x.responseText) - - - // $(_domElement).attr('class',_domId) - - - // - // If there is a script associated it must be extracted and executed - // menu.runScript(_domId) - // console.log([_domId, ' **** ',$(_domId + ' script')]) },1500) diff --git a/cms/templates/header.html b/cms/templates/header.html index 26428a6..ee0bde5 100644 --- a/cms/templates/header.html +++ b/cms/templates/header.html @@ -1,5 +1,4 @@ -
diff --git a/cms/templates/index.html b/cms/templates/index.html index dc9a2eb..825a231 100644 --- a/cms/templates/index.html +++ b/cms/templates/index.html @@ -31,10 +31,10 @@ Vanderbilt University Medical Center - - - - + + + + @@ -44,16 +44,16 @@ Vanderbilt University Medical Center - - - - - - - - - - + + + + + + + + + + - +
-