. */ namespace App\Helpers; use App\Exceptions\AccountNotLinkedException; use App\User; use Illuminate\Http\Client\RequestException; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Crypt; use Illuminate\Support\Facades\Http; // Small wrapper for the necessary sections of the Discord API; A library is overkill here class Discord { /** * The current working guild. Default is Home guild from app config * @var string */ protected string $workingGuild; /** * Current user. * * @var User The user all methods will affect. */ protected User $user; public function __construct() { if (!is_null($this->workingGuild)) { $this->setWorkingGuild(config('services.discord.home_guild')); } } /** * Sets the working guild * * @param string $workingGuild * @return Discord */ public function setWorkingGuild(string $workingGuild): Discord { $this->workingGuild = $workingGuild; return $this; } /** * Sets the current user, upon validation * * @param User $user * @return Discord * @throws AccountNotLinkedException */ public function setUser(User $user): Discord { if ($user->hasDiscordConnection()) { $this->user = $user; return $this; } throw new AccountNotLinkedException('Specified website user has not linked their Discord account yet.'); } /** * Adds current working user to current working guild. Bot must be member of target guild, and account must be linked * * @return object|bool A GuildMember object; false if member is already in guild * @throws RequestException Any client and server errors * @see https://discord.com/developers/docs/resources/guild#guild-member-object */ public function addGuildMember(): object|bool { $params = [ 'access_token' => $this->user->discord_token ]; $member = Http::withBody(json_encode($params), 'application/json') ->withHeaders([ 'Authorization' => 'Bot ' . config('services.discord.token') ])->put(config('services.discord.base_url') . "/guilds/{$this->workingGuild}/members/{$this->user->discord_user_id}") ->throw(); if ($member->successful() && $member->status() == 204) { return false; } else { return (object) $member->json(); } } /** * Bans a specified user from the guild. * May be called from the suspension service optionally by the banning user * * @param string $reason The reason to supply Discord with * @return void Nothing on success * @throws RequestException * @throws AccountNotLinkedException */ public function addGuildBan(string $reason): void { Http::withHeaders([ 'Authorization' => 'Bot ' . config('services.discord.token'), 'X-Audit-Log-Reason' => $reason ])->put(config('services.discord.base_url') . "/guilds/{$this->workingGuild}/bans/{$this->user->discord_user_id}") ->throw(); throw new AccountNotLinkedException('Specified website user has not linked their Discord account yet.'); } /** * Gets (possible) ban for current user. * * @return object|bool Ban object if user is banned. Null * @throws RequestException */ public function getGuildBan(): object|bool { $ban = Http::withHeaders([ 'Authorization' => 'Bot ' . config('services.discord.token') ])->get(config('services.discord.base_url') . "/guilds/{$this->workingGuild}/bans/{$this->user->discord_user_id}"); if ($ban->status() == 404) { return false; } return ($ban->successful()) ? (object) $ban->json() : $ban->throwIf($ban->status() !== 404); } }