@ -0,0 +1,2 @@
 | 
				
			||||
recursive-include cms/templates *
 | 
				
			||||
recursive-include cms/static *
 | 
				
			||||
@ -0,0 +1,354 @@
 | 
				
			||||
#!/usr/bin/env python
 | 
				
			||||
import numpy as np
 | 
				
			||||
import os
 | 
				
			||||
import sys
 | 
				
			||||
import json
 | 
				
			||||
import importlib
 | 
				
			||||
import importlib.util
 | 
				
			||||
from git.repo.base import Repo
 | 
				
			||||
import typer
 | 
				
			||||
from typing_extensions import Annotated
 | 
				
			||||
from typing import Optional
 | 
				
			||||
import meta
 | 
				
			||||
import uuid
 | 
				
			||||
from termcolor import colored
 | 
				
			||||
import base64
 | 
				
			||||
import io
 | 
				
			||||
from cms import index
 | 
				
			||||
 | 
				
			||||
start = index.start
 | 
				
			||||
 | 
				
			||||
__doc__ = """
 | 
				
			||||
(c) 2022 Quick Content Management System - QCMS
 | 
				
			||||
Health Information Privacy Lab - Vanderbilt University Medical Center
 | 
				
			||||
MIT License
 | 
				
			||||
 | 
				
			||||
Is a Python/Flask template for creating websites using disk structure to build the site and loading custom code
 | 
				
			||||
The basic template for a flask application will be created in a specified location, within this location will be found a folder "content"
 | 
				
			||||
    - within the folder specify the folder structure that constitute the menu
 | 
				
			||||
Usage :
 | 
				
			||||
    qcms --create <path> --version <value> --title <title> --subtitle <subtitle>
 | 
				
			||||
"""
 | 
				
			||||
 | 
				
			||||
PASSED = ' '.join(['[',colored(u'\u2713', 'green'),']'])
 | 
				
			||||
FAILED= ' '.join(['[',colored(u'\u2717','red'),']'])
 | 
				
			||||
 | 
				
			||||
INVALID_FOLDER = """
 | 
				
			||||
{FAILED} Unable to proceed, could not find project manifest. It should be qcms-manifest.json
 | 
				
			||||
"""
 | 
				
			||||
#
 | 
				
			||||
# handling cli interface
 | 
				
			||||
cli = typer.Typer()
 | 
				
			||||
 | 
				
			||||
def _get_config (path) :
 | 
				
			||||
    if os.path.exists(path) :
 | 
				
			||||
        f = open(path) 
 | 
				
			||||
        _conf = json.loads(f.read())
 | 
				
			||||
        f.close()
 | 
				
			||||
    else:
 | 
				
			||||
        _conf = {}
 | 
				
			||||
    return _conf
 | 
				
			||||
def _isvalid(_allowed,**_args):
 | 
				
			||||
    
 | 
				
			||||
    if not list(set(_allowed) - set(_args.keys())) :
 | 
				
			||||
        _pargs = {}
 | 
				
			||||
        for key in _allowed :
 | 
				
			||||
            _pargs [key] = _args[key]
 | 
				
			||||
        return _pargs
 | 
				
			||||
    return False
 | 
				
			||||
 
 | 
				
			||||
def write_config(_config, path):
 | 
				
			||||
        f = open(path,'w')
 | 
				
			||||
        f.write( json.dumps(_config)) ;
 | 
				
			||||
        f.close()
 | 
				
			||||
        
 | 
				
			||||
def _system(**_args):
 | 
				
			||||
    """
 | 
				
			||||
        Both version and context must be provided otherwise they are ignored
 | 
				
			||||
        :version
 | 
				
			||||
        :context    context
 | 
				
			||||
    """
 | 
				
			||||
    _info =  _isvalid(['version','context'],**_args) 
 | 
				
			||||
    _info['theme'] = 'default.css'
 | 
				
			||||
    _info = _info if _info else {'version':'0.0.0','context':'','theme':'default.css'}
 | 
				
			||||
    if _info :
 | 
				
			||||
        _info['logo'] = None if 'logo' not in _args else _args['logo']
 | 
				
			||||
    #
 | 
				
			||||
    # There is an aggregation entry here in app
 | 
				
			||||
    _appInfo = {'debug':True,'port':8084,'threaded':True,'host':'0.0.0.0'}
 | 
				
			||||
    if 'app' not in _args:
 | 
				
			||||
        _info['app']  = _appInfo
 | 
				
			||||
    else:
 | 
				
			||||
        _info['app'] = dict(_appInfo,**_args['app'])
 | 
				
			||||
        
 | 
				
			||||
    return _info
 | 
				
			||||
def _header(**_args):
 | 
				
			||||
    return  _isvalid(['logo','title','subtitle'],**_args)
 | 
				
			||||
def _layout(**_args):
 | 
				
			||||
    _info = _isvalid(['root','index'],**_args)
 | 
				
			||||
    _info['on'] = {"load":{},"error":{}}
 | 
				
			||||
    _url = 'qcms.co'
 | 
				
			||||
    _overwrite = {"folder1":{"type":"redirect","url":_url},"folder2":{"type":"dialog"},"folder3":{"type":"dialog","url":_url}}
 | 
				
			||||
    _info['icons'] = {"comment":"use folder names as keys and fontawesome type as values to add icons to menu"}
 | 
				
			||||
    _info["api"] = {"comment":"use keys as uri and function calls as values"}
 | 
				
			||||
    _info['map'] = {},
 | 
				
			||||
    _info['order'] = {'menu':[]}
 | 
				
			||||
    _info['overwrite'] = _overwrite
 | 
				
			||||
    return _info
 | 
				
			||||
    
 | 
				
			||||
def make (**_args):
 | 
				
			||||
    """
 | 
				
			||||
    :context
 | 
				
			||||
    :port   port to be served
 | 
				
			||||
    
 | 
				
			||||
    :title  title of the application
 | 
				
			||||
    :root   folder of the content to be scanned
 | 
				
			||||
    """
 | 
				
			||||
    if 'port' in _args :
 | 
				
			||||
        _args['app'] = {'port':_args['port']}
 | 
				
			||||
        del _args['port']
 | 
				
			||||
    if 'context' not in _args :
 | 
				
			||||
        _args['context'] = ''
 | 
				
			||||
    _info ={'system': _system(**_args)}
 | 
				
			||||
    _hargs = {'title':'QCMS'} if 'title' not in _args else {'title':_args['title']}
 | 
				
			||||
    _hargs['subtitle'] = '' if 'subtitle' not in _args else _args['subtitle']
 | 
				
			||||
    _hargs['logo'] = True
 | 
				
			||||
    
 | 
				
			||||
    
 | 
				
			||||
    
 | 
				
			||||
    
 | 
				
			||||
    _info['layout'] = _layout(root=_args['root'],index='index.html')
 | 
				
			||||
    _info['layout']['header'] = _header(**_hargs)
 | 
				
			||||
    #
 | 
				
			||||
   
 | 
				
			||||
 | 
				
			||||
    if 'footer' in _args :
 | 
				
			||||
        _info['layout']['footer'] = [{'text':_args['footer']}] if type(_args['footer']) != list else [{'text':term} for term in _args['footeer']]
 | 
				
			||||
    else:
 | 
				
			||||
        _info['layout']['footer'] = [{'text':'Vanderbilt University Medical Center'}]
 | 
				
			||||
    
 | 
				
			||||
    return _info
 | 
				
			||||
 | 
				
			||||
