From b821c1da4a4d54ed3f0775345a8c5d1f7754292e Mon Sep 17 00:00:00 2001 From: Harald Wolff Date: Thu, 1 Mar 2018 23:37:52 +0100 Subject: [PATCH] Initial Commit --- .gitignore | 8 + hServer.project | 211 ++++++++++ hServer/HServer.py | 39 ++ hServer/doc/templates.txt | 25 ++ hServer/hserver/__init__.py | 20 + hServer/hserver/api/__init__.py | 6 + hServer/hserver/api/fileobject.py | 32 ++ hServer/hserver/api/simpleobject.py | 16 + hServer/hserver/api/webobject.py | 108 +++++ hServer/hserver/exceptions.py | 13 + hServer/hserver/formdata.py | 85 ++++ hServer/hserver/headers.py | 68 ++++ hServer/hserver/mime.py | 109 ++++++ hServer/hserver/mimeheaders.py | 136 +++++++ hServer/hserver/packages/__init__.py | 3 + hServer/hserver/packages/package.py | 242 ++++++++++++ hServer/hserver/request.py | 179 +++++++++ hServer/hserver/run.py | 4 + hServer/hserver/server.py | 172 ++++++++ hServer/hserver/systemplates.py | 31 ++ hServer/hserver/templatemod.py | 73 ++++ hServer/hserver/templates.py | 369 ++++++++++++++++++ hServer/hserver/templates.src/so_updates.html | 3 + hServer/hserver/utils.py | 21 + hServer/hwo/Logging.py | 31 ++ hServer/hwo/Proxy.py | 62 +++ hServer/hwo/__init__.py | 10 + hServer/hwo/aquisition.py | 161 ++++++++ hServer/hwo/objectbroker.py | 115 ++++++ hServer/hwo/objectstore.py | 25 ++ hServer/hwo/persistence.py | 11 + hServer/packages/derkleinebasar/artikel.py | 91 +++++ hServer/packages/derkleinebasar/basar.py | 131 +++++++ hServer/packages/derkleinebasar/package.conf | 1 + .../templates/artikel_display.html | 111 ++++++ .../derkleinebasar/templates/artikel_tag.html | 38 ++ .../derkleinebasar/templates/common.css | 17 + .../derkleinebasar/templates/index.html | 1 + .../derkleinebasar/templates/layout.css | 181 +++++++++ .../derkleinebasar/templates/layout.html | 38 ++ .../templates/list_artikel.html | 65 +++ .../derkleinebasar/templates/list_verk.html | 71 ++++ .../derkleinebasar/templates/print.css | 163 ++++++++ .../derkleinebasar/templates/print_tags.html | 58 +++ .../derkleinebasar/templates/quittung.html | 71 ++++ .../derkleinebasar/templates/search.html | 13 + .../templates/verk_display.html | 82 ++++ .../derkleinebasar/templates/verk_prov.html | 164 ++++++++ .../derkleinebasar/templates/verkauf.html | 46 +++ hServer/packages/derkleinebasar/verkaeufer.py | 53 +++ hServer/packages/derkleinebasar/verkauf.py | 61 +++ hServer/packages/hcore/browser.py | 48 +++ hServer/packages/hcore/core.py | 19 + hServer/packages/hcore/coremod/__init__.py | 2 + hServer/packages/hcore/coremod/exceptions.py | 0 hServer/packages/hcore/package.conf | 1 + hServer/packages/hcore/templates/404.html | 15 + hServer/packages/hcore/templates/api.js | 17 + hServer/packages/hcore/templates/browse.css | 40 ++ hServer/packages/hcore/templates/browse.html | 40 ++ hServer/packages/hcore/templates/control.html | 14 + hServer/packages/hcore/templates/frame.html | 22 ++ hServer/packages/hcore/templates/list_wo.html | 11 + .../packages/hcore/templates/overview.html | 3 + .../packages/hcore/templates/packages.html | 38 ++ hServer/packages/hcore/templates/stat.html | 0 hServer/packages/hcore/templates/style.css | 80 ++++ hServer/packages/hcore/templates/tree.html | 30 ++ .../packages/hcore/templates/treelevel.html | 15 + hServer/packages/hcore/webmanager.py | 67 ++++ 70 files changed, 4306 insertions(+) create mode 100644 .gitignore create mode 100644 hServer.project create mode 100755 hServer/HServer.py create mode 100644 hServer/doc/templates.txt create mode 100644 hServer/hserver/__init__.py create mode 100644 hServer/hserver/api/__init__.py create mode 100644 hServer/hserver/api/fileobject.py create mode 100644 hServer/hserver/api/simpleobject.py create mode 100644 hServer/hserver/api/webobject.py create mode 100644 hServer/hserver/exceptions.py create mode 100644 hServer/hserver/formdata.py create mode 100644 hServer/hserver/headers.py create mode 100644 hServer/hserver/mime.py create mode 100644 hServer/hserver/mimeheaders.py create mode 100644 hServer/hserver/packages/__init__.py create mode 100644 hServer/hserver/packages/package.py create mode 100644 hServer/hserver/request.py create mode 100644 hServer/hserver/run.py create mode 100644 hServer/hserver/server.py create mode 100644 hServer/hserver/systemplates.py create mode 100644 hServer/hserver/templatemod.py create mode 100644 hServer/hserver/templates.py create mode 100644 hServer/hserver/templates.src/so_updates.html create mode 100644 hServer/hserver/utils.py create mode 100644 hServer/hwo/Logging.py create mode 100644 hServer/hwo/Proxy.py create mode 100644 hServer/hwo/__init__.py create mode 100644 hServer/hwo/aquisition.py create mode 100644 hServer/hwo/objectbroker.py create mode 100644 hServer/hwo/objectstore.py create mode 100644 hServer/hwo/persistence.py create mode 100644 hServer/packages/derkleinebasar/artikel.py create mode 100644 hServer/packages/derkleinebasar/basar.py create mode 100644 hServer/packages/derkleinebasar/package.conf create mode 100644 hServer/packages/derkleinebasar/templates/artikel_display.html create mode 100644 hServer/packages/derkleinebasar/templates/artikel_tag.html create mode 100644 hServer/packages/derkleinebasar/templates/common.css create mode 100644 hServer/packages/derkleinebasar/templates/index.html create mode 100644 hServer/packages/derkleinebasar/templates/layout.css create mode 100644 hServer/packages/derkleinebasar/templates/layout.html create mode 100644 hServer/packages/derkleinebasar/templates/list_artikel.html create mode 100644 hServer/packages/derkleinebasar/templates/list_verk.html create mode 100644 hServer/packages/derkleinebasar/templates/print.css create mode 100644 hServer/packages/derkleinebasar/templates/print_tags.html create mode 100644 hServer/packages/derkleinebasar/templates/quittung.html create mode 100644 hServer/packages/derkleinebasar/templates/search.html create mode 100644 hServer/packages/derkleinebasar/templates/verk_display.html create mode 100644 hServer/packages/derkleinebasar/templates/verk_prov.html create mode 100644 hServer/packages/derkleinebasar/templates/verkauf.html create mode 100644 hServer/packages/derkleinebasar/verkaeufer.py create mode 100644 hServer/packages/derkleinebasar/verkauf.py create mode 100644 hServer/packages/hcore/browser.py create mode 100644 hServer/packages/hcore/core.py create mode 100644 hServer/packages/hcore/coremod/__init__.py create mode 100644 hServer/packages/hcore/coremod/exceptions.py create mode 100644 hServer/packages/hcore/package.conf create mode 100644 hServer/packages/hcore/templates/404.html create mode 100644 hServer/packages/hcore/templates/api.js create mode 100644 hServer/packages/hcore/templates/browse.css create mode 100644 hServer/packages/hcore/templates/browse.html create mode 100644 hServer/packages/hcore/templates/control.html create mode 100644 hServer/packages/hcore/templates/frame.html create mode 100644 hServer/packages/hcore/templates/list_wo.html create mode 100644 hServer/packages/hcore/templates/overview.html create mode 100644 hServer/packages/hcore/templates/packages.html create mode 100644 hServer/packages/hcore/templates/stat.html create mode 100644 hServer/packages/hcore/templates/style.css create mode 100644 hServer/packages/hcore/templates/tree.html create mode 100644 hServer/packages/hcore/templates/treelevel.html create mode 100644 hServer/packages/hcore/webmanager.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2d4f436 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.DS_Store + +**/*.pyc + +#hServer/packages/* +!hServer/packages/hcore +#hServer/DiskSync/* +#hServer/objects/* diff --git a/hServer.project b/hServer.project new file mode 100644 index 0000000..16dc57a --- /dev/null +++ b/hServer.project @@ -0,0 +1,211 @@ + + + + + + + + + + ../hserver + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hServer/HServer.py b/hServer/HServer.py new file mode 100755 index 0000000..0590940 --- /dev/null +++ b/hServer/HServer.py @@ -0,0 +1,39 @@ +#!/usr/bin/python3 + + +import hserver + +import os +import sys + + +newDefault = None + +listen = ['localhost',8080] + +opts = list( sys.argv[1:] ) + +while (len(opts)>0): + o = opts.pop(0) + if (o == '-b'): + listen[0] = opts.pop(0) + elif (o == '-p'): + listen[1] = int(opts.pop(0)) + elif (o == '--default'): + newDefault = opts.pop(0) + +server = hserver.HServer(listen) + +if not newDefault is None: + server.getRoot().setDefault(newDefault) + +server.run() + + + + + + + + + diff --git a/hServer/doc/templates.txt b/hServer/doc/templates.txt new file mode 100644 index 0000000..c1e2112 --- /dev/null +++ b/hServer/doc/templates.txt @@ -0,0 +1,25 @@ + +Simple Python Template Engine +----------------------------- + + HEX: 0x0D,0x0A,0x20 + +<%[action][expr]%> + +[action] Aktion + +"" [expr] als Python Code Interpretieren += Rückgabewert von [expr] in Dokument einsetzen +include Weiteres Template einfügen [expr] ist entweder eine Liste der Form ('template-name',) oder 'template-name' + +Zukünftig: +---------- +iterate [expr] = +end Markiert Ende eines Blocks (z.B. iterate) + + + +Globale Funktionen: + +include(,) Fügt das Template mit der "self" referenz an der aktuellen Position ein +print() Gibt an der aktuellen Position aus diff --git a/hServer/hserver/__init__.py b/hServer/hserver/__init__.py new file mode 100644 index 0000000..674311b --- /dev/null +++ b/hServer/hserver/__init__.py @@ -0,0 +1,20 @@ + + +from hserver.exceptions import HServerException,FinishRequestException,HttpException + +import hserver.api + +from hserver.request import Request +from hserver.headers import Headers + +from hserver.templates import Template +from hserver.templatemod import TemplateModule + +import hserver.run +import hserver.systemplates + + +from hserver.server import HServer + + + diff --git a/hServer/hserver/api/__init__.py b/hServer/hserver/api/__init__.py new file mode 100644 index 0000000..ed39698 --- /dev/null +++ b/hServer/hserver/api/__init__.py @@ -0,0 +1,6 @@ +from hwo import Persistence,NoPersistence,Aquisition + +from hserver.api.webobject import WebObject,WebFolder,WebCallable +from hserver.api.fileobject import FileObject +from hserver.api.simpleobject import SimpleObject + diff --git a/hServer/hserver/api/fileobject.py b/hServer/hserver/api/fileobject.py new file mode 100644 index 0000000..e8080eb --- /dev/null +++ b/hServer/hserver/api/fileobject.py @@ -0,0 +1,32 @@ +from hserver.api import WebObject +from hwo import Persistence,NoPersistence + +import os + +class FileObject(WebObject): + + def __init__(self,file=None,path=None,contenttype="application/octet-stream"): + self._file = file + self._path = path + self._content = None + self._contenttype = contenttype + + def __call__(self,request,o=None): + if self._content is None: + if self._file is None: + self._file = open( self._path, "rb" ) + self._content = self._file.read() + + request.setResponseHeader("Content-Type",self._contenttype) + request.getBinaryContentFile().write(self._content) + + +class DiskFolder(WebObject,Persistence): + + def __init__(self,path): + self._path = path + + def __dir__(self): + return os.listdir( self._path) + + diff --git a/hServer/hserver/api/simpleobject.py b/hServer/hserver/api/simpleobject.py new file mode 100644 index 0000000..6e46c97 --- /dev/null +++ b/hServer/hserver/api/simpleobject.py @@ -0,0 +1,16 @@ +from hserver.api.webobject import WebObject,Persistence +import hserver + + +class SimpleObject(WebObject,Persistence): + + def __init__(self,accepts=["*/*"],contenttype="application/octetstream",content=b""): + self.setDefault("update") + self.accepts = accepts + self.contenttype = contenttype + self.content = content + + + def __call__(self,request,o=None): + request.setResponseHeader("Content-Type",self.contenttype) + request.getBinaryContentFile().write( bytes(self.content) ) diff --git a/hServer/hserver/api/webobject.py b/hServer/hserver/api/webobject.py new file mode 100644 index 0000000..b66647f --- /dev/null +++ b/hServer/hserver/api/webobject.py @@ -0,0 +1,108 @@ +from hwo import Persistence,NoPersistence,Aquisition,AquisitionProxy +import hserver + +class WebCallable: + + def __init__(self, method=None, instance=None): + self._method = method + self._instance = instance + + def __call__(self,request, o=None): + if (hasattr(self,"_method")): + m = getattr( self, "_method") + i = getattr( self, "_instance", o) + if i is None: + i = o + m(i,request, o=o) + else: + request.getContentFile().write("No ContentSorry, no content here!") + + +class WebObject(WebCallable,Aquisition): + + def __init__(self): + self.__default = None + + def __getitem__(self,name): + try: + return getattr( self, name ) + except: + raise IndexError("%s not found in %s" % (name,self)) + + def __setitem__(self,name,value): + setattr( self, name, value ) + + def __delitem__(self,name): + delattr( self, name ) + + def setDefault(self,default): + self.__default = default + + def setChild(self,name,child): + setattr( self, name, child ) + + def children(self): + ls = [] + for an in dir(self): + if isinstance( self[an], WebObject ): + ls.append( an ) + return ls + + def walk(self,request): + next, stack = request.pathwalker().walk() + + no = getattr(self, next, None) + if no is None: + raise hserver.HttpException(404,"%s in /%s" % (next,request.pathwalker().walked(-1))) + + if (len(stack)==0) or (not isinstance(no,WebObject)): + if (isinstance(no,WebCallable)): + no(request, o=self) + else: + raise hserver.HttpException(404,"%s in /%s" % (next,request.pathwalker().walked(-1))) + else: + no.walk(request) + + + def __call__(self,request,o = None): + if not self.__default is None: + request.redirect( request.pathwalker().walked() + "/" + self.__default ) + + request.getContentFile().write("No ContentSorry, no content here!") + + def attribute(self,name,default): + if not hasattr(self,name): + setattr( self, name, default ) + return getattr( self, name ) + + def __public_types(self): + if hasattr(self,"_public_types"): + return self._public_types + return {} + + def __public_names(self): + if hasattr(self,"_public_names"): + return self._public_names + return {} + + def update(self,request): + if not request is None: + f = request.getForm() + else: + f = None + + for n in self.__public_names(): + if n in self.__public_types(): + t = self.__public_types()[n] + else: + t = str + + if (not f is None) and (n in f): + setattr(self, n, t(f[n].value())) + + elif not hasattr(self, n): + setattr( self, n, t() ) + + +class WebFolder(WebObject, Persistence): + pass diff --git a/hServer/hserver/exceptions.py b/hServer/hserver/exceptions.py new file mode 100644 index 0000000..d096b0f --- /dev/null +++ b/hServer/hserver/exceptions.py @@ -0,0 +1,13 @@ + +class HServerException(Exception): + pass + +class FinishRequestException(HServerException): + pass + +class HttpException(HServerException): + + def __init__(self,status,message): + HServerException.__init__(self) + self.status = status + self.message = message diff --git a/hServer/hserver/formdata.py b/hServer/hserver/formdata.py new file mode 100644 index 0000000..2c90832 --- /dev/null +++ b/hServer/hserver/formdata.py @@ -0,0 +1,85 @@ +from urllib.parse import unquote_plus + +class FormValue: + + def __init__(self,name,value = None,headers = {}): + self.__name = name + self.__value = value + self.__headers = headers + + def name(self): + return self.__name + def value(self): + return self.__value + def headers(self): + return self.__headers + + def filename(self): + pp = self.__headers.parameters("CONTENT-DISPOSITION") + if (not pp is None) and ("filename" in pp.keys()): + return pp["filename"] + return None + + + +class FormData: + + def __init__(self,request): + self.__request = request + self.__values = {} + + self.__append_query() + + self.__append_mime() + + def __getitem__(self,name): + return self.__values[name][0] + + def __contains__(self,name): + return name in self.__values + + def get(self,name): + try: + return self[name][0] + except: + return None + + def keys(self): + return self.__values.keys() + + def list(self,name): + if name in self.__values: + return list(self.__values[name]) + return [] + + def __append_var(self,var): + if not var.name() in self.__values.keys(): + self.__values[var.name()] = [] + self.__values[var.name()].append( var ) + + def __append_mime(self): + mime = self.__request.mime() + + if (mime.multipart()): + for p in mime.parts(): + n = p.name() + if not n is None: + self.__append_var(FormValue(n,p.body(),p.headers())) + + def __append_query(self): + qs = self.__request.QUERY_STRING + + pairs = qs.split("&") + for pair in pairs: + sp = pair.split("=") + if (len(sp)>0): + name = sp[0] + if (len(sp)>1): + value = sp[1] + else: + value= "" + + self.__append_var(FormValue( unquote_plus(name), unquote_plus(value))) + + + diff --git a/hServer/hserver/headers.py b/hServer/hserver/headers.py new file mode 100644 index 0000000..c6eff8f --- /dev/null +++ b/hServer/hserver/headers.py @@ -0,0 +1,68 @@ +import io +import string + +import hserver.utils + +class Headers: + + def __init__(self, fp=None, src=None): + self.__items = {} + self.__parameters = {} + + if not fp is None: + self.__read(fp) + + def get(self,name,default = None): + if not name in self.__items.keys(): + return default + + return self.__items[name] + + + + def __getitem__(self,name): + if name in self.__items.keys(): + return self.__items[name] + raise KeyError() + + def __read(self,fp): + cont = True + lines = [] + + while (cont): + l = str(fp.readline(),"iso-8859-1").strip() + if (l.strip() == ""): + cont = False + else: + if (l[0] in string.whitespace ): + lines[-1] = lines[-1] + " " + l.lstrip() + else: + lines.append(l) + + for line in lines: + self.__parseline(line) + + def __parseline(self,line): + i = line.find(":") + if (i > 0): + name = line[:i] + value = line[ i+1 : ].strip() + + i = value.find(";") + if (i>0): + parameters = value[ i+1 : ] + value = value[ :i ] + else: + parameters = None + + self.__items[name] = value + print("Headers: %s: %s" % (name,value)) + +# if (not parameters is None): +# p = hserver.utils.StreamTokenizer(io.StringIO(parameters)) + + + + + + diff --git a/hServer/hserver/mime.py b/hServer/hserver/mime.py new file mode 100644 index 0000000..9146934 --- /dev/null +++ b/hServer/hserver/mime.py @@ -0,0 +1,109 @@ +import io +import traceback + +from hserver.mimeheaders import MIMEHeaders + +class MIMEException(Exception): + pass + +class ContentSizeLimitException(MIMEException): + pass + +class MIME: + + def __init__(self,fp=None,source=None,limit=10485760,defaultlength=-1,parent=None): + if (not fp is None): + self.__fp = fp + elif (not source is None): + self.__fp = io.BytesIO(source) + + self.__parent = parent + self.__limit = limit + self.__defaultlength = defaultlength + + self.__body = None + self.__headers = None + self.__multipart = False + self.__parts = [] + + self.__parse() + + def __getitem__(self,name): + if self.__multipart: + for p in self.__parts: + if not p.name() is None: + return p.name() + raise KeyError() + + def headers(self): + return self.__headers + + def multipart(self): + return self.__multipart + + def parts(self): + return self.__parts + + def name(self): + pp = self.__headers.parameters("CONTENT-DISPOSITION") + if (not pp is None) and ("name" in pp.keys()): + return pp["name"] + return None + + def body(self): + return self.__body + + def __parse(self): + self.__headers = MIMEHeaders( fp=self.__fp ) + l = int(self.__headers.value("CONTENT-LENGTH",self.__defaultlength)) + if (l > self.__limit): + raise ContentSizeLimitException(size=l,limit=self.__limit) + + self.__body = self.__fp.read(l) + + if (not "filename" in self.__headers.parameters("CONTENT-DISPOSITION")) and (self.__headers.value("CONTENT-TYPE").upper() == "TEXT/PLAIN"): + if ("charset" in self.__headers.parameters("CONTENT-TYPE")): + charset = self.__headers.parameters("CONTENT-TYPE")["charset"] + else: +# charset = "us-ascii" + charset = "utf-8" + self.__body = str(self.__body,charset) + + type = self.__headers.value("CONTENT-TYPE","/").split("/")[0].upper() + if (type == "MULTIPART"): + try: + self.__parsemultipart() + except Exception as ex: + traceback.print_exception(type(ex),ex,ex.__traceback__) + + def __parsemultipart(self): + """ + p = start of preceeding boundary + c = end of preceeding boundary + e = start of following boundary + """ + self.__multipart = True + + boundary = b'--' + bytes(self.__headers.get("CONTENT-TYPE").parameters()["boundary"],"iso-8859-1") + + p = self.__body.find(boundary) + c = p + len(boundary) + 2 + + boundary = b'\r\n' + boundary + + while (True): + e = self.__body.find(boundary,c) + + if (e < 0): + return + else: + self.__parts.append(MIME(source=self.__body[c : e],parent=self)) + + p = e + c = p + len(boundary) + 2 + + if (self.__body[c - 2 : c] == b"--"): + return + + + \ No newline at end of file diff --git a/hServer/hserver/mimeheaders.py b/hServer/hserver/mimeheaders.py new file mode 100644 index 0000000..677367b --- /dev/null +++ b/hServer/hserver/mimeheaders.py @@ -0,0 +1,136 @@ +import io +import string + +import hserver.utils + +class MIMEHeader: + + def __init__(self,line): + self.__line = line + self.__parameters ={} + + self.__parseline() + + def name(self): + return self.__name + + def rawvalue(self): + return self.__rawvalue + + def value(self): + return self.__value + + def parameters(self): + return self.__parameters + + + def __parseparameters(self,parameters): + p = 0 + while (p < len(parameters)): + pe = parameters.find("=",p) + if (pe < 0): + return + + name = parameters[p:pe].strip() + + pe = pe + 1 + + if (parameters[pe] == '"'): + pe = pe + 1 + pq = parameters.find('"',pe) + pr = parameters.find(';',pq) + value = parameters[ pe : pq] + else: + pq = parameters.find(";",pe) + if (pq < 0): + pq = len(parameters) + pr = pq + value = parameters[ pe : pq].strip() + + self.__parameters[name] = value + if (pr < 0): + return + p = pr + 1 + + def __parseline(self): + i = self.__line.find(":") + if (i > 0): + self.__name = self.__line[:i].upper() + self.__rawvalue = self.__line[ i+1 : ].strip() + + i = self.__rawvalue.find(";") + if (i>0): + self.__parseparameters(self.__rawvalue[ i+1 : ]) + self.__value = self.__rawvalue[ :i ] + else: + self.__value = self.__rawvalue + + +# print("MIMEHeader: %s: %s %s" % (self.__name,self.__value,self.__parameters)) + + + +class MIMEHeaders: + + def __init__(self, fp=None, src=None): + self.__items = {} + self.__parameters = {} + + if not fp is None: + self.__read(fp) + + def get(self,name): + name = name.upper() + if not name in self.__items.keys(): + return None + + return self.__items[name] + + def __getitem__(self,name): + name = name.upper() + if name in self.__items.keys(): + return self.__items[name].rawvalue() + raise KeyError() + + def value(self,name,default=None): + h = self.get(name) + if h is None: + return default + return h.value() + + def rawvalue(self,name,default=None): + h = self.get(name) + if h is None: + return default + return h.rawvalue() + + def parameters(self,name): + h = self.get(name) + if h is None: + return {} + return h.parameters() + + + def __read(self,fp): + cont = True + lines = [] + + while (cont): + l = str(fp.readline(),"iso-8859-1").strip() + if (l.strip() == ""): + cont = False + else: + if (l[0] in string.whitespace ): + lines[-1] = lines[-1] + " " + l.lstrip() + else: + lines.append(l) + + for line in lines: + h = MIMEHeader(line) + self.__items[ h.name() ] = h + + if self.get("CONTENT-TYPE") is None: + self.__items[ "CONTENT-TYPE" ] = MIMEHeader("Content-Type: text/plain") + + + diff --git a/hServer/hserver/packages/__init__.py b/hServer/hserver/packages/__init__.py new file mode 100644 index 0000000..84b1e59 --- /dev/null +++ b/hServer/hserver/packages/__init__.py @@ -0,0 +1,3 @@ + +from hserver.packages.package import Package,PackageManager + diff --git a/hServer/hserver/packages/package.py b/hServer/hserver/packages/package.py new file mode 100644 index 0000000..9b93115 --- /dev/null +++ b/hServer/hserver/packages/package.py @@ -0,0 +1,242 @@ +import os +import os.path +import sys +import gc +import importlib + +import types + +import hserver.api + + +def new_module(modname, path = None, file = None): + mod = types.ModuleType( modname ) + if not path is None: + mod.__path__ = path + if not file is None: + mod.__file__ = file + + sys.modules[ modname ] = mod + + return mod + + +class Package: + + def __init__(self, pm, path, pname): + self.__pm = pm + self.__path = path + + self.__modpath = "packages.%s" % (pname,) + self.__mod = new_module( self.__modpath ) + self.__allowed_modules = [ "hserver", "hserver.api" ] + + self.__modules = {} + + self.__builtins = dict(__builtins__) + self.__builtins["__import__"] = self.__mod_import + self.__builtins["export"] = self.__export + + self.__exports = {} + + self.__load() + + def module(self): + return self.__mod + + def __load(self): + print("Package.__load(): Path=%s" % (self.__path,)) + setattr( self.__mod, "Templates", hserver.TemplateModule("%s/templates" % (self.__path,)) ) + self.__modules["%s.Templates" % (self.__modpath,)] = self.__mod.Templates + + if os.path.exists("%s/package.conf" % (self.__path,)): + pcn = "%s/package.conf" % (self.__path,) + self.__config = new_module( "package.conf", file=pcn ) + self.__mod_refresh( self.__config ) + + + if (hasattr(self.__config,"modules")): + for mname in self.__config.modules: + self.__allowed_modules.append( mname ) + + files = os.listdir( self.__path ) + for fn in files: + if (fn.endswith(".py")): + self.__mod_create( fn[:-3] ) + + print("Package: Modules: %s" % (self.__modules,)) + + + def __mod_create(self, localname): + "Erstelle/Lade ein Modul aus diesem Package" + modname = "%s.%s" % (self.__modpath,localname) + + if modname in self.__modules: + return self.__modules[ modname ] + + modpath = localname.split(".") + localfile = modpath[-1] + del modpath[-1] + + if len(modpath)==0 : + modparent = self.__mod + else: + modparent = self.__mod_create( ".".join(modpath) ) + + + mfile = ("%s/%s/%s.py" % (self.__path,"/".join(modpath),localfile)).replace("//","/") + mpath = ("%s/%s" % (self.__path,"/".join(modpath))).replace("//","/") + + print("__mod_create( %s ): Check: F=%s , P=%s" % (localname, mfile, mpath)) + if not (os.path.exists(mfile)): + mfile = ("%s/%s/%s/__init__.py" % (self.__path,"/".join(modpath),localfile)).replace("//","/") + mpath = ("%s/%s/%s" % (self.__path,"/".join(modpath), localfile)).replace("//","/") + + print("__mod_create( %s ): Check: F=%s , P=%s" % (localname, mfile, mpath)) + + if os.path.exists(mpath): + if not (os.path.exists(mfile)): + mfile = None + else: + raise Exception("Package: module '%s'not found" % (localname,)) + + print("__mod_create( %s ): Result: F=%s , P=%s" % (localname, mfile, mpath)) + + mod = new_module( modname, path=mpath, file=mfile ) + self.__modules[ modname ] = mod + setattr( modparent, localfile, mod) + + mod.__builtins__ = self.__builtins + + self.__mod_refresh( mod ) + + return mod + + def exports(self): + return dict(self.__exports) + + def modules(self): + return dict(self.__modules) + + def reload(self): + + for modname in list(self.__modules.keys()): + mod = self.__modules[ modname ] + self.__mod_refresh( mod ) + self.__update_classes( modname ) + + files = os.listdir( self.__path ) + for fn in files: + if (fn.endswith(".py")): + if not fn[:-3] in self.__modules: + self.__mod_create( fn[:-3] ) + + def __update_classes(self, modname): + for o in gc.get_objects(): + if (isinstance( o, object )): + if o.__class__.__module__ == modname: + c = getattr( self.__modules[modname], o.__class__.__name__, None ) + if not c is None: + try: + o.__class__ = c + except Exception as ex: + print("__update_classes(): Exception: %s" % (ex,)) + + + + def __mod_import(self,name,globals=None,locals=None,fromlist=(),level=0): + print("import(%s,%s,%s,%s,%s)" % (name,"...","...",fromlist,level)) + + bname = name.split(".")[0] + + if (name in self.__allowed_modules): + mod = importlib.import_module( name ) + self.__modules[ name ] = mod + bmod = sys.modules[ bname ] + else: + mod = self.__mod_create( name ) + if bname == name: + bmod = mod + else: + bmod = self.__modules[ "%s.%s" % (self.__modpath,bname) ] + + if (not fromlist is None) and (len(fromlist) > 0): + return mod + + return bmod + + def __mod_refresh(self, mod): + if not hasattr(mod, "__file__"): + return + + print("__mod_refresh: %s [%s]" % (mod.__name__,mod.__file__)) + + if not os.path.exists( mod.__file__ ): + del self.__modules[ mod.__name__ ] + return + + f = open(mod.__file__, "r") + src = f.read() + f.close() + + co = compile( src, mod.__file__, "exec" ) + exec( co, mod.__dict__ ) + + def __export(self, name, o, glob=False): + self.__exports[ name ] = o + if glob: + self.__pm.export( name, o ) + + def __getattr__(self, name): + if name in self.__modules: + return self.__modules[ name ] + if name in self.__exports: + return self.__exports[ name ] + raise AttributeError("%s not found in %s" % (name,self)) + +class PackageManager: + + def __init__(self, path ): + self.__path = os.path.abspath( path ) + self.__packagesmod = new_module( "packages" ) + + self.__packages = {} + self.__exports = {} + + print("PackageManager loads from %s" % (self.__path,)) + self.__load() + + + def __load(self): + plist = os.listdir( self.__path ) + for pname in plist: + ppath = "%s/%s" % (self.__path,pname) + + if (os.path.isdir(ppath)): + print("PackageManager loads %s" % (pname,)) + p = Package( self, ppath, pname ) + + self.__packages[ pname ] = p + setattr( self.__packagesmod, pname, p.module() ) + + def export(self, name, o): + self.__exports[ name ] = o + + def imp(self, modname): + if modname in self.__exports: + return self.__exports[ modname ] + return None + + def list_exports(self): + return list( self.__exports.keys() ) + + def exports(self): + return self.__exports + + def packages(self): + return self.__packages + + def __getattr__(self, name): + if name in self.__packages: + return self.__packages[ name ] + raise AttributeError("%s not found in %s" % (name,self)) diff --git a/hServer/hserver/request.py b/hServer/hserver/request.py new file mode 100644 index 0000000..075e232 --- /dev/null +++ b/hServer/hserver/request.py @@ -0,0 +1,179 @@ +import http.server +import hserver + +from hserver.formdata import FormData + +import io + +class PathWalker: + + def __init__(self,path_info): + self.__walk = path_info + self.__walked = [] + + def len(self): + return len(self.__walk) + + def next(self): + return self.__walk[0] + + def walk(self): + n = self.__walk[0] + del self.__walk[0] + self.__walked.append(n) + return (n,self.__walk) + + def walked(self, limit=None): + if limit is None: + return "%s" % ("/".join(self.__walked),) + return "%s" % ("/".join(self.__walked[:limit]),) + + def stack(self): + return self.__walk + + def wstack(self,ind = None): + if ind is None: + return self.__walked + return self.__walked[ind] + + + +class Request: + + def __init__(self, MIME=None, URI = None, vars = {}, method = "", read = None): + self.reset() + + self.__mime = MIME + + self.__headers = self.__mime.headers() + self.__vars = vars + self.__form = None + self.__read = read + + self.set("REQUEST_URI", URI) + self.set("REQUEST_METHOD", method) + + self.__initialize() + + + def __resetContent(self): + self.__bcontent = io.BytesIO() + self.__content = io.TextIOWrapper(self.__bcontent,write_through=True) + + def reset(self): + self.__resetContent() + self.__status = 200 + self.__rheaders = { "Content-Type": "text/html" } + + def mime(self): + return self.__mime + + def getContentFile(self): + return self.__content + + def getBinaryContentFile(self): + return self.__bcontent + + def getContent(self): + return self.__bcontent.getvalue() + + + def __getattr__(self,name): + if name in self.__vars.keys(): + return self.__vars[name] + raise AttributeError() + + def set(self,name,value): + self.__vars[name] = value + + def keys(self): + return self.__vars.keys() + + def __getitem__(self,name): + if name in self.__vars.keys(): + return self.__vars[ name ] + + def getForm(self): + return self.__form + + + def getResponseHeaders(self): + return self.__rheaders + + def setResponseHeader(self,name,value): + self.__rheaders[ name ] = value + + def setStatus(self,status): + self.__status = status + def getStatus(self): + return self.__status + + + def self(self,limit = None,trail=False): + p = self.SCRIPT_NAME + "/" + self.__pathwalker.walked( limit ) + if trail and (p!="/"): + p = p + "/" + return p + + def pathwalker(self): + return self.__pathwalker + + def __initvar(self,name): + if not name in self.__vars.keys(): + self.__vars[name] = "" + + def __initialize(self): + self.__initvar("SCRIPT_NAME") + self.__vars["CLIMBPATH"] = [] + + ind = self.REQUEST_URI.find("?") + if (ind >= 0): + self.set("QUERY_STRING", self.REQUEST_URI[ ind + 1 :]) + else: + self.set("QUERY_STRING", "") + ind = len(self.REQUEST_URI) + + self.set("PATH_INFO", self.REQUEST_URI[:ind]) + + l = int( self.__headers.value("Content-Length",0) ) + + print("Request: Content-Length: %s" % (l,)) + + self.set("CONTENT_TYPE", self.__headers.value("Content-Type", "")) + self.set("REFERER", self.__headers.value("Referer", "")) + + self.__construct_path_info() + + self.__form = FormData(self) + + self.__pathwalker = PathWalker(self.__path_info) + + def __construct_path_info(self): + path_info = self.PATH_INFO.split("/") + del path_info[0] + if (len(path_info)>0) and (path_info[0] == ""): + del path_info[0] + if (len(path_info)>0) and (path_info[-1] == ""): + del path_info[-1] + self.__path_info = path_info + + def redirect(self,uri = "",append = None): + if (len(uri)>0 and uri[0]!="/"): + uri = "/" + uri + + if not append is None: + uri = "%s/%s" % (uri,append) + + self.__status = 307 + self.setResponseHeader("Location", "%s%s" % (self.SCRIPT_NAME,uri)) + + raise hserver.FinishRequestException() + + + def __str__(self): + b = io.StringIO() + + b.write("" % (self.REQUEST_METHOD,self.REQUEST_URI)) + + return b.getvalue() + diff --git a/hServer/hserver/run.py b/hServer/hserver/run.py new file mode 100644 index 0000000..d4cdad9 --- /dev/null +++ b/hServer/hserver/run.py @@ -0,0 +1,4 @@ +import hserver +import os.path + +templates = hserver.TemplateModule(path="%s/templates.src" % (os.path.dirname(__file__),)) diff --git a/hServer/hserver/server.py b/hServer/hserver/server.py new file mode 100644 index 0000000..b883b55 --- /dev/null +++ b/hServer/hserver/server.py @@ -0,0 +1,172 @@ +import socketserver +import traceback +import io + +import hserver +import hserver.systemplates + +import threading +import socket + +from hserver.mime import MIME +from hserver.packages import PackageManager + +import hwo +from hwo import AquisitionProxy + +class HServerRequestHandler(socketserver.StreamRequestHandler): + "" + + def handle(self): + self.__keepalive = False + + print("handle():") + + try: + self.handle_request() + while (self.__keepalive): + self.handle_request() + + except: + print("handle(): Exception:") + traceback.print_exc() + +# self.rfile.close() +# self.wfile.close() + self.request.close() + + print("handle(): finished.") + + def handle_request(self): + print("handle_request():") + + l = self.rfile.readline() + rline = str(l,"iso-8859-1") + toks = rline.split() + print("handle_request: requestline: %s" % (toks,)) + + if (len(toks)!=3): + return + + method,uri,version = toks + + if (not version.startswith("HTTP/")): + print("handle_request: Version String: %s" % (version,)) + return + + #self.rbfile = self.rfile + #self.rfile = io.TextIOWrapper(self.rbfile, "iso-8859-1") + + print("MIMEing...") + + mime = MIME(self.rfile, defaultlength=0) + r = hserver.Request( URI=uri, MIME=mime, method=method, read=self.rfile ) + + try: + self.server.hserver.handle(r) + except hserver.FinishRequestException: + pass + except hserver.HttpException as ex: + r.reset() + r.setResponseHeader("Content-Type","text/html") + + t = self.server.hserver.packagemanager().hcore.Templates.provide("%s.html" % (ex.status,)) + t.run( ex, outfile=r.getContentFile() ) + + except Exception as ex: + traceback.print_exception(type(ex),ex,ex.__traceback__) + + r.reset() + r.setResponseHeader("Content-Type","text/html") + + self.templ_exception = hserver.Template(source=hserver.systemplates.tmpl_exception, disable_sandbox=True) + self.templ_exception.run( ex, globals(), outfile=r.getContentFile() ) + + print("handle_request(): reply") + + + r.setResponseHeader("Connection","close") + + w = io.TextIOWrapper(self.wfile) + w.write("%s %s %s\r\n" % (version,r.getStatus(),r.getStatus())) + + c = r.getContent() + + r.getResponseHeaders()['Content-Length'] = str(len(c)) + + for k in r.getResponseHeaders().keys(): + w.write("%s: %s\r\n" % (k, r.getResponseHeaders()[k])) + + w.write("\r\n") + w.flush() + + print("handle_request(): sending content... (%s Bytes)" % (len(c),)) + + self.wfile.write( c ) + #self.wfile.write( b"\r\n" ); + print("handle_request(): finished.") + + + + +class HServer: + + def __init__(self,listen = ('localhost',8080)): + self.__listen = (listen[0],listen[1]) + + self.__disksync = hwo.DiscObjectStore("./DiskSync") + self.__broker = hwo.ObjectBroker( self.__disksync ) + + self.__packages = PackageManager("./packages") + + if "ROOT" in self.__disksync: + self.__root = self.__broker.load( self.__disksync["ROOT"].decode("UTF-8") ) + else: + self.__root = hserver.api.WebFolder() + persistence_id = self.__broker.save( self.__root ) + self.__disksync["ROOT"] = persistence_id.encode("UTF-8") + + self.__packages.hcore.module().core.init(self) + + + def _shutdown(self): + self.__http.shutdown() + + def shutdown(self): + t = threading.Thread(target=HServer._shutdown,args=(self,)) + t.start() + + def packagemanager(self): + return self.__packages + + def getRoot(self): + return self.__root + + def aq_root(self): + return AquisitionProxy( self.__root ) + + def run(self): + socketserver.TCPServer.allow_reuse_address = True + self.__http = socketserver.TCPServer(self.__listen,HServerRequestHandler) + self.__http.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) + self.__http.hserver = self + self.__http.serve_forever() + + + + def handle(self,request): + print("Hserver.handle(%s)" % (request,)) + + root = self.aq_root() + + if (request.pathwalker().len()==0): + root( request ) + else: + root.walk( request ) + self.__broker.save( self.__root ) + + + + + + diff --git a/hServer/hserver/systemplates.py b/hServer/hserver/systemplates.py new file mode 100644 index 0000000..bbd01b4 --- /dev/null +++ b/hServer/hserver/systemplates.py @@ -0,0 +1,31 @@ +import hserver + + +tmpl_exception = """ + + + HServer Exception + + + +

