diff -r eb04ac3a8327 -r 3f4bdea2abbf iro/offer/smstrade.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/offer/smstrade.py Thu Sep 27 17:15:46 2012 +0200 @@ -0,0 +1,190 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 netzguerilla.net +# +# This file is part of Iro. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +# #Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +import urllib +from functools import partial +from decimal import Decimal +#import copy + +from ..config import Option +from ..model.status import Status +from .provider import Provider, providers +from ..error import RejectRecipient, ExternalException + +#import logging +#logger=logging.getLogger("smstrade") + +statusCodes = {10 : "Empfaengernummer nicht korrekt.", + 20 : "Absenderkennung nicht korrekt.", + 30 : "Nachrichtentext nicht korrekt.", + 31 : "Messagetyp nicht korrekt.", + 40 : "SMS Route nicht korrekt.", + 50 : "Identifikation fehlgeschlagen.", + 60 : "nicht genuegend Guthaben.", + 70 : "Netz wird von Route nicht abgedeckt.", + 71 : "Feature nicht ueber diese Route moeglich.", + 80 : "Uebergabe an SMS-C fehlgeschlagen.", + 90 : "Versand nicht moeglich.", + 100 : "SMS wurde versendet.", + } +"""statuscodes of external smstrade API""" + + +class SmstradeException(ExternalException): + """An excetion that connects the status code with the excetion string (see :attr:`statusCodes`)""" + def __init__(self,status): + ExternalException.__init__(self) + self.status = status + self.str_=str(status) + + def __str__(self): + return "%s\n%s"%(ExternalException.__str__(self),self.str_) + + +class StatusCode: + """Class that represents the output of one smstrade request.""" + def __init__(self,code, exID=None, costs=Decimal("0.0"), count=0): + self.code = code + + self.exID = exID + self.costs = Decimal(costs) + self.count = int(count) + + def __str__(self): + if self.code in statusCodes.keys(): + return "%i: %s"%(self.code, statusCodes[self.code]) + + return "%i: unknown statuscode."%self.code + + def __int__(self): + return self.code + +class Smstrade(Provider): + """A Provider to send SMS to recipients using smstrade. + Smstrade only supports to send SMS and four diffrent routes: ``["basic","economy","gold","direct"]``. + + It needs a smstrade Gateway Key https://login.smstrade.de/index.php?gateway in configuration file. + + smstrade API documentation: http://kundencenter.smstrade.de/sites/smstrade.de.kundencenter/__pdf/SMS-Gateway_HTTP_API_v2.pdf + + The smstrade API supports a debug mode, that can be set with :attr:`~iro.offer.provider.Provider.testmode`. + """ + _params= {"debug":("boolean",False), + "concat_sms":('boolean',False), + "message_id":('boolean',False), + "count":('boolean',False), + "cost":('boolean',False), + } + '''dict for standrd values of the smstrade api, it is used to get the right values to the API.''' + + def __init__(self, name): + self.url = "https://gateway.smstrade.de" + options =[("key", Option(lambda x,y:x,long="smstrade Gateway Key https://login.smstrade.de/index.php?gateway", must=True)),] + Provider.__init__(self, name, {"sms":["basic","economy","gold","direct"]},options) + + def send(self, route, recipient, sms): + """send one SMS to recipient via route + + :param string route: A valid route ``["basic", "economy", "gold", "direct"]`` + :param `iro.telnumber.Telnumber` recipient: Mobilenumber of recipient + :param `iro.model.message.SMS` sms: the sms to send + :return: + - All went ok -- :class:`iro.model.status.Status` object + - otherwise -- an exception + """ + #logger.debug('smstrade.sendSMS(%s,%s)'%(sms, recipient)) + + route = unicode(route) + + if recipient.land != '49' and route == "basic": + raise RejectRecipient(recipient) + + to ='00'+recipient.land+recipient.number + + s = self.__send(route, to, sms) + if int(s) in (100,): + return Status(self,route, exID=s.exID, costs=s.costs, count=s.count) + elif int(s) in (70,71,): + raise RejectRecipient(recipient, status=s) + else: + raise SmstradeException(s) + + def __send(self, route, to, sms): + """ This is the main function to request to the sms service. + + :param string route: A valid route ``["basic", "economy", "gold", "direct"] + :param string recipient: Mobilenumber of recipient + :param `iro.model.message.sms` sms: the sms to send + :return: a :class:`.StatusCode` object + """ + + #logger.debug('smstrade._send(%s,%s,%s)'%( route, to, sms)) + parameters= {"key": self.key, + "route": route, + "to": to, + "message": sms.content, + "charset":"utf-8", + "debug": self.testmode, + "message_id":True, + "count":True, + "cost":True, + } + + doubleChar="€[]{}|\\^~" #these charactar need two GSM Chars + + if sms.from_ is not None: + parameters["from"] = sms.from_ + + length=len(sms.content) + for s in doubleChar: + length += sms.content.count(s) + parameters["concat_sms"] = True if length > 160 else False + + ps={} + for p in parameters: + if p in self._params.keys(): + if self._params[p][0] == "boolean": + if parameters[p] != self._params[p][1]: + ps[p]=int(bool(parameters[p])) + else: + ps[p] = parameters[p] + + params = urllib.urlencode(ps) + #dp=copy.deepcopy(ps) + #dp["key"]="" + #print 'smstrade._send-parameters:%s\n\t->%s'%(str(dp), urllib.urlencode(dp)) + + response = urllib.urlopen(self.url, params) + data = response.readlines() + if len(data) == 1: + return StatusCode(int(data[0])) + return StatusCode(int(data[0]),exID=data[1],costs=data[2],count=data[3]) + + def getSendFunc(self, typ, route): + """returns a partial :meth:`send` methed with bounded route, if typ and route is valid.""" + + Provider.getSendFunc(self, typ, route) + return partial(self.send,route) + +providers["smstrade"]=Smstrade