@cli.command(name="info")
 | 
				
			||||
def _info():
 | 
				
			||||
    """
 | 
				
			||||
    This function returns metadata information about this program, no parameters are needed
 | 
				
			||||
    """
 | 
				
			||||
    print ()
 | 
				
			||||
    print (meta.__name__,meta.__version__)
 | 
				
			||||
    print (meta.__author__,meta.__email__)
 | 
				
			||||
    print ()
 | 
				
			||||
 | 
				
			||||
@cli.command(name='set-app')
 | 
				
			||||
# def set_app (host:str="0.0.0.0",context:str="",port:int=8084,debug=True):
 | 
				
			||||
def set_app (host:Annotated[str,typer.Argument(help="bind host IP address")]="0.0.0.0",
 | 
				
			||||
             context:Annotated[str,typer.Argument(help="if behind a proxy server (no forward slash needed)")]="",
 | 
				
			||||
             port:Annotated[int,typer.Argument(help="port on which to run the application")]=8084,
 | 
				
			||||
             debug:Annotated[bool,typer.Argument(help="set debug mode on|off")]=True):
 | 
				
			||||
    """
 | 
				
			||||
    This function consists in editing application access i.e port, debug, and/or context
 | 
				
			||||
 | 
				
			||||
    :context    alias or path for applications living behind proxy server
 | 
				
			||||
    """
 | 
				
			||||
    global INVALID_FOLDER
 | 
				
			||||
    _config = _get_config()
 | 
				
			||||
    if _config :
 | 
				
			||||
        _app = _config['system']['app']
 | 
				
			||||
        _app['host'] = host
 | 
				
			||||
        _app['port'] = port
 | 
				
			||||
        _app['debug'] = debug
 | 
				
			||||
        _config['system']['context'] = context
 | 
				
			||||
        _config['app'] = _app
 | 
				
			||||
        write_config(_config)
 | 
				
			||||
        _msg = f"""{PASSED} Successful update, good job !
 | 
				
			||||
        """
 | 
				
			||||
    else:
 | 
				
			||||
        _msg = INVALID_FOLDER
 | 
				
			||||
    print (_msg)
 | 
				
			||||
@cli.command(name='set-cloud')
 | 
				
			||||
# def set_cloud(path:str): #url:str,uid:str,token:str):
 | 
				
			||||
def set_cloud(path:Annotated[str,typer.Argument(help="path of the auth-file for the cloud")]): #url:str,uid:str,token:str):
 | 
				
			||||
    """
 | 
				
			||||
    This function overwrites or sets token information for nextcloud. This function will load the content from the cloud instead of locally
 | 
				
			||||
 | 
				
			||||
    :url    url of the nextcloud
 | 
				
			||||
    :uid    account identifier
 | 
				
			||||
    :token  token to be used to signin
 | 
				
			||||
    """
 | 
				
			||||
    if os.path.exists(path):
 | 
				
			||||
        f = open (path)
 | 
				
			||||
        _auth = json.loads(f.read())
 | 
				
			||||
        if not set(['url','token','uid'])  -  set(_auth.keys()) :
 | 
				
			||||
            url = _auth['url']
 | 
				
			||||
 | 
				
			||||
            if os.path.exists('qcms-manifest.json') :
 | 
				
			||||
                _config = _get_config()
 | 
				
			||||
                _config['system']['source'] = path #{'id':'cloud','auth':{'url':url,'uid':uid,'token':token}}
 | 
				
			||||
                write_config(_config)
 | 
				
			||||
                title = _config['layout']['header']['title']
 | 
				
			||||
                _msg = f"""
 | 
				
			||||
                Successfully update, good job!
 | 
				
			||||
                {url} 
 | 
				
			||||
                """
 | 
				
			||||
            else:
 | 
				
			||||
                _msg = INVALID_FOLDER
 | 
				
			||||
        else:
 | 
				
			||||
            _msg = """NOT A VALID NEXTCLOUD FILE"""
 | 
				
			||||
    else:
 | 
				
			||||
        _msg = INVALID_FOLDER
 | 
				
			||||
    print (_msg)
 | 
				
			||||
@cli.command(name='set-key')
 | 
				
			||||
# def set_key(path):
 | 
				
			||||
def set_key(
 | 
				
			||||
    manifest:Annotated[str,typer.Argument(help="path of the manifest file")],
 | 
				
			||||
    keyfile:Annotated[str,typer.Argument(help="path of the key file to generate")]):
 | 
				
			||||
    """
 | 
				
			||||
    create a security key to control the application during developement. The location must have been created prior.
 | 
				
			||||
 | 
				
			||||
    """
 | 
				
			||||
    if not os.path.exists(keyfile):
 | 
				
			||||
        f = open(keyfile,'w')
 | 
				
			||||
        f.write(str(uuid.uuid4()))
 | 
				
			||||
        f.close()
 | 
				
			||||
        #
 | 
				
			||||
        _config = _get_config(manifest)
 | 
				
			||||
        if 'source' not in _config['system']:
 | 
				
			||||
            _config['system']['source'] = {'id':'disk'}
 | 
				
			||||
        _config['system']['source']['key'] = keyfile
 | 
				
			||||
        write_config(_config,manifest)
 | 
				
			||||
        _msg = f"""{PASSED} A key was generated and written to {keyfile}
 | 
				
			||||
            use this key in header to enable reload of the site ...`
 | 
				
			||||
        """
 | 
				
			||||
    else:
 | 
				
			||||
        _msg = f"""{FAILED} Could NOT generate a key, because it would seem you already have one
 | 
				
			||||
            Please manually delete {keyfile}
 | 
				
			||||
 | 
				
			||||
            
 | 
				
			||||
        """
 | 
				
			||||
    print (_msg)
 | 
				
			||||
 | 
				
			||||
