PageRenderTime 47ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/python/prowlpy.py

https://github.com/jacobb/prowlpy
Python | 296 lines | 231 code | 10 blank | 55 comment | 2 complexity | 9d26e0ab17f846d732b8e4d37fc14ee3 MD5 | raw file
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # Copyright (c) 2009, Jaccob Burch
  4. # Copyright (c) 2010, Olivier Hervieu
  5. # Copyright (c) 2011, Ken Pepple
  6. #
  7. # All rights reserved.
  8. #
  9. # Redistribution and use in source and binary forms, with or without
  10. # modification, are permitted provided that the following conditions are met:
  11. #
  12. # * Redistributions of source code must retain the above copyright
  13. # notice, this list of conditions and the following disclaimer.
  14. #
  15. # * Redistributions in binary form must reproduce the above copyright
  16. # notice, this list of conditions and the following disclaimer in the
  17. # documentation and/or other materials provided with the distribution.
  18. #
  19. # * Neither the name of the University of California, Berkeley nor the
  20. # names of its contributors may be used to endorse or promote products
  21. # derived from this software without specific prior written permission.
  22. #
  23. # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
  24. # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  25. # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  26. # DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
  27. # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  28. # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  29. # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  30. # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  32. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. """
  34. Prowlpy V0.50 originally written by Jacob Burch, modified by Olivier Hervieu.
  35. Updated to Prowl API version 1.2 by Ken Pepple.
  36. Python Prowlpy is a python module that implement the public api of Prowl to
  37. send push notification to iPhones.
  38. See http://prowlapp.com for information about Prowl.
  39. The prowlpy module respect the API of prowl. So prowlpy provides a Prowl class
  40. which implements four methods :
  41. - post, to push a notification to an iPhone,
  42. - verify_key, to verify an API key.
  43. - retrieve_token, to get a registration token for use in retrieve/apikey and
  44. the associated URL for the user to approve the request.
  45. - retrieve_apikey, to get an API key from a registration token retrieved in
  46. retrieve/token.
  47. """
  48. __author__ = 'Jacob Burch'
  49. __author_email__ = 'jacoburch@gmail.com'
  50. __maintainer__ = 'Olivier Hervieu'
  51. __maintainer_email__ = 'olivier.hervieu@gmail.com'
  52. __version__ = 0.51
  53. from httplib import HTTPSConnection as Https
  54. from urllib import urlencode
  55. from xml.dom import minidom
  56. API_DOMAIN = 'api.prowlapp.com'
  57. class Prowl(object):
  58. def __init__(self, apikey, providerkey=None):
  59. """
  60. Initialize a Prowl instance.
  61. """
  62. self.apikey = apikey
  63. # Set User-Agent
  64. self.headers = {'User-Agent': "Prowlpy/%s" % str(__version__),
  65. 'Content-type': "application/x-www-form-urlencoded"}
  66. # Aliasing
  67. self.add = self.post
  68. def _relay_error(self, error_code, reason=""):
  69. """
  70. Errors from http://www.prowlapp.com/api.php:
  71. - 400 Bad request, the parameters you provided did not validate,
  72. see ERRORMESSAGE,
  73. - 401 Not authorized, the API key given is not valid, and does not
  74. correspond to a user,
  75. - 406 Not acceptable, your IP address has exceeded the API limit,
  76. - 409 Not approved, the user has yet to approve your retrieve request,
  77. - 500 Internal server error, something failed to execute properly on
  78. the Prowl side.
  79. """
  80. if error_code == 400:
  81. raise Exception(
  82. "Bad Request. The parameters you provided did not validate")
  83. elif error_code == 401:
  84. raise Exception(
  85. "%s Probably invalid API key %s" % (reason, self.apikey))
  86. elif error_code == 406:
  87. raise Exception(
  88. "Not acceptable, your IP address has exceeded the API limit")
  89. elif error_code == 409:
  90. raise Exception(
  91. "Not approved, the user has yet to approve your retrieve request")
  92. elif error_code == 500:
  93. raise Exception(
  94. "Internal server error")
  95. def post(self, application=None, event=None,
  96. description=None, priority=0, providerkey=None,
  97. url=None):
  98. """
  99. Post a notification..
  100. You must provide either event or description or both.
  101. The parameters are :
  102. - application ; The name of your application or the application
  103. generating the event.
  104. - providerkey (optional) : your provider API key.
  105. Only necessary if you have been whitelisted.
  106. - priority (optional) : default value of 0 if not provided.
  107. An integer value ranging [-2, 2] representing:
  108. -2. Very Low
  109. -1. Moderate
  110. 0. Normal
  111. 1. High
  112. 2. Emergency (note : emergency priority messages may bypass
  113. quiet hours according to the user's settings)
  114. - event : the name of the event or subject of the notification.
  115. - description : a description of the event, generally terse.
  116. - url (optional) : The URL which should be attached to the
  117. notification.
  118. """
  119. # Create the http object
  120. h = Https(API_DOMAIN)
  121. # Perform the request and get the response headers and content
  122. data = {'apikey': self.apikey,
  123. 'application': application,
  124. 'event': event,
  125. 'description': description,
  126. 'priority': priority}
  127. if providerkey is not None:
  128. data['providerkey'] = providerkey
  129. if url is not None:
  130. data['url'] = url[0:512] # API limits to 512 characters
  131. h.request("POST",
  132. "/publicapi/add",
  133. headers=self.headers,
  134. body=urlencode(data))
  135. response = h.getresponse()
  136. request_status = response.status
  137. if request_status == 200:
  138. return True
  139. else:
  140. self._relay_error(request_status, response.reason)
  141. def verify_key(self, providerkey=None):
  142. """
  143. Verify if the API key is valid.
  144. The parameters are :
  145. - providerkey (optional) : your provider API key.
  146. Only necessary if you have been whitelisted.
  147. """
  148. h = Https(API_DOMAIN)
  149. data = {'apikey': self.apikey}
  150. if providerkey is not None:
  151. data['providerkey'] = providerkey
  152. h.request("GET",
  153. "/publicapi/verify?" + urlencode(data),
  154. headers=self.headers)
  155. request_status = h.getresponse().status
  156. if request_status != 200:
  157. self._relay_error(request_status)
  158. def retrieve_token(self, providerkey=None):
  159. """
  160. Get a registration token for use in retrieve/apikey
  161. and the associated URL for the user to approve the request.
  162. The parameters are :
  163. - providerkey (required) : your provider API key.
  164. This returns a dictionary such as:
  165. {'code': u'0',
  166. 'remaining': u'999',
  167. 'resetdate': u'1299535575',
  168. 'token': u'60fd568423e3cd337b45172be91cabe46b94c200',
  169. 'url': u'https://www.prowlapp.com/retrieve.php?token=60fd5684'}
  170. """
  171. h = Https(API_DOMAIN)
  172. data = {'apikey': self.apikey}
  173. if providerkey is not None:
  174. data['providerkey'] = providerkey
  175. h.request("GET",
  176. "/publicapi/retrieve/token?" + urlencode(data),
  177. headers=self.headers)
  178. request = h.getresponse()
  179. request_status = request.status
  180. if request_status == 200:
  181. dom = minidom.parseString(request.read())
  182. code = dom.getElementsByTagName('prowl')[0].\
  183. getElementsByTagName('success')[0].\
  184. getAttribute('code')
  185. remaining = dom.getElementsByTagName('prowl')[0].\
  186. getElementsByTagName('success')[0].\
  187. getAttribute('remaining')
  188. resetdate = dom.getElementsByTagName('prowl')[0].\
  189. getElementsByTagName('success')[0].\
  190. getAttribute('resetdate')
  191. token = dom.getElementsByTagName('prowl')[0].\
  192. getElementsByTagName('retrieve')[0].\
  193. getAttribute('token')
  194. url = dom.getElementsByTagName('prowl')[0].\
  195. getElementsByTagName('retrieve')[0].\
  196. getAttribute('url')
  197. return dict(token=token, url=url, code=code,
  198. remaining=remaining, resetdate=resetdate)
  199. else:
  200. self._relay_error(request_status)
  201. def retrieve_apikey(self, providerkey=None, token=None):
  202. """
  203. Get an API key from a registration token retrieved in retrieve/token.
  204. The user must have approved your request first, or you will get an
  205. error response.
  206. The parameters are :
  207. - providerkey (required) : your provider API key.
  208. - token (required): the token returned from retrieve_token.
  209. This returns a dictionary such as:
  210. {'apikey': u'16b776682332cf11102b67d6db215821f2c233a3',
  211. 'code': u'200',
  212. 'remaining': u'999',
  213. 'resetdate': u'1299535575'}
  214. """
  215. h = Https(API_DOMAIN)
  216. data = {'apikey': self.apikey}
  217. if providerkey is not None:
  218. data['providerkey'] = providerkey
  219. else:
  220. raise Exception("Provider Key is required for retrieving API key")
  221. if token is not None:
  222. data['token'] = token
  223. else:
  224. raise Exception("Token is required for retrieving API key.\
  225. Call retrieve_token to request it.")
  226. h.request("GET",
  227. "/publicapi/retrieve/apikey?" + urlencode(data),
  228. headers=self.headers)
  229. request = h.getresponse()
  230. request_status = request.status
  231. if request_status == 200:
  232. dom = minidom.parseString(request.read())
  233. code = dom.getElementsByTagName('prowl')[0].\
  234. getElementsByTagName('success')[0].\
  235. getAttribute('code')
  236. remaining = dom.getElementsByTagName('prowl')[0].\
  237. getElementsByTagName('success')[0].\
  238. getAttribute('remaining')
  239. resetdate = dom.getElementsByTagName('prowl')[0].\
  240. getElementsByTagName('success')[0].\
  241. getAttribute('resetdate')
  242. users_api_key = dom.getElementsByTagName('prowl')[0].\
  243. getElementsByTagName('retrieve')[0].\
  244. getAttribute('apikey')
  245. return dict(apikey=users_api_key, code=code, remaining=remaining,
  246. resetdate=resetdate)
  247. else:
  248. self._relay_error(request_status)