iro/model/schema.py
branchdevel
changeset 258 0a5eb5aac0be
parent 219 4e9d79c35088
child 263 52284710c0b4
equal deleted inserted replaced
257:31114e40178d 258:0a5eb5aac0be
    15 from ..error import JobNotFound
    15 from ..error import JobNotFound
    16 
    16 
    17 Base = declarative_base()
    17 Base = declarative_base()
    18 
    18 
    19 class Userright(Base):
    19 class Userright(Base):
    20     """Über welche Routen darf ein Benutzer Daten verschicken und welches sind die Standardrouten (<em>default!=None</em>) für den Benuter. Geordnert werden die Standardrouten nach default."""
    20     """Allowed offers for one user. Default routes are sorted by **default** value."""
    21     __tablename__ = 'userright'
    21     __tablename__ = 'userright'
    22     user_name = Column('user', String(100), ForeignKey('apiuser.name'), primary_key=True)
    22     user_name = Column('user', String(100), ForeignKey('apiuser.name'), primary_key=True)
       
    23     """username"""
    23     offer_name = Column('offer', String(100), ForeignKey('offer.name'), primary_key=True)
    24     offer_name = Column('offer', String(100), ForeignKey('offer.name'), primary_key=True)
       
    25     """offername"""
    24     default = Column(Integer)
    26     default = Column(Integer)
       
    27     """sorting defaults routes with this value"""
    25     offer = relationship("Offer")
    28     offer = relationship("Offer")
       
    29     """connected :class:`Offer` object"""
    26     user = relationship("User")
    30     user = relationship("User")
       
    31     """connected :class:`User` object"""
    27 
    32 
    28     def __init__(self, offer, default=None):
    33     def __init__(self, offer, default=None):
       
    34         """Constructor of Userright class.
       
    35 
       
    36         :param `Offer` offer: a offer object
       
    37         :param integer default: default value
       
    38         """
       
    39 
    29         self.offer = offer
    40         self.offer = offer
    30         self.default = default
    41         self.default = default
    31 
    42 
    32     @property
    43     @property
    33     def bill(self):
    44     def bill(self):
    34         '''getting a list of unbilled messages grouped by Job.info'''
    45         """returns a list of unbilled messages grouped by Job.info"""
    35         query = [ func.count(Message.id).label('anz'),      # anz of messages
    46         query = [ func.count(Message.id).label('anz'),      # anz of messages
    36                   func.sum(Message.price).label("price"),   # price of the messages
    47                   func.sum(Message.price).label("price"),   # price of the messages
    37                   Job.info.label('info'),                   # info tag
    48                   Job.info.label('info'),                   # info tag
    38                   ]
    49                   ]
    39 
    50 
    43                    Message.job_id==Job.id,                  # join Message and Job
    54                    Message.job_id==Job.id,                  # join Message and Job
    44                 ]
    55                 ]
    45         return object_session(self).query(*query).filter(and_(*filters)).group_by(Job.info)
    56         return object_session(self).query(*query).filter(and_(*filters)).group_by(Job.info)
    46 
    57 
    47 class Offer(Base):
    58 class Offer(Base):
    48     """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."""
    59     """All possible Offers over a Message can be sended. **provider**, **typ** and **route** are used to get the data form configuration file."""
    49     __tablename__ = "offer"
    60     __tablename__ = "offer"
    50     name = Column(String(100), primary_key=True)
    61     name = Column(String(100), primary_key=True)
       
    62     """name of the offer"""
    51     provider = Column(String(100))
    63     provider = Column(String(100))
       
    64     """provider name"""
    52     route = Column(String(100))
    65     route = Column(String(100))
       
    66     """route of the provider"""
    53     typ = Column(String(100))
    67     typ = Column(String(100))
       
    68     """typ of message"""
       
    69     
       
    70     def __init__(self, **kwargs):
       
    71         Base.__init__(self,**kwargs)
    54   
    72   
    55     @classmethod
    73     @classmethod
    56     def get(cls, session, provider, route, typ):
    74     def get(cls, session, provider, route, typ):
       
    75         """returns a Offer object."""
    57         return session.query(cls).filter(and_(cls.provider==provider, cls.route==route, cls.typ==typ)).first()
    76         return session.query(cls).filter(and_(cls.provider==provider, cls.route==route, cls.typ==typ)).first()
    58 
    77 
    59     @classmethod
    78     @classmethod
    60     def routes(cls, session, typ):
    79     def routes(cls, session, typ):
       
    80         """returns a query object of all possible offers.
       
    81         
       
    82         :param string typ: get all offers that support this typ
       
    83         """
    61         return session.query(cls).filter_by(typ=typ)
    84         return session.query(cls).filter_by(typ=typ)
    62 
    85 
    63     @classmethod
    86     @classmethod
    64     def typs(cls, session):
    87     def typs(cls, session):
       
    88         """returns a list of all possible types.
       
    89         """
    65         return session.query(cls.typ).distinct()
    90         return session.query(cls.typ).distinct()
    66 
    91 
    67     @classmethod
    92     @classmethod
    68     def providers(cls, session, typ):
    93     def providers(cls, session, typ):
       
    94         """returns a list of all possible providers.
       
    95         
       
    96         :param string typ: get all providers that support this typ
       
    97         """
    69         return session.query(cls.provider).filter_by(typ=typ).distinct()
    98         return session.query(cls.provider).filter_by(typ=typ).distinct()
    70 
    99 
    71 class Message(Base):
   100 class Message(Base):
    72     """Wenn ein Vorgang von Iro Kosten erzeugt hat wird eine neue Zeile eingefügt. Solange nicht bezahlt wurde ist <em>isBilled=0</em>."""
   101     """A message that has created costs.
       
   102     
       
   103     **isBilled** is False since the bill is paid.
       
   104     """
    73     __tablename__ = "message"
   105     __tablename__ = "message"
    74     id = Column(Integer, Sequence('message_id_seq'), primary_key=True)
   106     id = Column(Integer, Sequence('message_id_seq'), primary_key=True)
       
   107     """primary key of the message"""
       
   108 
    75     recipient = Column(String(100))
   109     recipient = Column(String(100))
       
   110     """string representation of the recipient"""
       
   111     
    76     isBilled = Column(Boolean)
   112     isBilled = Column(Boolean)
       
   113     """is bill paid?"""
       
   114 
    77     date = Column(DateTime)
   115     date = Column(DateTime)
       
   116     """date of sending the message"""
       
   117 
    78     price = Column(Numeric(8,4))
   118     price = Column(Numeric(8,4))
       
   119     """price of sending the message"""
       
   120 
    79     count = Column(Integer)
   121     count = Column(Integer)
       
   122     """Count of sended messages"""
    80     exID = Column(String(100))
   123     exID = Column(String(100))
       
   124     """external API id """
       
   125 
    81     job_id = Column("job", String(40), ForeignKey('job.id'))
   126     job_id = Column("job", String(40), ForeignKey('job.id'))
       
   127     """id of the connected job"""
    82     job = relationship("Job", backref=backref('messages'))
   128     job = relationship("Job", backref=backref('messages'))
       
   129     """connected :class:`Job` object"""
       
   130     
    83     offer_id = Column("offer",String(100), ForeignKey('offer.name'))
   131     offer_id = Column("offer",String(100), ForeignKey('offer.name'))
       
   132     """sended message over this offer woth ithe offer.name"""
       
   133 
    84     offer = relationship("Offer", backref=backref('messages'))
   134     offer = relationship("Offer", backref=backref('messages'))
       
   135     """connected :class:`Offer` object"""
       
   136     
       
   137     def __init__(self, **kwargs):
       
   138         Base.__init__(self,**kwargs)
    85 
   139 
    86 
   140 
    87 class Job(Base):
   141 class Job(Base):
    88     """Ein kompletter Auftrag, der an Iro zum verschicken übergeben wird. Status zeigt den generellen Status des Auftrages an (<em>init</em>, <em>started</em>, <em>sending</em>, <em>sended</em> oder <em>error</em>). <em>info</em> wird verwendet um dem Benutzer eine Möglickeit zu geben verschiede Auftragsgruppen zu erstellen."""
   142     """A complete Job.
       
   143 
       
   144     - **status** show the status of the job (``init``, ``started``, ``sending``, ``sended`` or ``error``). 
       
   145     - **info** is used to make it possible to create diffrent billing groups for user.
       
   146     """
    89     __tablename__ = "job"
   147     __tablename__ = "job"
    90     id = Column(Integer, Sequence('job_id_seq'), primary_key=True)
   148     id = Column(Integer, Sequence('job_id_seq'), primary_key=True)
       
   149     """job id"""
    91     info = Column(String(100))
   150     info = Column(String(100))
       
   151     """job info, for billing porpuse"""
    92     status = Column(Enum("init","started","sending","sended","error"))
   152     status = Column(Enum("init","started","sending","sended","error"))
       
   153     """status of a job"""
    93     user_id = Column("user", String(100), ForeignKey('apiuser.name'))
   154     user_id = Column("user", String(100), ForeignKey('apiuser.name'))
       
   155     """connected user id"""
       
   156 
    94     user = relationship("User", backref=backref('jobs'))
   157     user = relationship("User", backref=backref('jobs'))
       
   158     """connected :class:`User` object"""
       
   159     
       
   160     def __init__(self, **kwargs):
       
   161         """
       
   162         .. automethod:: __repr__
       
   163         """
       
   164         Base.__init__(self,**kwargs)
    95 
   165 
    96     @property
   166     @property
    97     def extend(self):
   167     def extend(self):
       
   168         """returns the connected :class:`iro.model.job.ExJob`"""
    98         return job.exJobs[self.id]
   169         return job.exJobs[self.id]
    99 
   170 
   100 
   171 
   101     def __repr__(self):
   172     def __repr__(self):
       
   173         """string representation of the Job class.
       
   174 
       
   175         :return: ``<Job('id' ,'info', 'status', 'user_id')>``
       
   176         """
   102         try:
   177         try:
   103             return "<Job('%s','%s','%s','%s')>"%(self.id,self.info, self.status, self.user_id)
   178             return "<Job('%s' ,'%s', '%s', '%s')>"%(self.id,self.info, self.status, self.user_id)
   104         except DetachedInstanceError:
   179         except DetachedInstanceError:
   105             return Base.__repr__(self)
   180             return Base.__repr__(self)
   106 
   181 
   107     @classmethod
   182     @classmethod
   108     def get(cls, session, id):
   183     def get(cls, session, id):
       
   184         """returns a job object from a given id"""
   109         return session.query(cls).filter_by(id=id).first()
   185         return session.query(cls).filter_by(id=id).first()
   110 
   186 
   111 class User(Base):
   187 class User(Base):
   112     """Die Benutzerdatenbank von Iro. <em>ng_kunde</em> ist der verknüpfte netzguerilla.net Benutzer, der die Rechnung zahlt."""
   188     """One user in iro"""
   113     __tablename__ = "apiuser"
   189     __tablename__ = "apiuser"
       
   190     
   114     name = Column(String(100), primary_key=True)
   191     name = Column(String(100), primary_key=True)
       
   192     """Username"""
       
   193     
   115     ng_kunde = Column(Integer)
   194     ng_kunde = Column(Integer)
       
   195     """Connection to the netzguerilla userdatabase"""
       
   196 
   116     apikey = Column(String(50),unique=True)
   197     apikey = Column(String(50),unique=True)
       
   198     """apikey only [0-9a-f]"""
       
   199     
   117     rights = relationship('Userright')
   200     rights = relationship('Userright')
       
   201     """all allowed offers to send with."""
       
   202 
   118     def __init__(self, name, apikey):
   203     def __init__(self, name, apikey):
       
   204         """Constructor of User class.
       
   205 
       
   206         :param string name: username
       
   207         :param string apikey: apikey for the user
       
   208 
       
   209         .. automethod:: __repr__
       
   210         """
   119         self.name=name
   211         self.name=name
   120         self.apikey=apikey
   212         self.apikey=apikey
   121 
   213 
   122     def __repr__(self):
   214     def __repr__(self):
       
   215         """string representation of the user class.
       
   216 
       
   217         :return: ``<User('name', 'apikey')>``
       
   218         """
   123         try:
   219         try:
   124             return "<User('%s','%s')>"%(self.name,self.apikey)
   220             return "<User('%s','%s')>"%(self.name,self.apikey)
   125         except DetachedInstanceError:
   221         except DetachedInstanceError:
   126             return Base.__repr__(self)
   222             return Base.__repr__(self)
   127     
   223     
   128     def routes(self, typ, default = False):
   224     def routes(self, typ, default = False):
   129         '''returns a query object to get all possible routes for a given typ'''
   225         """returns a query object to get all possible routes for a given typ
       
   226 
       
   227         :param string typ: the typ
       
   228         :param boolean default: use only default routes
       
   229         """
   130         filters=[User.name == self.name,
   230         filters=[User.name == self.name,
   131                 Offer.typ == typ, 
   231                 Offer.typ == typ, 
   132                 ]
   232                 ]
   133         if default:
   233         if default:
   134             filters.append(Userright.default != None)
   234             filters.append(Userright.default != None)
   135         return object_session(self).query(Userright.offer_name).join(Offer,User).filter(and_(*filters)).order_by(Userright.default)
   235         return object_session(self).query(Userright.offer_name).join(Offer,User).filter(and_(*filters)).order_by(Userright.default)
   136    
   236    
   137     def providers(self, typ, default = False):
   237     def providers(self, typ, default = False):
   138         '''return a query object for all possible providers for a given typ'''
   238         """return a query object for all possible providers for a given typ
       
   239 
       
   240         :param string typ: the typ
       
   241         :param boolean default: use only default routes
       
   242         """
   139         filters=[User.name == self.name,
   243         filters=[User.name == self.name,
   140                 Offer.typ == typ, 
   244                 Offer.typ == typ, 
   141                 ]
   245                 ]
   142         if default:
   246         if default:
   143             filters.append(Userright.default != None)
   247             filters.append(Userright.default != None)
   144         return object_session(self).query(Offer.provider).join(Userright,User).filter(and_(*filters))
   248         return object_session(self).query(Offer.provider).join(Userright,User).filter(and_(*filters))
   145 
   249 
   146     def has_right(self, typ, offer_name = None, provider = None, route = None):
   250     def has_right(self, typ, offer_name = None, provider = None, route = None):
   147         '''returns offer_name, if the user is allowed to use offer otherwise None
   251         """if a user has the right to use a offer, provider e. al. (arguments are and connected).
   148            ->raise sqlalchemy.orm.exc.MultipleResultsFound if not a single offer match'''
   252         
       
   253         :param string typ: the typ
       
   254         :param string offer_name: offer name
       
   255         :param string provider: provider name
       
   256         :param string route: a route name
       
   257         :return: offer_name or  None (not allwoed)
       
   258         :raises: :class:`sqlalchemy.orm.exc.MultipleResultsFound` if not a single offer match"""
   149         filters=[User.name == self.name,
   259         filters=[User.name == self.name,
   150                 Offer.typ == typ, 
   260                 Offer.typ == typ, 
   151                 ]
   261                 ]
   152         if offer_name:
   262         if offer_name:
   153             filters.append(Userright.offer_name==offer_name)
   263             filters.append(Userright.offer_name==offer_name)
   157             filters.append(Offer.route==route)
   267             filters.append(Offer.route==route)
   158 
   268 
   159         return object_session(self).query(Userright.offer_name).join(Offer,User).filter(and_(*filters)).scalar()
   269         return object_session(self).query(Userright.offer_name).join(Offer,User).filter(and_(*filters)).scalar()
   160 
   270 
   161     def job(self, id):
   271     def job(self, id):
       
   272         """returns a job object.
       
   273 
       
   274         :param integer id: id of a Job
       
   275         :return: :class:`Job`
       
   276         :raises: :exc:`iro.error.JobNotFound`
       
   277         """
   162         job = object_session(self).query(Job).join(User).filter(and_(User.name == self.name, Job.id==id)).first()
   278         job = object_session(self).query(Job).join(User).filter(and_(User.name == self.name, Job.id==id)).first()
   163         if job is None:
   279         if job is None:
   164             raise JobNotFound()
   280             raise JobNotFound()
   165         return job
   281         return job