Skip to content

Commit

Permalink
More generc dialogs work, fix broken external module feature.
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Dunn committed Apr 9, 2024
1 parent 71cbdee commit f60e1a4
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 147 deletions.
33 changes: 26 additions & 7 deletions kaithem/src/dialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,52 @@


class Dialog:
"By default all inputs are disabled unless user has system_admin"

def __init__(self, title) -> None:
# List of title, inputhtml pairs
self.items: list[tuple[str, str]] = []
self.title = title

def name_to_title(self, s: str):
if "." not in s and "-" not in s:
return s.capitalize()
else:
return s

def is_disabled_by_default(self):
return not pages.canUserDoThis("system_admin")

def text(self, s: str):
self.items.append(("", f"<p>{s}</s>"))
self.items.append(("", f"<p>{s}</p>"))

def text_input(
self, name: str, *, title: str | None = None, default: str = "", disabled=False
self, name: str, *, title: str | None = None, default: str = "", disabled=None
):
title = title or name
title = title or self.name_to_title(name)

if disabled is None:
disabled = self.is_disabled_by_default()

disabled = " disabled" if disabled else ""
self.items.append(
(title, f'<input name="{name}" value="{html.escape(default)}" {disabled}"')
(title, f'<input name="{name}" value="{html.escape(default)}" {disabled}>')
)

def submit_button(
self, name: str, *, title: str | None = None, value: str = "", disabled=False
self, name: str, *, title: str | None = None, value: str = "", disabled=None
):
title = title or "submit"
if disabled is None:
disabled = self.is_disabled_by_default()

title = title or "Submit"
disabled = " disabled" if disabled else ""
self.items.append(
(title, f'<button name="{name}" type="submit" {disabled}>{title}</button>')
("", f'<button name="{name}" type="submit" {disabled}>{title}</button>')
)

def render(self, target: str, hidden_inputs: dict | None = None):
"The form will target the given URL and have all the keys and values in hidden inputs"
return pages.render_jinja_template(
"dialogs/generic.j2.html",
items=self.items,
Expand Down
2 changes: 1 addition & 1 deletion kaithem/src/html/dialogs/generic.j2.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{% block body %}
<main>
<section class="window paper w-sm-double margin">
<header>{{title}}</header>
<header><h2>{{title}}</h2></header>

<form class="stacked-form" action="{{target}}" method="POST">
{% for i in items %}
Expand Down
2 changes: 1 addition & 1 deletion kaithem/src/html/error.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%include file="/pageheader.html"/>
<h2> Error!</h2>
${e or info}
<section class="error paper">${e or info}</section>
<%include file="/pagefooter.html"/>
10 changes: 0 additions & 10 deletions kaithem/src/html/modules/delete.html

This file was deleted.

10 changes: 0 additions & 10 deletions kaithem/src/html/modules/deleteresource.html

This file was deleted.

17 changes: 0 additions & 17 deletions kaithem/src/html/modules/new.html

This file was deleted.

19 changes: 0 additions & 19 deletions kaithem/src/html/modules/permissions/new.html

This file was deleted.

22 changes: 0 additions & 22 deletions kaithem/src/html/modules/permissions/permission.html

This file was deleted.

30 changes: 9 additions & 21 deletions kaithem/src/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,9 +513,9 @@ def loadModules(modulesdir: str):
# Read ythe location we are supposed to load from
with open(os.path.join(modulesdir, i)) as f:
s = f.read(4096)
# Get rid of the __ and .location, then set the location in the dict
# Get rid of the .location, then set the location in the dict
with modulesLock:
external_module_locations[util.unurl(i[2:-9])] = s
external_module_locations[util.unurl(i[0:-9])] = s
# We use the ignore func when loading ext modules
loadModule(s, util.unurl(i[2:-9]), detect_ignorable)
except Exception:
Expand Down Expand Up @@ -556,7 +556,7 @@ def _detect_ignorable(path: str):
def reloadOneResource(module, resource):
r = modules_state.ActiveModules[module][resource]
if "resource-loadedfrom" in r:
mfolder = os.path.join(directories.moduledir, "data", module)
mfolder = getModuleDir(module)
loadOneResource(
mfolder, os.path.relpath(r["resource-loadedfrom"], mfolder), module
)
Expand Down Expand Up @@ -616,11 +616,8 @@ def loadOneResource(folder, relpath, module):
os.path.join(folder, relpath), directories.vardir
) or util.in_directory(os.path.join(folder, relpath), directories.datadir):
t = parseTarget(r["target"], module)
target = os.path.normpath(
os.path.join(
directories.vardir, "modules", "data", module, "__filedata__", t
)
)
d = getModuleDir(module)
target = os.path.normpath(os.path.join(d, "__filedata__", t))
else:
t = parseTarget(r["target"], module, True)
target = os.path.normpath(os.path.join(folder, "__filedata__", t))
Expand Down Expand Up @@ -830,17 +827,7 @@ def getModuleAsYamlZip(module, noFiles=True):

else:
if not incompleteError:
logger.error(
"Missing file(s) in module including: "
+ os.path.join(
directories.vardir,
"modules",
"data",
module,
"__filedata__",
target,
)
)
logger.error(f"Missing file(s) in module including: {target}")
incompleteError = True
z.close()
s = ram_file.getvalue()
Expand Down Expand Up @@ -1202,8 +1189,9 @@ def rmModule(module, message="deleted"):

fn = getModuleFn(module)

if os.path.exists(fn):
shutil.rmtree(fn)
if module not in external_module_locations:
if os.path.exists(fn):
shutil.rmtree(fn)

