pushbullet_agent.rb 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. module Agents
  2. class PushbulletAgent < Agent
  3. include FormConfigurable
  4. cannot_be_scheduled!
  5. cannot_create_events!
  6. before_validation :create_device, on: :create
  7. API_BASE = 'https://api.pushbullet.com/v2/'
  8. TYPE_TO_ATTRIBUTES = {
  9. 'note' => [:title, :body],
  10. 'link' => [:title, :body, :url],
  11. 'address' => [:name, :address]
  12. }
  13. class Unauthorized < StandardError; end
  14. description <<-MD
  15. The Pushbullet agent sends pushes to a pushbullet device
  16. To authenticate you need to either the `api_key` or create a `pushbullet_api_key` credential, you can find yours at your account page:
  17. `https://www.pushbullet.com/account`
  18. If you do not select an existing device, Huginn will create a new one with the name 'Huginn'.
  19. To push to all of your devices, select `All Devices` from the devices list.
  20. You have to provide a message `type` which has to be `note`, `link`, or `address`. The message types `checklist`, and `file` are not supported at the moment.
  21. Depending on the message `type` you can use additional fields:
  22. * note: `title` and `body`
  23. * link: `title`, `body`, and `url`
  24. * address: `name`, and `address`
  25. In every value of the options hash you can use the liquid templating, learn more about it at the [Wiki](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid).
  26. MD
  27. def default_options
  28. {
  29. 'api_key' => '',
  30. 'device_id' => '',
  31. 'title' => "{{title}}",
  32. 'body' => '{{body}}',
  33. 'type' => 'note',
  34. }
  35. end
  36. form_configurable :api_key, roles: :validatable
  37. form_configurable :device_id, roles: :completable
  38. form_configurable :type, type: :array, values: ['note', 'link', 'address']
  39. form_configurable :title
  40. form_configurable :body, type: :text
  41. form_configurable :url
  42. form_configurable :name
  43. form_configurable :address
  44. def validate_options
  45. errors.add(:base, "you need to specify a pushbullet api_key") if options['api_key'].blank?
  46. errors.add(:base, "you need to specify a device_id") if options['device_id'].blank?
  47. errors.add(:base, "you need to specify a valid message type") if options['type'].blank? or not ['note', 'link', 'address'].include?(options['type'])
  48. TYPE_TO_ATTRIBUTES[options['type']].each do |attr|
  49. errors.add(:base, "you need to specify '#{attr.to_s}' for the type '#{options['type']}'") if options[attr].blank?
  50. end
  51. end
  52. def validate_api_key
  53. devices
  54. true
  55. rescue Unauthorized
  56. false
  57. end
  58. def complete_device_id
  59. devices
  60. .map { |d| {text: d['nickname'], id: d['iden']} }
  61. .unshift(text: 'All Devices', id: '__ALL__')
  62. end
  63. def working?
  64. received_event_without_error?
  65. end
  66. def receive(incoming_events)
  67. incoming_events.each do |event|
  68. safely do
  69. response = request(:post, 'pushes', query_options(event))
  70. end
  71. end
  72. end
  73. private
  74. def safely
  75. yield
  76. rescue Unauthorized => e
  77. error(e.message)
  78. end
  79. def request(http_method, method, options)
  80. response = JSON.parse(HTTParty.send(http_method, API_BASE + method, options).body)
  81. raise Unauthorized, response['error']['message'] if response['error'].present?
  82. response
  83. end
  84. def devices
  85. response = request(:get, 'devices', basic_auth)
  86. response['devices'].select { |d| d['pushable'] == true }
  87. rescue Unauthorized
  88. []
  89. end
  90. def create_device
  91. return if options['device_id'].present?
  92. safely do
  93. response = request(:post, 'devices', basic_auth.merge(body: {nickname: 'Huginn', type: 'stream'}))
  94. self.options[:device_id] = response['iden']
  95. end
  96. end
  97. def basic_auth
  98. {basic_auth: {username: interpolated[:api_key].presence || credential('pushbullet_api_key'), password: ''}}
  99. end
  100. def query_options(event)
  101. mo = interpolated(event)
  102. dev_ident = mo[:device_id] == "__ALL__" ? '' : mo[:device_id]
  103. basic_auth.merge(body: {device_iden: dev_ident, type: mo[:type]}.merge(payload(mo)))
  104. end
  105. def payload(mo)
  106. Hash[TYPE_TO_ATTRIBUTES[mo[:type]].map { |k| [k, mo[k]] }]
  107. end
  108. end
  109. end