refactored, new features with nextcloud

master
Steve Nyemba 11 months ago
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…
Cancel
Save