pushover 1.0.4 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +78 -0
- data/CODE_OF_CONDUCT.md +46 -0
- data/Gemfile +0 -37
- data/Guardfile +37 -27
- data/LICENSE +17 -32
- data/README.md +26 -153
- data/Rakefile +2 -3
- data/bin/pushover +0 -154
- data/lib/pushover.rb +8 -144
- data/lib/pushover/api.rb +35 -0
- data/lib/pushover/message.rb +38 -0
- data/lib/pushover/receipt.rb +5 -0
- data/lib/pushover/request.rb +12 -0
- data/lib/pushover/response.rb +40 -0
- data/lib/pushover/version.rb +2 -2
- data/pushover.gemspec +38 -25
- data/spec/lib/pushover/api_spec.rb +41 -0
- data/spec/lib/pushover/message_spec.rb +81 -0
- data/spec/lib/pushover/receipt_spec.rb +6 -0
- data/spec/lib/pushover/request_spec.rb +60 -0
- data/spec/lib/pushover/response_spec.rb +98 -0
- data/spec/lib/pushover_spec.rb +1 -116
- data/spec/spec_helper.rb +14 -39
- metadata +234 -36
- data/.travis.yml +0 -15
- data/lib/pushover/app.rb +0 -64
- data/lib/pushover/mixins.rb +0 -7
- data/lib/pushover/priority.rb +0 -63
- data/lib/pushover/user.rb +0 -68
- data/spec/bin/pushover_spec.rb +0 -108
- data/spec/cli_spec_helper.rb +0 -99
- data/spec/lib/pushover/app_spec.rb +0 -54
- data/spec/lib/pushover/user_spec.rb +0 -53
- data/whatsnew.md +0 -69
data/Rakefile
CHANGED
data/bin/pushover
CHANGED
@@ -1,154 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'pushover'
|
4
|
-
|
5
|
-
include Bini
|
6
|
-
include Pushover
|
7
|
-
Options.on("-u", "--user USER", "Which user, can be a saved name or token.") { |o| Options[:user] = o}
|
8
|
-
Options.on("-a", "--app APPKEY", "Which app to notify, can be a saved name or apikey.") { |o| Options[:token] = o}
|
9
|
-
Options.on("-t", "--title [TITLE]", "Set the title of the notification (optional).") { |o| Options[:title] = o}
|
10
|
-
Options.on("-p", "--priority [PRIORITY]", "Set the priority of the notification from (low,normal,high,emergency) (optional).") { |o| Options[:priority] = o}
|
11
|
-
Options.on("-d", "--device [DEVICE]", "Specify the device to send the notifcation to. (optional).") { |o| Options[:device] = o}
|
12
|
-
Options.on("-c", "--config_file [FILE]", "Set the target config file.") {|o| Options[:config_file] = o}
|
13
|
-
Options.on("--url [URL]", "Supplementary URL") { |o| Options[:url] = o }
|
14
|
-
Options.on("--url_title [TITLE]", "Supplementary URL title.") { |o| Options[:url_title] = o }
|
15
|
-
Options.on("--time [TIME]", "Set the messages time.") {|o| Options[:timestamp] = o}
|
16
|
-
Options.on("--save-app NAME", "Saves the application to the config file under NAME.") { |o| Options[:save_app] = o}
|
17
|
-
Options.on("--save-user NAME", "Saves the user to the config file under NAME.") { |o| Options[:save_user] = o}
|
18
|
-
Options.on("--sound [SOUND]", "Specify the sound to use. Can be a partial string as long as it is unambiguous enough.") { |o| Options[:sound] = o}
|
19
|
-
Options.on("--sound_list", "Display the current list of available sounds. Requires an app token.") { |o| Options[:sound_list] = true}
|
20
|
-
Options.on("--emergency_retry [TIME]", "The time in seconds between retries.") { |o| Options[:retry] = o}
|
21
|
-
Options.on("--emergency_expire [TIME]", "How long the emergency notification will hang around.") { |o| Options[:expire] = o}
|
22
|
-
Options.on("--emergency_callback_url [URL]", "A callback url to use when the notification is acknowledged.") { |o| Options[:callback] = o}
|
23
|
-
Options.on("--receipts", "List the receipts cached and if they have been acknowledged or not.") {|o| Options[:receipts] = true}
|
24
|
-
|
25
|
-
Options.parse!
|
26
|
-
bail = false
|
27
|
-
|
28
|
-
# Order is important.
|
29
|
-
if Options[:config_file]
|
30
|
-
Bini::Config.options[:file] = Options[:config_file]
|
31
|
-
puts "Selected config file: #{Options[:config_file]}"
|
32
|
-
# TODO: Make a healper for changing config so it clears/loads automatically.
|
33
|
-
Bini::Config.clear
|
34
|
-
Bini::Config.load
|
35
|
-
end
|
36
|
-
|
37
|
-
if Options[:save_app]
|
38
|
-
App.add Options[:save_app], Options[:token]
|
39
|
-
puts "Saved application #{Options[:token]} to #{Options[:save_app]}."
|
40
|
-
bail = true
|
41
|
-
end
|
42
|
-
|
43
|
-
if Options[:save_user]
|
44
|
-
User.add Options[:save_user], Options[:user]
|
45
|
-
puts "Saved user #{Options[:user]} to #{Options[:save_user]}."
|
46
|
-
bail = true
|
47
|
-
end
|
48
|
-
|
49
|
-
exit if bail # We don't care if we have a message, we should exit here.
|
50
|
-
|
51
|
-
if !App.current_app?
|
52
|
-
puts "Couldn't find an app via the cli or save file."
|
53
|
-
bail = true
|
54
|
-
end
|
55
|
-
|
56
|
-
if !User.current_user?
|
57
|
-
puts "Couldn't find a user via the cli or save file."
|
58
|
-
bail = true
|
59
|
-
end
|
60
|
-
|
61
|
-
if Options[:sound_list]
|
62
|
-
puts "Current Sound List:"
|
63
|
-
if Pushover.sounds
|
64
|
-
Pushover.sounds.each { |k,v| puts " #{v}" }
|
65
|
-
else
|
66
|
-
puts "Error retrieving sound list, are you connected to the internet? are your credentials correct?"
|
67
|
-
exit
|
68
|
-
end
|
69
|
-
bail = true
|
70
|
-
end
|
71
|
-
|
72
|
-
if Options[:receipts]
|
73
|
-
puts 'Updating receipts'
|
74
|
-
Pushover::Priority.update_receipts
|
75
|
-
Pushover::Priority::Receipts.each do |k,v|
|
76
|
-
if v["acknowledged"] != 0
|
77
|
-
print "Receipt #{k} was acknowledged at #{Time.at v["acknowledged_at"]}, "
|
78
|
-
else
|
79
|
-
print "Receipt #{k} has not been acknowledged yet, "
|
80
|
-
end
|
81
|
-
|
82
|
-
if v["expired"] == 0
|
83
|
-
puts "and will expire at: #{Time.at v["expires_at"]}."
|
84
|
-
else
|
85
|
-
puts "and expired at: #{Time.at v["expires_at"]}."
|
86
|
-
end
|
87
|
-
end
|
88
|
-
exit
|
89
|
-
end
|
90
|
-
|
91
|
-
if Options[:sound]
|
92
|
-
sounds = Pushover.sounds
|
93
|
-
if !sounds
|
94
|
-
puts "Error retrieving sound list, are you connected to the internet? are your credentials correct?"
|
95
|
-
exit
|
96
|
-
end
|
97
|
-
match = sounds.select { |k,v| v.downcase.start_with? Options[:sound].downcase}
|
98
|
-
if !match || match.count == 0
|
99
|
-
puts "No such sound: #{Options[:sound]}."
|
100
|
-
bail = true
|
101
|
-
elsif match.count > 1
|
102
|
-
print "Sound is ambiguous, possible matches: "
|
103
|
-
match.each {|k,v| print "#{v} "}
|
104
|
-
print "\n"
|
105
|
-
bail = true
|
106
|
-
else
|
107
|
-
Options[:sound] = match.first[0]
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
if Options[:priority]
|
112
|
-
# Is this an emergency, did we include everything we need?
|
113
|
-
if Priority.is_emergency?(Options[:priority])
|
114
|
-
Options[:retry] = 30 if !Options[:retry]
|
115
|
-
Options[:expire] = 86400 if !Options[:expire]
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
exit if bail
|
120
|
-
|
121
|
-
message = ARGV.join(" ")
|
122
|
-
if !message
|
123
|
-
puts "Must supply a message to be sent."
|
124
|
-
bail = true
|
125
|
-
end
|
126
|
-
|
127
|
-
exit if bail
|
128
|
-
|
129
|
-
options = Options[].select { |k,v| v}
|
130
|
-
options[:token] = Pushover::App.current_app
|
131
|
-
options[:user] = Pushover::User.current_user
|
132
|
-
|
133
|
-
options.delete :config_file
|
134
|
-
options.merge! message:message
|
135
|
-
|
136
|
-
response = Pushover.notification options
|
137
|
-
if response.code == 500
|
138
|
-
puts "Something is broken at pushover.net and it is returning 500's (server errors). Here is the response body."
|
139
|
-
puts response.body
|
140
|
-
exit
|
141
|
-
end
|
142
|
-
j = Yajl.load response.body
|
143
|
-
|
144
|
-
if response.code == 200
|
145
|
-
if Priority.is_emergency?(Options[:priority])
|
146
|
-
j = Yajl.load response.body
|
147
|
-
Pushover::Priority.process_receipt j["receipt"]
|
148
|
-
puts "emergency notification receipt: #{j["receipt"]}"
|
149
|
-
end
|
150
|
-
puts "Message sent successfully!"
|
151
|
-
else
|
152
|
-
puts "ErrorCode (#{response.code}): #{j['errors'].first}."
|
153
|
-
end
|
154
|
-
|
data/lib/pushover.rb
CHANGED
@@ -1,148 +1,12 @@
|
|
1
|
-
require '
|
2
|
-
require
|
3
|
-
require 'time'
|
4
|
-
require 'bini'
|
5
|
-
require 'bini/config'
|
6
|
-
require 'bini/optparser'
|
7
|
-
require 'open-uri'
|
8
|
-
require 'pushover/mixins.rb'
|
1
|
+
require 'oj'
|
2
|
+
require 'creatable'
|
9
3
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
4
|
+
require 'pushover/api'
|
5
|
+
require 'pushover/message'
|
6
|
+
require 'pushover/receipt'
|
7
|
+
require 'pushover/response'
|
8
|
+
require 'pushover/request'
|
16
9
|
|
17
|
-
#
|
10
|
+
# pushover interface for ruby
|
18
11
|
module Pushover
|
19
|
-
# Unfuckingbelievable. My code, and I still can't get it to work as expected.
|
20
|
-
Bini.long_name = 'pushover'
|
21
|
-
# lets save our config to it's own dir, just because.
|
22
|
-
Bini::Config.options[:file] = "#{Dir.home}/.config/pushover/credentials.yaml"
|
23
|
-
Bini::Config.load
|
24
|
-
|
25
|
-
extend self
|
26
|
-
|
27
|
-
# [String] The api key to be used for the notifcation.
|
28
|
-
attr_accessor :token
|
29
|
-
# [String] of the user token currently being used.
|
30
|
-
attr_accessor :user
|
31
|
-
# [String] message the message to be sent.
|
32
|
-
attr_accessor :message
|
33
|
-
# [optional,String] Title of the message.
|
34
|
-
attr_accessor :title
|
35
|
-
# [optional,String] device to recieve the message.
|
36
|
-
attr_accessor :device
|
37
|
-
attr_reader :priority
|
38
|
-
attr_accessor :url
|
39
|
-
attr_accessor :url_title
|
40
|
-
attr_accessor :emergency_retry
|
41
|
-
attr_accessor :emergency_expire
|
42
|
-
attr_accessor :emergency_callback
|
43
|
-
# [optional,String, Fixnum] time a time stamp im one of three forms (epoch, strfmt, rails)
|
44
|
-
attr_reader :timestamp
|
45
|
-
|
46
|
-
# Stdlib time, seems to take a shitload of options.
|
47
|
-
# rfc822: Tue, 14 Nov 2000 14:55:07 -0500
|
48
|
-
# xml: 1979-08-13T06:30:00.313UTC
|
49
|
-
# Time.parse 'Aug 13, 1979 6:30'
|
50
|
-
# Time.parse '1979/08/13, 6:30:50 UTC'
|
51
|
-
def timestamp=(time_string)
|
52
|
-
@timestamp = timestamp_magic time_string
|
53
|
-
end
|
54
|
-
|
55
|
-
# push a message to pushover, must supply all variables.
|
56
|
-
# @param [String] message The message to be sent
|
57
|
-
# @param [optional, String] title The title of the message
|
58
|
-
# @param [optional, Fixnum] priority of the message to be sent, from -1 to 1.
|
59
|
-
# @param [optional, String] device The specific device to be notified.
|
60
|
-
# @param [optional, String] app api key.
|
61
|
-
# @param [optional, String] user the user token.
|
62
|
-
# @return [String] the response from pushover.net, in json.
|
63
|
-
def notification(tokens={})
|
64
|
-
tokens[:timestamp] = timestamp_magic tokens[:timestamp] if tokens[:timestamp]
|
65
|
-
tokens[:priority] = Pushover::Priority.parse tokens[:priority] if tokens[:priority]
|
66
|
-
tokens[:user] ||= @user
|
67
|
-
tokens[:token] ||= @token
|
68
|
-
|
69
|
-
HTTParty.post('https://api.pushover.net/1/messages.json', body:tokens)
|
70
|
-
end
|
71
|
-
|
72
|
-
# Return a [Hash] of sounds.
|
73
|
-
def sounds
|
74
|
-
cache_file = "#{Bini.cache_dir}/sounds.json"
|
75
|
-
sounds = {}
|
76
|
-
|
77
|
-
cache_sounds if File.exists?(cache_file) && File.stat(cache_file).mtime < Time.at(Time.now.day - 1)
|
78
|
-
|
79
|
-
return nil if !cache_sounds
|
80
|
-
sounds = Yajl.load open(cache_file).read
|
81
|
-
sounds["sounds"]
|
82
|
-
end
|
83
|
-
|
84
|
-
# Adds a rails style configure method
|
85
|
-
def configure
|
86
|
-
yield self
|
87
|
-
parameters
|
88
|
-
end
|
89
|
-
|
90
|
-
# List available parameters and values in those params
|
91
|
-
def parameters
|
92
|
-
h = {}
|
93
|
-
keys.each { |k| h[k.to_sym] = Pushover.instance_variable_get("@#{k}") }
|
94
|
-
return h
|
95
|
-
end
|
96
|
-
alias_method :params, :parameters
|
97
|
-
|
98
|
-
# Returns true or false if all parameters are set.
|
99
|
-
def parameters?
|
100
|
-
parameters.values.all?
|
101
|
-
end
|
102
|
-
|
103
|
-
# Clear all the currently set parameters
|
104
|
-
def clear
|
105
|
-
keys.each do |k|
|
106
|
-
Pushover.instance_variable_set("@#{k}", nil)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
# A [Array] of keys available in Pushover.
|
111
|
-
def keys
|
112
|
-
Pushover.instance_methods.select do |m|
|
113
|
-
m =~ /=$/
|
114
|
-
end.map do |m|
|
115
|
-
m[0..-2]
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
|
120
|
-
private
|
121
|
-
|
122
|
-
def timestamp_magic(time_string)
|
123
|
-
if time_string.class == String
|
124
|
-
begin
|
125
|
-
return Time.parse(time_string).to_i
|
126
|
-
rescue ArgumentError
|
127
|
-
return time_string.to_i
|
128
|
-
end
|
129
|
-
elsif
|
130
|
-
time_string.class == Fixnum
|
131
|
-
return time_string
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def cache_sounds
|
136
|
-
cache_file = "#{Bini.cache_dir}/sounds.json"
|
137
|
-
|
138
|
-
response = HTTParty.get('https://api.pushover.net/1/sounds.json', query:{token:Pushover::App.current_app})
|
139
|
-
|
140
|
-
return nil if response.code != 200
|
141
|
-
FileUtils.mkdir_p Bini.cache_dir
|
142
|
-
f = open(cache_file, 'w')
|
143
|
-
f.write response.body
|
144
|
-
f.flush
|
145
|
-
f.close
|
146
|
-
return true
|
147
|
-
end
|
148
12
|
end
|
data/lib/pushover/api.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'creatable'
|
2
|
+
require 'excon'
|
3
|
+
require 'oj'
|
4
|
+
|
5
|
+
require 'pushover/response'
|
6
|
+
|
7
|
+
module Pushover
|
8
|
+
# Api module
|
9
|
+
module Api
|
10
|
+
module_function
|
11
|
+
|
12
|
+
def endpoints
|
13
|
+
%i[messages sounds limits receipts validate]
|
14
|
+
end
|
15
|
+
|
16
|
+
def sounds
|
17
|
+
%i[ pushover bike bugle cashregister classical cosmic falling gamelan incoming
|
18
|
+
intermission magic mechanical pianobar siren spacealarm tugboat alien
|
19
|
+
climb persistent echo updown none]
|
20
|
+
end
|
21
|
+
|
22
|
+
def connection
|
23
|
+
Excon.new url
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
Excon.defaults[:headers]['Content-Type'] = 'application/json'
|
28
|
+
Excon.defaults[:headers]['User-Agent'] = "pushover (ruby gem) v#{Pushover::VERSION}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def url
|
32
|
+
"https://api.pushover.net"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Pushover interface
|
2
|
+
module Pushover
|
3
|
+
class Message
|
4
|
+
include Creatable
|
5
|
+
|
6
|
+
attribute name: 'attachment'
|
7
|
+
attribute name: 'device', kind_of: String
|
8
|
+
attribute name: 'html', kind_of: TrueClass
|
9
|
+
attribute name: 'message', kind_of: String
|
10
|
+
attribute name: 'priority', kind_of: String
|
11
|
+
attribute name: 'sound', kind_of: String
|
12
|
+
attribute name: 'timestamp', kind_of: Numeric
|
13
|
+
attribute name: 'title', kind_of: String
|
14
|
+
attribute name: 'token', kind_of: String
|
15
|
+
attribute name: 'response', kind_of: Pushover::Response
|
16
|
+
attribute name: 'url_title', kind_of: String
|
17
|
+
attribute name: 'url', kind_of: String
|
18
|
+
attribute name: 'user', kind_of: String
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@timestamp = Time.now.to_i
|
22
|
+
end
|
23
|
+
|
24
|
+
def push
|
25
|
+
raise ArgumentError, 'user is a required parameter' unless user
|
26
|
+
raise ArgumentError, 'token is a required parameter' unless token
|
27
|
+
raise ArgumentError, 'message is a required parameter' unless message
|
28
|
+
|
29
|
+
query = {}
|
30
|
+
|
31
|
+
attributes.each { |e| query.store e[:name], instance_variable_get("@#{e[:name]}") if instance_variable_get("@#{e[:name]}") }
|
32
|
+
|
33
|
+
response = Request.create.push(:messages, query)
|
34
|
+
response.process
|
35
|
+
@response = response
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Pushover
|
2
|
+
class Request
|
3
|
+
include Creatable
|
4
|
+
|
5
|
+
def push(endpoint, config = {})
|
6
|
+
excon_response = Api.connection.post path: "1/#{endpoint}.json", query: config
|
7
|
+
response = Response.create original: excon_response
|
8
|
+
response.process
|
9
|
+
@response = response
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Pushover
|
2
|
+
class Response
|
3
|
+
include Creatable
|
4
|
+
|
5
|
+
attribute name: 'user', kind_of: String
|
6
|
+
attribute name: 'errors', kind_of: Array
|
7
|
+
attribute name: 'status', kind_of: Numeric
|
8
|
+
attribute name: 'receipt', kind_of: String
|
9
|
+
attribute name: 'request', kind_of: String
|
10
|
+
attribute name: 'original', kind_of: String
|
11
|
+
attribute name: 'limit', kind_of: String
|
12
|
+
attribute name: 'remaining', kind_of: String
|
13
|
+
attribute name: 'reset', kind_of: String
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@status = 0
|
17
|
+
@errors = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def process
|
21
|
+
process_body
|
22
|
+
process_headers
|
23
|
+
end
|
24
|
+
|
25
|
+
def process_body
|
26
|
+
body = Oj.load original[:body]
|
27
|
+
|
28
|
+
@status = body["status"]
|
29
|
+
@request = body["request"]
|
30
|
+
@receipt = body["receipt"] if body["receipt"]
|
31
|
+
@errors = body["errors"] if body["errors"]
|
32
|
+
end
|
33
|
+
|
34
|
+
def process_headers
|
35
|
+
@limit = original.headers['X-Limit-App-Limit']
|
36
|
+
@remaining = original.headers['X-Limit-App-Remaining']
|
37
|
+
@reset = original.headers['X-Limit-App-Reset']
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|