def load(**_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
 | 
				
			||||
 | 
				
			||||
@cli.command (name='create')
 | 
				
			||||
# def create(folder:str,root:str,index:str='index.html',title:str='qcms',subtitle:str='',footer:str='Quick Content Management System',version:str='0.1'):
 | 
				
			||||
def create(folder:Annotated[str,typer.Argument(help="path of the project folder")],
 | 
				
			||||
           root:Annotated[str,typer.Argument(help="folder of the content (inside the project folder)")],
 | 
				
			||||
           index:str=typer.Option(default="index.html",help="index file (markup or html)"), #Annotated[str,typer.Argument(help="index file to load (.html or markup)")]='index.html',
 | 
				
			||||
           title:str=typer.Option(default="QCMS PROJECT", help="name of the project") , #Annotated[str,typer.Argument(help="title of the project")]='QCMS - TITLE',
 | 
				
			||||
           subtitle:str=typer.Option(default="designed & built by The Phi Technology",help="tag line about the project (sub-title)"), #Annotated[str,typer.Argument(help="subtitle of the project")]='qcms - subtitle',
 | 
				
			||||
           footer:str=typer.Option(default="Quick Content Management System",help="text to be placed as footer"), #Annotated[str,typer.Argument(help="text on the footer of the main page")]='Quick Content Management System',
 | 
				
			||||
           version:str=typer.Option(default="0.2",help="version number") #Annotated[str,typer.Argument(help="version of the site")]='0.1'
 | 
				
			||||
           ):
 | 
				
			||||
    """
 | 
				
			||||
    This function will create a project folder by performing a git clone (pull the template project)
 | 
				
			||||
    and adding a configuration file to that will bootup the project
 | 
				
			||||
 | 
				
			||||
    
 | 
				
			||||
    folder  project folder
 | 
				
			||||
    
 | 
				
			||||
    root    name/location of root folder associated with the web application
 | 
				
			||||
 | 
				
			||||
    @TODO: 
 | 
				
			||||
        - add port, 
 | 
				
			||||
    """
 | 
				
			||||
    #global SYS_ARGS
 | 
				
			||||
    #folder  = SYS_ARGS['create']
 | 
				
			||||
   
 | 
				
			||||
    url = "https://dev.the-phi.com/git/cloud/cms.git" 
 | 
				
			||||
    #if 'url' in SYS_ARGS :
 | 
				
			||||
    #    url = SYS_ARGS['url']
 | 
				
			||||
    print ("\tcreating project into folder " +folder)
 | 
				
			||||
    #
 | 
				
			||||
    # if standalone, then we should create the git repository
 | 
				
			||||
    # if standalone :
 | 
				
			||||
    #     _repo = Repo.clone_from(url,folder)
 | 
				
			||||
    #     #
 | 
				
			||||
    #     # removing remote folder associated with the project
 | 
				
			||||
    #     _repo.delete_remote(remote='origin')
 | 
				
			||||
    # else:
 | 
				
			||||
    #     os.makedirs(folder)
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
    #
 | 
				
			||||
    # @TODO: root should be handled in 
 | 
				
			||||
    rootpath = os.sep.join([folder,root]) 
 | 
				
			||||
    _img = None
 | 
				
			||||
    if not os.path.exists(rootpath) :
 | 
				
			||||
        print (f"{PASSED} Creating content folder "+rootpath)
 | 
				
			||||
        os.makedirs(rootpath)
 | 
				
			||||
        os.makedirs(os.sep.join([rootpath,'_images']))
 | 
				
			||||
        _img = """data:image/png;base64,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"""
 | 
				
			||||
        _,_img = _img.split(',',1)
 | 
				
			||||
        logo = os.sep.join([rootpath,'_images','logo.png'])
 | 
				
			||||
        f = open(logo,'wb')
 | 
				
			||||
        f.write(base64.b64decode(_img))
 | 
				
			||||
        f.close()
 | 
				
			||||
 | 
				
			||||
    _html = __doc__.replace("<","<").replace(">",">").replace("Usage","<br>Usage")
 | 
				
			||||
    
 | 
				
			||||
    if not os.path.exists(os.sep.join([rootpath,'index.html'])) :
 | 
				
			||||
        f = open(os.sep.join([rootpath,'index.html']),'w')
 | 
				
			||||
        f.write(_html)
 | 
				
			||||
        f.close()
 | 
				
			||||
    print (f'{PASSED} configuration being written to project folder')
 | 
				
			||||
    _args = {'title':title,'subtitle':subtitle,'version':version,'root':root,'index':index}
 | 
				
			||||
    if footer :
 | 
				
			||||
        _args['footer'] = footer
 | 
				
			||||
    _config = make(**_args)
 | 
				
			||||
    #
 | 
				
			||||
    # updating logo reference (default for now)
 | 
				
			||||
    _config['system']['logo'] = os.sep.join([_config['layout']['root'],'_images/logo.png'])
 | 
				
			||||
   
 | 
				
			||||
 | 
				
			||||
    f = open(os.sep.join([folder,'qcms-manifest.json']),'w')
 | 
				
			||||
    f.write(json.dumps(_config))
 | 
				
			||||
    f.close()
 | 
				
			||||
    return _config     
 | 
				
			||||
 | 
				
			||||
@cli.command (name='reload')
 | 
				
			||||
def reload (path) :
 | 
				
			||||
    if os.path.exists (path):
 | 
				
			||||
        pass
 | 
				
			||||
@cli.command(name="bootup")
 | 
				
			||||
def bootup (
 | 
				
			||||
    path:Annotated[str,typer.Argument(help="path of the manifest file")]='qcms-manifest.json',
 | 
				
			||||
    port:int=typer.Option(default=None, help="port number to serve on (will override configuration)")
 | 
				
			||||
    ):
 | 
				
			||||
    """
 | 
				
			||||
    This function will launch a site/project given the location of the manifest file
 | 
				
			||||
    """
 | 
				
			||||
    index.start(path,port)
 | 
				
			||||
    # if not port :
 | 
				
			||||
    #     index.start(path)
 | 
				
			||||
    # else:
 | 
				
			||||
    #     index.start(path,port)
 | 
				
			||||
     
 | 
				
			||||
def reset():
 | 
				
			||||
    """
 | 
				
			||||
    """
 | 
				
			||||
    global SYS_ARGS
 | 
				
			||||
if __name__ == '__main__':
 | 
				
			||||
    cli()
 | 
				
			||||
@ -0,0 +1,433 @@
 | 
				
			||||
import json
 | 
				
			||||
import os
 | 
				
			||||
import io
 | 
				
			||||
import copy
 | 
				
			||||
from cms import disk, cloud
 | 
				
			||||
from jinja2 import Environment, BaseLoader, FileSystemLoader
 | 
				
			||||
import importlib
 | 
				
			||||
import importlib.util
 | 
				
			||||
"""
 | 
				
			||||
There are four classes at play here:
 | 
				
			||||
[ Initializer ] <|-- [ Module ] <|-- [ MicroService ] <--<>[ CMS ]
 | 
				
			||||
"""
 | 
				
			||||
 | 
				
			||||
class Initializer :
 | 
				
			||||
    """
 | 
				
			||||
    This class handles initialization of all sorts associated with "cms engine" 
 | 
				
			||||
    :path
 | 
				
			||||
    :location
 | 
				
			||||
    :shared
 | 
				
			||||
    """
 | 
				
			||||
    def __init__(self,**_args):
 | 
				
			||||
        self._config = {'system':{},'layout':{},'plugins':{}}
 | 
				
			||||
        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 {}
 | 
				
			||||
        # self._ISCLOUD = 'source' in self._config['system'] and self._config['system']['source']['id'] == 'cloud'
 | 
				
			||||
        # print ([self._ISCLOUD,self._config['system'].keys()])
 | 
				
			||||
        self._ISCLOUD = False
 | 
				
			||||
        self._caller = None if 'caller'  not in _args else _args['caller']
 | 
				
			||||
        self._args = _args
 | 
				
			||||
 | 
				
			||||
        self.reload() #-- this is an initial load of various components
 | 
				
			||||
 | 
				
			||||
    def reload(self):
 | 
				
			||||
 | 
				
			||||
        self._iconfig(**self._args)
 | 
				
			||||
        self._uconfig(**self._args)
 | 
				
			||||
        self._isource()
 | 
				
			||||
        self._imenu()        
 | 
				
			||||
        self._iplugins()
 | 
				
			||||
        
 | 
				
			||||
 | 
				
			||||
        # self._ISCLOUD = 'source' in self._config['system'] and self._config['system']['source']['id'] == 'cloud'
 | 
				
			||||
 | 
				
			||||
    def _handler  (self):
 | 
				
			||||
        """
 | 
				
			||||
        This function returns the appropriate handler to the calling code, The handler enables read/write from a location
 | 
				
			||||
        """
 | 
				
			||||
        
 | 
				
			||||
        if self._ISCLOUD: #'source' in self._config['system'] and self._config['system']['source']['id'] == 'cloud' :
 | 
				
			||||
            return cloud
 | 
				
			||||
        else:
 | 
				
			||||
            return disk
 | 
				
			||||
        
 | 
				
			||||
    def _imenu(self,**_args) :
 | 
				
			||||
        pass
 | 
				
			||||
    def _iplugins(self,**_args) :
 | 
				
			||||
        """
 | 
				
			||||
        Initialize plugins from disk (always)
 | 
				
			||||
        :plugins
 | 
				
			||||
        """
 | 
				
			||||
        _config = self._config
 | 
				
			||||
        PATH= os.sep.join([_config['layout']['root'],'_plugins'])
 | 
				
			||||
        
 | 
				
			||||
        if not os.path.exists(PATH) and self._location and os.path.exists(self._location) :
 | 
				
			||||
            #
 | 
				
			||||
            # overriding the location of plugins ...
 | 
				
			||||
            if os.path.isfile(self._location) :
 | 
				
			||||
                _location = os.sep.join(self._location.split(os.sep)[:-1])
 | 
				
			||||
            else:
 | 
				
			||||
                _location = self._location 
 | 
				
			||||
            PATH = os.sep.join([_location, _config['layout']['root'],'_plugins'])
 | 
				
			||||
        _context = _config['system']['context']
 | 
				
			||||
        _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 = disk.plugins(path=_path,name=_name,context=_context)
 | 
				
			||||
                if _pointer :
 | 
				
			||||
                    _uri = "/".join(["api",_key,_name]) 
 | 
				
			||||
                    if _context :
 | 
				
			||||
                        _uri = f'{_context}/{_uri}'
 | 
				
			||||
                    _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 self._ISCLOUD :
 | 
				
			||||
            _plugins = cloud.plugins(_context)
 | 
				
			||||
        else:
 | 
				
			||||
            _plugins = disk.plugins(context=_context)
 | 
				
			||||
        #
 | 
				
			||||
        # 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 _isource (self):
 | 
				
			||||
        """
 | 
				
			||||
        Initializing the source of the data, so we can read/write load from anywhere
 | 
				
			||||
        """
 | 
				
			||||
        if 'source' not in self._config['system'] :
 | 
				
			||||
            return
 | 
				
			||||
        #
 | 
				
			||||
        #
 | 
				
			||||
        self._ISCLOUD = 'source' in self._config['system'] and self._config['system']['source']['id'] == 'cloud'
 | 
				
			||||
        _source = self._config['system']['source']
 | 
				
			||||
        if 'key' in _source :
 | 
				
			||||
            #
 | 
				
			||||
            _path = _source['key']
 | 
				
			||||
            if os.path.exists(_path) :
 | 
				
			||||
                f = open(_path)
 | 
				
			||||
                _source['key'] = f.read()
 | 
				
			||||
                f.close()
 | 
				
			||||
                self._config['system']['source'] = _source
 | 
				
			||||
    def _ilayout(self,**_args):
 | 
				
			||||
        """
 | 
				
			||||
        Initialization of the layout section (should only happen if ) being called via framework
 | 
				
			||||
        :path   path to the dependent apps
 | 
				
			||||
        """
 | 
				
			||||
        _layout = self._config['layout']
 | 
				
			||||
        _path = os.sep.join(_args['path'].split(os.sep)[:-1])
 | 
				
			||||
        #
 | 
				
			||||
        # find the new root and the one associated with the dependent app
 | 
				
			||||
        #
 | 
				
			||||
 | 
				
			||||
        pass
 | 
				
			||||
    def _imenu(self,**_args):
 | 
				
			||||
        _gshandler = self._handler()
 | 
				
			||||
        _object = _gshandler.build(self._config) #-- this will build the menu
 | 
				
			||||
        #
 | 
				
			||||
        # post-processing menu, overwrite items and behaviors
 | 
				
			||||
        #
 | 
				
			||||
        
 | 
				
			||||
        _layout = copy.deepcopy(self._config['layout'])
 | 
				
			||||
        _overwrite = _layout['overwrite'] if 'overwrite' in _layout else {}
 | 
				
			||||
        _context = self.system()['context']
 | 
				
			||||
        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 _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'],'')
 | 
				
			||||
                    # _item['uri'] = _gshandler._format(_item['uri'],self._config)
 | 
				
			||||
 | 
				
			||||
                _submenu[_index] = _item
 | 
				
			||||
                _index += 1
 | 
				
			||||
        #
 | 
				
			||||
        # updating menu _items as it relates to apps, configuration and the order in which they appear
 | 
				
			||||
        #
 | 
				
			||||
        _layout['menu'] = _object
 | 
				
			||||
        self._menu      = _object 
 | 
				
			||||
        self._config['layout'] = _layout
 | 
				
			||||
        self._iapps()
 | 
				
			||||
        self._iorder()
 | 
				
			||||
        pass
 | 
				
			||||
 | 
				
			||||
    def _iorder (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 _iapps (self):
 | 
				
			||||
        """
 | 
				
			||||
        Initializing dependent applications into a menu area if need be
 | 
				
			||||
        """
 | 
				
			||||
        _layout = self._config['layout']
 | 
				
			||||
        _menu   = _layout['menu'] if 'menu' in _layout else {}
 | 
				
			||||
        _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'})
 | 
				
			||||
        #
 | 
				
			||||
        # update the menu items and the configuration 
 | 
				
			||||
        #
 | 
				
			||||
        _layout['menu'] = _menu
 | 
				
			||||
        self._config['layout'] = _layout
 | 
				
			||||
    def _ilogo(self):
 | 
				
			||||
        _gshandler = self._handler()
 | 
				
			||||
 | 
				
			||||
        pass
 | 
				
			||||
    def _iconfig(self,**_args):
 | 
				
			||||
        """
 | 
				
			||||
        Implement this in a base class
 | 
				
			||||
        :path or uri
 | 
				
			||||
        """
 | 
				
			||||
        raise Exception ("Configuration Initialization is NOT implemented")
 | 
				
			||||
    def _uconfig(self,**_args):
 | 
				
			||||
        """
 | 
				
			||||
        This file will update the configuration provided the CMS is run in shared mode (framework level)
 | 
				
			||||
        """
 | 
				
			||||
        if not self._location :
 | 
				
			||||
            return ;
 | 
				
			||||
        _path = os.sep.join(self._location.split(os.sep)[:-1])
 | 
				
			||||
        _layout = self._config['layout']
 | 
				
			||||
        _oroot = _layout['root']
 | 
				
			||||
        _orw = _layout['overwrite']
 | 
				
			||||
        _index = _layout['index']
 | 
				
			||||
        _newpath = os.sep.join([_path,_oroot])
 | 
				
			||||
        self._config['system']['portal'] = self._caller != None
 | 
				
			||||
        _context = self.system()['context']
 | 
				
			||||
        if self._caller :
 | 
				
			||||
            #
 | 
				
			||||
            _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
 | 
				
			||||
        
 | 
				
			||||
        
 | 
				
			||||
        if os.path.exists(_newpath) and not self._ISCLOUD:
 | 
				
			||||
            #
 | 
				
			||||
            # LOG: rewrite due to the mode in which the site is being run
 | 
				
			||||
            #
 | 
				
			||||
            _api = f'{_context}/api/disk/read?uri='+_oroot
 | 
				
			||||
            _stream = json.dumps(self._config)
 | 
				
			||||
            _stream = _stream.replace(_oroot,_api)
 | 
				
			||||
            # self._config = json.loads(_stream)            
 | 
				
			||||
            self._config['layout']['root'] = _oroot
 | 
				
			||||
 | 
				
			||||
            # self._config['layout']['overwrite'] = _orw
 | 
				
			||||
        #
 | 
				
			||||
        # We need to update the  logo/icon
 | 
				
			||||
        _logo = self._config['system']['logo']
 | 
				
			||||
        if self._ISCLOUD:
 | 
				
			||||
            
 | 
				
			||||
            _icon = f'{_context}/api/cloud/download?doc=/{_logo}'
 | 
				
			||||
            
 | 
				
			||||
            
 | 
				
			||||
        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):
 | 
				
			||||
    """
 | 
				
			||||
    This is a basic structure for an application working in either portal or app mode,
 | 
				
			||||
    """
 | 
				
			||||
    def __init__(self,**_args):
 | 
				
			||||
        super().__init__(**_args)
 | 
				
			||||
        pass
 | 
				
			||||
    def _iconfig(self, **_args):
 | 
				
			||||
        """
 | 
				
			||||
        initialization of the configuration file i.e loading the files and having a baseline workable structure
 | 
				
			||||
        :path|stream   path of the configuration file
 | 
				
			||||
                        or stream of JSON configuration file
 | 
				
			||||
        """
 | 
				
			||||
        if 'path' in _args :
 | 
				
			||||
            f = open(_args['path'])
 | 
				
			||||
            self._config = json.loads(f.read())
 | 
				
			||||
            f.close()
 | 
				
			||||
        elif 'stream' in _args :
 | 
				
			||||
            _stream = _args['stream']
 | 
				
			||||
            if type(_stream) == 'str' :
 | 
				
			||||
                self._config  = json.loads(_stream)
 | 
				
			||||
            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'
 | 
				
			||||
        #
 | 
				
			||||
        #
 | 
				
			||||
        # self._name = self._config['system']['name'] if 'name' in self._config['system'] else _args['name']
 | 
				
			||||
    def system (self,skip=[]):
 | 
				
			||||
        """
 | 
				
			||||
        This function returns system attributes without specific components
 | 
				
			||||
        """
 | 
				
			||||
        _data = copy.deepcopy(self._config['system'])
 | 
				
			||||
        exclude = skip
 | 
				
			||||
        _system = {}
 | 
				
			||||
        if exclude and _system:
 | 
				
			||||
            for key in _data.keys() :
 | 
				
			||||
                if key not in exclude :
 | 
				
			||||
                    _system[key] = _data[key]
 | 
				
			||||
        else:
 | 
				
			||||
            _system= _data
 | 
				
			||||
        return _system 
 | 
				
			||||
    def layout (self):
 | 
				
			||||
        return copy.copy(self._config['layout'])
 | 
				
			||||
    def plugins (self):
 | 
				
			||||
        return copy.copy(self._config['plugins'])
 | 
				
			||||
    def config (self):
 | 
				
			||||
        
 | 
				
			||||
        return copy.copy(self._config)
 | 
				
			||||
    def app(self):
 | 
				
			||||
        _system = self.system()
 | 
				
			||||
        return _system['app'] 
 | 
				
			||||
    def set(self,key,value):
 | 
				
			||||
        """
 | 
				
			||||
        This function will update/set an attribute with a given value
 | 
				
			||||
        :key    
 | 
				
			||||
        """
 | 
				
			||||
        _keys = key.split('.')
 | 
				
			||||
        _found = 0
 | 
				
			||||
        if _keys[0] in self._config :
 | 
				
			||||
            _object = self._config[_keys[0]]
 | 
				
			||||
            for _akey in _object.keys() :
 | 
				
			||||
                if _akey == _keys[-1] :
 | 
				
			||||
                    _object[_akey] = value
 | 
				
			||||
                    _found = 1
 | 
				
			||||
                    break
 | 
				
			||||
 | 
				
			||||
        #
 | 
				
			||||
        #
 | 
				
			||||
        return _found
 | 
				
			||||
        #
 | 
				
			||||
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)
 | 
				
			||||
    def format(_content,mimetype):
 | 
				
			||||
        pass
 | 
				
			||||
    def html (self,uri, id) :
 | 
				
			||||
        _system = self.system()
 | 
				
			||||
        _gshandler = self._handler()
 | 
				
			||||
        #
 | 
				
			||||
        #@TODO:
 | 
				
			||||
        # The uri here must be properly formatted, We need to define the conditions for this
 | 
				
			||||
        #
 | 
				
			||||
        _html = _gshandler.html(uri,self._config)
 | 
				
			||||
        return " ".join([f'<div id="{id}" > ',_html, '</div>'])
 | 
				
			||||
    def context(self):
 | 
				
			||||
        return Environment(loader=BaseLoader())
 | 
				
			||||
    def data (self,**_args):
 | 
				
			||||
        request = _args['request']
 | 
				
			||||
    def icon (self):
 | 
				
			||||
        _handler = self._handler()
 | 
				
			||||
        _uri = self.system()['icon']
 | 
				
			||||
 | 
				
			||||
        return _handler.read(uri=_uri,config=self._config)
 | 
				
			||||
