diff --git a/README.md b/README.md
index d372951..17f6513 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,242 @@
-# TopPHP
-A Top.gg API wrapper written in PHP 8.
+# Top.gg PHP SDK
-## Documentation
-See [here](https://docs.top.gg/libraries/php/) for the official information.
+The community-maintained PHP library for Top.gg.
+
+## Chapters
+
+- [Installation](#installation)
+- [Setting up](#setting-up)
+- [Usage](#usage)
+ - [API v1](#api-v1-1)
+ - [Getting your project's vote information of a user](#getting-your-projects-vote-information-of-a-user)
+ - [Posting your bot's application commands list](#posting-your-bots-application-commands-list)
+ - [API v0](#api-v0-1)
+ - [Getting a bot](#getting-a-bot)
+ - [Getting several bots](#getting-several-bots)
+ - [Getting your project's voters](#getting-your-projects-voters)
+ - [Check if a user has voted for your project](#check-if-a-user-has-voted-for-your-project)
+ - [Getting your bot's statistics](#getting-your-bots-statistics)
+ - [Posting your bot's statistics](#posting-your-bots-statistics)
+ - [Automatically posting your bot's statistics every few minutes](#automatically-posting-your-bots-statistics-every-few-minutes)
+ - [Checking if the weekend vote multiplier is active](#checking-if-the-weekend-vote-multiplier-is-active)
+ - [Generating widget URLs](#generating-widget-urls)
+ - [Webhooks](#webhooks)
+ - [Being notified whenever someone voted for your project](#being-notified-whenever-someone-voted-for-your-project)
## Installation
-TopPHP uses composer to download. In order to install the library, use the following line:
-`composer require top-gg/php-sdk`
+```sh
+$ composer require top-gg/php-sdk
+```
+
+## Setting up
+
+### API v1
+
+> **NOTE**: API v1 also includes API v0.
+
+```php
+include_once __DIR__ . "/vendor/autoload.php";
+
+use DBL\V1DBL;
+
+$client = new V1DBL([
+ "token" => "Top.gg API token"
+]);
+```
+
+### API v0
+
+```php
+include_once __DIR__ . "/vendor/autoload.php";
+
+use DBL\DBL;
+
+$client = new DBL([
+ "token" => "Top.gg API token"
+]);
+```
+
+## Usage
+
+### API v1
+
+#### Getting your project's vote information of a user
+
+```php
+$vote = $client->get_vote(661200758510977084);
+```
+
+#### Posting your bot's application commands list
+
+```php
+$client->post_commands([
+ [
+ "options" => [],
+ "name" => "test",
+ "name_localizations" => null,
+ "description" => "command description",
+ "description_localizations" => null,
+ "contexts" => [],
+ "default_permission" => null,
+ "default_member_permissions" => null,
+ "dm_permission" => false,
+ "integration_types" => [],
+ "nsfw" => false
+ ]
+]);
+```
+
+### API v0
+
+#### Getting a bot
+
+```php
+$bot = $client->get_bot(1026525568344264724);
+```
+
+#### Getting several bots
+
+```php
+// Limit Offset Sort by
+$bots = $client->get_bots(50, 0, "monthlyPoints");
+```
+
+#### Getting your project's voters
+
+##### First page
+
+```php
+$voters = $client->get_votes();
+```
+
+##### Subsequent pages
+
+```php
+// Bot ID (unused) Page number
+$voters = $client->get_votes(0, 2);
+```
+
+#### Check if a user has voted for your project
+
+```php
+// Bot ID (unused) User ID
+$has_voted = $client->get_user_vote(0, 661200758510977084);
+```
+
+#### Getting your bot's statistics
+
+```php
+$stats = $client->get_stats();
+```
+
+#### Posting your bot's statistics
+
+```php
+$client->post_stats(0, [
+ "server_count" => $bot->get_server_count()
+]);
+```
+
+#### Automatically posting your bot's statistics every few minutes
+
+> **NOTE**: Considering PHP's shortcomings, this is only possible via a URL.
+
+In your original client declaration:
+
+```php
+$client = new DBL([
+ "token" => "Insert your Top.gg API token here.",
+ "auto_stats" => [
+ "url": "Your URL",
+ "callback": => function () use ($bot) {
+ return [
+ "server_count" => $bot->get_server_count()
+ ];
+ }
+ ]
+]);
+```
+
+#### Checking if the weekend vote multiplier is active
+
+```php
+$is_weekend = $client->is_weekend();
+```
+
+#### Generating widget URLs
+
+##### Large
+
+```php
+use DBL\Widget;
+use DBL\WidgetType;
+
+$widget_url = Widget::large(WidgetType::DiscordBot, 574652751745777665);
+```
+
+##### Votes
+
+```php
+use DBL\Widget;
+use DBL\WidgetType;
+
+$widget_url = Widget::votes(WidgetType::DiscordBot, 574652751745777665);
+```
+
+##### Owner
+
+```php
+use DBL\Widget;
+use DBL\WidgetType;
+
+$widget_url = Widget::owner(WidgetType::DiscordBot, 574652751745777665);
+```
+
+##### Social
+
+```php
+use DBL\Widget;
+use DBL\WidgetType;
+
+$widget_url = Widget::social(WidgetType::DiscordBot, 574652751745777665);
+```
+
+### Webhooks
+
+#### Being notified whenever someone voted for your project
+
+**With Laravel:**
+
+In your `config/logging.php`:
+
+```php
+"channels" => [
+ "stdout" => [
+ "driver" => "single",
+ "path" => "php://stdout",
+ "level" => "debug"
+ ]
+]
+```
+
+In your `routes/api.php`:
+
+```php
+use DBL\Webhook;
-## Features
+use Illuminate\Support\Facades\Route;
+use Illuminate\Support\Facades\Log;
-* Working GET and POST requests.
-* Enumerable constants for HTTP search lookups.
-* Flexible namespaces and interfaces for easily editing.
-* Up-to-standard package following the latest PSR.
-* Automatic bot statistics POST requests. (Shards, guilds)
+class MyVoteListener extends Webhook {
+ public function getAuthorization() {
+ return getenv("MY_TOPGG_WEBHOOK_SECRET");
+ }
-## Coming Soon
+ public function callback(array $vote) {
+ Log::channel("stdout")->info("A user with the ID of " . $vote["user"] . " has voted us on Top.gg!");
+ }
+}
-* Webhooks
-* Forced library global rate-limiting.
+Route::post('/votes', [MyVoteListener::class, "main"]);
+```
diff --git a/composer.json b/composer.json
index 9a9ac10..930aed9 100644
--- a/composer.json
+++ b/composer.json
@@ -3,7 +3,9 @@
"description": "The official Top.gg PHP API wrapper.",
"license": "MIT",
"require": {
- "php": "^7.3|^8.0"
+ "php": "^7.3|^8.0",
+ "illuminate/routing": "^12.19",
+ "illuminate/http": "^12.19"
},
"authors": [
{
diff --git a/main.php b/main.php
index ab78619..395f293 100644
--- a/main.php
+++ b/main.php
@@ -18,12 +18,61 @@
*/
include_once __DIR__ . "/vendor/autoload.php";
-use DBL\DBL;
-use DBL\API\Http;
+use DBL\V1DBL;
$token = @file_get_contents(".TOKEN");
-$api = new DBL([
+$client = new V1DBL([
"token" => $token
]);
+echo "\nrunning get bot:\n";
+$bot = $client->get_bot(1026525568344264724);
+print_r($bot);
+
+echo "\nrunning get bots:\n";
+$bots = $client->get_bots();
+print_r($bots);
+
+echo "\nrunning get votes:\n";
+$voters = $client->get_votes();
+print_r($voters);
+
+echo "\nrunning get user vote:\n";
+$has_voted = $client->get_user_vote(0, 661200758510977084);
+print_r($has_voted);
+
+echo "\nrunning get stats:\n";
+$stats = $client->get_stats();
+print_r($stats);
+
+echo "\nrunning post stats:\n";
+$client->post_stats(0, [
+ "server_count" => 2
+]);
+
+echo "\nrunning is weekend:\n";
+$is_weekend = $client->is_weekend();
+print_r($is_weekend);
+
+echo "\nrunning post commands:\n";
+$client->post_commands([
+ [
+ "options" => [],
+ "name" => "test",
+ "name_localizations" => null,
+ "description" => "command description",
+ "description_localizations" => null,
+ "contexts" => [],
+ "default_permission" => null,
+ "default_member_permissions" => null,
+ "dm_permission" => false,
+ "integration_types" => [],
+ "nsfw" => false
+ ]
+]);
+
+echo "\nrunning get vote:\n";
+$vote = $client->get_vote(661200758510977084);
+print_r($vote);
+
?>
diff --git a/src/TopPHP/API/Exceptions/GlobalRatelimitException.php b/src/TopPHP/API/Exceptions/GlobalRatelimitException.php
deleted file mode 100644
index b22e98b..0000000
--- a/src/TopPHP/API/Exceptions/GlobalRatelimitException.php
+++ /dev/null
@@ -1,51 +0,0 @@
-message = "You have encountered a global ratelimit. Please refer to the JSON contents for your remaining time.";
-
- switch($type)
- {
- case self::THROW_NONE:
- break;
-
- default:
- die($this->message);
- break;
- }
- }
-}
-
-?>
diff --git a/src/TopPHP/API/Exceptions/MissingStatsException.php b/src/TopPHP/API/Exceptions/MissingStatsException.php
deleted file mode 100644
index 58d6237..0000000
--- a/src/TopPHP/API/Exceptions/MissingStatsException.php
+++ /dev/null
@@ -1,52 +0,0 @@
-message = "The API could not make a successful connection due to missing value(s). (Check for valid value?)";
-
- switch($type)
- {
- case self::THROW_NONE:
- break;
-
- default:
- die($this->message);
- break;
- }
- }
-}
-
-?>
diff --git a/src/TopPHP/API/Exceptions/MissingTokenException.php b/src/TopPHP/API/Exceptions/MissingTokenException.php
index 194f7ac..7cbbade 100644
--- a/src/TopPHP/API/Exceptions/MissingTokenException.php
+++ b/src/TopPHP/API/Exceptions/MissingTokenException.php
@@ -17,34 +17,19 @@
* This allows for an exception to be made when
* the DBL class does not detect a token.
*/
-class MissingTokenException
+class MissingTokenException extends \Exception
{
/** @var mixed */
public $message;
- /** Special throwing rules. */
- public const THROW_NONE = 0;
- public const THROW_DEFAULT = 1;
-
/**
* Creates a MissingTokenException class.
- *
- * @param const|null $type The throwing type.
- * @return void
*/
- public function __construct($type = self::THROW_DEFAULT)
+ public function __construct()
{
$this->message = "The API could not make a successful connection due to a missing token. (Do you have a token path specified in the DBL class?)";
-
- switch($type)
- {
- case self::THROW_NONE:
- break;
-
- default:
- die($this->message);
- break;
- }
+
+ parent::__construct($this->message);
}
}
diff --git a/src/TopPHP/API/Exceptions/ResourceRatelimitException.php b/src/TopPHP/API/Exceptions/ResourceRatelimitException.php
index 7bde38d..1465c6a 100644
--- a/src/TopPHP/API/Exceptions/ResourceRatelimitException.php
+++ b/src/TopPHP/API/Exceptions/ResourceRatelimitException.php
@@ -17,35 +17,21 @@
* This allows for exceptions to be made when
* the HTTP hits a rate limit for a specific request.
*/
-class ResourceRatelimitException
+class ResourceRatelimitException extends \Exception
{
/** @var mixed */
public $message;
- /** Special throwing rules. */
- public const THROW_NONE = 0;
- public const THROW_DEFAULT = 1;
-
/**
* Creates a ResourceRatelimitException class.
*
* @param string $message The error message.
- * @param const|null $type The throwing type.
- * @return void
*/
- public function __construct(string $message, $type = self::THROW_DEFAULT)
+ public function __construct(string $message)
{
- $this->message = $message;
+ parent::__construct($message);
- switch($type)
- {
- case self::THROW_NONE:
- break;
-
- default:
- die($this->message);
- break;
- }
+ $this->message = $message;
}
}
diff --git a/src/TopPHP/API/Http.php b/src/TopPHP/API/Http.php
index 19f7be2..3cf1b23 100644
--- a/src/TopPHP/API/Http.php
+++ b/src/TopPHP/API/Http.php
@@ -11,7 +11,9 @@
*/
namespace DBL\API;
+
use DBL\Structs\HttpStruct;
+use DBL\API\Exceptions\ResourceRatelimitException;
/**
* Represents the HTTP class for Top.gg.
@@ -51,8 +53,8 @@ public function __construct(string $http, int $port = 80)
* Has to meet with the constants of currently
* accepted HTTP requests compatible with the API.
*
- * @param string $type The HTTP request you're using.
- * @param string $path The HTTP path you're calling.
+ * @param string $type The HTTP request you're using.
+ * @param string $path The HTTP path you're calling.
* @param array $payload Additional information you want to pass on as JSON.
* @return array
*/
@@ -91,8 +93,8 @@ public function call(string $type, string $path, array $payload = []): array
$_headers = ($_type) ? get_headers($path) : "400";
$_response = substr($_headers[0], 9, 3);
- if($_response === "401") $_response = "200"; // This is because the token is not being enforced.
- if($_response === "429")
+ if ($_response === "401") $_response = "200"; // This is because the token is not being enforced.
+ if ($_response === "429")
{
/**
* We have two specific ratelimit exceptions here.
@@ -103,12 +105,11 @@ public function call(string $type, string $path, array $payload = []): array
* will be updated in the future.
*/
- die("You have encountered a rate limit. Please refer to the JSON contents for the remaining time.");
+ throw new ResourceRatelimitException("You have encountered a rate limit. Please refer to the JSON contents for the remaining time.");
}
/** Now provide the information for the structure. */
$_path = ($_response === "200") ? $path : null;
- $_payload = (!$payload) ? $payload : null;
/**
* All returned information will be formatted this way.
@@ -120,7 +121,7 @@ public function call(string $type, string $path, array $payload = []): array
"type" => $_type,
"path" => $_path,
"status" => $_response,
- "json" => $_payload
+ "json" => $payload
];
}
diff --git a/src/TopPHP/API/Request.php b/src/TopPHP/API/Request.php
index 3b8b5c6..7aef83e 100644
--- a/src/TopPHP/API/Request.php
+++ b/src/TopPHP/API/Request.php
@@ -11,6 +11,7 @@
*/
namespace DBL\API;
+
use DBL\API\Http;
use DBL\Structs\RequestStruct;
@@ -70,64 +71,55 @@ public function __construct(string $token, string $http = self::SERVER_ADDR)
* @param array $json Additional information you want to pass on as JSON.
* @return array
*/
- public function req(string $type, string $path = null, array $json = [], int $port = self::SERVER_PORT): array
+ public function req(string $type, ?string $path = null, array $json = [], int $port = self::SERVER_PORT): array
{
$_http = new Http($this->http, $port);
- $_path = ($path) ? $_http->getHttp(), $path : null;
+ $_path = ($path) ? $_http->getHttp() . $path : "";
$_error = false;
$_request = null;
$_response = null;
- $_json = (![]) ? http_build_query($json) : null;
+ $_json = ($json && $type === "GET") ? "?" . http_build_query($json) : "";
try
{
- /** Ensure headers are restored. */
- // header_remove("Content-Type");
-
/**
* Set up the HTTP request structure.
* Will contextualize and create how we will interact.
*/
- $_path = $_path, $_json;
+ $_path = $_path . $_json;
$_struct = [
"http" => [
"method" => $type,
"header" => "Content-Type: application/json" . "\r\n" .
- "Authorization: {$this->token}" . "\r\n"
+ "Authorization: Bearer {$this->token}" . "\r\n"
]
];
- $_struct = @stream_context_create($_struct);
- /**
- * Here is where the official request is made
- * to receive information.
- */
+ if ($json && $type !== "GET") {
+ $_struct["http"]["content"] = json_encode($json);
+ }
+
+ $_struct = @stream_context_create($_struct);
$_request = @file_get_contents($_path, true, $_struct);
- if(!$_request) $_error = true;
}
- catch (Exception $error) { return $error; }
+ catch (\Exception $error) { return $error; }
finally
{
- if(!$_error)
+ if (!$_error)
{
- // header("Content-Type: application/json");
- // @http_response_code(intval($this->response) + 0);
-
$_struct = $_http->call(
$type,
$_path,
- json_decode($_request, true)
+ $_request ? json_decode($_request, true) : []
);
$this->cache = $_struct;
return $_struct;
}
-
else
{
- error_reporting(E_ALL);
$_error = error_get_last();
/**
@@ -142,7 +134,7 @@ public function req(string $type, string $path = null, array $json = [], int $po
"type" => $type,
"path" => $_path,
"status" => $_response,
- "json" => ["message" => $_error["message"]]
+ "json" => ["message" => $_error["message"] ?? $_error["detail"]]
];
return $this->content;
diff --git a/src/TopPHP/DBL.php b/src/TopPHP/DBL.php
index 2d5bfa7..dd0bbf2 100644
--- a/src/TopPHP/DBL.php
+++ b/src/TopPHP/DBL.php
@@ -11,20 +11,18 @@
*/
namespace DBL;
+
use DBL\API\Http;
use DBL\API\Request;
use DBL\API\Exceptions\MissingTokenException;
-use DBL\API\Exceptions\MissingStatsException;
use DBL\Structs\BaseStruct;
+use DBL\Webhook;
+use DBL\Widget;
/**
- * Represents the TopPHP/Top.gg base class.
- * This class handles all of the specified
- * GET and POST requests that the API allows
- * to be called on, and has methods declared
- * for each specific/particular usage.
+ * Top.gg API v0 client
*/
-final class DBL implements BaseStruct
+class DBL implements BaseStruct
{
/**
* @var string
@@ -58,10 +56,10 @@ final class DBL implements BaseStruct
private $features;
/**
- * @var bool
- * @access public
+ * @var int
+ * @access private
*/
- public $connected;
+ private $id;
/**
* Creates a DBL instance.
@@ -83,8 +81,6 @@ public function __construct(array $parameters)
* KEKW.
*/
- error_reporting(0);
-
/**
* Begin scanning through all of the possible accepted parameters.
* PHP Warnings are thrown in the event that they're found to be as invalid keys
@@ -97,26 +93,53 @@ public function __construct(array $parameters)
"webhook" => []
];
- if($parameters["auto_stats"]) $this->features["auto_stats"][0] = true;
- if($parameters["safety"]) $this->features["safety"] = true;
- if($parameters["webhook"]) $this->features["webhook"] = true;
- if($parameters["token"]) $this->token = $parameters["token"];
+ if (array_key_exists("auto_stats", $parameters) && $parameters["auto_stats"]) $this->features["auto_stats"][0] = true;
+ if (array_key_exists("safety", $parameters) && $parameters["safety"]) $this->features["safety"] = true;
+ if (array_key_exists("webhook", $parameters) && $parameters["webhook"]) $this->features["webhook"] = true;
+ if (array_key_exists("token", $parameters) && $parameters["token"]) $this->token = $parameters["token"];
else throw new MissingTokenException();
- $this->http = (!$parameters["webhook"]["url"]) ? Request::SERVER_ADDR : $parameters["webhook"]["url"];
- $this->port = (!$parameters["webhook"]["port"]) ? Request::SERVER_PORT : $parameters["webhook"]["port"];
+ $this->http = (!array_key_exists("webhook", $parameters) || !array_key_exists("url", $parameters["webhook"]) || !$parameters["webhook"]["url"]) ? Request::SERVER_ADDR : $parameters["webhook"]["url"];
+ $this->port = (!array_key_exists("webhook", $parameters) || !array_key_exists("port", $parameters["webhook"]) || !$parameters["webhook"]["port"]) ? Request::SERVER_PORT : $parameters["webhook"]["port"];
$this->api = new Request($this->token, $this->http);
- /** Proxy an HTTP request to see if it works. */
- $_response = $this->api->req("GET", "/users/140862798832861184")["status"];
- if($_response === "200") $this->connected = true;
+ try {
+ $parts = explode('.', $this->token);
+
+ if (count($parts) < 2) {
+ throw new \Exception();
+ }
+
+ $encoded_json = $parts[1];
+ $padding = 4 - (strlen($encoded_json) % 4);
+
+ if ($padding < 4) {
+ $encoded_json .= str_repeat('=', $padding);
+ }
+
+ $decoded_json = base64_decode($encoded_json, true);
+
+ if ($decoded_json === false) {
+ throw new \Exception();
+ }
+
+ $token_data = json_decode($decoded_json, true);
+
+ if (!isset($token_data['id']) || !is_numeric($token_data['id'])) {
+ throw new \Exception();
+ }
+
+ $this->id = intval($token_data['id']);
+ } catch (\Exception $e) {
+ throw new MissingTokenException();
+ }
/** Finally do our feature checks from the parameters list. */
- if($parameters["auto_stats"])
+ if (array_key_exists("auto_stats", $parameters) && $parameters["auto_stats"])
{
$this->check_auto_stats(
$parameters["auto_stats"]["url"],
- $parameters["auto_stats"]["id"]
+ $parameters["auto_stats"]["callback"]
);
}
@@ -127,33 +150,21 @@ public function __construct(array $parameters)
* Checks if stats should be posted to the website automatically.
* This can only be done for a website URL.
*
- * @param string $path The HTTP path you're using.
- * @param int $id The bot ID.
- * @param array $values A list of values to be automatically posted.
+ * @param string $url The HTTP path you're using.
+ * @param callable $callback The callback function that returns the bot's statistics.
* @return void
*/
- protected function check_auto_stats(string $path, int $id, array $values)
+ private function check_auto_stats(string $url, callable $callback)
{
try
{
- if($values["shards"]) $_json["shards"] = $values["shards"];
- if($values["shard_id"]) $_json["shard_id"] = $values["shard_id"];
- if($values["shard_count"]) $_json["shard_count"] = $values["shard_count"];
- if($values["server_count"]) $_json["server_count"] = $values["server_count"];
- else throw new MissingStatsException();
-
- $_id = ($id) ? $id : throw new MissingStatsException();
- $_url = ($path) ? $path : throw new MissingStatsException();
- $_type = Http::BOT;
- $_request = $this->api->req("POST", "/{$_type}/{$_id}/stats", $_json)["json"];
+ $this->post_stats(0, $callback());
}
-
- catch(Exception $error) { echo $error; }
-
+ catch (\Exception $error) { echo $error; }
finally
{
header("Content-Type: application/json");
- echo "";
+ echo "";
}
}
@@ -167,10 +178,12 @@ protected function check_auto_stats(string $path, int $id, array $values)
protected function check_safety()
{
/** One last time to check. */
- if($this->features["safety"]) die();
+ if ($this->features["safety"]) die();
}
/**
+ * @deprecated Use get_bots() instead.
+ *
* Shows the information from the specified type through a query search.
*
* @param string $type The search type.
@@ -179,27 +192,25 @@ protected function check_safety()
*/
public function show_info(string $type, array $json = []): array
{
+ trigger_error('show_info() is deprecated, use get_bots() instead', E_USER_DEPRECATED);
+
switch($type)
{
- case Http::USER:
- $_path = "users";
- break;
-
case Http::BOT:
- $_path = "bots";
break;
default:
- die("Invalid search parameter: {$type}");
+ throw new \Exception("Invalid search parameter: {$type}");
break;
}
- return $this->api->req("GET", "/{$type}", $json)["json"];
+ return $this->api->req("GET", "/bots", $json)["json"];
}
/**
- * Displays the general information about something
- * given through the search type.
+ * @deprecated Use get_bot() instead.
+ *
+ * Gets the general information about something given through the search type.
*
* @param string $type The search type.
* @param int $id The bot/user ID.
@@ -207,68 +218,119 @@ public function show_info(string $type, array $json = []): array
*/
public function find_info(string $type, int $id): array
{
+ trigger_error('find_info() is deprecated, use get_bot() instead', E_USER_DEPRECATED);
+
switch($type)
{
- case Http::USER:
- $_path = "users";
- break;
-
case Http::BOT:
- $_path = "bots";
break;
default:
- die("Invalid search parameter: {$type}");
+ throw new \Exception("Invalid search parameter: {$type}");
break;
}
- return $this->api->req("GET", "/{$type}/{$id}")["json"];
+ return $this->api->req("GET", "/bots/{$id}")["json"];
}
/**
- * Returns the total votes of the bot.
+ * Returns the unique voters of your project.
*
- * @param int $id The bot ID.
+ * @param int $id The project ID. Unused, no longer has an effect.
+ * @param int $page The page counter. Defaults to 1.
* @return array
*/
- public function get_votes(int $id)
+ public function get_votes(int $id = 0, int $page = 1): array
{
- return $this->api->req("GET", "/bots/{$id}/votes")["json"];
+ return $this->api->req("GET", "/bots/{$this->id}/votes", ["page" => $page])["json"];
}
/**
- * Returns a boolean check for if a user voted for your bot.
+ * Returns true if a user has voted for your project.
*
- * @param int $id The bot user ID.
- * @param int $user The user Snowflake ID.
- * @return array
+ * @param int $id The project ID. Unused, no longer has an effect.
+ * @param int $user The user ID.
+ * @return bool
*/
- public function get_user_vote(int $id, int $user): array
+ public function get_user_vote(int $id, int $user): bool
{
- return $this->api->req("GET", "/bots/{$id}/check", ["userId" => $user])["json"]["voted"];
+ return $this->api->req("GET", "/bots/check", ["userId" => $user])["json"]["voted"] != 0;
}
/**
- * Returns the statistics of the bot.
+ * Returns your bot's posted statistics.
*
- * @param int $id The bot ID.
+ * @param int $id The bot ID. Unused, no longer has an effect.
+ * @return array
+ */
+ public function get_stats(int $id = 0): array
+ {
+ return $this->api->req("GET", "/bots/stats")["json"];
+ }
+
+ /**
+ * Posts your Discord bot's statistics to the API. This will update the statistics in your Discord bot's Top.gg page.
+ *
+ * @param int $id The bot ID. Unused, no longer has an effect.
+ * @param array $json Your bot's new statistics.
+ */
+ public function post_stats(int $id, array $json)
+ {
+ $this->api->req("POST", "/bots/stats", $json);
+ }
+
+ /**
+ * Gets the general information of several bots.
+ *
+ * @param int $limit The maximum amount of bots to be queried.
+ * @param int $offset The amount of bots to be skipped.
+ * @param string $sort_by Sorts results based on a specific criteria. Results will always be descending.
* @return array
*/
- public function get_stats(int $id): array
+ public function get_bots(int $limit = 50, int $offset = 0, string $sort_by = "monthlyPoints"): array
{
- return $this->api->req("GET", "/bots/{$id}/stats")["json"];
+ if ($limit <= 0) {
+ $limit .= 1;
+ } else if ($limit > 500) {
+ $limit .= 500;
+ }
+
+ if ($offset < 0) {
+ $offset .= 0;
+ } else if ($offset > 499) {
+ $offset .= 499;
+ }
+
+ if ($sort_by !== "monthlyPoints" && $sort_by !== "date" && $sort_by !== "id") {
+ throw new \Exception("sort_by argument must be \"monthlyPoints\", \"date\", or \"id\".");
+ }
+
+ return $this->api->req("GET", "/bots", [
+ "limit" => $limit,
+ "offset" => $offset,
+ "sort" => $sort_by,
+ ])["json"];
}
/**
- * Posts statistics to the bot's Top.gg page.
+ * Gets the general information about a bot.
*
- * @param int $id The bot ID.
- * @param array $json The JSON query fields.
+ * @param int $id The bot ID.
* @return array
*/
- public function post_stats(int $id, array $json): array
+ public function get_bot(int $id): array
+ {
+ return $this->api->req("GET", "/bots/{$id}")["json"];
+ }
+
+ /**
+ * Returns true if the weekend multiplier is active, where a single vote counts as two.
+ *
+ * @return bool
+ */
+ public function is_weekend(): bool
{
- return $this->api->req("POST", "/bots/{$id}/stats", $json)["json"];
+ return $this->api->req("GET", "/weekend")["json"]["is_weekend"];
}
/**
diff --git a/src/TopPHP/Structs/BaseStruct.php b/src/TopPHP/Structs/BaseStruct.php
index 25bef85..c5dca64 100644
--- a/src/TopPHP/Structs/BaseStruct.php
+++ b/src/TopPHP/Structs/BaseStruct.php
@@ -25,9 +25,13 @@ public function __construct(array $parameters);
public function show_info(string $type, array $json = []);
public function find_info(string $type, int $id);
- /** Get information on the votes, vote check; and stats. */
- public function get_votes(int $id);
+ public function get_bots(int $limit, int $offset, string $sort_by);
+ public function get_bot(int $id);
+
+ /** Get information on your voters, vote check, weekend multiplier, and stats. */
+ public function get_votes(int $id, int $page);
public function get_user_vote(int $id, int $user);
+ public function is_weekend();
public function get_stats(int $id);
/**
diff --git a/src/TopPHP/Structs/RequestStruct.php b/src/TopPHP/Structs/RequestStruct.php
index dee2023..a3e9b0b 100644
--- a/src/TopPHP/Structs/RequestStruct.php
+++ b/src/TopPHP/Structs/RequestStruct.php
@@ -15,7 +15,7 @@
interface RequestStruct
{
public function __construct(string $token, string $http);
- public function req(string $type, string $path = null, array $json = [], int $port = 80);
+ public function req(string $type, ?string $path = null, array $json = [], int $port = 80);
/** Accessor methods for getting private instances. */
public function getContents();
diff --git a/src/TopPHP/V1DBL.php b/src/TopPHP/V1DBL.php
new file mode 100644
index 0000000..9cdba6b
--- /dev/null
+++ b/src/TopPHP/V1DBL.php
@@ -0,0 +1,56 @@
+api->req("POST", "/v1/projects/@me/commands", $commands);
+ }
+
+ /**
+ * Gets the latest vote information of a Top.gg user on your project.
+ *
+ * @param int $id The user's ID.
+ * @param string $source The ID type to use. Defaults to "discord".
+ * @return array|null
+ */
+ public function get_vote(int $id, string $source = "discord"): array|null
+ {
+ if ($source !== "topgg" && $source !== "discord")
+ {
+ throw new \Exception("source argument must be \"topgg\" or \"discord\".");
+ }
+
+ $result = $this->api->req("GET", "/v1/projects/@me/votes/{$id}", ["source" => $source]);
+
+ if ($result["status"] === "404") {
+ return null;
+ }
+
+ return $result["json"];
+ }
+}
+
+?>
diff --git a/src/TopPHP/Webhook.php b/src/TopPHP/Webhook.php
new file mode 100644
index 0000000..fc35408
--- /dev/null
+++ b/src/TopPHP/Webhook.php
@@ -0,0 +1,51 @@
+header("Authorization") !== $this->getAuthorization()) {
+ return response("Unauthorized", 401);
+ }
+
+ $data = $request->json()->all();
+
+ if (!empty($data)) {
+ $this->callback($data);
+
+ return response("", 204);
+ }
+
+ return response("Bad request", 400);
+ }
+
+ /**
+ * Retrieves the authorization token used to authorize incoming webhook requests.
+ *
+ * @return string
+ */
+ public abstract function getAuthorization();
+
+ /**
+ * Receives the JSON body sent from Top.gg containing webhook event information.
+ *
+ * @param array $data The JSON body sent from Top.gg containing webhook event information.
+ * @return void
+ */
+ public abstract function callback(array $data);
+}
+
+?>
\ No newline at end of file
diff --git a/src/TopPHP/Widget.php b/src/TopPHP/Widget.php
new file mode 100644
index 0000000..1582983
--- /dev/null
+++ b/src/TopPHP/Widget.php
@@ -0,0 +1,68 @@
+value . "/$id";
+ }
+
+ /**
+ * Generates a small widget URL for displaying votes.
+ *
+ * @param WidgetType $ty The widget type.
+ * @param int $id The ID.
+ * @return string
+ */
+ public static function votes(WidgetType $ty, int $id): string {
+ return self::BASE_URL . "/widgets/small/votes/" . $ty->value . "/$id";
+ }
+
+ /**
+ * Generates a small widget URL for displaying a project's owner.
+ *
+ * @param WidgetType $ty The widget type.
+ * @param int $id The ID.
+ * @return string
+ */
+ public static function owner(WidgetType $ty, int $id): string {
+ return self::BASE_URL . "/widgets/small/owner/" . $ty->value . "/$id";
+ }
+
+ /**
+ * Generates a small widget URL for displaying social stats.
+ *
+ * @param WidgetType $ty The widget type.
+ * @param int $id The ID.
+ * @return string
+ */
+ public static function social(WidgetType $ty, int $id): string {
+ return self::BASE_URL . "/widgets/small/social/" . $ty->value . "/$id";
+ }
+}
+
+?>
\ No newline at end of file