diff --git a/.gitignore b/.gitignore index 06de90a..b81217d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.bundle \ No newline at end of file +.bundle +*.gem \ No newline at end of file diff --git a/Gemfile b/Gemfile index f97a909..ed050f9 100644 --- a/Gemfile +++ b/Gemfile @@ -1,8 +1,11 @@ # frozen_string_literal: true -source 'https://rubygems.org' +source "https://rubygems.org" # Specify your gem's dependencies in topgg.gemspec gemspec -gem 'rake', '~> 13.0' +gem "rack" +gem "rake" +gem "ostruct" +gem "cgi" diff --git a/Gemfile.lock b/Gemfile.lock index f90d67a..87ef933 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,19 +1,27 @@ PATH remote: . specs: - topgg (1.1.0) + topgg (2.0.0) + rack (~> 3.0.9.1) GEM remote: https://rubygems.org/ specs: + cgi (0.5.0) + ostruct (0.6.1) + rack (3.0.9.1) rake (13.0.6) PLATFORMS + x64-mingw-ucrt x86_64-linux DEPENDENCIES - rake (~> 13.0) + cgi (~> 0.5.0) + ostruct + rack + rake topgg! BUNDLED WITH - 2.2.22 + 2.6.9 diff --git a/LICENSE b/LICENSE index 0b78562..68561e0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 rhydderchc +Copyright (c) 2021-2025 rhydderchc Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/LICENSE.txt b/LICENSE.txt index 420b77e..68561e0 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ -The MIT License (MIT) +MIT License -Copyright (c) 2021 TODO: Write your name +Copyright (c) 2021-2025 rhydderchc Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -9,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 26f3cce..19935aa 100644 --- a/README.md +++ b/README.md @@ -1,57 +1,159 @@ -# [Top.gg](https://top.gg) Ruby +# Top.gg Ruby SDK -The Top.gg Ruby SDK is a lighweight package, that allows you -to fetch data from the top.gg api and post data such as statistics to the website. +The community-maintained Ruby library for Top.gg. -It provides you with numerous methods to interact with the API. -## Dependencies +## Installation -* Ruby +```sh +$ gem install topgg +``` -## Installation +## Setting up -``` bash +```rb +require "topgg" -gem install topgg +client = Topgg.new(ENV["TOPGG_TOKEN"]) +``` +## Usage + +### Getting a bot + +```rb +bot = client.get_bot("264811613708746752") ``` -## Note -You require a Token to interact with the Api. -The token can be found at `https://top.gg/bot/[YOUR_BOT_ID]/webhooks` +### Getting several bots -## Example +```rb +bots = client.get_bots({ sort: "date", limit: 50, offset: 0 }) -Here's a straightforward example of how to request data with the wrapper. +for bot in bots.results do + puts bot.username +end +``` -```ruby -require 'topgg' +### Getting your bot's voters -client = Topgg.new("AUTH_TOKEN", "BOTID") +#### First page -client.get_bot("1234").defAvatar -# returns -# "6debd47ed13483642cf09e832ed0bc1b" +```rb +voters = client.get_voters +for voter in voters.results do + puts voter.username +end ``` -### Auto Posting -The library provides you with autoposting functionality, and autoposts at an interval of 30 minutes. -Here's how you can use it +#### Subsequent pages + +```rb +voters = client.get_voters(2) -```ruby -require 'topgg' -require 'discordrb' +for voter in voters.results do + puts voter.username +end +``` -bot = Discordrb::Bot.new token: "TOKEN" +### Check if a user has voted for your bot -client = Topgg.new("AUTH_TOKEN", "BOTID") - bot.ready do |event| - client.auto_post_stats(bot) # The discordrb bot client. +```rb +has_voted = client.voted?("661200758510977084") +``` + +### Getting your bot's server count + +```rb +server_count = client.get_server_count +``` + +### Posting your bot's server count + +```rb +client.post_server_count(bot.server_count) +``` + +### Automatically posting your bot's server count every few minutes + +For Discordrb: + +```rb +require "discordrb" + +bot = Discordrb::Bot.new(token: env["BOT_TOKEN"], intents: [:servers]) + +bot.ready do |event| + client.auto_post_stats(bot) + + puts "Bot is now ready!" end + bot.run ``` -# Documentation +### Checking if the weekend vote multiplier is active -Check out the api reference [here](https://rubydoc.info/gems/topgg/) +```rb +is_weekend = client.is_weekend? +``` + +### Generating widget URLs + +#### Large + +```rb +widget_url = Dbl::Widget.large(:discord_bot, "574652751745777665") +``` + +#### Votes + +```rb +widget_url = Dbl::Widget.votes(:discord_bot, "574652751745777665") +``` + +#### Owner + +```rb +widget_url = Dbl::Widget.owner(:discord_bot, "574652751745777665") +``` + +#### Social + +```rb +widget_url = Dbl::Widget.social(:discord_bot, "574652751745777665") +``` + +### Webhooks + +#### Being notified whenever someone voted for your bot + +##### Ruby on Rails + +In your `config/application.rb`: + +```rb +module MyServer + class Application < Rails::Application + # ... + + config.middleware.use Dbl::Webhook, + type: Dbl::Webhook::VOTE, + path: "/votes", + auth: ENV["MY_TOPGG_WEBHOOK_SECRET"] do |vote| + Rails.logger.info "A user with the ID of #{vote.voter_id} has voted us on Top.gg!" + end + end +end +``` + +##### Sinatra + +```rb +use Dbl::Webhook, +type: Dbl::Webhook::VOTE, +path: "/votes", +auth: ENV["MY_TOPGG_WEBHOOK_SECRET"] do |vote| + puts "A user with the ID of #{vote.voter_id} has voted us on Top.gg!" +end +``` \ No newline at end of file diff --git a/lib/lib.rb b/lib/lib.rb deleted file mode 100644 index 4bf0263..0000000 --- a/lib/lib.rb +++ /dev/null @@ -1,120 +0,0 @@ -# frozen_string_literal: true - -require_relative 'topgg/utils/request' -require 'json' -require_relative 'topgg/bot' -require_relative 'topgg/botSearch' -require_relative 'topgg/user' -require_relative 'topgg/stats' -require_relative 'topgg/votes' -# Class Topgg -# The class instantiates all the methods for api requests and posts. -class Topgg - # initializes the class attributes. - # @param token [String] The authorization token from top.gg - # @param id [String] The client id of the bot. - def initialize(token, id) - @id = id - @token = token - @request = Dbl::Utils::Request.new(token) - end - - # The method fetches bot statistics from top.gg - # @param id [String] The id of the bot you want to fetch statistics from. - # @return [Dbl::Bot] The Bot Object - def get_bot(id) - resp = @request.get("bots/#{id}") - - Dbl::Bot.new(resp) - end - - # The method searches bots from top.gg using a keyword query. - # @param [Object] params The parameters that can be used to query a search - # To know what the parameters are check it out here - # @return [Dbl::BotSearch] The BotSearch Object - def search_bot(params) - resp = @request.get('bots/search', params) - Dbl::BotSearch.new(resp) - end - - # Search for a user on top.gg with id - # @param id [String] The id of the user to search for. - # @return [Dbl::User] - def user(id) - resp = @request.get("users/#{id}") - - Dbl::User.new(resp) - end - - # Get Bot statistics. - # @param id [String] Id of the bot you want to get statistics of - # @return [Dbl::Stats] - def get_stats(id) - resp = @request.get("bots/#{id}/stats") - - Dbl::Stats.new(resp) - end - - # Mini-method to query if the bot(self) was voted by the user. - # @param userid [String] The user id. - # @return [Boolean] - def voted?(userid) - resp = @request.get("bots/#{@id}/check", { userId: userid }) - - ret = resp - ret['voted'] == 1 - end - - # Get the Last 1000 votes of the bot(self) - # @return [Dbl::Votes] - def votes - resp = @request.get("bots/#{@id}/votes") - - Dbl::Votes.new(resp) - end - - # Post Bot Statistics to the website - # @param server_count [Integer] The amount of servers the bot is in. - # @param shards [Integer] The amount of servers the bot is in per shard - # @param shard_count [Integer] The total number of shards. - def post_stats(server_count, shards: nil, shard_count: nil) - json_post = { - server_count: server_count, - shards: shards, - shard_count: shard_count - }.to_json - @request.post("bots/#{@id}/stats", json_post, { 'Content-Type' => 'application/json' }) - end - - # Auto-posts stats on to the top.gg website - # @param client [Discordrb::Bot] instanceof discordrb client. - def auto_post_stats(client) - semaphore = Mutex.new - Thread.new do - semaphore.synchronize do - interval 1800 do - server_len = client.servers.length - post_stats(server_len) - print("[TOPGG] : \033[31;1;4m Bot statistics has been successfully posted!\033[0m") - end - end - end - end - - # Mini-method to get statistics on self - # @return [get_bot] - def self - get_bot(@id) - end - - def interval(seconds) - loop do - yield - sleep seconds - end - end -end - - - - diff --git a/lib/topgg.rb b/lib/topgg.rb new file mode 100644 index 0000000..b2659b8 --- /dev/null +++ b/lib/topgg.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +require "base64" +require "json" + +require_relative "topgg/bot" +require_relative "topgg/botSearch" +require_relative "topgg/user" +require_relative "topgg/vote" +require_relative "topgg/votes" +require_relative "topgg/webhooks" +require_relative "topgg/widget" +require_relative "topgg/utils/request" + +# Class Topgg +# The class instantiates all the methods for api requests and posts. +class Topgg + # initializes the class attributes. + # @param token [String] The authorization token from top.gg + def initialize(token) + begin + token_section = token.split('.')[1] + padding = '=' * ((4 - token_section.length % 4) % 4) + token_section += padding + + token_data = JSON.parse(Base64.decode64(token_section)) + + @id = token_data['id'] + rescue StandardError + raise ArgumentError, 'Got a malformed API token.' + end + + @token = token + @request = Dbl::Utils::Request.new(token) + end + + # The method fetches bot statistics from top.gg + # @param id [String] The id of the bot you want to fetch statistics from. + # @return [Dbl::Bot] The Bot Object + def get_bot(id) + Dbl::Bot.new(@request.get("bots/#{id}")) + end + + # The method searches bots from top.gg using a keyword query. + # @param [Object] params The parameters that can be used to query a search + # To know what the parameters are check it out here + # @return [Dbl::BotSearch] The BotSearch Object + def get_bots(params) + Dbl::BotSearch.new(@request.get("bots", params)) + end + + # The method fetches your Discord bot's posted server count. + # @return [Integer] + def get_server_count + resp = @request.get("bots/stats") + resp["server_count"] + end + + # Mini-method to query if the bot(self) was voted by the user. + # @param userid [String] The user id. + # @return [Boolean] + def voted?(userid) + resp = @request.get("bots/check", { userId: userid }) + resp["voted"] == 1 + end + + # Checks if the weekend multiplier is active, where a single vote counts as two. + # @return [Boolean] + def is_weekend? + resp = @request.get("weekend") + resp["is_weekend"] + end + + # Get the last 1000 unique votes of the bot(self) + # @param page [Integer] The page to use. Defaults to 1. + # @return [Dbl::Votes] + def get_votes(page = 1) + page = 1 if page.to_i < 1 + resp = @request.get("bots/#{@id}/votes", { page: page }) + + Dbl::Votes.new(resp) + end + + # The method posts your Discord bot's server count to the API. This will update the server count in your bot's Top.gg page. + # @param server_count [Integer] The amount of servers the bot is in. Must not be less than 1. + def post_server_count(server_count) + raise ArgumentError, "server_count cannot be less than 1" unless server_count > 0 + + json_post = { server_count: server_count }.to_json + @request.post( + "bots/stats", + json_post + ) + end + + # Auto-posts stats on to the top.gg website + # @param client [Discordrb::Bot] instanceof discordrb client. + def auto_post_stats(client) + semaphore = Mutex.new + Thread.new do + semaphore.synchronize do + interval 900 do + server_len = client.servers.length + post_server_count(server_len) + puts( + "[TOPGG] : \033[31;1;4m Bot statistics has been successfully posted!\033[0m" + ) + end + end + end + end + + # Mini-method to get statistics on self + # @return [get_bot] + def self + get_bot(@id) + end + + def interval(seconds) + loop do + yield + sleep seconds + end + end +end diff --git a/lib/topgg/bot.rb b/lib/topgg/bot.rb index f0bad3d..58060fe 100644 --- a/lib/topgg/bot.rb +++ b/lib/topgg/bot.rb @@ -1,3 +1,5 @@ +require "date" + module Dbl # The Bot class spreads the json parsed hash into different methods class Bot @@ -6,173 +8,132 @@ class Bot def initialize(obj) @obj = obj end + # Returns raw hash of the parsed json object # @return [Hash] attr_reader :obj - alias :raw :obj - + alias raw obj alias data obj - # Returns error message, if there's an error - # @return [String] - def error - @obj['error'].to_str - end - # Returns the default Avatar of the client + # Returns error message if there's an error, otherwise nil # @return [String] - def defAvatar - @obj['defAvatar'].to_str + def error + @obj["error"] end # Returns the invite link of the bot # @return [String] def invite - @obj['invite'].to_str + @obj["invite"] end # Returns the bot website, if configured # @return [String] def website - @obj['website'].to_str + @obj["website"] end # Returns support server link # @return [String] def support - "https://discord.gg/#{@obj['support']}" + @obj["support"] end # Returns github repository link, if any # @return [String] def github - @obj['github'].to_str + @obj["github"] end # Returns the long Description of the bot # @return [String] def longdesc - @obj['longdesc'].to_str + @obj["longdesc"] end # Returns the short description of the bot # @return [String] def shortdesc - @obj['shortdesc'].to_str + @obj["shortdesc"] end # Returns the default prefix of the bot # @return [String] def prefix - @obj['prefix'].to_str - end - - # Returns the bot library - # @return [String] - def lib - @obj['lib'].to_str + @obj["prefix"] end # Returns the bot client id # @return [String] def clientid - @obj['clientid'].to_str + @obj["clientid"] end # Returns the avatar link of the bot # @return [String] def avatar - "https://cdn.discordapp.com/avatars/#{@obj['id']}/#{@obj['avatar']}.webp?size=1024" + @obj["avatar"] end # Returns the bot id # @return [String] def id - @obj['id'].to_str - end - - # Returns the bot descriminator - # @return [String] - def descriminator - @obj['descriminator'].to_str + @obj["id"] end # Returns the bot username # @return [String] def username - @obj['username'].to_str + @obj["username"] end # Returns the date on which the bot was submitted # @return [Date] def date - Date.parse(@obj['date']) + Date.parse(@obj["date"]) end # Returns the server count of the bot # @return [Integer] def server_count - @obj['server_count'].to_i - end - - # Returns the amount of shards - # @return [String] - def shard_count - @obj['shard_count'].to_str - end - - # Returns configured guilds in which the bot is in - # @return [String] - def guilds - @obj['guilds'].to_str - end - - # Returns the amount of guilds per shard of the bot - # @return [String] - def shards - @obj['shards'].to_str + @obj["server_count"].to_i end - # Returns the monthyPoints of the bot - # @return [String] + # Returns the monthly vote count of the bot + # @return [Integer] def monthlyPoints - @obj['monthlyPoints'].to_str + @obj["monthlyPoints"].to_i end # Returns the total points of the bot - # @return [String] + # @return [Integer] def points - @obj['points'].to_str + @obj["points"].to_i end - # Returns true/false depending on if the bot is certified or not - # @return [Boolean] - def certifiedBot - @obj['certifiedBot'].to_str + # Returns the Top.gg vanity URL code, can be nil + # @return [String] + def vanity + @obj["vanity"] end # Returns the owner ids # @return [Array] def owners - @obj['owners'].to_str + @obj["owners"] end # Return the bot tags # @return [Array] def tags - @obj['tags'].to_str + @obj["tags"] end - # Returns the bot banner url - # @return [String] - def bannerUrl - @obj['bannerUrl'].to_str - end - - # Returns the donate bot guild ID - # @return [String] - def donatebotguildid - @obj['donatebotguildid'].to_str + # Returns an object containing the bot's reviews information. + # @return [Object] + def reviews + @obj["reviews"] end end end diff --git a/lib/topgg/botSearch.rb b/lib/topgg/botSearch.rb index 97b3ce8..43d2225 100644 --- a/lib/topgg/botSearch.rb +++ b/lib/topgg/botSearch.rb @@ -7,48 +7,60 @@ class BotSearch def initialize(obj) @obj = obj end + # Get raw hash response # @return [Hash] attr_reader :obj - - alias raw obj + alias raw obj alias data obj # The Total number of results # @return [Integer] def total - @obj['total'].to_i + @obj["total"].to_i end - # The first result - # @return [Spreader::Bot] + # The first result, can be nil + # @return [Bot] def first - Spreader::Bot.new(@obj['results'][0]) + results = @obj["results"] + + if results.empty? + nil + else + Bot.new(results[0]) + end end # The number of bots shown in the first page # @return [Integer] def count - @obj['count'].to_i + @obj["count"].to_i end - # Iterates through the results - # @return [Array] - def results - arr = [] - flag = 0 # iteration flag - @obj['results'].each do |data| - arr[flag] = Spreader::Bot.new(data) - flag += 1 + # The number of bots skipped, can be nil + # @return [Integer] + def offset + offset = @obj["offset"] + + if offset.nil? + nil + else + offset.to_i end - arr + end + + # Returns the results array + # @return [Array] + def results + @obj["results"].map { |b| Bot.new(b) } end # Length of the results. # @return [Integer] def size - @obj['results'].length + @obj["results"].length end end end diff --git a/lib/topgg/stats.rb b/lib/topgg/stats.rb deleted file mode 100644 index 7504821..0000000 --- a/lib/topgg/stats.rb +++ /dev/null @@ -1,34 +0,0 @@ -module Dbl - # The Stats class spreads the json response into different methods - class Stats - # Initializes the Stats class - # @param obj [Object] Response Hash - def initialize(obj) - @obj = obj - end - - # Returns raw Hash of the response - attr_reader :obj - - alias raw obj - - alias data obj - # Returns the server Count of the bot - # @return [Integer] - def server_count - @obj['server_count'] - end - - # The amount of servers per shard - # @return [Integer] - def shards - @obj['shards'] - end - - # Returns the total number of shards - # @return [Integer] - def shard_count - @obj['shard_count'] - end - end -end diff --git a/lib/topgg/user.rb b/lib/topgg/user.rb index a5bf680..d8463e8 100644 --- a/lib/topgg/user.rb +++ b/lib/topgg/user.rb @@ -8,72 +8,32 @@ def initialize(obj) @obj = obj end + # Get raw hash response + # @return [Hash] attr_reader :obj alias raw obj - alias data obj + # Check for errors, if any def error - @obj['error'] + @obj["error"] end # The Id of the user def id - @obj['id'] + @obj["id"] end # The username of the user def username - @obj['username'] + @obj["username"] end # The avatar of the user # @return [String] def avatar - "https://cdn.discordapp.com/avatars/#{@obj['id']}/#{@obj['avatar']}.webp?size=1024" - end - - # The default avatar of the user - # @return [String] - def defAvatar - @obj['defAvatar'] - end - - # Returns true/false depending upon if the user is a moderator or not. - # @return [Boolean] - def mod - @obj['mod'] - end - - # Returns true/false depending upon if the user is a supporter or not. - # @return [Boolean] - def supporter - @obj['supporter'] - end - - # Returns true/false depending upon if the user is a certified developer or not. - # @return [Boolean] - def certifiedDev - @obj['certifiedDev'] - end - - # Returns an object containing all user social integrations. - # @return [Object] - def social - @obj['social'] - end - - # Returns true/false depending on weather the user is an admin or not. - # @return [Boolean] - def admin - @obj['admin'] - end - - # Returns true/false depending on weather the user is a website Moderator or not. - # @return [Boolean] - def webMod - @obj['webMod'] + @obj["avatar"] end end end diff --git a/lib/topgg/utils/request.rb b/lib/topgg/utils/request.rb index 916910f..89e5e1a 100644 --- a/lib/topgg/utils/request.rb +++ b/lib/topgg/utils/request.rb @@ -1,43 +1,51 @@ -require 'net/http' -require 'json' - -module Dbl - module Utils - class Request - def initialize(token) - @token = token - @url = "https://top.gg/api" - end - - - def get(params) - - uri = URI.parse(@url+"/#{params}") +require "net/http" +require "json" + +module Dbl + module Utils + class Request + def initialize(token) + @token = token + @url = "https://top.gg/api/v1" + end + + def get(params, query=nil) + uri = URI.parse(@url + "/#{params}") + + if not query.nil? + uri.query = URI.encode_www_form(query) + end + http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Get.new(uri.request_uri) - request.add_field 'Authorization', @token + request.add_field "Authorization", @token response = http.request(request) JSON.parse(response.body) - end - - def post(params, data) - + end - uri = URI.parse(@url+"/#{params}") - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = true - http.verify_mode = OpenSSL::SSL::VERIFY_NONE + def post(params, data) + uri = URI.parse(@url + "/#{params}") + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = true + http.verify_mode = OpenSSL::SSL::VERIFY_NONE - request = Net::HTTP::Post.new(uri.request_uri, initheader = {'Content-Type' =>'application/json', 'Authorization' => @token}) - request.body = data.to_json + request = + Net::HTTP::Post.new( + uri.request_uri, + initheader = { + "Content-Type" => "application/json", + "Authorization" => @token + } + ) + request.body = data.to_json - response = http.request(request) - JSON.parse(response.body) - end -end + response = http.request(request) + JSON.parse(response.body) + end + end + end end -end \ No newline at end of file diff --git a/lib/topgg/vote.rb b/lib/topgg/vote.rb new file mode 100644 index 0000000..db8c69d --- /dev/null +++ b/lib/topgg/vote.rb @@ -0,0 +1,46 @@ +module Dbl + class Vote + def initialize(obj) + @obj = obj + end + + # Returns raw hash of the parsed json object + # @return [Hash] + attr_reader :obj + + alias raw obj + alias data obj + + # Returns the ID of the Discord bot/server that received a vote. + # @return [String] + def receiver_id + !@obj["bot"].nil? ? @obj["guild"] : @obj["bot"] + end + + # Returns the ID of the Top.gg user who voted. + # @return [String] + def voter_id + @obj["user"] + end + + # Returns whether this vote is just a test done from the page settings. + # @return [Boolean] + def is_test + @obj["type"] == "test" + end + + # Returns whether the weekend multiplier is active, where a single vote counts as two. + # @return [Boolean] + def is_weekend + @obj["isWeekend"] == true + end + + # Returns query strings found on the vote page. + # @return [Hash] + def query + return nil if @obj["query"].nil? + + CGI.parse(@obj["query"]).transform_values(&:first) + end + end +end \ No newline at end of file diff --git a/lib/topgg/votes.rb b/lib/topgg/votes.rb index c44c0cd..739452f 100644 --- a/lib/topgg/votes.rb +++ b/lib/topgg/votes.rb @@ -10,14 +10,24 @@ def initialize(obj) # Get raw hash return of the object # @return [Hash] attr_reader :obj - + alias raw obj alias data obj - # Get the first vote amongst all the other votes. - # @return [Spreader::User] + # Get the first vote amongst all the other votes, can be nil + # @return [User] def first - Spreader::User.new(@obj[0]) + if @obj.empty? + nil + else + User.new(@obj[0]) + end + end + + # Returns the results array + # @return [Array] + def results + @obj.map { |u| User.new(u) } end # Get the total number of votes @@ -26,4 +36,4 @@ def total @obj.length end end -end \ No newline at end of file +end diff --git a/lib/topgg/webhooks.rb b/lib/topgg/webhooks.rb new file mode 100644 index 0000000..dc7f6b8 --- /dev/null +++ b/lib/topgg/webhooks.rb @@ -0,0 +1,45 @@ +require "rack" +require "cgi" + +require_relative "vote" + +module Dbl + class Webhook + VOTE = ->(json) { Vote.new(json) } + + def initialize(app, type:, path:, auth:, &callback) + raise ArgumentError, "A callback must be provided" unless callback + raise ArgumentError, "A type must be provided" unless type.respond_to?(:call) + + @app = app + @deserializer = type + @path = path + @auth = auth + @callback = callback + end + + def call(env) + req = Rack::Request.new(env) + + if req.post? && req.path.start_with?(@path) + if req.get_header('HTTP_AUTHORIZATION') != @auth + return [401, { 'Content-Type' => 'text/plain' }, ['Unauthorized']] + end + + body = req.body.read + + begin + data = JSON.parse(body) + + @callback.call(@deserializer.call(data)) if data + + return [204, { 'Content-Type' => 'text/plain' }, ['']] + rescue JSON::ParserError + return [400, { 'Content-Type' => 'text/plain' }, ['Bad request']] + end + end + + @app.call(env) + end + end +end \ No newline at end of file diff --git a/lib/topgg/widget.rb b/lib/topgg/widget.rb new file mode 100644 index 0000000..6268083 --- /dev/null +++ b/lib/topgg/widget.rb @@ -0,0 +1,52 @@ +module Dbl + # Widget generator functions. + class Widget + @base_url = "https://top.gg/api/v1" + + class << self + attr_accessor :base_url + + TYPES = [:discord_bot, :discord_server] + + # Generates a large widget URL. + # @param ty [Symbol] The widget type. + # @param id [String] The ID. + def large(ty, id) + raise ArgumentError, "Invalid widget type" unless TYPES.include?(ty) + type = ty.to_s.gsub('_', '/') + + "#{@base_url}/widgets/large/#{type}/#{id}" + end + + # Generates a small widget URL for displaying votes. + # @param ty [Symbol] The widget type. + # @param id [String] The ID. + def votes(ty, id) + raise ArgumentError, "Invalid widget type" unless TYPES.include?(ty) + type = ty.to_s.gsub('_', '/') + + "#{@base_url}/widgets/small/votes/#{type}/#{id}" + end + + # Generates a small widget URL for displaying an entity's owner. + # @param ty [Symbol] The widget type. + # @param id [String] The ID. + def owner(ty, id) + raise ArgumentError, "Invalid widget type" unless TYPES.include?(ty) + type = ty.to_s.gsub('_', '/') + + "#{@base_url}/widgets/small/owner/#{type}/#{id}" + end + + # Generates a small widget URL for displaying social stats. + # @param ty [Symbol] The widget type. + # @param id [String] The ID. + def social(ty, id) + raise ArgumentError, "Invalid widget type" unless TYPES.include?(ty) + type = ty.to_s.gsub('_', '/') + + "#{@base_url}/widgets/small/social/#{type}/#{id}" + end + end + end +end \ No newline at end of file diff --git a/topgg.gemspec b/topgg.gemspec index 795f39d..9f59e0a 100644 --- a/topgg.gemspec +++ b/topgg.gemspec @@ -1,31 +1,24 @@ # frozen_string_literal: true Gem::Specification.new do |spec| - spec.name = 'topgg' - spec.version = '1.1.0' - spec.authors = ['Adonis Tremblay'] - spec.email = ['rhydderchc@gmail.com'] + spec.name = "topgg" + spec.version = "2.0.0" + spec.authors = ["Adonis Tremblay"] + spec.email = ["rhydderchc@gmail.com"] - spec.summary = 'A top.gg api wrapper for ruby.' - spec.description = 'This is a ruby library of the top.gg API.' - spec.homepage = 'https://github.com/rhydderchc/topgg-ruby' - spec.license = 'MIT' - spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0') + spec.summary = "A top.gg api wrapper for ruby." + spec.description = "This is a ruby library of the top.gg API." + spec.homepage = "https://github.com/Top-gg-Community/ruby-sdk" + spec.license = "MIT" + spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0") - spec.metadata['allowed_push_host'] = "https://rubygems.org" + spec.metadata["allowed_push_host"] = "https://rubygems.org" + spec.metadata["homepage_uri"] = spec.homepage - spec.metadata['homepage_uri'] = spec.homepage - spec.metadata['source_code_uri'] = 'https://github.com/rhydderchc/topgg-ruby' - spec.metadata['changelog_uri'] = 'https://github.com/rhydderchc/CHANGELOG.md' - - # Specify which files should be added to the gem when it is released. - # The `git ls-files -z` loads the files in the RubyGem that have been added into git. - spec.files = Dir.chdir(File.expand_path(__dir__)) do - `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) } - end - spec.bindir = 'exe' - spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } - spec.require_paths = ['lib'] + spec.files = Dir.glob("lib/**/*") + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] # Uncomment to register a new dependency of your gem # spec.add_dependency "example-gem", "~> 1.0"