class CMS:
 | 
				
			||||
    """
 | 
				
			||||
    This class aggregates microservices and allows the application of a given service (site/app)
 | 
				
			||||
    """
 | 
				
			||||
    def __init__(self,**_args) :
 | 
				
			||||
        
 | 
				
			||||
        # _app = Getter (path = path)
 | 
				
			||||
        # _void = MicroService()
 | 
				
			||||
        
 | 
				
			||||
        _app = MicroService (**_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] = MicroService(context=_name,path=_path,caller=_app,location=_path)
 | 
				
			||||
 | 
				
			||||
        self._apps['main'] = _app    
 | 
				
			||||
    #
 | 
				
			||||
    # The following are just a simple delegation pattern (it makes the calling code simpler)
 | 
				
			||||
    #
 | 
				
			||||
    def config (self):
 | 
				
			||||
        return self.get().config()
 | 
				
			||||
    
 | 
				
			||||
    def render(self,_uri,_id,_appid):
 | 
				
			||||
        # _handler = self.get()
 | 
				
			||||
        _handler = self._apps[_appid]
 | 
				
			||||
        _config = _handler.config()
 | 
				
			||||
        _args = {'layout':_handler.layout()}
 | 
				
			||||
        if 'plugins' in _config:
 | 
				
			||||
            _args['routes'] = _config['plugins']
 | 
				
			||||
        
 | 
				
			||||
        _html =  _handler.html(_uri,_id)
 | 
				
			||||
        _args['system'] = _handler.system(skip=['source','app'])
 | 
				
			||||
        e = Environment(loader=BaseLoader()).from_string(_html)
 | 
				
			||||
        _args[_id] =  str(e.render(**_args)) #,_args
 | 
				
			||||
        return _args
 | 
				
			||||
    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']
 | 
				
			||||
