pushover 3.0.3 → 4.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +28 -0
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +11 -24
  5. data/.ruby-version +1 -0
  6. data/CONVENTIONS.md +19 -0
  7. data/Gemfile +1 -2
  8. data/Guardfile +3 -3
  9. data/README.md +236 -44
  10. data/Rakefile +9 -59
  11. data/exe/pushover +6 -5
  12. data/lib/pushover/client.rb +53 -0
  13. data/lib/pushover/glances.rb +86 -0
  14. data/lib/pushover/groups.rb +137 -0
  15. data/lib/pushover/licenses.rb +67 -0
  16. data/lib/pushover/limits.rb +18 -0
  17. data/lib/pushover/message.rb +29 -32
  18. data/lib/pushover/message_encryption.rb +48 -0
  19. data/lib/pushover/message_validator.rb +167 -0
  20. data/lib/pushover/messages.rb +20 -0
  21. data/lib/pushover/receipt.rb +23 -10
  22. data/lib/pushover/receipts.rb +60 -0
  23. data/lib/pushover/response.rb +8 -3
  24. data/lib/pushover/sounds.rb +18 -0
  25. data/lib/pushover/subscriptions.rb +48 -0
  26. data/lib/pushover/teams.rb +93 -0
  27. data/lib/pushover/users.rb +37 -0
  28. data/lib/pushover/version.rb +1 -1
  29. data/lib/pushover.rb +14 -1
  30. data/pushover.gemspec +9 -7
  31. data/spec/gem/specification_spec.rb +19 -0
  32. data/spec/pushover/client_spec.rb +149 -0
  33. data/spec/pushover/glances_spec.rb +206 -0
  34. data/spec/pushover/groups_spec.rb +486 -0
  35. data/spec/pushover/licenses_spec.rb +238 -0
  36. data/spec/pushover/limits_spec.rb +92 -0
  37. data/spec/pushover/message_spec.rb +146 -26
  38. data/spec/pushover/messages_spec.rb +199 -0
  39. data/spec/pushover/receipt_spec.rb +119 -11
  40. data/spec/pushover/receipts_spec.rb +232 -0
  41. data/spec/pushover/response_spec.rb +21 -16
  42. data/spec/pushover/sounds_spec.rb +92 -0
  43. data/spec/pushover/subscriptions_spec.rb +185 -0
  44. data/spec/pushover/teams_spec.rb +325 -0
  45. data/spec/pushover/users_spec.rb +115 -0
  46. data/spec/spec_helper.rb +2 -3
  47. metadata +54 -18
  48. data/.travis.yml +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1462e57e5e54fdde38e0ffd646012e186505e391ab4a6e806a05e20daf00fd4c
4
- data.tar.gz: 6d932f6727563a8329f14fe3c8a7a5d7039fb325f8320e3e6d2586107e7a6073
3
+ metadata.gz: 7a19291da36f95fd19954df7a7b93aa1d4b78cb8708702fe4c8ebafb6d14a4c8
4
+ data.tar.gz: b416babb1ae31c5d7e2fe51707785c4bd87c6dfead296568dd378155ac852a82
5
5
  SHA512:
6
- metadata.gz: 4c215eaa108f2b43ece3568b6149c901d0e643d33c31a05703125b1982a09dd6c7be26fce91a7096a7d99ce65ee8e41d08bdd426fbd2aab3030a4982c80f4783
7
- data.tar.gz: e3ee589d7db9836f53246740d43fb9a3be22bc3f4908095634991053d7cb34bad02bfa9e6678c2a928eda3314137364890624b10b4fbb2f8aa2e1666e204a68b
6
+ metadata.gz: ffbdf22b369588fd862768b8ad4ba7ce285d78b22c50a64334d9668deaadec498d29d8bde17a05de9969875d9773266f9dc68a90e5c470707eca5906dffd8272
7
+ data.tar.gz: c9aee830ca7abff85081dbda9ba6f912055667607e606e294a6aeaed551f16e574330079dc2362936264904f1cf7209e631ce96f4dbc8eb2d6ea96ed9ca98e7f
@@ -0,0 +1,28 @@
1
+ name: CI
2
+
3
+ 'on':
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ verify:
14
+ name: Verify
15
+ runs-on: ubuntu-latest
16
+ timeout-minutes: 10
17
+
18
+ steps:
19
+ - name: Check out repository
20
+ uses: actions/checkout@v7
21
+
22
+ - name: Set up Ruby
23
+ uses: ruby/setup-ruby@v1
24
+ with:
25
+ bundler-cache: true
26
+
27
+ - name: Run CI
28
+ run: bundle exec rake ci
data/.gitignore CHANGED
@@ -18,3 +18,4 @@ tmp
18
18
  spec/test_config
