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

Source Code for Module pushnotify.prowl

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3  # 
  4  # Copyright (C) 2013 Jeffrey Goettsch and other contributors. 
  5  # 
  6  # This file is part of py-pushnotify. 
  7  # 
  8  # py-pushnotify is free software: you can redistribute it and/or modify 
  9  # it under the terms of the GNU General Public License as published by 
 10  # the Free Software Foundation, either version 3 of the License, or 
 11  # (at your option) any later version. 
 12  # 
 13  # py-pushnotify is distributed in the hope that it will be useful, 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 16  # GNU General Public License for more details. 
 17  # 
 18  # You should have received a copy of the GNU General Public License 
 19  # along with py-pushnotify.  If not, see <http://www.gnu.org/licenses/>. 
 20   
 21  """Module for sending push notifications to iOS devices that have 
 22  Prowl installed. See http://www.prowlapp.com/ for more 
 23  information. 
 24   
 25  """ 
 26   
 27   
 28  try: 
 29      from xml.etree import cElementTree 
 30      ElementTree = cElementTree 
 31  except ImportError: 
 32      from xml.etree import ElementTree 
 33   
 34  from pushnotify import abstract 
 35  from pushnotify import exceptions 
 36   
 37   
 38  PUBLIC_API_URL = u'https://api.prowlapp.com/publicapi' 
 39  VERIFY_URL = u'/'.join([PUBLIC_API_URL, 'verify']) 
 40  NOTIFY_URL = u'/'.join([PUBLIC_API_URL, 'add']) 
 41  RETRIEVE_TOKEN_URL = u'/'.join([PUBLIC_API_URL, 'retrieve', 'token']) 
 42  RETRIEVE_APIKEY_URL = u'/'.join([PUBLIC_API_URL, 'retrieve', 'apikey']) 
 43   
 44  DESC_LIMIT = 10000 
 45   
 46   
