Skip to content

Commit a57115f

Browse files
committed
feat: add webhooks
1 parent e18a03a commit a57115f

File tree

11 files changed

+150
-23
lines changed

11 files changed

+150
-23
lines changed

Gemfile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,7 @@ source "https://rubygems.org"
55
# Specify your gem's dependencies in topgg.gemspec
66
gemspec
77

8-
gem "rake", "~> 13.0"
9-
gem "ostruct", "~> 0.6"
8+
gem "rack"
9+
gem "rake"
10+
gem "ostruct"
11+
gem "cgi"

Gemfile.lock

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,26 @@ PATH
22
remote: .
33
specs:
44
topgg (2.0.0)
5+
rack (~> 3.0.9.1)
56

67
GEM
78
remote: https://rubygems.org/
89
specs:
10+
cgi (0.5.0)
911
ostruct (0.6.1)
10-
power_assert (2.0.5)
12+
rack (3.0.9.1)
1113
rake (13.0.6)
12-
test-unit (3.6.8)
13-
power_assert
1414

1515
PLATFORMS
1616
x64-mingw-ucrt
1717
x86_64-linux
1818

1919
DEPENDENCIES
20-
ostruct (~> 0.6)
21-
rake (~> 13.0)
22-
test-unit (~> 3.1, >= 3.1.8)
20+
cgi (~> 0.5.0)
21+
ostruct
22+
rack
23+
rake
2324
topgg!
2425

2526
BUNDLED WITH
26-
2.6.7
27+
2.6.9

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,38 @@ widget_url = Dbl::Widget.owner(:discord_bot, "574652751745777665")
123123

124124
```rb
125125
widget_url = Dbl::Widget.social(:discord_bot, "574652751745777665")
126+
```
127+
128+
### Webhooks
129+
130+
#### Being notified whenever someone voted for your bot
131+
132+
##### Ruby on Rails
133+
134+
In your `config/application.rb`:
135+
136+
```rb
137+
module WebhookApi
138+
class Application < Rails::Application
139+
# ...
140+
141+
config.middleware.use Dbl::Webhook,
142+
type: Dbl::Webhook::VOTE,
143+
path: "/votes",
144+
auth: ENV["MY_TOPGG_WEBHOOK_SECRET"] do |vote|
145+
Rails.logger.info "A user with the ID of #{vote.voter_id} has voted us on Top.gg!"
146+
end
147+
end
148+
end
149+
```
150+
151+
##### Sinatra
152+
153+
```rb
154+
use Dbl::Webhook,
155+
type: Dbl::Webhook::VOTE,
156+
path: "/votes",
157+
auth: ENV["MY_TOPGG_WEBHOOK_SECRET"] do |vote|
158+
puts "A user with the ID of #{vote.voter_id} has voted us on Top.gg!"
159+
end
126160
```

lib/lib.rb renamed to lib/topgg.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
require "base64"
44
require "json"
55

6-
require_relative "topgg/utils/request"
76
require_relative "topgg/bot"
87
require_relative "topgg/botSearch"
98
require_relative "topgg/user"
109
require_relative "topgg/stats"
10+
require_relative "topgg/vote"
1111
require_relative "topgg/votes"
12+
require_relative "topgg/webhooks"
1213
require_relative "topgg/widget"
1314

1415
# Class Topgg

lib/topgg/bot.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require "Date"
1+
require "date"
22

33
module Dbl
44
# The Bot class spreads the json parsed hash into different methods
@@ -8,13 +8,14 @@ class Bot
88
def initialize(obj)
99
@obj = obj
1010
end
11+
1112
# Returns raw hash of the parsed json object
1213
# @return [Hash]
1314
attr_reader :obj
1415

1516
alias raw obj
16-
1717
alias data obj
18+
1819
# Returns error message if there's an error, otherwise nil
1920
# @return [String]
2021
def error

lib/topgg/botSearch.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ class BotSearch
77
def initialize(obj)
88
@obj = obj
99
end
10+
1011
# Get raw hash response
1112
# @return [Hash]
1213
attr_reader :obj
1314

1415
alias raw obj
15-
1616
alias data obj
1717

1818
# The Total number of results

lib/topgg/stats.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ def initialize(obj)
77
@obj = obj
88
end
99

10-
# Returns raw Hash of the response
10+
# Get raw hash response
11+
# @return [Hash]
1112
attr_reader :obj
1213

1314
alias raw obj
14-
1515
alias data obj
16+
1617
# Returns the server Count of the bot
1718
# @return [Integer]
1819
def server_count

lib/topgg/user.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ def initialize(obj)
88
@obj = obj
99
end
1010

11+
# Get raw hash response
12+
# @return [Hash]
1113
attr_reader :obj
1214

1315
alias raw obj
14-
1516
alias data obj
17+
1618
# Check for errors, if any
1719
def error
1820
@obj["error"]

lib/topgg/vote.rb

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
module Dbl
2+
class Vote
3+
def initialize(obj)
4+
@obj = obj
5+
end
6+
7+
# Returns raw hash of the parsed json object
8+
# @return [Hash]
9+
attr_reader :obj
10+
11+
alias raw obj
12+
alias data obj
13+
14+
# Returns the ID of the Discord bot/server that received a vote.
15+
# @return [String]
16+
def receiver_id
17+
!@obj["bot"].nil? ? @obj["guild"] : @obj["bot"]
18+
end
19+
20+
# Returns the ID of the Top.gg user who voted.
21+
# @return [String]
22+
def voter_id
23+
@obj["user"]
24+
end
25+
26+
# Returns whether this vote is just a test done from the page settings.
27+
# @return [Boolean]
28+
def is_test
29+
@obj["type"] == "test"
30+
end
31+
32+
# Returns whether the weekend multiplier is active, where a single vote counts as two.
33+
# @return [Boolean]
34+
def is_weekend
35+
@obj["isWeekend"] == true
36+
end
37+
38+
# Returns query strings found on the vote page.
39+
# @return [Hash<String, String>]
40+
def query
41+
return nil if @obj["query"].nil?
42+
43+
CGI.parse(@obj["query"]).transform_values(&:first)
44+
end
45+
end
46+
end

lib/topgg/webhooks.rb

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
require "rack"
2+
require "cgi"
3+
4+
require_relative "vote"
5+
6+
module Dbl
7+
class Webhook
8+
VOTE = ->(json) { Vote.new(json) }
9+
10+
def initialize(app, type:, path:, auth:, &callback)
11+
raise ArgumentError, "A callback must be provided" unless callback
12+
raise ArgumentError, "A type must be provided" unless type.respond_to?(:call)
13+
14+
@app = app
15+
@deserializer = type
16+
@path = path
17+
@auth = auth
18+
@callback = callback
19+
end
20+
21+
def call(env)
22+
req = Rack::Request.new(env)
23+
24+
if req.post? && req.path.start_with?(@path)
25+
if req.get_header('HTTP_AUTHORIZATION') != @auth
26+
return [401, { 'Content-Type' => 'text/plain' }, ['Unauthorized']]
27+
end
28+
29+
body = req.body.read
30+
31+
begin
32+
data = JSON.parse(body)
33+
34+
@callback.call(@deserializer.call(data)) if data
35+
36+
return [204, { 'Content-Type' => 'text/plain' }, ['']]
37+
rescue JSON::ParserError
38+
return [400, { 'Content-Type' => 'text/plain' }, ['Bad request']]
39+
end
40+
end
41+
42+
@app.call(env)
43+
end
44+
end
45+
end

0 commit comments

Comments
 (0)