19
19
  .rspec
20
20
  *.tmp
21
+ CURRENT_WORK.md
data/.rubocop.yml CHANGED
@@ -1,15 +1,14 @@
1
- require: rubocop-rspec
1
+ plugins: rubocop-rspec
2
2
 
3
3
  AllCops:
4
- TargetRubyVersion: 2.4.0
4
+ NewCops: enable
5
+ TargetRubyVersion: 3.3
5
6
  Exclude:
6
- - 'vendor/**/*'
7
7
  - 'tmp/**/*'
8
- - 'spec/spec_helper.rb'
8
+ - 'vendor/bundle/**/*'
9
9
 
10
10
  # The defaults for these seem to be based on a rails env, this is not rails.
11
11
  Metrics/ModuleLength:
12
- CountComments: false
13
12
  Max: 250
14
13
 
15
14
  Metrics/ClassLength:
@@ -27,8 +26,8 @@ Metrics/CyclomaticComplexity:
27
26
  Metrics/PerceivedComplexity:
28
27
  Max: 10
29
28
 
30
- # it's 2016, people have wide monitors.
31
- Metrics/LineLength:
29
+ # Line length is intentionally unrestricted.
30
+ Layout/LineLength:
32
31
  Enabled: false
33
32
 
34
33
  Metrics/BlockLength:
@@ -47,7 +46,7 @@ Style/RegexpLiteral:
47
46
  - 'Guardfile'
48
47
  - '*.gemspec'
49
48
 
50
- # Prefer single-quoted strings when you don't need string interpolation or special symbols
49
+ # String literal quote style is not enforced.
51
50
  Style/StringLiterals:
52
51
  Enabled: false
53
52
 
@@ -59,22 +58,10 @@ Style/FrozenStringLiteralComment:
59
58
 
60
59
  Style/MixinUsage:
61
60
  Exclude:
62
- - 'bin/*'
63
- - 'exe/*'
61
+ - 'bin/*'
62
+ - 'exe/*'
64
63
 
65
- # Specs don't need inline documentation.
66
- Style/Documentation:
67
- Enabled: true
68
- Exclude:
69
- - 'spec/**/*'
70
-
71
- RSpec/NamedSubject:
72
- Enabled: false
73
-
74
- Lint/Debugger:
75
- Enabled: false
76
-
77
- # Purty hashes.
78
- Layout/AlignHash:
64
+ # Align hash pairs as tables.
65
+ Layout/HashAlignment:
79
66
  EnforcedHashRocketStyle: table
80
67
  EnforcedColonStyle: table
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.3.0
data/CONVENTIONS.md ADDED
@@ -0,0 +1,19 @@
1
+ # Project Conventions
2
+
3
+ ## Design
4
+
5
+ - Prefer modern Ruby patterns over legacy implementation patterns.
6
+ - Preserve released public behavior when practical, but do not preserve obsolete implementation details unless they are explicitly part of the supported contract.
7
+
8
+ ## Ruby runtime
9
+
10
+ - Run Ruby, Bundler, Rake, RSpec, RuboCop, and other Ruby commands through `/opt/homebrew/bin/rbenv exec`.
11
+ - The Codex shell may resolve `/usr/bin/ruby` (Apple Ruby 2.6) instead of the project's Ruby version.
12
+ - The project runtime is defined by `.ruby-version`.
13
+
14
+ ## HTTP client
15
+
16
+ - Use Excon for Pushover HTTP requests. Do not introduce another HTTP client without a specific need.
17
+ - Use Excon's request stubs for mocked HTTP tests.
18
+ - Consult the installed Excon documentation or source before assuming library behavior.
19
+ - it has no context 7 documentation, so read the source code for details.
data/Gemfile CHANGED
@@ -4,7 +4,6 @@ gemspec
4
4
  gem 'excon'
