Initial Commit
commit
b821c1da4a
|
@ -0,0 +1,8 @@
|
|||
.DS_Store
|
||||
|
||||
**/*.pyc
|
||||
|
||||
#hServer/packages/*
|
||||
!hServer/packages/hcore
|
||||
#hServer/DiskSync/*
|
||||
#hServer/objects/*
|
|
@ -0,0 +1,211 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CodeLite_Project Name="hServer" InternalType="">
|
||||
<Reconciliation>
|
||||
<Regexes/>
|
||||
<Excludepaths/>
|
||||
<Ignorefiles/>
|
||||
<Extensions>
|
||||
<![CDATA[cpp;c;h;hpp;xrc;wxcp;fbp;py;]]>
|
||||
</Extensions>
|
||||
<Topleveldir>../hserver</Topleveldir>
|
||||
</Reconciliation>
|
||||
<Description/>
|
||||
<Dependencies/>
|
||||
<Settings Type="Executable">
|
||||
<GlobalSettings>
|
||||
<Compiler Options="" C_Options="" Assembler="">
|
||||
<IncludePath Value="."/>
|
||||
</Compiler>
|
||||
<Linker Options="">
|
||||
<LibraryPath Value="."/>
|
||||
</Linker>
|
||||
<ResourceCompiler Options=""/>
|
||||
</GlobalSettings>
|
||||
<Configuration Name="Debug" CompilerType="GCC" DebuggerType="GNU gdb debugger" Type="Executable" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
|
||||
<Compiler Options="-g -Wall" C_Options="" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
|
||||
<IncludePath Value="."/>
|
||||
</Compiler>
|
||||
<Linker Options="-O0" Required="yes">
|
||||
<LibraryPath Value="."/>
|
||||
<LibraryPath Value="Debug"/>
|
||||
</Linker>
|
||||
<ResourceCompiler Options="" Required="no"/>
|
||||
<General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="./Debug" Command="./$(ProjectName)" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="./Debug" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
|
||||
<Environment EnvVarSetName="<Use Workspace Settings>" DbgSetName="<Use Global Settings>">
|
||||
<![CDATA[]]>
|
||||
</Environment>
|
||||
<Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
|
||||
<DebuggerSearchPaths/>
|
||||
<PostConnectCommands/>
|
||||
<StartupCommands/>
|
||||
</Debugger>
|
||||
<PreBuild/>
|
||||
<PostBuild/>
|
||||
<CustomBuild Enabled="no">
|
||||
<RebuildCommand/>
|
||||
<CleanCommand/>
|
||||
<BuildCommand/>
|
||||
<PreprocessFileCommand/>
|
||||
<SingleFileCommand/>
|
||||
<MakefileGenerationCommand/>
|
||||
<ThirdPartyToolName/>
|
||||
<WorkingDirectory/>
|
||||
</CustomBuild>
|
||||
<AdditionalRules>
|
||||
<CustomPostBuild/>
|
||||
<CustomPreBuild/>
|
||||
</AdditionalRules>
|
||||
<Completion EnableCpp11="no" EnableCpp14="no">
|
||||
<ClangCmpFlagsC/>
|
||||
<ClangCmpFlags/>
|
||||
<ClangPP/>
|
||||
<SearchPaths/>
|
||||
</Completion>
|
||||
</Configuration>
|
||||
</Settings>
|
||||
<VirtualDirectory Name="hServer">
|
||||
<VirtualDirectory Name="hserver">
|
||||
<File Name="hServer/hserver/__init__.py"/>
|
||||
<File Name="hServer/hserver/request.py"/>
|
||||
<File Name="hServer/hserver/server.py"/>
|
||||
<File Name="hServer/hserver/headers.py"/>
|
||||
<File Name="hServer/hserver/systemplates.py"/>
|
||||
<File Name="hServer/hserver/utils.py"/>
|
||||
<File Name="hServer/hserver/mime.py"/>
|
||||
<File Name="hServer/hserver/mimeheaders.py"/>
|
||||
<File Name="hServer/hserver/formdata.py"/>
|
||||
<File Name="hServer/hserver/templates.py"/>
|
||||
<VirtualDirectory Name="packages">
|
||||
<File Name="hServer/hserver/packages/__init__.py"/>
|
||||
<File Name="hServer/hserver/packages/package.py"/>
|
||||
</VirtualDirectory>
|
||||
<File Name="hServer/hserver/templatemod.py"/>
|
||||
<VirtualDirectory Name="configuration"/>
|
||||
<VirtualDirectory Name="ostore"/>
|
||||
<VirtualDirectory Name="api">
|
||||
<File Name="hServer/hserver/api/__init__.py"/>
|
||||
<File Name="hServer/hserver/api/fileobject.py"/>
|
||||
<File Name="hServer/hserver/api/simpleobject.py"/>
|
||||
<File Name="hServer/hserver/api/webobject.py"/>
|
||||
</VirtualDirectory>
|
||||
<File Name="hServer/hserver/run.py"/>
|
||||
<VirtualDirectory Name="templates.src">
|
||||
<File Name="hServer/hserver/templates.src/so_updates.html"/>
|
||||
</VirtualDirectory>
|
||||
<File Name="hServer/hserver/exceptions.py"/>
|
||||
</VirtualDirectory>
|
||||
<VirtualDirectory Name="doc">
|
||||
<File Name="hServer/doc/templates.txt"/>
|
||||
</VirtualDirectory>
|
||||
<VirtualDirectory Name="packages">
|
||||
<VirtualDirectory Name="hserver-h_wo_image">
|
||||
<VirtualDirectory Name="templates"/>
|
||||
</VirtualDirectory>
|
||||
<VirtualDirectory Name="h_asterisk">
|
||||
<VirtualDirectory Name="asterisk">
|
||||
<File Name="hServer/packages/h_asterisk/asterisk/__init__.py"/>
|
||||
<File Name="hServer/packages/h_asterisk/asterisk/exceptions.py"/>
|
||||
<File Name="hServer/packages/h_asterisk/asterisk/connection.py"/>
|
||||
<File Name="hServer/packages/h_asterisk/asterisk/asterisk.py"/>
|
||||
</VirtualDirectory>
|
||||
<File Name="hServer/packages/h_asterisk/h_asterisk.py"/>
|
||||
</VirtualDirectory>
|
||||
<VirtualDirectory Name="h_astfax">
|
||||
<VirtualDirectory Name="templates">
|
||||
<File Name="hServer/packages/h_astfax/templates/status.html"/>
|
||||
<File Name="hServer/packages/h_astfax/templates/view.html"/>
|
||||
<File Name="hServer/packages/h_astfax/templates/page.html"/>
|
||||
<File Name="hServer/packages/h_astfax/templates/child.html"/>
|
||||
<File Name="hServer/packages/h_astfax/templates/view-row-page.html"/>
|
||||
<File Name="hServer/packages/h_astfax/templates/queues.html"/>
|
||||
</VirtualDirectory>
|
||||
<File Name="hServer/packages/h_astfax/tifftools.py"/>
|
||||
<File Name="hServer/packages/h_astfax/FaxJob.py"/>
|
||||
<File Name="hServer/packages/h_astfax/package.conf"/>
|
||||
<File Name="hServer/packages/h_astfax/WebFaxJob.py"/>
|
||||
</VirtualDirectory>
|
||||
<VirtualDirectory Name="hcore">
|
||||
<VirtualDirectory Name="templates">
|
||||
<File Name="hServer/packages/hcore/templates/404.html"/>
|
||||
<File Name="hServer/packages/hcore/templates/overview.html"/>
|
||||
<File Name="hServer/packages/hcore/templates/frame.html"/>
|
||||
<File Name="hServer/packages/hcore/templates/packages.html"/>
|
||||
<File Name="hServer/packages/hcore/templates/style.css"/>
|
||||
<File Name="hServer/packages/hcore/templates/stat.html"/>
|
||||
<File Name="hServer/packages/hcore/templates/control.html"/>
|
||||
<File Name="hServer/packages/hcore/templates/tree.html"/>
|
||||
<File Name="hServer/packages/hcore/templates/treelevel.html"/>
|
||||
<File Name="hServer/packages/hcore/templates/api.js"/>
|
||||
<File Name="hServer/packages/hcore/templates/list_wo.html"/>
|
||||
<File Name="hServer/packages/hcore/templates/browse.html"/>
|
||||
<File Name="hServer/packages/hcore/templates/browse.css"/>
|
||||
</VirtualDirectory>
|
||||
<File Name="hServer/packages/hcore/core.py"/>
|
||||
<VirtualDirectory Name="coremod">
|
||||
<File Name="hServer/packages/hcore/coremod/__init__.py"/>
|
||||
<File Name="hServer/packages/hcore/coremod/exceptions.py"/>
|
||||
</VirtualDirectory>
|
||||
<File Name="hServer/packages/hcore/webmanager.py"/>
|
||||
<File Name="hServer/packages/hcore/package.conf"/>
|
||||
<File Name="hServer/packages/hcore/browser.py"/>
|
||||
</VirtualDirectory>
|
||||
<VirtualDirectory Name="h_endkontrolle">
|
||||
<File Name="hServer/packages/h_endkontrolle/endkontrolle.py"/>
|
||||
<VirtualDirectory Name="templates">
|
||||
<File Name="hServer/packages/h_endkontrolle/templates/frame.html"/>
|
||||
<File Name="hServer/packages/h_endkontrolle/templates/index.html"/>
|
||||
<File Name="hServer/packages/h_endkontrolle/templates/style.css"/>
|
||||
<File Name="hServer/packages/h_endkontrolle/templates/parts.html"/>
|
||||
<File Name="hServer/packages/h_endkontrolle/templates/partdetail.html"/>
|
||||
<File Name="hServer/packages/h_endkontrolle/templates/packaging.html"/>
|
||||
<File Name="hServer/packages/h_endkontrolle/templates/partprint.html"/>
|
||||
</VirtualDirectory>
|
||||
<File Name="hServer/packages/h_endkontrolle/package.conf"/>
|
||||
</VirtualDirectory>
|
||||
<VirtualDirectory Name="WebAlbum"/>
|
||||
<VirtualDirectory Name="h_wo_image">
|
||||
<File Name="hServer/packages/h_wo_image/package.conf"/>
|
||||
<File Name="hServer/packages/h_wo_image/h_wo_image.py"/>
|
||||
</VirtualDirectory>
|
||||
<VirtualDirectory Name="derkleinebasar">
|
||||
<VirtualDirectory Name="templates">
|
||||
<File Name="hServer/packages/derkleinebasar/templates/layout.html"/>
|
||||
<File Name="hServer/packages/derkleinebasar/templates/layout.css"/>
|
||||
<File Name="hServer/packages/derkleinebasar/templates/index.html"/>
|
||||
<File Name="hServer/packages/derkleinebasar/templates/list_verk.html"/>
|
||||
<File Name="hServer/packages/derkleinebasar/templates/print_tags.html"/>
|
||||
<File Name="hServer/packages/derkleinebasar/templates/search.html"/>
|
||||
<File Name="hServer/packages/derkleinebasar/templates/list_artikel.html"/>
|
||||
<File Name="hServer/packages/derkleinebasar/templates/verk_prov.html"/>
|
||||
<File Name="hServer/packages/derkleinebasar/templates/artikel_display.html"/>
|
||||
<File Name="hServer/packages/derkleinebasar/templates/verk_display.html"/>
|
||||
<File Name="hServer/packages/derkleinebasar/templates/artikel_tag.html"/>
|
||||
<File Name="hServer/packages/derkleinebasar/templates/print.css"/>
|
||||
<File Name="hServer/packages/derkleinebasar/templates/verkauf.html"/>
|
||||
<File Name="hServer/packages/derkleinebasar/templates/quittung.html"/>
|
||||
<File Name="hServer/packages/derkleinebasar/templates/common.css"/>
|
||||
</VirtualDirectory>
|
||||
<File Name="hServer/packages/derkleinebasar/basar.py"/>
|
||||
<File Name="hServer/packages/derkleinebasar/artikel.py"/>
|
||||
<File Name="hServer/packages/derkleinebasar/verkaeufer.py"/>
|
||||
<File Name="hServer/packages/derkleinebasar/package.conf"/>
|
||||
<File Name="hServer/packages/derkleinebasar/verkauf.py"/>
|
||||
</VirtualDirectory>
|
||||
</VirtualDirectory>
|
||||
<VirtualDirectory Name="hwo">
|
||||
<File Name="hServer/hwo/Proxy.py"/>
|
||||
<File Name="hServer/hwo/__init__.py"/>
|
||||
<File Name="hServer/hwo/Logging.py"/>
|
||||
<File Name="hServer/hwo/objectbroker.py"/>
|
||||
<File Name="hServer/hwo/objectstore.py"/>
|
||||
<File Name="hServer/hwo/persistence.py"/>
|
||||
<File Name="hServer/hwo/aquisition.py"/>
|
||||
</VirtualDirectory>
|
||||
<File Name="hServer/HServer.py"/>
|
||||
<VirtualDirectory Name="DiskSync">
|
||||
<File Name="hServer/DiskSync/ROOT"/>
|
||||
</VirtualDirectory>
|
||||
<VirtualDirectory Name="objects"/>
|
||||
</VirtualDirectory>
|
||||
<Dependencies Name="Debug"/>
|
||||
</CodeLite_Project>
|
|
@ -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()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
Simple Python Template Engine
|
||||
-----------------------------
|
||||
|
||||
<WS> HEX: 0x0D,0x0A,0x20
|
||||
|
||||
<%[action]<WS>[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',<self-ref>) oder 'template-name'
|
||||
|
||||
Zukünftig:
|
||||
----------
|
||||
iterate [expr] = <iterator> <iteration>
|
||||
end Markiert Ende eines Blocks (z.B. iterate)
|
||||
|
||||
|
||||
|
||||
Globale Funktionen:
|
||||
|
||||
include(<templatename>,<selfref>) Fügt das Template <templatename> mit der "self" referenz <selfref> an der aktuellen Position ein
|
||||
print(<text>) Gibt <text> an der aktuellen Position aus
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
@ -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) )
|
|
@ -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("<html><head><title>No Content</title></head><body>Sorry, no content here!</body></html>")
|
||||
|
||||
|
||||
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("<html><head><title>No Content</title></head><body>Sorry, no content here!</body></html>")
|
||||
|
||||
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
|
|
@ -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
|
|
@ -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)))
|
||||
|
||||
|
||||
|
|
@ -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))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
from hserver.packages.package import Package,PackageManager
|
||||
|
|
@ -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))
|
|
@ -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("<Request(M:%s U:%s)>" % (self.REQUEST_METHOD,self.REQUEST_URI))
|
||||
|
||||
return b.getvalue()
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import hserver
|
||||
import os.path
|
||||
|
||||
templates = hserver.TemplateModule(path="%s/templates.src" % (os.path.dirname(__file__),))
|
|
@ -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 )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import hserver
|
||||
|
||||
|
||||
tmpl_exception = """
|
||||
<html>
|
||||
<head>
|
||||
<title>HServer Exception</title>
|
||||
<style>
|
||||
body,p,div {
|
||||
font-family: "DejaVu Sans","Helvetica", "Arial", "Sans";
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>HServer Exception</h1>
|
||||
<p>There was an exception raised, while handling your request!</p>
|
||||
<p>Eine Ausnahme trat auf, während die Anfrage bearbeitet wurde!</p>
|
||||
<div>
|
||||
<%
|
||||
tracelist = traceback.extract_tb( self.__traceback__ )
|
||||
%>
|
||||
<%iterate trace tracelist%>
|
||||
<div>
|
||||
<b><%=trace[0]%>:<%=trace[1]%></b> in <i><%=trace[2]%></i><br/>
|
||||
<%=trace[3]%><br/><br/>
|
||||
</div>
|
||||
<%end%>
|
||||
</div>
|
||||
</body>
|
||||
</html>"""
|
||||
|
|
@ -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 "<TemplateModule (%s)>" % (", ".join(cl))
|
|
@ -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}<p>{1}</p>".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 "<TemplateSegment>"
|
||||
|
||||
|
||||
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 "<TemplateGroupSegment( %s )>" % (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 "<TemplateTextSegment>"
|
||||
|
||||
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 "<TemplateCodeSegment(%s)>" %(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 "<TemplateIterateSegment( %s=%s : %s )>" % (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 "<TemplateIfSegment( %s )>" % (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 "<TemplateIncludeSegment(%s)>" % (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 "<TemplateContentSegment(%s)>" % (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 <tag> to a list of [ <action>, <expr> ]"
|
||||
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("<!--INCLUDE: %s" % (expr,))
|
||||
child = self.__provider.provide( expr[0] )
|
||||
cenv = dict( self.env )
|
||||
|
||||
self.__content.write( child.run( expr[1], cenv) )
|
||||
|
||||
def escape(self,t):
|
||||
return t.replace("\\","\\\\").replace("\"","\\\"")
|
||||
|
||||
def __call__(self,request, o = None, output=None):
|
||||
if output is None:
|
||||
output = request.getContentFile()
|
||||
self.run( o=o, env = { "request": request },outfile=output)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<form action="">
|
||||
<div>so_updates</div>
|
||||
</form>
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
|
||||
class StreamTokenizer:
|
||||
|
||||
WHITESPACE = [' ','\n','\r','\t','\d']
|
||||
|
||||
def __init__(self,stream):
|
||||
self.__stream = stream
|
||||
|
||||
def read(self,len = 1):
|
||||
self.__stream.read(len)
|
||||
|
||||
def readToSeparator(self,separator = WHITESPACE):
|
||||
token = bytearray()
|
||||
c = self.__stream.read(1)
|
||||
while (not c is None) and (len(c) != 0) and (not c in separator):
|
||||
token.append(c)
|
||||
c = self.__stream.read(1)
|
||||
|
||||
return token
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import sys
|
||||
import datetime
|
||||
|
||||
LLERROR = 0
|
||||
LLINFO = 1
|
||||
LLDETAIL = 2
|
||||
|
||||
LLDEBUGCALL = 5
|
||||
LLDEBUG = 10
|
||||
|
||||
|
||||
|
||||
class Logger:
|
||||
|
||||
def __init__(self,target = sys.stderr,maxlevel = 1):
|
||||
self.__target = target
|
||||
|
||||
def log(self,msg,level = 0,o = None):
|
||||
dt = datetime.datetime.today()
|
||||
self.__target.write("%s: [%s] %s\n" % (dt,level,msg))
|
||||
self.__target.flush()
|
||||
|
||||
|
||||
|
||||
|
||||
default_logging = Logger()
|
||||
|
||||
|
||||
def log(msg,level = 0):
|
||||
default_logging.log(msg,level)
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
def getter(attrib):
|
||||
return lambda self, *args, **kwargs: getattr(object.__getattribute__( self, "_o"), attrib)(*args, **kwargs)
|
||||
|
||||
|
||||
class InterceptedProxy:
|
||||
_special_names=[
|
||||
'__abs__', '__add__', '__and__', '__call__', '__cmp__', '__coerce__',
|
||||
'__contains__', '__delitem__', '__delslice__', '__div__', '__divmod__',
|
||||
'__eq__', '__float__', '__floordiv__', '__ge__', '__getitem__',
|
||||
'__getslice__', '__gt__', '__hash__', '__hex__', '__iadd__', '__iand__',
|
||||
'__idiv__', '__idivmod__', '__ifloordiv__', '__ilshift__', '__imod__',
|
||||
'__imul__', '__int__', '__invert__', '__ior__', '__ipow__', '__irshift__',
|
||||
'__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__', '__len__',
|
||||
'__long__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__',
|
||||
'__neg__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__',
|
||||
'__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__',
|
||||
'__repr__', '__reversed__', '__rfloorfiv__', '__rlshift__', '__rmod__',
|
||||
'__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__',
|
||||
'__rtruediv__', '__rxor__', '__setitem__', '__setslice__', '__sub__',
|
||||
'__truediv__', '__xor__', 'next',
|
||||
]
|
||||
|
||||
def _get_proxy_cls(cls,obj):
|
||||
ocls = obj.__class__
|
||||
ns = {}
|
||||
|
||||
for n in InterceptedProxy._special_names:
|
||||
if (hasattr(ocls, n)):
|
||||
ns[n] = getter(n)
|
||||
return type( "InterceptedProxy(%s)" % (ocls.__name__,), (cls,), ns )
|
||||
|
||||
def __new__(cls,obj,listener):
|
||||
pcls = InterceptedProxy._get_proxy_cls(cls,obj)
|
||||
|
||||
inst = object.__new__( pcls )
|
||||
object.__setattr__( inst, "_o", obj)
|
||||
object.__setattr__( inst, "_l", listener)
|
||||
|
||||
return inst
|
||||
|
||||
def __getattribute__(self,name):
|
||||
v = getattr( object.__getattribute__( self, "_o"), name )
|
||||
return v
|
||||
|
||||
def __setattr__(self,name,value):
|
||||
o = object.__getattribute__( self, "_o")
|
||||
setattr( o, name, value )
|
||||
object.__getattribute__( self, "_l").notify("__setattr__",o,name,value)
|
||||
|
||||
def __delattr__(self,name):
|
||||
delattr( object.__getattribute__( self, "_o"), name )
|
||||
|
||||
def __nonzero__(self):
|
||||
return bool(object.__getattribute__(self, "_o"))
|
||||
def __str__(self):
|
||||
return str(object.__getattribute__(self, "_o"))
|
||||
def __repr__(self):
|
||||
return repr(object.__getattribute__(self, "_o"))
|
||||
def __dir__(self):
|
||||
return dir( object.__getattribute__(self, "_o") )
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import hwo.Logging
|
||||
|
||||
from hwo.persistence import Persistence,NoPersistence
|
||||
|
||||
from hwo.objectstore import DiscObjectStore
|
||||
from hwo.objectbroker import ObjectBroker
|
||||
from hwo.aquisition import Aquisition,AquisitionProxy
|
||||
|
||||
import hwo.Proxy
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
import collections
|
||||
|
||||
__doc__ = """Einfache Objekt Aquisition für Python."""
|
||||
|
||||
class Aquisition:
|
||||
"""Markiert ein Objekt als Ziel von Aquisition durch AquisitionProxy"""
|
||||
pass
|
||||
|
||||
|
||||
def caller(inst,a):
|
||||
return lambda *args,**kwargs: a.__func__(inst,*args,**kwargs)
|
||||
|
||||
def call(self,method,*args,**kwargs):
|
||||
m = getattr(object.__getattribute__( self, "_o"), method)
|
||||
if hasattr(m,"__func__"):
|
||||
return m.__func__(self,*args,**kwargs)
|
||||
else:
|
||||
return m(*args,**kwargs)
|
||||
|
||||
def getter(attrib):
|
||||
return lambda self, *args, **kwargs: call(self,attrib,*args, **kwargs)
|
||||
|
||||
if hasattr(m, "__func__"):
|
||||
return lambda self, *args, **kwargs: m.__func__(self, *args, **kwargs)
|
||||
else:
|
||||
return lambda self, *args, **kwargs: m(*args, **kwargs)
|
||||
|
||||
|
||||
class AquisitionProxy:
|
||||
"""Basisobjekt für Aquisition."""
|
||||
_special_names=[
|
||||
'__abs__', '__add__', '__and__', '__call__', '__cmp__', '__coerce__',
|
||||
'__contains__', '__delitem__', '__delslice__', '__div__', '__divmod__',
|
||||
'__eq__', '__float__', '__floordiv__', '__ge__', '__getitem__',
|
||||
'__getslice__', '__gt__', '__hash__', '__hex__', '__iadd__', '__iand__',
|
||||
'__idiv__', '__idivmod__', '__ifloordiv__', '__ilshift__', '__imod__',
|
||||
'__imul__', '__int__', '__invert__', '__ior__', '__ipow__', '__irshift__',
|
||||
'__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__', '__len__',
|
||||
'__long__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__',
|
||||
'__neg__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__',
|
||||
'__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__',
|
||||
'__repr__', '__reversed__', '__rfloorfiv__', '__rlshift__', '__rmod__',
|
||||
'__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__',
|
||||
'__rtruediv__', '__rxor__', '__setitem__', '__setslice__', '__sub__',
|
||||
'__truediv__', '__xor__', 'next',
|
||||
]
|
||||
|
||||
def _get_proxy_cls(cls,obj):
|
||||
ocls = obj.__class__
|
||||
ns = {}
|
||||
_methods = {}
|
||||
|
||||
for n in AquisitionProxy._special_names:
|
||||
if (hasattr(ocls, n)):
|
||||
ns[n] = getter(n)
|
||||
|
||||
return type( "AProxy(%s)" % (ocls.__name__,), (cls,), ns )
|
||||
|
||||
|
||||
def __new__(cls,obj,p = None,aq_name=None,aq_root=None):
|
||||
pcls = AquisitionProxy._get_proxy_cls(cls,obj)
|
||||
|
||||
inst = object.__new__( pcls )
|
||||
|
||||
_methods = {}
|
||||
for n in dir(obj):
|
||||
# print("AQ_ATTR: %s" % (n,))
|
||||
a = getattr(obj,n)
|
||||
if isinstance( a, collections.Callable ) and hasattr( a, "__func__" ): # and not hasattr( AquisitionProxy, n ):
|
||||
# print("AQ_METHOD: %s = %s" % (n,a))
|
||||
_methods[n] = caller(inst,a)
|
||||
|
||||
object.__setattr__( inst, "_methods", _methods )
|
||||
object.__setattr__( inst, "_o", obj)
|
||||
object.__setattr__( inst, "_p", p)
|
||||
object.__setattr__( inst, "_aq_name", aq_name)
|
||||
|
||||
if (aq_root is None):
|
||||
aq_root = inst
|
||||
|
||||
object.__setattr__( inst, "_aq_root", aq_root)
|
||||
|
||||
return inst
|
||||
|
||||
def __getattribute__(self,name):
|
||||
v = None
|
||||
# print("AQN: %s" % (name,))
|
||||
|
||||
if name.startswith("_aq_"):
|
||||
if (name == "_aq_parent"):
|
||||
return object.__getattribute__( self, "_p")
|
||||
# return AquisitionProxy( p, self, aq_name=p._aq_name, aq_root=self._aq_root )
|
||||
if (name == "_aq_name"):
|
||||
n = object.__getattribute__( self, "_aq_name")
|
||||
if n is None:
|
||||
return "/"
|
||||
return n
|
||||
if (name == "_aq_object"):
|
||||
return object.__getattribute__( self, "_o")
|
||||
|
||||
return object.__getattribute__( self, name )
|
||||
|
||||
_methods = object.__getattribute__(self,"_methods")
|
||||
if name in _methods:
|
||||
return _methods[name]
|
||||
|
||||
try:
|
||||
v = getattr( object.__getattribute__( self, "_o"), name )
|
||||
except AttributeError as ae:
|
||||
try:
|
||||
print("AQN_PARENT: %s %s" % (object.__getattribute__( self, "_p"), name))
|
||||
v = getattr( object.__getattribute__( self, "_p"), name)
|
||||
if (isinstance(v, AquisitionProxy)):
|
||||
v = object.__getattribute__( v, "_o" )
|
||||
except AttributeError as ae2:
|
||||
raise ae2
|
||||
|
||||
if isinstance( v, Aquisition ):
|
||||
v = AquisitionProxy( v, self, aq_name=name, aq_root=self._aq_root )
|
||||
|
||||
return v
|
||||
|
||||
def __setattr__(self,name,value):
|
||||
setattr( object.__getattribute__( self, "_o"), name, value )
|
||||
|
||||
def __delattr__(self,name):
|
||||
delattr( object.__getattribute__( self, "_o"), name )
|
||||
|
||||
def __nonzero__(self):
|
||||
return bool(object.__getattribute__(self, "_o"))
|
||||
def __str__(self):
|
||||
return str(object.__getattribute__(self, "_o"))
|
||||
def __repr__(self):
|
||||
return repr(object.__getattribute__(self, "_o"))
|
||||
|
||||
def __dir__(self):
|
||||
return dir( object.__getattribute__(self, "_o") )
|
||||
|
||||
def dir(self,cls):
|
||||
realcls = object.__getattribute__( self, "__class__" )
|
||||
|
||||
ls = []
|
||||
|
||||
for an in dir(self):
|
||||
if issubclass( getattr( self, an ).__class__, cls):
|
||||
ls.append(an)
|
||||
|
||||
if issubclass(realcls,AquisitionProxy):
|
||||
p = object.__getattribute__( self, "_p")
|
||||
if not p is None:
|
||||
for an in AquisitionProxy.dir(p, cls):
|
||||
if not an in ls:
|
||||
ls.append( an )
|
||||
|
||||
return ls
|
||||
|
||||
def _aq_path(self):
|
||||
if (self._aq_name is None) or (self._aq_parent is None):
|
||||
return ""
|
||||
return "%s/%s" % (self._aq_parent._aq_path(),self._aq_name)
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
import weakref
|
||||
import hwo
|
||||
import collections
|
||||
import pickle
|
||||
|
||||
from hwo.Logging import log,LLDEBUGCALL,LLDEBUG,LLINFO,LLERROR
|
||||
|
||||
def dump_state(state):
|
||||
print("Persistent ID: %s" % (state["pid"],))
|
||||
print("Type: %s.%s" % (state["module"],state["class"]))
|
||||
|
||||
print("Non-Persistent:")
|
||||
for n in state["fields"].keys():
|
||||
print("K: %s = %s" % (n,state["fields"][n]))
|
||||
|
||||
print("Persistent:")
|
||||
for n in state["pfields"].keys():
|
||||
print("K: %s = %s" % (n,state["pfields"][n]))
|
||||
print("")
|
||||
|
||||
def obj_getstate(o):
|
||||
if not isinstance(o, hwo.Persistence):
|
||||
raise TypeError("obj_getstate() needs Persistence object")
|
||||
|
||||
state = {}
|
||||
state["pid"] = hwo.Persistence._persistence_id( o )
|
||||
state["module"] = o.__class__.__module__
|
||||
state["class"] = o.__class__.__name__
|
||||
state["fields"] = {}
|
||||
state["pfields"] = {}
|
||||
state["pvalues"] = {}
|
||||
|
||||
|
||||
d = object.__getattribute__(o, "__dict__")
|
||||
for n in d.keys():
|
||||
a = getattr( o, n )
|
||||
if (not isinstance( a, collections.Callable)) or isinstance( a, object ):
|
||||
if (isinstance( a, hwo.NoPersistence)):
|
||||
state["fields"][n] = None
|
||||
elif (isinstance( a, hwo.Persistence)):
|
||||
state["pvalues"][n] = a
|
||||
state["pfields"][n] = hwo.Persistence._persistence_id( a )
|
||||
else:
|
||||
state["fields"][n] = a
|
||||
|
||||
return state
|
||||
|
||||
|
||||
class ObjectBroker:
|
||||
"""ObjectBroker """
|
||||
|
||||
def __init__(self, store={}):
|
||||
self.__store = store
|
||||
self.__cache = weakref.WeakValueDictionary()
|
||||
self.__unsaved = {}
|
||||
|
||||
log("ObjectBroker instantiated", LLDEBUGCALL)
|
||||
|
||||
def save(self,o,recursed=False):
|
||||
|
||||
if (o in self.__unsaved):
|
||||
return
|
||||
|
||||
state = obj_getstate(o)
|
||||
# dump_state( state )
|
||||
|
||||
self.__cache[ state["pid"] ] = o
|
||||
self.__unsaved[o] = state
|
||||
|
||||
for pn in state["pvalues"]:
|
||||
self.save( state["pvalues"][pn], recursed=True )
|
||||
|
||||
# dump_state(state)
|
||||
|
||||
if not recursed:
|
||||
|
||||
for n in list( self.__unsaved.keys() ):
|
||||
s = self.__unsaved[n]
|
||||
s["pvalues"] = None
|
||||
self.__store[ s["pid"] ] = pickle.dumps(s)
|
||||
del self.__unsaved[n]
|
||||
|
||||
return state["pid"]
|
||||
|
||||
def load(self,persistence_id):
|
||||
|
||||
if (persistence_id in self.__cache):
|
||||
o = self.__cache[persistence_id]
|
||||
if not o is None:
|
||||
return o
|
||||
|
||||
state = pickle.loads(self.__store[ persistence_id ])
|
||||
# dump_state(state)
|
||||
|
||||
m = __import__(state["module"],fromlist=[state["class"]])
|
||||
cls = getattr(m, state["class"] )
|
||||
|
||||
o = cls.__new__(cls)
|
||||
|
||||
self.__cache[ persistence_id ] = o
|
||||
|
||||
for n in state["fields"]:
|
||||
setattr( o, n, state["fields"][n] )
|
||||
|
||||
for n in state["pfields"]:
|
||||
print("SS: %s = %s" % (n,state["pfields"][n]))
|
||||
setattr( o, n, self.load( state["pfields"][n] ))
|
||||
|
||||
return o
|
||||
|
||||
|
||||
|
||||
def remove(self,o=None,persistence_id=None):
|
||||
pass
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import os
|
||||
|
||||
class DiscObjectStore:
|
||||
"""DiscObjectStore ist ein Mapping Objekt, welches ein Verzeichnis im Dateisystem als Speicher nutzt und somit persistent zwischen Programmstarts arbeitet"""
|
||||
def __init__(self,path = "./objects"):
|
||||
self._path = path
|
||||
self.check()
|
||||
|
||||
def check(self):
|
||||
if not os.path.exists( self._path ):
|
||||
os.makedirs( self._path )
|
||||
|
||||
def __contains__(self, name):
|
||||
return os.path.exists( "%s/%s" % (self._path, name))
|
||||
|
||||
def __getitem__(self, name):
|
||||
f = open("%s/%s" % (self._path, name), "rb")
|
||||
v = f.read()
|
||||
f.close()
|
||||
return v
|
||||
|
||||
def __setitem__(self, name, value):
|
||||
f = open("%s/%s" % (self._path, name), "wb")
|
||||
v = f.write(value)
|
||||
f.close()
|
|
@ -0,0 +1,11 @@
|
|||
import uuid
|
||||
|
||||
class Persistence:
|
||||
|
||||
def _persistence_id(self):
|
||||
if not hasattr(self, "__persistence_id__"):
|
||||
setattr( self, "__persistence_id__", uuid.uuid4().hex )
|
||||
return getattr( self, "__persistence_id__" )
|
||||
|
||||
class NoPersistence:
|
||||
pass
|
|
@ -0,0 +1,91 @@
|
|||
from hserver.api import WebObject,Persistence,WebFolder,WebCallable
|
||||
import hserver
|
||||
|
||||
import Templates
|
||||
import uuid
|
||||
import os
|
||||
import io
|
||||
import time
|
||||
|
||||
|
||||
class Artikel(WebObject,Persistence):
|
||||
|
||||
_public_names = {
|
||||
"bezeichnung": "",
|
||||
"bezeichnung2": "",
|
||||
"preis": 0.00,
|
||||
"beschreibung": "",
|
||||
"seriennummer": "",
|
||||
"bemerkungen": "",
|
||||
"verkauft": False,
|
||||
"bezahlt": False,
|
||||
"erloes": 0.00
|
||||
}
|
||||
_public_types = {
|
||||
"preis": float,
|
||||
"verkauft": bool,
|
||||
"bezahlt": bool,
|
||||
"erloes": float
|
||||
}
|
||||
|
||||
#tag = Templates.artikel_tag_html
|
||||
|
||||
def __init__(self,vid):
|
||||
WebObject.__init__(self)
|
||||
|
||||
self.id = uuid.uuid4().hex
|
||||
self.vid = vid
|
||||
self.update(None)
|
||||
|
||||
|
||||
def __call__(self,request,o=None):
|
||||
Templates.artikel_display_html(request,self)
|
||||
|
||||
def verkaeufer(self):
|
||||
vl = self._aq_parent._aq_parent.verkaeufer
|
||||
v = getattr( vl, self.vid, None)
|
||||
return v
|
||||
|
||||
def _tag(self,request,o=None):
|
||||
_io = io.StringIO()
|
||||
Templates.artikel_tag_html(request,o,output=_io)
|
||||
|
||||
if "printer" in request.getForm():
|
||||
prn = request.getForm()["printer"].value()
|
||||
else:
|
||||
prn = None
|
||||
|
||||
pcmd = None
|
||||
if prn in self.printers:
|
||||
pcmd = self.printers[prn]
|
||||
|
||||
print("TAG Print: {0} / {1}".format(prn,pcmd))
|
||||
|
||||
|
||||
tmphtml = "/tmp/print.{0}.html".format(time.time())
|
||||
tmppdf = tmphtml + ".pdf"
|
||||
|
||||
tmp = open(tmphtml,"w")
|
||||
tmp.write(_io.getvalue())
|
||||
tmp.close()
|
||||
|
||||
os.system("wkhtmltopdf -T 0 -B 0 -L 0 -R 0 --dpi 400 --print-media-type --page-width 96mm --page-height 48mm {0} {1}".format(tmphtml,tmppdf))
|
||||
#os.system("lpr -P SII_SLP440 {0}".format(tmppdf))
|
||||
if pcmd is None:
|
||||
request.reset()
|
||||
tp = open(tmppdf,"rb")
|
||||
pdf = tp.read()
|
||||
tp.close()
|
||||
|
||||
request.getBinaryContentFile().write(pdf)
|
||||
request.setResponseHeader("content-type","application/pdf")
|
||||
else:
|
||||
os.system(pcmd.format(tmppdf))
|
||||
request.redirect(request.self(-1))
|
||||
|
||||
tag = WebCallable(method=_tag)
|
||||
|
||||
def __str__(self):
|
||||
return self.bezeichnung
|
||||
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
from hserver.api import WebObject,Persistence,WebFolder,WebCallable
|
||||
import hserver
|
||||
|
||||
import Templates
|
||||
import uuid
|
||||
|
||||
from verkaeufer import Verkaeufer
|
||||
from artikel import Artikel
|
||||
from verkauf import Verkauf
|
||||
|
||||
import qrcode
|
||||
import qrcode.image.svg
|
||||
|
||||
import io
|
||||
|
||||
class KleinerBasar(WebObject,Persistence):
|
||||
|
||||
layout_css = Templates.layout_css
|
||||
|
||||
index = Templates.index_html
|
||||
|
||||
list_verk = Templates.list_verk_html
|
||||
list_artikel = Templates.list_artikel_html
|
||||
|
||||
print_tags = Templates.print_tags_html
|
||||
print_css = Templates.print_css
|
||||
|
||||
printers = {
|
||||
"SLP440": "lpr -P SII_SLP440 {0}",
|
||||
"SLP200": "lpr -P SII_SLP200 {0}",
|
||||
"PDF": None,
|
||||
"PDF (Server)": "open {0}"
|
||||
}
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.setDefault("index")
|
||||
self.artikel = WebFolder()
|
||||
self.verkaeufer = WebFolder()
|
||||
self.verkauf = WebFolder()
|
||||
self.tags = WebFolder()
|
||||
|
||||
def walk(self,request):
|
||||
if not hasattr(self,"verkauf"):
|
||||
self.verkauf = WebFolder()
|
||||
|
||||
request.app = request.self()
|
||||
WebObject.walk(self,request)
|
||||
|
||||
def _tags(self):
|
||||
l = []
|
||||
for n in range(128):
|
||||
l.append(uuid.uuid4())
|
||||
|
||||
return l
|
||||
|
||||
def _addverk(self,request,o=None):
|
||||
v = Verkaeufer()
|
||||
v.update(request)
|
||||
setattr( self.verkaeufer, v.id, v )
|
||||
request.redirect( request.app + "/verkaeufer/" + v.id )
|
||||
|
||||
addverk = WebCallable(method=_addverk)
|
||||
|
||||
def _addartikel(self,request,o=None):
|
||||
a = Artikel(request.getForm()["vid"].value())
|
||||
a.update(request)
|
||||
|
||||
setattr( self.artikel, a.id, a )
|
||||
request.redirect( request.app + "/artikel/" + a.id )
|
||||
|
||||
addartikel = WebCallable(method=_addartikel)
|
||||
|
||||
|
||||
|
||||
def _search(self,request,o=None):
|
||||
q = request.getForm()["q"].value()
|
||||
if hasattr(self.verkaeufer, q):
|
||||
request.redirect(request.app + "/verkaeufer/" + q)
|
||||
if hasattr(self.artikel, q):
|
||||
request.redirect(request.app + "/artikel/" + q)
|
||||
if hasattr(self.verkauf, q):
|
||||
request.redirect(request.app + "/verkauf/" + q)
|
||||
|
||||
r = []
|
||||
|
||||
for n in self.artikel.children():
|
||||
a = getattr(self.artikel, n)
|
||||
for n in dir(a):
|
||||
if (str(getattr(a,n)).lower().find(q.lower())>=0):
|
||||
r.append( {
|
||||
"link": request.app + "/artikel/" + a.id,
|
||||
"text": "Artikel: %s" % (a.bezeichnung,)
|
||||
})
|
||||
break
|
||||
|
||||
for n in self.verkaeufer.children():
|
||||
v = getattr(self.verkaeufer, n)
|
||||
for n in dir(v):
|
||||
if (str(getattr(v,n)).lower().find(q.lower())>=0):
|
||||
r.append( {
|
||||
"link": request.app + "/verkaeufer/" + v.id,
|
||||
"text": "Verkäufer: %s, %s" % (v.lastname,v.firstname)
|
||||
})
|
||||
break
|
||||
|
||||
request.results = r
|
||||
|
||||
Templates.search_html(request,self)
|
||||
|
||||
search = WebCallable(method=_search)
|
||||
|
||||
def svgqrcode(self,c):
|
||||
qr = qrcode.make(c, image_factory=qrcode.image.svg.SvgPathImage, box_size=8)
|
||||
b = io.BytesIO()
|
||||
qr.save(b)
|
||||
return str(b.getvalue(),"utf-8").split("\n")[1]
|
||||
|
||||
def _qrcode(self,request,o=None):
|
||||
img = qrcode.make(request.getForm()["c"].value())
|
||||
img.save( request.getBinaryContentFile(), format="png" )
|
||||
request.setResponseHeader("Content-Type","image/png")
|
||||
qrcode = WebCallable(method=_qrcode)
|
||||
|
||||
def _verkaufen(self,request,o=None):
|
||||
v = Verkauf()
|
||||
setattr(self.verkauf, v._persistence_id(), v)
|
||||
request.redirect(request.self(-1)+"/verkauf/"+v._persistence_id())
|
||||
verkaufen = WebCallable(method=_verkaufen)
|
||||
|
||||
hserver.api.KleinerBasar = KleinerBasar
|
|
@ -0,0 +1 @@
|
|||
modules=["uuid","datetime","qrcode","qrcode.image.svg","io","os","time"]
|
|
@ -0,0 +1,111 @@
|
|||
<%frame layout_html%>
|
||||
<%
|
||||
self.update(request)
|
||||
%>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
storage = window.localStorage;
|
||||
|
||||
|
||||
|
||||
function $(name){
|
||||
return document.getElementById(name);
|
||||
}
|
||||
|
||||
function setDefaultLabelPrinter(){
|
||||
var selp = $("printers")
|
||||
var prn = selp.options[selp.selectedIndex].value
|
||||
storage.setItem("def_label_printer",prn);
|
||||
}
|
||||
|
||||
function loadDefaultLabelPrinter(){
|
||||
var selp = $("printers")
|
||||
var defprn = storage.getItem("def_label_printer");
|
||||
var n;
|
||||
for (n=0;n<selp.options.length;n++){
|
||||
if (selp.options[n].value == defprn){
|
||||
selp.selectedIndex = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<h1>Artikel Details</h1>
|
||||
<br/>
|
||||
Artikel# <%=self.id%><br/>
|
||||
Verkäufer: <a href="<%=request.app%>/verkaeufer/<%=self.vid%>"><%=self.verkaeufer().lastname%>, <%=self.verkaeufer().firstname%></a>
|
||||
<br/>
|
||||
<br/>
|
||||
<div>
|
||||
<form action="<%=request.self()%>/tag" method="GET" __enctype="multipart/form-data" onsubmit="setDefaultLabelPrinter();">
|
||||
<select size="1" name="printer" id="printers">
|
||||
<%iterate printer self.printers%><option value="<%=printer%>"><%=printer%></option>
|
||||
<%end%></select>
|
||||
<input type="submit" value="LABEL DRUCKEN"/>
|
||||
</form>
|
||||
</div>
|
||||
<br/>
|
||||
<form action="<%=request.self()%>" method="post" enctype="multipart/form-data">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Bezeichnung (kurz):</td>
|
||||
<td><input type="text" name="bezeichnung" value="<%=self.bezeichnung%>"/></td>
|
||||
<td>Preis</td>
|
||||
<td><input type="number" name="preis" min="0" max="999999" step="0.01" value="<%=self.preis%>"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Bezeichnung (lang):</td>
|
||||
<td colspan="3"><input type="text" name="bezeichnung2" value="<%=self.bezeichnung2%>"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Seriennummer:</td>
|
||||
<td colspan="3">
|
||||
<input type="text" name="seriennummer" value="<%=self.seriennummer%>"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Verkauft:</td>
|
||||
<td colspan="3">
|
||||
<select name="verkauft">
|
||||
<option value=""<%if not self.verkauft%> selected<%end%>>Nein</option>
|
||||
<option value="True"<%if self.verkauft%> selected<%end%>>Ja</option>
|
||||
</select>
|
||||
für
|
||||
<input type="number" name="erloes" min="0" max="999999" step="0.01" value="<%=self.erloes%>"/>
|
||||
<%if hasattr(self,"quittung")%>
|
||||
<a href="<%=request.app%>/verkauf/<%=self.quittung%>" target="_blank">Quittung</a>
|
||||
<%end%>
|
||||
</td>
|
||||
<!-- <td>Bezahlt:</td>
|
||||
<td>
|
||||
<select name="bezahlt">
|
||||
<option value=""<%if not self.bezahlt%> selected<%end%>>Nein</option>
|
||||
<option value="True"<%if self.bezahlt%> selected<%end%>>Ja</option>
|
||||
</select>
|
||||
</td>-->
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4">
|
||||
Beschreibung:<br/>
|
||||
<textarea name="beschreibung"><%=self.beschreibung%></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4">
|
||||
Bemerkungen:<br/>
|
||||
<textarea name="bemerkungen"><%=self.bemerkungen%></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="submit" value="aktualisieren"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<script type="text/javascript">
|
||||
loadDefaultLabelPrinter();
|
||||
</script>
|
|
@ -0,0 +1,38 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<!--link rel="stylesheet" href="<%=request.app%>/print_css"/-->
|
||||
<style>
|
||||
<%include ("print.css",None)%>
|
||||
</style>
|
||||
</head>
|
||||
<body class="SRL">
|
||||
<div id="page">
|
||||
<div>
|
||||
<div id="scancode">
|
||||
<%=self.svgqrcode(self.id)%>
|
||||
</div>
|
||||
|
||||
<div class="title">Fahrradbörse 2018</div>
|
||||
|
||||
<section id="content">
|
||||
<div class="title sub">
|
||||
<div><%=self.bezeichnung%></div><br/>
|
||||
<%=self.bezeichnung2%>
|
||||
</div>
|
||||
|
||||
<div id="description"><%=text2html(self.beschreibung)%></div>
|
||||
|
||||
<div id="price" class="title ul">
|
||||
<div><%="%0.2f €" % (self.preis,)%></div>
|
||||
</div>
|
||||
|
||||
<div id="tagid" class="small">
|
||||
<%=self.id%>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<%frame layout_html%>
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="UTF-8"/>
|
||||
<html>
|
||||
<head>
|
||||
<title>Der kleine Basar</title>
|
||||
<link rel="stylesheet" href="layout_css"/>
|
||||
</head>
|
||||
<body onLoad="document.getElementById('query').focus();">
|
||||
<div id="body">
|
||||
<section id="header">
|
||||
<div>Der kleine Basar</div>
|
||||
</section>
|
||||
|
||||
<section id="menu">
|
||||
<form action="<%=request.app%>/search">
|
||||
<div id="search">
|
||||
Direktsuche:<br/>
|
||||
<input type="text" id="query" name="q" value=""/><br/>
|
||||
<input type="submit" value="suchen..."/>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<a href="<%=request.app%>/list_verk">Verkäufer</a>
|
||||
<a href="<%=request.app%>/list_artikel">Artikel</a>
|
||||
<a href="<%=request.app%>/verkaufen" target="_blank">Verkauf</a>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="page"><%content%></section>
|
||||
|
||||
<section id="footer">
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,65 @@
|
|||
<%frame layout_html%>
|
||||
<h1>Artikelliste</h1>
|
||||
<br/>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Artikel#</td>
|
||||
<td>Bezeichnung</td>
|
||||
<td>Verkauft</td>
|
||||
<td>Verkäufer</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%
|
||||
|
||||
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%>
|
||||
<tr>
|
||||
<td><a href="<%=request.app%>/artikel/<%=a.id%>"><%=a.id%></a></td>
|
||||
<td><%=a.bezeichnung%></td>
|
||||
<td>
|
||||
<%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%>
|
||||
</td>
|
||||
<td>
|
||||
<a href="<%=request.app%>/verkaeufer/<%=a.vid%>">
|
||||
<%=a.verkaeufer().lastname%>, <%=a.verkaeufer().firstname%>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<%end%>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<br/>
|
||||
<br/>
|
||||
<div>
|
||||
Statistik: <%=len(al)%> Artikel,
|
||||
davon <%=n_verkauft%> verkauft für insgesamt <%="%0.2f" % (s_verkauft,)%>€
|
||||
(Provisionen: <%="%0.2f" % (s_verkauft*0.1,)%>€)
|
||||
<br/>
|
||||
Bepreiste Verkaufssumme wäre gewesen: <%="%0.2f" % (s_preisverkauf,)%>€, dies wären <%="%0.2f" % (s_preisverkauf*0.1,)%>€ Provision gewesen.<br/>
|
||||
Bepreiste Gesamtsumme war: <%="%0.2f" % (s_preis,)%>€, dies wären <%="%0.2f" % (s_preis*0.1,)%>€ Provision gewesen.<br/>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<%frame layout_html%>
|
||||
<h1>Verkäuferliste</h1>
|
||||
<br/>
|
||||
<a href="<%=request.self()%>?away=yes">[ +AUSGECHECKTE ]</a><br/>
|
||||
<br/>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Verk.#</td>
|
||||
<td>Nachname</td>
|
||||
<td>Vornamen</td>
|
||||
<td>Angebotene Artikel</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<form action="<%=request.app%>/addverk">
|
||||
<tr style="background-color: #E0E0E0;">
|
||||
<td>neu:</td>
|
||||
<td><input type="text" name="lastname" value=""/></td>
|
||||
<td><input type="text" name="firstname" value=""/></td>
|
||||
<td></td>
|
||||
<td><input type="submit" value="erstellen..."/></td>
|
||||
</tr>
|
||||
</form>
|
||||
<%
|
||||
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%>
|
||||
<tr>
|
||||
<td><a href="<%=request.app%>/verkaeufer/<%=v.id%>"><%=v.id%></a></td>
|
||||
<td><%=v.lastname%></td>
|
||||
<td><%=v.firstname%></td>
|
||||
<td style="max-width: 250px;">
|
||||
<div style="display: inline-block; vertical-align: top;">
|
||||
<%=v.artikel().__len__()%></div>
|
||||
<div style="display: inline-block; margin-left: 5px;">
|
||||
<%iterate a v.artikel()%>
|
||||
<div><a <%if a.verkauft%>class="stroke gray" <%end%>href="<%=request.app%>/artikel/<%=a.id%>"><%=a.bezeichnung%></a></div>
|
||||
<%end%>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<%end%>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<br/>
|
||||
<br/>
|
||||
<div>
|
||||
Auf dieser Liste sind <%=len(vl)%> Verkäufer gelistet.
|
||||
</div>
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
<%
|
||||
tags = self._tags()
|
||||
%>
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<link rel="stylesheet" href="<%=request.app%>/print_css"/>
|
||||
<style>
|
||||
|
||||
#page > div {
|
||||
|
||||
position: absolute:
|
||||
top: 13.23mm;
|
||||
left: 8mm;
|
||||
right: 8mm;
|
||||
bottom: 13.23mm;
|
||||
padding: 0cm;
|
||||
margin: 0cm;
|
||||
}
|
||||
|
||||
|
||||
.tag {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 48.5mm;
|
||||
height: 16.9mm;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
.tagrow {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
<div>
|
||||
<%iterate y range(16)%>
|
||||
<div class="tagrow">
|
||||
<%iterate x range(4)%><%
|
||||
t = tags.pop()
|
||||
%><div class="tag">
|
||||
<img src="<%=request.app%>/qrcode?c=<%=t%>" style="width: 10mm; height: 10mm;"/>
|
||||
</div><%end%><br/>
|
||||
</div>
|
||||
<%end%>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,71 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<link rel="stylesheet" href="<%=request.app%>/print_css"/>
|
||||
<style>
|
||||
#page > div {
|
||||
position: absolute;
|
||||
top: 15mm;
|
||||
left: 15mm;
|
||||
bottom: 15mm;
|
||||
right: 15mm;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
<div>
|
||||
|
||||
<%
|
||||
summe = 0.0
|
||||
%>
|
||||
<div class="right">
|
||||
<%=self.svgqrcode(self._aq_name)%>
|
||||
</div>
|
||||
|
||||
<div class="title">Fahrradbörse von<br/>
|
||||
<div>Bündnis90 / Die Grünen (2016)</div>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
|
||||
<br/>
|
||||
<div class="big">Quittung / Mitnahmeschein</div><br/>
|
||||
<div class="small"><%=self._aq_name%></div><br/>
|
||||
<div class="small"><%=self.zeit%></div>
|
||||
<br/>
|
||||
|
||||
<br/>
|
||||
<%iterate artikel self.artikel.keys()%>
|
||||
<div class="hr box">
|
||||
<%=artikel.bezeichnung%>
|
||||
<div class="right"><%="%0.2f" % (self.artikel[artikel],)%>€</div><br/>
|
||||
<div class="small pre indent"><%=artikel.beschreibung%></div>
|
||||
</div>
|
||||
<%
|
||||
summe = summe + self.artikel[artikel]
|
||||
%>
|
||||
<%end%>
|
||||
<br/>
|
||||
<br/>
|
||||
<div class="right">Summe: <%="%0.2f" % (summe,)%>€</div>
|
||||
<br/>
|
||||
|
||||
<div class="small"><span class="ul">Grundsätze:</span><br/>
|
||||
Veranstalter der Fahrradbörse ist Bündnis90 / die Grünen OV Vaihingen.<br/>
|
||||
Der Veranstalter tritt in der Fahrradbörse als Vermittler auf, die Vermittlerprovision beträgt 10% des erzielten Preises.<br/>
|
||||
<br/>
|
||||
Der Veranstalter übernimmt keine Gewährleistung und Garantie für die Ware!<br/>
|
||||
Bitte prüfen Sie den Zustand und die Funktionsfähigkeit der Ware genau!<br/>
|
||||
<br/>
|
||||
Der Veranstalter überwacht die Fahrradbörse, er übernimmt keine Haftung bei Diebstahl.<br/>
|
||||
Am Abend nicht abgeholte Ware geht in den Besitz des Veranstalters über und wird gespendet bzw. entsorgt.
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,13 @@
|
|||
<%frame layout_html%>
|
||||
<h1>Direktsuche</h1>
|
||||
<br/>
|
||||
Suche nach: <%=request.getForm()["q"].value()%><br/>
|
||||
<hr/>
|
||||
<%if len(request.results)==0%>
|
||||
<div>Keine Treffer!</div>
|
||||
<%end%>
|
||||
<%if len(request.results)!=0%>
|
||||
<%iterate r request.results%>
|
||||
<a href="<%=r["link"]%>"><%=r["text"]%></a><br/>
|
||||
<%end%>
|
||||
<%end%>
|
|
@ -0,0 +1,82 @@
|
|||
<%frame layout_html%>
|
||||
<%
|
||||
self.update(request)
|
||||
%>
|
||||
<h1>Verkäufer Details</h1>
|
||||
<a href="<%=request.self()%>/prov" target="_blank">Abrechnungsliste</a><br/>
|
||||
<br/>
|
||||
<%if self.checkedout%>
|
||||
<h1>!!! AUSGECHECKT !!!</h1>
|
||||
<%end%>
|
||||
<form action="<%=request.self()%>" method="POST" enctype="multipart/form-data">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Nachname:</td>
|
||||
<td><input type="text" name="lastname" value="<%=self.lastname%>"/></td>
|
||||
<td>Vorname:</td>
|
||||
<td><input type="text" name="firstname" value="<%=self.firstname%>"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Firma:</td>
|
||||
<td colspan="3"><input type="text" name="company" value="<%=self.company%>"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Telefon:</td>
|
||||
<td colspan="3"><input type="text" name="telefon" value="<%=self.telefon%>"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ausgecheckt:</td>
|
||||
<td colspan="3">
|
||||
<select name="checkedout">
|
||||
<option value=""<%if not self.checkedout%> selected<%end%>>NEIN</option>
|
||||
<option value="True"<%if self.checkedout%> selected<%end%>>JA</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4">Anschrift:<br/>
|
||||
<textarea name="anschrift"><%=self.anschrift%></textarea></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4">Bemerkungen:<br/>
|
||||
<textarea name="bemerkungen"><%=self.bemerkungen%></textarea></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="submit" value="aktualisieren"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<br/>
|
||||
<h2>Angebotene Artikel</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Artikel#</td>
|
||||
<td>Bezeichnung (kurz)</td>
|
||||
<td>Bezeichnung (lang)</td>
|
||||
<td>Preis</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<form action="<%=request.app%>/addartikel?vid=<%=self.id%>" method="POST" enctype="multipart/form-data">
|
||||
<tr style="background-color: #E0E0E0;">
|
||||
<td>neu:</td>
|
||||
<td><input type="text" name="bezeichnung" value=""/></td>
|
||||
<td><input type="text" name="bezeichnung2" value=""/></td>
|
||||
<td><input type="number" name="preis" min="0" max="999999" step="0.01" value="1"/></td>
|
||||
<td></td>
|
||||
<td><input type="submit" value="erstellen..."/></td>
|
||||
</tr>
|
||||
<%iterate artikel self.artikel()%>
|
||||
<tr>
|
||||
<td><a href="<%=request.app%>/artikel/<%=artikel.id%>"><%=artikel.id%></a></td>
|
||||
<td><%=artikel.bezeichnung%></td>
|
||||
<td><%=artikel.bezeichnung2%></td>
|
||||
<td><%=artikel.preis%></td>
|
||||
</tr>
|
||||
<%end%>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
%><!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>Verkäuferabrechnung</title>
|
||||
<link rel="stylesheet" href="<%=request.app%>/print_css"/>
|
||||
<style>
|
||||
td {
|
||||
border-bottom: 1px dotted black;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
#scancode {
|
||||
position: absolute;
|
||||
right: 1cm;
|
||||
top: 0cm;
|
||||
}
|
||||
|
||||
#scancode > img {
|
||||
width: 3cm;
|
||||
height: 3cm;
|
||||
}
|
||||
|
||||
#page > div {
|
||||
position: absolute;
|
||||
top: 15mm;
|
||||
left: 15mm;
|
||||
bottom: 15mm;
|
||||
right: 15mm;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
<div>
|
||||
<div id="scancode"><img src="<%=request.app%>/qrcode?c=<%=self.id%>"/></div>
|
||||
<%if not self.checkedout%>
|
||||
<div class="noprint">
|
||||
<a href="<%=request.self(-1)%>/checkout">[ VERKÄUFER AUSCHECKEN ]</a>
|
||||
</div>
|
||||
<%end%>
|
||||
<div class="title">Fahrradbörse von<br/>
|
||||
<div>Bündnis90 / Die Grünen (2018)</div>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
<%if self.checkedout%>
|
||||
<span class="ul b i big">CHECKOUT</span><br/><br/>
|
||||
<%end%>
|
||||
|
||||
<div class="title">
|
||||
Abrechnungsliste Verkäufer<br/>
|
||||
<div><%=self.lastname%>, <%=self.firstname%></div><br/>
|
||||
Verkäufer-ID: <%=self.id%>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<table style="width: 18cm;">
|
||||
<thead>
|
||||
<tr>
|
||||
<td class="i small">Artikel</td>
|
||||
<td class="i small">Bepreisung</td>
|
||||
<td class="i small">Erlös</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%iterate a al%>
|
||||
<tr>
|
||||
<td>
|
||||
<%=a.bezeichnung%><br/>
|
||||
<div class="sub"><%=a.id%></div><br/>
|
||||
|
||||
</td>
|
||||
<td style="text-align: right;">
|
||||
<%="%03.2f" % (a.preis,)%>€
|
||||
</td>
|
||||
<td style="text-align: right;">
|
||||
<%
|
||||
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%>
|
||||
</td>
|
||||
</tr>
|
||||
<%end%>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td class="borderless"></td>
|
||||
<td class="borderless"></td>
|
||||
<td class="borderless"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="borderless" style="text-align: right;">Summe:</td>
|
||||
<td style="text-align: right;">( <%="%03.2f" % (round(summe,2),)%>€ )</td>
|
||||
<td style="text-align: right;"><%="%03.2f" % (round(sum_erloes,2),)%>€</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="borderless" style="text-align: right;">Provision:</td>
|
||||
<td style="text-align: right;">( <%="%03.2f" % (round(summe * 0.1,2),)%>€ )</td>
|
||||
<td style="text-align: right;"><%="%03.2f" % (round(sum_erloes * 0.1,2),)%>€</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="borderless" style="text-align: right;">Auszahlung:</td>
|
||||
<td class="borderless" style="font-weight: normal; text-align: right;">( <%="%03.2f" % (round(summe * 0.9,2),)%>€ )</td>
|
||||
<td class="borderless" style="font-weight: bold; font-size: 8mm; text-decoration: underline; text-align: right;"><%="%03.2f" % (round(sum_erloes * 0.9,2),)%>€</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
<%if self.checkedout%>
|
||||
<div>
|
||||
<br/>
|
||||
<br/>
|
||||
Betrag erhalten: <div style="width: 8cm; border-bottom: 0.1cm dotted black;"> </div>
|
||||
</div>
|
||||
<br/><br/>
|
||||
<%end%>
|
||||
|
||||
<div class="small"><span class="ul">Grundsätze:</span><br/>
|
||||
Veranstalter der Fahrradbörse ist Bündnis90 / die Grünen OV Vaihingen.<br/>
|
||||
Der Veranstalter tritt in der Fahrradbörse als Vermittler auf, die Vermittlerprovision beträgt 10% des erzielten Preises.<br/>
|
||||
<br/>
|
||||
Der Veranstalter übernimmt keine Gewährleistung und Garantie für die Ware!<br/>
|
||||
Bitte prüfen Sie den Zustand und die Funktionsfähigkeit der Ware genau!<br/>
|
||||
<br/>
|
||||
Der Veranstalter überwacht die Fahrradbörse, er übernimmt keine Haftung bei Diebstahl.<br/>
|
||||
Am Abend nicht abgeholte Ware geht in den Besitz des Veranstalters über und wird gespendet bzw. entsorgt.
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,46 @@
|
|||
<%frame layout_html%>
|
||||
|
||||
<%
|
||||
|
||||
summe = 0.0
|
||||
|
||||
%>
|
||||
|
||||
<br/>
|
||||
<div class="big">Verkauf</div>
|
||||
<br/>
|
||||
|
||||
<form action="" method="post" enctype="multipart/form-data">
|
||||
|
||||
<%if hasattr(request,"message")%>
|
||||
<div class="message"><%=request.message%></div>
|
||||
<br/>
|
||||
<%end%>
|
||||
|
||||
<div>
|
||||
Artikel hinzufügen: <input class="wide" type="text" id="artikelid" name="artikelid" value=""/>
|
||||
</div>
|
||||
<br/>
|
||||
<%iterate artikel self.artikel.keys()%>
|
||||
<div class="space hr">
|
||||
<a href="<%=request.self(-3)%>/artikel/<%=artikel.id%>" target="_blank"><%=artikel.bezeichnung%></a>
|
||||
<input class="right" type="number" name="erloes_<%=artikel.id%>" min="0" max="999999" step="1.0" value="<%=self.artikel[artikel]%>"/><br/>
|
||||
<div class="small pre indent"><%=artikel.beschreibung%></div>
|
||||
</div>
|
||||
<%
|
||||
summe = summe + self.artikel[artikel]
|
||||
%>
|
||||
<%end%>
|
||||
<br/>
|
||||
<br/>
|
||||
<div style="position: relative; right: 0px; text-align: right;">Summe: <%="%0.2f" % (summe,)%>€</div>
|
||||
<br/>
|
||||
<br/>
|
||||
<input class="big" type="submit" name="action" value="AKTUALISIEREN"/>
|
||||
|
||||
<input class="big" type="submit" name="action" value="BEZAHLT"/>
|
||||
|
||||
</form>
|
||||
<script>
|
||||
window.setTimeout( function(){document.getElementById('artikelid').focus();}, 250 );
|
||||
</script>
|
|
@ -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)
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -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())
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
|
|
@ -0,0 +1 @@
|
|||
modules=("hwo",)
|
|
@ -0,0 +1,15 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>404 Not Found</title>
|
||||
<style>
|
||||
body,p,div {
|
||||
font-family: "DejaVu Sans","Helvetica", "Arial", "Sans";
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Die angeforderte Resource konnte nicht gefunden werden</h1>
|
||||
<h1>The requested resource was not found</h1>
|
||||
<div><%=self.message%></div>
|
||||
</body>
|
||||
</html>
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<%frame frame_html%>
|
||||
|
||||
<div id="path">Pfad: <%=request.self(-1,trail=True)%></div>
|
||||
<div id="display">
|
||||
<div id="tree">
|
||||
<%if not self._aq_parent is None%>
|
||||
<div><a href="<%=request.self(-2,trail=True)%>_browse">..</a></div>
|
||||
<%end%>
|
||||
<%if self._aq_parent is None%>
|
||||
<div> </div>
|
||||
<%end%>
|
||||
|
||||
<form action="<%=request.self()%>/add">
|
||||
<div class="treenode">
|
||||
<input type="text" name="oname"/><br/>
|
||||
<select size="1" name="oclass">
|
||||
<%iterate wo_cls getattr(self,"_browse").wo_types()%><option value="<%=wo_cls%>"><%=wo_cls%></option><%end%>
|
||||
</select><br/>
|
||||
<input type="submit" value="erstellen"/>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<%iterate node self.children()%>
|
||||
<div class="treenode"><a href="<%=request.self(-1,trail=True)%><%=node%>/_browse"><%=node%></a><div><%=getattr(self,node).__class__.__name__%></div></div>
|
||||
<%end%>
|
||||
</div>
|
||||
<div id="details">
|
||||
<%=self._aq_name%> (<%=self.__class__.__name__%>)<br/>
|
||||
<div id="actions">
|
||||
<a href="<%=request.self(-1)%>">[ ANZEIGEN ]</a>
|
||||
<%if not self._aq_name=="/"%>
|
||||
<a href="<%=request.self()%>/remove">[ ENTFERNEN ]</a>
|
||||
<%end%>
|
||||
</div>
|
||||
<br/>
|
||||
<%if hasattr(self,"_wo_manage")%>
|
||||
<% self._wo_manage(request,self) %>
|
||||
<%end%>
|
||||
</div>
|
||||
</div>
|
|
@ -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" %>
|
||||
<div id="message">Server will shutdown after this request.</div>
|
||||
<%end%>
|
||||
|
||||
<a href="<%=request.self()%>?shutdown=yes"><div class="button">Shutdown</div></a>
|
|
@ -0,0 +1,22 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>HServer Management</title>
|
||||
<style>
|
||||
<%include ("style_css",self)%>
|
||||
<%include ("browse.css",self)%>
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<section id="menu">
|
||||
<a href="/manage/control"><div>Control</div></a>
|
||||
<a href="/manage/packages"><div>Packages</div></a>
|
||||
<a href="/_browse"><div>Tree Browser</div></a>
|
||||
</section>
|
||||
|
||||
<div id="content">
|
||||
<%content%>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,11 @@
|
|||
<div class="wo_frame">
|
||||
<div class="wo_name"><%=self._aq_name%></div>
|
||||
<div class="wo_class">[<%=escape(self.__class__.__name__)%>]</div>
|
||||
<div class="wo_actions">
|
||||
<a href="" onClick="addObject( '<%=self._aq_path()%>' )">[ ADD HERE ]</a>
|
||||
|
||||
</div>
|
||||
<%iterate wobj self.children()%>
|
||||
<%include ("list_wo.html",getattr(self,wobj))%>
|
||||
<%end%>
|
||||
</div>
|
|
@ -0,0 +1,3 @@
|
|||
<%frame frame_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())
|
||||
|
||||
%>
|
||||
<div>Loaded Packages: (<a href="<%=request.self()%>?reload=_all">reload</a>) <br/>
|
||||
<%iterate _p self.server().packagemanager().packages().keys()%>
|
||||
<% p = self.server().packagemanager().packages()[_p] %>
|
||||
<div class="block">
|
||||
<div class="headline"><%=_p%> (<a href="<%=request.self()%>?reload=<%=escape(_p)%>">reload</a>)</div>
|
||||
<div>Exports:<br/>
|
||||
<%iterate e p.exports()%>
|
||||
<% exp = p.exports()[e] %>
|
||||
<div class="listitem"><%=e%>: <%=escape("%s" % (exp,))%></div>
|
||||
<%end%>
|
||||
</div>
|
||||
|
||||
<div>Contents:<br/>
|
||||
<%iterate e p.modules()%>
|
||||
<% exp = p.modules()[e] %>
|
||||
<div class="listitem"><%=e%>: <%=escape("%s" % (exp,))%></div>
|
||||
<%end%>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<%end%>
|
||||
</div>
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<%frame frame_html%>
|
||||
|
||||
<script src="api"></script>
|
||||
|
||||
<div>Tree Setup</div><br/>
|
||||
<br/>
|
||||
|
||||
<%
|
||||
path = ()
|
||||
objs = self.list_webobjects()
|
||||
%>
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<div>Neues Objekt:
|
||||
<input type="text" id="oname" value=""/>
|
||||
<select id="oclass" size="1">
|
||||
<%iterate t objs%>
|
||||
<option value="<%=t.__name__%>"><%=t.__name__%></option>
|
||||
<%end%>
|
||||
</select>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
<%include ("list_wo.html",self.server().aq_root())%>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
<div id="treeitem">
|
||||
<div class="cell"><%=self[0]%></div>
|
||||
<div class="cell"><%=self[1].__class__.__name__%></div>
|
||||
<div class="cell" style="width: auto;">
|
||||
<img src="<%=request.self(-1)%>/gfx_plus.png" class="icon" onClick="addObject( '<%=self[0]%>' )"/>
|
||||
</div>
|
||||
<%iterate n self[2]%>
|
||||
<%include ('treelevel_html', n)%>
|
||||
<%end%>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
|
@ -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
|
Loading…
Reference in New Issue