HServer Exception

+

There was an exception raised, while handling your request!

+

Eine Ausnahme trat auf, während die Anfrage bearbeitet wurde!

+
+<% +tracelist = traceback.extract_tb( self.__traceback__ ) +%> +<%iterate trace tracelist%> +
+ <%=trace[0]%>:<%=trace[1]%> in <%=trace[2]%>
+ <%=trace[3]%>

+
+<%end%> +
+ +""" + diff --git a/hServer/hserver/templatemod.py b/hServer/hserver/templatemod.py new file mode 100644 index 0000000..74a820e --- /dev/null +++ b/hServer/hserver/templatemod.py @@ -0,0 +1,73 @@ +import os +import os.path + +import hserver + +class TemplateModule: + + def __init__(self,path,parent=None): + self.__path = path + self.__parent = parent + + self.__children = {} + self.__altchildren = {} + + self.__load() + + def __load(self): + if not os.path.exists( self.__path ): + return + + l = os.listdir( self.__path ) + for fn in l: + p = "%s/%s" % (self.__path, fn) + + o = None + if os.path.isdir( p ): + o = TemplateModule( p, self) + elif (os.path.isfile( p )): + o = hserver.Template( template=fn, base=self.__path, provider=self) + + if not o is None: + self.__children[ fn ] = o + self.__altchildren[ self.transform(fn) ] = o + + + def transform(self,name): + if not name[0].isalpha(): + name = "_%s" % (name,) + + return name.replace(".","_") + + def __getattr__(self,name): + if not ((name in self.__children) or (name in self.__altchildren)): + self.__load() + + if name in self.__children: + return self.__children[name] + if name in self.__altchildren: + return self.__altchildren[name] + raise AttributeError("%s not found in %s" % (name,self)) + + def __getitem__(self,name): + if not ((name in self.__children) or (name in self.__altchildren)): + self.__load() + + if name in self.__children: + return self.__children[name] + if name in self.__altchildren: + return self.__altchildren[name] + raise IndexError("%s not found in %s" % (name,self)) + + def provide(self,name): + s = name.split("/") + if len(s) > 1: + return self[s[0]].provide("/".join(s[1:])) + return self[s[0]] + + def __str__(self): + cl = [] + for c in self.__children: + cl.append( c ) + + return "" % (", ".join(cl)) diff --git a/hServer/hserver/templates.py b/hServer/hserver/templates.py new file mode 100644 index 0000000..f5c86b1 --- /dev/null +++ b/hServer/hserver/templates.py @@ -0,0 +1,369 @@ +import io +import re +import sys +import os + +import hserver.api + +import html + +import builtins + + +def text2html(text): + lines = text.splitlines() + html = "" + for l in lines: + html = "{0}

{1}

".format(html,l) + return html + +class SandboxPrinter: + + def __init__(self,stream): + self.stream = stream + + def __call__(self,te = ""): + self.stream.write(str(te)) + +class SandboxInclude: + + def __init__(self,template): + self.__template = template + + def __call__(self,template,selfref = None): + if (selfref is None): + self.__template.include( template ) + else: + self.__template.include( [template, selfref] ) + +class TemplateSegment: + + def __init__(self,template,parent = None): + self.__template = template + self.__parent = parent + + def setParent(self,parent): + self.__parent = parent + + def getParent(self): + return self.__parent + + def getTemplate(self): + return self.__template + + def run(self,env,priv = {}): + """Run this Segement of the Template""" + pass + + def __repr__(self): + return "" + + +class TemplateGroupSegment(TemplateSegment): + + def __init__(self,template,parent = None): + TemplateSegment.__init__(self,template,parent) + self.__children = [] + + def appendChild(self,segment): + self.__children.append(segment) + + def getChildren(self): + return self.__children + + def run(self,env,priv={}): + for child in self.__children: + child.run(env,priv) + + def __repr__(self): + return "" % (str(self.getChildren()),) + +class TemplateTextSegment(TemplateSegment): + + def __init__(self,template,parent = None,text = ""): + TemplateSegment.__init__(self,template,parent) + self.__text = text + + def run(self,env,priv={}): + self.getTemplate().getContentFile().write(self.__text) + + def __repr__(self): + return "" + +class TemplateCodeSegment(TemplateSegment): + def __init__(self,template,parent = None,code = ""): + TemplateSegment.__init__(self,template,parent) + self.__code = code + + def run(self,env,priv={}): + exec( self.__code, env ) + + def __repr__(self): + return "" %(self.__code,) + + +class TemplateValueSegment(TemplateSegment): + def __init__(self,template,parent = None,code = ""): + TemplateSegment.__init__(self,template,parent) + self.__code = code + + def run(self,env,priv={}): + code = self.__code + v = eval( code, env ) + self.getTemplate().getContentFile().write(str(v)) + +class TemplateIterateSegment(TemplateGroupSegment): + def __init__(self,template,parent = None,code = ""): + TemplateGroupSegment.__init__(self,template,parent) + (self.__iterator, self.__iteration) = code.split(" ",1) + + def run(self,env,priv={}): + iter = eval( self.__iteration, env ) + for v in iter: + env[self.__iterator] = v + TemplateGroupSegment.run(self,env,priv) + + def __repr__(self): + return "" % (self.__iterator,self.__iteration,self.getChildren(),) + +class TemplateIfSegment(TemplateGroupSegment): + def __init__(self,template,parent = None,code = ""): + TemplateGroupSegment.__init__(self,template,parent) + self.__code = code + + def run(self,env,priv={}): + v = eval( self.__code, env ) + if (v): + TemplateGroupSegment.run(self,env,priv) + + def __repr__(self): + return "" % (str(self.__children),) + + +class TemplateIncludeSegment(TemplateSegment): + def __init__(self,template,parent = None,code = ""): + TemplateSegment.__init__(self,template,parent) + self.__code = code + + def run(self,env,priv={}): + v = eval( self.__code, env ) + self.getTemplate().include(v,priv={}) + + def __repr__(self): + return "" % (str(self.__code),) + +class TemplateContentSegment(TemplateSegment): + def __init__(self,template,parent = None): + TemplateSegment.__init__(self,template,parent) + + def run(self,env,priv={}): + priv["framed"].framed(env,priv) + + def __repr__(self): + return "" % (str(self.__code),) + + +class Template(hserver.api.WebCallable): + + def __init__(self,template=None,base = ".",source = None,disable_sandbox=False,frame=None,provider=None): + self.template = template + self.base = base + self.__content = None + self.__frame = frame + self.__source = source + self.__root = None + self.__current = self.__root + self.__disable_sandbox = disable_sandbox + self.__timestamp = None + self.__provider = provider + + def getContent(self): + return self.__content.getvalue() + + def getContentFile(self): + return self.__content + + def setFrame(self,frame): + self.__frame = frame + + def provider(self): + return self.__provider + + def __appendSegment(self,segment): + self.__current.appendChild(segment) + + def __appendGroup(self,segment): + self.__appendSegment(segment) + self.__current = segment + + def __leaveGroup(self): + if (self.__current != self.__root) and (self.__current.getParent() is not None): + self.__current = self.__current.getParent() + + def indexWS(self,te): + p = 0 + while (p < len(te)): + if (ord(te[p]) <= 0x20): + return p + p = p + 1 + + return p + + + def __splittag(self,tag): + "Split to a list of [ , ]" + if (ord(tag[0]) <= 0x20): + return ["",tag[1:]] + elif (tag[0]=="="): + return ["=",tag[1:]] + else: + i = self.indexWS(tag) + if (i == len(tag)): + return [ tag , "" ] + else: + return [ tag[:i], tag[ i+1: ] ] + + def __parsetag(self,tag): + (action,expr) = self.__splittag(tag) + + if (action == ""): + self.__appendSegment( TemplateCodeSegment(self,self.__current,expr) ) + elif (action == "="): + self.__appendSegment( TemplateValueSegment(self,self.__current,expr) ) + elif (action == "include"): + self.__appendSegment( TemplateIncludeSegment(self,self.__current,expr) ) + elif (action == "iterate"): + s = TemplateIterateSegment(self,self.__current,expr) + self.__appendGroup( s ) + elif (action == "if"): + s = TemplateIfSegment(self,self.__current,expr) + self.__appendGroup( s ) + elif (action == "end"): + self.__leaveGroup() + elif (action == "content"): + self.__appendSegment( TemplateContentSegment( self, self.__current )) + elif (action == "frame"): + self.__frame = self.__provider.provide( expr ) + else: + pass + + + def __parse(self,source): + if self.__root is None: + self.__root = TemplateGroupSegment(self) + self.__current = self.__root + pos = 0; + while (len(source) > pos): + iopen = None + iclose = None + + try: + iopen = source.index( "<%", pos ) + iclose = source.index( "%>", iopen ) + + except ValueError as ve: + self.debugException(ve) + if (iopen is None): + iopen = len(source) + iclose = len(source) + else: + raise ve + + if (iopen > pos): + self.__appendSegment( TemplateTextSegment(self, self.__current, source[pos : iopen]) ) + + if (iopen < len(source)): + self.__parsetag( source[ iopen + 2 : iclose ] ) + + pos = iclose + 2 + + def debugException(self,ex): + pass + + def __load_source(self): + if not self.template is None: + tfilename = "%s/%s" % (self.base,self.template) + st = os.stat( tfilename ) + print("Template.__load_source(): Check %s > %s" % (st.st_mtime, self.__timestamp)) + if (self.__timestamp is None) or (st.st_mtime > self.__timestamp): + self.__timestamp = st.st_mtime + tfile = open(tfilename,"r") + self.__source = tfile.read() + tfile.close() + self.__root = None + + __allowed_builtins = ["getattr","setattr","hasattr","range","abs","dict","hex","int","float","bytes","bool","chr","ord","pow","str","map","round","len"] + + def run(self,o = None,env = {},outfile=None,framed=None): + save_content = self.__content + + if (not outfile is None): + self.__content = outfile + else: + self.__content = io.StringIO() + + priv = {} + priv["framed"] = framed + + self.__load_source() + self.__parse(self.__source) + + if o is not None: + env['self'] = o + + if not self.__disable_sandbox: + env['__builtins__'] = { + getattr: getattr + } + env['print'] = SandboxPrinter(self.__content) + + + env['include'] = SandboxInclude(self) + env['escape'] = html.escape + env['text2html'] = text2html + + for an in self.__allowed_builtins: + if hasattr(globals(),an): + env[an] = getattr(globals(),an) + if hasattr(builtins,an): + env[an] = getattr(builtins,an) + + print("Template.run(): my frame is: %s" % (self.__frame,)) + + self.env = env + if self.__frame is not None: + self.frame(env) + else: + self.__root.run(env,priv) + + if (isinstance( self.__content, io.StringIO) ): + c = self.__content.getvalue() + else: + c = None + + self.__content = save_content + return c + + def frame(self,env): + print("Template: Framing with %s" % (self.__frame,)) + self.__frame.run(env=env,outfile=self.__content,framed=self) + + def framed(self,env,priv): + print("Frame %s called %s" % (self.__frame,self)) + self.__root.run(env,priv) + + def include(self,expr,priv): + print(" + + + + Beschreibung:
+ + + + + + Bemerkungen:
+ + + + + + + + + diff --git a/hServer/packages/derkleinebasar/templates/artikel_tag.html b/hServer/packages/derkleinebasar/templates/artikel_tag.html new file mode 100644 index 0000000..be46d46 --- /dev/null +++ b/hServer/packages/derkleinebasar/templates/artikel_tag.html @@ -0,0 +1,38 @@ + + + + + + + + +
+
+
+ <%=self.svgqrcode(self.id)%> +
+ +
Fahrradbörse 2018
+ +
+
+
<%=self.bezeichnung%>

+ <%=self.bezeichnung2%> +
+ +
<%=text2html(self.beschreibung)%>
+ +
+
<%="%0.2f €" % (self.preis,)%>
+
+ +
+ <%=self.id%> +
+
+
+
+ + diff --git a/hServer/packages/derkleinebasar/templates/common.css b/hServer/packages/derkleinebasar/templates/common.css new file mode 100644 index 0000000..4a7454b --- /dev/null +++ b/hServer/packages/derkleinebasar/templates/common.css @@ -0,0 +1,17 @@ +.right { + position: absolute; + right: 0px; + text-align: right; +} + +.hr { + border-bottom: 1px dotted gray; +} + +.indent { + margin-left: 1cm; +} + +.box { + display: block; +} \ No newline at end of file diff --git a/hServer/packages/derkleinebasar/templates/index.html b/hServer/packages/derkleinebasar/templates/index.html new file mode 100644 index 0000000..c55d424 --- /dev/null +++ b/hServer/packages/derkleinebasar/templates/index.html @@ -0,0 +1 @@ +<%frame layout_html%> diff --git a/hServer/packages/derkleinebasar/templates/layout.css b/hServer/packages/derkleinebasar/templates/layout.css new file mode 100644 index 0000000..2e570ef --- /dev/null +++ b/hServer/packages/derkleinebasar/templates/layout.css @@ -0,0 +1,181 @@ +<% +request.setResponseHeader("Content-Type","text/css") +%> + +<%include ("common_css",self)%> + +body,div,section { + font-family: DejaVu Sans, Sans; + font-size: 14px; +} + +table { + border-collapse: collapse; + border-spacing: 0px; +} + +td { + padding: 4px; + padding-right: 10px; + height: auto; + overflow: scroll; + vertical-align: top; + border-bottom: 1px dotted gray; +} + +td textarea { + width: 95%; + height: 80px; +} + +input[type="number"] { + text-align: right; +} + +#header { + position: absolute; + top: 0px; + left: 0px; + right: 0px; + height: 40px; + + border-bottom: 2px solid black; + background-color: #60FF80; +} + +#header > div { + position: absolute; + top: 5px; + right: 15px; + + font-size: 24px; + font-style: italic; +} + +#search { + border-radius: 8px; + border: 1px solid black; + margin-top: 5px; + padding: 8px; + width: 90%; + font-size: 12px; + font-style: italic; + background-color: #60FF80; +} + +#search input[type=text] { + border-radius: 5px; + padding: 2px; + width: 160px; + margin-top: 4px; + margin-bottom: 4px; +} + +#menu { + float: left; + position: absolute; + top: 50px; + left: 0px; + + padding-left: 20px; + padding-right: 10px; + + border-right: 2px solid #60FF80; + + min-height: 400px; + min-width: 180px; +} + +#menu > a { + display: block; + padding: 10px; + margin: 5px; + border: 2px solid #60FF80; + border-radius: 8px; + font-size: 24px; + text-align: center; +} + +#menu > a:link { + font-style: normal; + text-decoration: none; + color: blue; + background-color: #A0FFD0; +} +#menu > a:visited { + font-style: normal; + text-decoration: none; + color: blue; +} + +#menu > a:hover { + background-color: #40DF60; + font-style: italic; +} + +#page { + display: block; + margin-left: 240px; + margin-top: 50px; +} + +thead > tr { + padding-bottom: 2px; + border-bottom: 1px solid black; + font-style: italic; + font-weight: bold; +} + +thead > tr > td { + padding-right: 40px; +} + +a { + font-style: italic; +} + +td > input { + width: 95%; + min-width: 60px; +} + +.big { + font-size: 150%; +} + +.wide { + width: 240px; +} + + +.space { + padding-top: 8px; + padding-bottom: 8px; +} + +.pre { + white-space: pre; +} + +.indent { + margin-left: 1cm; +} + +.stroke { + text-decoration: line-through; +} + +.gray { + color: gray; +} + +@media print { + #menu, #search { + visibility: hidden; + display: none; + } + + #page { + margin-left: 0px; + } +} \ No newline at end of file diff --git a/hServer/packages/derkleinebasar/templates/layout.html b/hServer/packages/derkleinebasar/templates/layout.html new file mode 100644 index 0000000..0f1832c --- /dev/null +++ b/hServer/packages/derkleinebasar/templates/layout.html @@ -0,0 +1,38 @@ + + + + + Der kleine Basar + + + +
+ + + + +
<%content%>
+ + + + +
+ + diff --git a/hServer/packages/derkleinebasar/templates/list_artikel.html b/hServer/packages/derkleinebasar/templates/list_artikel.html new file mode 100644 index 0000000..8898ca9 --- /dev/null +++ b/hServer/packages/derkleinebasar/templates/list_artikel.html @@ -0,0 +1,65 @@ +<%frame layout_html%> +

Artikelliste

+
+ + + + + + + + + + + <% + +n_artikel = 0 +s_verkauft = 0.0 +n_verkauft = 0 +s_preis = 0.0 +s_preisverkauf = 0.0 + +def akey(p): + return getattr(self.artikel, p).bezeichnung + +al = self.artikel.children() +al.sort(key=akey) + +for n in range(al.__len__()): + al[n] = getattr(self.artikel, al[n]) + s_preis = s_preis + al[n].preis + +%> +<%iterate a al%> + + + + + + +<%end%> + + +
Artikel#BezeichnungVerkauftVerkäufer
<%=a.id%><%=a.bezeichnung%> + <%if not a.verkauft%>NEIN<%end%> + <%if a.verkauft%>Verkauft (<%="%0.2f" % (a.erloes,)%>€)<% +s_verkauft = s_verkauft + a.erloes +n_verkauft = n_verkauft + 1 +s_preisverkauf = s_preisverkauf + a.preis +%><%end%> + + + <%=a.verkaeufer().lastname%>, <%=a.verkaeufer().firstname%> + +
+
+
+
+Statistik: <%=len(al)%> Artikel, +davon <%=n_verkauft%> verkauft für insgesamt <%="%0.2f" % (s_verkauft,)%>€ +(Provisionen: <%="%0.2f" % (s_verkauft*0.1,)%>€) +
+Bepreiste Verkaufssumme wäre gewesen: <%="%0.2f" % (s_preisverkauf,)%>€, dies wären <%="%0.2f" % (s_preisverkauf*0.1,)%>€ Provision gewesen.
+Bepreiste Gesamtsumme war: <%="%0.2f" % (s_preis,)%>€, dies wären <%="%0.2f" % (s_preis*0.1,)%>€ Provision gewesen.
+
+ diff --git a/hServer/packages/derkleinebasar/templates/list_verk.html b/hServer/packages/derkleinebasar/templates/list_verk.html new file mode 100644 index 0000000..e304d32 --- /dev/null +++ b/hServer/packages/derkleinebasar/templates/list_verk.html @@ -0,0 +1,71 @@ +<%frame layout_html%> +

Verkäuferliste

+
+[ +AUSGECHECKTE ]
+
+ + + + + + + + + + + + + + + + + + + + <% +def vkey(p): + return getattr(self.verkaeufer, p).lastname + +vl = self.verkaeufer.children() +vl.sort(key=vkey) + +for n in range(vl.__len__()): + vl[n] = getattr(self.verkaeufer, vl[n]) + +if "away" in request.getForm(): + away = True +else: + away = False + +l = [] +for v in vl: + if (not v.checkedout) or away: + l.append(v) + +vl = l + +%> +<%iterate v vl%> + + + + + + +<%end%> + + +
Verk.#NachnameVornamenAngebotene Artikel
neu:
<%=v.id%><%=v.lastname%><%=v.firstname%> +
+ <%=v.artikel().__len__()%>
+ +
+
+
+
+Auf dieser Liste sind <%=len(vl)%> Verkäufer gelistet. +
\ No newline at end of file diff --git a/hServer/packages/derkleinebasar/templates/print.css b/hServer/packages/derkleinebasar/templates/print.css new file mode 100644 index 0000000..c8f5195 --- /dev/null +++ b/hServer/packages/derkleinebasar/templates/print.css @@ -0,0 +1,163 @@ +<% +request.setResponseHeader("Content-Type","text/css") +%> +* { + font-family: DejaVu Sans,Sans,Helvetica,Arial; + font-size: 4mm; + border: none; + margin: 0; + padding: 0; +} + +<%include ("common_css",self)%> + +body { +} + +.title { + display: block; + font-size: 4mm; + font-style: italic; +} + +.title div { + font-size: 150%; + font-weight: bold; +} + +.sub { + font-size: 5mm; +} + +.big { + font-size: 200%; +} + +.ul { + text-decoration: underline; +} +.b { + font-weight: bold; +} +.i { + font-style: italic; +} + +.pre { + white-space: pre; +} + +.small { + font-size: 3mm; +} + +.borderless { + border: none; +} + +#price { + position: absolute; + right: 0.5cm; + top: 0.8cm; + font-size: 5mm; + -webkit-transform: rotate(-90deg); + -webkit-transform-origin: right top; +} + +#tagid { + position: absolute; + right: 0.1cm; + top: 0.1cm; +} + +#description { + margin-top: 0.4cm; + width: 7cm; + white-space: pre-wrap; +} + +#description > p { + margin-bottom: 0.2cm; +} + +@page { + margin: 0cm; +} + +#scancode { + position: absolute; + right: 4mm; + top: 4mm; +} + +#scancode > svg { + width: 25mm; + height: 25mm; +} + +#page > div { + position: absolute; + top: 2mm; + left: 2mm; + bottom: 2mm; + right: 2mm; + display: block; +} + + +@media print { + .RLE { + width: 86mm; + height: 32mm; + } + + body, .SRL { + width: 95mm; + height: 47mm; + } + + body { + margin: 0px; + padding: 0px; + } + + #page { + position: absolute; + left: 0cm; + top: 0cm; + right: 0cm; + bottom: 0cm; + border: 0px; + } + .noprint { + visibility: hidden; + } +} + +@media screen { + body { + background-color: #404040; + } + + #page { + position: relative; + top: 30px; + left: 30px; + + background-color: white; + width: 210mm; + height: 297mm; + border: 2px solid black; + } + + .RLE #page { + width: 86mm; + height: 32mm; + } + +} + + +div { + display: inline-block; +} diff --git a/hServer/packages/derkleinebasar/templates/print_tags.html b/hServer/packages/derkleinebasar/templates/print_tags.html new file mode 100644 index 0000000..1a6f639 --- /dev/null +++ b/hServer/packages/derkleinebasar/templates/print_tags.html @@ -0,0 +1,58 @@ +<% +tags = self._tags() +%> + + + + + + + + +
+
+ <%iterate y range(16)%> +
+ <%iterate x range(4)%><% +t = tags.pop() + %>
+ +
<%end%>
+
+ <%end%> + + +
+
+ + \ No newline at end of file diff --git a/hServer/packages/derkleinebasar/templates/quittung.html b/hServer/packages/derkleinebasar/templates/quittung.html new file mode 100644 index 0000000..d7d8209 --- /dev/null +++ b/hServer/packages/derkleinebasar/templates/quittung.html @@ -0,0 +1,71 @@ + + + + + + + + +
+
+ +<% +summe = 0.0 +%> +
+ <%=self.svgqrcode(self._aq_name)%> +
+ +
Fahrradbörse von
+
Bündnis90 / Die Grünen (2016)
+
+
+ + +
+
Quittung / Mitnahmeschein

+
<%=self._aq_name%>

+
<%=self.zeit%>
+
+ +
+<%iterate artikel self.artikel.keys()%> +
+ <%=artikel.bezeichnung%> +
<%="%0.2f" % (self.artikel[artikel],)%>€

+
<%=artikel.beschreibung%>
+
+<% +summe = summe + self.artikel[artikel] +%> +<%end%> +
+
+
Summe: <%="%0.2f" % (summe,)%>€
+
+ +
Grundsätze:
+ Veranstalter der Fahrradbörse ist Bündnis90 / die Grünen OV Vaihingen.
+ Der Veranstalter tritt in der Fahrradbörse als Vermittler auf, die Vermittlerprovision beträgt 10% des erzielten Preises.
+
+ Der Veranstalter übernimmt keine Gewährleistung und Garantie für die Ware!
+ Bitte prüfen Sie den Zustand und die Funktionsfähigkeit der Ware genau!
+
+ Der Veranstalter überwacht die Fahrradbörse, er übernimmt keine Haftung bei Diebstahl.
+ Am Abend nicht abgeholte Ware geht in den Besitz des Veranstalters über und wird gespendet bzw. entsorgt. +
+ + +
+
+ + \ No newline at end of file diff --git a/hServer/packages/derkleinebasar/templates/search.html b/hServer/packages/derkleinebasar/templates/search.html new file mode 100644 index 0000000..d70df6d --- /dev/null +++ b/hServer/packages/derkleinebasar/templates/search.html @@ -0,0 +1,13 @@ +<%frame layout_html%> +

Direktsuche

+
+Suche nach: <%=request.getForm()["q"].value()%>
+
+<%if len(request.results)==0%> +
Keine Treffer!
+<%end%> +<%if len(request.results)!=0%> + <%iterate r request.results%> + "><%=r["text"]%>
+ <%end%> +<%end%> diff --git a/hServer/packages/derkleinebasar/templates/verk_display.html b/hServer/packages/derkleinebasar/templates/verk_display.html new file mode 100644 index 0000000..2d7f9f3 --- /dev/null +++ b/hServer/packages/derkleinebasar/templates/verk_display.html @@ -0,0 +1,82 @@ +<%frame layout_html%> +<% +self.update(request) +%> +

Verkäufer Details

+Abrechnungsliste
+
+<%if self.checkedout%> +

!!! AUSGECHECKT !!!

+<%end%> +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Nachname:Vorname:
Firma:
Telefon:
Ausgecheckt: + +
Anschrift:
+
Bemerkungen:
+
+
+
+

Angebotene Artikel

+ + + + + + + + + + + + + + + + + + + + + <%iterate artikel self.artikel()%> + + + + + + + <%end%> + +
Artikel#Bezeichnung (kurz)Bezeichnung (lang)Preis
neu:
<%=artikel.id%><%=artikel.bezeichnung%><%=artikel.bezeichnung2%><%=artikel.preis%>
+ + diff --git a/hServer/packages/derkleinebasar/templates/verk_prov.html b/hServer/packages/derkleinebasar/templates/verk_prov.html new file mode 100644 index 0000000..4113e86 --- /dev/null +++ b/hServer/packages/derkleinebasar/templates/verk_prov.html @@ -0,0 +1,164 @@ +<% + +def akey(p): + return getattr(self._aq_parent.artikel, p).bezeichnung + +al = self._aq_parent.artikel.children() +al.sort(key=akey) + +for n in range(al.__len__()): + al[n] = getattr(self._aq_parent.artikel, al[n]) + +l = [] +for a in al: + if a.vid==self.id: + l.append(a) + +al = l + +summe = 0.00 +sum_erloes = 0.00 + + +%> + + + + Verkäuferabrechnung + + + + +
+
+
+ <%if not self.checkedout%> + + <%end%> +
Fahrradbörse von
+
Bündnis90 / Die Grünen (2018)
+
+
+ + <%if self.checkedout%> + CHECKOUT

+ <%end%> + +
+ Abrechnungsliste Verkäufer
+
<%=self.lastname%>, <%=self.firstname%>

+ Verkäufer-ID: <%=self.id%> +
+ +
+ + + + + + + + + + <%iterate a al%> + + + + + + <%end%> + + + + + + + + + + + + + + + + + + + + + + + +
ArtikelBepreisungErlös
+ <%=a.bezeichnung%>
+
<%=a.id%>

+ +
+ <%="%03.2f" % (a.preis,)%>€ + +<% +summe = summe + a.preis +%><%if a.verkauft%> + <%="%03.2f" % (a.erloes,)%>€ + <% +sum_erloes = sum_erloes + a.erloes + %> +<%end%> +<%if not (a.verkauft)%> +N. Verkauft +<%end%> +
Summe:( <%="%03.2f" % (round(summe,2),)%>€ )<%="%03.2f" % (round(sum_erloes,2),)%>€
Provision:( <%="%03.2f" % (round(summe * 0.1,2),)%>€ )<%="%03.2f" % (round(sum_erloes * 0.1,2),)%>€
Auszahlung:( <%="%03.2f" % (round(summe * 0.9,2),)%>€ )<%="%03.2f" % (round(sum_erloes * 0.9,2),)%>€
+ + <%if self.checkedout%> +
+
+
+ Betrag erhalten:
 
+
+

+ <%end%> + +
Grundsätze:
+ Veranstalter der Fahrradbörse ist Bündnis90 / die Grünen OV Vaihingen.
+ Der Veranstalter tritt in der Fahrradbörse als Vermittler auf, die Vermittlerprovision beträgt 10% des erzielten Preises.
+
+ Der Veranstalter übernimmt keine Gewährleistung und Garantie für die Ware!
+ Bitte prüfen Sie den Zustand und die Funktionsfähigkeit der Ware genau!
+
+ Der Veranstalter überwacht die Fahrradbörse, er übernimmt keine Haftung bei Diebstahl.
+ Am Abend nicht abgeholte Ware geht in den Besitz des Veranstalters über und wird gespendet bzw. entsorgt. +
+ + +
+
+ + diff --git a/hServer/packages/derkleinebasar/templates/verkauf.html b/hServer/packages/derkleinebasar/templates/verkauf.html new file mode 100644 index 0000000..7ad9c0b --- /dev/null +++ b/hServer/packages/derkleinebasar/templates/verkauf.html @@ -0,0 +1,46 @@ +<%frame layout_html%> + +<% + +summe = 0.0 + +%> + +
+
Verkauf
+
+ + + +<%if hasattr(request,"message")%> +
<%=request.message%>
+
+<%end%> + +
+Artikel hinzufügen: +
+
+<%iterate artikel self.artikel.keys()%> +
+ <%=artikel.bezeichnung%> +
+
<%=artikel.beschreibung%>
+
+<% +summe = summe + self.artikel[artikel] +%> +<%end%> +
+
+
Summe: <%="%0.2f" % (summe,)%>€
+
+
+ +        + + + + diff --git a/hServer/packages/derkleinebasar/verkaeufer.py b/hServer/packages/derkleinebasar/verkaeufer.py new file mode 100644 index 0000000..c42b658 --- /dev/null +++ b/hServer/packages/derkleinebasar/verkaeufer.py @@ -0,0 +1,53 @@ +from hserver.api import WebObject,Persistence,WebFolder,WebCallable +import hserver + +import Templates +import uuid + +import qrcode + +class Verkaeufer(WebObject,Persistence): + + _public_names = { + "lastname": "", + "firstname": "", + "anschrift": "", + "bemerkungen": "", + "company": "", + "telefon": "", + "checkedout": False + }; + _public_types = { + "checkedout": bool + } + + prov = Templates.verk_prov_html + + def __init__(self): + WebObject.__init__(self) + + self.id = uuid.uuid4().hex + self.lastname = ""; + self.firstname = ""; + self.company = ""; + self.anschrift = ""; + self.bemerkungen = ""; + self.telefon = "" + self.checkedout = False + + def __call__(self,request,o=None): + Templates.verk_display_html(request,self) + + def artikel(self): + r = [] + artikel = self._aq_parent._aq_parent.artikel + for n in artikel.children(): + a = getattr(artikel, n) + if a.vid == self.id: + r.append(a) + return r + + def _checkout(self,request,o=None): + self.checkedout = True + request.redirect(request.self(-1) + "/prov") + checkout = WebCallable(method=_checkout) diff --git a/hServer/packages/derkleinebasar/verkauf.py b/hServer/packages/derkleinebasar/verkauf.py new file mode 100644 index 0000000..a92972c --- /dev/null +++ b/hServer/packages/derkleinebasar/verkauf.py @@ -0,0 +1,61 @@ +from hserver.api import WebObject,Persistence,WebFolder,WebCallable +import hserver + +import Templates +import uuid + +import qrcode +import datetime + +class Verkauf(WebObject,Persistence): + + def __init__(self): + WebObject.__init__(self) + self.setDefault("verkauf") + self.artikel = {} + self.bezahlt = False + + + def _verkauf(self,request,o=None): + if not self.bezahlt: + if ("artikelid" in request.getForm()) and not (request.getForm()["artikelid"].value()==""): + try: + a = getattr( self._aq_parent._aq_parent.artikel, request.getForm()["artikelid"].value())._aq_object + if a is not None: + if a in self.artikel: + request.message = "Artikel bereits gescannt!" + else: + if a.verkauft: + request.message = "Artikel wurde bereits verkauft!" + else: + self.artikel[ a ] = a.preis; + + except Exception as e: + request.message = "Artikel nicht gefunden!" + print(e) + + for a in self.artikel: + ea = "erloes_%s" % (a.id,) + if ea in request.getForm(): + self.artikel[a] = float(request.getForm()[ea].value()) + + if ("action" in request.getForm()): + ac = request.getForm()["action"].value() + if ac=="BEZAHLT": + for a in self.artikel: + a.verkauft = True + a.erloes = self.artikel[a] + a.quittung = self._aq_name + self.bezahlt = True + self.zeit = str(datetime.datetime.now()) + if self.bezahlt: + Templates.quittung_html(request,o) + else: + Templates.verkauf_html(request,o) + + verkauf = WebCallable(method=_verkauf) + + + + + diff --git a/hServer/packages/hcore/browser.py b/hServer/packages/hcore/browser.py new file mode 100644 index 0000000..b86b8aa --- /dev/null +++ b/hServer/packages/hcore/browser.py @@ -0,0 +1,48 @@ +from hserver.api import WebObject,NoPersistence,WebCallable +import Templates +import hserver + +class TreeBrowser(WebObject,NoPersistence): + + def __init__(self): + WebObject.__init__(self) + self.setDefault("browse") + + _browse = Templates.browse_html; + + def __call__(self,request,o=None): + return self._browse(request,o) + + def _addObject(self, request, o): + f = request.getForm() + + if ("oname" in f) and ("oclass" in f): + oclass = getattr( hserver.api , f["oclass"].value() ) + i = oclass() + + print(">>>%s" % (o._aq_parent._aq_name,)) + + setattr( self._aq_parent, f["oname"].value(), i ) + + request.redirect( request.pathwalker().walked(-2) + "/_browse" ) + add = WebCallable(method=_addObject) + + def _delObject(self, request, o): + print(">>>%s" % (o._aq_parent._aq_name,)) + + delattr(o._aq_parent._aq_parent, o._aq_parent._aq_name) + + request.redirect( request.pathwalker().walked(-3) + "/_browse" ) + remove = WebCallable(method=_delObject) + + def wo_types(self): + r = [] + exp = hserver.api.__dict__ + for t in exp.values(): + try: + if (issubclass(t,hserver.api.WebObject)): + r.append(t. __name__) + except: + pass + r.sort() + return r diff --git a/hServer/packages/hcore/core.py b/hServer/packages/hcore/core.py new file mode 100644 index 0000000..57409dd --- /dev/null +++ b/hServer/packages/hcore/core.py @@ -0,0 +1,19 @@ +import coremod.exceptions + +from webmanager import WebManager +from browser import TreeBrowser + +_hserver = None + +def init(hserver): + _hserver = hserver + + root = hserver.getRoot() + manager = WebManager( hserver ) + + root.setChild( "manage", manager) + root.setDefault("manage") + + root.setChild("_browse", TreeBrowser()) + + diff --git a/hServer/packages/hcore/coremod/__init__.py b/hServer/packages/hcore/coremod/__init__.py new file mode 100644 index 0000000..139597f --- /dev/null +++ b/hServer/packages/hcore/coremod/__init__.py @@ -0,0 +1,2 @@ + + diff --git a/hServer/packages/hcore/coremod/exceptions.py b/hServer/packages/hcore/coremod/exceptions.py new file mode 100644 index 0000000..e69de29 diff --git a/hServer/packages/hcore/package.conf b/hServer/packages/hcore/package.conf new file mode 100644 index 0000000..a8c5ae1 --- /dev/null +++ b/hServer/packages/hcore/package.conf @@ -0,0 +1 @@ +modules=("hwo",) diff --git a/hServer/packages/hcore/templates/404.html b/hServer/packages/hcore/templates/404.html new file mode 100644 index 0000000..57190f0 --- /dev/null +++ b/hServer/packages/hcore/templates/404.html @@ -0,0 +1,15 @@ + + + 404 Not Found + + + +

Die angeforderte Resource konnte nicht gefunden werden

+

The requested resource was not found

+
<%=self.message%>
+ + diff --git a/hServer/packages/hcore/templates/api.js b/hServer/packages/hcore/templates/api.js new file mode 100644 index 0000000..1447163 --- /dev/null +++ b/hServer/packages/hcore/templates/api.js @@ -0,0 +1,17 @@ +function byID(id){ + return document.getElementById(id); +} + +function addObject( path ){ + oname = byID("oname").value; + oclass = byID("oclass").value; + + if (oname == ""){ + alert("Bitte einen Objektnamen vergeben!"); + byID("oname").focus(); + } else { + url = "<%=request.self(-1)%>/addObject?path=" + path + "&oclass=" + oclass + "&oname=" + oname; + window.location.href = url + } + +} diff --git a/hServer/packages/hcore/templates/browse.css b/hServer/packages/hcore/templates/browse.css new file mode 100644 index 0000000..1236399 --- /dev/null +++ b/hServer/packages/hcore/templates/browse.css @@ -0,0 +1,40 @@ + +#display { + white-space: nowrap; + vertical-align: top; + position: absolute; +} + +#path{ + margin-bottom: 20px; +} + +#tree, #details { + display: inline-block; +} + +.treenode { + display: block; + position: relative; + border-top: 1px solid gray; + font-size: 14px; + padding-top: 5px; + padding-bottom: 5px; + white-space: nowrap; +} + +.treenode > div { + display: inline-block; + text-align: right; + float: right; + padding-left: 10px; + position: relative; + top: -14px; +} + +#tree { + padding-right: 10px; + margin-right: 10px; + border-right: 1px solid black; + float: left; +} diff --git a/hServer/packages/hcore/templates/browse.html b/hServer/packages/hcore/templates/browse.html new file mode 100644 index 0000000..6a4db50 --- /dev/null +++ b/hServer/packages/hcore/templates/browse.html @@ -0,0 +1,40 @@ +<%frame frame_html%> + +
Pfad: <%=request.self(-1,trail=True)%>
+
+
+ <%if not self._aq_parent is None%> + + <%end%> + <%if self._aq_parent is None%> +
 
+ <%end%> + +
+
+
+
+ +
+
+ + <%iterate node self.children()%> +
<%=node%>
<%=getattr(self,node).__class__.__name__%>
+ <%end%> +
+
+ <%=self._aq_name%> (<%=self.__class__.__name__%>)
+
+ [ ANZEIGEN ] + <%if not self._aq_name=="/"%> + [ ENTFERNEN ] + <%end%> +
+
+ <%if hasattr(self,"_wo_manage")%> + <% self._wo_manage(request,self) %> + <%end%> +
+
diff --git a/hServer/packages/hcore/templates/control.html b/hServer/packages/hcore/templates/control.html new file mode 100644 index 0000000..1b82806 --- /dev/null +++ b/hServer/packages/hcore/templates/control.html @@ -0,0 +1,14 @@ +<%frame frame_html%> + +<% + +if "shutdown" in request.getForm() and request.getForm()["shutdown"].value()=="yes": + self.server().shutdown() + +%> + +<%if "shutdown" in request.getForm() and request.getForm()["shutdown"].value()=="yes" %> +
Server will shutdown after this request.
+<%end%> + +
Shutdown
diff --git a/hServer/packages/hcore/templates/frame.html b/hServer/packages/hcore/templates/frame.html new file mode 100644 index 0000000..f936371 --- /dev/null +++ b/hServer/packages/hcore/templates/frame.html @@ -0,0 +1,22 @@ + + + HServer Management + + + + + + +
+ <%content%> +
+ + + diff --git a/hServer/packages/hcore/templates/list_wo.html b/hServer/packages/hcore/templates/list_wo.html new file mode 100644 index 0000000..26963b0 --- /dev/null +++ b/hServer/packages/hcore/templates/list_wo.html @@ -0,0 +1,11 @@ +
+
<%=self._aq_name%>
+
[<%=escape(self.__class__.__name__)%>]
+
+ [ ADD HERE ] + +
+ <%iterate wobj self.children()%> + <%include ("list_wo.html",getattr(self,wobj))%> + <%end%> +
diff --git a/hServer/packages/hcore/templates/overview.html b/hServer/packages/hcore/templates/overview.html new file mode 100644 index 0000000..fabb04a --- /dev/null +++ b/hServer/packages/hcore/templates/overview.html @@ -0,0 +1,3 @@ +<%frame frame_html%> + + diff --git a/hServer/packages/hcore/templates/packages.html b/hServer/packages/hcore/templates/packages.html new file mode 100644 index 0000000..be94545 --- /dev/null +++ b/hServer/packages/hcore/templates/packages.html @@ -0,0 +1,38 @@ +<%frame frame_html%> +<% + +if ("reload" in request.getForm().keys()): + which = request.getForm()["reload"].value() + if (which == "_all"): + l = self.server().packagemanager().packages().keys() + else: + l = (which,) + + for p in l: + self.server().packagemanager().packages()[ p ].reload() + + request.redirect(request.self()) + +%> +
Loaded Packages: (reload)
+<%iterate _p self.server().packagemanager().packages().keys()%> +<% p = self.server().packagemanager().packages()[_p] %> +
+
<%=_p%> (reload)
+
Exports:
+ <%iterate e p.exports()%> + <% exp = p.exports()[e] %> +
<%=e%>: <%=escape("%s" % (exp,))%>
+ <%end%> +
+ +
Contents:
+ <%iterate e p.modules()%> + <% exp = p.modules()[e] %> +
<%=e%>: <%=escape("%s" % (exp,))%>
+ <%end%> +
+ +
+<%end%> +
diff --git a/hServer/packages/hcore/templates/stat.html b/hServer/packages/hcore/templates/stat.html new file mode 100644 index 0000000..e69de29 diff --git a/hServer/packages/hcore/templates/style.css b/hServer/packages/hcore/templates/style.css new file mode 100644 index 0000000..ad62ba5 --- /dev/null +++ b/hServer/packages/hcore/templates/style.css @@ -0,0 +1,80 @@ +body,p,div { + font-family: "DejaVu Sans","Helvetica", "Arial", "Sans"; +} + +#menu { + width: 90%; + + border-bottom: 1px solid black; + margin-bottom: 40px; +} + +#menu>a { + display: inline; +} + +#menu>a>div { + padding: 10px; + display: inline-block; +} + +.block { + display: block; + border: 1px solid black; + background-color: #C0C0C0; + + margin-bottom: 10px; +} + +.headline { + width: 100%; + border-bottom: 1px solid #404040; + background-color: #4040FF; + margin-bottom: 5px; +} + +.listitem { + padding-left: 5px; +} + +.button { + background-color: #00D0D0; + padding: 20px; + display: inline-block; + border: 1px solid #008080; +} + +#treeitem { + x-border-left: 1px solid blue; + border-top: 1px solid blue; + padding-left: 5px; +} + +.cell { + display: inline-block; + width: 140px; +} + +#icon { + width: 24px; + height: 24px; +} + +.wo_frame { + position: relative; + left: 10px; + display: block; + margin-top: 5px; + border-top: 1px solid gray; +} + +.wo_name { + display: inline-block; + position: relative; +} + +.wo_class,.wo_actions { + display: inline-block; + position: relative; + left: 50px; +} diff --git a/hServer/packages/hcore/templates/tree.html b/hServer/packages/hcore/templates/tree.html new file mode 100644 index 0000000..40de3b2 --- /dev/null +++ b/hServer/packages/hcore/templates/tree.html @@ -0,0 +1,30 @@ +<%frame frame_html%> + + + +
Tree Setup

+
+ +<% +path = () +objs = self.list_webobjects() +%> + + + +
+ +
Neues Objekt: + + +
+
+ + <%include ("list_wo.html",self.server().aq_root())%> + +
+ diff --git a/hServer/packages/hcore/templates/treelevel.html b/hServer/packages/hcore/templates/treelevel.html new file mode 100644 index 0000000..c11de7b --- /dev/null +++ b/hServer/packages/hcore/templates/treelevel.html @@ -0,0 +1,15 @@ + +
+
<%=self[0]%>
+
<%=self[1].__class__.__name__%>
+
+ +
+<%iterate n self[2]%> + <%include ('treelevel_html', n)%> +<%end%> + +
+ + + diff --git a/hServer/packages/hcore/webmanager.py b/hServer/packages/hcore/webmanager.py new file mode 100644 index 0000000..65ced60 --- /dev/null +++ b/hServer/packages/hcore/webmanager.py @@ -0,0 +1,67 @@ +import Templates +import hserver.api +from hwo import NoPersistence + +import browser + +class WebManager(hserver.api.WebObject,NoPersistence): + + def __init__(self,server): + hserver.api.WebObject.__init__(self) + self.__server = server + self.setDefault("overview") + + def server(self): + return self.__server + + def list_webobjects(self): + r = [] + #exp = self.__server.exports() + exp = hserver.api.__dict__ + for t in exp.values(): + try: + if (issubclass(t,hserver.api.WebObject)): + r.append(t) + except: + pass + return r + + def list_paths(self,folder = None, path = "", recurse = 100): + if recurse <= 0: + return [] + + if folder is None: + folder = self.__server.getRoot() + path = "" + + return [ "/", folder, self.list_paths( folder, "", 100), "" ] + + ls = [] + for c in folder.children(): + co = folder[c] + cpath = "%s/%s" % (path,c) + ls.append( [ cpath, co, self.list_paths( co, cpath, recurse - 1), c ] ) + + return ls + + def _addObject(self, request, o): + f = request.getForm() + + if ("oname" in f) and ("oclass" in f): + oclass = getattr( hserver.api , f["oclass"].value() ) + i = oclass() + + setattr( self.server().getRoot(), f["oname"].value(), i ) + + request.redirect( request.pathwalker().walked(-1) + "/tree" ) + + + addObject = hserver.api.WebCallable(method=_addObject) + + + overview = Templates.overview_html + packages = Templates.packages_html + control = Templates.control_html + tree = Templates.tree_html + + api = Templates.api_js