Coverage for /home/runner/work/viur-core/viur-core/viur/src/viur/core/render/vi/__init__.py: 0%
118 statements
« prev ^ index » next coverage.py v7.6.3, created at 2024-10-16 22:16 +0000
« prev ^ index » next coverage.py v7.6.3, created at 2024-10-16 22:16 +0000
1import datetime
2import fnmatch
3import json
4import logging
5from viur.core import Module, conf, current, errors
6from viur.core.decorators import *
7from viur.core.render.json import skey as json_render_skey
8from viur.core.render.json.default import CustomJsonEncoder, DefaultRender
9# noinspection PyUnresolvedReferences
10from viur.core.render.vi.user import UserRender as user # this import must exist!
11from viur.core.skeleton import SkeletonInstance
14class default(DefaultRender):
15 kind = "json.vi"
18__all__ = [default]
21@exposed
22def timestamp(*args, **kwargs):
23 d = datetime.datetime.now()
24 current.request.get().response.headers["Content-Type"] = "application/json"
25 return json.dumps(d.strftime("%Y-%m-%dT%H-%M-%S"))
28@exposed
29def getStructure(module):
30 """
31 Returns all available skeleton structures for a given module.
33 To access the structure of a nested module, separate the path with dots (.).
34 """
35 path = module.split(".")
36 moduleObj = conf.main_app.vi
37 while path:
38 moduleObj = getattr(moduleObj, path.pop(0), None)
39 if not isinstance(moduleObj, Module) or not moduleObj.describe():
40 return json.dumps(None)
42 res = {}
44 # check for tree prototype
45 if "nodeSkelCls" in dir(moduleObj):
46 # Try Node/Leaf
47 for stype in ("viewSkel", "editSkel", "addSkel"):
48 for treeType in ("node", "leaf"):
49 if stype in dir(moduleObj):
50 try:
51 skel = getattr(moduleObj, stype)(treeType)
52 except (TypeError, ValueError):
53 continue
55 if isinstance(skel, SkeletonInstance):
56 storeType = stype.replace("Skel", "") + ("LeafSkel" if treeType == "leaf" else "NodeSkel")
57 res[storeType] = DefaultRender.render_structure(skel.structure())
58 else:
59 # every other prototype
60 for stype in ("viewSkel", "editSkel", "addSkel"): # Unknown skel type
61 if stype in dir(moduleObj):
62 try:
63 skel = getattr(moduleObj, stype)()
64 except (TypeError, ValueError):
65 continue
66 if isinstance(skel, SkeletonInstance):
67 res[stype] = DefaultRender.render_structure(skel.structure())
69 current.request.get().response.headers["Content-Type"] = "application/json"
70 return json.dumps(res or None, cls=CustomJsonEncoder)
73@exposed
74@skey
75def setLanguage(lang):
76 if lang in conf.i18n.available_languages:
77 current.language.set(lang)
80@exposed
81def dumpConfig():
82 res = {}
83 visited_objects = set()
85 def collect_modules(parent, depth: int = 0) -> None:
86 """Recursively collects all routable modules for the vi renderer"""
87 if depth > 10:
88 logging.warning(f"Reached maximum recursion limit of {depth} at {parent=}")
89 return
91 for key in dir(parent):
92 module = getattr(parent, key, None)
93 if not isinstance(module, Module):
94 continue
95 if module in visited_objects:
96 # Some modules reference other modules as parents, this will
97 # lead to infinite recursion. We can avoid reaching the
98 # maximum recursion limit by remembering already seen modules.
99 if conf.debug.trace:
100 logging.debug(f"Already visited and added {module=}")
101 continue
102 visited_objects.add(module)
104 if admin_info := module.describe():
105 # map path --> config
106 res[module.modulePath.removeprefix("/vi/").replace("/", ".")] = admin_info
107 # Collect children
108 collect_modules(module, depth=depth + 1)
110 collect_modules(conf.main_app.vi)
112 res = {
113 "modules": res,
114 # "configuration": dict(conf.admin.items()), # TODO: this could be the short vision, if we use underscores
115 "configuration": {
116 k.replace("_", "."): v for k, v in conf.admin.items(True)
117 }
118 }
119 current.request.get().response.headers["Content-Type"] = "application/json"
120 return json.dumps(res, cls=CustomJsonEncoder)
123@exposed
124def getVersion(*args, **kwargs):
125 """
126 Returns viur-core version number
127 """
128 current.request.get().response.headers["Content-Type"] = "application/json"
130 version = conf.version
132 # always fill up to 4 parts
133 while len(version) < 4:
134 version += (None,)
136 if conf.instance.is_dev_server \
137 or ((cuser := current.user.get()) and ("root" in cuser["access"] or "admin" in cuser["access"])):
138 return json.dumps(version[:4])
140 # Hide patch level + appendix to non-authorized users
141 return json.dumps((version[0], version[1], None, None))
144def canAccess(*args, **kwargs) -> bool:
145 """
146 General access restrictions for the vi-render.
147 """
149 if (cuser := current.user.get()) and any(right in cuser["access"] for right in ("root", "admin")):
150 return True
152 return any(fnmatch.fnmatch(current.request.get().path, pat) for pat in conf.security.admin_allowed_paths)
155@exposed
156def index(*args, **kwargs):
157 if args or kwargs:
158 raise errors.NotFound()
159 if (
160 not conf.instance.project_base_path.joinpath("vi", "main.html").exists()
161 and not conf.instance.project_base_path.joinpath("admin", "main.html").exists()
162 ):
163 raise errors.NotFound()
164 if conf.instance.is_dev_server or current.request.get().isSSLConnection:
165 raise errors.Redirect("/vi/s/main.html")
166 else:
167 appVersion = current.request.get().request.host
168 raise errors.Redirect(f"https://{appVersion}/vi/s/main.html")
171@exposed
172def get_settings():
173 """
174 Get public admin-tool specific settings, requires no user to be logged in.
175 This is used by new vi-admin.
176 """
177 fields = {k.replace("_", "."): v for k, v in conf.admin.items(True)}
179 if conf.user.google_client_id:
180 fields["admin.user.google.clientID"] = conf.user.google_client_id
182 current.request.get().response.headers["Content-Type"] = "application/json"
183 return json.dumps(fields, cls=CustomJsonEncoder)
186def _postProcessAppObj(obj):
187 obj["skey"] = json_render_skey
188 obj["timestamp"] = timestamp
189 obj["config"] = dumpConfig
190 obj["settings"] = get_settings
191 obj["getStructure"] = getStructure
192 obj["canAccess"] = canAccess
193 obj["setLanguage"] = setLanguage
194 obj["getVersion"] = getVersion
195 obj["index"] = index
196 return obj