mirror of http://localhost:9400/cloud/cms
parent
8bfa773195
commit
d450779557
@ -0,0 +1,112 @@
|
|||||||
|
"""
|
||||||
|
Reads from nextcloud
|
||||||
|
"""
|
||||||
|
|
||||||
|
import nextcloud_client as nc
|
||||||
|
import copy
|
||||||
|
from mistune import markdown
|
||||||
|
|
||||||
|
|
||||||
|
_CLOUDHANDLER = None
|
||||||
|
def _format_root_folder (_root):
|
||||||
|
if _root[0] == '/' :
|
||||||
|
_root = _root[1:]
|
||||||
|
if _root[-1] == '/' :
|
||||||
|
_root = _root[:-1]
|
||||||
|
return _root
|
||||||
|
def content(_args):
|
||||||
|
"""
|
||||||
|
:url
|
||||||
|
:uid
|
||||||
|
:token
|
||||||
|
:folder
|
||||||
|
"""
|
||||||
|
global _CLOUDHANDLER
|
||||||
|
_handler = nc.Client(_args['url'])
|
||||||
|
_handler.login(_args['uid'],_args['token'])
|
||||||
|
_CLOUDHANDLER = _handler
|
||||||
|
_files = _handler.list(_args['folder'],10)
|
||||||
|
_root = _args['folder']
|
||||||
|
if _root.startswith('/') :
|
||||||
|
_root = _root[1:]
|
||||||
|
if _root.endswith('/') :
|
||||||
|
_root = _root[:-1]
|
||||||
|
_menu = {} #[_args['folder']] + [_item for _item in _files if _item.file_type == 'dir' and _item.name[0] not in ['.','_']]
|
||||||
|
_menu = {} #dict.fromkeys(_menu,[])
|
||||||
|
for _item in _files :
|
||||||
|
_folder = _item.path.split(_item.name)[0].strip()
|
||||||
|
_folder = _folder.replace(_root,'').replace('/','')
|
||||||
|
|
||||||
|
if _item.name[0] in ['.','_'] or _folder == '':
|
||||||
|
continue ;
|
||||||
|
|
||||||
|
if _item.file_type == 'file' and _item.get_content_type() in ['text/markdown','text/html'] :
|
||||||
|
# _folder = _item.path.split(_item.name)[0].strip()
|
||||||
|
# _folder = _folder.replace(_root,'').replace('//','')
|
||||||
|
if _folder == '' :
|
||||||
|
_folder = str(_root)
|
||||||
|
_folder = _folder.replace('/' ,' ').strip()
|
||||||
|
if _folder not in _menu :
|
||||||
|
_menu [_folder] = []
|
||||||
|
# print ([_item.name,_key, _key in _menu])
|
||||||
|
|
||||||
|
# _menuItem = _ref[_key]
|
||||||
|
# uri = '/'.join([_args['url'],_item.path])
|
||||||
|
# uri = _item
|
||||||
|
# print ([_menuItem, _menuItem in _menu])
|
||||||
|
uri = '/'.join(_item.path.split('/')[2:])
|
||||||
|
_menu[_folder].append({'text':_item.name.split('.')[0],'uri':uri})
|
||||||
|
#
|
||||||
|
# clean up the content ...
|
||||||
|
_keys = [_name for _name in _menu.keys() if _name.startswith('_')]
|
||||||
|
[_menu.pop(_name) for _name in _keys]
|
||||||
|
return _menu
|
||||||
|
|
||||||
|
|
||||||
|
def build(_config):
|
||||||
|
"""
|
||||||
|
The function will build a menu based on a folder structure in nextcloud
|
||||||
|
:_args authentication arguments for nextcloud
|
||||||
|
:_config configuration for the cms
|
||||||
|
"""
|
||||||
|
_args = copy.deepcopy(_config['system']['source']['auth'])
|
||||||
|
_args['folder'] = _config['layout']['root']
|
||||||
|
# update(_config)
|
||||||
|
return content(_args)
|
||||||
|
def html (uri,_config) :
|
||||||
|
global _CLOUDHANDLER
|
||||||
|
_handler = _CLOUDHANDLER
|
||||||
|
_root = _format_root_folder(_config['layout']['root'])
|
||||||
|
uri = _format_root_folder (uri)
|
||||||
|
|
||||||
|
|
||||||
|
_prefix = '/'.join (uri.split('/')[:-1])
|
||||||
|
_link = '/'.join(['{{context}}api/cloud/download?doc='+_prefix,'.attachments.'])
|
||||||
|
# _link = '/'.join(['api/cloud/download?doc='+_prefix,'_images'])
|
||||||
|
_html = _handler.get_file_contents(uri).decode('utf-8').replace('.attachments.',_link)
|
||||||
|
# print ([uri,uri[-2:] ,uri[-2:] in ['md','MD','markdown']])
|
||||||
|
return markdown(_html) if uri[-2:] in ['md','MD','Md','mD'] else _html.replace(_root,('{{context}}api/cloud/download?doc='+_root))
|
||||||
|
# def update (_config):
|
||||||
|
# """
|
||||||
|
# This function updates the configuration provided by loading default plugins
|
||||||
|
# """
|
||||||
|
# if 'plugins' not in _config :
|
||||||
|
# _config['plugins'] = {}
|
||||||
|
# _config['plugins'] = plugins ()
|
||||||
|
# return _config
|
||||||
|
def download(**_args):
|
||||||
|
_handler = _CLOUDHANDLER
|
||||||
|
|
||||||
|
if _args['doc'][-2:] in ['md','ht']:
|
||||||
|
_stream = html(_args['doc'],_args['config'])
|
||||||
|
else:
|
||||||
|
_stream = _handler.get_file_contents(_args['doc'])
|
||||||
|
|
||||||
|
return _stream
|
||||||
|
pass
|
||||||
|
|
||||||
|
def plugins ():
|
||||||
|
"""
|
||||||
|
This function publishes the plugins associated with this module
|
||||||
|
"""
|
||||||
|
return {'api/cloud/download':download}
|
@ -0,0 +1,40 @@
|
|||||||
|
"""
|
||||||
|
This file pulls the content from the disk
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
def folders (_path):
|
||||||
|
"""
|
||||||
|
This function reads the content of a folder (no depth, it must be simple)
|
||||||
|
"""
|
||||||
|
_content = os.listdir(_path)
|
||||||
|
return [_name for _name in _content if os.path.isdir(os.sep.join([_path,_name])) if not _name.startswith('_')]
|
||||||
|
|
||||||
|
def content(_folder):
|
||||||
|
"""
|
||||||
|
:content of the folder
|
||||||
|
"""
|
||||||
|
|
||||||
|
if os.path.exists(_folder) :
|
||||||
|
_menuItems = os.listdir(_folder)
|
||||||
|
# return [{'text':_name.split('.')[0].replace('_', ' ').replace('-',' ').strip(),'uri': os.sep.join([_folder,_name])} for _name in os.listdir(_folder) if not _name.startswith('_') and os.path.isfile( os.sep.join([_folder,_name]))]
|
||||||
|
return [{'text':_name.split('.')[0].replace('_', ' ').replace('-',' ').strip(),'uri': os.sep.join([_folder,_name])} for _name in os.listdir(_folder) if not _name.startswith('_') and os.path.isfile( os.sep.join([_folder,_name]))]
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
def build (_config): #(_path,_content):
|
||||||
|
"""
|
||||||
|
building the menu for the site given the content is on disk
|
||||||
|
:path path of the files on disk
|
||||||
|
:config configuration associated with the
|
||||||
|
"""
|
||||||
|
_path = _config['layout']['root']
|
||||||
|
_items = folders(_path)
|
||||||
|
_subItems = [ content (os.sep.join([_path,_name]))for _name in _items ]
|
||||||
|
# return dict(zip())
|
||||||
|
return dict.fromkeys(_items,_subItems)
|
||||||
|
|
||||||
|
def html(uri) :
|
||||||
|
_html = (open(uri)).read()
|
||||||
|
return _html
|
||||||
|
def plugins ():
|
||||||
|
return {}
|
||||||
|
|
@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
These are a few default plugins that will be exported and made available to the calling code
|
||||||
|
The purpose of plugins is to perform data processing
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def copyright (_args) :
|
||||||
|
return {"author":"Steve L. Nyemba","email":"steve@the-phi.com","organization":"The Phi Technology","license":"MIT", "site":"https://dev.the-phi.com/git/cloud/qcms"}
|
||||||
|
|
||||||
|
def log (_args):
|
||||||
|
"""
|
||||||
|
perform logging against duckdb
|
||||||
|
"""
|
||||||
|
pass
|
@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* This is the default window and we will have to hide the pane (side)
|
||||||
|
*/
|
||||||
|
|
||||||
|
body .pane { display:none}
|
@ -0,0 +1,90 @@
|
|||||||
|
.main {
|
||||||
|
margin:10px;
|
||||||
|
padding:4px;
|
||||||
|
display:grid;
|
||||||
|
grid-template-columns: 50% 50% ; gap:4px;
|
||||||
|
grid-template-rows: 48px 48px auto 32px;
|
||||||
|
font-family: helvetica;
|
||||||
|
font-weight: lighter;
|
||||||
|
font-size:18px;
|
||||||
|
line-height: 1.5;
|
||||||
|
justify-items: normal;
|
||||||
|
;
|
||||||
|
}
|
||||||
|
.main .header {
|
||||||
|
height:48px;
|
||||||
|
grid-row:1;
|
||||||
|
grid-column: 1 / span 2;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .header img { width:40px; margin:4px;}
|
||||||
|
.main .menu { grid-row:2; grid-column: 1 / span 2; background-color: #f3f3f3; }
|
||||||
|
.main .content {
|
||||||
|
grid-row:3;
|
||||||
|
grid-column: 1 ;
|
||||||
|
text-wrap: wrap;
|
||||||
|
height:100%;
|
||||||
|
display:grid;
|
||||||
|
align-content: start;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
.main .content #index {
|
||||||
|
text-align: left;
|
||||||
|
text-wrap: wrap;
|
||||||
|
}
|
||||||
|
/* .main .content #index{
|
||||||
|
text-align:left;
|
||||||
|
align-content:normal;
|
||||||
|
display:grid;
|
||||||
|
background-color: green;
|
||||||
|
} */
|
||||||
|
|
||||||
|
.main .pane {
|
||||||
|
border-left:3px dotted gray;
|
||||||
|
grid-column: 2;
|
||||||
|
font-family: sans-serif;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
.pane iframe {
|
||||||
|
border:1px solid transparent;
|
||||||
|
width:99%;
|
||||||
|
height:100%;
|
||||||
|
|
||||||
|
}
|
||||||
|
.main .footer {grid-row:4; grid-column: 1 / span 2; font-size:13px; font-weight: lighter;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* styling tables here
|
||||||
|
*/
|
||||||
|
p {
|
||||||
|
margin-top:22px;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
width:99%;
|
||||||
|
border: 1px solid #CAD5E0;
|
||||||
|
}
|
||||||
|
table td {padding:4px; margin:4px;}
|
||||||
|
table thead {
|
||||||
|
|
||||||
|
font-weight:bold;
|
||||||
|
background-color:#f3f3f3;
|
||||||
|
}
|
||||||
|
/* table tbody tr:hover {
|
||||||
|
background-color: #4682B4;
|
||||||
|
color:white ;
|
||||||
|
cursor:pointer;
|
||||||
|
} */
|
||||||
|
|
||||||
|
#gallery img {
|
||||||
|
justify-content: left;
|
||||||
|
width:70px;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#gallery table {width:100%;}
|
Loading…
Reference in new issue