--- a/iro/controller/viewinterface.py Thu Jan 26 01:23:04 2012 +0100
+++ b/iro/controller/viewinterface.py Fri Jan 27 15:01:59 2012 +0100
@@ -1,10 +1,12 @@
# -*- coding: utf-8 -*-
from ..model.user import with_user
-
+from ..validate import validate, boolean, validateHash
class Interface(object):
'''class for a xmlrpc user
'''
+ @validate(kwd="detailed", func=boolean, need=False)
+ @validate(kwd="id", func=validateHash, need=False)
@with_user
def status(self, user, id=None, detailed=False):
'''Gibt den aktuellen Status eines Auftrages oder Mehreren zurück.
@@ -21,7 +23,10 @@
'''
- return str(user)
+ if id or detailed:
+ return str(user),id,detailed
+ else:
+ return str(user)
#return user.status(id,detailed)
return ""
--- a/iro/model/user.py Thu Jan 26 01:23:04 2012 +0100
+++ b/iro/model/user.py Fri Jan 27 15:01:59 2012 +0100
@@ -1,9 +1,11 @@
from inspect import getcallargs
+from functools import wraps
from .schema import User
from .utils import DBDefer
from ..validate import vuserhash, validate
from ..error import UserNotFound, InterfaceException
+
dbdefer=DBDefer(None)
def setEngine(engine,autocommit=False):
@@ -11,7 +13,7 @@
dbdefer.autocommit = autocommit
@dbdefer
-@validate(apikey=vuserhash)
+@validate(kwd="apikey", func=vuserhash)
def getuser(apikey, session):
user = session.query(User).filter_by(apikey=apikey).first()
if user is None:
@@ -20,8 +22,9 @@
return user
def with_user(f):
- def new_f(*args,**kargs):
- kp=getcallargs(f,*args,**kargs)
+ @wraps(f)
+ def wrapper(*args,**kargs):
+ kp=getcallargs(wrapper.original,*args,**kargs)
try:
apikey = kp["user"]
except KeyError:
@@ -33,8 +36,10 @@
d=getuser(apikey=apikey)
return d.addCallback(_gotResult)
-
- new_f.__name__ = f.__name__
- return new_f
+ try:
+ wrapper.original=f.original
+ except AttributeError:
+ wrapper.original=f
+ return wrapper
--- a/iro/model/utils.py Thu Jan 26 01:23:04 2012 +0100
+++ b/iro/model/utils.py Fri Jan 27 15:01:59 2012 +0100
@@ -3,6 +3,8 @@
from twisted.internet import threads
from twisted.python.threadpool import ThreadPool
+from functools import wraps
+
POOL_SIZE=5 #how many threads should the db connector pool should have
class Data:
@@ -19,6 +21,7 @@
def run_in_db_thread(f):
"""Decorator to run DB queries in Twisted's thread pool"""
+ @wraps(f)
def wrapper(*args, **kwargs):
return threads.deferToThreadPool(d.reactor, d.pool, f, *args, **kwargs)
return wrapper
@@ -50,6 +53,7 @@
def __call__(self, func):
@run_in_db_thread
+ @wraps(func)
def wrapper(*args, **kwargs):
with WithSession(self.engine, self.autocommit) as session:
return func(*args, session=session, **kwargs)
--- a/iro/validate.py Thu Jan 26 01:23:04 2012 +0100
+++ b/iro/validate.py Fri Jan 27 15:01:59 2012 +0100
@@ -1,27 +1,57 @@
import re
+from functools import wraps
+
from inspect import getcallargs
from .error import ValidateException
-def vuserhash(hash,field):
- '''vailidate function for userhash'''
- if not re.match(r'^[a-f0-9]{15,}$', hash.lower()):
+def boolean(value, field):
+ t=[True,"true",1]
+ f=[False,"false",0]
+ if value in t:
+ return True
+ elif value in f:
+ return False
+ else:
+ raise ValidateException(field=field, msg='%s is not boolean' % field)
+
+
+def validateHash(value,field,minlength=None,maxlength=None):
+ if not re.match(r'^[a-f0-9]*$', value.lower()):
raise ValidateException(field=field)
- return True
+ if minlength and len(value)<minlength:
+ raise ValidateException(field=field)
+ if maxlength and len(value)>maxlength:
+ raise ValidateException(field=field)
+ return value
-def validate(**kargs):
+def vuserhash(value,field):
+ '''vailidate function for userhash'''
+ return validateHash(value,field,minlength=15,maxlength=15)
+
+def validate(kwd,func, need=True,*args,**kargs):
'''validate decorator
use it like this:
- @validate(userhash=vuserhash)
+ @validate(kwd=userhash, func=vuserhash)
f(userhash)
- that will validate usrhah with the function vuserhash.
+ that will validate usrhash with the function vuserhash.
Every validate function should raise an Exception, if the the value is not valid'''
def v(f):
+ @wraps(f)
def new_f(*a,**k):
- kp=getcallargs(f,*a,**k)
- for i in kargs:
- kargs[i](kp[i],i)
- return f(*a,**k)
- new_f.__name__ = f.__name__
+ kp=getcallargs(new_f.original,*a,**k)
+ try:
+ if need or kp[kwd] is not None:
+ kp[kwd] = func(kp[kwd],kwd,*args,**kargs)
+ else:
+ kp[kwd] = None
+ except KeyError:
+ if need:
+ raise ValidateException(field=kwd,msg="%s is nessasary"%kwd)
+ return f(**kp)
+ try:
+ new_f.original=f.original
+ except AttributeError:
+ new_f.original=f
return new_f
return v
--- a/tests/xmlrpc.py Thu Jan 26 01:23:04 2012 +0100
+++ b/tests/xmlrpc.py Fri Jan 27 15:01:59 2012 +0100
@@ -52,7 +52,7 @@
def __rpc2(self):
return ServerProxy('http://localhost:7080/RPC2')
-
+
def testDebugHello(self):
'''simple test for the connection to xmlrpc server'''
ret=self.__debug().hello()
@@ -66,6 +66,13 @@
def testStatus(self):
ret = self.__rpc2().status('abcdef123456789')
self.failUnlessEqual(ret, "<User('test','abcdef123456789')>")
+ self.failUnlessEqual(self.__rpc2().status('abcdef123456789','abcde'), ["<User('test','abcdef123456789')>",'abcde',False])
+ self.failUnlessEqual(self.__rpc2().status('abcdef123456789','abcde', True), ["<User('test','abcdef123456789')>",'abcde', True])
+ self.failUnlessEqual(self.__rpc2().status('abcdef123456789', '', 'true'), ["<User('test','abcdef123456789')>", '', True])
+ self.failUnlessEqual(self.__rpc2().status('abcdef123456789', '', 'false'), "<User('test','abcdef123456789')>")
+ self.failUnlessEqual(self.__rpc2().status('abcdef123456789', '', 0), "<User('test','abcdef123456789')>")
+ self.failUnlessEqual(self.__rpc2().status('abcdef123456789', '', 1), ["<User('test','abcdef123456789')>", '', True])
+
def testNoSuchUser(self):
'''a unknown user should raise a UserNotNound Exception
@@ -85,7 +92,7 @@
self.failUnlessEqual(exc.faultCode, 8001)
self.failUnlessEqual(exc.faultString, "procedure nosuchmethod not found")
- def testValidation(self):
+ def testValidationFault(self):
'''a validate Exception should be translated to a xmlrpclib.Fault.'''
with self.assertRaises(Fault) as fault:
self.__rpc2().status('xxx')
@@ -93,8 +100,6 @@
self.failUnlessEqual(exc.faultCode, 700)
self.failUnlessEqual(exc.faultString, "Validation of 'apikey' failed.")
-
-
def startReactor(engine):
"""starts the Rector with a special debug Clild, so that the reactor can be stopped remotly. """
from twisted.internet import reactor