@ -0,0 +1,329 @@
 | 
				
			||||
__doc__ = """
 | 
				
			||||
    arguments :
 | 
				
			||||
        --config    path of the configuration otherwise it will look for the default in the working directory
 | 
				
			||||
"""
 | 
				
			||||
from flask import Flask,render_template,send_from_directory,request, redirect, Response, session
 | 
				
			||||
import flask
 | 
				
			||||
import transport
 | 
				
			||||
from transport import providers
 | 
				
			||||
import cms
 | 
				
			||||
import sys
 | 
				
			||||
import os
 | 
				
			||||
import json
 | 
				
			||||
import copy
 | 
				
			||||
import io
 | 
				
			||||
import base64
 | 
				
			||||
from jinja2 import Environment, BaseLoader
 | 
				
			||||
import typer
 | 
				
			||||
from typing_extensions import Annotated
 | 
				
			||||
from typing import Optional
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
import pandas as pd
 | 
				
			||||
import uuid
 | 
				
			||||
import datetime
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
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')
 | 
				
			||||
    return _route._apps[_id]
 | 
				
			||||
def _setHandler (id) :
 | 
				
			||||
    session['app_id'] = id
 | 
				
			||||
@_app.route("/robots.txt")
 | 
				
			||||
def robots_txt():
 | 
				
			||||
    """
 | 
				
			||||
    This function will generate a robots expression for a variety of crawlers, the paths will be provided by
 | 
				
			||||
    menu options
 | 
				
			||||
    """
 | 
				
			||||
    global _route
 | 
				
			||||
    _system = _route.get ().system()
 | 
				
			||||
 | 
				
			||||
    _info  = ['''
 | 
				
			||||
    User-agent: *
 | 
				
			||||
    Allow: /
 | 
				
			||||
    ''']
 | 
				
			||||
 | 
				
			||||
    if 'routes' in _system  :
 | 
				
			||||
        for _key in _system['routes'] :
 | 
				
			||||
            _uri = '/'.join(['',_key])
 | 
				
			||||
            _info.append(f'''
 | 
				
			||||
    User-agent: *
 | 
				
			||||
    Allow: {_uri}
 | 
				
			||||
                        ''')
 | 
				
			||||
    
 | 
				
			||||
    # return '\n'.join(_info),200,{'Content-Type':'plain/text'}
 | 
				
			||||
    return Response('\n'.join(_info), mimetype='text/plain')    
 | 
				
			||||