modules_state.modulesHaveChanged()
# Get rid of any garbage cycles associated with the event.
Expand Down
55 changes: 27 additions & 28 deletions kaithem/src/modules_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,12 @@ def library(self):
@cherrypy.expose
def newmodule(self):
pages.require("system_admin")
return pages.get_template("modules/new.html").render()
d = dialogs.Dialog("Add New Module")
d.text_input("name", title="Name of New Module")
d.text("Choose an existing dir to load that module.")
d.text_input("location", title="Save location(Blank: auto in kaithem dir)")
d.submit_button("Submit")
return d.render("/modules/newmoduletarget")

# @cherrypy.expose
# def manual_run(self,module, resource):
Expand All @@ -331,6 +336,10 @@ def newmodule(self):
@cherrypy.expose
def deletemodule(self):
pages.require("system_admin")
d = dialogs.Dialog("Delete Module")
d.text_input("name")
d.submit_button("Submit")
return d.render("/modules/deletemoduletarget")
return pages.get_template("modules/delete.html").render()

# POST target for CRUD screen for deleting module
Expand Down Expand Up @@ -507,9 +516,8 @@ def module(self, module, *path, **kwargs):

if path[0] == "getfileresource":
pages.require("system_admin")
folder = os.path.join(
directories.vardir, "modules", "data", module, "__filedata__"
)
d = modules.getModuleDir(module)
folder = os.path.join(d, "__filedata__")
data_basename = modules_state.fileResourceAbsPaths[module, path[1]]
dataname = os.path.join(folder, data_basename)
if os.path.isfile(dataname):
Expand Down Expand Up @@ -538,15 +546,8 @@ def module(self, module, *path, **kwargs):
if path[0] == "uploadfileresourcetarget":
pages.require("system_admin", noautoreturn=True)
pages.postOnly()

if module not in external_module_locations:
folder = os.path.join(
directories.vardir, "modules", "data", module, "__filedata__"
)
else:
folder = os.path.join(
external_module_locations[module], "__filedata__"
)
d = modules.getModuleDir(module)
folder = os.path.join(d, "__filedata__")

os.makedirs(folder, exist_ok=True)
data_basename = kwargs["name"]
Expand All @@ -555,10 +556,7 @@ def module(self, module, *path, **kwargs):
if len(path) > 1:
dataname = f"{path[1]}/{dataname}"

if module not in external_module_locations:
dataname = os.path.join(folder, dataname)
else:
dataname = os.path.join(folder, dataname)
dataname = os.path.join(folder, dataname)

inputfile = kwargs["file"]

Expand Down Expand Up @@ -618,13 +616,11 @@ def insertResource(r):
if path[0] == "deleteresource":
cherrypy.response.headers["X-Frame-Options"] = "SAMEORIGIN"
pages.require("system_admin", noautoreturn=True)
if len(path) > 1:
x = path[1]
else:
x = ""
return pages.get_template("modules/deleteresource.html").render(
module=module, r=x
)

d = dialogs.Dialog(f"Delete resource in {root}")
d.text_input("name", default=path[1])
d.submit_button("Submit")
return d.render(f"/modules/module/{url(root)}/deleteresourcetarget")

# This handles the POST request to actually do the deletion
if path[0] == "deleteresourcetarget":
Expand Down Expand Up @@ -932,11 +928,14 @@ def resourceEditPage(module, resource, version="default", kwargs={}):

def permissionEditPage(module, resource):
pages.require("view_admin_info")
return pages.get_template("modules/permissions/permission.html").render(
module=module,
permission=resource,
description=modules_state.ActiveModules[module][resource]["description"],

d = dialogs.Dialog(f"Permission: {resource} in {module}")
d.text_input(
"description",
default=modules_state.ActiveModules[module][resource]["description"],
)
d.submit_button("Submit")
return d.render(f"/modules/module/{url(module)}/updateresource/{url(resource)}/")


# The actual POST target to modify a resource. Context dependant based on resource type.
Expand Down
28 changes: 17 additions & 11 deletions kaithem/src/modules_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,14 +220,18 @@ def rawDeleteResource(m: str, r: str):
os.remove(fn)


def getResourceFn(m, r, o):
dir = os.path.join(directories.moduledir, "data")
return os.path.join(dir, m, urllib.parse.quote(r, safe=" /")) + getExt(o)
def getModuleFn(modulename: str):
if modulename not in external_module_locations:
dir = os.path.join(directories.moduledir, "data", modulename)
else:
dir = external_module_locations[modulename]

return dir


def getModuleFn(m):
dir = os.path.join(directories.moduledir, "data")
return os.path.join(dir, m)
def getResourceFn(m, r, o):
dir = getModuleFn(m)
return os.path.join(dir, urllib.parse.quote(r, safe=" /")) + getExt(o)


def saveModule(module, modulename: str):
Expand All @@ -239,23 +243,25 @@ def saveModule(module, modulename: str):
if "__do__not__save__to__disk__:" in modulename:
return

if modulename in external_module_locations:
fn = os.path.join(directories.moduledir, "data", modulename + ".location")
with open(fn, "w") as f:
f.write(external_module_locations[modulename])

# Iterate over all of the resources in a module and save them as json files
# under the URL url module name for the filename.
logger.debug("Saving module " + str(modulename))
saved = []

# do the saving
if modulename not in external_module_locations:
dir = os.path.join(directories.moduledir, "data", modulename)
else:
dir = external_module_locations[modulename]
dir = getModuleFn(modulename)

if not modulename:
raise RuntimeError("Something wrong")

try:
# Make sure there is a directory at where/module/
os.makedirs(os.path.join(dir), exist_ok=True)
os.makedirs(dir, exist_ok=True)
util.chmod_private_try(dir)
for resource in module:
r = module[resource]
Expand Down

0 comments on commit f60e1a4

Please sign in to comment.