pushover 1.0.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|