@_app.route("/")
 | 
				
			||||
def _index ():
 | 
				
			||||
    # global _config
 | 
				
			||||
    # global _route
 | 
				
			||||
    # _handler = _route.get() 
 | 
				
			||||
    # _config = _route.config()
 | 
				
			||||
    _handler = _getHandler()
 | 
				
			||||
    _config = _handler.config()
 | 
				
			||||
    print ([' serving ',session.get('app_id','NA'),_handler.layout()['root']])
 | 
				
			||||
    # _system = _handler.system()
 | 
				
			||||
    # _plugins= _handler.plugins()
 | 
				
			||||
    # _args = {}
 | 
				
			||||
    # # if 'plugins' in _config :
 | 
				
			||||
    # #     _args['routes']=_config['plugins']
 | 
				
			||||
    # # _system = cms.components.get_system(_config) #copy.deepcopy(_config['system'])
 | 
				
			||||
    # _html = ""
 | 
				
			||||
    _args={'system':_handler.system(skip=['source','app','data']),'layout':_handler.layout()}
 | 
				
			||||
    try:
 | 
				
			||||
        uri = os.sep.join([_config['layout']['root'], _config['layout']['index']])
 | 
				
			||||
        
 | 
				
			||||
    #     # _html = _route.get().html(uri,'index',_config,_system)
 | 
				
			||||
    #     _html = _handler.html(uri,'index')
 | 
				
			||||
        _index_page = "index.html"
 | 
				
			||||
        _args = _route.render(uri,'index',session.get('app_id','main'))
 | 
				
			||||
    except Exception as e:
 | 
				
			||||
    #     print ()
 | 
				
			||||
        print (e)
 | 
				
			||||
        _index_page = "404.html"
 | 
				
			||||
    #     _args['uri'] = request.base_url
 | 
				
			||||
    #     pass
 | 
				
			||||
    # # if 'source' in _system :
 | 
				
			||||
    # #     del _system['source']
 | 
				
			||||
    # _args = {'layout':_config['layout'],'index':_html}
 | 
				
			||||
    # _args['system'] = _handler.system(skip=['source','app','route'])
 | 
				
			||||
    
 | 
				
			||||
    return render_template(_index_page,**_args),200 if _index_page != "404.html" else 200
 | 
				
			||||
 | 
				
			||||
