--- a/iro/controller/viewinterface.py Fri Jan 27 21:14:18 2012 +0100
+++ b/iro/controller/viewinterface.py Fri Jan 27 21:21:41 2012 +0100
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-from ..model.decorators import vUser, vRoute
-from ..model.utils import vTyp
+from ..model.decorators import vUser, vRoute, dbdefer, vTyp
+from ..model.schema import User
from ..validate import validate, vBool, vHash, vTel, vEmail
class Interface(object):
@@ -108,7 +108,8 @@
@validate(kwd="typ", func=vTyp)
@vUser
- def routes(self, user, typ):
+ @dbdefer
+ def routes(self, user, typ, session):
'''Gibt eine Liste aller verfügbaren Provider zurück.
Keywords:
@@ -120,11 +121,13 @@
providerlist[list]: Eine Liste aller möglichen Provider
'''
- return ""
+ user = session.query(User).filter_by(name=user.name).first()
+ return [u.offer_name for u in user.rights]
@validate(kwd="typ", func=vTyp)
@vUser
- def defaultRoute(self, user, typ):
+ @dbdefer
+ def defaultRoute(self, user, typ, session):
'''Gibt den Standardprovider zurück.
Keywords:
@@ -137,7 +140,8 @@
'''
- return ""
+ user = session.query(User).filter_by(name=user.name).first()
+ return [u.offer_name for u in user.rights if u.isDefault == True]
@vUser
def statistic(self, user):
--- a/iro/main.py Fri Jan 27 21:14:18 2012 +0100
+++ b/iro/main.py Fri Jan 27 21:21:41 2012 +0100
@@ -5,8 +5,7 @@
import logging
-from .model.user import setEngine
-from .model.utils import POOL_SIZE as DB_POOL_SIZE, startPool
+from .model import setEngine,startPool, POOL_SIZE
from .view import xmlrpc
def runReactor(reactor, engine, root):
@@ -20,7 +19,7 @@
if __name__ == '__main__':
engine = create_engine('mysql://test:test@localhost/test',
- poolclass = pool.SingletonThreadPool, pool_size=DB_POOL_SIZE, )
+ poolclass = pool.SingletonThreadPool, pool_size=POOL_SIZE, )
root = resource.Resource()
--- a/iro/model/__init__.py Fri Jan 27 21:14:18 2012 +0100
+++ b/iro/model/__init__.py Fri Jan 27 21:21:41 2012 +0100
@@ -1,3 +1,10 @@
import schema
import user
import utils
+
+from dbdefer import setEngine
+from pool import startPool,POOL_SIZE
+
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/iro/model/dbdefer.py Fri Jan 27 21:21:41 2012 +0100
@@ -0,0 +1,39 @@
+from decorator import FunctionMaker
+
+from .pool import runInDBPool
+from .utils import WithSession
+
+import inspect
+
+class DBDefer(object):
+ '''a twisted sqlalchemy connector this Decorator adds a session parameter, with a valid session connection'''
+ def __init__(self, engine, autocommit=False):
+ self.autocommit=autocommit
+ self.engine = engine
+
+ def __call__(self, func):
+ @runInDBPool
+ def wrapper(func,*args, **kwargs):
+ with WithSession(self.engine, self.autocommit) as session:
+ return func(*args, session=session, **kwargs)
+
+ caller=func
+ args =[i for i in inspect.getargspec(caller)[0] if i != "session" ]
+ sargs=", ".join(args)
+ evaldict = caller.func_globals.copy()
+ evaldict['_call_'] = func
+ evaldict['decorator'] = wrapper
+ wrap = FunctionMaker.create(
+ '%s(%s)' % (caller.__name__, sargs),
+ 'return decorator(_call_, %s)' % sargs,
+ evaldict, undecorated=caller, __wrapped__=caller,
+ doc=caller.__doc__, module=caller.__module__, addsource=True)
+ return wrap
+
+dbdefer=DBDefer(None)
+
+def setEngine(engine,autocommit=False):
+ dbdefer.engine = engine
+ dbdefer.autocommit = autocommit
+
+
--- a/iro/model/decorators.py Fri Jan 27 21:14:18 2012 +0100
+++ b/iro/model/decorators.py Fri Jan 27 21:21:41 2012 +0100
@@ -1,10 +1,25 @@
from decorator import decorator
-from .utils import DBDefer
from .user import vUser
+from .dbdefer import dbdefer
+from .pool import runInDBPool
+from .schema import Offer
+
+from ..error import ValidateException
def vRoute(typ):
@decorator
def wrapper(f, *args, **kwargs):
return f(*args, **kwargs)
return wrapper
+
+from .utils import WithSession
+#@dbdefer
+def vTyp(value,field):
+ with WithSession(dbdefer.engine) as session:
+ for typ in session.query(Offer.typ).distinct():
+ if value == typ[0]:
+ break
+ else:
+ raise ValidateException(field=field,msg='Typ is not valid.')
+ return value
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/iro/model/pool.py Fri Jan 27 21:21:41 2012 +0100
@@ -0,0 +1,25 @@
+from decorator import decorator
+from twisted.python.threadpool import ThreadPool
+from twisted.internet import threads
+
+POOL_SIZE=5 #how many threads should the db connector pool should have
+
+class Data:
+ def __init__(self):
+ self.pool = ThreadPool(minthreads=1, maxthreads=POOL_SIZE, name='database')
+ self.reactor = None
+
+data = Data()
+#a valid dbDefer decorator
+
+def startPool(reactor):
+ data.pool.start()
+ data.reactor = reactor
+ data.reactor.addSystemEventTrigger('before', 'shutdown', data.pool.stop)
+
+@decorator
+def runInDBPool(f,*args,**kwargs):
+ """Decorator to run DB queries in Twisted's thread pool"""
+ return threads.deferToThreadPool(data.reactor, data.pool, f, *args, **kwargs)
+
+
--- a/iro/model/schema.py Fri Jan 27 21:14:18 2012 +0100
+++ b/iro/model/schema.py Fri Jan 27 21:21:41 2012 +0100
@@ -19,6 +19,10 @@
isDefault = Column(Boolean)
offer = relationship("Offer")
+ def __init__(self, offer, default=False):
+ self.offer = offer
+ self.isDefault = default
+
class Offer(Base):
"""Alle Routen über die SMS, Faxe und Mails verschickt werden könnnen. <em>provider</em>, <em>typ</em> und <em>route</em> werden verwendet, um die entsprechenden Zugangsdaten laden zu können."""
__tablename__ = "offer"
@@ -26,6 +30,12 @@
provider = Column(String(100))
route = Column(String(100))
typ = Column(String(100))
+
+ def __init__(self, name, provider, route, typ):
+ self.name = name
+ self.provider = provider
+ self.route = route
+ self.typ = typ
class Message(Base):
--- a/iro/model/user.py Fri Jan 27 21:14:18 2012 +0100
+++ b/iro/model/user.py Fri Jan 27 21:21:41 2012 +0100
@@ -2,16 +2,11 @@
from decorator import decorator
from .schema import User
-from .utils import DBDefer
+from .dbdefer import dbdefer
+
from ..validate import validate, vHash
from ..error import UserNotFound, InterfaceException
-dbdefer=DBDefer(None)
-
-def setEngine(engine,autocommit=False):
- dbdefer.engine = engine
- dbdefer.autocommit = autocommit
-
@dbdefer
@validate(kwd="apikey", func=vHash, minlength=15, maxlength=15)
--- a/iro/model/utils.py Fri Jan 27 21:14:18 2012 +0100
+++ b/iro/model/utils.py Fri Jan 27 21:21:41 2012 +0100
@@ -1,32 +1,5 @@
from sqlalchemy.orm import sessionmaker
-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:
- def __init__(self):
- self.pool = ThreadPool(minthreads=1, maxthreads=POOL_SIZE, name='database')
- self.reactor = None
-
-d = Data()
-
-def startPool(reactor):
- d.pool.start()
- d.reactor = reactor
- d.reactor.addSystemEventTrigger('before', 'shutdown', d.pool.stop)
-
-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
-
-
class WithSession(object):
'''a with statement for a database session connection'''
def __init__(self, engine, autocommit=False):
@@ -45,19 +18,5 @@
self.session.rollback()
self.session.close()
-class DBDefer(object):
- '''a twisted sqlalchemy connector this Decorator adds a session parameter, with a valid session connection'''
- def __init__(self, engine, autocommit=False):
- self.autocommit=autocommit
- self.engine = engine
- 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)
- return wrapper
-def vTyp(value,field):
- return value
--- a/tests/xmlrpc.py Fri Jan 27 21:14:18 2012 +0100
+++ b/tests/xmlrpc.py Fri Jan 27 21:21:41 2012 +0100
@@ -6,9 +6,11 @@
from tempfile import mkdtemp
import shutil
-from iro.model.utils import WithSession, POOL_SIZE as DB_POOL_SIZE
+from iro.model.utils import WithSession
+from iro.model import POOL_SIZE as DB_POOL_SIZE
-from iro.model.schema import User, Base
+from iro.model.schema import User, Base, Offer, Userright
+import iro.model.schema as schema
from ngdatabase.mysql import Server, createConfig, Database
@@ -46,6 +48,12 @@
self.__debug().stop()
time.sleep(.2)
self.s.join()
+ self.__cleanDB()
+
+ def __cleanDB(self):
+ with WithSession(md.engine, autocommit=True) as session:
+ for table in schema.__tables__:
+ session.query(getattr(schema,table)).delete()
def __debug(self):
return xServer('http://localhost:7080/debug')
@@ -64,6 +72,9 @@
self.failUnlessEqual(ret, ['listMethods', 'status', 'stop', 'sms', 'fax', 'mail', 'routes', 'defaultRoute', 'statistic'])
def testStatus(self):
+ ''' test the status function'''
+ with WithSession(md.engine, autocommit=True) as session:
+ session.add(User(name='test',apikey='abcdef123456789'))
ret = self.__rpc2().status('abcdef123456789')
self.failUnlessEqual(ret, "<User('test','abcdef123456789')>")
self.failUnlessEqual(self.__rpc2().status('abcdef123456789','abcde'), ["<User('test','abcdef123456789')>",'abcde',False])
@@ -73,12 +84,11 @@
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
bewcause xmlrpc only has a Fault exception this Exception has to be deliverd through a xmlrpclib.Fault Exception'''
with self.assertRaises(Fault) as fault:
- self.__rpc2().status('abcdef123456788')
+ self.__rpc2().status('abcdef123456789')
exc = fault.exception
unf=IroError.UserNotFound()
self.failUnlessEqual(exc.faultCode, unf.code)
@@ -100,6 +110,28 @@
self.failUnlessEqual(exc.faultCode, 700)
self.failUnlessEqual(exc.faultString, "Validation of 'apikey' failed.")
+ def testRoutes(self):
+ '''test the route function'''
+ with WithSession(md.engine, autocommit=True) as session:
+ u=User(name='test',apikey='abcdef123456789')
+ o=Offer(name="sipgate_basic", provider="sipgate", route="basic", typ="sms")
+ u.rights.append(Userright(o))
+ session.add(u)
+ self.failUnlessEqual(self.__rpc2().routes('abcdef123456789','sms'),['sipgate_basic'])
+
+ with self.assertRaises(Fault) as fault:
+ self.__rpc2().routes('abcdef123456789','fax')
+ exc = fault.exception
+ self.failUnlessEqual(exc.faultCode, 700)
+ self.failUnlessEqual(exc.faultString, "Typ is not valid.")
+
+ with WithSession(md.engine, autocommit=True) as session:
+ o=Offer(name="sipgate_plus", provider="sipgate", route="plus", typ="sms")
+ u = session.query(User).filter_by(name="test").first()
+ u.rights.append(Userright(o))
+ session.commit()
+ self.failUnlessEqual(self.__rpc2().routes('abcdef123456789','sms'),['sipgate_basic','sipgate_plus'])
+
def startReactor(engine):
"""starts the Rector with a special debug Clild, so that the reactor can be stopped remotly. """
from twisted.internet import reactor
@@ -136,8 +168,6 @@
self.server.start()
self.db.create()
Base.metadata.create_all(self.engine)
- with WithSession(self.engine, autocommit=True) as session:
- session.add(User(name='test',apikey='abcdef123456789'))
def tearDown(self):
self.server.stop()