mirror of
https://github.com/the-programmers-hangout/Hermes.git
synced 2026-09-08 23:45:36 +02:00
init
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
quote_type = single
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.php]
|
||||||
|
indent_size = 4
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
APP_NAME=Hermes
|
||||||
|
APP_ENV=development
|
||||||
|
|
||||||
|
DISCORD_TOKEN=
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
|
/.github export-ignore
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/vendor
|
||||||
|
/builds
|
||||||
|
/.laracord
|
||||||
|
*.sqlite
|
||||||
|
.env
|
||||||
|
storage/logs/*
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "es5"
|
||||||
|
}
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"python-envs.defaultEnvManager": "ms-python.python:pyenv",
|
||||||
|
"python-envs.pythonProjects": []
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) Brandon Nifong
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
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 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.
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<p align="center">
|
||||||
|
<img title="Laracord" height="100" src="https://raw.githubusercontent.com/laracord/laracord.com/main/public/images/logo-full-dark.png" alt="Laracord Logo" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/laracord/framework/actions"><img src="https://img.shields.io/github/actions/workflow/status/laracord/framework/main.yml?branch=main&style=flat-square" alt="Build Status" /></a>
|
||||||
|
<a href="https://packagist.org/packages/laracord/framework"><img src="https://img.shields.io/packagist/dt/laracord/framework.svg?style=flat-square" alt="Total Downloads" /></a>
|
||||||
|
<a href="https://packagist.org/packages/laracord/framework"><img src="https://img.shields.io/packagist/v/laracord/framework.svg?label=framework&style=flat-square" alt="Latest Stable Version" /></a>
|
||||||
|
<a href="https://packagist.org/packages/laracord/framework"><img src="https://img.shields.io/packagist/l/laracord/framework.svg?style=flat-square" alt="License" /></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Laracord is a [micro-framework](https://github.com/laracord/framework) providing a powerful starting point for your next [Discord](https://discord.com/developers/docs/intro) bot.
|
||||||
|
|
||||||
|
Quickly build functional, elegant bots using [Laravel](https://laravel.com/) alongside [DiscordPHP](https://github.com/discord-php/DiscordPHP).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- ⚡️ Out of the box support for databases, caching, and many other Laravel features thanks to [Laravel Zero](https://laravel-zero.com/).
|
||||||
|
- 🚀 Instantly generate working bot [commands](https://laracord.com/docs/commands) and [event listeners](https://laracord.com/docs/events) with 0 knowledge.
|
||||||
|
- 🧑💻 Automatic handling of registering/updating/unregistering application [slash commands](https://laracord.com/docs/slash-commands).
|
||||||
|
- 🚚 Easy to use [interaction routing](https://laracord.com/docs/interactions) for persistence on message buttons and actions.
|
||||||
|
- 👷 Generate asynchronous [services/tasks](https://laracord.com/docs/services) that run parallel to the bot.
|
||||||
|
- 🌎 Optional [HTTP Server](https://laracord.com/docs/http-server) with native Laravel routing and [Livewire support](https://laracord.com/docs/livewire).
|
||||||
|
- 🔧 Fully configurable and extendable.
|
||||||
|
- 💄 Beautiful console logging with timestamps.
|
||||||
|
- 🔍️ Fully [documented](https://laracord.com) and maintained.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
For full documentation, visit [Laracord.com](https://laracord.com).
|
||||||
|
|
||||||
|
## Bug Reports
|
||||||
|
|
||||||
|
If you discover a bug in Laracord, please [open an issue](https://github.com/laracord/framework/issues).
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributing whether it be through PRs, reporting an issue, or suggesting an idea is encouraged and appreciated.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Laracord is provided under the [MIT License](LICENSE.md).
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use Laracord\Laracord;
|
||||||
|
|
||||||
|
class Bot extends Laracord
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The HTTP routes.
|
||||||
|
*/
|
||||||
|
public function routes(): void
|
||||||
|
{
|
||||||
|
Route::middleware('web')->group(function () {
|
||||||
|
// Route::get('/', fn () => 'Hello world!');
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::middleware('api')->group(function () {
|
||||||
|
// Route::get('/commands', fn () => collect($this->registeredCommands)->map(fn ($command) => [
|
||||||
|
// 'signature' => $command->getSignature(),
|
||||||
|
// 'description' => $command->getDescription(),
|
||||||
|
// ]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Events;
|
||||||
|
|
||||||
|
use Discord\Discord;
|
||||||
|
use Discord\Parts\Channel\Message;
|
||||||
|
use Discord\WebSockets\Event as Events;
|
||||||
|
use Laracord\Events\Event;
|
||||||
|
|
||||||
|
class MessageCreate extends Event
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The event handler.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $handler = Events::MESSAGE_CREATE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*/
|
||||||
|
public function handle(Message $message, Discord $discord)
|
||||||
|
{
|
||||||
|
$this->console()->log('The Message Create event has fired!');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Events;
|
||||||
|
|
||||||
|
use App\Models\Emote;
|
||||||
|
use App\Models\User;
|
||||||
|
use Discord\Discord;
|
||||||
|
use Discord\Parts\WebSockets\MessageReaction;
|
||||||
|
use Discord\WebSockets\Event as Events;
|
||||||
|
use Laracord\Events\Event;
|
||||||
|
|
||||||
|
class MessageReactionAdd extends Event
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The event handler.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $handler = Events::MESSAGE_REACTION_ADD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*/
|
||||||
|
public function handle(MessageReaction $reaction, Discord $discord)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($reaction->user->bot || ! $reaction->guild_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($reaction->emoji && $reaction->emoji->id) {
|
||||||
|
|
||||||
|
if ($reaction->emoji->guild_id) {
|
||||||
|
if ($reaction->emoji->guild_id !== $reaction->guild_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$guild = $discord->guilds->get('id', $reaction->guild_id);
|
||||||
|
if (! $guild || ! $guild->emojis->get('id', $reaction->emoji->id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = User::firstOrCreate(
|
||||||
|
['discord_id' => $reaction->user_id],
|
||||||
|
['username' => $reaction->user->username]
|
||||||
|
);
|
||||||
|
|
||||||
|
$emoteId = $reaction->emoji->id ?? $reaction->emoji->name;
|
||||||
|
$type = $reaction->emoji->id ? ($reaction->emoji->animated ? 'ANIMATED' : 'STATIC') : 'UNICODE';
|
||||||
|
$guildId = $reaction->guild_id;
|
||||||
|
|
||||||
|
$emote = Emote::firstOrCreate(
|
||||||
|
['emote_id' => $emoteId],
|
||||||
|
[
|
||||||
|
'guild_id' => $guildId,
|
||||||
|
'emote_name' => $reaction->emoji->name,
|
||||||
|
'type' => $type,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$emote->addReaction(
|
||||||
|
user: $user,
|
||||||
|
guildId: $reaction->guild_id,
|
||||||
|
channelId: $reaction->channel_id,
|
||||||
|
messageId: $reaction->message_id,
|
||||||
|
unicodeEmoji: boolval($reaction->emoji->id) ? null : $reaction->emoji->name
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Events;
|
||||||
|
|
||||||
|
use App\Models\Emote;
|
||||||
|
use App\Models\User;
|
||||||
|
use Discord\Discord;
|
||||||
|
use Discord\Parts\WebSockets\MessageReaction;
|
||||||
|
use Discord\WebSockets\Event as Events;
|
||||||
|
use Laracord\Events\Event;
|
||||||
|
|
||||||
|
class MessageReactionRemove extends Event
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The event handler.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $handler = Events::MESSAGE_REACTION_REMOVE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*/
|
||||||
|
public function handle(MessageReaction $reaction, Discord $discord)
|
||||||
|
{
|
||||||
|
if ($reaction->user->bot || ! $reaction->guild_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($reaction->emoji && $reaction->emoji->id) {
|
||||||
|
|
||||||
|
if ($reaction->emoji->guild_id) {
|
||||||
|
if ($reaction->emoji->guild_id !== $reaction->guild_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$guild = $discord->guilds->get('id', $reaction->guild_id);
|
||||||
|
if (! $guild || ! $guild->emojis->get('id', $reaction->emoji->id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = User::where('discord_id', $reaction->user_id)->first();
|
||||||
|
|
||||||
|
if (! $user) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$emoteId = $reaction->emoji->id ?? $reaction->emoji->name;
|
||||||
|
$emote = Emote::where('emote_id', $emoteId)
|
||||||
|
->where('guild_id', $reaction->guild_id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($emote) {
|
||||||
|
$emote->removeReaction(
|
||||||
|
$user,
|
||||||
|
$reaction->guild_id,
|
||||||
|
$reaction->message_id,
|
||||||
|
boolval($reaction->emoji->id) ? null : $reaction->emoji->name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Events;
|
||||||
|
|
||||||
|
use App\Models\EmoteGuildStat;
|
||||||
|
use App\Models\EmoteLog;
|
||||||
|
use Discord\Discord;
|
||||||
|
use Discord\Parts\WebSockets\MessageReaction;
|
||||||
|
use Discord\WebSockets\Event as Events;
|
||||||
|
use Laracord\Events\Event;
|
||||||
|
|
||||||
|
class MessageReactionRemoveAll extends Event
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The event handler.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $handler = Events::MESSAGE_REACTION_REMOVE_ALL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*/
|
||||||
|
public function handle(MessageReaction $reaction, Discord $discord)
|
||||||
|
{
|
||||||
|
if ($reaction->user->bot || ! $reaction->guild_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($reaction->emoji && $reaction->emoji->id) {
|
||||||
|
|
||||||
|
if ($reaction->emoji->guild_id) {
|
||||||
|
if ($reaction->emoji->guild_id !== $reaction->guild_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$guild = $discord->guilds->get('id', $reaction->guild_id);
|
||||||
|
if (! $guild || ! $guild->emojis->get('id', $reaction->emoji->id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$logs = EmoteLog::where('message_id', $reaction->message->id)
|
||||||
|
->where('guild_id', $reaction->message->guild_id)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
foreach ($logs as $log) {
|
||||||
|
EmoteGuildStat::where([
|
||||||
|
'emote_id' => $log->emote_id,
|
||||||
|
'guild_id' => $log->guild_id,
|
||||||
|
])->decrement('usage_count');
|
||||||
|
}
|
||||||
|
|
||||||
|
EmoteLog::where('message_id', $reaction->message->id)
|
||||||
|
->where('guild_id', $reaction->message->guild_id)
|
||||||
|
->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Emote extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'emote_id',
|
||||||
|
'guild_id',
|
||||||
|
'emote_name',
|
||||||
|
'type',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'emote_id' => 'string',
|
||||||
|
'guild_id' => 'string',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function logs()
|
||||||
|
{
|
||||||
|
return $this->hasMany(
|
||||||
|
EmoteLog::class,
|
||||||
|
'emote_id',
|
||||||
|
'emote_id'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function guildStats()
|
||||||
|
{
|
||||||
|
return $this->hasMany(
|
||||||
|
EmoteGuildStat::class,
|
||||||
|
'emote_id',
|
||||||
|
'emote_id'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeForGuild($query, $guildId)
|
||||||
|
{
|
||||||
|
return $query->where('guild_id', $guildId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addReaction(User $user, string $guildId, string $channelId, string $messageId, ?string $unicodeEmoji = null)
|
||||||
|
{
|
||||||
|
$exists = EmoteLog::where([
|
||||||
|
'emote_id' => $this->emote_id,
|
||||||
|
'user_id' => $user->discord_id,
|
||||||
|
'guild_id' => $guildId,
|
||||||
|
'message_id' => $messageId,
|
||||||
|
'emoji_unicode' => boolval($unicodeEmoji),
|
||||||
|
])->exists();
|
||||||
|
|
||||||
|
if ($exists) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EmoteLog::create([
|
||||||
|
'emote_id' => $this->emote_id,
|
||||||
|
'user_id' => $user->discord_id,
|
||||||
|
'guild_id' => $guildId,
|
||||||
|
'channel_id' => $channelId,
|
||||||
|
'message_id' => $messageId,
|
||||||
|
'emoji_unicode' => boolval($unicodeEmoji),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($unicodeEmoji === null) {
|
||||||
|
EmoteGuildStat::firstOrCreate(
|
||||||
|
['emote_id' => $this->emote_id, 'guild_id' => $guildId],
|
||||||
|
['usage_count' => 0]
|
||||||
|
)->increment('usage_count');
|
||||||
|
}
|
||||||
|
|
||||||
|
UserGuildStat::firstOrCreate(
|
||||||
|
[
|
||||||
|
'user_id' => $user->discord_id,
|
||||||
|
'guild_id' => $guildId,
|
||||||
|
'emote_id' => $this->emote_id,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'usage_count' => 0,
|
||||||
|
'emote_id' => $this->emote_id,
|
||||||
|
]
|
||||||
|
)->increment('usage_count');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeReaction(User $user, string $guildId, string $messageId, ?string $unicodeEmoji = null)
|
||||||
|
{
|
||||||
|
$deleted = EmoteLog::where([
|
||||||
|
'emote_id' => $this->emote_id,
|
||||||
|
'user_id' => $user->discord_id,
|
||||||
|
'guild_id' => $guildId,
|
||||||
|
'message_id' => $messageId,
|
||||||
|
'emoji_unicode' => boolval($unicodeEmoji),
|
||||||
|
])->delete();
|
||||||
|
|
||||||
|
if ($deleted) {
|
||||||
|
|
||||||
|
if ($unicodeEmoji === null) {
|
||||||
|
EmoteGuildStat::where(['emote_id' => $this->emote_id, 'guild_id' => $guildId])
|
||||||
|
->decrement('usage_count');
|
||||||
|
}
|
||||||
|
|
||||||
|
UserGuildStat::where(['user_id' => $user->discord_id, 'guild_id' => $guildId])
|
||||||
|
->decrement('usage_count');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class EmoteGuildStat extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'emote_id',
|
||||||
|
'guild_id',
|
||||||
|
'usage_count',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'emote_id' => 'string',
|
||||||
|
'guild_id' => 'string',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function emote()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(
|
||||||
|
Emote::class,
|
||||||
|
'emote_id',
|
||||||
|
'emote_id'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class EmoteLog extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'emote_id',
|
||||||
|
'user_id',
|
||||||
|
'guild_id',
|
||||||
|
'channel_id',
|
||||||
|
'message_id',
|
||||||
|
'emoji_unicode',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'emote_id' => 'string',
|
||||||
|
'guild_id' => 'string',
|
||||||
|
'channel_id' => 'string',
|
||||||
|
'message_id' => 'string',
|
||||||
|
'emoji_unicode' => 'boolean',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function emote()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(
|
||||||
|
Emote::class,
|
||||||
|
'emote_id',
|
||||||
|
'emote_id'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'user_id', 'discord_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Laravel\Sanctum\HasApiTokens;
|
||||||
|
|
||||||
|
class User extends Model
|
||||||
|
{
|
||||||
|
use HasApiTokens;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'username',
|
||||||
|
'discord_id',
|
||||||
|
'is_admin',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'is_admin' => 'boolean',
|
||||||
|
'discord_id' => 'string',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function emoteLogs()
|
||||||
|
{
|
||||||
|
return $this->hasMany(EmoteLog::class, 'user_id', 'discord_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function emotes()
|
||||||
|
{
|
||||||
|
return $this->hasManyThrough(
|
||||||
|
Emote::class,
|
||||||
|
EmoteLog::class,
|
||||||
|
'user_id',
|
||||||
|
'emote_id',
|
||||||
|
'discord_id',
|
||||||
|
'emote_id'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasUsedEmote($emoteId): bool
|
||||||
|
{
|
||||||
|
return $this->emoteLogs()
|
||||||
|
->where('emote_id', $emoteId)
|
||||||
|
->exists();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class UserGuildStat extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id',
|
||||||
|
'guild_id',
|
||||||
|
'emote_id',
|
||||||
|
'usage_count',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'user_id' => 'string',
|
||||||
|
'guild_id' => 'string',
|
||||||
|
'emote_id' => 'string',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'user_id', 'discord_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Laracord\LaracordServiceProvider;
|
||||||
|
|
||||||
|
class BotServiceProvider extends LaracordServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bootstrap any application services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
parent::boot();
|
||||||
|
|
||||||
|
if (env('APP_ENV') === 'development') {
|
||||||
|
\DB::listen(function ($query) {
|
||||||
|
$sql = $query->sql;
|
||||||
|
$bindings = json_encode($query->bindings);
|
||||||
|
$time = $query->time;
|
||||||
|
$log = '['.date('Y-m-d H:i:s')."] SQL: $sql | Bindings: $bindings | Time: {$time}ms\n";
|
||||||
|
$logPath = storage_path('logs/query.log');
|
||||||
|
file_put_contents($logPath, $log, FILE_APPEND);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register any application services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
parent::register();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use LaravelZero\Framework\Application;
|
||||||
|
|
||||||
|
return Application::configure(basePath: dirname(__DIR__))->create();
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"chmod": "0755",
|
||||||
|
"directories": [
|
||||||
|
"app",
|
||||||
|
"bootstrap",
|
||||||
|
"config",
|
||||||
|
"vendor",
|
||||||
|
"database"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"composer.json"
|
||||||
|
],
|
||||||
|
"exclude-composer-files": false,
|
||||||
|
"compression": "GZ",
|
||||||
|
"compactors": [
|
||||||
|
"KevinGH\\Box\\Compactor\\Php",
|
||||||
|
"KevinGH\\Box\\Compactor\\Json"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"name": "laracord/laracord",
|
||||||
|
"type": "project",
|
||||||
|
"description": "Create Discord bots harnessing the full power of Laravel.",
|
||||||
|
"keywords": ["framework", "laravel", "discord"],
|
||||||
|
"license": "MIT",
|
||||||
|
"require": {
|
||||||
|
"php": "^8.2",
|
||||||
|
"laracord/framework": "^2.3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"fakerphp/faker": "^1.23",
|
||||||
|
"laravel/pint": "^1.15"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"App\\": "app/",
|
||||||
|
"Database\\Factories\\": "database/factories/",
|
||||||
|
"Database\\Seeders\\": "database/seeders/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"post-root-package-install": [
|
||||||
|
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"preferred-install": "dist",
|
||||||
|
"sort-packages": true,
|
||||||
|
"optimize-autoloader": true,
|
||||||
|
"allow-plugins": {
|
||||||
|
"php-http/discovery": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minimum-stability": "dev",
|
||||||
|
"prefer-stable": true
|
||||||
|
}
|
||||||
Generated
+8715
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Name
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value is the name of your application. This value is used when the
|
||||||
|
| framework needs to place the application's name in a notification or
|
||||||
|
| any other location as required by the application or its packages.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'name' => env('APP_NAME', 'Laracord'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Version
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value determines the "version" your application is currently running
|
||||||
|
| in. You may want to follow the "Semantic Versioning" - Given a version
|
||||||
|
| number MAJOR.MINOR.PATCH when an update happens: https://semver.org.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'version' => app('git.version'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Environment
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value determines the "environment" your application is currently
|
||||||
|
| running in. This may determine how you prefer to configure various
|
||||||
|
| services the application utilizes. This can be overridden using
|
||||||
|
| the global command line "--env" option when calling commands.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'env' => env('APP_ENV', 'production'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Timezone
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify the default timezone for your application, which
|
||||||
|
| will be used by the PHP date and date-time functions. We have gone
|
||||||
|
| ahead and set this to a sensible default for you out of the box.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'timezone' => env('APP_TIMEZONE', 'UTC'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Autoloaded Service Providers
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The service providers listed here will be automatically loaded on the
|
||||||
|
| request to your application. Feel free to add your own services to
|
||||||
|
| this array to grant expanded functionality to your applications.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'providers' => [
|
||||||
|
App\Providers\BotServiceProvider::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Discord\WebSockets\Intents;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Discord Bot Description
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify the description of your Discord bot. This will be
|
||||||
|
| used when the bot is mentioned in chat, or when you run the "servers"
|
||||||
|
| command. Change this to anything you like.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'description' => env('DISCORD_BOT_DESCRIPTION', 'The Laracord Discord Bot.'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Discord Token
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify your Discord bot token. You can find it under the
|
||||||
|
| "Bot" section of your Discord application. Make sure to keep this
|
||||||
|
| token private and never share it with anyone for security.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'token' => env('DISCORD_TOKEN', ''),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Gateway Intents
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify the gateway intents for your Discord bot. This
|
||||||
|
| will tell Discord what events your bot should receive. Intents can be
|
||||||
|
| enabled in the Discord developer application portal under:
|
||||||
|
|
|
||||||
|
| Settings > Bot > Privileged Gateway Intents
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'intents' => Intents::getDefaultIntents() | Intents::MESSAGE_CONTENT | Intents::GUILD_MEMBERS,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Command Prefix
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify the command prefix for the Discord bot. This
|
||||||
|
| prefix will be used to distinguish commands from regular chat
|
||||||
|
| messages. To use mentioning the bot as a prefix, use "@mention".
|
||||||
|
| To use multiple prefixes, you may pass an array instead.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'prefix' => env('DISCORD_COMMAND_PREFIX', '!'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Additional DiscordPHP Options
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify any additional options for the DiscordPHP client.
|
||||||
|
| These options will be passed directly to the DiscordPHP client.
|
||||||
|
|
|
||||||
|
| For more information, see the DiscordPHP documentation:
|
||||||
|
| ↪ <https://discord-php.github.io/DiscordPHP/#basics>
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'options' => [
|
||||||
|
'loadAllMembers' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| HTTP Server
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The Laracord HTTP server allows you to receive and respond to HTTP
|
||||||
|
| requests from the bot at the specified address/port. This can be useful
|
||||||
|
| for creating a RESTful API for your bot.
|
||||||
|
|
|
||||||
|
| The HTTP server is automatically started when a `routes.php` file is
|
||||||
|
| present and contains valid routes. You can override this behavior by
|
||||||
|
| setting this option to `false`.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'http' => env('HTTP_SERVER', ':8080'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Timestamp Format
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify the timestamp format for the Discord bot. This
|
||||||
|
| format will be used when formatting console output. You can set this
|
||||||
|
| to `false` to disable timestamps.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'timestamp' => 'h:i:s A',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Bot Admins
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may manually specify bot admins without using the User model.
|
||||||
|
| These users will have access to all bot admin commands. User's must
|
||||||
|
| be specified by their Discord user ID.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'admins' => [
|
||||||
|
//
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Additional Commands
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify any additional commands for the Discord bot. These
|
||||||
|
| commands will be loaded in addition to the commands automatically loaded
|
||||||
|
| in your project. By default, the Laracord-provided help command is
|
||||||
|
| is registered here.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'commands' => [
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Additional Context Menus
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify any additional context menus for the Discord bot.
|
||||||
|
| These context menus will be loaded in addition to the context menus
|
||||||
|
| automatically loaded in your project.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'menus' => [
|
||||||
|
//
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Additional Services
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify any additional services to run asynchronously
|
||||||
|
| alongside the Discord bot. These services will be loaded in addition
|
||||||
|
| to the services automatically loaded from your project.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'services' => [
|
||||||
|
//
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Additional Events
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify any additional events to listen for in your
|
||||||
|
| Discord bot. These events will be registered in addition to the
|
||||||
|
| events automatically registered from your project.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'events' => [
|
||||||
|
//
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('users', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('username')->index();
|
||||||
|
$table->string('discord_id')->index()->unique();
|
||||||
|
$table->boolean('is_admin')->default(false);
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('users');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('personal_access_tokens', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->morphs('tokenable');
|
||||||
|
$table->string('name');
|
||||||
|
$table->string('token', 64)->unique();
|
||||||
|
$table->text('abilities')->nullable();
|
||||||
|
$table->timestamp('last_used_at')->nullable();
|
||||||
|
$table->timestamp('expires_at')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('personal_access_tokens');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('emotes', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->string('emote_id')->unique();
|
||||||
|
$table->unsignedBigInteger('guild_id')->index();
|
||||||
|
|
||||||
|
$table->string('emote_name');
|
||||||
|
$table->enum('type', ['STATIC', 'ANIMATED', 'UNICODE']);
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->charset = 'utf8mb4';
|
||||||
|
$table->collation = 'utf8mb4_unicode_ci';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('emotes');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('emote_logs', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->string('emote_id');
|
||||||
|
$table->unsignedBigInteger('user_id');
|
||||||
|
|
||||||
|
$table->unsignedBigInteger('guild_id')->index();
|
||||||
|
$table->unsignedBigInteger('channel_id');
|
||||||
|
$table->unsignedBigInteger('message_id');
|
||||||
|
$table->boolean('emoji_unicode')->default(false);
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->foreign('emote_id')
|
||||||
|
->references('emote_id')
|
||||||
|
->on('emotes')
|
||||||
|
->onDelete('cascade');
|
||||||
|
|
||||||
|
$table->index(['guild_id', 'emote_id']);
|
||||||
|
$table->index(['guild_id', 'user_id']);
|
||||||
|
$table->index(['guild_id', 'message_id']);
|
||||||
|
|
||||||
|
$table->charset = 'utf8mb4';
|
||||||
|
$table->collation = 'utf8mb4_unicode_ci';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('emote_logs');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('emote_guild_stats', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->string('emote_id');
|
||||||
|
$table->unsignedBigInteger('guild_id');
|
||||||
|
|
||||||
|
$table->unsignedBigInteger('usage_count')->default(0);
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->foreign('emote_id')
|
||||||
|
->references('emote_id')
|
||||||
|
->on('emotes')
|
||||||
|
->onDelete('cascade');
|
||||||
|
|
||||||
|
$table->unique(['emote_id', 'guild_id']);
|
||||||
|
|
||||||
|
$table->charset = 'utf8mb4';
|
||||||
|
$table->collation = 'utf8mb4_unicode_ci';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('emote_guild_stats');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('user_guild_stats', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->unsignedBigInteger('user_id');
|
||||||
|
$table->unsignedBigInteger('guild_id');
|
||||||
|
$table->string('emote_id');
|
||||||
|
$table->unsignedBigInteger('usage_count')->default(0);
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->foreign('emote_id')
|
||||||
|
->references('emote_id')
|
||||||
|
->on('emotes')
|
||||||
|
->onDelete('cascade');
|
||||||
|
|
||||||
|
$table->unique(['user_id', 'guild_id', 'emote_id']);
|
||||||
|
|
||||||
|
$table->charset = 'utf8mb4';
|
||||||
|
$table->collation = 'utf8mb4_unicode_ci';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('user_guild_stats');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
define('LARAVEL_START', microtime(true));
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Register The Auto Loader
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Composer provides a convenient, automatically generated class loader
|
||||||
|
| for our application. We just need to utilize it! We'll require it
|
||||||
|
| into the script here so that we do not have to worry about the
|
||||||
|
| loading of any our classes "manually". Feels great to relax.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
$autoloader = require file_exists(__DIR__.'/vendor/autoload.php') ? __DIR__.'/vendor/autoload.php' : __DIR__.'/../../autoload.php';
|
||||||
|
|
||||||
|
$app = require_once __DIR__.'/bootstrap/app.php';
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Run The Artisan Application
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When we run the console application, the current CLI command will be
|
||||||
|
| executed in this console and the response sent back to a terminal
|
||||||
|
| or another output device for the developers. Here goes nothing!
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
|
||||||
|
|
||||||
|
$status = $kernel->handle(
|
||||||
|
$input = new Symfony\Component\Console\Input\ArgvInput,
|
||||||
|
new Symfony\Component\Console\Output\ConsoleOutput
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Shutdown The Application
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Once Artisan has finished running, we will fire off the shutdown events
|
||||||
|
| so that any final work may be done by the application before we shut
|
||||||
|
| down the process. This is the last thing to happen to the request.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
$kernel->terminate($input, $status);
|
||||||
|
|
||||||
|
exit($status);
|
||||||
Reference in New Issue
Block a user