# @_app.route('/id/<uid>') 
 | 
				
			||||
# def people(uid):
 | 
				
			||||
#     """
 | 
				
			||||
#     This function will implement hardened links that can directly "do something"
 | 
				
			||||
#     """
 | 
				
			||||
#     global _config    
 | 
				
			||||
#     return "0",200
 | 
				
			||||
  
 | 
				
			||||
@_app.route('/dialog')
 | 
				
			||||
def _dialog ():
 | 
				
			||||
    # global _config 
 | 
				
			||||
    global _route
 | 
				
			||||
    _handler = _route.get()
 | 
				
			||||
    _uri = request.headers['uri']
 | 
				
			||||
    
 | 
				
			||||
    _id = request.headers['dom']
 | 
				
			||||
    # _html = ''.join(["<div style='padding:1%'>",str( e.render(**_args)),'</div>'])
 | 
				
			||||
    _args = _route.render(_uri,'html',session.get('app_id','main'))
 | 
				
			||||
    _args['title'] = _id
 | 
				
			||||
    return render_template('dialog.html',**_args) #title=_id,html=_html)
 | 
				
			||||
@_app.route("/caller/<app>/api/<module>/<name>")
 | 
				
			||||
def _delegate_call(app,module,name):
 | 
				
			||||
    global _route
 | 
				
			||||
    _handler = _route._apps[app]
 | 
				
			||||
    return _delegate(_handler,module,name)
 | 
				
			||||
 | 
				
			||||
@_app.route('/api/<module>/<name>')
 | 
				
			||||
