Package pushnotify :: Module nma
[hide private]
[frames] | no frames]

Source Code for Module pushnotify.nma

  1  #!/usr/bin/env python 
  2  # vim: set fileencoding=utf-8 
  3   
  4  """Module for sending push notifications to Android devices that have 
  5  Notify My Android installed. See www.notifymyandroid.com/ for more 
  6  information. 
  7   
  8  copyright: Copyright (c) Jeffrey Goettsch and other contributors. 
  9  license: BSD, see LICENSE for details. 
 10   
 11  """ 
 12   
 13   
 14  import logging 
 15  import urllib 
 16  import urllib2 
 17  try: 
 18      from xml.etree import cElementTree 
 19      ElementTree = cElementTree 
 20  except ImportError: 
 21      from xml.etree import ElementTree 
 22   
 23  from pushnotify import exceptions 
 24   
 25   
 26  PUBLIC_API_URL = u'https://www.notifymyandroid.com/publicapi' 
 27  VERIFY_URL = u'/'.join([PUBLIC_API_URL, 'verify']) 
 28  NOTIFY_URL = u'/'.join([PUBLIC_API_URL, 'notify']) 
 29   
 30   
31 -class Client(object):
32 """Client for sending push notificiations to Android devices with 33 the Notify My Android application installed. 34 35 Member Vars: 36 apikeys: A list of strings, each containing a 48 character api 37 key. 38 developerkey: A string containing a 48 character developer key. 39 40 """ 41
42 - def __init__(self, apikeys=None, developerkey=None):
43 """Initialize the Notify My Android client. 44 45 Args: 46 apikeys: A list of strings, each containing a valid api 47 key. 48 developerkey: A string containing a valid developer key. 49 50 """ 51 52 self.logger = logging.getLogger('{0}.{1}'.format( 53 self.__module__, self.__class__.__name__)) 54 55 self._browser = urllib2.build_opener(urllib2.HTTPSHandler()) 56 self._last_type = None 57 self._last_code = None 58 self._last_message = None 59 self._last_remaining = None 60 self._last_resettimer = None 61 62 self.apikeys = [] if apikeys is None else apikeys 63 self.developerkey = developerkey
64
65 - def _get(self, url):
66 67 self.logger.debug('_get requesting url: {0}'.format(url)) 68 69 request = urllib2.Request(url) 70 response_stream = self._browser.open(request) 71 response = response_stream.read() 72 73 self.logger.info('_get received response: {0}'.format(response)) 74 75 return response
76
77 - def _parse_response(self, xmlresp, verify=False):
78 79 root = ElementTree.fromstring(xmlresp) 80 81 self._last_type = root[0].tag.lower() 82 self._last_code = root[0].attrib['code'] 83 84 if self._last_type == 'success': 85 self._last_message = None 86 self._last_remaining = root[0].attrib['remaining'] 87 self._last_resettimer = root[0].attrib['resettimer'] 88 elif self._last_type == 'error': 89 self._last_message = root[0].text 90 self._last_remaining = None 91 self._last_resettimer = None 92 93 if (not verify or 94 (self._last_code != '400' and self._last_code != '401')): 95 self._raise_exception() 96 else: 97 raise exceptions.UnrecognizedResponseError(xmlresp, -1) 98 99 return root
100
101 - def _post(self, url, data):
102 103 self.logger.debug('_post sending data: {0}'.format(data)) 104 self.logger.debug('_post sending to url: {0}'.format(url)) 105 106 request = urllib2.Request(url, data) 107 response_stream = self._browser.open(request) 108 response = response_stream.read() 109 110 self.logger.info('_post received response: {0}'.format(response)) 111 112 return response
113
114 - def _raise_exception(self):
115 116 if self._last_code == '400': 117 raise exceptions.FormatError(self._last_message, 118 int(self._last_code)) 119 elif self._last_code == '401': 120 raise exceptions.ApiKeyError(self._last_message, 121 int(self._last_code)) 122 elif self._last_code == '402': 123 raise exceptions.RateLimitExceeded(self._last_message, 124 int(self._last_code)) 125 elif self._last_code == '500': 126 raise exceptions.ServerError(self._last_message, 127 int(self._last_code)) 128 else: 129 raise exceptions.UnknownError(self._last_message, 130 int(self._last_code))
131
132 - def notify(self, app, event, desc, kwargs=None):
133 """Send a notification to each apikey in self.apikeys. 134 135 Args: 136 app: A string of up to 256 characters containing the name 137 of the application sending the notification. 138 event: A string of up to 1000 characters containing the 139 event that is being notified (i.e. subject or brief 140 description.) 141 desc: A string of up to 10000 characters containing the 142 notification text. 143 kwargs: A dictionary with any of the following strings as 144 keys: 145 priority: An integer between -2 and 2, indicating the 146 priority of the notification. -2 is the lowest, 2 is 147 the highest, and 0 is normal. 148 url: A string of up to 2000 characters containing a URL 149 to attach to the notification. 150 content_type: A string containing "text/html" (without 151 the quotes) that then allows some basic HTML to be 152 used while displaying the notification. 153 (default: None) 154 155 Raises: 156 pushnotify.exceptions.FormatError 157 pushnotify.exceptions.ApiKeyError 158 pushnotify.exceptions.RateLimitExceeded 159 pushnotify.exceptions.ServerError 160 pushnotify.exceptions.UnknownError 161 pushnotify.exceptions.UnrecognizedResponseError 162 163 """ 164 165 data = {'apikey': ','.join(self.apikeys), 166 'application': app, 167 'event': event, 168 'description': desc} 169 170 if self.developerkey: 171 data['developerkey'] = self.developerkey 172 173 if kwargs: 174 data.update(kwargs) 175 176 data = urllib.urlencode(data) 177 178 response = self._post(NOTIFY_URL, data) 179 self._parse_response(response)
180
181 - def verify(self, apikey):
182 """Verify an API key. 183 184 Args: 185 apikey: A string of 48 characters containing an API key. 186 187 Raises: 188 pushnotify.exceptions.RateLimitExceeded 189 pushnotify.exceptions.ServerError 190 pushnotify.exceptions.UnknownError 191 pushnotify.exceptions.UnrecognizedResponseError 192 193 Returns: 194 A boolean containing True if the API key is valid, and False 195 if it is not. 196 197 """ 198 199 data = {'apikey': apikey} 200 201 if self.developerkey: 202 data['developerkey'] = self.developerkey 203 204 querystring = urllib.urlencode(data) 205 url = '?'.join([VERIFY_URL, querystring]) 206 207 response = self._get(url) 208 self._parse_response(response, True) 209 210 return self._last_code == '200'
211 212 if __name__ == '__main__': 213 pass 214