magicbell 0.2.0 → 1.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +147 -125
- data/Rakefile +12 -0
- data/lib/magicbell.rb +40 -12
- data/lib/magicbell/action_mailer_extension.rb +1 -1
- data/lib/magicbell/api_operations.rb +44 -0
- data/lib/magicbell/api_resource.rb +119 -0
- data/lib/magicbell/api_resource_collection.rb +89 -0
- data/lib/magicbell/api_resources/notification.rb +4 -0
- data/lib/magicbell/api_resources/user.rb +45 -0
- data/lib/magicbell/api_resources/user_notification.rb +21 -0
- data/lib/magicbell/api_resources/user_notification_preferences.rb +11 -0
- data/lib/magicbell/api_resources/user_notification_read.rb +14 -0
- data/lib/magicbell/api_resources/user_notification_unread.rb +14 -0
- data/lib/magicbell/api_resources/user_notifications.rb +15 -0
- data/lib/magicbell/api_resources/user_notifications_read.rb +7 -0
- data/lib/magicbell/api_resources/user_notifications_seen.rb +7 -0
- data/lib/magicbell/client.rb +22 -7
- data/lib/magicbell/config.rb +20 -5
- data/lib/magicbell/singleton_api_resource.rb +7 -0
- data/lib/magicbell/version.rb +1 -1
- metadata +66 -14
- data/lib/magicbell/client/notifications.rb +0 -20
- data/lib/magicbell/hmac.rb +0 -14
- data/lib/magicbell/user.rb +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8478515db437819ee9ff7f478fecfdb8b5899647609d8f57332181af74402bfb
|
4
|
+
data.tar.gz: 75ef0e7dcb952f02b2cd0dea409df4d51ef7392877089a5352bec6940c68ec75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e47dd2b39572412bb3c25e9d29b588004df2abcf2e189f383b524f350bd6f14ad9a8a227543a74f9297192533fb18b37863bd37c3d4d1939d57251de38c9b4b
|
7
|
+
data.tar.gz: ae556dac4b1adcf1310bc4821b06007d8080b21d7212da62b011b82dd94792994eeb201e991850c353366a6df44427b9fcd722dd3671b722f56cc310142fe691
|
data/README.md
CHANGED
@@ -1,94 +1,161 @@
|
|
1
|
-
# magicbell-
|
1
|
+
# magicbell-ruby
|
2
2
|
|
3
|
-
|
3
|
+
[MagicBell](https://magicbell.io) is an embeddable Notification Inbox for web applications.
|
4
4
|
|
5
|
-
|
5
|
+
This gem
|
6
|
+
|
7
|
+
1. Makes it easy to interact with [MagicBell's REST API](https://developer.magicbell.io/reference) from Ruby.
|
8
|
+
|
9
|
+
You can use it to create a notification in your MagicBell project etc.
|
10
|
+
3. Can BCC your ActionMailer email notifications to MagicBell if you rather not use MagicBell's API in your Rails application.
|
11
|
+
|
12
|
+
MagicBell will create an in-app notification from any email notification that's blind copied to it.
|
13
|
+
3. Helps you calculate the HMAC for a user's email when you turn on HMAC Authentication for your MagicBell project
|
14
|
+
|
15
|
+
<img width="415" alt="MagicBell Notification Inbox" src="https://user-images.githubusercontent.com/1789832/28327736-f3503f44-6c01-11e7-9a72-c15023db18c6.png">
|
6
16
|
|
7
17
|
## Installation
|
8
18
|
|
9
|
-
|
19
|
+
Sign up at magicbell.io and obtain your MagicBell project's API Key and API Secret from the "Settings" section in your MagicBell dashboard.
|
20
|
+
|
21
|
+
Add the gem to your app's Gemfile
|
10
22
|
|
11
23
|
```ruby
|
12
24
|
gem "magicbell"
|
13
25
|
```
|
14
26
|
|
15
|
-
|
27
|
+
and install the gem
|
16
28
|
|
17
29
|
```
|
18
30
|
bundle install
|
19
31
|
```
|
20
32
|
|
21
|
-
|
33
|
+
The gem will automatically pick your MagicBell project's API Key and API Secret from the `MAGICBELL_API_KEY` and `MAGICBELL_API_SECRET` environment variables. Alternatively, provide the API Key and API Secret in an initializer
|
22
34
|
|
23
35
|
```
|
24
36
|
vim config/initializers/magicbell.rb
|
25
37
|
```
|
26
38
|
|
27
39
|
```ruby
|
40
|
+
# config/initializers/magicbell.rb
|
41
|
+
|
28
42
|
MagicBell.configure do |config|
|
29
43
|
config.api_key = "your_magicbell_api_key"
|
30
44
|
config.api_secret = "your_magicbell_api_secret"
|
31
|
-
config.project_id = 1 # your magicbell project id
|
32
|
-
config.magic_address = "your_magicell_magic_address@ring.magicbell.io"
|
33
45
|
end
|
34
46
|
```
|
35
47
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
```
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
48
|
+
## API Wrapper
|
49
|
+
|
50
|
+
This gem makes it easy to interact with MagicBell's REST API https://developer.magicbell.io/reference from Ruby
|
51
|
+
|
52
|
+
### Create a notification
|
53
|
+
|
54
|
+
Send a notification to one or many users
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
magicbell = MagicBell::Client.new
|
58
|
+
magicbell.create_notification(
|
59
|
+
"title" => "Rob assigned a task to you",
|
60
|
+
"recipients" => [
|
61
|
+
{
|
62
|
+
email: "joe@example.com"
|
63
|
+
},
|
64
|
+
]
|
65
|
+
)
|
66
|
+
```
|
67
|
+
|
68
|
+
You can even provide content for the notification and a URL to redirect the user to when they click on the notification the MagicBell Notification Inbox
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
magicbell = MagicBell::Client.new
|
72
|
+
magicbell.create_notification(
|
73
|
+
"title" => "Rob assigned to a task to you",
|
74
|
+
"recipients" => [
|
75
|
+
{
|
76
|
+
email: "joe@example.com"
|
77
|
+
},
|
78
|
+
],
|
79
|
+
"content": "Hey Joe, can give this customer a demo of our app?",
|
80
|
+
"action_url" => "https://yourwebsite.com/task_path"
|
81
|
+
)
|
82
|
+
```
|
83
|
+
|
84
|
+
### Fetch a user's notifications
|
85
|
+
|
86
|
+
Fetch a user's notifications
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
magicbell = MagicBell::Client.new
|
90
|
+
user = magicbell.user_with_email("joe@example.com")
|
91
|
+
user_notifications = user.notifications
|
92
|
+
user_notifications.each { |user_notification| puts user_notification.attribute("title") }
|
93
|
+
```
|
94
|
+
|
95
|
+
Please note that the example above fetches the user's 15 most recent notification (the default number of notifications per page) If you'd like to fetch subsequent pages, use
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
magicbell = MagicBell::Client.new
|
99
|
+
user = magicbell.user_with_email("joe@example.com")
|
100
|
+
user_notifications = user.notifications
|
101
|
+
user_notifications.each_page do |page|
|
102
|
+
page.each do |user_notification|
|
103
|
+
puts user_notification.attribute("title")
|
104
|
+
end
|
105
|
+
end
|
70
106
|
```
|
71
107
|
|
72
|
-
|
108
|
+
### Mark a user notification as read/unread
|
73
109
|
|
74
|
-
```
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
110
|
+
```ruby
|
111
|
+
magicbell = MagicBell::Client.new
|
112
|
+
user = magicbell.user_with_email("joe@example.com")
|
113
|
+
user_notification = user.notifications.first
|
114
|
+
user_notification.mark_as_read
|
115
|
+
user_notification.mark_as_unread
|
116
|
+
```
|
117
|
+
|
118
|
+
### Mark all notifications of a user as read/seen
|
79
119
|
|
80
|
-
|
81
|
-
|
120
|
+
```ruby
|
121
|
+
magicbell = MagicBell::Client.new
|
122
|
+
user = magicbell.user_with_email("joe@example.com")
|
123
|
+
user.mark_all_notifications_as_read
|
124
|
+
user.mark_all_notifications_as_seen
|
82
125
|
```
|
83
126
|
|
84
|
-
|
127
|
+
### Error handling
|
128
|
+
|
129
|
+
Please note that the gem raises a `MagicBell::Client::HTTPError` if an API returns a non 2xx response
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
begin
|
133
|
+
magicbell = MagicBell::Client.new
|
134
|
+
magicbell.create_notification(
|
135
|
+
"title" => "Rob assigned to a task to you"
|
136
|
+
)
|
137
|
+
rescue MagicBell::Client::HTTPError => e
|
138
|
+
# Report the error to your error tracker
|
139
|
+
error_context = {
|
140
|
+
response_status: e.response_status,
|
141
|
+
response_headers: e.response_headers,
|
142
|
+
response_body: e.response_body
|
143
|
+
}
|
144
|
+
ErrorReporter.report(e, context: error_context)
|
145
|
+
end
|
146
|
+
```
|
147
|
+
|
148
|
+
## Rails integration
|
149
|
+
|
150
|
+
If you've existing ActionMailer email notifications in your Rails app and prefer to not spend time migrating to MagicBell's API, you can blind copy your ActionMailer email notifications to MagicBell. MagicBell will create in-app notifications from email notifications blind copied to it.
|
151
|
+
|
152
|
+
Call the `ring_the_magicbell` method in your action mailers like in the example below
|
85
153
|
|
86
154
|
```ruby
|
87
155
|
class NotificationMailer < ActionMailer::Base
|
88
|
-
#
|
156
|
+
# The ring_the_magicbell method will bcc your email notifications to your MagicBell project's BCC email address
|
89
157
|
#
|
90
|
-
# Upon receiving
|
91
|
-
# create in-app notications for users
|
158
|
+
# Upon receiving a blind copied email notification, magicbell.io will automatically create an in-app notification for the user
|
92
159
|
ring_the_magicbell
|
93
160
|
|
94
161
|
# This is an email notification in your app
|
@@ -103,35 +170,29 @@ class NotificationMailer < ActionMailer::Base
|
|
103
170
|
end
|
104
171
|
```
|
105
172
|
|
106
|
-
|
107
|
-
|
108
|
-
That's it! All your users now benefit from having in-app notifications.
|
109
|
-
|
110
|
-
If you've trouble adding MagicBell to your app or find yourself stuck, please don't hestitate to reach out to us at hana@magicbell.io We usually respond within 24 hours (often much lesser).
|
111
|
-
|
112
|
-
## Advanced Features
|
113
|
-
|
114
|
-
#### ActionUrl
|
115
|
-
|
116
|
-
When a user clicks on a notification in MagicBell's widget, the widget redirects the user to the first URL the body of the email notification. We call this URL the `ActionUrl`.
|
173
|
+
The gem will automatically pick your MagicBell project's BCC email from the `MAGICBELL_BCC_EMAIL` environment variable. Alternatively, provide your MagicBell project's BCC email address in an initializer
|
117
174
|
|
118
|
-
|
175
|
+
```
|
176
|
+
vim config/initializers/magicbell.rb
|
177
|
+
```
|
119
178
|
|
120
179
|
```ruby
|
121
|
-
|
122
|
-
ring_the_magicbell
|
180
|
+
# config/initializers/magicbell.rb
|
123
181
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
end
|
182
|
+
MagicBell.configure do |config|
|
183
|
+
config.api_key = "your_magicbell_api_key"
|
184
|
+
config.api_secret = "your_magicbell_api_secret"
|
185
|
+
config.bcc_email = "your_magicbell_bcc_email@ring.magicbell.io"
|
129
186
|
end
|
130
187
|
```
|
131
188
|
|
132
|
-
|
189
|
+
The BCC email address is available in the "Settings" section in your MagicBell dashboard.
|
190
|
+
|
191
|
+
### Customize Action URL
|
133
192
|
|
134
|
-
|
193
|
+
When a user clicks on a notification in MagicBell's Notification Inbox, the Notification Inbox redirects the user to the first URL the body of the email notification. This URL is called the `action_url`.
|
194
|
+
|
195
|
+
If you wish to redirect users to a different URL instead, provide an `action_url` in your mailers
|
135
196
|
|
136
197
|
```ruby
|
137
198
|
class NotificationMailer < ActionMailer::Base
|
@@ -139,15 +200,15 @@ class NotificationMailer < ActionMailer::Base
|
|
139
200
|
|
140
201
|
def new_comment(comment)
|
141
202
|
# ...
|
142
|
-
|
203
|
+
magicbell_notification_action_url("https://myapp.com/comments/#{comment.id}")
|
143
204
|
# ...
|
144
205
|
end
|
145
206
|
end
|
146
207
|
```
|
147
208
|
|
148
|
-
|
209
|
+
### Customize Notification Title
|
149
210
|
|
150
|
-
|
211
|
+
The Notification inbox will use the subject of the email notification as a notification's title. If this behaviour isn't sutiable for your app, provide a title in your mailers
|
151
212
|
|
152
213
|
```ruby
|
153
214
|
class NotificationMailer < ActionMailer::Base
|
@@ -155,63 +216,24 @@ class NotificationMailer < ActionMailer::Base
|
|
155
216
|
|
156
217
|
def new_comment(comment)
|
157
218
|
# ...
|
158
|
-
|
219
|
+
magicbell_notification_title("Richard posted a new comment")
|
159
220
|
# ...
|
160
221
|
end
|
161
222
|
end
|
162
223
|
```
|
163
224
|
|
164
|
-
|
165
|
-
|
166
|
-
#### Customize widget behaviour
|
167
|
-
|
168
|
-
When a user clicks on a notification in MagicBell's widget, the widget redirects the user to the notification's `ActionUrl`. If this behaviour isn't suitable for your app (if your app is a Single Page Application for example), you can customize it.
|
225
|
+
## HMAC Authentication
|
169
226
|
|
170
|
-
|
227
|
+
### Calculate HMAC
|
171
228
|
|
172
|
-
```javascript
|
173
|
-
function initializeMagicBell() {
|
174
|
-
MagicBell.initialize({
|
175
|
-
target: document.getElementById('magicbell_notifications'),
|
176
|
-
projectId: "<%= MagicBell.project_id %>",
|
177
|
-
apiKey: "<%= MagicBell.api_key %>",
|
178
|
-
userEmail: <%= current_user.email %>,
|
179
|
-
userKey: "<%= MagicBell.user_key(current_user.email) %>",
|
180
|
-
onNotificationClick: function (notification) {
|
181
|
-
// openComment is a function that you've defined in your app's javascript to open
|
182
|
-
// and display a specific comment to the user
|
183
|
-
openComment(notification.meta_data.comment_id)
|
184
|
-
}
|
185
|
-
});
|
186
|
-
}
|
187
229
|
```
|
188
|
-
|
189
|
-
|
190
|
-
## Managing notifications
|
191
|
-
|
192
|
-
### Creating a notification
|
193
|
-
|
194
|
-
You can create notifications for users. Once `MagicBell` is configured, you can
|
195
|
-
call `create_notification` method to create a notification for a given project.
|
196
|
-
|
197
|
-
```
|
198
|
-
params = {
|
199
|
-
to: "user@example.com",
|
200
|
-
title: "Your download is ready",
|
201
|
-
content: "Zip file to download is here",
|
202
|
-
action_url: "https://example.com/notifications/1"
|
203
|
-
}
|
204
|
-
|
205
|
-
client = MagicBell::Client.new()
|
206
|
-
client.create_notification(params)
|
230
|
+
user_email = "joe@example.com"
|
231
|
+
hmac = MagicBell.hmac(user_email)
|
207
232
|
```
|
208
233
|
|
209
|
-
|
210
|
-
`body` will be available for further inspection.
|
211
|
-
|
234
|
+
See https://developer.magicbell.io/docs/turn-on-hmac-authentication for more information on turning on HMAC Authentication for your MagicBell Project
|
212
235
|
|
213
|
-
If you'd like us to add more callbacks to the widget, reach out to us at hana@magicbell.io
|
214
236
|
|
215
|
-
##
|
237
|
+
## Developer Hub
|
216
238
|
|
217
|
-
|
239
|
+
Please visit our [Developer Hub](https://developer.magicbell.io) for documentation on MagicBell's API and MagicBell's embeddable Notification Inbox
|
data/Rakefile
CHANGED
@@ -25,3 +25,15 @@ Rake::TestTask.new(:test) do |t|
|
|
25
25
|
end
|
26
26
|
|
27
27
|
task default: :test
|
28
|
+
|
29
|
+
task :publish_to_rubygems do
|
30
|
+
`gem build magicbell.gemspec`
|
31
|
+
require_relative "lib/magicbell"
|
32
|
+
`gem push magicbell-#{MagicBell::VERSION}.gem`
|
33
|
+
end
|
34
|
+
|
35
|
+
task :console do
|
36
|
+
require_relative "lib/magicbell"
|
37
|
+
require "pry"
|
38
|
+
binding.pry
|
39
|
+
end
|
data/lib/magicbell.rb
CHANGED
@@ -1,11 +1,27 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
require "openssl"
|
4
|
+
require "base64"
|
5
|
+
|
1
6
|
require "magicbell/config"
|
2
|
-
require "magicbell/hmac"
|
3
|
-
require "magicbell/user"
|
4
|
-
require "magicbell/railtie" if defined?(Rails)
|
5
|
-
require "magicbell/client"
|
6
7
|
|
7
|
-
require
|
8
|
+
require "httparty"
|
9
|
+
require "magicbell/api_operations"
|
10
|
+
require "magicbell/client"
|
11
|
+
require "magicbell/api_resource"
|
12
|
+
require "magicbell/singleton_api_resource"
|
13
|
+
require "magicbell/api_resource_collection"
|
14
|
+
require "magicbell/api_resources/notification"
|
15
|
+
require "magicbell/api_resources/user"
|
16
|
+
require "magicbell/api_resources/user_notification"
|
17
|
+
require "magicbell/api_resources/user_notifications"
|
18
|
+
require "magicbell/api_resources/user_notification_read"
|
19
|
+
require "magicbell/api_resources/user_notification_unread"
|
20
|
+
require "magicbell/api_resources/user_notifications_read"
|
21
|
+
require "magicbell/api_resources/user_notifications_seen"
|
22
|
+
require "magicbell/api_resources/user_notification_preferences"
|
8
23
|
|
24
|
+
require "magicbell/railtie" if defined?(Rails)
|
9
25
|
|
10
26
|
module MagicBell
|
11
27
|
WIDGET_JAVASCRIPT_URL = "https://assets.magicbell.io/widget.magicbell.js"
|
@@ -14,7 +30,10 @@ module MagicBell
|
|
14
30
|
class << self
|
15
31
|
extend Forwardable
|
16
32
|
|
17
|
-
def_delegators
|
33
|
+
def_delegators :config, :api_key,
|
34
|
+
:api_secret,
|
35
|
+
:bcc_email,
|
36
|
+
:api_host
|
18
37
|
|
19
38
|
def configure
|
20
39
|
yield(config)
|
@@ -25,19 +44,28 @@ module MagicBell
|
|
25
44
|
end
|
26
45
|
|
27
46
|
def reset_config
|
28
|
-
@config =
|
47
|
+
@config = Config.new
|
29
48
|
end
|
30
49
|
|
31
|
-
def
|
50
|
+
def authentication_headers
|
32
51
|
{
|
33
|
-
|
34
|
-
|
52
|
+
"X-MAGICBELL-API-KEY" => api_key,
|
53
|
+
"X-MAGICBELL-API-SECRET" => api_secret
|
35
54
|
}
|
36
55
|
end
|
37
56
|
|
38
57
|
# Calculate HMAC for user's email
|
39
|
-
def
|
40
|
-
|
58
|
+
def hmac(message)
|
59
|
+
digest = sha256_digest
|
60
|
+
secret = api_secret
|
61
|
+
|
62
|
+
Base64.encode64(OpenSSL::HMAC.digest(digest, secret, message)).strip
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def sha256_digest
|
68
|
+
OpenSSL::Digest::Digest.new('sha256')
|
41
69
|
end
|
42
70
|
end
|
43
71
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module MagicBell
|
2
|
+
module ApiOperations
|
3
|
+
def get(url, options = {})
|
4
|
+
response = HTTParty.get(
|
5
|
+
url,
|
6
|
+
options.merge(headers: authentication_headers)
|
7
|
+
)
|
8
|
+
raise_http_error_unless_2xx_response(response)
|
9
|
+
|
10
|
+
response
|
11
|
+
end
|
12
|
+
|
13
|
+
def post(url, options = {})
|
14
|
+
response = HTTParty.post(
|
15
|
+
url,
|
16
|
+
options.merge(headers: authentication_headers)
|
17
|
+
)
|
18
|
+
raise_http_error_unless_2xx_response(response)
|
19
|
+
|
20
|
+
response
|
21
|
+
end
|
22
|
+
|
23
|
+
def put(url, options = {})
|
24
|
+
response = HTTParty.put(
|
25
|
+
url,
|
26
|
+
options.merge(headers: authentication_headers)
|
27
|
+
)
|
28
|
+
raise_http_error_unless_2xx_response(response)
|
29
|
+
|
30
|
+
response
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def raise_http_error_unless_2xx_response(response)
|
36
|
+
return if response.success?
|
37
|
+
e = MagicBell::Client::HTTPError.new
|
38
|
+
e.response_status = response.code
|
39
|
+
e.response_headers = response.headers.to_h
|
40
|
+
e.response_body = response.body
|
41
|
+
raise e
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require "active_support/inflector"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module MagicBell
|
5
|
+
class ApiResource
|
6
|
+
class << self
|
7
|
+
def create(client, attributes = {})
|
8
|
+
new(client, attributes).create
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
to_s.demodulize.underscore
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_path
|
16
|
+
"/#{name}s"
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_url
|
20
|
+
MagicBell.api_host + create_path
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_reader :id
|
25
|
+
|
26
|
+
def initialize(client, attributes = {})
|
27
|
+
@client = client
|
28
|
+
@attributes = attributes
|
29
|
+
|
30
|
+
@id = @attributes["id"]
|
31
|
+
@retrieved = true if @id
|
32
|
+
end
|
33
|
+
|
34
|
+
def attributes
|
35
|
+
retrieve_unless_retrieved
|
36
|
+
@attributes
|
37
|
+
end
|
38
|
+
alias_method :to_h, :attributes
|
39
|
+
|
40
|
+
def attribute(attribute_name)
|
41
|
+
attributes[attribute_name]
|
42
|
+
end
|
43
|
+
|
44
|
+
def retrieve
|
45
|
+
response = @client.get(url)
|
46
|
+
parse_response(response)
|
47
|
+
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
def name
|
52
|
+
self.class.name
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_url
|
56
|
+
MagicBell.api_host + create_path
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_path
|
60
|
+
"/#{name}s"
|
61
|
+
end
|
62
|
+
|
63
|
+
def url
|
64
|
+
MagicBell.api_host + path
|
65
|
+
end
|
66
|
+
|
67
|
+
def path
|
68
|
+
"/#{name}s/#{id}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def create
|
72
|
+
response = @client.post(
|
73
|
+
create_url,
|
74
|
+
body: { name => attributes }.to_json,
|
75
|
+
headers: authentication_headers
|
76
|
+
)
|
77
|
+
parse_response(response)
|
78
|
+
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
def update(new_attributes = {})
|
83
|
+
response = @client.put(
|
84
|
+
url,
|
85
|
+
body: new_attributes.to_json,
|
86
|
+
headers: authentication_headers
|
87
|
+
)
|
88
|
+
parse_response(response)
|
89
|
+
|
90
|
+
self
|
91
|
+
end
|
92
|
+
|
93
|
+
protected
|
94
|
+
|
95
|
+
def authentication_headers
|
96
|
+
MagicBell.authentication_headers
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
attr_reader :response,
|
102
|
+
:response_hash
|
103
|
+
|
104
|
+
def retrieve_unless_retrieved
|
105
|
+
return unless id # Never retrieve a new unsaved resource
|
106
|
+
return if @retrieved
|
107
|
+
retrieve
|
108
|
+
end
|
109
|
+
|
110
|
+
def parse_response(response)
|
111
|
+
@response = response
|
112
|
+
unless response.body.empty?
|
113
|
+
@response_hash = JSON.parse(@response.body)
|
114
|
+
@attributes = @response_hash[name]
|
115
|
+
end
|
116
|
+
@retrieved = true
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module MagicBell
|
2
|
+
class ApiResourceCollection
|
3
|
+
def initialize(client, query_params = {})
|
4
|
+
@client = client
|
5
|
+
@query_params = query_params
|
6
|
+
@retrieved = false
|
7
|
+
end
|
8
|
+
|
9
|
+
# @todo Add examples
|
10
|
+
def retrieve
|
11
|
+
@response = @client.get(
|
12
|
+
url,
|
13
|
+
query: @query_params
|
14
|
+
)
|
15
|
+
@response_hash = JSON.parse(response.body)
|
16
|
+
@resources = response_hash[name].map { |resource_attributes| resource_class.new(@client, resource_attributes) }
|
17
|
+
@retrieved = true
|
18
|
+
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_a
|
23
|
+
resources
|
24
|
+
end
|
25
|
+
|
26
|
+
def first
|
27
|
+
resources.first
|
28
|
+
end
|
29
|
+
|
30
|
+
def url
|
31
|
+
MagicBell.api_host + path
|
32
|
+
end
|
33
|
+
|
34
|
+
def authentication_headers
|
35
|
+
MagicBell.authentication_headers
|
36
|
+
end
|
37
|
+
|
38
|
+
def each(&block)
|
39
|
+
resources.each(&block)
|
40
|
+
end
|
41
|
+
|
42
|
+
def each_page
|
43
|
+
current_page = self
|
44
|
+
loop do
|
45
|
+
yield(current_page)
|
46
|
+
break if current_page.last_page?
|
47
|
+
current_page = current_page.next_page
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def last_page?
|
52
|
+
current_page == total_pages
|
53
|
+
end
|
54
|
+
|
55
|
+
def next_page
|
56
|
+
self.class.new(@client, page: current_page + 1, per_page: per_page)
|
57
|
+
end
|
58
|
+
|
59
|
+
def current_page
|
60
|
+
retrieve_unless_retrieved
|
61
|
+
response_hash["current_page"]
|
62
|
+
end
|
63
|
+
|
64
|
+
def total_pages
|
65
|
+
retrieve_unless_retrieved
|
66
|
+
response_hash["total_pages"]
|
67
|
+
end
|
68
|
+
|
69
|
+
def per_page
|
70
|
+
retrieve_unless_retrieved
|
71
|
+
response_hash["per_page"]
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
attr_reader :response,
|
77
|
+
:response_hash
|
78
|
+
|
79
|
+
def resources
|
80
|
+
retrieve_unless_retrieved
|
81
|
+
return @resources
|
82
|
+
end
|
83
|
+
|
84
|
+
def retrieve_unless_retrieved
|
85
|
+
return if @retrieved
|
86
|
+
retrieve
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module MagicBell
|
2
|
+
class User < ApiResource
|
3
|
+
include ApiOperations
|
4
|
+
|
5
|
+
attr_reader :email
|
6
|
+
|
7
|
+
def initialize(client, attributes)
|
8
|
+
@client = client
|
9
|
+
@email = attributes["email"]
|
10
|
+
super(client, attributes)
|
11
|
+
end
|
12
|
+
|
13
|
+
def notifications(query_params = {})
|
14
|
+
client = self
|
15
|
+
MagicBell::UserNotifications.new(client, query_params)
|
16
|
+
end
|
17
|
+
|
18
|
+
def mark_all_notifications_as_read
|
19
|
+
client = self
|
20
|
+
MagicBell::UserNotificationsRead.new(client).create
|
21
|
+
end
|
22
|
+
|
23
|
+
def mark_all_notifications_as_seen
|
24
|
+
client = self
|
25
|
+
MagicBell::UserNotificationsSeen.new(client).create
|
26
|
+
end
|
27
|
+
|
28
|
+
def notification_preferences
|
29
|
+
client = self
|
30
|
+
MagicBell::UserNotificationPreferences.new(client)
|
31
|
+
end
|
32
|
+
|
33
|
+
def path
|
34
|
+
if id
|
35
|
+
self.class.path + "/#{id}"
|
36
|
+
elsif email
|
37
|
+
self.class.path + "/email:#{email}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def authentication_headers
|
42
|
+
MagicBell.authentication_headers.merge("X-MAGICBELL-USER-EMAIL" => email)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module MagicBell
|
2
|
+
class UserNotification < ApiResource
|
3
|
+
class << self
|
4
|
+
def path
|
5
|
+
"/notifications"
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def path
|
10
|
+
"/notifications/#{id}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def mark_as_read
|
14
|
+
UserNotificationRead.new(@client, "user_notification" => self).create
|
15
|
+
end
|
16
|
+
|
17
|
+
def mark_as_unread
|
18
|
+
UserNotificationUnread.new(@client, "user_notification" => self).create
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module MagicBell
|
2
|
+
class UserNotificationRead < SingletonApiResource
|
3
|
+
attr_reader :user_notification
|
4
|
+
|
5
|
+
def initialize(client, attributes)
|
6
|
+
@user_notification = attributes.delete("user_notification")
|
7
|
+
super(client, attributes)
|
8
|
+
end
|
9
|
+
|
10
|
+
def path
|
11
|
+
user_notification.path + "/read"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module MagicBell
|
2
|
+
class UserNotificationRead < SingletonApiResource
|
3
|
+
attr_reader :user_notification
|
4
|
+
|
5
|
+
def initialize(client, attributes)
|
6
|
+
@user_notification = attributes.delete("user_notification")
|
7
|
+
super(client, attributes)
|
8
|
+
end
|
9
|
+
|
10
|
+
def path
|
11
|
+
user_notification.path + "/unread"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/magicbell/client.rb
CHANGED
@@ -1,13 +1,28 @@
|
|
1
|
-
require "magicbell/client/notifications"
|
2
|
-
|
3
1
|
module MagicBell
|
4
2
|
class Client
|
5
|
-
|
3
|
+
class HTTPError < StandardError
|
4
|
+
attr_accessor :response_status,
|
5
|
+
:response_headers,
|
6
|
+
:response_body
|
7
|
+
end
|
8
|
+
|
9
|
+
include ApiOperations
|
10
|
+
|
11
|
+
def create_notification(notification_attributes)
|
12
|
+
MagicBell::Notification.create(self, notification_attributes)
|
13
|
+
end
|
14
|
+
|
15
|
+
# def user(user_id)
|
16
|
+
# MagicBell::User.find(user_id)
|
17
|
+
# end
|
18
|
+
|
19
|
+
def user_with_email(email)
|
20
|
+
client = self
|
21
|
+
MagicBell::User.new(client, "email" => email)
|
22
|
+
end
|
6
23
|
|
7
|
-
|
8
|
-
|
9
|
-
def connection
|
10
|
-
@connection ||= Faraday.new(url: MagicBell.api_host)
|
24
|
+
def authentication_headers
|
25
|
+
MagicBell.authentication_headers
|
11
26
|
end
|
12
27
|
end
|
13
28
|
end
|
data/lib/magicbell/config.rb
CHANGED
@@ -1,13 +1,28 @@
|
|
1
1
|
module MagicBell
|
2
2
|
class Config
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
attr_accessor :api_host
|
3
|
+
attr_writer :api_key
|
4
|
+
attr_writer :api_secret
|
5
|
+
attr_writer :bcc_email
|
6
|
+
attr_writer :api_host
|
8
7
|
|
9
8
|
def initialize
|
10
9
|
@api_host = "https://api.magicbell.io"
|
11
10
|
end
|
11
|
+
|
12
|
+
def api_key
|
13
|
+
@api_key || ENV["MAGICBELL_API_KEY"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def api_secret
|
17
|
+
@api_secret || ENV["MAGICBELL_API_SECRET"]
|
18
|
+
end
|
19
|
+
|
20
|
+
def bcc_email
|
21
|
+
@bcc_email || ENV["MAGICBELL_BCC_EMAIL"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def api_host
|
25
|
+
@api_host || ENV["MAGICBELL_API_HOST"] || "https://api.magicbell.io"
|
26
|
+
end
|
12
27
|
end
|
13
28
|
end
|
data/lib/magicbell/version.rb
CHANGED
metadata
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: magicbell
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.beta2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hana Mohan
|
8
8
|
- Nisanth Chunduru
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-
|
12
|
+
date: 2020-12-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: httparty
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '0'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
|
-
name:
|
29
|
+
name: activesupport
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
32
|
- - ">="
|
@@ -40,7 +40,7 @@ dependencies:
|
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '0'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
|
-
name:
|
43
|
+
name: actionmailer
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
46
|
- - ">="
|
@@ -67,6 +67,48 @@ dependencies:
|
|
67
67
|
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '3.9'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: webmock
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: pry
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: rake
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
70
112
|
description: Notifications like never before!
|
71
113
|
email:
|
72
114
|
- hana@magicbell.io
|
@@ -80,18 +122,28 @@ files:
|
|
80
122
|
- Rakefile
|
81
123
|
- lib/magicbell.rb
|
82
124
|
- lib/magicbell/action_mailer_extension.rb
|
125
|
+
- lib/magicbell/api_operations.rb
|
126
|
+
- lib/magicbell/api_resource.rb
|
127
|
+
- lib/magicbell/api_resource_collection.rb
|
128
|
+
- lib/magicbell/api_resources/notification.rb
|
129
|
+
- lib/magicbell/api_resources/user.rb
|
130
|
+
- lib/magicbell/api_resources/user_notification.rb
|
131
|
+
- lib/magicbell/api_resources/user_notification_preferences.rb
|
132
|
+
- lib/magicbell/api_resources/user_notification_read.rb
|
133
|
+
- lib/magicbell/api_resources/user_notification_unread.rb
|
134
|
+
- lib/magicbell/api_resources/user_notifications.rb
|
135
|
+
- lib/magicbell/api_resources/user_notifications_read.rb
|
136
|
+
- lib/magicbell/api_resources/user_notifications_seen.rb
|
83
137
|
- lib/magicbell/client.rb
|
84
|
-
- lib/magicbell/client/notifications.rb
|
85
138
|
- lib/magicbell/config.rb
|
86
|
-
- lib/magicbell/hmac.rb
|
87
139
|
- lib/magicbell/railtie.rb
|
88
|
-
- lib/magicbell/
|
140
|
+
- lib/magicbell/singleton_api_resource.rb
|
89
141
|
- lib/magicbell/version.rb
|
90
142
|
homepage: https://magicbell.io
|
91
143
|
licenses:
|
92
144
|
- MIT
|
93
145
|
metadata: {}
|
94
|
-
post_install_message:
|
146
|
+
post_install_message:
|
95
147
|
rdoc_options: []
|
96
148
|
require_paths:
|
97
149
|
- lib
|
@@ -102,12 +154,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
102
154
|
version: '0'
|
103
155
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
156
|
requirements:
|
105
|
-
- - "
|
157
|
+
- - ">"
|
106
158
|
- !ruby/object:Gem::Version
|
107
|
-
version:
|
159
|
+
version: 1.3.1
|
108
160
|
requirements: []
|
109
|
-
rubygems_version: 3.1.
|
110
|
-
signing_key:
|
161
|
+
rubygems_version: 3.1.4
|
162
|
+
signing_key:
|
111
163
|
specification_version: 4
|
112
164
|
summary: Ruby wrapper for MagicBell.io
|
113
165
|
test_files: []
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module MagicBell
|
2
|
-
class Client
|
3
|
-
module Notifications
|
4
|
-
# Creates a notification for a given project
|
5
|
-
#
|
6
|
-
# @param to [String] Email of a user for this notification
|
7
|
-
# @param title [String] Title of the notification
|
8
|
-
# @param content [String] Content of the notification
|
9
|
-
# @param action_url [String] Url to redirect to from widget
|
10
|
-
def create_notification(to, title, content, action_url)
|
11
|
-
params = {to: to, title: title, content: content, action_url: action_url}
|
12
|
-
|
13
|
-
connection.post("/notifications.json") do |req|
|
14
|
-
req.headers = {"X-MAGICBELL-API-SECRET" => MagicBell.api_secret}
|
15
|
-
req.body = {notification: params}
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
data/lib/magicbell/hmac.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
require "openssl"
|
2
|
-
require "base64"
|
3
|
-
|
4
|
-
module MagicBell
|
5
|
-
module HMAC
|
6
|
-
class << self
|
7
|
-
def calculate(message)
|
8
|
-
secret = MagicBell.api_secret
|
9
|
-
digest = OpenSSL::Digest::Digest.new('sha256')
|
10
|
-
Base64.encode64(OpenSSL::HMAC.digest(digest, secret, message)).strip
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
data/lib/magicbell/user.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
require 'faraday'
|
2
|
-
require 'json'
|
3
|
-
|
4
|
-
module MagicBell
|
5
|
-
class User
|
6
|
-
|
7
|
-
attr_accessor :email
|
8
|
-
attr_accessor :preferences
|
9
|
-
|
10
|
-
def initialize(attributes)
|
11
|
-
@attributes = attributes
|
12
|
-
@email = @attributes[:email]
|
13
|
-
@conn = Faraday.new({
|
14
|
-
url: MagicBell.api_host,
|
15
|
-
headers: MagicBell.project_specific_headers.merge(
|
16
|
-
'X-MAGICBELL-USER-EMAIL' => @email
|
17
|
-
)
|
18
|
-
})
|
19
|
-
end
|
20
|
-
|
21
|
-
def notifications
|
22
|
-
response = @conn.get "/notifications.json"
|
23
|
-
JSON.parse(response.body)["notifications"]
|
24
|
-
end
|
25
|
-
|
26
|
-
def hmac_signature
|
27
|
-
MagicBell::HMAC.calculate @email
|
28
|
-
end
|
29
|
-
|
30
|
-
def notification_preferences
|
31
|
-
response = @conn.get "/notification_preferences.json"
|
32
|
-
JSON.parse(response.body)["notification_preferences"]
|
33
|
-
end
|
34
|
-
|
35
|
-
def notification_preferences=(preferences)
|
36
|
-
@conn.put "/notification_preferences.json",
|
37
|
-
{notification_preferences: preferences}
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
41
|
-
end
|