def _getproxy(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()
 | 
				
			||||
    return _delegate(_handler,module,name)
 | 
				
			||||
 | 
				
			||||
def _delegate(_handler,module,name):
 | 
				
			||||
    global _route
 | 
				
			||||
    uri =  '/'.join(['api',module,name])
 | 
				
			||||
    # _args = dict(request.args,**{})
 | 
				
			||||
    # _args['config'] = _handler.config()
 | 
				
			||||
    _plugins = _handler.plugins()
 | 
				
			||||
    _context = _handler.system()['context']
 | 
				
			||||
    if _context :
 | 
				
			||||
        uri  = f'{_context}/{uri}'
 | 
				
			||||
    
 | 
				
			||||
    if uri not in _plugins :
 | 
				
			||||
        _data = {}
 | 
				
			||||
        _code = 404
 | 
				
			||||
    else:
 | 
				
			||||
        pointer = _plugins[uri]
 | 
				
			||||
        # if _args :
 | 
				
			||||
        #     _data = pointer (**_args)
 | 
				
			||||
        # else:
 | 
				
			||||
        #     _data = pointer()
 | 
				
			||||
        
 | 
				
			||||
        _data = pointer(request=request,config=_handler.config())
 | 
				
			||||
        if type(_data) == pd.DataFrame :
 | 
				
			||||
            _data = _data.to_dict(orient='records')
 | 
				
			||||
        if type(_data) == list:
 | 
				
			||||
            _data = json.dumps(_data)   
 | 
				
			||||
        _code = 200 if _data else 500
 | 
				
			||||
    return _data,_code
 | 
				
			||||
@_app.route("/api/<module>/<name>" , methods=['POST'])
 | 
				
			||||
def _post (module,name):
 | 
				
			||||
    # global _config
 | 
				
			||||
    # global _route
 | 
				
			||||
    # _handler = _route.get()
 | 
				
			||||
    _handler = _getHandler()
 | 
				
			||||
    return _delegate(_handler,module,name)
 | 
				
			||||
 | 
				
			||||
@_app.route('/version')
 | 
				
			||||
def _version ():
 | 
				
			||||
    global _route
 | 
				
			||||
    _handler = _route.get()
 | 
				
			||||
    global _config 
 | 
				
			||||
    return _handler.system()['version']
 | 
				
			||||
@_app.route('/reload',methods=['POST'])
 | 
				
			||||
def reload():
 | 
				
			||||
    global _route
 | 
				
			||||
 | 
				
			||||
    _handler = _route.get_main()
 | 
				
			||||
    _system = _handler.system()
 | 
				
			||||
    _key = request.headers['key'] if 'key' in request.headers else None
 | 
				
			||||
    if not 'source' in _system :
 | 
				
			||||
        _systemKey = None
 | 
				
			||||
    elif 'key' in _system['source'] and _system['source']['key']:
 | 
				
			||||
        _systemKey = _system['source']['key']
 | 
				
			||||
        print ([_key,_systemKey,_systemKey == _key])
 | 
				
			||||
        if _key and _systemKey and _systemKey == _key :
 | 
				
			||||
            _handler.reload()
 | 
				
			||||
            return "",200
 | 
				
			||||
        pass
 | 
				
			||||
    return "",403
 | 
				
			||||
@_app.route('/page',methods=['POST'])
 | 
				
			||||
def cms_page():
 | 
				
			||||
    """
 | 
				
			||||
    return the content of a folder formatted for a menu
 | 
				
			||||
    """
 | 
				
			||||
    # global _config
 | 
				
			||||
    global _route
 | 
				
			||||
    # _handler = _route.get()
 | 
				
			||||
    # _config = _handler.config()
 | 
				
			||||
    _handler = _getHandler()
 | 
				
			||||
    _config = _handler.config()
 | 
				
			||||
    # _uri = os.sep.join([_config['layout']['root'],request.headers['uri']])
 | 
				
			||||
    _uri = request.headers['uri']
 | 
				
			||||
    if 'dom' not in request.headers :
 | 
				
			||||
        _id = _uri.split('/')[-1].split('.')[0]
 | 
				
			||||
    else:
 | 
				
			||||
        _id = request.headers['dom']
 | 
				
			||||
    # _args = {'layout':_config['layout']}
 | 
				
			||||
    # if 'plugins' in _config:
 | 
				
			||||
    #     _args['routes'] = _config['plugins']
 | 
				
			||||
    
 | 
				
			||||
    # _system = _handler.system() #cms.components.get_system(_config)
 | 
				
			||||
    # # _html =  _handler.html(_uri,_id,_args,_system) #cms.components.html(_uri,_id,_args,_system)
 | 
				
			||||
 | 
				
			||||
    # _html =  _handler.html(_uri,_id)
 | 
				
			||||
    # # _system = cms.components.get_system(_config)
 | 
				
			||||
    # _args['system'] = _handler.system(skip=['source','app'])
 | 
				
			||||
    # e = Environment(loader=BaseLoader()).from_string(_html)
 | 
				
			||||
    # _html = e.render(**_args)
 | 
				
			||||
    if 'read?uri=' in _uri or 'download?doc=' in _uri :
 | 
				
			||||
        _uri = _uri.split('=')[1]
 | 
				
			||||
    
 | 
				
			||||
    _args = _route.render(_uri,_id,session.get('app_id','main'))
 | 
				
			||||
    return _args[_id],200
 | 
				
			||||
    # return _html,200
 | 
				
			||||
@_app.route('/page')
 | 
				
			||||
def _cms_page ():
 | 
				
			||||
    # global _config
 | 
				
			||||
    global _route
 | 
				
			||||
    # _handler = _route.get()
 | 
				
			||||
    # _config = _handler.config()
 | 
				
			||||
    _uri = request.args['uri']
 | 
				
			||||
    
 | 
				
			||||
    # _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'))
 | 
				
			||||
    return _args[_title],200
 | 
				
			||||
 | 
				
			||||
@_app.route('/set/<id>')
 | 
				
			||||
def set(id):
 | 
				
			||||
    global _route
 | 
				
			||||
    _setHandler(id)
 | 
				
			||||
    # _route.set(id)
 | 
				
			||||
    # _handler = _route.get()
 | 
				
			||||
    _handler = _getHandler()
 | 
				
			||||
    _context = _handler.system()['context']
 | 
				
			||||
    _uri = f'/{_context}'.replace('//','/')
 | 
				
			||||
    return redirect(_uri)
 | 
				
			||||
@_app.route('/<id>')    
 | 
				
			||||
def _open(id):
 | 
				
			||||
    global _route
 | 
				
			||||
    # _handler = _route.get()
 | 
				
			||||
 | 
				
			||||
    _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()
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
@cli.command()
 | 
				
			||||
def start (
 | 
				
			||||
    path:Annotated[str,typer.Argument(help="path of the manifest file")]='qcms-manifest.json',
 | 
				
			||||
    port:int=typer.Option(default=None, help="port number to serve on (will override configuration)")
 | 
				
			||||
 | 
				
			||||
    ) :
 | 
				
			||||
    """
 | 
				
			||||
    This function is designed to start the application with its associated manifest (configuration) location
 | 
				
			||||
    :path   path to the  the manifest
 | 
				
			||||
    :shared run in shared mode i.e 
 | 
				
			||||
    """
 | 
				
			||||
    global _route
 | 
				
			||||
 | 
				
			||||
    if os.path.exists(path) and os.path.isfile(path):
 | 
				
			||||
        _args = {'path':path}
 | 
				
			||||
        # if shared :
 | 
				
			||||
        #     _args['location'] = path
 | 
				
			||||
        #     _args['shared'] = shared
 | 
				
			||||
        _args['location'] = path
 | 
				
			||||
        _args['shared'] = True
 | 
				
			||||
        
 | 
				
			||||
        # _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()
 | 
				
			||||
        if port :
 | 
				
			||||
            _args['port'] = port
 | 
				
			||||
        _app.secret_key = str(uuid.uuid4())
 | 
				
			||||
        _app.config['PERMANENT_SESSION_LIFETIME'] = datetime.timedelta(hours=24)
 | 
				
			||||
        _app.run(**_args)
 | 
				
			||||
        _status = 'found'
 | 
				
			||||
    else:
 | 
				
			||||
        _status = 'not found'
 | 
				
			||||
    print(f'''
 | 
				
			||||
            manifest: {path}
 | 
				
			||||
            status  : {_status}
 | 
				
			||||
        ''')
 | 
				
			||||
@cli.command(name='help')
 | 
				
			||||
def _help() :
 | 
				
			||||
    pass
 | 
				
			||||
if __name__ == '__main__' :
 | 
				
			||||
    cli()
 | 
				
			||||
@ -0,0 +1 @@
 | 
				
			||||
.main { font-size:14px; font-weight: lighter;}
 | 
				
			||||
@ -0,0 +1,17 @@
 | 
				
			||||
.content {
 | 
				
			||||
    min-height:85vh;
 | 
				
			||||
    line-height: 1.5;
 | 
				
			||||
    font-weight:lighter;
 | 
				
			||||
    font-family: sans-serif;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
.main .header {
 | 
				
			||||
    display:grid;
 | 
				
			||||
    grid-template-columns: 64px auto; gap:4px;
 | 
				
			||||
}
 | 
				
			||||
.main .header .title {font-weight:bold; font-size:24px; text-transform: capitalize;}
 | 
				
			||||
.main .header .subtitle {font-size:14px; text-transform: capitalize;}
 | 
				
			||||
.main .header img {height:64px; width:64px}
 | 
				
			||||
.main .menu {display:none}
 | 
				
			||||
 | 
				
			||||
.pane {width:50%; height:100px; background-color: pink;}
 | 
				
			||||
| 
		 After Width: | Height: | Size: 1.9 MiB  | 
| 
		 After Width: | Height: | Size: 2.5 MiB  | 
| 
		 After Width: | Height: | Size: 3.3 MiB  | 
| 
		 After Width: | Height: | Size: 1.6 MiB  | 
| 
		 After Width: | Height: | Size: 786 KiB  | 
| 
		 After Width: | Height: | Size: 1.7 MiB  | 
| 
		 Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB  | 
| 
		 Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB  | 
| 
		 After Width: | Height: | Size: 116 KiB  | 
| 
		 After Width: | Height: | Size: 396 KiB  | 
| 
		 After Width: | Height: | Size: 187 KiB  | 
@ -0,0 +1,31 @@
 | 
				
			||||
var dialog = {}
 | 
				
			||||
dialog.context = ''
 | 
				
			||||
dialog.show = function(_title,_internalURI,_message,_pointer){
 | 
				
			||||
   var http = HttpClient.instance()
 | 
				
			||||
//    http.setData({title:_title,html:_message},'application/json')
 | 
				
			||||
   var uri = dialog.context+'/dialog'
 | 
				
			||||
   http.setHeader('dom',_title)
 | 
				
			||||
   http.setHeader('uri',_internalURI)
 | 
				
			||||
   http.get(uri,function(x){
 | 
				
			||||
      $('.jxmodal').remove()
 | 
				
			||||
       jx.modal.show({html:x.responseText,id:'body'})
 | 
				
			||||
       if(jx.dom.exists('dialog-message') && _message != null){
 | 
				
			||||
          jx.dom.set.value('dialog-message',_message)
 | 
				
			||||
         
 | 
				
			||||
       }
 | 
				
			||||
      //
 | 
				
			||||
      // In order to perhaps execute any js script that should have been executed on load ...
 | 
				
			||||
      //
 | 
				
			||||
      
 | 
				
			||||
      var scripts = $('.jxmodal script')
 | 
				
			||||
      jx.utils.patterns.visitor(scripts,function(_item){
 | 
				
			||||
         if(_item.text.trim().length > 0){
 | 
				
			||||
            var _routine = eval(_item.text)
 | 
				
			||||
            //
 | 
				
			||||
            //@TODO:
 | 
				
			||||
            // Find a way to add the running function into the page to enable scripts to work
 | 
				
			||||
            //
 | 
				
			||||
         }
 | 
				
			||||
      })
 | 
				
			||||
   })
 | 
				
			||||
}
 | 
				
			||||