iro/offer/smstrade.py
changeset 302 3f4bdea2abbf
parent 295 dc3cc61c7f6f
child 307 6acae4210716
equal deleted inserted replaced
90:eb04ac3a8327 302:3f4bdea2abbf
       
     1 # -*- coding: utf-8 -*-
       
     2 
       
     3 # Copyright (c) 2012 netzguerilla.net <iro@netzguerilla.net>
       
     4 # 
       
     5 # This file is part of Iro.
       
     6 # 
       
     7 # Permission is hereby granted, free of charge, to any person obtaining a copy of
       
     8 # this software and associated documentation files (the "Software"), to deal in
       
     9 # the Software without restriction, including without limitation the rights to use,
       
    10 # copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
       
    11 # #Software, and to permit persons to whom the Software is furnished to do so,
       
    12 # subject to the following conditions:
       
    13 # 
       
    14 # The above copyright notice and this permission notice shall be included in
       
    15 # all copies or substantial portions of the Software.
       
    16 # 
       
    17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       
    18 # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       
    19 # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       
    20 # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       
    21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       
    22 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       
    23 
       
    24 
       
    25 import urllib
       
    26 from functools import partial
       
    27 from decimal import Decimal
       
    28 #import copy
       
    29 
       
    30 from ..config import Option
       
    31 from ..model.status import Status
       
    32 from .provider import Provider, providers
       
    33 from ..error import RejectRecipient, ExternalException
       
    34 
       
    35 #import logging
       
    36 #logger=logging.getLogger("smstrade")
       
    37 
       
    38 statusCodes = {10 : "Empfaengernummer nicht korrekt.",
       
    39     20 : "Absenderkennung nicht korrekt.",
       
    40     30 : "Nachrichtentext nicht korrekt.",
       
    41     31 : "Messagetyp nicht korrekt.",
       
    42     40 : "SMS Route nicht korrekt.",
       
    43     50 : "Identifikation fehlgeschlagen.",
       
    44     60 : "nicht genuegend Guthaben.",
       
    45     70 : "Netz wird von Route nicht abgedeckt.",
       
    46     71 : "Feature nicht ueber diese Route moeglich.",
       
    47     80 : "Uebergabe an SMS-C fehlgeschlagen.",
       
    48     90 : "Versand nicht moeglich.",
       
    49     100 : "SMS wurde versendet.",
       
    50     }
       
    51 """statuscodes of external smstrade API"""
       
    52 
       
    53 
       
    54 class SmstradeException(ExternalException):
       
    55     """An excetion that connects the status code with the excetion string (see :attr:`statusCodes`)"""
       
    56     def __init__(self,status):
       
    57         ExternalException.__init__(self)
       
    58         self.status = status
       
    59         self.str_=str(status)
       
    60     
       
    61     def __str__(self):
       
    62         return "%s\n%s"%(ExternalException.__str__(self),self.str_)
       
    63 
       
    64 
       
    65 class StatusCode:
       
    66     """Class that represents the output of one smstrade request."""
       
    67     def __init__(self,code, exID=None, costs=Decimal("0.0"), count=0):
       
    68         self.code = code
       
    69         
       
    70         self.exID = exID
       
    71         self.costs = Decimal(costs)
       
    72         self.count = int(count)
       
    73      
       
    74     def __str__(self):
       
    75         if self.code in statusCodes.keys():
       
    76             return "%i: %s"%(self.code, statusCodes[self.code])
       
    77         
       
    78         return "%i: unknown statuscode."%self.code
       
    79 
       
    80     def __int__(self):
       
    81         return self.code
       
    82 
       
    83 class Smstrade(Provider):
       
    84     """A Provider to send SMS to recipients using smstrade.
       
    85     Smstrade only supports to send SMS  and four diffrent routes: ``["basic","economy","gold","direct"]``.
       
    86 
       
    87     It needs a smstrade Gateway Key https://login.smstrade.de/index.php?gateway in configuration file.
       
    88 
       
    89     smstrade API documentation:  http://kundencenter.smstrade.de/sites/smstrade.de.kundencenter/__pdf/SMS-Gateway_HTTP_API_v2.pdf
       
    90 
       
    91     The smstrade API supports a debug mode, that can be set  with :attr:`~iro.offer.provider.Provider.testmode`.
       
    92     """
       
    93     _params= {"debug":("boolean",False),
       
    94             "concat_sms":('boolean',False),
       
    95             "message_id":('boolean',False),
       
    96             "count":('boolean',False),
       
    97             "cost":('boolean',False),
       
    98            }
       
    99     '''dict for standrd values of the smstrade api, it is used to get the right values to the API.'''
       
   100 
       
   101     def __init__(self, name):       
       
   102         self.url = "https://gateway.smstrade.de"
       
   103         options =[("key", Option(lambda x,y:x,long="smstrade Gateway Key https://login.smstrade.de/index.php?gateway", must=True)),]
       
   104         Provider.__init__(self, name, {"sms":["basic","economy","gold","direct"]},options)
       
   105 
       
   106     def send(self, route, recipient, sms):
       
   107         """send one SMS to recipient via route
       
   108         
       
   109         :param string route: A valid route ``["basic", "economy", "gold", "direct"]``
       
   110         :param `iro.telnumber.Telnumber` recipient: Mobilenumber of recipient
       
   111         :param `iro.model.message.SMS` sms: the sms to send
       
   112         :return:
       
   113             - All went ok -- :class:`iro.model.status.Status` object
       
   114             - otherwise -- an exception
       
   115         """
       
   116         #logger.debug('smstrade.sendSMS(%s,%s)'%(sms,  recipient))
       
   117 
       
   118         route = unicode(route)
       
   119 
       
   120         if recipient.land != '49' and route == "basic":
       
   121             raise RejectRecipient(recipient)
       
   122         
       
   123         to ='00'+recipient.land+recipient.number
       
   124         
       
   125         s = self.__send(route, to, sms)	
       
   126         if int(s) in (100,):
       
   127             return Status(self,route, exID=s.exID, costs=s.costs, count=s.count)
       
   128         elif int(s) in (70,71,):
       
   129             raise RejectRecipient(recipient, status=s)
       
   130         else:
       
   131             raise SmstradeException(s)
       
   132 
       
   133     def __send(self, route, to, sms):
       
   134         """ This is the main function to request to the sms service.    
       
   135 
       
   136         :param string route: A valid route ``["basic", "economy", "gold", "direct"]
       
   137         :param string recipient: Mobilenumber of recipient
       
   138         :param `iro.model.message.sms` sms: the sms to send
       
   139         :return: a :class:`.StatusCode` object
       
   140         """
       
   141         
       
   142         #logger.debug('smstrade._send(%s,%s,%s)'%( route, to, sms))
       
   143         parameters= {"key": self.key,
       
   144                 "route": route,
       
   145                 "to": to,
       
   146                 "message": sms.content,
       
   147                 "charset":"utf-8", 
       
   148                 "debug": self.testmode,
       
   149                 "message_id":True,
       
   150                 "count":True,
       
   151                 "cost":True,
       
   152                 }
       
   153         
       
   154         doubleChar="€[]{}|\\^~"    #these charactar need two GSM Chars
       
   155 
       
   156         if sms.from_ is not None:
       
   157             parameters["from"] = sms.from_
       
   158        
       
   159         length=len(sms.content)
       
   160         for s in doubleChar:
       
   161             length += sms.content.count(s)
       
   162         parameters["concat_sms"] = True if length > 160 else False
       
   163 
       
   164         ps={}
       
   165         for p in parameters:
       
   166             if p in self._params.keys():
       
   167                 if self._params[p][0] == "boolean":
       
   168                     if parameters[p] != self._params[p][1]:
       
   169                         ps[p]=int(bool(parameters[p]))
       
   170             else:
       
   171                 ps[p] = parameters[p]
       
   172 
       
   173         params = urllib.urlencode(ps)
       
   174         #dp=copy.deepcopy(ps)
       
   175         #dp["key"]="<KEY>"
       
   176         #print 'smstrade._send-parameters:%s\n\t->%s'%(str(dp), urllib.urlencode(dp))
       
   177         
       
   178         response = urllib.urlopen(self.url, params)
       
   179         data = response.readlines()
       
   180         if len(data) == 1:
       
   181             return StatusCode(int(data[0]))
       
   182         return StatusCode(int(data[0]),exID=data[1],costs=data[2],count=data[3])
       
   183 
       
   184     def getSendFunc(self, typ, route):
       
   185         """returns  a partial :meth:`send` methed with bounded route, if typ and route is valid."""
       
   186 
       
   187         Provider.getSendFunc(self, typ, route)
       
   188         return partial(self.send,route)
       
   189 
       
   190 providers["smstrade"]=Smstrade