47 -class Client(abstract.AbstractClient):
48 """Client for sending push notificiations to iOS devices with 49 the Prowl application installed. 50 51 Member Vars: 52 developerkey: A string containing a valid provider key for the 53 Prowl application. 54 application: A string containing the name of the application on 55 behalf of whom the Prowl client will be sending messages. 56 apikeys: A dictionary where the keys are strings containing 57 valid user API keys, and the values are lists of strings, 58 each containing a valid user device key. Device keys are not 59 used by this client. 60 61 """ 62
63 - def __init__(self, developerkey='', application=''):
64 """Initialize the Prowl client. 65 66 Args: 67 developerkey: A string containing a valid provider key for 68 the Prowl application. 69 application: A string containing the name of the application 70 on behalf of whom the Prowl client will be sending 71 messages. 72 73 """ 74 75 super(self.__class__, self).__init__(developerkey, application) 76 77 self._type = 'prowl' 78 self._urls = {'notify': NOTIFY_URL, 'verify': VERIFY_URL, 79 'retrieve_token': RETRIEVE_TOKEN_URL, 80 'retrieve_apikey': RETRIEVE_APIKEY_URL}
81
82 - def _parse_response(self, response, verify=False):
83 84 xmlresp = response.text 85 self.logger.info('received response: {0}'.format(xmlresp)) 86 87 root = ElementTree.fromstring(xmlresp) 88 89 self._last['type'] = root[0].tag.lower() 90 self._last['code'] = root[0].attrib['code'] 91 92 if self._last['type'] == 'success': 93 self._last['message'] = None 94 self._last['remaining'] = root[0].attrib['remaining'] 95 self._last['resetdate'] = root[0].attrib['resetdate'] 96 elif self._last['type'] == 'error': 97 self._last['message'] = root[0].text 98 self._last['remaining'] = None 99 self._last['resetdate'] = None 100 101 if (not verify or 102 (self._last['code'] != '400' and 103 self._last['code'] != '401')): 104 self._raise_exception() 105 else: 106 raise exceptions.UnrecognizedResponseError(xmlresp, -1) 107 108 if len(root) > 1: 109 if root[1].tag.lower() == 'retrieve': 110 if 'token' in root[1].attrib: 111 self._last['token'] = root[1].attrib['token'] 112 self._last['token_url'] = root[1].attrib['url'] 113 self._last['apikey'] = None 114 elif 'apikey' in root[1].attrib: 115 self._last['token'] = None 116 self._last['token_url'] = None 117 self._last['apikey'] = root[1].attrib['apikey'] 118 else: 119 raise exceptions.UnrecognizedResponseError(xmlresp, -1) 120 else: 121 raise exceptions.UnrecognizedResponseError(xmlresp, -1) 122 123 return root
124
125 - def _raise_exception(self):
126 127 if self._last['code'] == '400': 128 raise exceptions.FormatError(self._last['message'], 129 int(self._last['code'])) 130 elif self._last['code'] == '401': 131 if 'provider' not in self._last['message'].lower(): 132 raise exceptions.ApiKeyError(self._last['message'], 133 int(self._last['code'])) 134 else: 135 raise exceptions.ProviderKeyError(self._last['message'], 136 int(self._last['code'])) 137 elif self._last['code'] == '406': 138 raise exceptions.RateLimitExceeded(self._last['message'], 139 int(self._last['code'])) 140 elif self._last['code'] == '409': 141 raise exceptions.PermissionDenied(self._last['message'], 142 int(self._last['code'])) 143 elif self._last['code'] == '500': 144 raise exceptions.ServerError(self._last['message'], 145 int(self._last['code'])) 146 else: 147 raise exceptions.UnknownError(self._last['message'], 148 int(self._last['code']))
149
150 - def notify(self, description, event, split=True, kwargs=None):
151 """Send a notification to each user's apikey in self.apikeys. 152 153 Args: 154 description: A string of up to DESC_LIMIT characters 155 containing the notification text. 156 event: A string of up to 1024 characters containing a 157 subject or brief description of the event. 158 split: A boolean indicating whether to split long 159 descriptions among multiple notifications (True) or to 160 possibly raise an exception (False). (default True) 161 kwargs: A dictionary with any of the following strings as 162 keys: 163 priority: An integer between -2 and 2, indicating the 164 priority of the notification. -2 is the lowest, 2 is 165 the highest, and 0 is normal. 166 url: A string of up to 512 characters containing a URL 167 to attach to the notification. 168 (default: None) 169 170 Raises: 171 pushnotify.exceptions.ApiKeyError 172 pushnotify.exceptions.FormatError 173 pushnotify.exceptions.RateLimitExceeded 174 pushnotify.exceptions.ServerError 175 pushnotify.exceptions.UnknownError 176 pushnotify.exceptions.UnrecognizedResponseError 177 178 """ 179 180 def send_notify(description, event, kwargs): 181 data = {'apikey': ','.join(self.apikeys), 182 'application': self.application, 183 'event': event, 184 'description': description} 185 186 if self.developerkey: 187 data['providerkey'] = self.developerkey 188 189 if kwargs: 190 data.update(kwargs) 191 192 response = self._post(self._urls['notify'], data) 193 self._parse_response(response)
194 195 if not self.apikeys: 196 self.logger.warn('notify called with no users set') 197 return 198 199 if split: 200 while description: 201 this_desc = description[0:DESC_LIMIT] 202 description = description[DESC_LIMIT:] 203 send_notify(this_desc, event, kwargs) 204 else: 205 send_notify(description, event, kwargs)
206
207 - def retrieve_apikey(self, reg_token):
208 """Get a user's API key for a given registration token. 209 210 Once a user has approved you sending them push notifications, 211 you can supply the returned token here and get an API key. 212 213 Args: 214 reg_token: A string containing a registration token returned 215 from the retrieve_token method. 216 217 Raises: 218 pushnotify.exceptions.ProviderKeyError 219 220 Returns: 221 A string containing the API key. 222 223 """ 224 225 data = {'providerkey': self.developerkey, 226 'token': reg_token} 227 228 response = self._get(self._urls['retrieve_apikey'], data) 229 self._parse_response(response) 230 231 return self._last['apikey']
232
233 - def retrieve_token(self):
234 """Get a registration token and approval URL. 235 236 A user follows the approval URL and logs in to the Prowl website 237 to approve you sending them push notifications. If you have 238 associated a 'Retrieve success URL' with your provider key, they 239 will be redirected there. 240 241 Raises: 242 pushnotify.exceptions.ProviderKeyError 243 244 Returns: 245 A two-item tuple where the first item is a string containing 246 a registration token, and the second item is a string 247 containing the associated URL. 248 """ 249 250 data = {'providerkey': self.developerkey} 251 252 response = self._get(self._urls['retrieve_token'], data) 253 self._parse_response(response) 254 255 return self._last['token'], self._last['token_url']
256
257 - def verify_user(self, apikey):
258 """Verify a user's API key. 259 260 Args: 261 apikey: A string of 40 characters containing a user's API 262 key. 263 264 Raises: 265 pushnotify.exceptions.RateLimitExceeded 266 pushnotify.exceptions.ServerError 267 pushnotify.exceptions.UnknownError 268 pushnotify.exceptions.UnrecognizedResponseError 269 270 Returns: 271 A boolean containing True if the user's API key is valid, 272 and False if it is not. 273 274 """ 275 276 data = {'apikey': apikey} 277 278 if self.developerkey: 279 data['providerkey'] = self.developerkey 280 281 response = self._get(self._urls['verify'], data) 282 self._parse_response(response, True) 283 284 return self._last['code'] == '200'
285 286 if __name__ == '__main__': 287 pass 288