cli functions, bug fixes with login

pull/52/head
Steve Nyemba 4 days ago
parent 81a72b882a
commit bc84ad79d5

@ -19,6 +19,7 @@ import base64
import io import io
import cms import cms
from cms import index from cms import index
import cms.cli
from cms.engine.config.structure import Layout, System from cms.engine.config.structure import Layout, System
from cms.engine import project, themes from cms.engine import project, themes
@ -142,8 +143,7 @@ def set_cloud(manifest:Annotated[str,typer.Argument(help="path of the auth-file
else: else:
_msg = INVALID_FOLDER _msg = INVALID_FOLDER
print (_msg) print (_msg)
@cli.command(name='secure') @cli.command(name='set-key')
# def set_key(path):
def secure( def secure(
manifest:Annotated[str,typer.Argument(help="path of the manifest file")], manifest:Annotated[str,typer.Argument(help="path of the manifest file")],
keyfile:Annotated[str,typer.Argument(help="path of the key file to generate")]): keyfile:Annotated[str,typer.Argument(help="path of the key file to generate")]):
@ -202,77 +202,77 @@ def load(**_args):
return getattr(module,_name) if hasattr(module,_name) else None return getattr(module,_name) if hasattr(module,_name) else None
@cli.command(name='plugins') # @cli.command(name='plugins')
def plugin_manager (manifest:Annotated[str,typer.Argument(help="path to manifest file")], # def plugin_manager (manifest:Annotated[str,typer.Argument(help="path to manifest file")],
show:bool=typer.Option(default=False,help="list plugins loaded"), # show:bool=typer.Option(default=False,help="list plugins loaded"),
add: Annotated[Optional[bool],typer.Option("--register/--unregister",help="add/remove a plugin to manifest use with --pointer option")] = None, # add: Annotated[Optional[bool],typer.Option("--register/--unregister",help="add/remove a plugin to manifest use with --pointer option")] = None,
pointer:str=typer.Option(default=None,help="pointer is structured as 'filename.function'") # pointer:str=typer.Option(default=None,help="pointer is structured as 'filename.function'")
) : # ) :
""" # """
Manage plugins list loaded plugins, # Manage plugins list loaded plugins,
""" # """
manifest = get_manifest(manifest) # manifest = get_manifest(manifest)
_config = cms.engine.config.get(manifest) # _config = cms.engine.config.get(manifest)
if _config : # if _config :
_root = os.sep.join(manifest.split(os.sep)[:-1] + [_config['layout']['root'],'_plugins']) # _root = os.sep.join(manifest.split(os.sep)[:-1] + [_config['layout']['root'],'_plugins'])
else : # else :
_root = None # _root = None
if _root and os.path.exists(_root) : # if _root and os.path.exists(_root) :
# files = os.listdir(_root) # # files = os.listdir(_root)
_msg = f"""{FAILED} no operation was specified, please use --help option""" # _msg = f"""{FAILED} no operation was specified, please use --help option"""
# if 'plugins' in _config : # # if 'plugins' in _config :
_plugins = _config['plugins'] if 'plugins' in _config else {} # _plugins = _config['plugins'] if 'plugins' in _config else {}
if show : # if show :
if not _plugins : # if not _plugins :
_msg = f"""{FAILED} no plugins are loaded\n\t{manifest}""" # _msg = f"""{FAILED} no plugins are loaded\n\t{manifest}"""
else: # else:
_data = [] # _data = []
_plugConf = _config['plugins'] # _plugConf = _config['plugins']
for _name in _plugConf : # for _name in _plugConf :
_log = {"files":_name,"loaded":len(_plugConf[_name]),"functions":json.dumps(_plugConf[_name])} # _log = {"files":_name,"loaded":len(_plugConf[_name]),"functions":json.dumps(_plugConf[_name])}
_data.append(_log) # _data.append(_log)
_data= pd.DataFrame(_data) # _data= pd.DataFrame(_data)
# # # _data = plugins.stats(_plugins) # # # # _data = plugins.stats(_plugins)
# # _data = cms.Plugin.stats(_plugins) # # # _data = cms.Plugin.stats(_plugins)
print (to_Table(_data)) # print (to_Table(_data))
_msg = f"""{PASSED} [bold]{_config['layout']['header']['title']}[/bold]: found a total of {_data.loaded.sum()} plugins loaded from {_data.shape[0]} file(s)\n\t{_root}""" # _msg = f"""{PASSED} [bold]{_config['layout']['header']['title']}[/bold]: found a total of {_data.loaded.sum()} plugins loaded from {_data.shape[0]} file(s)\n\t{_root}"""
if add in [True,False] and pointer : # if add in [True,False] and pointer :
file,fnName = pointer.split('.') # file,fnName = pointer.split('.')
# _fnpointer = plugins.load(_root,file+'.py',fnName) # # _fnpointer = plugins.load(_root,file+'.py',fnName)
# _fnpointer = cms.Plugin.load(_root,file+'.py',fnName) # # _fnpointer = cms.Plugin.load(_root,file+'.py',fnName)
_ploader = plugin_ix.Loader(file = os.sep.join([_root,file+'.py'])) # _ploader = plugin_ix.Loader(file = os.sep.join([_root,file+'.py']))
if add and _ploader.has(fnName): # if add and _ploader.has(fnName):
if file not in _plugins : # if file not in _plugins :
_plugins[file] = [] # _plugins[file] = []
if fnName not in _plugins[file] : # if fnName not in _plugins[file] :
_plugins[file].append(fnName) # _plugins[file].append(fnName)
_msg = f"""{PASSED} [bold]{_config['layout']['header']['title']}[/bold]: registered {pointer}, use the --show option to list loaded plugins""" # _msg = f"""{PASSED} [bold]{_config['layout']['header']['title']}[/bold]: registered {pointer}, use the --show option to list loaded plugins"""
else: # else:
_msg = f"""{FAILED} [bold]{_config['layout']['header']['title']}[/bold]: could not register {pointer}, it already exists""" # _msg = f"""{FAILED} [bold]{_config['layout']['header']['title']}[/bold]: could not register {pointer}, it already exists"""
elif add is False and file in _plugins: # elif add is False and file in _plugins:
_plugins[file] = [_name.strip() for _name in _plugins[file] if _name.strip() != fnName.strip() ] # _plugins[file] = [_name.strip() for _name in _plugins[file] if _name.strip() != fnName.strip() ]
_msg = f"""{PASSED} [bold]{_config['layout']['header']['title']}[/bold]: unregistered {pointer}, use the --show option to list loaded plugins """ # _msg = f"""{PASSED} [bold]{_config['layout']['header']['title']}[/bold]: unregistered {pointer}, use the --show option to list loaded plugins """
# # # # #
# # We need to write this down !! # # # We need to write this down !!
if add in [True,False] : # if add in [True,False] :
_config['plugins'] = _plugins # _config['plugins'] = _plugins
cms.engine.config.write(_config,manifest) # cms.engine.config.write(_config,manifest)
# else: # # else:
# _msg = f"""{FAILED} [bold]{_config['layout']['header']['title']}[/bold]: no plugins are loaded """ # # _msg = f"""{FAILED} [bold]{_config['layout']['header']['title']}[/bold]: no plugins are loaded """
print() # print()
print(_msg) # print(_msg)
else: # else:
_msg = f"""{FAILED} No plugin folder could be found in {manifest}""" # _msg = f"""{FAILED} No plugin folder could be found in {manifest}"""
print (_msg) # print (_msg)
@cli.command (name='create') @cli.command (name='create')
@ -501,4 +501,6 @@ def handle_theme (
global SYS_ARGS global SYS_ARGS
if __name__ == '__main__': if __name__ == '__main__':
cli.add_typer(cli_theme,name="themes",help="manage themes associated with a site") cli.add_typer(cli_theme,name="themes",help="manage themes associated with a site")
cli.add_typer(cms.cli.auth.cli,name="login",help="manage login (authentication/authorization) to a sites")
cli.add_typer(cms.cli.plugins.cli,name="plugins",help="manage plugins associated with a site")
cli() cli()

@ -10,6 +10,14 @@ from . import sites
from . import apexchart from . import apexchart
from . import meta from . import meta
from . import secure from . import secure
# def get_manifest (manifest):
# if not manifest.endswith('json') and os.path.isdir(manifest):
# manifest = manifest if not manifest.endswith(os.sep) else os.sep.join(manifest.split(os.sep)[:-1])
# return os.sep.join([manifest,'qcms-manifest.json'])
# else:
# return manifest
class Plugin : class Plugin :
# #
# decorator for plugin functions, this is a preliminary to enable future developement # decorator for plugin functions, this is a preliminary to enable future developement
@ -87,8 +95,7 @@ class Plugin :
#
# default plugins to load into the configuration file
@Plugin(mimetype="application/json") @Plugin(mimetype="application/json")
def authorizationURL (**_args): def authorizationURL (**_args):
# _config = _args['config'] # _config = _args['config']
@ -144,4 +151,4 @@ def oauthFinalize (**_args):
<div style="font-size:13px">Please wait ...</div> <div style="font-size:13px">Please wait ...</div>
</div> </div>
""" """
return _html return _html

@ -0,0 +1 @@
from . import plugins, secure, auth

@ -0,0 +1,85 @@
import typer
from typing_extensions import Annotated
from typing import Optional
from typing import Tuple
import os
import json
import plugin_ix as px
from enum import Enum
import pandas as pd
from rich.table import Table
from rich import print
import uuid
import cms
import requests
FAILED = '[ [red] \u2717 [/red] ]'
PASSED = '[ [green] \u2713 [/green] ]'
cli = typer.Typer()
@cli.command(name="set")
def set_auth (
id:Annotated[str,typer.Argument(help="identifier used in setting cookies")],
manifest:Annotated[str,typer.Argument(help="path manifest or site folder")],
registry:Annotated[str,typer.Argument(help="path to the registry created by plugin-ix")],
authpath:Annotated[str,typer.Argument(help="Authentication file location, that contains the authentication model")]
):
"""
This function will set login configuration to a manifest
"""
try:
_args = {"id":id,"registry":registry,"path":authpath,"authorization":{}}
path = cms.engine.config.get_manifest(manifest=manifest)
_config = cms.engine.config.get(path)
_config['system']['source'] = {'secure':_args}
_secEngine = cms.secure.Manager(config=_config)
cms.engine.config.write(config=_config,path=path)
except Exception as e:
print (f"""{FAILED} [bold][red]{id}, failed [/red][/bold], error found {str(e)}""")
#
# we should try to test this configuration to see if it works
#
pass
def permissions():
pass
def inspect ():
pass
@cli.command("drop")
def remove (manifest:Annotated[str,typer.Argument(help="path manifest or site folder")]):
"""
This function removes login configuration from a manifest
"""
path = cms.engine.config.get_manifest(manifest=manifest)
_config = cms.engine.config.get(path)
_msg = f'{FAILED}'
try:
if 'secure' in _config['system']['source'] :
del _config['system']['source']['secure']
cms.engine.config.write(config=_config,path=path)
_msg = f'{PASSED} [green]Successfully[/green] removed secure attribute'
except Exception as e:
_msg = f'{_msg}, error found {str(e)}'
print (_msg)
pass
@cli.command(name="template")
def gen_auth (
_model:Annotated[str,typer.Argument(help="generate an authentication parameter file")],
):
"""
This function generates a template login file content for a model (pam, oauth2, nextcloud)
"""
_conf = {"method":_model}
_map = {"pam":{"age":3600},"nextcloud":{"url":"https://your-nextcloud-site"}}
#
# parameters client_id, client-secret,
_map["oauth2"] = {"client_id":"client_id","client_secret":"client_secret","scope":"profile","response_type":"code","authorization_url":"authorization_url","redirect_uri":"redirect_uri"}
if _model in _map :
_conf = dict(_conf, **_map.get(_model))
print (_conf)
print ()
print(f'{PASSED} [bold] Edit[/bold] and [bold]save[/bold] the content into an [bold]"authentication file"[/bold]')
else:
print (f"""{FAILED} [bold]{_model}[/bold] is not a supported authentication model""")

@ -0,0 +1,207 @@
import typer
from typing_extensions import Annotated
from typing import Optional
from typing import Tuple
import os
import json
import plugin_ix as px
from enum import Enum
import pandas as pd
from rich.table import Table
from rich import print
import cms
FAILED = '[ [red] \u2717 [/red] ]'
PASSED = '[ [green] \u2713 [/green] ]'
"""
Handling cli interface for plugins, performing add list and remove
"""
cli = typer.Typer()
def to_Table(df: pd.DataFrame):
"""Displays a Pandas DataFrame as a rich table."""
table = Table(show_header=True, header_style="bold magenta")
for col in df.columns:
table.add_column(col)
for _, row in df.iterrows():
table.add_row(*row.astype(str).tolist())
# console.print(table)
return table
# def cms.get_manifest (manifest):
# if not manifest.endswith('json') and os.path.isdir(manifest):
# manifest = manifest if not manifest.endswith(os.sep) else os.sep.join(manifest.split(os.sep)[:-1])
# path = os.sep.join([manifest,'qcms-manifest.json'])
# else:
# path = manifest
# return path
# def get_config(path,key=None):
# f = open(path)
# _config = json.loads(f.read())
# f.close()
# return _config[key] if key and key in _config else _config
def format(file,_content):
return [{'file':file.replace('.py',''),'uri':f'api/{file.replace(".py","")}/{_name}','endpoint':_name} for _name in _content]
def get (manifest:Annotated[str,typer.Argument(help="project folder or manifest file")],):
"""
List the plugins in the from a project folder (from the manifest)
"""
path = cms.engine.config.get_manifest(manifest=manifest) #
_config = cms.engine.config.get(path) #get_config(path)
_root = _config['layout']['root']
#
# remove the manifest file to pull the plugins folder
folder = os.sep.join([path.replace('qcms-manifest.json','')[:-1],f'{_root}/_plugins'])
loader = px.Loader ()
_api = []
for _name in os.listdir(folder):
_file = os.sep.join([folder,_name])
try:
loader.load(file=_file)
_api+= format(_name,loader.names())
# _ondisk[_name] = loader.names()
except Exception as e:
#
# If the file has an error, it will be skipped
print (e)
break
#
# at this point we know what we have on disk, we should be able to make a report/dashboard of sorts
pass
# On disk
# files = os.listdir(folder)
#
_online = []
_plugins = _config['plugins']
for _name in _plugins :
_online += format(_name, _plugins[_name])
return _api,_online
class StatusFilter(str,Enum):
online="online"
offline="offline"
@cli.command(name="status")
def status(manifest:Annotated[str,typer.Argument(help="project folder or manifest file")],
filter : StatusFilter = None
):
"""
This function will provide the status of all available plugins
"""
_avail,_depl = get(manifest)
_avail = pd.DataFrame(_avail)# available on disk (not deployed)
_depl = pd.DataFrame(_depl) # deployed
files = _avail.file.unique().tolist()+ _depl.file.unique().tolist()
_df = pd.DataFrame()
for _name in files :
_xe = _avail[_avail.file == _name].endpoint.tolist()
_ye = _depl[_depl.file == _name].endpoint.tolist()
_online = list(set(_xe) & set(_ye))
_offline = list(set(_xe) - set(_ye))
_data = pd.DataFrame()
_data['api'] = _offline + _online
_data['file'] = _name
_data['status'] = (['[red]offline[/red]']* len(_offline)) + (['[green]online[/green]']* len(_online))
# _data['deployed'] = _online
_data = _data[['file','api','status']]
_df = pd.concat([_df, _data])
# _df.append({'file':_name,'deployed':_online,'offline':_offline})
_df['uri'] = _df.apply(lambda row: f'api/{row.file}/{row.api}',axis=1)
_df = _df[['file','uri','api','status']]
if filter :
print (f"status in ('{filter.value}')")
_df = _df[_df.status.str.contains(filter.value, case=False, regex=True)]
# _df = _df.query(f" '{filter.value}' in status")
print (to_Table(_df))
pass
@cli.command(name="register")
def add (manifest:Annotated[str,typer.Argument(help="project folder or manifest file")],
pointer:Annotated[str,typer.Argument(help="file/function or file.function with no file extension. e.g: demo/info")]
):
"""
This function will add a plugin function to the site's configuration file making it available as an API
"""
#
# Let's make sure we are adding to the configuration something that actually exists
#
_file,_name = pointer.split('/')
path = cms.engine.config.get_manifest(manifest=manifest) #
_config = cms.engine.config.get(path) #get_config(path)
_root = _config['layout']['root']
_folder = os.sep.join([path.replace('qcms-manifest.json','')[:-1],f'{_root}/_plugins'])
if f'{_file}.py' in os.listdir(_folder) :
loader = px.Loader ()
loader.load(file=f'{_folder}{os.sep}{_file}.py')
if loader.has(_name) :
#
# adding to plugins
_plugins = _config['plugins']
if _file not in _plugins :
_plugins[_file] = []
if _name not in _plugins[_file] :
_plugins[_file].append (_name)
_config['plugins'] = _plugins
cms.engine.config.write(config=_config,path=path)
_msg = f"{PASSED} [bold]{pointer}[/bold] successfully added to {manifest}\nAPI endpoint [bold]api/{_file}/{_name}[/bold]"
else:
_msg = f"{FAILED} [bold]{pointer}[/bold] [red]already exists[/red] in configuration"
else:
#
# failure at this point, asking for a function in a file that doesn't exist
_msg = f"[bold]{pointer}[/bold] [red]{_name} missing[/red] in {_folder}{os.sep}{_file}.py"
pass
else:
#
# throw/raise an exception
_msg = f"{FAILED} [bold]{pointer}[/bold] [red]NOT found[/red] in {_folder}"
print (_msg)
pass
@cli.command(name="unregister")
def remove(manifest:Annotated[str,typer.Argument(help="project folder or manifest file")],
pointer:Annotated[str,typer.Argument(help="file/function or file.function with no file extension. e.g: demo/info")]
):
"""
This function will remove an api from the configuration of a project and won't be available via http/https
"""
_file,_name = pointer.split('/')
path = cms.engine.config.get_manifest(manifest=manifest) #
_config = cms.engine.config.get(path) #get_config(path)
_root = _config['layout']['root']
_plugins = _config.get('plugins',{})
if _file in _plugins :
_plugins[_file] = [_fname for _fname in _plugins[_file] if _fname != _name]
_config['plugins'] = _plugins
_msg = f"{PASSED} [bold]{pointer}[/bold] was [green]successfully[/green] removed from {path}"
else:
_msg = f"{FAILED} [bold]{pointer}[/bold] was [red]NOT found[/red] in {path}"
print (_msg)
cms.engine.config.write(_config,path)
#
#
# def post(config,path):
# f = open(path,'w')
# f.write(json.dumps(config,indent=4))
# f.close()

@ -0,0 +1,88 @@
"""
This file will handle security aspects associated with QCMS
"""
import typer
from typing_extensions import Annotated
from typing import Optional
from typing import Tuple
import os
import json
import plugin_ix as px
from enum import Enum
import pandas as pd
from rich.table import Table
from rich import print
import uuid
import cms
import requests
FAILED = '[ [red] \u2717 [/red] ]'
PASSED = '[ [green] \u2713 [/green] ]'
cli = typer.Typer()
@cli.command(name="set-key")
def set_key (manifest:Annotated[str,typer.Argument(help="path to manifest or manifest folder")],
keyfile:Annotated[str,typer.Argument(help="path of the key file to generate")]
):
"""
force-reload of an application
"""
keyfile = cms.engine.config.get_manifest(keyfile)
if not os.path.exists(keyfile):
f = open(keyfile,'w')
f.write(str(uuid.uuid4()))
f.close()
#
manifest = cms.engine.config.get_manifest(manifest)
_config = cms.engine.config.get(manifest)
if 'source' not in _config['system']:
_config['system']['source'] = {'id':'disk'}
_config['system']['source']['key'] = os.path.abspath(keyfile)
cms.engine.config.write(_config,manifest)
_msg = f"""{PASSED} [bold]{_config['layout']['header']['title']}[/bold] : A key was generated and written to {keyfile}
use this key in header to enable reload of the site ...
"""
else:
_msg = f"""{FAILED} [bold]{_config['system']['layout']['header']['title']}[/bold] : could [bold]NOT[/bold] generate a key, because it would seem you already have one
Please manually delete {keyfile}
"""
print (_msg)
@cli.command (name='reload')
def reload (
path:Annotated[str,typer.Argument(help="")],
port:int=typer.Option(default=None,help="port of the host to call")
) :
"""
Reload a site/portal given the manifest ...
"""
path = cms.engine.config.get_manifest(path)
_config = cms.engine.config.get( path)
if 'source' in _config['system'] and 'key' in _config['system']['source'] :
_spath = _config['system']['source']['key']
# f = open(_config['system']['source']['key'])
if not os.path.exists(_spath) :
mpath = path.split(os.sep)[:-1] + _spath.split(os.sep)
_spath = os.sep.join(mpath)
pass
f = open(_spath)
key = f.read()
f.close()
_port = port if port else _config['system']['app']['port']
url = f"http://localhost:{_port}/reload"
resp = requests.post(url, headers={"key":key})
if resp.status_code == 200 :
_msg = f"""{PASSED} [bold]{_config['layout']['header']['title']}[/bold] : successfully reloaded {url}"""
else:
_msg = f"""{FAILED} failed to reload, status code {resp.status_code}\n{url}
"""
else:
_msg = f"""{FAILED} no secure key found in manifest to request reload"""
print (_msg)

@ -5,6 +5,8 @@ import os
import json import json
def get (path) : def get (path) :
#
# Opens the manifest file and returns the configuration
if os.path.exists(path) : if os.path.exists(path) :
f = open(path) f = open(path)
_conf = json.loads(f.read()) _conf = json.loads(f.read())
@ -12,6 +14,15 @@ def get (path) :
else: else:
_conf = {} _conf = {}
return _conf return _conf
def get_manifest(manifest):
#
# returns the manifest file (absolute path) for a site
if not manifest.endswith('json') and os.path.isdir(manifest):
manifest = manifest if not manifest.endswith(os.sep) else os.sep.join(manifest.split(os.sep)[:-1])
return os.sep.join([manifest,'qcms-manifest.json'])
else:
return manifest
def _isvalid(_allowed,**_args): def _isvalid(_allowed,**_args):
if not list(set(_allowed) - set(_args.keys())) : if not list(set(_allowed) - set(_args.keys())) :
@ -21,8 +32,8 @@ def _isvalid(_allowed,**_args):
return _pargs return _pargs
return False return False
def write(_config, path): def write(config, path):
f = open(path,'w') f = open(path,'w')
f.write( json.dumps(_config,indent=2)) ; f.write( json.dumps(config,indent=4)) ;
f.close() f.close()

@ -60,12 +60,11 @@ import cms
# register this in config.plugins: {"demo":["info"]} # register this in config.plugins: {"demo":["info"]}
@cms.plugins(mimetype='application/json') : @cms.Plugin(mimetype='application/json',methods=['POST','GET'])
def info (**_args): def info (**_args):
_request= _args['request'] _request= _args['request']
_config = _args['config'] _config = _args['config']
return {"version":_config['system']['version'],'title':_config['layout']['header']['title']} return {"version":_config['system']['version'],'title':_config['layout']['header']['title']}
pass
""" """
loc = os.sep.join([_path,_root,'_plugins','demo.py']) loc = os.sep.join([_path,_root,'_plugins','demo.py'])
f = open(loc,'w') f = open(loc,'w')
@ -137,6 +136,9 @@ def _index (_path,root):
</div> </div>
</div> </div>
<p> <p>
<div>
Add custom python functions and provide access as <b>api</b>
</div>
<div align="center">Learn more about <b>QCMS</b> and at {themes.URL}</div> <div align="center">Learn more about <b>QCMS</b> and at {themes.URL}</div>
</p> </p>
""" """

@ -63,9 +63,10 @@ class Manager :
# we will assume that all authenticated users have access to every part of the site # we will assume that all authenticated users have access to every part of the site
# #
if 'authorization' in _kwargs: if 'authorization' in _kwargs:
# # #
# loading permissions table from a designated location # # loading permissions table from a designated location
reader = transport.get.reader(**_kwargs['authorization']) reader = transport.get.reader(**_kwargs['authorization'])
self._permissions = reader.read() self._permissions = reader.read()
@ -77,7 +78,6 @@ class Manager :
if not path or not os.path.exists(path) : if not path or not os.path.exists(path) :
raise Exception (f'Missing {what} {path}') raise Exception (f'Missing {what} {path}')
def authenticate(self,**_args): def authenticate(self,**_args):
print (" ********* ", self._authKey)
_kwargs = copy.copy(_args) _kwargs = copy.copy(_args)
_kwargs['config'] = self._config _kwargs['config'] = self._config
# _user = self.login(**_kwargs) # _user = self.login(**_kwargs)

@ -45,43 +45,4 @@ qcms.login.cancel = function (){
}) })
$('.qcms-login-error').slideUp() $('.qcms-login-error').slideUp()
} }
/**
* PAM authentication
*/
// qcms.authenticate = {}
// qcms.authenticate.nextcloud = function (){
// var _uri = ([qcms.context,'/login']).join('')
// _args = qcms.login.get()
// var http = HttpClient.instance()
// http.setHeader('Content-Type','application/json')
// // http.setHeader('method','pam')
// http.setData( JSON.stringify(_args))
// http.post(_uri,(x)=>{
// if(x.readyState == 4 && x.status == 200){
// }
// })
// }
// qcms.authenticate.pam = function (){
// var _uri = ([qcms.context,'/login']).join('')
// var _args = {
// username:$('.qcms-login-input .username').val(),
// password:$('.qcms-login-input .password').val()
// }
// var http = HttpClient.instance()
// http.setHeader('Content-Type','application/json')
// http.setHeader('method','pam')
// http.setData( JSON.stringify(_args))
// http.post(_uri,(x)=>{
// if(x.readyState == 4 && x.status == 200){
// window.open(x.responseURL,'_self')
// ;
// }
// })
// }
Loading…
Cancel
Save