5
5
  gem 'gli'
6
6
  gem 'oj'
7
- gem 'codecov', :require => false, :group => :test
8
7
 
9
8
  group :test do
10
9
  gem 'bump'
@@ -13,7 +12,7 @@ group :test do
13
12
  gem 'rspec'
14
13
  gem 'rubocop'
15
14
  gem 'rubocop-rspec'
16
- gem 'simplecov'
15
+ gem 'simplecov', '~> 1.0.3'
17
16
  gem 'yard'
18
17
  end
19
18
 
data/Guardfile CHANGED
@@ -41,8 +41,8 @@ end
41
41
 
42
42
  unless ENV["DISABLE_YARD"] == 'true'
43
43
  guard 'yard' do
44
- watch(%r{app\/.+\.rb})
45
- watch(%r{lib\/.+\.rb})
46
- watch(%r{ext\/.+\.c})
44
+ watch(%r{app/.+\.rb})
45
+ watch(%r{lib/.+\.rb})
46
+ watch(%r{ext/.+\.c})
47
47
  end
48
48
  end
data/README.md CHANGED
@@ -1,76 +1,268 @@
1
1
  # Pushover
2
- [![Build Status](https://travis-ci.org/erniebrodeur/pushover.svg?branch=master)](https://travis-ci.org/erniebrodeur/pushover) [![codecov](https://codecov.io/gh/erniebrodeur/pushover/branch/master/graph/badge.svg)](https://codecov.io/gh/erniebrodeur/pushover)
3
2
 
4
- This gem provides a CLI and an API interface to https://pushover.net.
3
+ This gem provides a CLI and a Ruby API for [Pushover](https://pushover.net).
5
4
 
6
5
  ## Installation
7
6
 
8
- To install:
7
+ Install the gem:
9
8
 
10
- gem install pushover
9
+ ```shell
10
+ gem install pushover
11
+ ```
12
+
13
+ Or add it to your Gemfile and run `bundle install`:
11
14
 
12
- To use inside of an application, add this to the your gemfile:
15
+ ```ruby
16
+ gem 'pushover'
17
+ ```
13
18
 
14
- gem 'pushover'
19
+ ## Ruby API
15
20
 
16
- and run bundle to make it available:
21
+ Create one client with your application token, then use its API resources:
17
22
 
18
- bundle
23
+ ```ruby
24
+ require 'pushover'
19
25
 
26
+ client = Pushover::Client.new(token: 'app-token')
27
+
28
+ response = client.messages.create(
29
+ user: 'user-or-group-key',
30
+ message: 'Deployment completed',
31
+ title: 'Production'
32
+ )
33
+ ```
20
34
 
21
- ## Usage
35
+ `messages.create` supports the Pushover Message API's JSON parameters:
22
36
 
23
- For now, not much is supported on the CLI.
37
+ - `user` and `message` are required.
38
+ - `device`, `title`, `url`, `url_title`, `priority`, `sound`, `timestamp`, and `ttl` are optional.
39
+ - `html` and `monospace` accept booleans or `1` and `0`, but cannot both be enabled.
40
+ - Emergency priority (`priority: 2`) requires `retry` and `expire`, and may include `callback` and `tags`.
41
+ - Attachments use `attachment_base64` with `attachment_type`, such as `image/png`, and are limited to 5 MiB after decoding.
24
42
 
25
- Sending a message:
43
+ To encrypt the supported message fields end to end, pass the 64-character hexadecimal key configured on the receiving devices:
26
44
 
27
- pushover --token=your_app_token --user=user_key message here we go again, on my own.
28
- pushover -tyour_app_token -uuser_key message here we go again, on my own.
45
+ ```ruby
46
+ response = client.messages.create(
47
+ user: 'user-or-group-key',
48
+ message: 'Encrypted message',
49
+ encryption_key: ENV.fetch('PUSHOVER_ENCRYPTION_KEY')
50
+ )
51
+ ```
29
52
 
30
- Getting receipt details:
53
+ Deterministic request errors raise `ArgumentError` before a network request. Pushover API errors, including HTTP 4xx responses, are returned as `Pushover::Response` objects:
31
54
 
55
+ ```ruby
56
+ response.status # 0 or 1
57
+ response.request # Pushover request identifier
58
+ response.errors # API validation errors, if any
59
+ response.receipt # emergency message receipt, if any
60
+ response.headers # response headers, including application limits
61
+ response.attributes # other response fields
62
+ ```
32
63
 
33
- pushover -tyour_app_token receipt receipt-hash
64
+ Retrieve the status of an emergency message receipt through the same client:
34
65
 
35
- Currently unsupported message features:
36
- - attachments
37
- - callbacks
38
- - setting timestamp
66
+ ```ruby
67
+ response = client.receipts.get(receipt: 'AbCdEf0123456789GhIjKlMnOpQrSt')
68
+ ```
39
69
 
70
+ Cancel future retries for an emergency message before it expires:
40
71
 
41
- ### Api
72
+ ```ruby
73
+ response = client.receipts.cancel(receipt: 'AbCdEf0123456789GhIjKlMnOpQrSt')
74
+ ```
42
75
 
43
- ``` ruby
44
- require 'pushover'
76
+ Cancel future retries for all active emergency messages sent by the application with one tag:
45
77
 
46
- ### message
47
- message = Pushover::Message.new(token: 'token', user: 'user_key', message: '...')
48
- message.push
78
+ ```ruby
79
+ response = client.receipts.cancel_by_tag(tag: 'l=chicago')
80
+ ```
81
+
82
+ Receipt identifiers must contain exactly 30 alphanumeric characters. Receipt status fields are returned in `response.attributes`, including `acknowledged`, `acknowledged_at`, `acknowledged_by`, `acknowledged_by_device`, `last_delivered_at`, `expired`, `expires_at`, `called_back`, and `called_back_at`.
83
+
84
+ Cancellation stops future emergency-priority retries. `cancel_by_tag` accepts one nonempty tag and encodes it as a single URL path segment. Pushover permits receipt polling no more often than once every five seconds and retains receipt status for up to one week. The client does not enforce that interval or automatically retry requests. Connection failures continue to raise Excon transport exceptions.
85
+
86
+ Validate a user or group identifier, optionally for one device:
87
+
88
+ ```ruby
89
+ response = client.users.validate(
90
+ user: 'uQiRzpo4DXghDmr9QzzfQu27cmVRsG',
91
+ device: 'droid2'
92
+ )
93
+ ```
94
+
95
+ `user` must be a 30-character alphanumeric user or group identifier. `device` is optional and, when supplied, must be 1 to 25 characters using letters, numbers, underscores, or hyphens. Without a device, Pushover validates that the account has at least one active device. Successful validation returns active device names in `response.attributes['devices']` and licensed platforms in `response.attributes['licenses']`. Invalid or inactive users and devices are returned as Pushover API errors in the response.
96
+
97
+ Retrieve the sounds available to the application account:
98
+
99
+ ```ruby
100
+ response = client.sounds.get
101
+ available_sounds = response.attributes['sounds']
102
+ ```
49
103
 
104
+ The sounds hash maps each value accepted by `messages.create(sound: ...)` to its display name. It includes Pushover's built-in sounds and custom sounds uploaded by the account that owns the application token. Omit `sound`, or pass a blank value, to use the recipient's default sound.
50
105
 
51
- ### Receipt
52
- Pushover::Message.new(token: 'token', user: 'user_key', message: '...', 'priority': 2, expire: 1, retry: 60).push
106
+ Retrieve the current monthly message usage limits:
53
107
 
54
- receipt = Pushover::Receipt.new(receipt: "receipt", token: 'token')
55
- receipt.get
108
+ ```ruby
109
+ response = client.limits.get
110
+ monthly_limit = response.attributes['limit']
111
+ remaining = response.attributes['remaining']
112
+ reset_at = Time.at(response.attributes['reset'])
113
+ ```
114
+
115
+ `limit` is the account or team's monthly allowance, including purchased capacity. `remaining` is the number of messages left, and `reset` is the Unix timestamp for the next reset. Despite the historical endpoint and header names, these values represent usage shared across all applications owned by the account or team.
116
+
117
+ Update one or more fields on a user's registered Glances widgets:
118
+
119
+ ```ruby
120
+ response = client.glances.update(
121
+ user: 'uQiRzpo4DXghDmr9QzzfQu27cmVRsG',
122
+ title: 'Widgets Sold',
123
+ text: '30',
124
+ percent: 75
125
+ )
126
+ ```
127
+
128
+ `title`, `text`, and `subtext` accept up to 100 characters. `count` accepts any integer, including negative values, and `percent` accepts integers from 0 through 100. `device` may restrict the update to one device. At least one data field is required. Omitted data fields retain their previous values; pass an empty string to clear a field, including `count` or `percent`.
129
+
130
+ Glances updates do not create notifications and may take up to 10 minutes to appear. Pushover recommends at least 20 minutes between Apple Watch updates, and watchOS limits them to 50 per day. The client does not throttle updates.
131
+
132
+ Create an empty delivery group:
133
+
134
+ ```ruby
135
+ response = client.groups.create(name: 'On-call West')
136
+ group_key = response.attributes['group']
137
+ ```
138
+
139
+ The application token may belong to any application on the account or team that will own the group. Group names must be unique within that account; Pushover validates uniqueness. The returned 30-character group key can be used as the `user` value when sending messages.
140
+
141
+ List the delivery groups owned by the application token's account or team:
142
+
143
+ ```ruby
144
+ response = client.groups.list
145
+ group_entries = response.attributes['groups']
146
+ ```
147
+
148
+ Each entry contains a `group` key and `name`. Pushover does not document a sort order or pagination contract, so callers should not depend on response ordering.
149
+
150
+ Retrieve a delivery group's name and memberships:
151
+
152
+ ```ruby
153
+ response = client.groups.get(group: group_key)
154
+ group_name = response.attributes['name']
155
+ members = response.attributes['users']
156
+ ```
157
+
158
+ Each member contains `user`, `device`, `memo`, and `disabled`. A `device` of `nil` represents an unrestricted membership. Team members also include `name` and `email`. Pushover does not document membership ordering or pagination.
159
+
160
+ Manage group memberships and names:
161
+
162
+ ```ruby
163
+ client.groups.add_user(group: group_key, user: user_key, device: 'iphone', memo: 'Primary on-call')
164
+ client.groups.disable_user(group: group_key, user: user_key, device: 'iphone')
165
+ client.groups.enable_user(group: group_key, user: user_key, device: 'iphone')
166
+ client.groups.remove_user(group: group_key, user: user_key, device: 'iphone')
167
+ client.groups.rename(group: group_key, name: 'Operations')
168
+ ```
169
+
170
+ An added membership may include one device and a memo of up to 200 characters. Omitting `device`, or passing it as blank, creates an all-device membership. For removal, disabling, and enabling, an omitted or blank device affects every membership matching the user key; pass a device to target only that membership. Pushover enforces group-name uniqueness on the owning account or team.
171
+
172
+ Optionally migrate an existing user key to an application subscription:
173
+
174
+ ```ruby
175
+ response = client.subscriptions.migrate(
176
+ subscription: 'Forum-f504h08fhlasdfj',
177
+ user: 'uQiRzpo4DXghDmr9QzzfQu27cmVRsG',
178
+ device_name: 'droid2',
179
+ sound: 'pushover'
180
+ )
181
+ subscribed_user_key = response.attributes['subscribed_user_key']
182
+ ```
183
+
184
+ Pushover calls this user-key migration, but it is only needed when voluntarily adopting subscription-managed recipients for previously collected user keys. `subscription` must be a nonempty subscription code, and `user` must be a 30-character alphanumeric user key. `device_name` is optional and follows the standard device-name rules. `sound` may be any string because Pushover supports account-specific custom sounds; a blank sound selects the user's default. Pushover validates live subscriptions, users, devices, and sound availability.
185
+
186
+ Retrieve the application's available prepaid license credits, or permanently assign one credit:
187
+
188
+ ```ruby
189
+ credits = client.licenses.get.attributes['credits']
190
+
191
+ response = client.licenses.assign(
192
+ email: 'person@example.com',
193
+ os: 'Desktop'
194
+ )
195
+ remaining_credits = response.attributes['credits']
196
+ ```
197
+
198
+ `licenses.assign` requires a valid 30-character `user` key or a nonblank `email`; the gem does not invent an e-mail format beyond that documented requirement. `os` may be blank, `Android`, `iOS`, or `Desktop`. A blank or omitted value assigns the license to the first platform the user registers. Each call assigns one permanent, nonrefundable license. Assignment failures remain structured in `response.errors`, and the client never automatically retries the assignment.
199
+
200
+ Administer a Pushover for Teams organization with its Team API token:
201
+
202
+ ```ruby
203
+ team = Pushover::Client.new(token: 'team-api-token').teams
204
+
205
+ response = team.get
206
+ team_name = response.attributes['name']
207
+ members = response.attributes['users']
208
+ ```
209
+
210
+ `client.teams` requires a Team API token, not an Application API Token. The client cannot distinguish the credential types locally, so Pushover returns an API error when the wrong token type is supplied. Team names, users, administrator flags, and nested device details are preserved in `response.attributes`.
211
+
212
+ Add a team user with only an e-mail address, or include the documented invitation and administration options:
213
+
214
+ ```ruby
215
+ response = team.add_user(
216
+ email: 'member@example.com',
217
+ name: 'Team Member',
218
+ password: '',
219
+ instant: true,
220
+ admin: false,
221
+ group: 'On-call'
222
+ )
223
+ ```
224
+
225
+ `email` must be a nonblank string. `name`, `password`, and `group` are optional strings. A blank or omitted password lets Pushover assign and e-mail a random password. `instant: true` requests a seven-day Instant Login link, and `admin: true` adds the user as an administrator. False flags are omitted. A named Delivery Group is created by Pushover if it does not exist; omitting `group` uses the auto-updating Team Delivery Group.
226
+
227
+ Revoke an invitation that has not been accepted, or remove a current team user:
228
+
229
+ ```ruby
230
+ team.revoke_invitation(email: 'invitee@example.com')
231
+ team.remove_user(email: 'departing-member@example.com')
232
+ ```
233
+
234
+ Removing a user does not delete their Pushover account, but Pushover removes them from the team's Delivery Groups. Pushover also enforces that at least one administrator remains. Membership, invitation, and group-creation state are validated by Pushover.
235
+
236
+ ### Legacy API compatibility
237
+
238
+ The former message and receipt interfaces remain available as deprecated compatibility wrappers, with no scheduled removal:
239
+
240
+ ```ruby
241
+ Pushover::Message.new(token: 'app-token', user: 'user-key', message: 'Hello').push
242
+ Pushover::Receipt.new(token: 'app-token', receipt: 'AbCdEf0123456789GhIjKlMnOpQrSt').get
243
+ ```
244
+
245
+ Calling `push` or `get` emits a deprecation warning naming the replacement and delegates to the shared client resources. New code should use `client.messages.create` and `client.receipts.get`. The legacy raw `attachment` keyword remains accepted for constructor compatibility, but non-nil values are rejected because they cannot be safely translated to the supported `attachment_base64` and `attachment_type` interface.
246
+
247
+ ## CLI
248
+
249
+ Send a message:
250
+
251
+ ```shell
252
+ pushover --token=app-token --user=user-key message here we go again
253
+ pushover -tapp-token -uuser-key message here we go again
254
+ ```
56
255
 
57
- ### Responses
58
- response = Pushover::Message.new(token: 'token', user: 'user_key', message: '...').push
256
+ Get receipt details:
59
257
 
60
- # the below data is populated from the response
61
- puts response.status # return the status of the request, 0 or 1
62
- puts response.request # uuid of the request
63
- puts response.errors # array of errors (if any)
64
- puts response.receipt # receipt (if requested)
65
- puts response.headers # response headers (includes limits)
66
- puts response.attributes # any other k/v pair returned from pushover
258
+ ```shell
259
+ pushover -tapp-token receipt AbCdEf0123456789GhIjKlMnOpQrSt
67
260
  ```
68
261
 
69
262
  ## Contributing
70
263
 
71
- 1. Fork it
72
- 2. Switch to development (`git checkout development`)
73
- 3. Create your feature branch (`git checkout -b my-new-feature`)
74
- 4. Commit your changes (`git commit -am 'Added some feature'`)
75
- 5. Push to the branch (`git push origin my-new-feature`)
76
- 6. Create new Pull Request against `development`
264
+ 1. Fork the repository.
265
+ 2. Create a feature branch from `main`.
266
+ 3. Run `bundle exec rake ci`.
267
+ 4. Commit and push your changes.
268
+ 5. Open a pull request against `main`.
data/Rakefile CHANGED
@@ -1,63 +1,13 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
- require "open-uri"
4
- ### Configurables
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
5
4
 
6
- files = {
7
- Gemfile: 'https://gist.githubusercontent.com/erniebrodeur/5a5518f5051210f1828a0712bf623dc8/raw',
8
- Rakefile: 'https://gist.githubusercontent.com/erniebrodeur/afc92b72158413aa1f85d8d1facd267a/raw',
9
- Rubocop: 'https://gist.githubusercontent.com/erniebrodeur/f7f63996ef1e017aee9bf9d8e680a1df/raw',
10
- Tasks: 'https://gist.githubusercontent.com/erniebrodeur/03573fecf4f274101c14f6802abdbe83/raw',
11
- BinAdd: 'https://gist.githubusercontent.com/erniebrodeur/a815ee4d8bd9ccc54d91025a5543ebb8/raw',
12
- VsCodeFormatter: 'https://gist.githubusercontent.com/erniebrodeur/b24d757c0c625d108019eaceff2234cc/raw'
13
- }
14
-
15
- # spec
16
5
  RSpec::Core::RakeTask.new(:spec)
17
- task default: :spec
18
-
19
- # automagical updating
20
- desc "updates for various bits of the development environment."
21
-
22
- namespace :update do
23
- desc "update everything (multitasked)"
24
- multitask(all: %i[gemfile rakefile rubocop tasks vscode_formatter])
25
-
26
- desc 'Update Gemfile from gist'
27
- task :gemfile do
28
- grab_file 'Gemfile', files[:Gemfile]
29
- end
30
-
31
- desc 'Update Rakefile from gist'
32
- task :rakefile do
33
- grab_file 'Rakefile', files[:Rakefile]
34
- end
35
-
36
- desc 'Update .rubocop.yml from gist'
37
- task :rubocop do
38
- grab_file '.rubocop.yml', files[:Rubocop]
39
- end
40
-
41
- desc 'Update .vscode/tasks.json from gist'
42
- task :tasks do
43
- mkdir_p '.vscode'
44
- grab_file '.vscode/tasks.json', files[:Tasks]
45
- end
46
-
47
- desc 'Update vscode_formatter.rb in spec_helper'
48
- task :vscode_formatter do
49
- mkdir_p 'spec'
50
- grab_file 'spec/vscode_formatter.rb', files[:VsCodeFormatter]
51
- end
52
-
53
- desc 'Add a new lib and spec file (binary)'
54
- task :binadd do
55
- mkdir_p 'bin'
56
- grab_file 'bin/add', files[:BinAdd]
57
- end
6
+ RuboCop::RakeTask.new(:rubocop) do |task|
7
+ task.options = ['--cache-root', 'tmp/rubocop_cache']
58
8
  end
59
9
 
60
- def grab_file(filename, uri)
61
- File.write filename, OpenURI.open_uri(uri).read
62
- puts "Updated #{filename} from: #{uri}"
63
- end
10
+ desc 'Run all continuous integration checks'
11
+ task ci: %i[spec rubocop]
12
+
13
+ task default: :ci
data/exe/pushover CHANGED
@@ -4,7 +4,7 @@ require 'pushover'
4
4
 
5
5
  include GLI::App
6
6
 
7
- program_desc 'A simple todo list'
7
+ program_desc 'Send Pushover messages and retrieve receipts'
8
8
  subcommand_option_handling :normal
9
9
 
10
10
  flag %i[t token], type: String, desc: 'Application token'
@@ -21,16 +21,17 @@ command :message do |c|
21
21
  c.flag :expire, type: String, desc: 'how long should a priority message live'
22
22
  c.flag :retry, type: String, desc: 'how often should a resend be attempted (until acknowledged)'
23
23
  c.action do |global_options, options, args|
24
- puts Pushover::Message.new({
25
- message: args.join(" "), user: global_options[:user], token: global_options[:token]
26
- }.merge(GLI::Options.new(options).to_h.reject { |_k, v| v.nil? })).push
24
+ params = { message: args.join(" "), user: global_options[:user] }.merge(GLI::Options.new(options).to_h.compact)
25
+ %i[priority expire retry].each { |key| params[key] = params[key].to_i if params.key?(key) }
26
+
27
+ puts Pushover::Client.new(token: global_options[:token]).messages.create(**params)
27
28
  end
28
29
  end
29
30
 
30
31
  desc 'get a receipt'
31
32
  command :receipt do |c|
32
33
  c.action do |global_options, _options, args|
33
- puts Pushover::Receipt.new(token: global_options[:token], receipt: args[0]).get
34
+ puts Pushover::Client.new(token: global_options[:token]).receipts.get(receipt: args[0])
34
35
  end
35
36
  end
36
37
 
@@ -0,0 +1,53 @@
1
+ module Pushover
2
+ # Client holds shared application credentials and exposes API resources.
3
+ class Client
4
+ attr_reader :connection, :token
5
+
6
+ def initialize(token:, connection: Pushover::Excon)
7
+ raise ArgumentError, 'token must be supplied' unless token.is_a?(String) && !token.empty?
8
+
9
+ @token = token
10
+ @connection = connection
11
+ end
12
+
13
+ def messages
14
+ @messages ||= Messages.new(self)
15
+ end
16
+
17
+ def receipts
18
+ @receipts ||= Receipts.new(self)
19
+ end
20
+
21
+ def users
22
+ @users ||= Users.new(self)
23
+ end
24
+
25
+ def sounds
26
+ @sounds ||= Sounds.new(self)
27
+ end
28
+
29
+ def limits
30
+ @limits ||= Limits.new(self)
31
+ end
32
+
33
+ def glances
34
+ @glances ||= Glances.new(self)
35
+ end
36
+
37
+ def groups
38
+ @groups ||= Groups.new(self)
39
+ end
40
+
41
+ def subscriptions
42
+ @subscriptions ||= Subscriptions.new(self)
43
+ end
44
+
45
+ def licenses
46
+ @licenses ||= Licenses.new(self)
47
+ end
48
+
49
+ def teams
50
+ @teams ||= Teams.new(self)
51
+ end
52
+ end
53
+ end